Новичок
Профиль
Группа: Участник
Сообщений: 1
Регистрация: 30.1.2008
Репутация: нет Всего: нет
|
Здравствуйте! В общем нужно сгладить линию алгоритмом By, но сделать это с максимальным быстродействием (gdi+ не предлогать). Вот что у меня получилось: | Код | function GetPixelW(Bitmap: TBitmap; X,Y: Integer): TColor; var pixel: PRGBTriple; begin if Bitmap.PixelFormat = pf24bit then begin DWORD(pixel) := DWORD(Bitmap.ScanLine[Y]) + (X * SizeOf(TRGBTriple)); Result := RGB(pixel.rgbtRed, pixel.rgbtGreen, pixel.rgbtBlue); end else Result := 0; end;
procedure SetPixelW(Bitmap: TBitmap; X,Y: Integer; Color: TColor); var pixel: PRGBTriple; begin if Bitmap.PixelFormat = pf24bit then begin DWORD(pixel) := DWORD(Bitmap.ScanLine[Y]) + (X * SizeOf(TRGBTriple)); pixel.rgbtRed := GetRValue(Color); pixel.rgbtGreen := GetGValue(Color); pixel.rgbtBlue := GetBValue(Color); end; end;
function MixBytes(FG, BG, TRANS: byte): byte; asm push bx // push some regs push cx push dx mov DH,TRANS // remembering Transparency value (or Opacity - as you like) mov BL,FG // filling registers with our values mov AL,DH // BL = ForeGround (FG) mov CL,BG // CL = BackGround (BG) xor AH,AH // Clear High-order parts of regs xor BH,BH xor CH,CH mul BL // AL=AL*BL mov BX,AX // BX=AX xor AH,AH mov AL,DH xor AL,$FF // AX=(255-TRANS) mul CL // AL=AL*CL add AX,BX // AX=AX+BX shr AX,8 // Fine! Here we have mixed value in AL pop dx // Hm... No rubbish after us, ok? pop cx pop bx // Bye, dear Assembler - we go home to Delphi! end;
function MixColors(FG, BG: TColor; T: byte): TColor; var r,g,b:byte; begin R := MixBytes(FG and 255,BG and 255,T); // extracting and mixing Red G := MixBytes((FG shr 8) and 255,(BG shr 8) and 255,T); // the same with green B := MixBytes((FG shr 16) and 255,(BG shr 16) and 255,T); // and blue, of course Result := r+g*256+b*65536; // finishing with combining all channels together end;
procedure DrawWuLine(bt: TBitmap; x1, y1, x2, y2: real; clr: TColor); //-----------------------------------------------------// procedure SetPixel(x, y: Integer; Brightness: Double); var Color: TColor; begin if round(100*Brightness) = 100 then SetPixelW(bt, x, y, clr) else if not (trunc(100*Brightness) = 0) then begin Color := GetPixelW(bt, x, y); Color := MixColors(clr, Color, trunc(Brightness*255)); SetPixelW(bt, x, y, Color); end; end; //-----------------------------------------------------// function MyFrac(X: Double): Double; begin Result := X-Floor(X); end; //-----------------------------------------------------// var grad: Double; xd, yd: Double; xgap: Double; xend, yend: Double; yf: Double; brightness1: Double; brightness2: Double; x: Integer; ix1, ix2: Integer; iy1, iy2: Integer; WasExchange: Boolean; TmpReal: Double; begin if (x1 = x2) or (y1 = y2) then begin bt.Canvas.Pen.Color := clr; bt.Canvas.MoveTo(trunc(x1), trunc(y1)); bt.Canvas.LineTo(trunc(x2), trunc(y2)); Exit; end;
xd := x2-x1; yd := y2-y1;
if (xd=0) and (yd=0) then Exit; if Abs(xd) > Abs(yd) then WasExchange := False else begin WasExchange := True; TmpReal := x1; x1 := y1; y1 := TmpReal; TmpReal := x2; x2 := y2; y2 := TmpReal; TmpReal := xd; xd := yd; yd := TmpReal; end;
if x1 > x2 then begin TmpReal := x1; x1 := x2; x2 := TmpReal; TmpReal := y1; y1 := y2; y2 := TmpReal; xd := x2-x1; yd := y2-y1; end;
grad := yd / xd; xend := Floor(x1 + 0.5); yend := y1+grad*(xend - x1); xgap := 1-MyFrac(x1 + 0.5); ix1 := Floor(x1 + 0.5); iy1 := Floor(yend);
brightness1 := (1-MyFrac(yend))*xgap; brightness2 := MyFrac(yend)*xgap;
if WasExchange then begin SetPixel(iy1, ix1, Brightness1); SetPixel(iy1+1, ix1, Brightness2); end else begin SetPixel(ix1, iy1, Brightness1); SetPixel(ix1, iy1+1, Brightness2); end;
yf := yend+grad; xend := Floor(x2+0.5); yend := y2+grad*(xend-x2); xgap := 1-MyFrac(x2-0.5);
ix2 := Floor(x2+0.5); iy2 := Floor(yend);
brightness1 := (1-MyFrac(yend))*xgap; brightness2 := MyFrac(yend)*xgap;
if WasExchange then begin SetPixel(iy2, ix2, brightness1); SetPixel(iy2+1, ix2, brightness2); end else begin SetPixel(ix2, iy2, brightness1); SetPixel(ix2, iy2+1, brightness2); end;
x := ix1 + 1; while x <= ix2-1 do begin brightness1 := 1-MyFrac(yf); brightness2 := MyFrac(yf);
if WasExchange then begin SetPixel(Floor(yf), x, brightness1); SetPixel(Floor(yf)+1, x, brightness2); end else begin SetPixel(x, Floor(yf), brightness1); SetPixel(x, Floor(yf)+1, brightness2); end;
yf := yf+grad; Inc(x); end; end;
|
Нужно бы перевести эту функцию на asm и какие есть еще идеи оптимизации? И еще вопрос, что быстрее: использовать ScanLine для отрисовки обычной линии или MoveTo-LineTo? Это сообщение отредактировал(а) SMaks - 31.1.2008, 02:03
|