- 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; PBlockInfo = ^TBlockInfo;
TBlockInfo = record TBlockInfo = record
ScreenRect: TRect; 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; Item: TWorldItem;
HighRes: TMaterial; HighRes: TMaterial;
LowRes: TMaterial; LowRes: TMaterial;
@ -209,6 +210,7 @@ type
State: TScreenState; State: TScreenState;
Highlighted: Boolean; Highlighted: Boolean;
HueOverride: Boolean; HueOverride: Boolean;
CheckRealQuad: Boolean;
Next: PBlockInfo; Next: PBlockInfo;
end; end;
@ -1278,16 +1280,50 @@ end;
function TScreenBuffer.Find(AScreenPosition: TPoint): PBlockInfo; function TScreenBuffer.Find(AScreenPosition: TPoint): PBlockInfo;
var var
current: PBlockInfo; current: PBlockInfo;
buff: array[0..3] of GLuint;
hits: GLint;
begin begin
Result := nil; Result := nil;
current := FShortCuts[0]; current := FShortCuts[0];
while current <> nil do //search the last matching tile while current <> nil do //search the last matching tile
begin begin
if (current^.State = ssNormal) and if (current^.State = ssNormal) and
PtInRect(current^.ScreenRect, AScreenPosition) and PtInRect(current^.ScreenRect, AScreenPosition)then
current^.LowRes.HitTest(AScreenPosition.x - current^.ScreenRect.Left,
AScreenPosition.y - current^.ScreenRect.Top) then
begin begin
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; Result := current;
end; end;
current := current^.Next; current := current^.Next;

View File

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