- Added screen buffer pre processing (prepare materials and normals)

- Added 2D Vector to store the points for drawing terrain
- Added additional GetNormals function to TLandscape to fill an existing array
This commit is contained in:
Andreas Schneider 2009-05-17 22:06:42 +02:00
parent fee66eada8
commit 561104a924
3 changed files with 260 additions and 172 deletions

View File

@ -43,7 +43,7 @@ type
PRadarBlock = ^TRadarBlock; PRadarBlock = ^TRadarBlock;
TRadarBlock = array[0..7, 0..7] of Word; TRadarBlock = array[0..7, 0..7] of Word;
{ TMaterial } { TMaterial } //TODO : add ref counting
TMaterial = class(TObject) TMaterial = class(TObject)
constructor Create(AWidth, AHeight: Integer; AGraphic: TSingleImage); constructor Create(AWidth, AHeight: Integer; AGraphic: TSingleImage);
@ -145,6 +145,7 @@ type
ANoDraw: Boolean; AStaticsFilter: TStaticFilter); ANoDraw: Boolean; AStaticsFilter: TStaticFilter);
function GetEffectiveAltitude(ATile: TMapCell): ShortInt; function GetEffectiveAltitude(ATile: TMapCell): ShortInt;
function GetLandAlt(AX, AY: Word; ADefault: ShortInt): ShortInt; function GetLandAlt(AX, AY: Word; ADefault: ShortInt): ShortInt;
procedure GetNormals(AX, AY: Word; var ANormals: TNormals);
procedure MoveStatic(AStatic: TStaticItem; AX, AY: Word); procedure MoveStatic(AStatic: TStaticItem; AX, AY: Word);
procedure PrepareBlocks(AX1, AY1, AX2, AY2: Word); procedure PrepareBlocks(AX1, AY1, AX2, AY2: Word);
procedure UpdateStaticsPriority(AStaticItem: TStaticItem; procedure UpdateStaticsPriority(AStaticItem: TStaticItem;
@ -152,10 +153,13 @@ type
end; end;
TScreenState = (tsNormal, tsFiltered, tsGhost); TScreenState = (tsNormal, tsFiltered, tsGhost);
PDrawQuad = ^TDrawQuad;
TDrawQuad = array[0..3] of TVector2D;
PBlockInfo = ^TBlockInfo; PBlockInfo = ^TBlockInfo;
TBlockInfo = record TBlockInfo = record
ScreenRect: TRect; ScreenRect: TRect;
DrawQuad: PDrawQuad;
Item: TWorldItem; Item: TWorldItem;
HighRes: TMaterial; HighRes: TMaterial;
LowRes: TMaterial; LowRes: TMaterial;
@ -429,85 +433,8 @@ begin
end; end;
function TLandscape.GetNormals(AX, AY: Word): TNormals; function TLandscape.GetNormals(AX, AY: Word): TNormals;
var
cells: array[0..2, 0..2] of TNormals;
north, west, south, east: TVector;
i, j: Integer;
function GetPlainNormals(X, Y: SmallInt): TNormals;
var
cell: TMapCell;
north, west, south, east: ShortInt;
u, v: TVector;
begin
cell := GetMapCell(X, Y);
if Assigned(cell) then
begin
north := cell.Altitude;
west := GetLandAlt(cell.X, cell.Y + 1, north);
south := GetLandAlt(cell.X + 1, cell.Y + 1, north);
east := GetLandAlt(cell.X + 1, cell.Y, north);
end else
begin
north := 0;
west := 0;
east := 0;
south := 0;
end;
if (north = west) and (west = east) and (north = south) then
begin
Result[0] := Vector(0, 0, 1);
Result[1] := Vector(0, 0, 1);
Result[2] := Vector(0, 0, 1);
Result[3] := Vector(0, 0, 1);
end else
begin
u := Vector(-22, 22, (north - east) * 4);
v := Vector(-22, -22, (west - north) * 4);
Result[0] := VectorNorm(VectorCross(u, v));
u := Vector(22, 22, (east - south) * 4);
v := Vector(-22, 22, (north - east) * 4);
Result[1] := VectorNorm(VectorCross(u, v));
u := Vector(22, -22, (south - west) * 4);
v := Vector(22, 22, (east - south) * 4);
Result[2] := VectorNorm(VectorCross(u, v));
u := Vector(-22, -22, (west - north) * 4);
v := Vector(22, -22, (south - west) * 4);
Result[3] := VectorNorm(VectorCross(u, v));
end;
end;
begin begin
for i := 0 to 2 do GetNormals(AX, AY, Result);
for j := 0 to 2 do
cells[i, j] := GetPlainNormals(AX - 1 + i, AY - 1 + j);
north := cells[0, 0][2];
west := cells[0, 1][1];
east := cells[1, 0][3];
south := cells[1, 1][0];
Result[0] := VectorNorm(VectorAdd(VectorAdd(VectorAdd(north, west), east), south));
north := cells[1, 0][2];
west := cells[1, 1][1];
east := cells[2, 0][3];
south := cells[2, 1][0];
Result[1] := VectorNorm(VectorAdd(VectorAdd(VectorAdd(north, west), east), south));
north := cells[1, 1][2];
west := cells[1, 2][1];
east := cells[2, 1][3];
south := cells[2, 2][0];
Result[2] := VectorNorm(VectorAdd(VectorAdd(VectorAdd(north, west), east), south));
north := cells[0, 1][2];
west := cells[0, 2][1];
east := cells[1, 1][3];
south := cells[1, 2][0];
Result[3] := VectorNorm(VectorAdd(VectorAdd(VectorAdd(north, west), east), south));
end; end;
function TLandscape.GetStaticBlock(AX, AY: Word): TSeperatedStaticBlock; function TLandscape.GetStaticBlock(AX, AY: Word): TSeperatedStaticBlock;
@ -591,6 +518,7 @@ begin
cell.TileID := ABuffer.ReadWord; cell.TileID := ABuffer.ReadWord;
if Assigned(FOnChange) then FOnChange; if Assigned(FOnChange) then FOnChange;
end; end;
//TODO : update surrounding normals
end; end;
procedure TLandscape.OnInsertStaticPacket(ABuffer: TEnhancedMemoryStream); procedure TLandscape.OnInsertStaticPacket(ABuffer: TEnhancedMemoryStream);
@ -838,6 +766,88 @@ begin
Result := ADefault; Result := ADefault;
end; end;
procedure TLandscape.GetNormals(AX, AY: Word; var ANormals: TNormals);
var
cells: array[0..2, 0..2] of TNormals;
north, west, south, east: TVector;
i, j: Integer;
function GetPlainNormals(X, Y: SmallInt): TNormals;
var
cell: TMapCell;
north, west, south, east: ShortInt;
u, v: TVector;
begin
cell := GetMapCell(X, Y);
if Assigned(cell) then
begin
north := cell.Altitude;
west := GetLandAlt(cell.X, cell.Y + 1, north);
south := GetLandAlt(cell.X + 1, cell.Y + 1, north);
east := GetLandAlt(cell.X + 1, cell.Y, north);
end else
begin
north := 0;
west := 0;
east := 0;
south := 0;
end;
if (north = west) and (west = east) and (north = south) then
begin
ANormals[0] := Vector(0, 0, 1);
ANormals[1] := Vector(0, 0, 1);
ANormals[2] := Vector(0, 0, 1);
ANormals[3] := Vector(0, 0, 1);
end else
begin
u := Vector(-22, 22, (north - east) * 4);
v := Vector(-22, -22, (west - north) * 4);
ANormals[0] := VectorNorm(VectorCross(u, v));
u := Vector(22, 22, (east - south) * 4);
v := Vector(-22, 22, (north - east) * 4);
ANormals[1] := VectorNorm(VectorCross(u, v));
u := Vector(22, -22, (south - west) * 4);
v := Vector(22, 22, (east - south) * 4);
ANormals[2] := VectorNorm(VectorCross(u, v));
u := Vector(-22, -22, (west - north) * 4);
v := Vector(22, -22, (south - west) * 4);
ANormals[3] := VectorNorm(VectorCross(u, v));
end;
end;
begin
for i := 0 to 2 do
for j := 0 to 2 do
cells[i, j] := GetPlainNormals(AX - 1 + i, AY - 1 + j);
north := cells[0, 0][2];
west := cells[0, 1][1];
east := cells[1, 0][3];
south := cells[1, 1][0];
ANormals[0] := VectorNorm(VectorAdd(VectorAdd(VectorAdd(north, west), east), south));
north := cells[1, 0][2];
west := cells[1, 1][1];
east := cells[2, 0][3];
south := cells[2, 1][0];
ANormals[1] := VectorNorm(VectorAdd(VectorAdd(VectorAdd(north, west), east), south));
north := cells[1, 1][2];
west := cells[1, 2][1];
east := cells[2, 1][3];
south := cells[2, 2][0];
ANormals[2] := VectorNorm(VectorAdd(VectorAdd(VectorAdd(north, west), east), south));
north := cells[0, 1][2];
west := cells[0, 2][1];
east := cells[1, 1][3];
south := cells[1, 2][0];
ANormals[3] := VectorNorm(VectorAdd(VectorAdd(VectorAdd(north, west), east), south));
end;
procedure TLandscape.MoveStatic(AStatic: TStaticItem; AX, AY: Word); procedure TLandscape.MoveStatic(AStatic: TStaticItem; AX, AY: Word);
var var
sourceBlock, targetBlock: TSeperatedStaticBlock; sourceBlock, targetBlock: TSeperatedStaticBlock;
@ -1031,8 +1041,8 @@ begin
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 if current^.Normals <> nil then Dispose(current^.Normals);
Dispose(current^.Normals); if current^.DrawQuad <> nil then Dispose(current^.DrawQuad);
Dispose(current); Dispose(current);
next := nil; next := nil;
@ -1062,8 +1072,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 if current^.Normals <> nil then Dispose(current^.Normals);
Dispose(current^.Normals); if current^.DrawQuad <> nil then Dispose(current^.DrawQuad);
Dispose(current); Dispose(current);
current := next; current := next;
end; end;
@ -1106,6 +1116,7 @@ begin
AItem.Locked := True; AItem.Locked := True;
AItem.OnDestroy.RegisterEvent(@OnTileRemoved); AItem.OnDestroy.RegisterEvent(@OnTileRemoved);
Result^.Item := AItem; Result^.Item := AItem;
Result^.DrawQuad := nil;
Result^.HighRes := nil; Result^.HighRes := nil;
Result^.LowRes := nil; Result^.LowRes := nil;
Result^.Normals := nil; Result^.Normals := nil;

View File

@ -34,7 +34,7 @@ uses
ComCtrls, OpenGLContext, GL, GLU, UGameResources, ULandscape, ExtCtrls, ComCtrls, OpenGLContext, GL, GLU, UGameResources, ULandscape, ExtCtrls,
StdCtrls, Spin, UEnums, VirtualTrees, Buttons, UMulBlock, UWorldItem, math, StdCtrls, Spin, UEnums, VirtualTrees, Buttons, UMulBlock, UWorldItem, math,
LCLIntf, UOverlayUI, UStatics, UEnhancedMemoryStream, ActnList, LCLIntf, UOverlayUI, UStatics, UEnhancedMemoryStream, ActnList,
ImagingClasses, dateutils, UPlatformTypes; ImagingClasses, dateutils, UPlatformTypes, UVector;
type type
@ -1656,7 +1656,6 @@ var
z: ShortInt; z: ShortInt;
mat: TMaterial; mat: TMaterial;
cell: TMapCell; cell: TMapCell;
west, south, east: Single;
drawX, drawY: Single; drawX, drawY: Single;
staticItem: TStaticItem; staticItem: TStaticItem;
normals: TNormals; normals: TNormals;
@ -1996,6 +1995,16 @@ begin
end; end;
procedure TfrmMain.RebuildScreenBuffer; procedure TfrmMain.RebuildScreenBuffer;
var
blockInfo: PBlockInfo;
item: TWorldItem;
drawX, drawY: Single;
west, south, east: Single;
z: SmallInt;
drawQuad: PDrawQuad;
staticItem: TStaticItem;
hue: THue;
staticTiledata: TStaticTiledata;
begin begin
FLandscape.PrepareBlocks((FX + FLowOffsetX) div 8, (FY + FLowOffsetY) div 8, (FX + FHighOffsetX) div 8 + 1, (FY + FHighOffsetY) div 8 + 1); 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); PrepareVirtualLayer(FDrawDistance * 2 + 1, FDrawDistance * 2 + 1);
@ -2007,6 +2016,63 @@ begin
frmBoundaries.tbMaxZ.Position, tbTerrain.Down, tbStatics.Down, frmBoundaries.tbMaxZ.Position, tbTerrain.Down, tbStatics.Down,
acNoDraw.Checked, nil); //TODO : statics filter acNoDraw.Checked, nil); //TODO : statics filter
//TODO : ghost tile //TODO : ghost tile
//Pre-process the buffer - add normals to map tiles and materials where possible
blockInfo := nil;
while FScreenBuffer.Iterate(blockInfo) do
begin
item := blockInfo^.Item;
if acFlat.Checked then
z := 0
else
z := item.Z;
if item is TMapCell then
begin
if not acFlat.Checked then
begin
west := FLandscape.GetLandAlt(item.X, item.Y + 1, z);
south := FLandscape.GetLandAlt(item.X + 1, item.Y + 1, z);
east := FLandscape.GetLandAlt(item.X + 1, item.Y, z);
if (west <> z) or (south <> z) or (east <> z) then
begin
blockInfo^.HighRes := FTextureManager.GetTexMaterial(item.TileID);
end;
end;
if blockInfo^.HighRes <> nil then
begin
New(blockInfo^.Normals);
FLandscape.GetNormals(item.X, item.Y, blockInfo^.Normals^);
New(blockInfo^.DrawQuad);
drawQuad := blockInfo^.DrawQuad;
drawQuad^[0] := Vector(drawX, drawY - z * 4);
drawQuad^[1] := Vector(drawX + 22, drawY + 22 - east * 4);
drawQuad^[2] := Vector(drawX, drawY + 44 - south * 4);
drawQuad^[3] := Vector(drawX - 22, drawY + 22 - west * 4);
end;
blockInfo^.LowRes := FTextureManager.GetArtMaterial(item.TileID);
blockInfo^.ScreenRect := Bounds(Trunc(drawX - 22), Trunc(drawY - z * 4), 44, 44);
end else
begin
staticItem := TStaticItem(item);
staticTiledata := ResMan.Tiledata.StaticTiles[staticItem.TileID];
if staticItem.Hue > 0 then
hue := ResMan.Hue.Hues[staticItem.Hue - 1]
else
hue := nil;
blockInfo^.LowRes := FTextureManager.GetArtMaterial($4000 + staticItem.TileID, hue, (staticTileData.Flags and tdfPartialHue) = tdfPartialHue);
blockInfo^.ScreenRect := Bounds(Trunc(drawX - blockInfo^.LowRes.RealWidth div 2),
Trunc(drawY + 44 - blockInfo^.LowRes.RealHeight - z * 4),
blockInfo^.LowRes.RealWidth,
Trunc(blockInfo^.LowRes.RealHeight));
end;
end;
end; end;
procedure TfrmMain.UpdateCurrentTile; procedure TfrmMain.UpdateCurrentTile;

