📄 gr32_polygons.pas
字号:
const Points: TArrayOfArrayOfFixedPoint;
Closed: Boolean;
Transformation: TTransformation);
var
I: Integer;
begin
for I := 0 to High(Points) do PolylineXSP(Bitmap, Points[I], Closed, Transformation);
end;
procedure QSortLine(const ALine: TScanLine; L, R: Integer);
var
I, J, P: Integer;
begin
repeat
I := L;
J := R;
P := ALine[(L + R) shr 1] and $7FFFFFFF;
repeat
while (ALine[I] and $7FFFFFFF) < P do Inc(I);
while (ALine[J] and $7FFFFFFF) > P do Dec(J);
if I <= J then
begin
Swap(ALine[I], ALine[J]);
Inc(I);
Dec(J);
end;
until I > J;
if L < J then QSortLine(ALine, L, J);
L := I;
until I >= R;
end;
{ General routines for drawing polygons }
procedure SortLine(const ALine: TScanLine);
var
L, Tmp: Integer;
begin
L := Length(ALine);
Assert(not Odd(L));
if L = 2 then
begin
if (ALine[0] and $7FFFFFFF) > (ALine[1] and $7FFFFFFF) then
begin
Tmp := ALine[0];
ALine[0] := ALine[1];
ALine[1] := Tmp;
end;
end
else if L > 2 then QSortLine(ALine, 0, L - 1);
end;
procedure SortLines(const ScanLines: TScanLines);
var
I: Integer;
begin
for I := 0 to High(ScanLines) do SortLine(ScanLines[I]);
end;
procedure AddPolygon(const Points: TArrayOfPoint; const BaseX, BaseY: Integer;
const MaxX, MaxY: Integer; var ScanLines: TScanLines; SubSampleX: Boolean);
var
I, X1, Y1, X2, Y2: Integer;
Direction, PrevDirection: Integer; // up = 1 or down = -1
function Sign(I: Integer): Integer;
begin
if I > 0 then Result := 1
else if I < 0 then Result := -1
else Result := 0;
end;
procedure AddEdgePoint(X, Y: Integer; Direction: Integer);
var
Top, L: Integer;
begin
// positive direction (+1) is down
if (Y < BaseY) or (Y > MaxY) then Exit;
if X < BaseX then
X := BaseX
else if X > MaxX then
X := MaxX;
Top := Y - BaseY;
L := Length(ScanLines[Top]);
SetLength(ScanLines[Top], L + 1);
if Direction < 0 then
X := Integer(Longword(X) or $80000000); // set the highest bit if the winding is up
ScanLines[Top][L] := X;
end;
function DrawEdge(X1, Y1, X2, Y2: Integer): Integer;
var
X, Y, I, K: Integer;
Dx, Dy, Sx, Sy: Integer;
Delta: Integer;
begin
// this function 'renders' a line into the edge (ScanLines) buffer
// and returns the line direction (1 - down, -1 - up, 0 - horizontal)
Result := 0;
if Y2 = Y1 then Exit;
Dx := X2 - X1;
Dy := Y2 - Y1;
if Dy > 0 then Sy := 1
else
begin
Sy := -1;
Dy := -Dy;
end;
Result := Sy;
if Dx > 0 then Sx := 1
else
begin
Sx := -1;
Dx := -Dx;
end;
Delta := (Dx mod Dy) shr 1;
X := X1; Y := Y1;
for I := 0 to Dy - 1 do
begin
AddEdgePoint(X, Y, Result);
Inc(Y, Sy);
Inc(Delta, Dx);
// try it two times and if anything else left, use div and mod
if Delta > Dy then
begin
Inc(X, Sx);
Dec(Delta, Dy);
if Delta > Dy then // segment is tilted more than 45 degrees?
begin
Inc(X, Sx);
Dec(Delta, Dy);
if Delta > Dy then // are we still here?
begin
K := (Delta + Dy - 1) div Dy;
Inc(X, Sx * K);
Dec(Delta, Dy * K);
end;
end;
end;
end;
end;
begin
if Length(Points) < 3 then Exit;
with Points[0] do
begin
if SubSampleX then
X1 := X shl 8
else
X1 := X;
Y1 := Y;
end;
// find the last Y different from Y1 and assign it to Y0
PrevDirection := 0;
I := High(Points);
while I > 0 do
begin
PrevDirection := Sign(Y1 - Points[I].Y);
if PrevDirection <> 0 then Break;
Dec(I);
end;
for I := 1 to High(Points) do
begin
with Points[I] do
begin
if SubSampleX then
X2 := X shl 8
else
X2 := X;
Y2 := Y;
end;
if Y1 <> Y2 then
begin
Direction := DrawEdge(X1, Y1, X2, Y2);
if Direction <> PrevDirection then
begin
AddEdgePoint(X1, Y1, -Direction);
PrevDirection := Direction;
end;
end;
X1 := X2; Y1 := Y2;
end;
with Points[0] do
begin
if SubSampleX then
X2 := X shl 8
else
X2 := X;
Y2 := Y;
end;
if Y1 <> Y2 then
begin
Direction := DrawEdge(X1, Y1, X2, Y2);
if Direction <> PrevDirection then AddEdgePoint(X1, Y1, -Direction);
end;
end;
procedure ColorFillLines(Bitmap: TBitmap32; BaseY: Integer;
const ScanLines: TScanLines; Color: TColor32; Mode: TPolyFillMode);
var
I, J, L: Integer;
Top, Left, Right, OldRight, LP, RP, Cx: Integer;
Winding, NextWinding: Integer;
HorzLine: procedure(X1, Y, X2: Integer; Value: TColor32) of Object;
begin
if Color and $FF000000 <> $FF000000 then
HorzLine := Bitmap.HorzLineT
else
HorzLine := Bitmap.HorzLine;
Cx := Bitmap.ClipRect.Right - 1;
Top := BaseY - 1;
if Mode = pfAlternate then
for J := 0 to High(ScanLines) do
begin
Inc(Top);
L := Length(ScanLines[J]); // assuming length is even
if L = 0 then Continue;
I := 0;
OldRight := -1;
while I < L do
begin
Left := ScanLines[J][I] and $7FFFFFFF;
Inc(I);
Right := ScanLines[J][I] and $7FFFFFFF - 1;
if Right > Left then
begin
if (Left and $FF) < $80 then Left := Left shr 8
else Left := Left shr 8 + 1;
if (Right and $FF) < $80 then Right := Right shr 8
else Right := Right shr 8 + 1;
if Right >= Cx then Right := Cx;
if Left <= OldRight then Left := OldRight + 1;
OldRight := Right;
if Right >= Left then HorzLine(Left, Top, Right, Color);
end;
Inc(I);
end
end
else // Mode = pfWinding
for J := 0 to High(ScanLines) do
begin
Inc(Top);
L := Length(ScanLines[J]); // assuming length is even
if L = 0 then Continue;
I := 0;
Winding := 0;
Left := ScanLines[J][0];
if (Left and $80000000) <> 0 then Inc(Winding) else Dec(Winding);
Left := Left and $7FFFFFFF;
Inc(I);
while I < L do
begin
Right := ScanLines[J][I];
if (Right and $80000000) <> 0 then NextWinding := 1 else NextWinding := -1;
Right := Right and $7FFFFFFF;
Inc(I);
if Winding <> 0 then
begin
if (Left and $FF) < $80 then LP := Left shr 8
else LP := Left shr 8 + 1;
if (Right and $FF) < $80 then RP := Right shr 8
else RP := Right shr 8 + 1;
if RP >= Cx then RP := Cx;
if RP >= LP then HorzLine(LP, Top, RP, Color);
end;
Inc(Winding, NextWinding);
Left := Right;
end;
end;
end;
procedure ColorFillLines2(Bitmap: TBitmap32; BaseY: Integer;
const ScanLines: TScanLines; Color: TColor32; Mode: TPolyFillMode;
const AAMode: TAntialiasMode = DefaultAAMode);
var
I, J, L, N: Integer;
MinY, MaxY, Y, Top, Bottom: Integer;
MinX, MaxX, X, Dx: Integer;
Left, Right: Integer;
Buffer: array of Integer;
ColorBuffer: array of TColor32;
BufferSize: Integer;
C, A: TColor32;
ScanLine: PIntegerArray;
Winding, NextWinding: Integer;
AAShift, AALines, AAMultiplier: Integer;
BlendLineEx: TBlendLineEx;
begin
A := Color shr 24;
AAShift := AA_SHIFT[AAMode];
AALines := AA_LINES[AAMode] - 1; // we do the -1 here for optimization.
AAMultiplier := AA_MULTI[AAMode];
BlendLineEx := BLEND_LINE_EX[Bitmap.CombineMode];
// find the range of Y screen coordinates
MinY := BaseY shr AAShift;
MaxY := (BaseY + Length(ScanLines) + AALines) shr AAShift;
Y := MinY;
while Y < MaxY do
begin
Top := Y shl AAShift - BaseY;
Bottom := Top + AALines;
if Top < 0 then Top := 0;
if Bottom >= Length(ScanLines) then Bottom := High(ScanLines);
// find left and right edges of the screen scanline
MinX := $7F000000; MaxX := -$7F000000;
for J := Top to Bottom do
begin
L := Length(ScanLines[J]) - 1;
if L > 0 then
begin
Left := (ScanLines[J][0] and $7FFFFFFF);
Right := (ScanLines[J][L] and $7FFFFFFF + AALines);
if Left < MinX then MinX := Left;
if Right > MaxX then MaxX := Right;
end
end;
if MaxX >= MinX then
begin
MinX := MinX shr AAShift;
MaxX := MaxX shr AAShift;
// allocate buffer for a single scanline
BufferSize := MaxX - MinX + 2;
if Length(Buffer) < BufferSize then
begin
SetLength(Buffer, BufferSize + 64);
SetLength(ColorBuffer, BufferSize + 64);
end;
FillLongword(Buffer[0], BufferSize, 0);
// ...and fill it
if Mode = pfAlternate then
for J := Top to Bottom do
begin
I := 0;
L := Length(ScanLines[J]);
ScanLine := @ScanLines[J][0];
while I < L do
begin
// Left edge
X := ScanLine[I] and $7FFFFFFF;
Dx := X and AALines;
X := X shr AAShift - MinX;
Inc(Buffer[X], Dx xor AALines);
Inc(Buffer[X + 1], Dx);
Inc(I);
// Right edge
X := ScanLine[I] and $7FFFFFFF;
Dx := X and AALines;
X := X shr AAShift - MinX;
Dec(Buffer[X], Dx xor AALines);
Dec(Buffer[X + 1], Dx);
Inc(I);
end
end
else // mode = pfWinding
for J := Top to Bottom do
begin
I := 0;
L := Length(ScanLines[J]);
ScanLine := @ScanLines[J][0];
Winding := 0;
while I < L do
begin
X := ScanLine[I];
Inc(I);
if (X and $80000000) <> 0 then NextWinding := 1 else NextWinding := -1;
X := X and $7FFFFFFF;
if Winding = 0 then
begin
Dx := X and AALines;
X := X shr AAShift - MinX;
Inc(Buffer[X], Dx xor AALines);
Inc(Buffer[X + 1], Dx);
end;
Inc(Winding, NextWinding);
if Winding = 0 then
begin
Dx := X and AALines;
X := X shr AAShift - MinX;
Dec(Buffer[X], Dx xor AALines);
Dec(Buffer[X + 1], Dx);
end;
end;
end;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -