- Changed several OpenGL calls with their integer-equivalents (we don't use floats anyway)

- Added a "real quad" to the screenbuffer to keep track of the original terrain locations
- Added OpenGL based hit test to TScreenBuffer.Find
This commit is contained in:
Andreas Schneider 2009-12-04 15:52:27 +01:00
parent 082770f183
commit 14ab47bdf8
2 changed files with 135 additions and 56 deletions

View File

@ -201,7 +201,8 @@ type
PBlockInfo = ^TBlockInfo;
TBlockInfo = record
ScreenRect: TRect;
DrawQuad: array[0..3,0..1] of TGLfloat;
DrawQuad: array[0..3,0..1] of TGLint;
RealQuad: array[0..3,0..1] of TGLint;
Item: TWorldItem;
HighRes: TMaterial;
LowRes: TMaterial;
@ -209,6 +210,7 @@ type
State: TScreenState;
Highlighted: Boolean;
HueOverride: Boolean;
CheckRealQuad: Boolean;
Next: PBlockInfo;
end;
@ -1278,17 +1280,51 @@ end;
function TScreenBuffer.Find(AScreenPosition: TPoint): PBlockInfo;
var
current: PBlockInfo;
buff: array[0..3] of GLuint;
hits: GLint;
begin
Result := nil;
current := FShortCuts[0];
while current <> nil do //search the last matching tile
begin
if (current^.State = ssNormal) and
PtInRect(current^.ScreenRect, AScreenPosition) and
current^.LowRes.HitTest(AScreenPosition.x - current^.ScreenRect.Left,
AScreenPosition.y - current^.ScreenRect.Top) then
PtInRect(current^.ScreenRect, AScreenPosition)then
begin
Result := current;
if current^.CheckRealQuad then
begin
//OpenGL hit test
//We use the "real quad" here to prevent the draw-preview from
//intercepting with our actual tiles (which are "hidden" then).
glSelectBuffer(4, @buff[0]);
glViewport(current^.ScreenRect.Left, current^.ScreenRect.Top,
current^.ScreenRect.Right, current^.ScreenRect.Bottom);
glRenderMode(GL_SELECT);
glInitNames;
glPushName(0);
glPushMatrix;
glMatrixMode(GL_PROJECTION);
glLoadIdentity;
gluOrtho2D(AScreenPosition.x, AScreenPosition.x + 1,
AScreenPosition.y + 1, AScreenPosition.y);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity;
glBegin(GL_QUADS);
glVertex2iv(@current^.RealQuad[0]);
glVertex2iv(@current^.RealQuad[3]);
glVertex2iv(@current^.RealQuad[2]);
glVertex2iv(@current^.RealQuad[1]);
glEnd;
glPopMatrix;
glFlush;
if glRenderMode(GL_RENDER) > 0 then //glRenderMode now returns the number of hits
Result := current;
end else
if current^.LowRes.HitTest(AScreenPosition.x - current^.ScreenRect.Left,
AScreenPosition.y - current^.ScreenRect.Top) then
Result := current;
end;
current := current^.Next;
end;

View File

@ -292,7 +292,7 @@ type
procedure BuildTileList;
function ConfirmAction: Boolean;
procedure GetDrawOffset(ARelativeX, ARelativeY: Integer; out DrawX,
DrawY: Single); inline;
DrawY: Integer); inline;
function GetInternalTileID(ATile: TWorldItem): Word;
function GetSelectedRect: TRect;
procedure InitRender;
@ -1687,7 +1687,7 @@ begin
glDisable(GL_DITHER);
glEnable(GL_BLEND); // Enable alpha blending of textures
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glShadeModel(GL_SMOOTH); // Go with flat shading for now
glShadeModel(GL_SMOOTH);
glEnable(GL_NORMALIZE);
glEnable(GL_LIGHT0);
@ -1716,11 +1716,29 @@ begin
end;
procedure TfrmMain.PrepareScreenBlock(ABlockInfo: PBlockInfo);
procedure GetLandAlt(const AX, AY: Integer; const ADefaultZ,
ADefaultRaw: SmallInt; var Z, RawZ: SmallInt);
var
cell: TMapCell;
begin
cell := FLandscape.MapCell[AX, AY];
if cell <> nil then
begin
Z := cell.Z;
RawZ := cell.RawZ;
end else
begin
Z := ADefaultZ;
RawZ := ADefaultRaw;
end;
end;
var
item: TWorldItem;
drawX, drawY: Single;
west, south, east: Single;
z, rawZ: SmallInt;
drawX, drawY: Integer;
z, west, south, east: SmallInt;
rawZ, rawWest, rawSouth, rawEast: SmallInt;
staticItem: TStaticItem;
begin
//add normals to map tiles and materials where possible
@ -1739,23 +1757,58 @@ begin
rawZ := item.RawZ;
end;
ABlockInfo^.HighRes := nil;
ABlockInfo^.CheckRealQuad := False;
if item is TMapCell then
begin
ABlockInfo^.HighRes := nil;
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);
GetLandAlt(item.X, item.Y + 1, z, rawZ, west, rawWest);
GetLandAlt(item.X + 1, item.Y + 1, z, rawZ, south, rawSouth);
GetLandAlt(item.X + 1, item.Y, z, rawZ, east, rawEast);
if (west <> z) or (south <> z) or (east <> z) then
begin
ABlockInfo^.HighRes := FTextureManager.GetTexMaterial(item.TileID);
if (rawWest <> rawZ) or (rawSouth <> rawZ) or (rawEast <> rawZ) then
begin
ABlockInfo^.RealQuad[0][0] := drawX;
ABlockInfo^.RealQuad[0][1] := drawY - rawZ * 4;
ABlockInfo^.RealQuad[1][0] := drawX + 22;
ABlockInfo^.RealQuad[1][1] := drawY + 22 - rawEast * 4;
ABlockInfo^.RealQuad[2][0] := drawX;
ABlockInfo^.RealQuad[2][1] := drawY + 44 - rawSouth * 4;
ABlockInfo^.RealQuad[3][0] := drawX - 22;
ABlockInfo^.RealQuad[3][1] := drawY + 22 - rawWest * 4;
with ABlockInfo^ do
begin
with ScreenRect do
begin
Left := drawX - 22;
Right := drawX + 22;
Top := RealQuad[0][1];
Bottom := RealQuad[0][1];
if RealQuad[1][1] < Top then Top := RealQuad[1][1];
if RealQuad[1][1] > Bottom then Bottom := RealQuad[1][1];
if RealQuad[2][1] < Top then Top := RealQuad[2][1];
if RealQuad[2][1] > Bottom then Bottom := RealQuad[2][1];
if RealQuad[3][1] < Top then Top := RealQuad[3][1];
if RealQuad[3][1] > Bottom then Bottom := RealQuad[3][1];
end;
CheckRealQuad := True;
end;
end;
end;
if not ABlockInfo^.CheckRealQuad then
ABlockInfo^.ScreenRect := Bounds(Trunc(drawX - 22),
Trunc(drawY - rawZ * 4), 44, 44);
ABlockInfo^.LowRes := FTextureManager.GetArtMaterial(item.TileID);
ABlockInfo^.ScreenRect := Bounds(Trunc(drawX - 22), Trunc(drawY - rawZ * 4), 44, 44);
if ABlockInfo^.HighRes <> nil then
begin
@ -1785,7 +1838,8 @@ begin
if item is TVirtualTile then
begin
ABlockInfo^.LowRes := FVLayerMaterial;
ABlockInfo^.ScreenRect := Bounds(Trunc(drawX - 22), Trunc(drawY - z * 4), 44, 44);
ABlockInfo^.ScreenRect := Bounds(Trunc(drawX - 22), Trunc(drawY - z * 4),
44, 44);
ABlockInfo^.DrawQuad[0][0] := drawX - 22;
ABlockInfo^.DrawQuad[0][1] := drawY - z * 4;
ABlockInfo^.DrawQuad[1][0] := drawX - 22 + ABlockInfo^.LowRes.Width;
@ -1866,46 +1920,36 @@ begin
glLogicOp(GL_COPY_INVERTED);
end;
if item is TMapCell then
if blockInfo^.HighRes <> nil then
begin
if blockInfo^.HighRes <> nil then
begin
glBindTexture(GL_TEXTURE_2D, blockInfo^.HighRes.Texture);
glBindTexture(GL_TEXTURE_2D, blockInfo^.HighRes.Texture);
if not highlight then
glEnable(GL_LIGHTING);
if not highlight then
glEnable(GL_LIGHTING);
glBegin(GL_QUADS);
glNormal3fv(@blockInfo^.Normals^[0]);
glTexCoord2f(0, 0); glVertex2fv(@blockInfo^.DrawQuad[0]);
glNormal3fv(@blockInfo^.Normals^[3]);
glTexCoord2f(0, 1); glVertex2fv(@blockInfo^.DrawQuad[3]);
glNormal3fv(@blockInfo^.Normals^[2]);
glTexCoord2f(1, 1); glVertex2fv(@blockInfo^.DrawQuad[2]);
glNormal3fv(@blockInfo^.Normals^[1]);
glTexCoord2f(1, 0); glVertex2fv(@blockInfo^.DrawQuad[1]);
glEnd;
glLoadName(PtrInt(item));
glBegin(GL_QUADS);
glNormal3fv(@blockInfo^.Normals^[0]);
glTexCoord2i(0, 0); glVertex2iv(@blockInfo^.DrawQuad[0]);
glNormal3fv(@blockInfo^.Normals^[3]);
glTexCoord2i(0, 1); glVertex2iv(@blockInfo^.DrawQuad[3]);
glNormal3fv(@blockInfo^.Normals^[2]);
glTexCoord2i(1, 1); glVertex2iv(@blockInfo^.DrawQuad[2]);
glNormal3fv(@blockInfo^.Normals^[1]);
glTexCoord2i(1, 0); glVertex2iv(@blockInfo^.DrawQuad[1]);
glEnd;
if not highlight then
glDisable(GL_LIGHTING);
end else
begin
glBindTexture(GL_TEXTURE_2D, blockInfo^.LowRes.Texture);
glBegin(GL_QUADS);
glTexCoord2f(0, 0); glVertex2fv(@blockInfo^.DrawQuad[0]);
glTexCoord2f(1, 0); glVertex2fv(@blockInfo^.DrawQuad[1]);
glTexCoord2f(1, 1); glVertex2fv(@blockInfo^.DrawQuad[2]);
glTexCoord2f(0, 1); glVertex2fv(@blockInfo^.DrawQuad[3]);
glEnd;
end;
if not highlight then
glDisable(GL_LIGHTING);
end else
begin
glBindTexture(GL_TEXTURE_2D, blockInfo^.LowRes.Texture);
glLoadName(PtrInt(item));
glBegin(GL_QUADS);
glTexCoord2f(0, 0); glVertex2fv(@blockInfo^.DrawQuad[0]);
glTexCoord2f(1, 0); glVertex2fv(@blockInfo^.DrawQuad[1]);
glTexCoord2f(1, 1); glVertex2fv(@blockInfo^.DrawQuad[2]);
glTexCoord2f(0, 1); glVertex2fv(@blockInfo^.DrawQuad[3]);
glTexCoord2i(0, 0); glVertex2iv(@blockInfo^.DrawQuad[0]);
glTexCoord2i(1, 0); glVertex2iv(@blockInfo^.DrawQuad[1]);
glTexCoord2i(1, 1); glVertex2iv(@blockInfo^.DrawQuad[2]);
glTexCoord2i(0, 1); glVertex2iv(@blockInfo^.DrawQuad[3]);
glEnd;
end;
@ -2193,7 +2237,7 @@ end;
procedure TfrmMain.UpdateCurrentTile(AX, AY: Integer);
var
info: PBlockInfo;
blockInfo: PBlockInfo;
begin
FOverlayUI.ActiveArrow := FOverlayUI.HitTest(AX, AY);
if FOverlayUI.ActiveArrow > -1 then
@ -2202,11 +2246,10 @@ begin
Exit;
end;
info := FScreenBuffer.Find(Point(AX, AY));
if info <> nil then
begin
CurrentTile := info^.Item;
end else
blockInfo := FScreenBuffer.Find(Point(AX, AY));
if blockInfo <> nil then
CurrentTile := blockInfo^.Item
else
CurrentTile := nil;
end;
@ -2547,7 +2590,7 @@ begin
end;
procedure TfrmMain.GetDrawOffset(ARelativeX, ARelativeY: Integer; out DrawX,
DrawY: Single); inline;
DrawY: Integer); inline;
begin
DrawX := (oglGameWindow.Width div 2) + (ARelativeX - ARelativeY) * 22;
DrawY := (oglGamewindow.Height div 2) + (ARelativeX + ARelativeY) * 22;