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