aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llrender/llcubemap.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra/llrender/llcubemap.cpp')
-rw-r--r--linden/indra/llrender/llcubemap.cpp532
1 files changed, 532 insertions, 0 deletions
diff --git a/linden/indra/llrender/llcubemap.cpp b/linden/indra/llrender/llcubemap.cpp
new file mode 100644
index 0000000..563d616
--- /dev/null
+++ b/linden/indra/llrender/llcubemap.cpp
@@ -0,0 +1,532 @@
1/**
2 * @file llcubemap.cpp
3 * @brief LLCubeMap class implementation
4 *
5 * $LicenseInfo:firstyear=2002&license=viewergpl$
6 *
7 * Copyright (c) 2002-2008, Linden Research, Inc.
8 *
9 * Second Life Viewer Source Code
10 * The source code in this file ("Source Code") is provided by Linden Lab
11 * to you under the terms of the GNU General Public License, version 2.0
12 * ("GPL"), unless you have obtained a separate licensing agreement
13 * ("Other License"), formally executed by you and Linden Lab. Terms of
14 * the GPL can be found in doc/GPL-license.txt in this distribution, or
15 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
16 *
17 * There are special exceptions to the terms and conditions of the GPL as
18 * it is applied to this Source Code. View the full text of the exception
19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 *
22 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above,
24 * and agree to abide by those obligations.
25 *
26 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
27 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
28 * COMPLETENESS OR PERFORMANCE.
29 * $/LicenseInfo$
30 */
31#include "linden_common.h"
32
33#include "llworkerthread.h"
34
35#include "llcubemap.h"
36
37#include "v4coloru.h"
38#include "v3math.h"
39#include "v3dmath.h"
40#include "m3math.h"
41#include "m4math.h"
42#include "llcamera.h"
43
44#include "llrender.h"
45
46#include "llglheaders.h"
47
48const F32 epsilon = 1e-7f;
49const U16 RESOLUTION = 64;
50
51#if LL_DARWIN
52// mipmap generation on cubemap textures seems to be broken on the Mac for at least some cards.
53// Since the cubemap is small (64x64 per face) and doesn't have any fine detail, turning off mipmaps is a usable workaround.
54const BOOL use_cube_mipmaps = FALSE;
55#else
56const BOOL use_cube_mipmaps = FALSE; //current build works best without cube mipmaps
57#endif
58
59bool LLCubeMap::sUseCubeMaps = true;
60
61LLCubeMap::LLCubeMap()
62 : mTextureStage(0),
63 mTextureCoordStage(0),
64 mMatrixStage(0)
65{
66}
67
68LLCubeMap::~LLCubeMap()
69{
70}
71
72void LLCubeMap::initGL()
73{
74 llassert(gGLManager.mInited);
75
76 if (gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps)
77 {
78 mTargets[0] = GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB;
79 mTargets[1] = GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB;
80 mTargets[2] = GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB;
81 mTargets[3] = GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB;
82 mTargets[4] = GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB;
83 mTargets[5] = GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB;
84
85 // Not initialized, do stuff.
86 if (mImages[0].isNull())
87 {
88 GLuint texname = 0;
89
90 glGenTextures(1, &texname);
91
92 for (int i = 0; i < 6; i++)
93 {
94 mImages[i] = new LLImageGL(64, 64, 4, (use_cube_mipmaps? TRUE : FALSE));
95 mImages[i]->setTarget(mTargets[i], GL_TEXTURE_CUBE_MAP_ARB);
96 mRawImages[i] = new LLImageRaw(64, 64, 4);
97 mImages[i]->createGLTexture(0, mRawImages[i], texname);
98
99 glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, texname);
100 mImages[i]->setClampCubemap (TRUE, TRUE, TRUE);
101 stop_glerror();
102 }
103 }
104 disable();
105 }
106 else
107 {
108 llwarns << "Using cube map without extension!" << llendl
109 }
110}
111
112void LLCubeMap::initRawData(const std::vector<LLPointer<LLImageRaw> >& rawimages)
113{
114 bool flip_x[6] = { false, true, false, false, true, false };
115 bool flip_y[6] = { true, true, true, false, true, true };
116 bool transpose[6] = { false, false, false, false, true, true };
117
118 // Yes, I know that this is inefficient! - djs 08/08/02
119 for (int i = 0; i < 6; i++)
120 {
121 const U8 *sd = rawimages[i]->getData();
122 U8 *td = mRawImages[i]->getData();
123
124 S32 offset = 0;
125 S32 sx, sy, so;
126 for (int y = 0; y < 64; y++)
127 {
128 for (int x = 0; x < 64; x++)
129 {
130 sx = x;
131 sy = y;
132 if (flip_y[i])
133 {
134 sy = 63 - y;
135 }
136 if (flip_x[i])
137 {
138 sx = 63 - x;
139 }
140 if (transpose[i])
141 {
142 S32 temp = sx;
143 sx = sy;
144 sy = temp;
145 }
146
147 so = 64*sy + sx;
148 so *= 4;
149 *(td + offset++) = *(sd + so++);
150 *(td + offset++) = *(sd + so++);
151 *(td + offset++) = *(sd + so++);
152 *(td + offset++) = *(sd + so++);
153 }
154 }
155 }
156}
157
158void LLCubeMap::initGLData()
159{
160 for (int i = 0; i < 6; i++)
161 {
162 mImages[i]->setSubImage(mRawImages[i], 0, 0, 64, 64);
163 }
164}
165
166void LLCubeMap::init(const std::vector<LLPointer<LLImageRaw> >& rawimages)
167{
168 if (!gGLManager.mIsDisabled)
169 {
170 initGL();
171 initRawData(rawimages);
172 initGLData();
173 }
174}
175
176GLuint LLCubeMap::getGLName()
177{
178 return mImages[0]->getTexName();
179}
180
181void LLCubeMap::bind()
182{
183 if (gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps)
184 {
185 // We assume that if they have cube mapping, they have multitexturing.
186 if (mTextureStage > 0)
187 {
188 gGL.getTexUnit(mTextureStage)->activate();
189 }
190 glEnable(GL_TEXTURE_CUBE_MAP_ARB);
191 glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, mImages[0]->getTexName());
192
193 mImages[0]->setMipFilterNearest (FALSE, FALSE);
194 if (mTextureStage > 0)
195 {
196 gGL.getTexUnit(0)->activate();
197 }
198 }
199 else
200 {
201 llwarns << "Using cube map without extension!" << llendl
202 }
203}
204
205void LLCubeMap::enable(S32 stage)
206{
207 enableTexture(stage);
208 enableTextureCoords(stage);
209}
210
211void LLCubeMap::enableTexture(S32 stage)
212{
213 mTextureStage = stage;
214 if (gGLManager.mHasCubeMap && stage >= 0 && LLCubeMap::sUseCubeMaps)
215 {
216 if (stage > 0)
217 {
218 gGL.getTexUnit(stage)->activate();
219 }
220
221 glEnable(GL_TEXTURE_CUBE_MAP_ARB);
222
223 if (stage > 0)
224 {
225 gGL.getTexUnit(0)->activate();
226 }
227 }
228}
229
230void LLCubeMap::enableTextureCoords(S32 stage)
231{
232 mTextureCoordStage = stage;
233 if (gGLManager.mHasCubeMap && stage >= 0 && LLCubeMap::sUseCubeMaps)
234 {
235 if (stage > 0)
236 {
237 gGL.getTexUnit(stage)->activate();
238 }
239
240 glEnable(GL_TEXTURE_GEN_R);
241 glEnable(GL_TEXTURE_GEN_S);
242 glEnable(GL_TEXTURE_GEN_T);
243
244 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
245 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
246 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
247
248 if (stage > 0)
249 {
250 gGL.getTexUnit(0)->activate();
251 }
252 }
253}
254
255void LLCubeMap::disable(void)
256{
257 disableTexture();
258 disableTextureCoords();
259}
260
261void LLCubeMap::disableTexture(void)
262{
263 if (gGLManager.mHasCubeMap && mTextureStage >= 0 && LLCubeMap::sUseCubeMaps)
264 {
265 if (mTextureStage > 0)
266 {
267 gGL.getTexUnit(mTextureStage)->activate();
268 }
269 glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, 0);
270 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
271 if (mTextureStage > 0)
272 {
273 gGL.getTexUnit(0)->activate();
274 }
275 }
276}
277
278void LLCubeMap::disableTextureCoords(void)
279{
280 if (gGLManager.mHasCubeMap && mTextureCoordStage >= 0 && LLCubeMap::sUseCubeMaps)
281 {
282 if (mTextureCoordStage > 0)
283 {
284 gGL.getTexUnit(mTextureCoordStage)->activate();
285 }
286 glDisable(GL_TEXTURE_GEN_S);
287 glDisable(GL_TEXTURE_GEN_T);
288 glDisable(GL_TEXTURE_GEN_R);
289 if (mTextureCoordStage > 0)
290 {
291 gGL.getTexUnit(0)->activate();
292 }
293 }
294}
295
296void LLCubeMap::setMatrix(S32 stage)
297{
298 mMatrixStage = stage;
299
300 if (stage > 0)
301 {
302 gGL.getTexUnit(stage)->activate();
303 }
304
305 LLVector3 x(LLVector3d(gGLModelView+0));
306 LLVector3 y(LLVector3d(gGLModelView+4));
307 LLVector3 z(LLVector3d(gGLModelView+8));
308
309 LLMatrix3 mat3;
310 mat3.setRows(x,y,z);
311 LLMatrix4 trans(mat3);
312 trans.transpose();
313
314 glMatrixMode(GL_TEXTURE);
315 glPushMatrix();
316 glLoadMatrixf((F32 *)trans.mMatrix);
317 glMatrixMode(GL_MODELVIEW);
318
319 if (stage > 0)
320 {
321 gGL.getTexUnit(0)->activate();
322 }
323}
324
325void LLCubeMap::restoreMatrix()
326{
327 if (mMatrixStage > 0)
328 {
329 gGL.getTexUnit(mMatrixStage)->activate();
330 }
331 glMatrixMode(GL_TEXTURE);
332 glPopMatrix();
333 glMatrixMode(GL_MODELVIEW);
334
335 if (mMatrixStage > 0)
336 {
337 gGL.getTexUnit(0)->activate();
338 }
339}
340
341void LLCubeMap::setReflection (void)
342{
343 glBindTexture (GL_TEXTURE_CUBE_MAP_ARB, getGLName());
344 mImages[0]->setMipFilterNearest (FALSE, FALSE);
345 mImages[0]->setClampCubemap (TRUE, TRUE);
346}
347
348LLVector3 LLCubeMap::map(U8 side, U16 v_val, U16 h_val) const
349{
350 LLVector3 dir;
351
352 const U8 curr_coef = side >> 1; // 0/1 = X axis, 2/3 = Y, 4/5 = Z
353 const S8 side_dir = (((side & 1) << 1) - 1); // even = -1, odd = 1
354 const U8 i_coef = (curr_coef + 1) % 3;
355 const U8 j_coef = (i_coef + 1) % 3;
356
357 dir.mV[curr_coef] = side_dir;
358
359 switch (side)
360 {
361 case 0: // negative X
362 dir.mV[i_coef] = -F32((v_val<<1) + 1) / RESOLUTION + 1;
363 dir.mV[j_coef] = F32((h_val<<1) + 1) / RESOLUTION - 1;
364 break;
365 case 1: // positive X
366 dir.mV[i_coef] = -F32((v_val<<1) + 1) / RESOLUTION + 1;
367 dir.mV[j_coef] = -F32((h_val<<1) + 1) / RESOLUTION + 1;
368 break;
369 case 2: // negative Y
370 dir.mV[i_coef] = -F32((v_val<<1) + 1) / RESOLUTION + 1;
371 dir.mV[j_coef] = F32((h_val<<1) + 1) / RESOLUTION - 1;
372 break;
373 case 3: // positive Y
374 dir.mV[i_coef] = F32((v_val<<1) + 1) / RESOLUTION - 1;
375 dir.mV[j_coef] = F32((h_val<<1) + 1) / RESOLUTION - 1;
376 break;
377 case 4: // negative Z
378 dir.mV[i_coef] = -F32((h_val<<1) + 1) / RESOLUTION + 1;
379 dir.mV[j_coef] = -F32((v_val<<1) + 1) / RESOLUTION + 1;
380 break;
381 case 5: // positive Z
382 dir.mV[i_coef] = -F32((h_val<<1) + 1) / RESOLUTION + 1;
383 dir.mV[j_coef] = F32((v_val<<1) + 1) / RESOLUTION - 1;
384 break;
385 default:
386 dir.mV[i_coef] = F32((v_val<<1) + 1) / RESOLUTION - 1;
387 dir.mV[j_coef] = F32((h_val<<1) + 1) / RESOLUTION - 1;
388 }
389
390 dir.normVec();
391 return dir;
392}
393
394
395BOOL LLCubeMap::project(F32& v_val, F32& h_val, BOOL& outside,
396 U8 side, const LLVector3& dir) const
397{
398 const U8 curr_coef = side >> 1; // 0/1 = X axis, 2/3 = Y, 4/5 = Z
399 const S8 side_dir = (((side & 1) << 1) - 1); // even = -1, odd = 1
400 const U8 i_coef = (curr_coef + 1) % 3;
401 const U8 j_coef = (i_coef + 1) % 3;
402
403 outside = TRUE;
404 if (side_dir * dir.mV[curr_coef] < 0)
405 return FALSE;
406
407 LLVector3 ray;
408
409 F32 norm_val = fabs(dir.mV[curr_coef]);
410
411 if (norm_val < epsilon)
412 norm_val = 1e-5f;
413
414 ray.mV[curr_coef] = side_dir;
415 ray.mV[i_coef] = dir.mV[i_coef] / norm_val;
416 ray.mV[j_coef] = dir.mV[j_coef] / norm_val;
417
418
419 const F32 i_val = (ray.mV[i_coef] + 1) * 0.5f * RESOLUTION;
420 const F32 j_val = (ray.mV[j_coef] + 1) * 0.5f * RESOLUTION;
421
422 switch (side)
423 {
424 case 0: // negative X
425 v_val = RESOLUTION - i_val;
426 h_val = j_val;
427 break;
428 case 1: // positive X
429 v_val = RESOLUTION - i_val;
430 h_val = RESOLUTION - j_val;
431 break;
432 case 2: // negative Y
433 v_val = RESOLUTION - i_val;
434 h_val = j_val;
435 break;
436 case 3: // positive Y
437 v_val = i_val;
438 h_val = j_val;
439 break;
440 case 4: // negative Z
441 v_val = RESOLUTION - j_val;
442 h_val = RESOLUTION - i_val;
443 break;
444 case 5: // positive Z
445 v_val = RESOLUTION - j_val;
446 h_val = i_val;
447 break;
448 default:
449 v_val = i_val;
450 h_val = j_val;
451 }
452
453 outside = ((v_val < 0) || (v_val > RESOLUTION) ||
454 (h_val < 0) || (h_val > RESOLUTION));
455
456 return TRUE;
457}
458
459BOOL LLCubeMap::project(F32& v_min, F32& v_max, F32& h_min, F32& h_max,
460 U8 side, LLVector3 dir[4]) const
461{
462 v_min = h_min = RESOLUTION;
463 v_max = h_max = 0;
464
465 BOOL fully_outside = TRUE;
466 for (U8 vtx = 0; vtx < 4; ++vtx)
467 {
468 F32 v_val, h_val;
469 BOOL outside;
470 BOOL consider = project(v_val, h_val, outside, side, dir[vtx]);
471 if (!outside)
472 fully_outside = FALSE;
473 if (consider)
474 {
475 if (v_val < v_min) v_min = v_val;
476 if (v_val > v_max) v_max = v_val;
477 if (h_val < h_min) h_min = h_val;
478 if (h_val > h_max) h_max = h_val;
479 }
480 }
481
482 v_min = llmax(0.0f, v_min);
483 v_max = llmin(RESOLUTION - epsilon, v_max);
484 h_min = llmax(0.0f, h_min);
485 h_max = llmin(RESOLUTION - epsilon, h_max);
486
487 return !fully_outside;
488}
489
490
491void LLCubeMap::paintIn(LLVector3 dir[4], const LLColor4U& col)
492{
493 F32 v_min, v_max, h_min, h_max;
494 LLVector3 center = dir[0] + dir[1] + dir[2] + dir[3];
495 center.normVec();
496
497 for (U8 side = 0; side < 6; ++side)
498 {
499 if (!project(v_min, v_max, h_min, h_max, side, dir))
500 continue;
501
502 U8 *td = mRawImages[side]->getData();
503
504 U16 v_minu = (U16) v_min;
505 U16 v_maxu = (U16) (ceil(v_max) + 0.5);
506 U16 h_minu = (U16) h_min;
507 U16 h_maxu = (U16) (ceil(h_max) + 0.5);
508
509 for (U16 v = v_minu; v < v_maxu; ++v)
510 for (U16 h = h_minu; h < h_maxu; ++h)
511 //for (U16 v = 0; v < RESOLUTION; ++v)
512 // for (U16 h = 0; h < RESOLUTION; ++h)
513 {
514 const LLVector3 ray = map(side, v, h);
515 if (ray * center > 0.999)
516 {
517 const U32 offset = (RESOLUTION * v + h) * 4;
518 for (U8 cc = 0; cc < 3; ++cc)
519 td[offset + cc] = U8((td[offset + cc] + col.mV[cc]) * 0.5);
520 }
521 }
522 mImages[side]->setSubImage(mRawImages[side], 0, 0, 64, 64);
523 }
524}
525
526void LLCubeMap::destroyGL()
527{
528 for (S32 i = 0; i < 6; i++)
529 {
530 mImages[i] = NULL;
531 }
532}