- 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>
<SmartLinkUnit Value="True"/>
<Optimizations>
<OptimizationLevel Value="3"/>
<OptimizationLevel Value="0"/>
</Optimizations>
</CodeGeneration>
<Linking>

View File

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

View File

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

View File

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