- 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;
TRadarBlock = array[0..7, 0..7] of Word;
{ TMaterial }
{ TMaterial } //TODO : add ref counting
TMaterial = class(TObject)
constructor Create(AWidth, AHeight: Integer; AGraphic: TSingleImage);
@ -145,6 +145,7 @@ type
ANoDraw: Boolean; AStaticsFilter: TStaticFilter);
function GetEffectiveAltitude(ATile: TMapCell): 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 PrepareBlocks(AX1, AY1, AX2, AY2: Word);
procedure UpdateStaticsPriority(AStaticItem: TStaticItem;
@ -152,10 +153,13 @@ type
end;
TScreenState = (tsNormal, tsFiltered, tsGhost);
PDrawQuad = ^TDrawQuad;
TDrawQuad = array[0..3] of TVector2D;
PBlockInfo = ^TBlockInfo;
TBlockInfo = record
ScreenRect: TRect;
DrawQuad: PDrawQuad;
Item: TWorldItem;
HighRes: TMaterial;
LowRes: TMaterial;
@ -429,85 +433,8 @@ begin
end;
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
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];
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));
GetNormals(AX, AY, Result);
end;
function TLandscape.GetStaticBlock(AX, AY: Word): TSeperatedStaticBlock;
@ -591,6 +518,7 @@ begin
cell.TileID := ABuffer.ReadWord;
if Assigned(FOnChange) then FOnChange;
end;
//TODO : update surrounding normals
end;
procedure TLandscape.OnInsertStaticPacket(ABuffer: TEnhancedMemoryStream);
@ -838,6 +766,88 @@ begin
Result := ADefault;
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);
var
sourceBlock, targetBlock: TSeperatedStaticBlock;
@ -1031,8 +1041,8 @@ begin
if FLastBlock = current then FLastBlock := last;
if last <> nil then last^.Next := current^.Next;
if current^.Normals <> nil then
Dispose(current^.Normals);
if current^.Normals <> nil then Dispose(current^.Normals);
if current^.DrawQuad <> nil then Dispose(current^.DrawQuad);
Dispose(current);
next := nil;
@ -1062,8 +1072,8 @@ begin
next := current^.Next;
current^.Item.Locked := False;
current^.Item.OnDestroy.UnregisterEvent(@OnTileRemoved);
if current^.Normals <> nil then
Dispose(current^.Normals);
if current^.Normals <> nil then Dispose(current^.Normals);
if current^.DrawQuad <> nil then Dispose(current^.DrawQuad);
Dispose(current);
current := next;
end;
@ -1106,6 +1116,7 @@ begin
AItem.Locked := True;
AItem.OnDestroy.RegisterEvent(@OnTileRemoved);
Result^.Item := AItem;
Result^.DrawQuad := nil;
Result^.HighRes := nil;
Result^.LowRes := nil;
Result^.Normals := nil;

View File

@ -34,7 +34,7 @@ uses
ComCtrls, OpenGLContext, GL, GLU, UGameResources, ULandscape, ExtCtrls,
StdCtrls, Spin, UEnums, VirtualTrees, Buttons, UMulBlock, UWorldItem, math,
LCLIntf, UOverlayUI, UStatics, UEnhancedMemoryStream, ActnList,
ImagingClasses, dateutils, UPlatformTypes;
ImagingClasses, dateutils, UPlatformTypes, UVector;
type
@ -1656,7 +1656,6 @@ var
z: ShortInt;
mat: TMaterial;
cell: TMapCell;
west, south, east: Single;
drawX, drawY: Single;
staticItem: TStaticItem;
normals: TNormals;
@ -1996,6 +1995,16 @@ begin
end;
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
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);
@ -2007,6 +2016,63 @@ begin
frmBoundaries.tbMaxZ.Position, tbTerrain.Down, tbStatics.Down,
acNoDraw.Checked, nil); //TODO : statics filter
//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;
procedure TfrmMain.UpdateCurrentTile;

View File

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