📄 gr32_microtiles.pas
字号:
else if Dx < 0 then
begin
Dx := -Dx;
Sx := -1;
end
else // Dx = 0
begin
TempRect := MakeRect(X1, Y1, X2, Y2);
InflateArea(TempRect, LineWidth, LineWidth);
MicroTilesAddRect(MicroTiles, TempRect, RoundToWholeTiles);
Exit;
end;
if Dy > 0 then
Sy := 1
else if Dy < 0 then
begin
Dy := -Dy;
Sy := -1;
end
else // Dy = 0
begin
TempRect := MakeRect(X1, Y1, X2, Y2);
InflateArea(TempRect, LineWidth, LineWidth);
MicroTilesAddRect(MicroTiles, TempRect, RoundToWholeTiles);
Exit;
end;
X1 := X1 * FixedOne;
Y1 := Y1 * FixedOne;
Dx := Dx * FixedOne;
Dy := Dy * FixedOne;
if Dx < Dy then
begin
Swapped := True;
Swap(Dx, Dy);
end
else
Swapped := False;
Rects := Dx div MICROTILE_SIZE;
DeltaX := MICROTILE_SIZE * FixedOne;
DeltaY := FixedDiv(Dy, Rects);
if Swapped then
Swap(DeltaX, DeltaY);
DeltaX := Sx * DeltaX;
DeltaY := Sy * DeltaY;
for I := 1 to FixedCeil(Rects) do
begin
NewX := X1 + DeltaX;
NewY := Y1 + DeltaY;
TempRect := MakeRect(FixedRect(X1, Y1, NewX, NewY));
InflateArea(TempRect, LineWidth, LineWidth);
MicroTilesAddRect(MicroTiles, TempRect, RoundToWholeTiles);
X1 := NewX;
Y1 := NewY;
end;
end;
procedure MicroTilesAddRect(var MicroTiles: TMicroTiles; Rect: TRect; RoundToWholeTiles: Boolean);
var
ModLeft, ModRight, ModTop, ModBottom, Temp: Integer;
LeftTile, TopTile, RightTile, BottomTile, ColSpread, RowSpread: Integer;
CurRow, CurCol: Integer;
TilePtr, TilePtr2: PMicroTile;
begin
if MicroTiles.Count = 0 then Exit;
with Rect do
begin
TestSwap(Left, Right);
TestSwap(Top, Bottom);
if Left < 0 then Left := 0;
if Top < 0 then Top := 0;
Temp := MicroTiles.Columns shl MICROTILE_SHIFT;
if Right > Temp then Right := Temp;
Temp := MicroTiles.Rows shl MICROTILE_SHIFT;
if Bottom > Temp then Bottom := Temp;
if (Left > Right) or (Top > Bottom) then Exit;
end;
LeftTile := Rect.Left shr MICROTILE_SHIFT;
TopTile := Rect.Top shr MICROTILE_SHIFT;
RightTile := Rect.Right shr MICROTILE_SHIFT;
BottomTile := Rect.Bottom shr MICROTILE_SHIFT;
TilePtr := @MicroTiles.Tiles^[TopTile * MicroTiles.Columns + LeftTile];
if RoundToWholeTiles then
begin
for CurRow := TopTile to BottomTile do
begin
FillLongword(TilePtr^, RightTile - LeftTile + 1, MICROTILE_FULL);
Inc(TilePtr, MicroTiles.Columns);
end;
end
else
begin
// calculate number of tiles needed in columns and rows
ColSpread := ((Rect.Right + MICROTILE_SIZE) shr MICROTILE_SHIFT) -
(Rect.Left shr MICROTILE_SHIFT);
RowSpread := ((Rect.Bottom + MICROTILE_SIZE) shr MICROTILE_SHIFT) -
(Rect.Top shr MICROTILE_SHIFT);
ModLeft := Rect.Left mod MICROTILE_SIZE;
ModTop := Rect.Top mod MICROTILE_SIZE;
ModRight := Rect.Right mod MICROTILE_SIZE;
ModBottom := Rect.Bottom mod MICROTILE_SIZE;
if (ColSpread = 1) and (RowSpread = 1) then
MicroTileUnion(TilePtr^, MakeMicroTile(ModLeft, ModTop, ModRight, ModBottom))
else if ColSpread = 1 then
begin
MicroTileUnion(TilePtr^, MakeMicroTile(ModLeft, ModTop, ModRight, MICROTILE_SIZE));
Inc(TilePtr, MicroTiles.Columns);
if RowSpread > 2 then
for CurCol := TopTile + 1 to BottomTile - 1 do
begin
MicroTileUnion(TilePtr^, MakeMicroTile(ModLeft, 0, ModRight, MICROTILE_SIZE));
Inc(TilePtr, MicroTiles.Columns);
end;
MicroTileUnion(TilePtr^, MakeMicroTile(ModLeft, 0, ModRight, ModBottom));
end
else if RowSpread = 1 then
begin
MicroTileUnion(TilePtr^, MakeMicroTile(ModLeft, ModTop, MICROTILE_SIZE, ModBottom));
Inc(TilePtr);
if ColSpread > 2 then
for CurRow := LeftTile + 1 to RightTile - 1 do
begin
MicroTileUnion(TilePtr^, MakeMicroTile(0, ModTop, MICROTILE_SIZE, ModBottom));
Inc(TilePtr);
end;
MicroTileUnion(TilePtr^, MakeMicroTile(0, ModTop, ModRight, ModBottom));
end
else
begin
TilePtr2 := TilePtr;
// TOP:
// render top-left corner
MicroTileUnion(TilePtr2^, MakeMicroTile(ModLeft, ModTop, MICROTILE_SIZE, MICROTILE_SIZE));
Inc(TilePtr2);
// render top edge
if ColSpread > 2 then
for CurRow := LeftTile + 1 to RightTile - 1 do
begin
MicroTileUnion(TilePtr2^, MakeMicroTile(0, ModTop, MICROTILE_SIZE, MICROTILE_SIZE));
Inc(TilePtr2);
end;
// render top-right corner
MicroTileUnion(TilePtr2^, MakeMicroTile(0, ModTop, ModRight, MICROTILE_SIZE));
Inc(TilePtr, MicroTiles.Columns);
// INTERMEDIATE AREA:
if RowSpread > 2 then
for CurCol := TopTile + 1 to BottomTile - 1 do
begin
TilePtr2 := TilePtr;
// render left edge
MicroTileUnion(TilePtr2^, MakeMicroTile(ModLeft, 0, MICROTILE_SIZE, MICROTILE_SIZE));
Inc(TilePtr2);
// render content
if ColSpread > 2 then
begin
FillLongword(TilePtr2^, RightTile - LeftTile - 1, MICROTILE_FULL);
Inc(TilePtr2, RightTile - LeftTile - 1);
end;
// render right edge
MicroTileUnion(TilePtr2^, MakeMicroTile(0, 0, ModRight, MICROTILE_SIZE));
Inc(TilePtr, MicroTiles.Columns);
end;
TilePtr2 := TilePtr;
// BOTTOM:
// render bottom-left corner
MicroTileUnion(TilePtr2^, MakeMicroTile(ModLeft, 0, MICROTILE_SIZE, ModBottom));
Inc(TilePtr2);
// render bottom edge
if ColSpread > 2 then
for CurRow := LeftTile + 1 to RightTile - 1 do
begin
MicroTileUnion(TilePtr2^, MakeMicroTile(0, 0, MICROTILE_SIZE, ModBottom));
Inc(TilePtr2);
end;
// render bottom-right corner
MicroTileUnion(TilePtr2^, MakeMicroTile(0, 0, ModRight, ModBottom));
end;
end;
with MicroTiles.BoundsUsedTiles do
begin
if LeftTile < Left then Left := LeftTile;
if TopTile < Top then Top := TopTile;
if RightTile > Right then Right := RightTile;
if BottomTile > Bottom then Bottom := BottomTile;
end;
end;
procedure _MicroTilesUnion(var DstTiles: TMicroTiles; const SrcTiles: TMicroTiles);
var
SrcTilePtr, DstTilePtr: PMicroTile;
SrcTilePtr2, DstTilePtr2: PMicroTile;
X, Y: Integer;
SrcLeft, SrcTop, SrcRight, SrcBottom: Integer;
SrcTile: TMicroTile;
begin
SrcTilePtr := @SrcTiles.Tiles^[SrcTiles.BoundsUsedTiles.Top * SrcTiles.Columns + SrcTiles.BoundsUsedTiles.Left];
DstTilePtr := @DstTiles.Tiles^[SrcTiles.BoundsUsedTiles.Top * DstTiles.Columns + SrcTiles.BoundsUsedTiles.Left];
for Y := SrcTiles.BoundsUsedTiles.Top to SrcTiles.BoundsUsedTiles.Bottom do
begin
SrcTilePtr2 := SrcTilePtr;
DstTilePtr2 := DstTilePtr;
for X := SrcTiles.BoundsUsedTiles.Left to SrcTiles.BoundsUsedTiles.Right do
begin
SrcTile := SrcTilePtr2^;
SrcLeft := SrcTile shr 24;
SrcTop := (SrcTile and $FF0000) shr 16;
SrcRight := (SrcTile and $FF00) shr 8;
SrcBottom := SrcTile and $FF;
if (DstTilePtr2^ <> MICROTILE_FULL) and (SrcTilePtr2^ <> MICROTILE_EMPTY) and
(SrcRight - SrcLeft <> 0) and (SrcBottom - SrcTop <> 0) then
begin
if (DstTilePtr2^ = MICROTILE_EMPTY) or (SrcTilePtr2^ = MICROTILE_FULL) then
DstTilePtr2^ := SrcTilePtr2^
else
DstTilePtr2^ := Min(DstTilePtr2^ shr 24, SrcLeft) shl 24 or
Min(DstTilePtr2^ shr 16 and $FF, SrcTop) shl 16 or
Max(DstTilePtr2^ shr 8 and $FF, SrcRight) shl 8 or
Max(DstTilePtr2^ and $FF, SrcBottom);
end;
Inc(DstTilePtr2);
Inc(SrcTilePtr2);
end;
Inc(DstTilePtr, DstTiles.Columns);
Inc(SrcTilePtr, SrcTiles.Columns);
end;
end;
procedure M_MicroTilesUnion(var DstTiles: TMicroTiles; const SrcTiles: TMicroTiles);
var
SrcTilePtr, DstTilePtr: PMicroTile;
SrcTilePtr2, DstTilePtr2: PMicroTile;
X, Y: Integer;
SrcLeft, SrcTop, SrcRight, SrcBottom: Integer;
begin
SrcTilePtr := @SrcTiles.Tiles^[SrcTiles.BoundsUsedTiles.Top * SrcTiles.Columns + SrcTiles.BoundsUsedTiles.Left];
DstTilePtr := @DstTiles.Tiles^[SrcTiles.BoundsUsedTiles.Top * DstTiles.Columns + SrcTiles.BoundsUsedTiles.Left];
asm
MOV ECX, $FFFF // Mask
db $0F,$6E,$C1 /// MOVD MM0, ECX
db $0F,$6F,$E0 /// MOVQ MM4, MM0
db $0F,$72,$F4,$10 /// PSLLD MM4, 16 // shift mask left by 16 bits
end;
for Y := SrcTiles.BoundsUsedTiles.Top to SrcTiles.BoundsUsedTiles.Bottom do
begin
SrcTilePtr2 := SrcTilePtr;
DstTilePtr2 := DstTilePtr;
for X := SrcTiles.BoundsUsedTiles.Left to SrcTiles.BoundsUsedTiles.Right do
begin
SrcLeft := SrcTilePtr2^ shr 24;
SrcTop := (SrcTilePtr2^ and $FF0000) shr 16;
SrcRight := (SrcTilePtr2^ and $FF00) shr 8;
SrcBottom := SrcTilePtr2^ and $FF;
if (DstTilePtr2^ <> MICROTILE_FULL) and (SrcTilePtr2^ <> MICROTILE_EMPTY) and
(SrcRight - SrcLeft <> 0) and (SrcBottom - SrcTop <> 0) then
begin
if (DstTilePtr2^ = MICROTILE_EMPTY) or (SrcTilePtr2^ = MICROTILE_FULL) then
DstTilePtr2^ := SrcTilePtr2^
else
asm
MOV EAX, [DstTilePtr2]
db $0F,$6E,$10 /// MOVD MM2, [EAX]
MOV ECX, [SrcTilePtr2]
db $0F,$6E,$09 /// MOVD MM1, [ECX]
db $0F,$6F,$D9 /// MOVQ MM3, MM1
db $0F,$DA,$CA /// PMINUB MM1, MM2
db $0F,$DB,$CC /// PAND MM1, MM4
db $0F,$DE,$D3 /// PMAXUB MM2, MM3
db $0F,$DB,$D0 /// PAND MM2, MM0
db $0F,$EB,$CA /// POR MM1, MM2
db $0F,$7E,$08 /// MOVD [EAX], MM1
end;
end;
Inc(DstTilePtr2);
Inc(SrcTilePtr2);
end;
Inc(DstTilePtr, DstTiles.Columns);
Inc(SrcTilePtr, SrcTiles.Columns);
end;
asm
db $0F,$77 /// EMMS
end;
end;
procedure MicroTilesUnion(var DstTiles: TMicroTiles; const SrcTiles: TMicroTiles; RoundToWholeTiles: Boolean);
var
SrcTilePtr, DstTilePtr: PMicroTile;
SrcTilePtr2, DstTilePtr2: PMicroTile;
X, Y: Integer;
SrcLeft, SrcTop, SrcRight, SrcBottom: Integer;
begin
if SrcTiles.Count = 0 then Exit;
if RoundToWholeTiles then
begin
SrcTilePtr := @SrcTiles.Tiles^[SrcTiles.BoundsUsedTiles.Top * SrcTiles.Columns + SrcTiles.BoundsUsedTiles.Left];
DstTilePtr := @DstTiles.Tiles^[SrcTiles.BoundsUsedTiles.Top * DstTiles.Columns + SrcTiles.BoundsUsedTiles.Left];
for Y := SrcTiles.BoundsUsedTiles.Top to SrcTiles.BoundsUsedTiles.Bottom do
begin
SrcTilePtr2 := SrcTilePtr;
DstTilePtr2 := DstTilePtr;
for X := SrcTiles.BoundsUsedTiles.Left to SrcTiles.BoundsUsedTiles.Right do
begin
SrcLeft := SrcTilePtr2^ shr 24;
SrcTop := (SrcTilePtr2^ and $FF0000) shr 16;
SrcRight := (SrcTilePtr2^ and $FF00) shr 8;
SrcBottom := SrcTilePtr2^ and $FF;
if (DstTilePtr2^ <> MICROTILE_FULL) and (SrcTilePtr2^ <> MICROTILE_EMPTY) and
(SrcRight - SrcLeft <> 0) and (SrcBottom - SrcTop <> 0) then
DstTilePtr2^ := MICROTILE_FULL;
Inc(DstTilePtr2);
Inc(SrcTilePtr2);
end;
Inc(DstTilePtr, DstTiles.Columns);
Inc(SrcTilePtr, SrcTiles.Columns);
end
end
else
MicroTilesU(DstTiles, SrcTiles);
with DstTiles.BoundsUsedTiles do
begin
if SrcTiles.BoundsUsedTiles.Left < Left then Left := SrcTiles.BoundsUsedTiles.Left;
if SrcTiles.BoundsUsedTiles.Top < Top then Top := SrcTiles.BoundsUsedTiles.Top;
if SrcTiles.BoundsUsedTiles.Right > Right then Right := SrcTiles.BoundsUsedTiles.Right;
if SrcTiles.BoundsUsedTiles.Bottom > Bottom then Bottom := SrcTiles.BoundsUsedTiles.Bottom;
end;
end;
function MicroTilesCalcRects(const MicroTiles: TMicroTiles; DstRects: TRectList;
CountOnly, RoundToWholeTiles: Boolean): Integer;
begin
Result := MicroTilesCalcRects(MicroTiles, DstRects, MicroTiles.BoundsRect, CountOnly);
end;
function MicroTilesCalcRects(const MicroTiles: TMicroTiles; DstRects: TRectList;
const Clip: TRect; CountOnly, RoundToWholeTiles: Boolean): Integer;
var
Rects: Array Of TRect;
Rect: PRect;
CombLUT: Array Of Integer;
StartIndex: Integer;
CurTile, TempTile: TMicroTile;
Temp: Integer;
NewLeft, NewTop, NewRight, NewBottom: Integer;
CurCol, CurRow, I, RectsCount: Integer;
begin
Result := 0;
if (MicroTiles.Count = 0) or
(MicroTiles.BoundsUsedTiles.Right - MicroTiles.BoundsUsedTiles.Left < 0) or
(MicroTiles.BoundsUsedTiles.Bottom - MicroTiles.BoundsUsedTiles.Top < 0) then Exit;
SetLength(Rects, MicroTiles.Columns * MicroTiles.Rows);
SetLength(CombLUT, MicroTiles.Columns * MicroTiles.Rows);
FillLongword(CombLUT[0], Length(CombLUT), Cardinal(-1));
I := 0;
RectsCount := 0;
if not RoundToWholeTiles then
for CurRow := 0 to MicroTiles.Rows - 1 do
begin
CurCol := 0;
while CurCol < MicroTiles.Columns do
begin
CurTile := MicroTiles.Tiles[I];
if CurTile <> MICROTILE_EMPTY then
begin
Temp := CurRow shl MICROTILE_SHIFT;
NewTop := Constrain(Temp + CurTile shr 16 and $FF, Clip.Top, Clip.Bottom);
NewBottom := Constrain(Temp + CurTile and $FF, Clip.Top, Clip.Bottom);
NewLeft := Constrain(CurCol shl MICROTILE_SHIFT + CurTile shr 24, Clip.Left, Clip.Right);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -