📄 gr32_rasterizers.pas
字号:
Dec(Result.Y, 1 shl XI)
else
Dec(Result.X, 1 shl (YI + 1));
if Result.Y >= H then
begin
Result.Y := P.Y + 1 shl YI;
Result.X := P.X;
Result := GetDstCoord(Result);
end;
if Result.X >= W then
begin
Result.X := P.X + 1 shl XI;
Result.Y := P.Y;
Result := GetDstCoord(Result);
end;
end;
begin
W := DstRect.Right - DstRect.Left;
H := DstRect.Bottom - DstRect.Top;
L := DstRect.Left; T := DstRect.Top;
Size := 1 shl (ScanReverse(Max(W, H)) + 1) + 1;
SetLength(ForwardBuffer, Size);
I := 2;
while I < Size do
begin
ForwardBuffer[I] := ForwardBuffer[I shr 1] + 1;
Inc(I, 2);
end;
Size := W * H - 1;
GetSample := FSampler.GetSampleInt;
D := 1 shl FBlockSize;
PBlock := Point(L + D, T + D);
P1 := Point(-1, 0);
RowSize := Dst.Width;
for I := 0 to Size do
begin
P1 := GetDstCoord(P1);
P2.X := L + P1.X;
P2.Y := T + P1.Y;
AssignColor(Dst.Bits[P2.X + P2.Y * RowSize], GetSample(P2.X, P2.Y));
// Invalidate the current block
if (P2.X >= PBlock.X) or (P2.Y >= PBlock.Y) then
begin
Dst.Changed(Rect(PBlock.X - D, PBlock.Y - D, PBlock.X, PBlock.Y));
PBlock.X := P2.X + D;
PBlock.Y := P2.Y + D;
end;
end;
Dst.Changed(Rect(PBlock.X - D, PBlock.Y - D, PBlock.X, PBlock.Y));
end;
procedure TSwizzlingRasterizer.SetBlockSize(const Value: Integer);
begin
if FBlockSize <> Value then
begin
FBlockSize := Value;
Changed;
end;
end;
{ TProgressiveRasterizer }
constructor TProgressiveRasterizer.Create;
begin
inherited;
FSteps := 4;
FUpdateRows := True;
end;
procedure TProgressiveRasterizer.DoRasterize(Dst: TBitmap32;
DstRect: TRect);
var
I, J, Shift, W, H, B, Wk, Hk, X, Y: Integer;
DoUpdate: Boolean;
OnChanged: TAreaChangedEvent;
Step: Integer;
GetSample: TGetSampleInt;
begin
GetSample := FSampler.GetSampleInt;
OnChanged := Dst.OnAreaChanged;
DoUpdate := (TThreadPersistentAccess(Dst).UpdateCount = 0) and Assigned(OnChanged);
Dst.BeginUpdate;
W := DstRect.Right - DstRect.Left;
H := DstRect.Bottom - DstRect.Top;
J := DstRect.Top;
Step := 1 shl FSteps;
while J < DstRect.Bottom do
begin
I := DstRect.Left;
B := Min(J + Step, DstRect.Bottom);
while I < DstRect.Right - Step do
begin
Dst.FillRect(I, J, I + Step, B, GetSample(I, J));
Inc(I, Step);
end;
Dst.FillRect(I, J, DstRect.Right, B, GetSample(I, J));
if DoUpdate and FUpdateRows then
OnChanged(Dst, Rect(DstRect.Left, J, DstRect.Right, B), AREAINFO_RECT);
Inc(J, Step);
end;
if DoUpdate and (not FUpdateRows) then OnChanged(Dst, DstRect, AREAINFO_RECT);
Shift := FSteps;
while Step > 1 do
begin
Dec(Shift);
Step := Step div 2;
Wk := W div Step - 1;
Hk := H div Step;
for J := 0 to Hk do
begin
Y := DstRect.Top + J shl Shift;
B := Min(Y + Step, DstRect.Bottom);
if Odd(J) then
for I := 0 to Wk do
begin
X := DstRect.Left + I shl Shift;
Dst.FillRect(X, Y, X + Step, B, GetSample(X, Y));
end
else
for I := 0 to Wk do
if Odd(I) then
begin
X := DstRect.Left + I shl Shift;
Dst.FillRect(X, Y, X + Step, B, GetSample(X, Y));
end;
X := DstRect.Left + Wk shl Shift;
Dst.FillRect(X, Y, DstRect.Right, B, GetSample(X, Y));
if FUpdateRows and DoUpdate then
OnChanged(Dst, Rect(DstRect.Left, Y, DstRect.Right, B), AREAINFO_RECT);
end;
if DoUpdate and (not FUpdateRows) then OnChanged(Dst, DstRect, AREAINFO_RECT);
end;
Dst.EndUpdate;
end;
procedure TProgressiveRasterizer.SetSteps(const Value: Integer);
begin
if FSteps <> Value then
begin
FSteps := Value;
Changed;
end;
end;
procedure TProgressiveRasterizer.SetUpdateRows(const Value: Boolean);
begin
if FUpdateRows <> Value then
begin
FUpdateRows := Value;
Changed;
end;
end;
{ TTesseralRasterizer }
procedure TTesseralRasterizer.DoRasterize(Dst: TBitmap32; DstRect: TRect);
var
W, H, I: Integer;
GetSample: TGetSampleInt;
procedure SplitHorizontal(X, Y, Width, Height: Integer); forward;
procedure SplitVertical(X, Y, Width, Height: Integer);
var
HalfWidth, X2, I: Integer;
begin
HalfWidth := Width div 2;
if HalfWidth > 0 then
begin
X2 := X + HalfWidth;
for I := Y + 1 to Y + Height - 1 do
AssignColor(Dst.PixelPtr[X2, I]^, GetSample(X2, I));
Dst.Changed(Rect(X2, Y, X2 + 1, Y + Height));
SplitHorizontal(X, Y, HalfWidth, Height);
SplitHorizontal(X2, Y, Width - HalfWidth, Height);
end;
end;
procedure SplitHorizontal(X, Y, Width, Height: Integer);
var
HalfHeight, Y2, I: Integer;
begin
HalfHeight := Height div 2;
if HalfHeight > 0 then
begin
Y2 := Y + HalfHeight;
for I := X + 1 to X + Width - 1 do
AssignColor(Dst.PixelPtr[I, Y2]^, GetSample(I, Y2));
Dst.Changed(Rect(X, Y2, X + Width, Y2 + 1));
SplitVertical(X, Y, Width, HalfHeight);
SplitVertical(X, Y2, Width, Height - HalfHeight);
end;
end;
begin
GetSample := FSampler.GetSampleInt;
with DstRect do
begin
W := Right - Left;
H := Bottom - Top;
for I := Left to Right - 1 do
AssignColor(Dst.PixelPtr[I, Top]^, GetSample(I, Top));
Dst.Changed(Rect(Left, Top, Right, Top + 1));
for I := Top to Bottom - 1 do
AssignColor(Dst.PixelPtr[Left, I]^, GetSample(Left, I));
Dst.Changed(Rect(Left, Top, Left + 1, Bottom));
if W > H then
SplitVertical(Left, Top, W, H)
else
SplitHorizontal(Left, Top, W, H);
end;
end;
{ TContourRasterizer }
procedure InflateRect(const P: TPoint; var R: TRect);
begin
if P.X < R.Left then R.Left := P.X;
if P.Y < R.Top then R.Top := P.Y;
if P.X >= R.Right then R.Right := P.X + 1;
if P.Y >= R.Bottom then R.Bottom := P.Y + 1;
end;
procedure TContourRasterizer.DoRasterize(Dst: TBitmap32; DstRect: TRect);
type
TDirection = (North, East, South, West);
var
I, J, D, Diff: Integer;
C, CLast: TColor32;
P, PLast: TPoint;
GetSample: TGetSampleInt;
NewDir, Dir: TDirection;
Visited: TBooleanMap;
UpdateRect: TRect;
const
LEFT: array[TDirection] of TDirection = (West, North, East, South);
RIGHT: array[TDirection] of TDirection = (East, South, West, North);
COORDS: array[TDirection] of TPoint = ((X: 0; Y: -1), (X: 1; Y: 0), (X: 0; Y: 1), (X: -1; Y: 0));
UpdateSteps = 100;
label
MainLoop;
begin
GetSample := FSampler.GetSampleInt;
Visited := TBooleanMap.Create;
try
with DstRect do
Visited.SetSize(Right - Left, Bottom - Top);
I := 0; J := 0;
Dir := East;
NewDir := East;
PLast := Point(DstRect.Left, DstRect.Top);
CLast := GetSample(PLast.X, PLast.Y);
AssignColor(Dst.PixelPtr[PLast.X, PLast.Y]^, CLast);
UpdateRect := Rect(PLast.X, PLast.Y, PLast.X + 1, PLast.Y + 1);
while True do
begin
MainLoop:
Diff := MaxInt;
// forward
with COORDS[Dir] do P := Point(PLast.X + X, PLast.Y + Y);
if PtInRect(DstRect, P) and (not Visited[P.X, P.Y]) then
begin
C := GetSample(P.X, P.Y);
Diff := Intensity(ColorSub(C, CLast));
EMMS;
NewDir := Dir;
AssignColor(Dst.PixelPtr[P.X, P.Y]^, C);
Visited[P.X - DstRect.Left, P.Y - DstRect.Top] := True;
InflateRect(P, UpdateRect);
end;
// left
with COORDS[LEFT[Dir]] do P := Point(PLast.X + X, PLast.Y + Y);
if PtInRect(DstRect, P) and (not Visited[P.X, P.Y]) then
begin
C := GetSample(P.X, P.Y);
D := Intensity(ColorSub(C, CLast));
EMMS;
if D < Diff then
begin
NewDir := LEFT[Dir];
Diff := D;
end;
AssignColor(Dst.PixelPtr[P.X, P.Y]^, C);
Visited[P.X - DstRect.Left, P.Y - DstRect.Top] := True;
InflateRect(P, UpdateRect);
end;
// right
with COORDS[RIGHT[Dir]] do P := Point(PLast.X + X, PLast.Y + Y);
if PtInRect(DstRect, P) and (not Visited[P.X, P.Y]) then
begin
C := GetSample(P.X, P.Y);
D := Intensity(ColorSub(C, CLast));
EMMS;
if D < Diff then
begin
NewDir := RIGHT[Dir];
Diff := D;
end;
AssignColor(Dst.PixelPtr[P.X, P.Y]^, C);
Visited[P.X - DstRect.Left, P.Y - DstRect.Top] := True;
InflateRect(P, UpdateRect);
end;
if Diff = MaxInt then
begin
Dst.Changed(UpdateRect);
while J < Visited.Height do
begin
while I < Visited.Width do
begin
if not Visited[I, J] then
begin
Visited[I, J] := True;
PLast := Point(DstRect.Left + I, DstRect.Top + J);
CLast := GetSample(PLast.X, PLast.Y);
AssignColor(Dst.PixelPtr[PLast.X, PLast.Y]^, CLast);
UpdateRect := Rect(PLast.X, PLast.Y, PLast.X + 1, PLast.Y + 1);
goto MainLoop;
end;
Inc(I);
end;
I := 0;
Inc(J);
end;
Break;
end;
Dir := NewDir;
with COORDS[Dir] do PLast := Point(PLast.X + X, PLast.Y + Y);
CLast := Dst[PLast.X, PLast.Y];
end;
finally
Visited.Free;
end;
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -