Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
TerrainOverlay.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2012 Wildfire Games.
2  * This file is part of 0 A.D.
3  *
4  * 0 A.D. is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * 0 A.D. is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "precompiled.h"
19 
20 #include "TerrainOverlay.h"
21 
22 #include "graphics/Terrain.h"
23 #include "lib/bits.h"
24 #include "lib/ogl.h"
25 #include "maths/MathUtil.h"
26 #include "ps/Game.h"
27 #include "ps/Overlay.h"
28 #include "ps/Profile.h"
29 #include "ps/World.h"
30 #include "renderer/Renderer.h"
33 
34 #include <algorithm>
35 
36 // Handy things for STL:
37 
38 /// Functor for sorting pairs, using the &lt;-ordering of their second values.
39 struct compare2nd
40 {
41  template<typename S, typename T> bool operator()(const std::pair<S, T>& a, const std::pair<S, T>& b) const
42  {
43  return a.second < b.second;
44  }
45 };
46 
47 /// Functor for comparing the firsts of pairs to a specified value.
48 template<typename S> struct equal1st
49 {
50  const S& val;
51  equal1st(const S& val) : val(val) {}
52  template <typename T> bool operator()(const std::pair<S, T>& a) const
53  {
54  return a.first == val;
55  }
56 private:
57  const equal1st& operator=(const equal1st& rhs);
58 };
59 
60 //////////////////////////////////////////////////////////////////////////
61 
62 // Global overlay list management:
63 
64 static std::vector<std::pair<ITerrainOverlay*, int> > g_TerrainOverlayList;
65 
67 {
68  // Add to global list of overlays
69  g_TerrainOverlayList.push_back(std::make_pair(this, priority));
70  // Sort by overlays by priority. Do stable sort so that adding/removing
71  // overlays doesn't randomly disturb all the existing ones (which would
72  // be noticeable if they have the same priority and overlap).
73  std::stable_sort(g_TerrainOverlayList.begin(), g_TerrainOverlayList.end(),
74  compare2nd());
75 }
76 
78 {
79  std::vector<std::pair<ITerrainOverlay*, int> >::iterator newEnd =
80  std::remove_if(g_TerrainOverlayList.begin(), g_TerrainOverlayList.end(),
82  g_TerrainOverlayList.erase(newEnd, g_TerrainOverlayList.end());
83 }
84 
85 
87 {
88  if (g_TerrainOverlayList.empty())
89  return;
90 
91  PROFILE3_GPU("terrain overlays (before)");
92 
93  for (size_t i = 0; i < g_TerrainOverlayList.size(); ++i)
94  g_TerrainOverlayList[i].first->RenderBeforeWater();
95 }
96 
98 {
99  if (g_TerrainOverlayList.empty())
100  return;
101 
102  PROFILE3_GPU("terrain overlays (after)");
103 
104  for (size_t i = 0; i < g_TerrainOverlayList.size(); ++i)
105  g_TerrainOverlayList[i].first->RenderAfterWater();
106 }
107 
108 //////////////////////////////////////////////////////////////////////////
109 
110 TerrainOverlay::TerrainOverlay(const CSimContext& simContext, int priority /* = 100 */)
111  : ITerrainOverlay(priority), m_Terrain(&simContext.GetTerrain())
112 {
113 }
114 
116 {
117 }
118 
120 {
121 }
122 
124  ssize_t& min_i_inclusive, ssize_t& min_j_inclusive,
125  ssize_t& max_i_inclusive, ssize_t& max_j_inclusive)
126 {
127  // Default to whole map
128  min_i_inclusive = min_j_inclusive = 0;
129  max_i_inclusive = max_j_inclusive = m_Terrain->GetTilesPerSide()-1;
130 }
131 
133 {
134  if (!m_Terrain)
135  return; // should never happen, but let's play it safe
136 
137 #if CONFIG2_GLES
138 #warning TODO: implement TerrainOverlay::RenderOverlays for GLES
139 #else
140  glEnable(GL_BLEND);
141  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
142  glDepthMask(GL_FALSE);
143  // To ensure that outlines are drawn on top of the terrain correctly (and
144  // don't Z-fight and flicker nastily), draw them as QUADS with the LINE
145  // PolygonMode, and use PolygonOffset to pull them towards the camera.
146  // (See e.g. http://www.opengl.org/resources/faq/technical/polygonoffset.htm)
147  glPolygonOffset(-1.f, -1.f);
148  glEnable(GL_POLYGON_OFFSET_LINE);
149  glEnable(GL_POLYGON_OFFSET_FILL);
150 
151  pglActiveTextureARB(GL_TEXTURE0);
152  glDisable(GL_TEXTURE_2D);
153 
154  StartRender();
155 
156  ssize_t min_i, min_j, max_i, max_j;
157  GetTileExtents(min_i, min_j, max_i, max_j);
158  // Clamp the min to 0, but the max to -1 - so tile -1 can never be rendered,
159  // but if unclamped_max<0 then no tiles at all will be rendered. And the same
160  // for the upper limit.
161  min_i = clamp(min_i, ssize_t(0), m_Terrain->GetTilesPerSide());
162  min_j = clamp(min_j, ssize_t(0), m_Terrain->GetTilesPerSide());
163  max_i = clamp(max_i, ssize_t(-1), m_Terrain->GetTilesPerSide()-1);
164  max_j = clamp(max_j, ssize_t(-1), m_Terrain->GetTilesPerSide()-1);
165 
166  for (m_j = min_j; m_j <= max_j; ++m_j)
167  for (m_i = min_i; m_i <= max_i; ++m_i)
168  ProcessTile(m_i, m_j);
169 
170  EndRender();
171 
172  // Clean up state changes
173  glEnable(GL_CULL_FACE);
174  glEnable(GL_DEPTH_TEST);
175  glDisable(GL_POLYGON_OFFSET_LINE);
176  glDisable(GL_POLYGON_OFFSET_FILL);
177  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
178  glDepthMask(GL_TRUE);
179  glDisable(GL_BLEND);
180 #endif
181 }
182 
183 void TerrainOverlay::RenderTile(const CColor& colour, bool draw_hidden)
184 {
185  RenderTile(colour, draw_hidden, m_i, m_j);
186 }
187 
188 void TerrainOverlay::RenderTile(const CColor& colour, bool draw_hidden, ssize_t i, ssize_t j)
189 {
190  // TODO: if this is unpleasantly slow, make it much more efficient
191  // (e.g. buffering data and making a single draw call? or at least
192  // far fewer calls than it makes now)
193 
194  if (draw_hidden)
195  {
196  glDisable(GL_DEPTH_TEST);
197  glDisable(GL_CULL_FACE);
198  }
199  else
200  {
201  glEnable(GL_DEPTH_TEST);
202  glEnable(GL_CULL_FACE);
203  }
204 
205 #if CONFIG2_GLES
206 #warning TODO: implement TerrainOverlay::RenderTile for GLES
207 #else
208 
209  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
210 
211  CVector3D pos;
212  glBegin(GL_TRIANGLES);
213  glColor4fv(colour.FloatArray());
214  if (m_Terrain->GetTriangulationDir(i, j))
215  {
216  m_Terrain->CalcPosition(i, j, pos); glVertex3fv(pos.GetFloatArray());
217  m_Terrain->CalcPosition(i+1, j, pos); glVertex3fv(pos.GetFloatArray());
218  m_Terrain->CalcPosition(i, j+1, pos); glVertex3fv(pos.GetFloatArray());
219 
220  m_Terrain->CalcPosition(i+1, j, pos); glVertex3fv(pos.GetFloatArray());
221  m_Terrain->CalcPosition(i+1, j+1, pos); glVertex3fv(pos.GetFloatArray());
222  m_Terrain->CalcPosition(i, j+1, pos); glVertex3fv(pos.GetFloatArray());
223  }
224  else
225  {
226  m_Terrain->CalcPosition(i, j, pos); glVertex3fv(pos.GetFloatArray());
227  m_Terrain->CalcPosition(i+1, j, pos); glVertex3fv(pos.GetFloatArray());
228  m_Terrain->CalcPosition(i+1, j+1, pos); glVertex3fv(pos.GetFloatArray());
229 
230  m_Terrain->CalcPosition(i+1, j+1, pos); glVertex3fv(pos.GetFloatArray());
231  m_Terrain->CalcPosition(i, j+1, pos); glVertex3fv(pos.GetFloatArray());
232  m_Terrain->CalcPosition(i, j, pos); glVertex3fv(pos.GetFloatArray());
233  }
234  glEnd();
235 
236 #endif
237 }
238 
239 void TerrainOverlay::RenderTileOutline(const CColor& colour, int line_width, bool draw_hidden)
240 {
241  RenderTileOutline(colour, line_width, draw_hidden, m_i, m_j);
242 }
243 
244 void TerrainOverlay::RenderTileOutline(const CColor& colour, int line_width, bool draw_hidden, ssize_t i, ssize_t j)
245 {
246  if (draw_hidden)
247  {
248  glDisable(GL_DEPTH_TEST);
249  glDisable(GL_CULL_FACE);
250  }
251  else
252  {
253  glEnable(GL_DEPTH_TEST);
254  glEnable(GL_CULL_FACE);
255  }
256 
257 #if CONFIG2_GLES
258 #warning TODO: implement TerrainOverlay::RenderTileOutline for GLES
259 #else
260 
261  glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
262 
263  if (line_width != 1)
264  glLineWidth((float)line_width);
265 
266  CVector3D pos;
267  glBegin(GL_QUADS);
268  glColor4fv(colour.FloatArray());
269  m_Terrain->CalcPosition(i, j, pos); glVertex3fv(pos.GetFloatArray());
270  m_Terrain->CalcPosition(i+1, j, pos); glVertex3fv(pos.GetFloatArray());
271  m_Terrain->CalcPosition(i+1, j+1, pos); glVertex3fv(pos.GetFloatArray());
272  m_Terrain->CalcPosition(i, j+1, pos); glVertex3fv(pos.GetFloatArray());
273  glEnd();
274 
275  if (line_width != 1)
276  glLineWidth(1.0f);
277 
278 #endif
279 }
280 
281 //////////////////////////////////////////////////////////////////////////
282 
283 TerrainTextureOverlay::TerrainTextureOverlay(float texelsPerTile, int priority) :
284  ITerrainOverlay(priority), m_TexelsPerTile(texelsPerTile), m_Texture(0), m_TextureW(0), m_TextureH(0)
285 {
286  glGenTextures(1, &m_Texture);
287 }
288 
290 {
291  glDeleteTextures(1, &m_Texture);
292 }
293 
295 {
296  CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
297 
298  ssize_t w = (ssize_t)(terrain->GetTilesPerSide() * m_TexelsPerTile);
299  ssize_t h = (ssize_t)(terrain->GetTilesPerSide() * m_TexelsPerTile);
300 
301  pglActiveTextureARB(GL_TEXTURE0);
302 
303  // Recreate the texture with new size if necessary
305  {
308 
309  glBindTexture(GL_TEXTURE_2D, m_Texture);
310  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_TextureW, m_TextureH, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
311 
312  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
313  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
314  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
315  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
316  }
317 
318  u8* data = (u8*)calloc(w * h, 4);
319  BuildTextureRGBA(data, w, h);
320 
321  glBindTexture(GL_TEXTURE_2D, m_Texture);
322  glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, data);
323 
324  free(data);
325 
326  CMatrix3D matrix;
327  matrix.SetZero();
330  matrix._44 = 1;
331 
332  g_Renderer.GetTerrainRenderer().RenderTerrainOverlayTexture(matrix);
333 }
#define u8
Definition: types.h:39
equal1st(const S &val)
const ssize_t TERRAIN_TILE_SIZE
metres [world space units] per tile in x and z
Definition: Terrain.h:40
float _44
Definition: Matrix3D.h:45
Definition: Overlay.h:34
static void RenderOverlaysBeforeWater()
Draw all ITerrainOverlay objects that exist and that should be drawn before water.
CTerrain * m_Terrain
void SetZero()
Definition: Matrix3D.cpp:39
static void RenderOverlaysAfterWater()
Draw all ITerrainOverlay objects that exist and that should be drawn after water. ...
const equal1st & operator=(const equal1st &rhs)
TerrainOverlay(const CSimContext &simContext, int priority=100)
Construct the object and register it with the global list of terrain overlays.
void CalcPosition(ssize_t i, ssize_t j, CVector3D &pos) const
Definition: Terrain.cpp:118
bool GetTriangulationDir(ssize_t i, ssize_t j) const
Definition: Terrain.cpp:427
Contains pointers to various &#39;global&#39; objects that are needed by the simulation code, to allow easy access without using real (evil) global variables.
Definition: SimContext.h:32
float _11
Definition: Matrix3D.h:42
virtual ~ITerrainOverlay()
TerrainTextureOverlay(float texelsPerTile, int priority=100)
virtual void BuildTextureRGBA(u8 *data, size_t w, size_t h)=0
Called each frame to generate the texture to render on the terrain.
bool operator()(const std::pair< S, T > &a, const std::pair< S, T > &b) const
virtual void ProcessTile(ssize_t i, ssize_t j)=0
Override to perform processing of each tile.
#define g_Renderer
Definition: Renderer.h:61
CTerrain * GetTerrain()
Get the pointer to the terrain object.
Definition: World.h:88
void RenderTile(const CColor &colour, bool draw_hidden)
Draw a filled quad on top of the current tile.
T round_up_to_pow2(T x)
round up to next larger power of two.
Definition: bits.h:244
Common interface for terrain-tile-based and texture-based debug overlays.
static std::vector< std::pair< ITerrainOverlay *, int > > g_TerrainOverlayList
ssize_t GetTilesPerSide() const
Definition: Terrain.h:67
virtual void StartRender()
Override to perform processing at the start of the overlay rendering, before the ProcessTile calls...
void RenderTileOutline(const CColor &colour, int line_width, bool draw_hidden)
Draw an outlined quad on top of the current tile.
CGame * g_Game
Globally accessible pointer to the CGame object.
Definition: Game.cpp:56
intptr_t ssize_t
Definition: wposix_types.h:82
Functor for comparing the firsts of pairs to a specified value.
bool operator()(const std::pair< S, T > &a) const
virtual void RenderBeforeWater()
float _23
Definition: Matrix3D.h:44
ITerrainOverlay(int priority)
const float * FloatArray() const
Definition: Overlay.h:49
const float * GetFloatArray() const
Definition: Vector3D.h:108
CWorld * GetWorld()
Get the pointer to the game world object.
Definition: Game.h:120
virtual void GetTileExtents(ssize_t &min_i_inclusive, ssize_t &min_j_inclusive, ssize_t &max_i_inclusive, ssize_t &max_j_inclusive)
Override to limit the range over which ProcessTile will be called.
#define PROFILE3_GPU(name)
Definition: Profile.h:204
virtual void EndRender()
Override to perform processing at the end of the overlay rendering, after the ProcessTile calls...
T clamp(T value, T min, T max)
Definition: MathUtil.h:32
Functor for sorting pairs, using the &lt;-ordering of their second values.
const S & val