PageRenderTime 38ms CodeModel.GetById 14ms RepoModel.GetById 0ms 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
Possible License(s): LGPL-2.1
  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. #include "llworkerthread.h"
  28. #include "llcubemap.h"
  29. #include "v4coloru.h"
  30. #include "v3math.h"
  31. #include "v3dmath.h"
  32. #include "m3math.h"
  33. #include "m4math.h"
  34. #include "llrender.h"
  35. #include "llglslshader.h"
  36. #include "llglheaders.h"
  37. const F32 epsilon = 1e-7f;
  38. const U16 RESOLUTION = 64;
  39. #if LL_DARWIN
  40. // mipmap generation on cubemap textures seems to be broken on the Mac for at least some cards.
  41. // Since the cubemap is small (64x64 per face) and doesn't have any fine detail, turning off mipmaps is a usable workaround.
  42. const BOOL use_cube_mipmaps = FALSE;
  43. #else
  44. const BOOL use_cube_mipmaps = FALSE; //current build works best without cube mipmaps
  45. #endif
  46. bool LLCubeMap::sUseCubeMaps = true;
  47. LLCubeMap::LLCubeMap()
  48. : mTextureStage(0),
  49. mTextureCoordStage(0),
  50. mMatrixStage(0)
  51. {
  52. mTargets[0] = GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB;
  53. mTargets[1] = GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB;
  54. mTargets[2] = GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB;
  55. mTargets[3] = GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB;
  56. mTargets[4] = GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB;
  57. mTargets[5] = GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB;
  58. }
  59. LLCubeMap::~LLCubeMap()
  60. {
  61. }
  62. void LLCubeMap::initGL()
  63. {
  64. llassert(gGLManager.mInited);
  65. if (gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps)
  66. {
  67. // Not initialized, do stuff.
  68. if (mImages[0].isNull())
  69. {
  70. U32 texname = 0;
  71. LLImageGL::generateTextures(1, &texname);
  72. for (int i = 0; i < 6; i++)
  73. {
  74. mImages[i] = new LLImageGL(64, 64, 4, (use_cube_mipmaps? TRUE : FALSE));
  75. mImages[i]->setTarget(mTargets[i], LLTexUnit::TT_CUBE_MAP);
  76. mRawImages[i] = new LLImageRaw(64, 64, 4);
  77. mImages[i]->createGLTexture(0, mRawImages[i], texname);
  78. gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_CUBE_MAP, texname);
  79. mImages[i]->setAddressMode(LLTexUnit::TAM_CLAMP);
  80. stop_glerror();
  81. }
  82. gGL.getTexUnit(0)->disable();
  83. }
  84. disable();
  85. }
  86. else
  87. {
  88. llwarns << "Using cube map without extension!" << llendl;
  89. }
  90. }
  91. void LLCubeMap::initRawData(const std::vector<LLPointer<LLImageRaw> >& rawimages)
  92. {
  93. bool flip_x[6] = { false, true, false, false, true, false };
  94. bool flip_y[6] = { true, true, true, false, true, true };
  95. bool transpose[6] = { false, false, false, false, true, true };
  96. // Yes, I know that this is inefficient! - djs 08/08/02
  97. for (int i = 0; i < 6; i++)
  98. {
  99. const U8 *sd = rawimages[i]->getData();
  100. U8 *td = mRawImages[i]->getData();
  101. S32 offset = 0;
  102. S32 sx, sy, so;
  103. for (int y = 0; y < 64; y++)
  104. {
  105. for (int x = 0; x < 64; x++)
  106. {
  107. sx = x;
  108. sy = y;
  109. if (flip_y[i])
  110. {
  111. sy = 63 - y;
  112. }
  113. if (flip_x[i])
  114. {
  115. sx = 63 - x;
  116. }
  117. if (transpose[i])
  118. {
  119. S32 temp = sx;
  120. sx = sy;
  121. sy = temp;
  122. }
  123. so = 64*sy + sx;
  124. so *= 4;
  125. *(td + offset++) = *(sd + so++);
  126. *(td + offset++) = *(sd + so++);
  127. *(td + offset++) = *(sd + so++);
  128. *(td + offset++) = *(sd + so++);
  129. }
  130. }
  131. }
  132. }
  133. void LLCubeMap::initGLData()
  134. {
  135. for (int i = 0; i < 6; i++)
  136. {
  137. mImages[i]->setSubImage(mRawImages[i], 0, 0, 64, 64);
  138. }
  139. }
  140. void LLCubeMap::init(const std::vector<LLPointer<LLImageRaw> >& rawimages)
  141. {
  142. if (!gGLManager.mIsDisabled)
  143. {
  144. initGL();
  145. initRawData(rawimages);
  146. initGLData();
  147. }
  148. }
  149. GLuint LLCubeMap::getGLName()
  150. {
  151. return mImages[0]->getTexName();
  152. }
  153. void LLCubeMap::bind()
  154. {
  155. gGL.getTexUnit(mTextureStage)->bind(this);
  156. }
  157. void LLCubeMap::enable(S32 stage)
  158. {
  159. enableTexture(stage);
  160. enableTextureCoords(stage);
  161. }
  162. void LLCubeMap::enableTexture(S32 stage)
  163. {
  164. mTextureStage = stage;
  165. if (gGLManager.mHasCubeMap && stage >= 0 && LLCubeMap::sUseCubeMaps)
  166. {
  167. gGL.getTexUnit(stage)->enable(LLTexUnit::TT_CUBE_MAP);
  168. }
  169. }
  170. void LLCubeMap::enableTextureCoords(S32 stage)
  171. {
  172. mTextureCoordStage = stage;
  173. if (!LLGLSLShader::sNoFixedFunction && gGLManager.mHasCubeMap && stage >= 0 && LLCubeMap::sUseCubeMaps)
  174. {
  175. if (stage > 0)
  176. {
  177. gGL.getTexUnit(stage)->activate();
  178. }
  179. glEnable(GL_TEXTURE_GEN_R);
  180. glEnable(GL_TEXTURE_GEN_S);
  181. glEnable(GL_TEXTURE_GEN_T);
  182. glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
  183. glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
  184. glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
  185. if (stage > 0)
  186. {
  187. gGL.getTexUnit(0)->activate();
  188. }
  189. }
  190. }
  191. void LLCubeMap::disable(void)
  192. {
  193. disableTexture();
  194. disableTextureCoords();
  195. }
  196. void LLCubeMap::disableTexture(void)
  197. {
  198. if (gGLManager.mHasCubeMap && mTextureStage >= 0 && LLCubeMap::sUseCubeMaps)
  199. {
  200. gGL.getTexUnit(mTextureStage)->disable();
  201. if (mTextureStage == 0)
  202. {
  203. gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
  204. }
  205. }
  206. }
  207. void LLCubeMap::disableTextureCoords(void)
  208. {
  209. if (!LLGLSLShader::sNoFixedFunction && gGLManager.mHasCubeMap && mTextureCoordStage >= 0 && LLCubeMap::sUseCubeMaps)
  210. {
  211. if (mTextureCoordStage > 0)
  212. {
  213. gGL.getTexUnit(mTextureCoordStage)->activate();
  214. }
  215. glDisable(GL_TEXTURE_GEN_S);
  216. glDisable(GL_TEXTURE_GEN_T);
  217. glDisable(GL_TEXTURE_GEN_R);
  218. if (mTextureCoordStage > 0)
  219. {
  220. gGL.getTexUnit(0)->activate();
  221. }
  222. }
  223. }
  224. void LLCubeMap::setMatrix(S32 stage)
  225. {
  226. mMatrixStage = stage;
  227. if (mMatrixStage < 0) return;
  228. //if (stage > 0)
  229. {
  230. gGL.getTexUnit(stage)->activate();
  231. }
  232. LLVector3 x(gGLModelView+0);
  233. LLVector3 y(gGLModelView+4);
  234. LLVector3 z(gGLModelView+8);
  235. LLMatrix3 mat3;
  236. mat3.setRows(x,y,z);
  237. LLMatrix4 trans(mat3);
  238. trans.transpose();
  239. gGL.matrixMode(LLRender::MM_TEXTURE);
  240. gGL.pushMatrix();
  241. gGL.loadMatrix((F32 *)trans.mMatrix);
  242. gGL.matrixMode(LLRender::MM_MODELVIEW);
  243. /*if (stage > 0)
  244. {
  245. gGL.getTexUnit(0)->activate();
  246. }*/
  247. }
  248. void LLCubeMap::restoreMatrix()
  249. {
  250. if (mMatrixStage < 0) return;
  251. //if (mMatrixStage > 0)
  252. {
  253. gGL.getTexUnit(mMatrixStage)->activate();
  254. }
  255. gGL.matrixMode(LLRender::MM_TEXTURE);
  256. gGL.popMatrix();
  257. gGL.matrixMode(LLRender::MM_MODELVIEW);
  258. /*if (mMatrixStage > 0)
  259. {
  260. gGL.getTexUnit(0)->activate();
  261. }*/
  262. }
  263. void LLCubeMap::setReflection (void)
  264. {
  265. gGL.getTexUnit(mTextureStage)->bindManual(LLTexUnit::TT_CUBE_MAP, getGLName());
  266. mImages[0]->setFilteringOption(LLTexUnit::TFO_ANISOTROPIC);
  267. mImages[0]->setAddressMode(LLTexUnit::TAM_CLAMP);
  268. }
  269. LLVector3 LLCubeMap::map(U8 side, U16 v_val, U16 h_val) const
  270. {
  271. LLVector3 dir;
  272. const U8 curr_coef = side >> 1; // 0/1 = X axis, 2/3 = Y, 4/5 = Z
  273. const S8 side_dir = (((side & 1) << 1) - 1); // even = -1, odd = 1
  274. const U8 i_coef = (curr_coef + 1) % 3;
  275. const U8 j_coef = (i_coef + 1) % 3;
  276. dir.mV[curr_coef] = side_dir;
  277. switch (side)
  278. {
  279. case 0: // negative X
  280. dir.mV[i_coef] = -F32((v_val<<1) + 1) / RESOLUTION + 1;
  281. dir.mV[j_coef] = F32((h_val<<1) + 1) / RESOLUTION - 1;
  282. break;
  283. case 1: // positive X
  284. dir.mV[i_coef] = -F32((v_val<<1) + 1) / RESOLUTION + 1;
  285. dir.mV[j_coef] = -F32((h_val<<1) + 1) / RESOLUTION + 1;
  286. break;
  287. case 2: // negative Y
  288. dir.mV[i_coef] = -F32((v_val<<1) + 1) / RESOLUTION + 1;
  289. dir.mV[j_coef] = F32((h_val<<1) + 1) / RESOLUTION - 1;
  290. break;
  291. case 3: // positive Y
  292. dir.mV[i_coef] = F32((v_val<<1) + 1) / RESOLUTION - 1;
  293. dir.mV[j_coef] = F32((h_val<<1) + 1) / RESOLUTION - 1;
  294. break;
  295. case 4: // negative Z
  296. dir.mV[i_coef] = -F32((h_val<<1) + 1) / RESOLUTION + 1;
  297. dir.mV[j_coef] = -F32((v_val<<1) + 1) / RESOLUTION + 1;
  298. break;
  299. case 5: // positive Z
  300. dir.mV[i_coef] = -F32((h_val<<1) + 1) / RESOLUTION + 1;
  301. dir.mV[j_coef] = F32((v_val<<1) + 1) / RESOLUTION - 1;
  302. break;
  303. default:
  304. dir.mV[i_coef] = F32((v_val<<1) + 1) / RESOLUTION - 1;
  305. dir.mV[j_coef] = F32((h_val<<1) + 1) / RESOLUTION - 1;
  306. }
  307. dir.normVec();
  308. return dir;
  309. }
  310. BOOL LLCubeMap::project(F32& v_val, F32& h_val, BOOL& outside,
  311. U8 side, const LLVector3& dir) const
  312. {
  313. const U8 curr_coef = side >> 1; // 0/1 = X axis, 2/3 = Y, 4/5 = Z
  314. const S8 side_dir = (((side & 1) << 1) - 1); // even = -1, odd = 1
  315. const U8 i_coef = (curr_coef + 1) % 3;
  316. const U8 j_coef = (i_coef + 1) % 3;
  317. outside = TRUE;
  318. if (side_dir * dir.mV[curr_coef] < 0)
  319. return FALSE;
  320. LLVector3 ray;
  321. F32 norm_val = fabs(dir.mV[curr_coef]);
  322. if (norm_val < epsilon)
  323. norm_val = 1e-5f;
  324. ray.mV[curr_coef] = side_dir;
  325. ray.mV[i_coef] = dir.mV[i_coef] / norm_val;
  326. ray.mV[j_coef] = dir.mV[j_coef] / norm_val;
  327. const F32 i_val = (ray.mV[i_coef] + 1) * 0.5f * RESOLUTION;
  328. const F32 j_val = (ray.mV[j_coef] + 1) * 0.5f * RESOLUTION;
  329. switch (side)
  330. {
  331. case 0: // negative X
  332. v_val = RESOLUTION - i_val;
  333. h_val = j_val;
  334. break;
  335. case 1: // positive X
  336. v_val = RESOLUTION - i_val;
  337. h_val = RESOLUTION - j_val;
  338. break;
  339. case 2: // negative Y
  340. v_val = RESOLUTION - i_val;
  341. h_val = j_val;
  342. break;
  343. case 3: // positive Y
  344. v_val = i_val;
  345. h_val = j_val;
  346. break;
  347. case 4: // negative Z
  348. v_val = RESOLUTION - j_val;
  349. h_val = RESOLUTION - i_val;
  350. break;
  351. case 5: // positive Z
  352. v_val = RESOLUTION - j_val;
  353. h_val = i_val;
  354. break;
  355. default:
  356. v_val = i_val;
  357. h_val = j_val;
  358. }
  359. outside = ((v_val < 0) || (v_val > RESOLUTION) ||
  360. (h_val < 0) || (h_val > RESOLUTION));
  361. return TRUE;
  362. }
  363. BOOL LLCubeMap::project(F32& v_min, F32& v_max, F32& h_min, F32& h_max,
  364. U8 side, LLVector3 dir[4]) const
  365. {
  366. v_min = h_min = RESOLUTION;
  367. v_max = h_max = 0;
  368. BOOL fully_outside = TRUE;
  369. for (U8 vtx = 0; vtx < 4; ++vtx)
  370. {
  371. F32 v_val, h_val;
  372. BOOL outside;
  373. BOOL consider = project(v_val, h_val, outside, side, dir[vtx]);
  374. if (!outside)
  375. fully_outside = FALSE;
  376. if (consider)
  377. {
  378. if (v_val < v_min) v_min = v_val;
  379. if (v_val > v_max) v_max = v_val;
  380. if (h_val < h_min) h_min = h_val;
  381. if (h_val > h_max) h_max = h_val;
  382. }
  383. }
  384. v_min = llmax(0.0f, v_min);
  385. v_max = llmin(RESOLUTION - epsilon, v_max);
  386. h_min = llmax(0.0f, h_min);
  387. h_max = llmin(RESOLUTION - epsilon, h_max);
  388. return !fully_outside;
  389. }
  390. void LLCubeMap::paintIn(LLVector3 dir[4], const LLColor4U& col)
  391. {
  392. F32 v_min, v_max, h_min, h_max;
  393. LLVector3 center = dir[0] + dir[1] + dir[2] + dir[3];
  394. center.normVec();
  395. for (U8 side = 0; side < 6; ++side)
  396. {
  397. if (!project(v_min, v_max, h_min, h_max, side, dir))
  398. continue;
  399. U8 *td = mRawImages[side]->getData();
  400. U16 v_minu = (U16) v_min;
  401. U16 v_maxu = (U16) (ceil(v_max) + 0.5);
  402. U16 h_minu = (U16) h_min;
  403. U16 h_maxu = (U16) (ceil(h_max) + 0.5);
  404. for (U16 v = v_minu; v < v_maxu; ++v)
  405. for (U16 h = h_minu; h < h_maxu; ++h)
  406. //for (U16 v = 0; v < RESOLUTION; ++v)
  407. // for (U16 h = 0; h < RESOLUTION; ++h)
  408. {
  409. const LLVector3 ray = map(side, v, h);
  410. if (ray * center > 0.999)
  411. {
  412. const U32 offset = (RESOLUTION * v + h) * 4;
  413. for (U8 cc = 0; cc < 3; ++cc)
  414. td[offset + cc] = U8((td[offset + cc] + col.mV[cc]) * 0.5);
  415. }
  416. }
  417. mImages[side]->setSubImage(mRawImages[side], 0, 0, 64, 64);
  418. }
  419. }
  420. void LLCubeMap::destroyGL()
  421. {
  422. for (S32 i = 0; i < 6; i++)
  423. {
  424. mImages[i] = NULL;
  425. }
  426. }