1 /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
2
3 #include "Game/Camera.h"
4 #include "Game/Game.h"
5 #include "Map/BaseGroundDrawer.h"
6 #include "Map/Ground.h"
7 #include "Map/ReadMap.h"
8 #include "Map/MapInfo.h"
9 #include "Rendering/GlobalRendering.h"
10 #include "Rendering/UnitDrawer.h"
11 #include "Rendering/GL/myGL.h"
12 #include "Rendering/Env/ISky.h"
13 #include "Rendering/Env/CubeMapHandler.h"
14 #include "System/Config/ConfigHandler.h"
15
16 CONFIG(int, CubeTexSizeSpecular).defaultValue(128).minimumValue(1);
17 CONFIG(int, CubeTexSizeReflection).defaultValue(128).minimumValue(1);
18
19 static char cameraMemBuf[sizeof(CCamera)];
20
21 CubeMapHandler* cubeMapHandler = NULL;
22
CubeMapHandler()23 CubeMapHandler::CubeMapHandler() {
24 envReflectionTexID = 0;
25 skyReflectionTexID = 0;
26 specularTexID = 0;
27
28 reflTexSize = 0;
29 specTexSize = 0;
30
31 currReflectionFace = 0;
32 specularTexIter = 0;
33 mapSkyReflections = false;
34
35 specTexBuf = NULL;
36 }
37
Init()38 bool CubeMapHandler::Init() {
39 specTexSize = configHandler->GetInt("CubeTexSizeSpecular");
40 reflTexSize = configHandler->GetInt("CubeTexSizeReflection");
41 specTexBuf = new unsigned char[specTexSize * 4];
42
43 mapSkyReflections = !(mapInfo->smf.skyReflectModTexName.empty());
44
45 {
46 glGenTextures(1, &specularTexID);
47 glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, specularTexID);
48 glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
49 glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
50 glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
51 glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
52
53 CreateSpecularFace(GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, specTexSize, float3( 1, 1, 1), float3( 0, 0, -2), float3(0, -2, 0));
54 CreateSpecularFace(GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB, specTexSize, float3(-1, 1, -1), float3( 0, 0, 2), float3(0, -2, 0));
55 CreateSpecularFace(GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB, specTexSize, float3(-1, 1, -1), float3( 2, 0, 0), float3(0, 0, 2));
56 CreateSpecularFace(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB, specTexSize, float3(-1, -1, 1), float3( 2, 0, 0), float3(0, 0, -2));
57 CreateSpecularFace(GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB, specTexSize, float3(-1, 1, 1), float3( 2, 0, 0), float3(0, -2, 0));
58 CreateSpecularFace(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB, specTexSize, float3( 1, 1, -1), float3(-2, 0, 0), float3(0, -2, 0));
59 }
60
61 {
62 glGenTextures(1, &envReflectionTexID);
63 glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, envReflectionTexID);
64 glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
65 glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
66 glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
67 glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
68
69 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, 0, GL_RGBA8, reflTexSize, reflTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
70 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB, 0, GL_RGBA8, reflTexSize, reflTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
71 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB, 0, GL_RGBA8, reflTexSize, reflTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
72 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB, 0, GL_RGBA8, reflTexSize, reflTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
73 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB, 0, GL_RGBA8, reflTexSize, reflTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
74 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB, 0, GL_RGBA8, reflTexSize, reflTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
75 }
76
77 if (mapSkyReflections) {
78 glGenTextures(1, &skyReflectionTexID);
79 glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, skyReflectionTexID);
80 glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
81 glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
82 glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
83 glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
84
85 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, 0, GL_RGBA8, reflTexSize, reflTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
86 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB, 0, GL_RGBA8, reflTexSize, reflTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
87 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB, 0, GL_RGBA8, reflTexSize, reflTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
88 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB, 0, GL_RGBA8, reflTexSize, reflTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
89 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB, 0, GL_RGBA8, reflTexSize, reflTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
90 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB, 0, GL_RGBA8, reflTexSize, reflTexSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
91 }
92
93
94 if (reflectionCubeFBO.IsValid()) {
95 reflectionCubeFBO.Bind();
96 reflectionCubeFBO.CreateRenderBuffer(GL_DEPTH_ATTACHMENT_EXT, GL_DEPTH_COMPONENT, reflTexSize, reflTexSize);
97 reflectionCubeFBO.Unbind();
98 }
99
100 if (!reflectionCubeFBO.IsValid()) {
101 Free();
102 return false;
103 }
104
105 return true;
106 }
107
Free()108 void CubeMapHandler::Free() {
109 if (specularTexID != 0) {
110 glDeleteTextures(1, &specularTexID);
111 specularTexID = 0;
112 }
113 if (envReflectionTexID != 0) {
114 glDeleteTextures(1, &envReflectionTexID);
115 envReflectionTexID = 0;
116 }
117 if (skyReflectionTexID != 0) {
118 glDeleteTextures(1, &skyReflectionTexID);
119 skyReflectionTexID = 0;
120 }
121
122 delete [] specTexBuf;
123 }
124
125
126
UpdateReflectionTexture()127 void CubeMapHandler::UpdateReflectionTexture()
128 {
129 if (!unitDrawer->UseAdvShading())
130 return;
131
132 switch (currReflectionFace++) {
133 case 0: {
134 reflectionCubeFBO.Bind();
135 CreateReflectionFace(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB, -FwdVector, false);
136 CreateReflectionFace(GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB, UpVector, false);
137
138 if (mapSkyReflections) {
139 CreateReflectionFace(GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, RgtVector, true);
140 CreateReflectionFace(GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB, -RgtVector, true);
141 }
142 } break;
143 case 1: {} break;
144 case 2: {} break;
145 case 3: {
146 reflectionCubeFBO.Bind();
147 CreateReflectionFace(GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, RgtVector, false);
148 CreateReflectionFace(GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB, -RgtVector, false);
149
150 if (mapSkyReflections) {
151 CreateReflectionFace(GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB, UpVector, true);
152 CreateReflectionFace(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB, -UpVector, true);
153 }
154 } break;
155 case 4: {} break;
156 case 5: {} break;
157 case 6: {
158 reflectionCubeFBO.Bind();
159 CreateReflectionFace(GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB, FwdVector, false);
160 CreateReflectionFace(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB, -UpVector, false);
161
162 if (mapSkyReflections) {
163 CreateReflectionFace(GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB, FwdVector, true);
164 CreateReflectionFace(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB, -FwdVector, true);
165 }
166 } break;
167 case 7: {} break;
168 case 8: {
169 currReflectionFace = 0;
170 } break;
171 default: {
172 currReflectionFace = 0;
173 } break;
174 }
175 }
176
CreateReflectionFace(unsigned int glType,const float3 & camDir,bool skyOnly)177 void CubeMapHandler::CreateReflectionFace(unsigned int glType, const float3& camDir, bool skyOnly)
178 {
179 reflectionCubeFBO.AttachTexture((skyOnly? skyReflectionTexID: envReflectionTexID), glType);
180
181 glPushAttrib(GL_FOG_BIT | GL_DEPTH_BUFFER_BIT);
182 glViewport(0, 0, reflTexSize, reflTexSize);
183
184 if (skyOnly) {
185 glDepthMask(GL_FALSE);
186 glDisable(GL_DEPTH_TEST);
187 } else {
188 glClear(GL_DEPTH_BUFFER_BIT);
189 glDepthMask(GL_TRUE);
190 glEnable(GL_DEPTH_TEST);
191 }
192
193 // anti-crash workaround for multi-threading
194 new (cameraMemBuf) CCamera(*camera);
195
196 game->SetDrawMode(CGame::gameReflectionDraw);
197
198 camera->forward = camDir;
199 camera->SetFov(90.0f);
200 camera->SetPos((camera->GetPos()) * XZVector + UpVector * (CGround::GetHeightAboveWater(camera->GetPos().x, camera->GetPos().z, false) + 50.0f));
201 // calculate temporary new coor-system and matrices
202 camera->Update(true);
203
204 sky->Draw();
205
206 if (!skyOnly) {
207 readMap->GetGroundDrawer()->Draw(DrawPass::TerrainReflection);
208 }
209
210 // NOTE we do this later to save render context switches (this is one of the slowest OpenGL operations!)
211 // reflectionCubeFBO.Unbind();
212 // glViewport(globalRendering->viewPosX, 0, globalRendering->viewSizeX, globalRendering->viewSizeY);
213 glPopAttrib();
214
215 game->SetDrawMode(CGame::gameNormalDraw);
216
217 camera->~CCamera();
218 new (camera) CCamera(*reinterpret_cast<CCamera*>(cameraMemBuf));
219 reinterpret_cast<CCamera*>(cameraMemBuf)->~CCamera();
220
221 camera->Update();
222 }
223
224
UpdateSpecularTexture()225 void CubeMapHandler::UpdateSpecularTexture()
226 {
227 if (!unitDrawer->UseAdvShading())
228 return;
229
230 glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, specularTexID);
231
232 int specularTexRow = specularTexIter / 3; //FIXME WTF
233
234 switch (specularTexIter % 3) {
235 case 0: {
236 UpdateSpecularFace(GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, specTexSize, float3( 1, 1, 1), float3( 0, 0, -2), float3(0, -2, 0), specularTexRow, specTexBuf);
237 UpdateSpecularFace(GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB, specTexSize, float3(-1, 1, -1), float3( 0, 0, 2), float3(0, -2, 0), specularTexRow, specTexBuf);
238 break;
239 }
240 case 1: {
241 UpdateSpecularFace(GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB, specTexSize, float3(-1, 1, -1), float3( 2, 0, 0), float3(0, 0, 2), specularTexRow, specTexBuf);
242 UpdateSpecularFace(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB, specTexSize, float3(-1, -1, 1), float3( 2, 0, 0), float3(0, 0, -2), specularTexRow, specTexBuf);
243 break;
244 }
245 case 2: {
246 UpdateSpecularFace(GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB, specTexSize, float3(-1, 1, 1), float3( 2, 0, 0), float3(0, -2, 0), specularTexRow, specTexBuf);
247 UpdateSpecularFace(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB, specTexSize, float3( 1, 1, -1), float3(-2, 0, 0), float3(0, -2, 0), specularTexRow, specTexBuf);
248 break;
249 }
250 }
251
252 // update one face of one row per frame
253 ++specularTexIter;
254 specularTexIter = specularTexIter % (specTexSize * 3);
255 }
256
CreateSpecularFacePart(unsigned int texType,unsigned int size,const float3 & cdir,const float3 & xdif,const float3 & ydif,unsigned int y,unsigned char * buf)257 void CubeMapHandler::CreateSpecularFacePart(
258 unsigned int texType,
259 unsigned int size,
260 const float3& cdir,
261 const float3& xdif,
262 const float3& ydif,
263 unsigned int y,
264 unsigned char* buf)
265 {
266 // TODO move to a shader
267 for (int x = 0; x < size; ++x) {
268 const float3 dir = (cdir + (xdif * (x + 0.5f)) / size + (ydif * (y + 0.5f)) / size).Normalize();
269 const float dot = std::max(0.0f, dir.dot(sky->GetLight()->GetLightDir()));
270 const float spec = std::min(1.0f, math::pow(dot, mapInfo->light.specularExponent) + math::pow(dot, 3.0f) * 0.25f);
271
272 buf[x * 4 + 0] = (mapInfo->light.unitSpecularColor.x * spec * 255);
273 buf[x * 4 + 1] = (mapInfo->light.unitSpecularColor.y * spec * 255);
274 buf[x * 4 + 2] = (mapInfo->light.unitSpecularColor.z * spec * 255);
275 buf[x * 4 + 3] = 255;
276 }
277 }
278
CreateSpecularFace(unsigned int texType,unsigned int size,const float3 & cdir,const float3 & xdif,const float3 & ydif)279 void CubeMapHandler::CreateSpecularFace(
280 unsigned int texType,
281 unsigned int size,
282 const float3& cdir,
283 const float3& xdif,
284 const float3& ydif)
285 {
286 std::vector<unsigned char> buf(size * size * 4, 0);
287
288 for (int y = 0; y < size; ++y) {
289 CreateSpecularFacePart(texType, size, cdir, xdif, ydif, y, &buf[y * size * 4]);
290 }
291
292 //! note: no mipmaps, cubemap linear filtering is broken
293 glTexImage2D(texType, 0, GL_RGBA8, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, &buf[0]);
294 }
295
UpdateSpecularFace(unsigned int texType,unsigned int size,const float3 & cdir,const float3 & xdif,const float3 & ydif,unsigned int y,unsigned char * buf)296 void CubeMapHandler::UpdateSpecularFace(
297 unsigned int texType,
298 unsigned int size,
299 const float3& cdir,
300 const float3& xdif,
301 const float3& ydif,
302 unsigned int y,
303 unsigned char* buf)
304 {
305 CreateSpecularFacePart(texType, size, cdir, xdif, ydif, y, buf);
306
307 glTexSubImage2D(texType, 0, 0, y, size, 1, GL_RGBA, GL_UNSIGNED_BYTE, buf);
308 }
309
310