- Refined state handling for TBlockInfo

- Added caching of normals into TBlockInfo
- Added differentiation for low and high res materials to TBlockInfo
- Removed draw list clearing from FillDrawList
- Changed TScreenBuffer.Store to return a reference to the stored TBlockInfo
- Added missing ; to GetSerial
- More cleanups in ULandscape.pas
- Moved several local variables of TfrmMain.Render into TfrmMain members
- Moved several size related variable initializations from Render into OnResize
- Extracted GetDrawOffset
- Added seperate RebuildScreenBuffer
This commit is contained in:
Andreas Schneider 2009-05-17 15:32:51 +02:00
parent 61db743ee5
commit fee66eada8
4 changed files with 124 additions and 106 deletions

View File

@ -248,7 +248,7 @@
<CodeGeneration> <CodeGeneration>
<SmartLinkUnit Value="True"/> <SmartLinkUnit Value="True"/>
<Optimizations> <Optimizations>
<OptimizationLevel Value="3"/> <OptimizationLevel Value="0"/>
</Optimizations> </Optimizations>
</CodeGeneration> </CodeGeneration>
<Linking> <Linking>

View File

@ -38,6 +38,7 @@ uses
UCacheManager; UCacheManager;
type type
PNormals = ^TNormals;
TNormals = array[0..3] of TVector; TNormals = array[0..3] of TVector;
PRadarBlock = ^TRadarBlock; PRadarBlock = ^TRadarBlock;
TRadarBlock = array[0..7, 0..7] of Word; TRadarBlock = array[0..7, 0..7] of Word;
@ -149,12 +150,17 @@ type
procedure UpdateStaticsPriority(AStaticItem: TStaticItem; procedure UpdateStaticsPriority(AStaticItem: TStaticItem;
APrioritySolver: Integer); APrioritySolver: Integer);
end; end;
TScreenState = (tsNormal, tsFiltered, tsGhost);
PBlockInfo = ^TBlockInfo; PBlockInfo = ^TBlockInfo;
TBlockInfo = record TBlockInfo = record
ScreenRect: TRect; ScreenRect: TRect;
Item: TWorldItem; Item: TWorldItem;
Material: TMaterial; HighRes: TMaterial;
Ghost: Boolean; LowRes: TMaterial;
Normals: PNormals;
State: TScreenState;
Next: PBlockInfo; Next: PBlockInfo;
end; end;
@ -188,8 +194,7 @@ type
procedure Clear; override; procedure Clear; override;
function Find(AScreenPosition: TPoint): PBlockInfo; function Find(AScreenPosition: TPoint): PBlockInfo;
function GetSerial: Cardinal; function GetSerial: Cardinal;
procedure Store(AItem: TWorldItem; AMaterial: TMaterial = nil; function Store(AItem: TWorldItem): PBlockInfo;
AGhost: Boolean = False);
{ Events } { Events }
procedure OnTileRemoved(ATile: TMulBlock); procedure OnTileRemoved(ATile: TMulBlock);
end; end;
@ -772,7 +777,6 @@ var
drawStatics: TList; drawStatics: TList;
i, x, y: Integer; i, x, y: Integer;
begin begin
ADrawList.Clear;
for x := AX to AX + AWidth do for x := AX to AX + AWidth do
for y := AY to AY + AWidth do for y := AY to AY + AWidth do
begin begin
@ -1026,10 +1030,15 @@ begin
if FFirst = current then FFirst := current^.Next; if FFirst = current then FFirst := current^.Next;
if FLastBlock = current then FLastBlock := last; if FLastBlock = current then FLastBlock := last;
if last <> nil then last^.Next := current^.Next; if last <> nil then last^.Next := current^.Next;
if current^.Normals <> nil then
Dispose(current^.Normals);
Dispose(current); Dispose(current);
next := nil; next := nil;
end else end else
next := current^.Next; next := current^.Next;
last := current; last := current;
current := next; current := next;
end; end;
@ -1053,6 +1062,8 @@ begin
next := current^.Next; next := current^.Next;
current^.Item.Locked := False; current^.Item.Locked := False;
current^.Item.OnDestroy.UnregisterEvent(@OnTileRemoved); current^.Item.OnDestroy.UnregisterEvent(@OnTileRemoved);
if current^.Normals <> nil then
Dispose(current^.Normals);
Dispose(current); Dispose(current);
current := next; current := next;
end; end;
@ -1070,8 +1081,9 @@ begin
current := FFirst; current := FFirst;
while (current <> nil) and (Result = nil) do while (current <> nil) and (Result = nil) do
begin begin
if (not current^.Ghost) and PtInRect(current^.ScreenRect, AScreenPosition) and if (current^.State = tsNormal) and
current^.Material.HitTest(AScreenPosition.x - current^.ScreenRect.Left, PtInRect(current^.ScreenRect, AScreenPosition) and
current^.LowRes.HitTest(AScreenPosition.x - current^.ScreenRect.Left,
AScreenPosition.y - current^.ScreenRect.Top) then AScreenPosition.y - current^.ScreenRect.Top) then
begin begin
Result := current; Result := current;
@ -1082,65 +1094,49 @@ end;
function TScreenBuffer.GetSerial: Cardinal; function TScreenBuffer.GetSerial: Cardinal;
begin begin
Result := FSerial Result := FSerial;
Inc(FSerial); Inc(FSerial);
end; end;
procedure TScreenBuffer.Store(AItem: TWorldItem; AMaterial: TMaterial = nil; function TScreenBuffer.Store(AItem: TWorldItem): PBlockInfo;
AGhost: Boolean = False);
var var
current, existing: PBlockInfo; current: PBlockInfo;
begin begin
New(current); New(Result);
AItem.Locked := True; AItem.Locked := True;
AItem.OnDestroy.RegisterEvent(@OnTileRemoved); AItem.OnDestroy.RegisterEvent(@OnTileRemoved);
current^.Item := AItem; Result^.Item := AItem;
current^.Material := AMaterial; Result^.HighRes := nil;
current^.Ghost := AGhost; Result^.LowRes := nil;
Result^.Normals := nil;
Result^.State := tsNormal;
if (FFirst = nil) or (CompareWorldItems(AItem, FFirst) > 0) then if (FFirst = nil) or (CompareWorldItems(AItem, FFirst) > 0) then
begin begin
current^.Next := FFirst; Result^.Next := FFirst;
if FFirst = nil then if FFirst = nil then
FLastBlock := current; FLastBlock := Result;
FFirst := current; FFirst := Result;
end else end else
begin begin
existing := FFirst; current := FFirst;
while (existing^.Next = nil) and while (current^.Next = nil) and
(CompareWorldItems(AItem, existing^.Next^.Item) > 0) do (CompareWorldItems(AItem, current^.Next^.Item) > 0) do
begin begin
existing := existing^.Next; current := current^.Next;
end; end;
if existing^.Next = nil then if current^.Next = nil then
FLastBlock := current; FLastBlock := Result;
current^.Next := existing^.Next; Result^.Next := current^.Next;
existing^.Next := current; current^.Next := Result;
end; end;
end; end;
procedure TScreenBuffer.OnTileRemoved(ATile: TMulBlock); procedure TScreenBuffer.OnTileRemoved(ATile: TMulBlock);
var
currentItem, lastItem, nextItem: PBlockInfo;
begin begin
lastItem := nil; Delete(TWorldItem(ATile));
currentItem := FFirst;
while currentItem <> nil do
begin
if currentItem^.Item = ATile then
begin
if FFirst = currentItem then FFirst := currentItem^.Next;
if FLastBlock = currentItem then FLastBlock := lastItem;
if lastItem <> nil then lastItem^.Next := currentItem^.Next;
Dispose(currentItem);
nextItem := nil;
end else
nextItem := currentItem^.Next;
lastItem := currentItem;
currentItem := nextItem;
end;
end; end;
end. end.

