- 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

@ -1,87 +1,98 @@
(* (*
* CDDL HEADER START * CDDL HEADER START
* *
* The contents of this file are subject to the terms of the * The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only * Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance * (the "License"). You may not use this file except in compliance
* with the License. * with the License.
* *
* You can obtain a copy of the license at * You can obtain a copy of the license at
* http://www.opensource.org/licenses/cddl1.php. * http://www.opensource.org/licenses/cddl1.php.
* See the License for the specific language governing permissions * See the License for the specific language governing permissions
* and limitations under the License. * and limitations under the License.
* *
* When distributing Covered Code, include this CDDL HEADER in each * When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at * file and include the License file at
* http://www.opensource.org/licenses/cddl1.php. If applicable, * http://www.opensource.org/licenses/cddl1.php. If applicable,
* add the following below this CDDL HEADER, with the fields enclosed * add the following below this CDDL HEADER, with the fields enclosed
* by brackets "[]" replaced with your own identifying * information: * by brackets "[]" replaced with your own identifying * information:
* Portions Copyright [yyyy] [name of copyright owner] * Portions Copyright [yyyy] [name of copyright owner]
* *
* CDDL HEADER END * CDDL HEADER END
* *
* *
* Portions Copyright 2007 Andreas Schneider * Portions Copyright 2009 Andreas Schneider
*) *)
unit UVector; unit UVector;
interface interface
uses uses
Classes; Classes;
type type
TVector = record TVector = record
X: Real; X: Real;
Y: Real; Y: Real;
Z: Real; Z: Real;
end; end;
TVector2D = record
function Vector(AX, AY, AZ: Real): TVector; X: Single;
function VectorAdd(AVector1, AVector2: TVector): TVector; Y: Single;
function VectorDot(AVector1, AVector2: TVector): TVector; end;
function VectorCross(AVector1, AVector2: TVector): TVector;
function VectorNorm(AVector: TVector): TVector; function Vector(AX, AY, AZ: Real): TVector;
function Vector(AX, AY: Single): TVector2D;
implementation function VectorAdd(AVector1, AVector2: TVector): TVector;
function VectorDot(AVector1, AVector2: TVector): TVector;
function Vector(AX, AY, AZ: Real): TVector; function VectorCross(AVector1, AVector2: TVector): TVector;
begin function VectorNorm(AVector: TVector): TVector;
Result.X := AX;
Result.Y := AY; implementation
Result.Z := AZ;
end; function Vector(AX, AY, AZ: Real): TVector;
begin
function VectorAdd(AVector1, AVector2: TVector): TVector; Result.X := AX;
begin Result.Y := AY;
Result.X := AVector1.X + AVector2.X; Result.Z := AZ;
Result.Y := AVector1.Y + AVector2.Y; end;
Result.Z := AVector1.Z + AVector2.Z;
end; function Vector(AX, AY: Single): TVector2D;
begin
function VectorDot(AVector1, AVector2: TVector): TVector; Result.X := AX;
begin Result.Y := AY;
Result.X := AVector1.X * AVector2.X; end;
Result.Y := AVector1.Y * AVector2.Y;
Result.Z := AVector1.Z * AVector2.Z; function VectorAdd(AVector1, AVector2: TVector): TVector;
end; begin
Result.X := AVector1.X + AVector2.X;
function VectorCross(AVector1, AVector2: TVector): TVector; Result.Y := AVector1.Y + AVector2.Y;
begin Result.Z := AVector1.Z + AVector2.Z;
Result.X := AVector1.Y * AVector2.Z - AVector1.Z * AVector2.Y; end;
Result.Y := AVector1.Z * AVector2.X - AVector1.X * AVector2.Z;
Result.Z := AVector1.X * AVector2.Y - AVector1.Y * AVector2.X; function VectorDot(AVector1, AVector2: TVector): TVector;
end; begin
Result.X := AVector1.X * AVector2.X;
function VectorNorm(AVector: TVector): TVector; Result.Y := AVector1.Y * AVector2.Y;
var Result.Z := AVector1.Z * AVector2.Z;
abs: Real; end;
begin
abs := Sqrt(AVector.X * AVector.X + AVector.Y * AVector.Y + AVector.Z * AVector.Z); function VectorCross(AVector1, AVector2: TVector): TVector;
Result.X := AVector.X / abs; begin
Result.Y := AVector.Y / abs; Result.X := AVector1.Y * AVector2.Z - AVector1.Z * AVector2.Y;
Result.Z := AVector.Z / abs; Result.Y := AVector1.Z * AVector2.X - AVector1.X * AVector2.Z;
end; Result.Z := AVector1.X * AVector2.Y - AVector1.Y * AVector2.X;
end;
end.
function VectorNorm(AVector: TVector): TVector;
var
abs: Real;
begin
abs := Sqrt(AVector.X * AVector.X + AVector.Y * AVector.Y + AVector.Z * AVector.Z);
Result.X := AVector.X / abs;
Result.Y := AVector.Y / abs;
Result.Z := AVector.Z / abs;
end;
end.