Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
LOSTexture.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 "LOSTexture.h"
21 
22 #include "graphics/ShaderManager.h"
23 #include "graphics/Terrain.h"
24 #include "lib/bits.h"
25 #include "ps/CLogger.h"
26 #include "ps/Game.h"
27 #include "ps/Profile.h"
28 #include "renderer/Renderer.h"
29 #include "renderer/TimeManager.h"
33 
34 /*
35 
36 The LOS bitmap is computed with one value per map vertex, based on
37 CCmpRangeManager's visibility information.
38 
39 The bitmap is then blurred using an NxN filter (in particular a
40 7-tap Binomial filter as an efficient integral approximation of a Gaussian).
41 To implement the blur efficiently without using extra memory for a second copy
42 of the bitmap, we generate the bitmap with (N-1)/2 pixels of padding on each side,
43 then the blur shifts the image back into the corner.
44 
45 The blurred bitmap is then uploaded into a GL texture for use by the renderer.
46 
47 */
48 
49 
50 // Blur with a NxN filter, where N = g_BlurSize must be an odd number.
51 static const size_t g_BlurSize = 7;
52 
54  m_Simulation(simulation), m_Dirty(true), m_Texture(0), m_smoothFbo(0), m_MapSize(0), m_TextureSize(0), whichTex(true)
55 {
56  if (CRenderer::IsInitialised() && g_Renderer.m_Options.m_SmoothLOS)
57  {
58  m_smoothShader = g_Renderer.GetShaderManager().LoadEffect(str_los_interp);
59  CShaderProgramPtr shader = m_smoothShader->GetShader();
60 
61  if (m_smoothShader && shader)
62  {
63  pglGenFramebuffersEXT(1, &m_smoothFbo);
64  }
65  else
66  {
67  LOGERROR(L"Failed to load SmoothLOS shader, disabling.");
68  g_Renderer.m_Options.m_SmoothLOS = false;
69  }
70  }
71 }
72 
74 {
75  if (m_Texture)
76  DeleteTexture();
77 }
78 
80 {
81  glDeleteTextures(1, &m_Texture);
82  if (CRenderer::IsInitialised() && g_Renderer.m_Options.m_SmoothLOS)
83  {
84  glDeleteTextures(1, &m_TextureSmooth1);
85  glDeleteTextures(1, &m_TextureSmooth2);
86  }
87  m_Texture = 0;
88 }
89 
91 {
92  m_Dirty = true;
93 }
94 
96 {
97  if (m_Dirty)
98  {
99  RecomputeTexture(unit);
100  m_Dirty = false;
101  }
102 
103  g_Renderer.BindTexture(unit, m_Texture);
104 }
105 
107 {
108  if (CRenderer::IsInitialised() && !g_Renderer.m_Options.m_SmoothLOS)
109  return GetTexture();
110  else
112 }
113 
115 {
116  if (CRenderer::IsInitialised() && !g_Renderer.m_Options.m_SmoothLOS)
117  return;
118 
119  if (m_Dirty)
120  {
121  RecomputeTexture(0);
122  m_Dirty = false;
123  }
124 
125  GLint originalFBO;
126  glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &originalFBO);
127 
128  pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_smoothFbo);
129  pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D,
131 
132  GLenum status = pglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
133  if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
134  {
135  LOGWARNING(L"LOS framebuffer object incomplete: 0x%04X", status);
136  }
137 
138  m_smoothShader->BeginPass();
139  CShaderProgramPtr shader = m_smoothShader->GetShader();
140 
141  glDisable(GL_BLEND);
142 
143  shader->Bind();
144 
145  shader->BindTexture(str_losTex1, m_Texture);
146  shader->BindTexture(str_losTex2, whichTex ? m_TextureSmooth1 : m_TextureSmooth2);
147 
148  shader->Uniform(str_delta, (float)g_Renderer.GetTimeManager().GetFrameDelta() * 4.0f, 0.0f, 0.0f, 0.0f);
149 
150  glPushAttrib(GL_VIEWPORT_BIT);
151  glViewport(0, 0, m_TextureSize, m_TextureSize);
152 
153  glBegin(GL_QUADS);
154  glColor4f(1.f, 1.f, 1.f, 1.f);
155  glTexCoord2f(1.0, 1.0); glVertex2f(1,1);
156  glTexCoord2f(0.0, 1.0); glVertex2f(-1,1);
157  glTexCoord2f(0.0, 0.0); glVertex2f(-1,-1);
158  glTexCoord2f(1.0, 0.0); glVertex2f(1,-1);
159  glEnd();
160 
161  glPopAttrib();
162  shader->Unbind();
163  m_smoothShader->EndPass();
164 
165  pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, 0, 0);
166 
167  pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, originalFBO);
168 
169  whichTex = !whichTex;
170 }
171 
172 
174 {
175  if (m_Dirty)
176  {
177  RecomputeTexture(0);
178  m_Dirty = false;
179  }
180 
181  return m_Texture;
182 }
183 
185 {
186  ENSURE(!m_Dirty);
187  return m_TextureMatrix;
188 }
189 
191 {
192  ENSURE(!m_Dirty);
193  return &m_MinimapTextureMatrix._11;
194 }
195 
197 {
199  if (!cmpTerrain)
200  return;
201 
202  m_MapSize = cmpTerrain->GetVerticesPerSide();
203 
204  m_TextureSize = (GLsizei)round_up_to_pow2((size_t)m_MapSize + g_BlurSize - 1);
205 
206  glGenTextures(1, &m_Texture);
207 
208  // Initialise texture with SoD colour, for the areas we don't
209  // overwrite with glTexSubImage2D later
210  u8* texData = new u8[m_TextureSize * m_TextureSize * 4];
211  memset(texData, 0x00, m_TextureSize * m_TextureSize * 4);
212 
213  if (CRenderer::IsInitialised() && g_Renderer.m_Options.m_SmoothLOS)
214  {
215  glGenTextures(1, &m_TextureSmooth1);
216  glGenTextures(1, &m_TextureSmooth2);
217 
218  g_Renderer.BindTexture(unit, m_TextureSmooth1);
219  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_TextureSize, m_TextureSize, 0, GL_ALPHA, GL_UNSIGNED_BYTE, texData);
220  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
221  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
222  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
223  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
224 
225  g_Renderer.BindTexture(unit, m_TextureSmooth2);
226  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_TextureSize, m_TextureSize, 0, GL_ALPHA, GL_UNSIGNED_BYTE, texData);
227  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
228  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
229  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
230  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
231  }
232 
233  g_Renderer.BindTexture(unit, m_Texture);
234  glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, m_TextureSize, m_TextureSize, 0, GL_ALPHA, GL_UNSIGNED_BYTE, texData);
235  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
236  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
237  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
238  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
239 
240  delete[] texData;
241 
242  {
243  // Texture matrix: We want to map
244  // world pos (0, y, 0) (i.e. first vertex)
245  // onto texcoord (0.5/texsize, 0.5/texsize) (i.e. middle of first texel);
246  // world pos ((mapsize-1)*cellsize, y, (mapsize-1)*cellsize) (i.e. last vertex)
247  // onto texcoord ((mapsize-0.5) / texsize, (mapsize-0.5) / texsize) (i.e. middle of last texel)
248 
249  float s = (m_MapSize-1) / (float)(m_TextureSize * (m_MapSize-1) * TERRAIN_TILE_SIZE);
250  float t = 0.5f / m_TextureSize;
252  m_TextureMatrix._11 = s;
253  m_TextureMatrix._23 = s;
254  m_TextureMatrix._14 = t;
255  m_TextureMatrix._24 = t;
256  m_TextureMatrix._44 = 1;
257  }
258 
259  {
260  // Minimap matrix: We want to map UV (0,0)-(1,1) onto (0,0)-(mapsize/texsize, mapsize/texsize)
261 
262  float s = m_MapSize / (float)m_TextureSize;
267  }
268 }
269 
271 {
272  // If the map was resized, delete and regenerate the texture
273  if (m_Texture)
274  {
276  if (cmpTerrain && m_MapSize != (ssize_t)cmpTerrain->GetVerticesPerSide())
277  DeleteTexture();
278  }
279 
280  bool recreated = false;
281  if (!m_Texture)
282  {
283  ConstructTexture(unit);
284  recreated = true;
285  }
286 
287  PROFILE("recompute LOS texture");
288 
289  std::vector<u8> losData;
290  losData.resize(GetBitmapSize(m_MapSize, m_MapSize));
291 
293  if (!cmpRangeManager)
294  return;
295 
297 
298  GenerateBitmap(los, &losData[0], m_MapSize, m_MapSize);
299 
300  if (CRenderer::IsInitialised() && g_Renderer.m_Options.m_SmoothLOS && recreated)
301  {
302  g_Renderer.BindTexture(unit, m_TextureSmooth1);
303  glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_MapSize + g_BlurSize - 1, m_MapSize + g_BlurSize - 1, GL_ALPHA, GL_UNSIGNED_BYTE, &losData[0]);
304  g_Renderer.BindTexture(unit, m_TextureSmooth2);
305  glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_MapSize + g_BlurSize - 1, m_MapSize + g_BlurSize - 1, GL_ALPHA, GL_UNSIGNED_BYTE, &losData[0]);
306  }
307 
308  g_Renderer.BindTexture(unit, m_Texture);
309  glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_MapSize + g_BlurSize - 1, m_MapSize + g_BlurSize - 1, GL_ALPHA, GL_UNSIGNED_BYTE, &losData[0]);
310 }
311 
312 size_t CLOSTexture::GetBitmapSize(size_t w, size_t h)
313 {
314  return (w + g_BlurSize - 1) * (h + g_BlurSize - 1);
315 }
316 
317 void CLOSTexture::GenerateBitmap(ICmpRangeManager::CLosQuerier los, u8* losData, size_t w, size_t h)
318 {
319  const size_t rowSize = w + g_BlurSize-1; // size of losData rows
320 
321  u8 *dataPtr = losData;
322 
323  // Initialise the top padding
324  for (size_t j = 0; j < g_BlurSize/2; ++j)
325  for (size_t i = 0; i < rowSize; ++i)
326  *dataPtr++ = 0;
327 
328  for (size_t j = 0; j < h; ++j)
329  {
330  // Initialise the left padding
331  for (size_t i = 0; i < g_BlurSize/2; ++i)
332  *dataPtr++ = 0;
333 
334  // Fill in the visibility data
335  for (size_t i = 0; i < w; ++i)
336  {
337  if (los.IsVisible_UncheckedRange(i, j))
338  *dataPtr++ = 255;
339  else if (los.IsExplored_UncheckedRange(i, j))
340  *dataPtr++ = 127;
341  else
342  *dataPtr++ = 0;
343  }
344 
345  // Initialise the right padding
346  for (size_t i = 0; i < g_BlurSize/2; ++i)
347  *dataPtr++ = 0;
348  }
349 
350  // Initialise the bottom padding
351  for (size_t j = 0; j < g_BlurSize/2; ++j)
352  for (size_t i = 0; i < rowSize; ++i)
353  *dataPtr++ = 0;
354 
355  // Horizontal blur:
356 
357  for (size_t j = g_BlurSize/2; j < h + g_BlurSize/2; ++j)
358  {
359  for (size_t i = 0; i < w; ++i)
360  {
361  u8* d = &losData[i+j*rowSize];
362  *d = (
363  1*d[0] +
364  6*d[1] +
365  15*d[2] +
366  20*d[3] +
367  15*d[4] +
368  6*d[5] +
369  1*d[6]
370  ) / 64;
371  }
372  }
373 
374  // Vertical blur:
375 
376  for (size_t j = 0; j < h; ++j)
377  {
378  for (size_t i = 0; i < w; ++i)
379  {
380  u8* d = &losData[i+j*rowSize];
381  *d = (
382  1*d[0*rowSize] +
383  6*d[1*rowSize] +
384  15*d[2*rowSize] +
385  20*d[3*rowSize] +
386  15*d[4*rowSize] +
387  6*d[5*rowSize] +
388  1*d[6*rowSize]
389  ) / 64;
390  }
391  }
392 }
bool IsVisible_UncheckedRange(ssize_t i, ssize_t j)
Returns whether the given vertex is visible (i.e.
#define u8
Definition: types.h:39
void RecomputeTexture(int unit)
Definition: LOSTexture.cpp:270
void DeleteTexture()
Definition: LOSTexture.cpp:79
virtual CLosQuerier GetLosQuerier(player_id_t player)=0
Returns a CLosQuerier for checking whether vertex positions are visible to the given player (or other...
CLOSTexture(CSimulation2 &simulation)
Definition: LOSTexture.cpp:53
float _22
Definition: Matrix3D.h:43
const ssize_t TERRAIN_TILE_SIZE
metres [world space units] per tile in x and z
Definition: Terrain.h:40
#define LOGERROR
Definition: CLogger.h:35
CMatrix3D m_MinimapTextureMatrix
Definition: LOSTexture.h:103
float _44
Definition: Matrix3D.h:45
GLsizei m_TextureSize
Definition: LOSTexture.h:100
GLuint m_TextureSmooth1
Definition: LOSTexture.h:92
GLuint GetTextureSmooth()
Definition: LOSTexture.cpp:106
void SetZero()
Definition: Matrix3D.cpp:39
GLuint m_Texture
Definition: LOSTexture.h:91
float _11
Definition: Matrix3D.h:42
void GenerateBitmap(ICmpRangeManager::CLosQuerier los, u8 *losData, size_t w, size_t h)
Definition: LOSTexture.cpp:317
CShaderTechniquePtr m_smoothShader
Definition: LOSTexture.h:97
const entity_id_t SYSTEM_ENTITY
Entity ID for singleton &#39;system&#39; components.
Definition: Entity.h:44
Public API for simulation system.
Definition: Simulation2.h:46
#define g_Renderer
Definition: Renderer.h:61
#define LOGWARNING
Definition: CLogger.h:34
int GetPlayerID()
Definition: Game.cpp:249
GLuint m_TextureSmooth2
Definition: LOSTexture.h:92
#define ENSURE(expr)
ensure the expression &lt;expr&gt; evaluates to non-zero.
Definition: debug.h:282
T round_up_to_pow2(T x)
round up to next larger power of two.
Definition: bits.h:244
bool m_Dirty
Definition: LOSTexture.h:89
bool IsExplored_UncheckedRange(ssize_t i, ssize_t j)
Returns whether the given vertex is explored (i.e.
CSimulation2 & m_Simulation
Definition: LOSTexture.h:87
GLuint GetTexture()
Recomputes the LOS texture if necessary, and returns the texture handle.
Definition: LOSTexture.cpp:173
void MakeDirty()
Marks the LOS texture as needing recomputation.
Definition: LOSTexture.cpp:90
CGame * g_Game
Globally accessible pointer to the CGame object.
Definition: Game.cpp:56
#define PROFILE(name)
Definition: Profile.h:195
virtual u16 GetVerticesPerSide()=0
Returns number of vertices per side on the terrain.
float _24
Definition: Matrix3D.h:45
size_t GetBitmapSize(size_t w, size_t h)
Definition: LOSTexture.cpp:312
static bool IsInitialised()
Definition: Singleton.h:63
ssize_t m_MapSize
Definition: LOSTexture.h:99
A simplified syntax for accessing entity components.
Definition: CmpPtr.h:55
intptr_t ssize_t
Definition: wposix_types.h:82
void ConstructTexture(int unit)
Definition: LOSTexture.cpp:196
const float * GetMinimapTextureMatrix()
Returns a matrix to map (0,0)-(1,1) texture coordinates onto LOS texture coordinates, in the form expected by glLoadMatrixf.
Definition: LOSTexture.cpp:190
CMatrix3D m_TextureMatrix
Definition: LOSTexture.h:102
float _23
Definition: Matrix3D.h:44
Object providing efficient abstracted access to the LOS state.
void BindTexture(int unit)
Recomputes the LOS texture if necessary, and binds it to the requested texture unit.
Definition: LOSTexture.cpp:95
static const size_t g_BlurSize
Definition: LOSTexture.cpp:51
const CMatrix3D & GetTextureMatrix()
Returns a matrix to map (x,y,z) world coordinates onto (u,v) LOS texture coordinates, in the form expected by glLoadMatrixf.
Definition: LOSTexture.cpp:184
GLuint m_smoothFbo
Definition: LOSTexture.h:96
void InterpolateLOS()
Definition: LOSTexture.cpp:114
shared_ptr< CShaderProgram > CShaderProgramPtr
bool whichTex
Definition: LOSTexture.h:94
float _14
Definition: Matrix3D.h:45