View File

@ -971,6 +971,7 @@ object frmMain: TfrmMain
OnMouseUp = oglGameWindowMouseUp OnMouseUp = oglGameWindowMouseUp
OnMouseWheel = oglGameWindowMouseWheel OnMouseWheel = oglGameWindowMouseWheel
OnPaint = oglGameWindowPaint OnPaint = oglGameWindowPaint
OnResize = oglGameWindowResize
end end
object pnlChatHeader: TPanel object pnlChatHeader: TPanel
Left = 0 Left = 0

View File

@ -217,6 +217,7 @@ type
procedure oglGameWindowMouseWheel(Sender: TObject; Shift: TShiftState; procedure oglGameWindowMouseWheel(Sender: TObject; Shift: TShiftState;
WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean); WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
procedure oglGameWindowPaint(Sender: TObject); procedure oglGameWindowPaint(Sender: TObject);
procedure oglGameWindowResize(Sender: TObject);
procedure pmGrabTileInfoPopup(Sender: TObject); procedure pmGrabTileInfoPopup(Sender: TObject);
procedure tbFilterMouseMove(Sender: TObject; Shift: TShiftState; X, procedure tbFilterMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer); Y: Integer);
@ -265,8 +266,16 @@ type
procedure vstLocationsSaveNode(Sender: TBaseVirtualTree; procedure vstLocationsSaveNode(Sender: TBaseVirtualTree;
Node: PVirtualNode; Stream: TStream); Node: PVirtualNode; Stream: TStream);
protected protected
{ Members }
FX: Integer; FX: Integer;
FY: Integer; FY: Integer;
FDrawDistance: Integer;
FLowOffsetX: Integer;
FLowOffsetY: Integer;
FHighOffsetX: Integer;
FHighOffsetY: Integer;
FRangeX: Integer;
FRangeY: Integer;
FLandscape: TLandscape; FLandscape: TLandscape;
FTextureManager: TLandTextureManager; FTextureManager: TLandTextureManager;
FScreenBuffer: TScreenBuffer; FScreenBuffer: TScreenBuffer;
@ -280,38 +289,44 @@ type
FRandomPresetLocation: string; FRandomPresetLocation: string;
FLastDraw: TDateTime; FLastDraw: TDateTime;
FAccessChangedListeners: array of TAccessChangedListener; FAccessChangedListeners: array of TAccessChangedListener;
procedure SetX(const AValue: Integer); { Methods }
procedure SetY(const AValue: Integer);
procedure SetCurrentTile(const AValue: TWorldItem);
procedure SetSelectedTile(const AValue: TWorldItem);
procedure SetNormalLights; inline;
procedure SetDarkLights; inline;
procedure InitRender;
procedure InitSize;
procedure Render;
procedure OnLandscapeChanged;
procedure BuildTileList; procedure BuildTileList;
procedure ProcessToolState; function CanBeModified(ATile: TWorldItem): Boolean;
procedure ProcessAccessLevel; function ConfirmAction: Boolean;
procedure UpdateCurrentTile; procedure GetDrawOffset(ARelativeX, ARelativeY: Integer; out DrawX,
procedure UpdateCurrentTile(AX, AY: Integer); DrawY: Single);
procedure TileRemoved(ATile: TMulBlock);
procedure WriteChatMessage(ASender, AMessage: string);
procedure PrepareVirtualLayer(AWidth, AHeight: Word);
procedure OnClientHandlingPacket(ABuffer: TEnhancedMemoryStream);
function GetInternalTileID(ATile: TWorldItem): Word; function GetInternalTileID(ATile: TWorldItem): Word;
function GetSelectedRect: TRect; function GetSelectedRect: TRect;
function ConfirmAction: Boolean; procedure InitRender;
function CanBeModified(ATile: TWorldItem): Boolean; procedure InitSize;
procedure PrepareVirtualLayer(AWidth, AHeight: Word);
procedure ProcessToolState;
procedure ProcessAccessLevel;
procedure RebuildScreenBuffer;
procedure Render;
procedure SetCurrentTile(const AValue: TWorldItem);
procedure SetDarkLights; inline;
procedure SetNormalLights; inline;
procedure SetSelectedTile(const AValue: TWorldItem);
procedure SetX(const AValue: Integer);
procedure SetY(const AValue: Integer);
procedure UpdateCurrentTile;
procedure UpdateCurrentTile(AX, AY: Integer);
procedure WriteChatMessage(ASender, AMessage: string);
{ Events }
procedure OnClientHandlingPacket(ABuffer: TEnhancedMemoryStream);
procedure OnLandscapeChanged;
procedure OnTileRemoved(ATile: TMulBlock);
public public
{ Fields }
property X: Integer read FX write SetX; property X: Integer read FX write SetX;
property Y: Integer read FY write SetY; property Y: Integer read FY write SetY;
property Landscape: TLandscape read FLandscape; property Landscape: TLandscape read FLandscape;
property CurrentTile: TWorldItem read FCurrentTile write SetCurrentTile; property CurrentTile: TWorldItem read FCurrentTile write SetCurrentTile;
property SelectedTile: TWorldItem read FSelectedTile write SetSelectedTile; property SelectedTile: TWorldItem read FSelectedTile write SetSelectedTile;
{ Methods }
procedure SetPos(AX, AY: Word);
procedure RegisterAccessChangedListener(AListener: TAccessChangedListener); procedure RegisterAccessChangedListener(AListener: TAccessChangedListener);
procedure SetPos(AX, AY: Word);
procedure UnregisterAccessChangedListener(AListener: TAccessChangedListener); procedure UnregisterAccessChangedListener(AListener: TAccessChangedListener);
end; end;
@ -1149,6 +1164,21 @@ begin
oglGameWindow.SwapBuffers; oglGameWindow.SwapBuffers;
end; end;
procedure TfrmMain.oglGameWindowResize(Sender: TObject);
begin
FDrawDistance := Trunc(Sqrt(oglGameWindow.Width * oglGameWindow.Width + oglGamewindow.Height * oglGamewindow.Height) / 44);
{$HINTS off}{$WARNINGS off}
if FX - FDrawDistance < 0 then FLowOffsetX := -FX else FLowOffsetX := -FDrawDistance;
if FY - FDrawDistance < 0 then FLowOffsetY := -FY else FLowOffsetY := -FDrawDistance;
if FX + FDrawDistance >= FLandscape.Width * 8 then FHighOffsetX := FLandscape.Width * 8 - FX - 1 else FHighOffsetX := FDrawDistance;
if FY + FDrawDistance >= FLandscape.Height * 8 then FHighOffsetY := FLandscape.Height * 8 - FY - 1 else FHighOffsetY := FDrawDistance;
{$HINTS on}{$WARNINGS on}
FRangeX := FHighOffsetX - FLowOffsetX;
FRangeY := FHighOffsetY - FLowOffsetY;
end;
procedure TfrmMain.pmGrabTileInfoPopup(Sender: TObject); procedure TfrmMain.pmGrabTileInfoPopup(Sender: TObject);
begin begin
mnuGrabHue.Enabled := CurrentTile is TStaticItem; mnuGrabHue.Enabled := CurrentTile is TStaticItem;
@ -1559,19 +1589,19 @@ end;
procedure TfrmMain.SetCurrentTile(const AValue: TWorldItem); procedure TfrmMain.SetCurrentTile(const AValue: TWorldItem);
begin begin
if FCurrentTile <> nil then if FCurrentTile <> nil then
FCurrentTile.OnDestroy.UnregisterEvent(@TileRemoved); FCurrentTile.OnDestroy.UnregisterEvent(@OnTileRemoved);
FCurrentTile := AValue; FCurrentTile := AValue;
if FCurrentTile <> nil then if FCurrentTile <> nil then
FCurrentTile.OnDestroy.RegisterEvent(@TileRemoved); FCurrentTile.OnDestroy.RegisterEvent(@OnTileRemoved);
end; end;
procedure TfrmMain.SetSelectedTile(const AValue: TWorldItem); procedure TfrmMain.SetSelectedTile(const AValue: TWorldItem);
begin begin
if FSelectedTile <> nil then if FSelectedTile <> nil then
FSelectedTile.OnDestroy.UnregisterEvent(@TileRemoved); FSelectedTile.OnDestroy.UnregisterEvent(@OnTileRemoved);
FSelectedTile := AValue; FSelectedTile := AValue;
if FSelectedTile <> nil then if FSelectedTile <> nil then
FSelectedTile.OnDestroy.RegisterEvent(@TileRemoved); FSelectedTile.OnDestroy.RegisterEvent(@OnTileRemoved);
end; end;
procedure TfrmMain.SetNormalLights; procedure TfrmMain.SetNormalLights;
@ -1623,17 +1653,12 @@ end;
procedure TfrmMain.Render; procedure TfrmMain.Render;
var var
drawDistance: Integer;
lowOffX, lowOffY, highOffX, highOffY: Integer;
z: ShortInt; z: ShortInt;
mat: TMaterial; mat: TMaterial;
cell: TMapCell; cell: TMapCell;
west, south, east: Single; west, south, east: Single;
drawX, drawY: Single; drawX, drawY: Single;
draw: TList;
staticItem: TStaticItem; staticItem: TStaticItem;
i, j, k: Integer;
startOffX, endOffX, rangeX, rangeY: Integer;
normals: TNormals; normals: TNormals;
staticTileData: TStaticTileData; staticTileData: TStaticTileData;
hue: THue; hue: THue;
@ -1644,47 +1669,24 @@ var
staticsFilter: TStaticFilter; staticsFilter: TStaticFilter;
editing: Boolean; editing: Boolean;
intensity: GLfloat; intensity: GLfloat;
blockInfo: PBlockInfo;
item: TWorldItem; item: TWorldItem;
procedure GetMapDrawOffset(x, y: Integer; out drawX, drawY: Single);
begin begin
drawX := (oglGameWindow.Width div 2) + (x - y) * 22;
drawY := (oglGamewindow.Height div 2) + (x + y) * 22;
end;
begin
drawDistance := Trunc(Sqrt(oglGameWindow.Width * oglGameWindow.Width + oglGamewindow.Height * oglGamewindow.Height) / 44);
{$HINTS off}{$WARNINGS off}
if FX - drawDistance < 0 then lowOffX := -FX else lowOffX := -drawDistance;
if FY - drawDistance < 0 then lowOffY := -FY else lowOffY := -drawDistance;
if FX + drawDistance >= FLandscape.Width * 8 then highOffX := FLandscape.Width * 8 - FX - 1 else highOffX := drawDistance;
if FY + drawDistance >= FLandscape.Height * 8 then highOffY := FLandscape.Height * 8 - FY - 1 else highOffY := drawDistance;
{$HINTS on}{$WARNINGS on}
FLandscape.PrepareBlocks((FX + lowOffX) div 8, (FY + lowOffY) div 8, (FX + highOffX) div 8 + 1, (FY + highOffY) div 8 + 1);
PrepareVirtualLayer(drawDistance * 2 + 1, drawDistance * 2 + 1);
tileRect := GetSelectedRect; tileRect := GetSelectedRect;
FScreenBuffer.Clear;
rangeX := highOffX - lowOffX; RebuildScreenBuffer;
rangeY := highOffY - lowOffY;
{if acFilter.Checked then {if acFilter.Checked then
staticsFilter := @frmFilter.Filter staticsFilter := @frmFilter.Filter
else else
staticsFilter := nil;} //TODO : update list on change staticsFilter := nil;} //TODO : update list on change}
{draw := FLandscape.GetDrawList(FX + lowOffX, FY + lowOffY, rangeX, rangeY, blockInfo := nil;
frmBoundaries.tbMinZ.Position, frmBoundaries.tbMaxZ.Position, while FScreenBuffer.Iterate(blockInfo) do
nil, nil, tbTerrain.Down, tbStatics.Down, //TODO : ghost tile and virtual tile!
acNoDraw.Checked, nil); //TODO : statics filter!
for i := 0 to draw.Count - 1 do
begin begin
item := TWorldItem(draw[i]); item := blockInfo^.Item;
GetMapDrawOffset(item.X - FX, item.Y - FY, drawX, drawY); {GetMapDrawOffset(item.X - FX, item.Y - FY, drawX, drawY);
singleTarget := (CurrentTile <> nil) and singleTarget := (CurrentTile <> nil) and
(item.X = CurrentTile.X) and (item.X = CurrentTile.X) and
@ -1868,11 +1870,9 @@ begin
end; end;
if highlight then if highlight then
glDisable(GL_COLOR_LOGIC_OP); glDisable(GL_COLOR_LOGIC_OP);}
end; end;
draw.Free;}
FOverlayUI.Draw(oglGameWindow); FOverlayUI.Draw(oglGameWindow);
end; end;
@ -1995,6 +1995,20 @@ begin
Caption := Format('UO CentrED - [%s (%s)]', [dmNetwork.Username, GetAccessLevelString(dmNetwork.AccessLevel)]); Caption := Format('UO CentrED - [%s (%s)]', [dmNetwork.Username, GetAccessLevelString(dmNetwork.AccessLevel)]);
end; end;
procedure TfrmMain.RebuildScreenBuffer;
begin
FLandscape.PrepareBlocks((FX + FLowOffsetX) div 8, (FY + FLowOffsetY) div 8, (FX + FHighOffsetX) div 8 + 1, (FY + FHighOffsetY) div 8 + 1);
PrepareVirtualLayer(FDrawDistance * 2 + 1, FDrawDistance * 2 + 1);
FScreenBuffer.Clear;
//TODO : Virtual Layer
FLandscape.FillDrawList(FScreenBuffer, FX + FLowOffsetX, FY + FLowOffsetY,
FRangeX, FRangeY, frmBoundaries.tbMinZ.Position,
frmBoundaries.tbMaxZ.Position, tbTerrain.Down, tbStatics.Down,
acNoDraw.Checked, nil); //TODO : statics filter
//TODO : ghost tile
end;
procedure TfrmMain.UpdateCurrentTile; procedure TfrmMain.UpdateCurrentTile;
var var
localPos: TPoint; localPos: TPoint;
@ -2041,7 +2055,7 @@ begin
end; end;
end; end;
procedure TfrmMain.TileRemoved(ATile: TMulBlock); procedure TfrmMain.OnTileRemoved(ATile: TMulBlock);
begin begin
if ATile = FCurrentTile then if ATile = FCurrentTile then
FCurrentTile := nil FCurrentTile := nil
@ -2229,6 +2243,13 @@ begin
oglGameWindowMouseLeave(nil); oglGameWindowMouseLeave(nil);
end; end;
procedure TfrmMain.GetDrawOffset(ARelativeX, ARelativeY: Integer; out DrawX,
DrawY: Single);
begin
DrawX := (oglGameWindow.Width div 2) + (ARelativeX - ARelativeY) * 22;
DrawY := (oglGamewindow.Height div 2) + (ARelativeX + ARelativeY) * 22;
end;
function TfrmMain.CanBeModified(ATile: TWorldItem): Boolean; function TfrmMain.CanBeModified(ATile: TWorldItem): Boolean;
begin begin
Result := (not (ATile is TVirtualTile)) and Result := (not (ATile is TVirtualTile)) and