Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
SkyManager.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 /*
19  * Sky settings, texture management and rendering.
20  */
21 
22 #include "precompiled.h"
23 
24 #include <algorithm>
25 
26 #include "lib/timer.h"
27 #include "lib/tex/tex.h"
29 
30 #include "maths/MathUtil.h"
31 
32 #include "ps/CStr.h"
33 #include "ps/CLogger.h"
34 #include "ps/Loader.h"
35 #include "ps/Filesystem.h"
36 
37 #include "renderer/SkyManager.h"
38 #include "renderer/Renderer.h"
39 
40 #include "graphics/Camera.h"
41 #include "graphics/LightEnv.h"
42 #include "graphics/ShaderManager.h"
44 
45 
46 ///////////////////////////////////////////////////////////////////////////////////////////////
47 // SkyManager implementation
48 
49 
50 ///////////////////////////////////////////////////////////////////
51 // String names for each image, in order of the IMG_ constants
52 const wchar_t* SkyManager::s_imageNames[numTextures] = {
53  L"front",
54  L"back",
55  L"right",
56  L"left",
57  L"top"
58 };
59 
60 
61 ///////////////////////////////////////////////////////////////////
62 // Construction/Destruction
64 {
65  m_RenderSky = true;
66 
67  m_SkySet = L"";
68 
69  m_HorizonHeight = -150.0f;
70 
71  m_SkyCubeMap = 0;
72 }
73 
74 
75 ///////////////////////////////////////////////////////////////////
76 // Load all sky textures
78 {
79  /*for (size_t i = 0; i < ARRAY_SIZE(m_SkyTexture); ++i)
80  {
81  VfsPath path = VfsPath("art/textures/skies") / m_SkySet / (Path::String(s_imageNames[i])+L".dds");
82 
83  CTextureProperties textureProps(path);
84  textureProps.SetWrap(GL_CLAMP_TO_EDGE);
85  CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps);
86  texture->Prefetch();
87  m_SkyTexture[i] = texture;
88  }*/
89 
90  ///////////////////////////////////////////////////////////////////////////
91  // HACK: THE HORRIBLENESS HERE IS OVER 9000. The following code is a HUGE hack and will be removed completely
92  // as soon as all the hardcoded GL_TEXTURE_2D references are corrected in the TextureManager/OGL/tex libs.
93 
94  glGenTextures(1, &m_SkyCubeMap);
95  glBindTexture(GL_TEXTURE_CUBE_MAP, m_SkyCubeMap);
96 
97  int types[] = {
98  GL_TEXTURE_CUBE_MAP_POSITIVE_X,
99  GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
100  GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
101  GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
102  GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
103  GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
104  };
105 
106  const wchar_t* images[numTextures+1] = {
107  L"front",
108  L"back",
109  L"right",
110  L"left",
111  L"top",
112  L"top"
113  };
114 
115  for (size_t i = 0; i < numTextures+1; ++i)
116  {
117  VfsPath path = VfsPath("art/textures/skies") / m_SkySet / (Path::String(images[i])+L".dds");
118 
119  shared_ptr<u8> file;
120  size_t fileSize;
121  if (g_VFS->LoadFile(path, file, fileSize) < 0)
122  {
123  VfsPath path2 = VfsPath("art/textures/skies") / m_SkySet / (Path::String(images[i])+L".dds.cached.dds");
124  if (g_VFS->LoadFile(path2, file, fileSize) < 0)
125  {
126  glDeleteTextures(1, &m_SkyCubeMap);
127  LOGERROR(L"Error creating sky cubemap.");
128  return;
129  }
130  }
131 
132  Tex tex;
133  tex_decode(file, fileSize, &tex);
134 
136 
137  u8* data = tex_get_data(&tex);
138 
139  if (types[i] == GL_TEXTURE_CUBE_MAP_NEGATIVE_Y || types[i] == GL_TEXTURE_CUBE_MAP_POSITIVE_Y)
140  {
141  std::vector<u8> rotated(tex.dataSize);
142 
143  for (size_t y = 0; y < tex.h; ++y)
144  {
145  for (size_t x = 0; x < tex.w; ++x)
146  {
147  size_t invx = y, invy = tex.w-x-1;
148 
149  rotated[(y*tex.w + x) * 4 + 0] = data[(invy*tex.w + invx) * 4 + 0];
150  rotated[(y*tex.w + x) * 4 + 1] = data[(invy*tex.w + invx) * 4 + 1];
151  rotated[(y*tex.w + x) * 4 + 2] = data[(invy*tex.w + invx) * 4 + 2];
152  rotated[(y*tex.w + x) * 4 + 3] = data[(invy*tex.w + invx) * 4 + 3];
153  }
154  }
155 
156  glTexImage2D(types[i], 0, GL_RGB, tex.w, tex.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, &rotated[0]);
157  }
158  else
159  {
160  glTexImage2D(types[i], 0, GL_RGB, tex.w, tex.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
161  }
162 
163  tex_free(&tex);
164  }
165 
166  glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
167  glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
168  glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
169  glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
170  glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
171 
172  glBindTexture(GL_TEXTURE_2D, 0);
173  ///////////////////////////////////////////////////////////////////////////
174 }
175 
176 
177 ///////////////////////////////////////////////////////////////////
178 // Switch to a different sky set (while the game is running)
179 void SkyManager::SetSkySet( const CStrW& newSet )
180 {
181  if(newSet == m_SkySet)
182  return;
183 
184  if (m_SkyCubeMap)
185  {
186  glDeleteTextures(1, &m_SkyCubeMap);
187  m_SkyCubeMap = 0;
188  }
189 
190  m_SkySet = newSet;
191 
192  LoadSkyTextures();
193 }
194 
195 ///////////////////////////////////////////////////////////////////
196 // Generate list of available skies
197 std::vector<CStrW> SkyManager::GetSkySets() const
198 {
199  std::vector<CStrW> skies;
200 
201  // Find all subdirectories in art/textures/skies
202 
203  const VfsPath path(L"art/textures/skies/");
204  DirectoryNames subdirectories;
205  if(g_VFS->GetDirectoryEntries(path, 0, &subdirectories) < 0)
206  {
207  LOGERROR(L"Error opening directory '%ls'", path.string().c_str());
208  return std::vector<CStrW>(1, GetSkySet()); // just return what we currently have
209  }
210 
211  for(size_t i = 0; i < subdirectories.size(); i++)
212  skies.push_back(subdirectories[i].string());
213  sort(skies.begin(), skies.end());
214 
215  return skies;
216 }
217 
218 ///////////////////////////////////////////////////////////////////
219 // Render sky
221 {
222 #if CONFIG2_GLES
223 #warning TODO: implement SkyManager::RenderSky for GLES
224 #else
225 
226  // Draw the sky as a small box around the camera position, with depth write enabled.
227  // This will be done before anything else is drawn so we'll be overlapped by everything else.
228 
229  // Note: The coordinates for this were set up through a rather cumbersome trial-and-error
230  // process - there might be a smarter way to do it, but this seems to work.
231 
232  // Do nothing unless SetSkySet was called
233  if (m_SkySet.empty())
234  return;
235 
236  glDepthMask( GL_FALSE );
237 
238  pglActiveTextureARB(GL_TEXTURE0_ARB);
239  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
240 
241  glMatrixMode(GL_MODELVIEW);
242  glPushMatrix();
243 
244  // Translate so we are at the camera in the X and Z directions, but
245  // put the horizon at a fixed height regardless of camera Y
246  const CCamera& camera = g_Renderer.GetViewCamera();
247  CVector3D pos = camera.m_Orientation.GetTranslation();
248 
249  glTranslatef( pos.X, m_HorizonHeight, pos.Z );
250 
251  // Rotate so that the "left" face, which contains the brightest part of each
252  // skymap, is in the direction of the sun from our light environment
253  glRotatef( 180.0f /*+ 45.0f*/ + RADTODEG(g_Renderer.GetLightEnv().GetRotation()), 0.0f, 1.0f, 0.0f );
254 
255  // Distance to draw the faces at
256  const float D = 2000.0;
257 
258  CShaderProgramPtr shader;
259  CShaderTechniquePtr skytech;
260 
261  if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER)
262  {
263  skytech = g_Renderer.GetShaderManager().LoadEffect(str_sky_simple);
264  skytech->BeginPass();
265  shader = skytech->GetShader();
266  shader->BindTexture(str_baseTex, m_SkyCubeMap);
267  }
268  else
269  {
270  glDisable(GL_TEXTURE_2D);
271  glEnable(GL_TEXTURE_CUBE_MAP);
272  glBindTexture(GL_TEXTURE_CUBE_MAP, m_SkyCubeMap);
273  }
274 
275  // GL_TEXTURE_CUBE_MAP_NEGATIVE_X
276  glBegin(GL_QUADS);
277  glTexCoord3f( +1, +1, +1 ); glVertex3f( -D, -D, -D );
278  glTexCoord3f( +1, +1, -1 ); glVertex3f( -D, -D, +D );
279  glTexCoord3f( +1, -1, -1 ); glVertex3f( -D, +D, +D );
280  glTexCoord3f( +1, -1, +1 ); glVertex3f( -D, +D, -D );
281  glEnd();
282 
283  // GL_TEXTURE_CUBE_MAP_POSITIVE_X
284  glBegin(GL_QUADS);
285  glTexCoord3f( -1, +1, -1 ); glVertex3f( +D, -D, +D );
286  glTexCoord3f( -1, +1, +1 ); glVertex3f( +D, -D, -D );
287  glTexCoord3f( -1, -1, +1 ); glVertex3f( +D, +D, -D );
288  glTexCoord3f( -1, -1, -1 ); glVertex3f( +D, +D, +D );
289  glEnd();
290 
291  // GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
292  glBegin(GL_QUADS);
293  glTexCoord3f( -1, +1, +1 ); glVertex3f( +D, -D, -D );
294  glTexCoord3f( -1, +1, -1 ); glVertex3f( +D, -D, +D );
295  glTexCoord3f( +1, +1, -1 ); glVertex3f( -D, -D, +D );
296  glTexCoord3f( +1, +1, +1 ); glVertex3f( -D, -D, -D );
297 
298  glEnd();
299 
300  // GL_TEXTURE_CUBE_MAP_POSITIVE_Y
301  glBegin(GL_QUADS);
302  glTexCoord3f( +1, -1, +1 ); glVertex3f( -D, +D, -D );
303  glTexCoord3f( +1, -1, -1 ); glVertex3f( -D, +D, +D );
304  glTexCoord3f( -1, -1, -1 ); glVertex3f( +D, +D, +D );
305  glTexCoord3f( -1, -1, +1 ); glVertex3f( +D, +D, -D );
306  glEnd();
307 
308  // GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
309  glBegin(GL_QUADS);
310  glTexCoord3f( -1, +1, +1 ); glVertex3f( +D, -D, -D );
311  glTexCoord3f( +1, +1, +1 ); glVertex3f( -D, -D, -D );
312  glTexCoord3f( +1, -1, +1 ); glVertex3f( -D, +D, -D );
313  glTexCoord3f( -1, -1, +1 ); glVertex3f( +D, +D, -D );
314  glEnd();
315 
316  // GL_TEXTURE_CUBE_MAP_POSITIVE_Z
317  glBegin(GL_QUADS);
318  glTexCoord3f( +1, +1, -1 ); glVertex3f( -D, -D, +D );
319  glTexCoord3f( -1, +1, -1 ); glVertex3f( +D, -D, +D );
320  glTexCoord3f( -1, -1, -1 ); glVertex3f( +D, +D, +D );
321  glTexCoord3f( +1, -1, -1 ); glVertex3f( -D, +D, +D );
322  glEnd();
323 
324  if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER)
325  {
326  skytech->EndPass();
327  }
328  else
329  {
330  glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
331  glDisable(GL_TEXTURE_CUBE_MAP);
332  glEnable(GL_TEXTURE_2D);
333  }
334 
335  glPopMatrix();
336 
337  glDepthMask( GL_TRUE );
338 
339 #endif
340 }
void RenderSky()
RenderSky: Render the sky.
Definition: SkyManager.cpp:220
#define u8
Definition: types.h:39
Path VfsPath
VFS path of the form &quot;(dir/)*file?&quot;.
Definition: vfs_path.h:40
#define LOGERROR
Definition: CLogger.h:35
Status tex_transform_to(Tex *t, size_t new_flags)
Change &lt;t&gt;&#39;s pixel format (2nd version) (note: this is equivalent to tex_transform(t, t-&gt;flags^new_flags).
Definition: tex.cpp:494
flags &amp; TEX_DXT is a field indicating compression.
Definition: tex.h:149
mask
Definition: tex.h:199
indicates the image contains an alpha channel.
Definition: tex.h:171
shared_ptr< CShaderTechnique > CShaderTechniquePtr
GLuint m_SkyCubeMap
Definition: SkyManager.h:86
size_t h
Definition: tex.h:230
std::vector< CStrW > GetSkySets() const
Return a sorted list of available sky sets, in a form suitable for passing to SetSkySet.
Definition: SkyManager.cpp:197
flags &amp; TEX_ORIENTATION is a field indicating orientation, i.e.
Definition: tex.h:190
#define g_Renderer
Definition: Renderer.h:61
float m_HorizonHeight
Definition: SkyManager.h:34
float X
Definition: Vector3D.h:31
Definition: path.h:75
const String & string() const
Definition: path.h:123
std::wstring String
Definition: path.h:78
u8 * tex_get_data(const Tex *t)
rationale: since Tex is a struct, its fields are accessible to callers.
Definition: tex.cpp:629
CStrW m_SkySet
Name of current skyset (a directory within art/textures/skies)
Definition: SkyManager.h:70
Definition: Camera.h:39
void LoadSkyTextures()
Definition: SkyManager.cpp:77
size_t dataSize
Definition: tex.h:219
stores all data describing an image.
Definition: tex.h:210
bool m_RenderSky
Definition: SkyManager.h:33
size_t w
Definition: tex.h:229
std::vector< OsPath > DirectoryNames
Definition: file_system.h:77
static const wchar_t * s_imageNames[numTextures]
Definition: SkyManager.h:89
const CStrW & GetSkySet() const
GetSkySet(): Return the currently selected sky set name.
Definition: SkyManager.h:47
CMatrix3D m_Orientation
Definition: Camera.h:112
float Z
Definition: Vector3D.h:31
void SetSkySet(const CStrW &name)
GetSkySet(): Set the sky set name, potentially loading the textures.
Definition: SkyManager.cpp:179
CVector3D GetTranslation() const
Definition: Matrix3D.cpp:195
PIVFS g_VFS
Definition: Filesystem.cpp:30
shared_ptr< CShaderProgram > CShaderProgramPtr
size_t flags
see TexFlags and &quot;Format Conversion&quot; in docs.
Definition: tex.h:234
Status tex_decode(const shared_ptr< u8 > &data, size_t dataSize, Tex *t)
decode an in-memory texture file into texture object.
Definition: tex.cpp:717
void tex_free(Tex *t)
free all resources associated with the image and make further use of it impossible.
Definition: tex.cpp:610
#define RADTODEG(a)
Definition: MathUtil.h:22