PageRenderTime 101ms CodeModel.GetById 33ms app.highlight 63ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llrender/llcubemap.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 497 lines | 385 code | 71 blank | 41 comment | 54 complexity | 28ce6806011f01df544399250c7ecbdc MD5 | raw file
  1/** 
  2 * @file llcubemap.cpp
  3 * @brief LLCubeMap class implementation
  4 *
  5 * $LicenseInfo:firstyear=2002&license=viewerlgpl$
  6 * Second Life Viewer Source Code
  7 * Copyright (C) 2010, Linden Research, Inc.
  8 * 
  9 * This library is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU Lesser General Public
 11 * License as published by the Free Software Foundation;
 12 * version 2.1 of the License only.
 13 * 
 14 * This library is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * Lesser General Public License for more details.
 18 * 
 19 * You should have received a copy of the GNU Lesser General Public
 20 * License along with this library; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 22 * 
 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 24 * $/LicenseInfo$
 25 */
 26#include "linden_common.h"
 27
 28#include "llworkerthread.h"
 29
 30#include "llcubemap.h"
 31
 32#include "v4coloru.h"
 33#include "v3math.h"
 34#include "v3dmath.h"
 35#include "m3math.h"
 36#include "m4math.h"
 37
 38#include "llrender.h"
 39#include "llglslshader.h"
 40
 41#include "llglheaders.h"
 42
 43const F32 epsilon = 1e-7f;
 44const U16 RESOLUTION = 64;
 45
 46#if LL_DARWIN
 47// mipmap generation on cubemap textures seems to be broken on the Mac for at least some cards.
 48// Since the cubemap is small (64x64 per face) and doesn't have any fine detail, turning off mipmaps is a usable workaround.
 49const BOOL use_cube_mipmaps = FALSE;
 50#else
 51const BOOL use_cube_mipmaps = FALSE;  //current build works best without cube mipmaps
 52#endif
 53
 54bool LLCubeMap::sUseCubeMaps = true;
 55
 56LLCubeMap::LLCubeMap()
 57	: mTextureStage(0),
 58	  mTextureCoordStage(0),
 59	  mMatrixStage(0)
 60{
 61	mTargets[0] = GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB;
 62	mTargets[1] = GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB;
 63	mTargets[2] = GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB;
 64	mTargets[3] = GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB;
 65	mTargets[4] = GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB;
 66	mTargets[5] = GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB;
 67}
 68
 69LLCubeMap::~LLCubeMap()
 70{
 71}
 72
 73void LLCubeMap::initGL()
 74{
 75	llassert(gGLManager.mInited);
 76
 77	if (gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps)
 78	{
 79		// Not initialized, do stuff.
 80		if (mImages[0].isNull())
 81		{
 82			U32 texname = 0;
 83			
 84			LLImageGL::generateTextures(1, &texname);
 85
 86			for (int i = 0; i < 6; i++)
 87			{
 88				mImages[i] = new LLImageGL(64, 64, 4, (use_cube_mipmaps? TRUE : FALSE));
 89				mImages[i]->setTarget(mTargets[i], LLTexUnit::TT_CUBE_MAP);
 90				mRawImages[i] = new LLImageRaw(64, 64, 4);
 91				mImages[i]->createGLTexture(0, mRawImages[i], texname);
 92				
 93				gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_CUBE_MAP, texname); 
 94				mImages[i]->setAddressMode(LLTexUnit::TAM_CLAMP);
 95				stop_glerror();
 96			}
 97			gGL.getTexUnit(0)->disable();
 98		}
 99		disable();
100	}
101	else
102	{
103		llwarns << "Using cube map without extension!" << llendl;
104	}
105}
106
107void LLCubeMap::initRawData(const std::vector<LLPointer<LLImageRaw> >& rawimages)
108{
109	bool flip_x[6] =	{ false, true,  false, false, true,  false };
110	bool flip_y[6] = 	{ true,  true,  true,  false, true,  true  };
111	bool transpose[6] = { false, false, false, false, true,  true  };
112	
113	// Yes, I know that this is inefficient! - djs 08/08/02
114	for (int i = 0; i < 6; i++)
115	{
116		const U8 *sd = rawimages[i]->getData();
117		U8 *td = mRawImages[i]->getData();
118
119		S32 offset = 0;
120		S32 sx, sy, so;
121		for (int y = 0; y < 64; y++)
122		{
123			for (int x = 0; x < 64; x++)
124			{
125				sx = x;
126				sy = y;
127				if (flip_y[i])
128				{
129					sy = 63 - y;
130				}
131				if (flip_x[i])
132				{
133					sx = 63 - x;
134				}
135				if (transpose[i])
136				{
137					S32 temp = sx;
138					sx = sy;
139					sy = temp;
140				}
141
142				so = 64*sy + sx;
143				so *= 4;
144				*(td + offset++) = *(sd + so++);
145				*(td + offset++) = *(sd + so++);
146				*(td + offset++) = *(sd + so++);
147				*(td + offset++) = *(sd + so++);
148			}
149		}
150	}
151}
152
153void LLCubeMap::initGLData()
154{
155	for (int i = 0; i < 6; i++)
156	{
157		mImages[i]->setSubImage(mRawImages[i], 0, 0, 64, 64);
158	}
159}
160
161void LLCubeMap::init(const std::vector<LLPointer<LLImageRaw> >& rawimages)
162{
163	if (!gGLManager.mIsDisabled)
164	{
165		initGL();
166		initRawData(rawimages);
167		initGLData();
168	}
169}
170
171GLuint LLCubeMap::getGLName()
172{
173	return mImages[0]->getTexName();
174}
175
176void LLCubeMap::bind()
177{
178	gGL.getTexUnit(mTextureStage)->bind(this);
179}
180
181void LLCubeMap::enable(S32 stage)
182{
183	enableTexture(stage);
184	enableTextureCoords(stage);
185}
186
187void LLCubeMap::enableTexture(S32 stage)
188{
189	mTextureStage = stage;
190	if (gGLManager.mHasCubeMap && stage >= 0 && LLCubeMap::sUseCubeMaps)
191	{
192		gGL.getTexUnit(stage)->enable(LLTexUnit::TT_CUBE_MAP);
193	}
194}
195
196void LLCubeMap::enableTextureCoords(S32 stage)
197{
198	mTextureCoordStage = stage;
199	if (!LLGLSLShader::sNoFixedFunction && gGLManager.mHasCubeMap && stage >= 0 && LLCubeMap::sUseCubeMaps)
200	{
201		if (stage > 0)
202		{
203			gGL.getTexUnit(stage)->activate();
204		}
205		
206		glEnable(GL_TEXTURE_GEN_R);
207		glEnable(GL_TEXTURE_GEN_S);
208		glEnable(GL_TEXTURE_GEN_T);
209
210		glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
211		glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
212		glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
213		
214		if (stage > 0)
215		{
216			gGL.getTexUnit(0)->activate();
217		}
218	}
219}
220
221void LLCubeMap::disable(void)
222{
223	disableTexture();
224	disableTextureCoords();
225}
226
227void LLCubeMap::disableTexture(void)
228{
229	if (gGLManager.mHasCubeMap && mTextureStage >= 0 && LLCubeMap::sUseCubeMaps)
230	{
231		gGL.getTexUnit(mTextureStage)->disable();
232		if (mTextureStage == 0)
233		{
234			gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
235		}
236	}
237}
238
239void LLCubeMap::disableTextureCoords(void)
240{
241	if (!LLGLSLShader::sNoFixedFunction && gGLManager.mHasCubeMap && mTextureCoordStage >= 0 && LLCubeMap::sUseCubeMaps)
242	{
243		if (mTextureCoordStage > 0)
244		{
245			gGL.getTexUnit(mTextureCoordStage)->activate();
246		}
247		glDisable(GL_TEXTURE_GEN_S);
248		glDisable(GL_TEXTURE_GEN_T);
249		glDisable(GL_TEXTURE_GEN_R);
250		if (mTextureCoordStage > 0)
251		{
252			gGL.getTexUnit(0)->activate();
253		}
254	}
255}
256
257void LLCubeMap::setMatrix(S32 stage)
258{
259	mMatrixStage = stage;
260	
261	if (mMatrixStage < 0) return;
262	
263	//if (stage > 0)
264	{
265		gGL.getTexUnit(stage)->activate();
266	}
267
268	LLVector3 x(gGLModelView+0);
269	LLVector3 y(gGLModelView+4);
270	LLVector3 z(gGLModelView+8);
271
272	LLMatrix3 mat3;
273	mat3.setRows(x,y,z);
274	LLMatrix4 trans(mat3);
275	trans.transpose();
276
277	gGL.matrixMode(LLRender::MM_TEXTURE);
278	gGL.pushMatrix();
279	gGL.loadMatrix((F32 *)trans.mMatrix);
280	gGL.matrixMode(LLRender::MM_MODELVIEW);
281	
282	/*if (stage > 0)
283	{
284		gGL.getTexUnit(0)->activate();
285	}*/
286}
287
288void LLCubeMap::restoreMatrix()
289{
290	if (mMatrixStage < 0) return;
291
292	//if (mMatrixStage > 0)
293	{
294		gGL.getTexUnit(mMatrixStage)->activate();
295	}
296	gGL.matrixMode(LLRender::MM_TEXTURE);
297	gGL.popMatrix();
298	gGL.matrixMode(LLRender::MM_MODELVIEW);
299	
300	/*if (mMatrixStage > 0)
301	{
302		gGL.getTexUnit(0)->activate();
303	}*/
304}
305
306void LLCubeMap::setReflection (void)
307{
308	gGL.getTexUnit(mTextureStage)->bindManual(LLTexUnit::TT_CUBE_MAP, getGLName());
309	mImages[0]->setFilteringOption(LLTexUnit::TFO_ANISOTROPIC);
310	mImages[0]->setAddressMode(LLTexUnit::TAM_CLAMP);
311}
312
313LLVector3 LLCubeMap::map(U8 side, U16 v_val, U16 h_val) const
314{
315	LLVector3 dir;
316
317	const U8 curr_coef = side >> 1; // 0/1 = X axis, 2/3 = Y, 4/5 = Z
318	const S8 side_dir = (((side & 1) << 1) - 1);  // even = -1, odd = 1
319	const U8 i_coef = (curr_coef + 1) % 3;
320	const U8 j_coef = (i_coef + 1) % 3;
321
322	dir.mV[curr_coef] = side_dir;
323
324	switch (side)
325	{
326	case 0: // negative X
327		dir.mV[i_coef] = -F32((v_val<<1) + 1) / RESOLUTION + 1;
328		dir.mV[j_coef] = F32((h_val<<1) + 1) / RESOLUTION - 1;
329		break;
330	case 1: // positive X
331		dir.mV[i_coef] = -F32((v_val<<1) + 1) / RESOLUTION + 1;
332		dir.mV[j_coef] = -F32((h_val<<1) + 1) / RESOLUTION + 1;
333		break;
334	case 2:	// negative Y
335		dir.mV[i_coef] = -F32((v_val<<1) + 1) / RESOLUTION + 1;
336		dir.mV[j_coef] = F32((h_val<<1) + 1) / RESOLUTION - 1;
337		break;
338	case 3:	// positive Y
339		dir.mV[i_coef] = F32((v_val<<1) + 1) / RESOLUTION - 1;
340		dir.mV[j_coef] = F32((h_val<<1) + 1) / RESOLUTION - 1;
341		break;
342	case 4:	// negative Z
343		dir.mV[i_coef] = -F32((h_val<<1) + 1) / RESOLUTION + 1;
344		dir.mV[j_coef] = -F32((v_val<<1) + 1) / RESOLUTION + 1;
345		break;
346	case 5: // positive Z
347		dir.mV[i_coef] = -F32((h_val<<1) + 1) / RESOLUTION + 1;
348		dir.mV[j_coef] = F32((v_val<<1) + 1) / RESOLUTION - 1;
349		break;
350	default:
351		dir.mV[i_coef] = F32((v_val<<1) + 1) / RESOLUTION - 1;
352		dir.mV[j_coef] = F32((h_val<<1) + 1) / RESOLUTION - 1;
353	}
354
355	dir.normVec();
356	return dir;
357}
358
359
360BOOL LLCubeMap::project(F32& v_val, F32& h_val, BOOL& outside,
361						U8 side, const LLVector3& dir) const
362{
363	const U8 curr_coef = side >> 1; // 0/1 = X axis, 2/3 = Y, 4/5 = Z
364	const S8 side_dir = (((side & 1) << 1) - 1);  // even = -1, odd = 1
365	const U8 i_coef = (curr_coef + 1) % 3;
366	const U8 j_coef = (i_coef + 1) % 3;
367
368	outside = TRUE;
369	if (side_dir * dir.mV[curr_coef] < 0)
370		return FALSE;
371
372	LLVector3 ray;
373
374	F32 norm_val = fabs(dir.mV[curr_coef]);
375
376	if (norm_val < epsilon)
377		norm_val = 1e-5f;
378
379	ray.mV[curr_coef] = side_dir;
380	ray.mV[i_coef] = dir.mV[i_coef] / norm_val;
381	ray.mV[j_coef] = dir.mV[j_coef] / norm_val;
382
383
384	const F32 i_val = (ray.mV[i_coef] + 1) * 0.5f * RESOLUTION;
385	const F32 j_val = (ray.mV[j_coef] + 1) * 0.5f * RESOLUTION;
386
387	switch (side)
388	{
389	case 0: // negative X
390		v_val = RESOLUTION - i_val;
391		h_val = j_val;
392		break;
393	case 1: // positive X
394		v_val = RESOLUTION - i_val;
395		h_val = RESOLUTION - j_val;
396		break;
397	case 2:	// negative Y
398		v_val = RESOLUTION - i_val;
399		h_val = j_val;
400		break;
401	case 3:	// positive Y
402		v_val = i_val;
403		h_val = j_val;
404		break;
405	case 4:	// negative Z
406		v_val = RESOLUTION - j_val;
407		h_val = RESOLUTION - i_val;
408		break;
409	case 5: // positive Z
410		v_val = RESOLUTION - j_val;
411		h_val = i_val;
412		break;
413	default:
414		v_val = i_val;
415		h_val = j_val;
416	}
417
418	outside =  ((v_val < 0) || (v_val > RESOLUTION) ||
419		(h_val < 0) || (h_val > RESOLUTION));
420
421	return TRUE;
422}
423
424BOOL LLCubeMap::project(F32& v_min, F32& v_max, F32& h_min, F32& h_max, 
425						U8 side, LLVector3 dir[4]) const
426{
427	v_min = h_min = RESOLUTION;
428	v_max = h_max = 0;
429
430	BOOL fully_outside = TRUE;
431	for (U8 vtx = 0; vtx < 4; ++vtx)
432	{
433		F32 v_val, h_val;
434		BOOL outside;
435		BOOL consider = project(v_val, h_val, outside, side, dir[vtx]);
436		if (!outside)
437			fully_outside = FALSE;
438		if (consider)
439		{
440			if (v_val < v_min) v_min = v_val;
441			if (v_val > v_max) v_max = v_val;
442			if (h_val < h_min) h_min = h_val;
443			if (h_val > h_max) h_max = h_val;
444		}
445	}
446
447	v_min = llmax(0.0f, v_min);
448	v_max = llmin(RESOLUTION - epsilon, v_max);
449	h_min = llmax(0.0f, h_min);
450	h_max = llmin(RESOLUTION - epsilon, h_max);
451
452	return !fully_outside;
453}
454
455
456void LLCubeMap::paintIn(LLVector3 dir[4], const LLColor4U& col)
457{
458	F32 v_min, v_max, h_min, h_max;
459	LLVector3 center = dir[0] + dir[1] + dir[2] + dir[3];
460	center.normVec();
461
462	for (U8 side = 0; side < 6; ++side)
463	{
464		if (!project(v_min, v_max, h_min, h_max, side, dir))
465			continue;
466
467		U8 *td = mRawImages[side]->getData();
468		
469		U16 v_minu = (U16) v_min;
470		U16 v_maxu = (U16) (ceil(v_max) + 0.5);
471		U16 h_minu = (U16) h_min;
472		U16 h_maxu = (U16) (ceil(h_max) + 0.5);
473
474		for (U16 v = v_minu; v < v_maxu; ++v)
475			for (U16 h = h_minu; h < h_maxu; ++h)
476		//for (U16 v = 0; v < RESOLUTION; ++v)
477		//	for (U16 h = 0; h < RESOLUTION; ++h)
478			{
479				const LLVector3 ray = map(side, v, h);
480				if (ray * center > 0.999)
481				{
482					const U32 offset = (RESOLUTION * v + h) * 4;
483					for (U8 cc = 0; cc < 3; ++cc)
484						td[offset + cc] = U8((td[offset + cc] + col.mV[cc]) * 0.5);
485				}
486			}
487		mImages[side]->setSubImage(mRawImages[side], 0, 0, 64, 64);
488	}
489}
490
491void LLCubeMap::destroyGL()
492{
493	for (S32 i = 0; i < 6; i++)
494	{
495		mImages[i] = NULL;
496	}
497}