View File

@ -21,7 +21,7 @@
* CDDL HEADER END * CDDL HEADER END
* *
* *
* Portions Copyright 2007 Andreas Schneider * Portions Copyright 2009 Andreas Schneider
*) *)
unit UVector; unit UVector;
@ -36,8 +36,13 @@ type
Y: Real; Y: Real;
Z: Real; Z: Real;
end; end;
TVector2D = record
X: Single;
Y: Single;
end;
function Vector(AX, AY, AZ: Real): TVector; function Vector(AX, AY, AZ: Real): TVector;
function Vector(AX, AY: Single): TVector2D;
function VectorAdd(AVector1, AVector2: TVector): TVector; function VectorAdd(AVector1, AVector2: TVector): TVector;
function VectorDot(AVector1, AVector2: TVector): TVector; function VectorDot(AVector1, AVector2: TVector): TVector;
function VectorCross(AVector1, AVector2: TVector): TVector; function VectorCross(AVector1, AVector2: TVector): TVector;
@ -52,6 +57,12 @@ begin
Result.Z := AZ; Result.Z := AZ;
end; end;
function Vector(AX, AY: Single): TVector2D;
begin
Result.X := AX;
Result.Y := AY;
end;
function VectorAdd(AVector1, AVector2: TVector): TVector; function VectorAdd(AVector1, AVector2: TVector): TVector;
begin begin
Result.X := AVector1.X + AVector2.X; Result.X := AVector1.X + AVector2.X;