{=============================================================================== ===============================================================================} unit EnhBitmaps; interface uses Windows, Graphics; type TEnhBitmap = class(TBitmap) public X1: Integer; Y1: Integer; constructor Create; override; procedure LineTo(const X2: Integer; const Y2: Integer); procedure MoveTo(const X2: Integer; const Y2: Integer); end; implementation uses Math; {=============================================================================== ===============================================================================} constructor TEnhBitmap.Create; begin inherited; PixelFormat := pf32Bit; end; {=============================================================================== This procedure draws a line very quickly (compared to Canvas.LineTo). To enhance speed, references to ScanLine and Canvas.PenPos were minimized, and the code assumes PixelFormat = pf32Bit (pixels are treated as 32-bit integers). All loops were semi-unrolled to process pixels in pairs; this has several benefits: (1) The loop counters are tested half as often as they otherwise would be. (2) The if statement within the diagonal line loop is also tested half as often. (3) The lines are guaranteed to be symmetrical. (4) Modern processors can pair up the pixel operations and execute them simultaneously since they are not dependent on each other. ===============================================================================} procedure TEnhBitmap.LineTo(const X2: Integer; const Y2: Integer); var DX: Integer; // X-dimension of the line segment DY: Integer; // Y-dimension of the line segment Delta: Integer; // total distance remaining to next minor axis Epsilon: Integer; // aspect ratio of the line segment Index: Integer; // loop counter Pixel1: PInteger; // pixel pointers Pixel2: PInteger; RowOffset: Integer; // pointer offset for adjacent rows MajorOffset: Integer; // = ±RowOffset or ±ColOffset as appropriate MinorOffset: Integer; // = ±RowOffset or ±ColOffset as appropriate DiagonalOffset: Integer; // = MajorOffset + MinorOffset for 45° angles Count: Integer; // number of pixel pairs in the line segment const ColOffset = 1; // pointer offset for adjacent columns begin if (X1 < 0) or (X1 >= Width) or (X2 < 0) or (X2 >= Width) or (Y1 < 0) or (Y1 >= Height) or (Y2 < 0) or (Y2 >= Height) then begin MoveTo(X2, Y2); Exit; end; DX := Abs(X2 - X1); DY := Abs(Y2 - Y1); RowOffset := -Width; if (DX > DY) then begin if (X1 < X2) then MajorOffset := ColOffset else MajorOffset := -ColOffset; if (Y1 < Y2) then MinorOffset := RowOffset else MinorOffset := -RowOffset; end else begin if (Y1 < Y2) then MajorOffset := RowOffset else MajorOffset := -RowOffset; if (X1 < X2) then MinorOffset := ColOffset else MinorOffset := -ColOffset; end; Pixel1 := ScanLine[0]; Pixel2 := Pixel1; Inc(Pixel1, Y1 * RowOffset + X1 * ColOffset); Inc(Pixel2, Y2 * RowOffset + X2 * ColOffset); Count := Max(DX, DY) shr 1; if ((DX = 0) or (DY = 0)) then for Index := 0 to Count do begin Pixel1^ := 0; Pixel2^ := 0; Inc(Pixel1, MajorOffset); Dec(Pixel2, MajorOffset); end else if (DX = DY) then begin DiagonalOffset := MajorOffset + MinorOffset; for Index := 0 to Count do begin Pixel1^ := 0; Pixel2^ := 0; Inc(Pixel1, DiagonalOffset); Dec(Pixel2, DiagonalOffset); end; end else begin Epsilon := (Min(DX, DY) shl 16) div Max(DX, DY); Delta := 0; for Index := 0 to Count do begin Pixel1^ := 0; Pixel2^ := 0; Inc(Pixel1, MajorOffset); Dec(Pixel2, MajorOffset); Inc(Delta, Epsilon); if (Delta >= $8000) then begin Dec(Delta, $10000); Inc(Pixel1, MinorOffset); Dec(Pixel2, MinorOffset); end; end; end; MoveTo(X2, Y2); end; {=============================================================================== ===============================================================================} procedure TEnhBitmap.MoveTo(const X2: Integer; const Y2: Integer); begin X1 := X2; Y1 := Y2; end; end.