diff options
Diffstat (limited to 'linden/indra/llrender/llcubemap.cpp')
-rw-r--r-- | linden/indra/llrender/llcubemap.cpp | 532 |
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 | |||
48 | const F32 epsilon = 1e-7f; | ||
49 | const 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. | ||
54 | const BOOL use_cube_mipmaps = FALSE; | ||
55 | #else | ||
56 | const BOOL use_cube_mipmaps = FALSE; //current build works best without cube mipmaps | ||
57 | #endif | ||
58 | |||
59 | bool LLCubeMap::sUseCubeMaps = true; | ||
60 | |||
61 | LLCubeMap::LLCubeMap() | ||
62 | : mTextureStage(0), | ||
63 | mTextureCoordStage(0), | ||
64 | mMatrixStage(0) | ||
65 | { | ||
66 | } | ||
67 | |||
68 | LLCubeMap::~LLCubeMap() | ||
69 | { | ||
70 | } | ||
71 | |||
72 | void 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 | |||
112 | void 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 | |||
158 | void 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 | |||
166 | void LLCubeMap::init(const std::vector<LLPointer<LLImageRaw> >& rawimages) | ||
167 | { | ||
168 | if (!gGLManager.mIsDisabled) | ||
169 | { | ||
170 | initGL(); | ||
171 | initRawData(rawimages); | ||
172 | initGLData(); | ||
173 | } | ||
174 | } | ||
175 | |||
176 | GLuint LLCubeMap::getGLName() | ||
177 | { | ||
178 | return mImages[0]->getTexName(); | ||
179 | } | ||
180 | |||
181 | void 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 | |||
205 | void LLCubeMap::enable(S32 stage) | ||
206 | { | ||
207 | enableTexture(stage); | ||
208 | enableTextureCoords(stage); | ||
209 | } | ||
210 | |||
211 | void 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 | |||
230 | void 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 | |||
255 | void LLCubeMap::disable(void) | ||
256 | { | ||
257 | disableTexture(); | ||
258 | disableTextureCoords(); | ||
259 | } | ||
260 | |||
261 | void 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 | |||
278 | void 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 | |||
296 | void 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 | |||
325 | void 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 | |||
341 | void 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 | |||
348 | LLVector3 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 | |||
395 | BOOL 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 | |||
459 | BOOL 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 | |||
491 | void 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 | |||
526 | void LLCubeMap::destroyGL() | ||
527 | { | ||
528 | for (S32 i = 0; i < 6; i++) | ||
529 | { | ||
530 | mImages[i] = NULL; | ||
531 | } | ||
532 | } | ||