️ Speed up preview rendering

This commit is contained in:
Andreas Schneider 2022-07-20 20:22:42 +02:00
parent 9f66004c44
commit 6aa6496429
2 changed files with 76 additions and 44 deletions

View File

@ -322,6 +322,19 @@ type
TGhostTile = class(TStaticItem);
{ TMovableGhostTile }
TMovableGhostTile = class(TGhostTile)
private
FOriginalX: Word;
FOriginalY: Word;
FOriginalZ: ShortInt;
public
property OriginalX: Word read FOriginalX write FOriginalX;
property OriginalY: Word read FOriginalY write FOriginalY;
property OriginalZ: ShortInt read FOriginalZ write FOriginalZ;
end;
operator enumerator(AScreenBuffer: TScreenBuffer): TScreenBufferItemEnumerator;
implementation

View File

@ -368,6 +368,7 @@ type
FUoaDesigns: TUoaDesigns;
FCurrentUoaDesign: TUoaDesign;
FCurrentUoaDesignAnchor: TWorldItem;
FCurrentUoaTiles: TStaticItemList;
{ Methods }
procedure BuildTileList;
function ConfirmAction: Boolean;
@ -383,6 +384,7 @@ type
procedure LoadRandomPresets;
procedure LoadUoaDesigns;
procedure MoveBy(AOffsetX, AOffsetY: Integer); inline;
procedure MoveUoaDesign(AX, AY: Word; AZ: ShortInt);
procedure PlaceUoaDesign(AWorldItem: TWorldItem);
procedure PrepareMapCell(AMapCell: TMapCell);
procedure PrepareScreenBlock(ABlockInfo: PBlockInfo);
@ -2006,6 +2008,8 @@ end;
procedure TfrmMain.vstUoaDesignsDblClick(Sender: TObject);
var
selectedNode: PVirtualNode;
designTile: TStaticItem;
virtualTile: TMovableGhostTile;
begin
// Make sure to reset the current view first.
PreviewUoaDesign(nil);
@ -2020,7 +2024,25 @@ begin
Exit;
FreeAndNil(FCurrentUoaDesign);
FreeAndNil(FCurrentUoaTiles);
FCurrentUoaDesign := FUoaDesigns.LoadDesign(FUoaDesigns.Headers[selectedNode^.Index]);
FCurrentUoaTiles := TStaticItemList.Create(False);
for designTile in FCurrentUoaDesign.Tiles do
begin
virtualTile := TMovableGhostTile.Create(nil, nil, 0, 0);
virtualTile.X := designTile.X;
virtualTile.Y := designTile.Y;
virtualTile.Z := designTile.Z;
virtualTile.OriginalX := designTile.X;
virtualTile.OriginalY := designTile.Y;
virtualTile.OriginalZ := designTile.Z;
virtualTile.TileID := designTile.TileID;
virtualTile.Hue := designTile.Hue;
FCurrentUoaTiles.Add(virtualTile);
FVirtualTiles.Add(virtualTile);
end;
MoveUoaDesign(FX, FY, FLandscape.GetLandAlt(FX, FY, 0));
RegisterSelectionListener(@PlaceUoaDesign);
RegisterHoverListener(@PreviewUoaDesign);
@ -2328,6 +2350,39 @@ begin
UpdateCurrentTile;
end;
procedure TfrmMain.MoveUoaDesign(AX, AY: Word; AZ: ShortInt);
var
offsetX, offsetY, offsetZ, maxZ: Integer;
item: TStaticItem;
begin
maxZ := Low(Integer);
for item in FCurrentUoaDesign.Tiles do
if item.Z > maxZ then
maxZ := item.Z;
offsetX := AX - FCurrentUoaDesign.Header.Width div 2;
offsetY := AY - FCurrentUoaDesign.Header.Height div 2;
offsetZ := EnsureRange(AZ, -128, 127);
if offsetX < 0 then offsetX := 0;
if offsetX + FCurrentUoaDesign.Header.Width > FLandscape.CellWidth then
offsetX := FLandscape.CellWidth - FCurrentUoaDesign.Header.Width;
if offsetY < 0 then offsetY := 0;
if offsetY + FCurrentUoaDesign.Header.Height > FLandscape.CellHeight then
offsetY := FLandscape.CellHeight - FCurrentUoaDesign.Header.Height;
if offsetZ + maxZ > 127 then
offsetZ := 127 - maxZ;
for item in FCurrentUoaTiles do
begin
item.X := TMovableGhostTile(item).OriginalX + offsetX;
item.Y := TMovableGhostTile(item).OriginalY + offsetY;
item.Z := TMovableGhostTile(item).OriginalZ + offsetZ;
end;
InvalidateScreenBuffer;
end;
procedure TfrmMain.PlaceUoaDesign(AWorldItem: TWorldItem);
var
selectedNode: PVirtualNode;
@ -2338,6 +2393,7 @@ begin
UnregisterSelectionListener(@PlaceUoaDesign);
UnregisterHoverListener(@PreviewUoaDesign);
FreeAndNil(FCurrentUoaDesign);
FreeAndNil(FCurrentUoaTiles);
FCurrentUoaDesignAnchor := nil;
vstUoaDesigns.Enabled := True;
btnCancelUOAPlacement.Visible := False;
@ -2637,59 +2693,20 @@ begin
end;
procedure TfrmMain.PreviewUoaDesign(AWorldItem: TWorldItem);
var
offsetX, offsetY, offsetZ: Integer;
newX, newY, newZ: Integer;
i: Integer;
designTile, virtualTile: TStaticItem;
blockInfo: PBlockInfo;
begin
// If nothing has changed, we can keep this short.
if FCurrentUoaDesignAnchor = AWorldItem then
Exit;
FCurrentUoaDesignAnchor := AWorldItem;
// No design selected? Well then.
if FCurrentUoaDesign = nil then
Exit;
for i := FVirtualTiles.Count - 1 downto 0 do
begin
if FVirtualTiles[i] is TGhostTile then
begin
FScreenBuffer.Delete(FVirtualTiles[i]);
FVirtualTiles.Delete(i);
end;
end;
if AWorldItem = nil then
Exit;
offsetX := AWorldItem.X - FCurrentUoaDesign.Header.Width div 2;
offsetY := AWorldItem.Y - FCurrentUoaDesign.Header.Height div 2;
offsetZ := AWorldItem.Z;
for designTile in FCurrentUoaDesign.Tiles do
begin
newX := designTile.X + offsetX;
newY := designTile.Y + offsetY;
newZ := designTile.Z + offsetZ;
if (newX < 0) or (newX >= FLandscape.CellWidth) or
(newY < 0) or (newY >= FLandscape.CellHeight) or
(newZ < -128) or (newZ > 127) then
// We can't render this tile. Skip it.
continue;
virtualTile := TGhostTile.Create(nil, nil, 0, 0);
virtualTile.X := newX;
virtualTile.Y := newY;
virtualTile.Z := newZ;
virtualTile.TileID := designTile.TileID;
virtualTile.Hue := designTile.Hue;
FVirtualTiles.Add(virtualTile);
end;
InvalidateScreenBuffer;
MoveUoaDesign(AWorldItem.X, AWorldItem.Y, AWorldItem.Z);
end;
procedure TfrmMain.Render;
@ -3406,7 +3423,9 @@ begin
// If the current tile is nil, but we still have a selected tile, the
// procedure is pointless - the selection should stay intact.
if (CurrentTile <> nil) or (SelectedTile = nil) then
// Same if we are currently placing a UOA design, since we reuse the virtual
// tile and just update its position.
if ((CurrentTile <> nil) or (SelectedTile = nil)) and (FCurrentUoaTiles = nil) then
begin
if CurrentTile = nil then
selectedRect := Rect(-1, -1, -1, -1)