llpatchvertexarray.cpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. /**
  2. * @file llpatchvertexarray.cpp
  3. * @brief Implementation of the LLPatchVertexArray class.
  4. *
  5. * $LicenseInfo:firstyear=2001&license=viewergpl$
  6. *
  7. * Copyright (c) 2001-2009, 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
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #include "llviewerprecompiledheaders.h"
  33. #include "llpatchvertexarray.h"
  34. #include "llsurfacepatch.h"
  35. LLPatchVertexArray::LLPatchVertexArray()
  36. : mSurfaceWidth(0),
  37. mPatchWidth(0),
  38. mPatchOrder(0),
  39. mRenderLevelp(NULL),
  40. mRenderStridep(NULL)
  41. {
  42. }
  43. LLPatchVertexArray::LLPatchVertexArray(U32 surface_width, U32 patch_width,
  44. F32 meters_per_grid)
  45. : mRenderLevelp(NULL),
  46. mRenderStridep(NULL)
  47. {
  48. create(surface_width, patch_width, meters_per_grid);
  49. }
  50. LLPatchVertexArray::~LLPatchVertexArray()
  51. {
  52. destroy();
  53. }
  54. void LLPatchVertexArray::create(U32 surface_width, U32 patch_width,
  55. F32 meters_per_grid)
  56. {
  57. // PART 1 -- Make sure the arguments are good...
  58. // Make sure patch_width is not greater than surface_width
  59. if (patch_width > surface_width)
  60. {
  61. U32 temp = patch_width;
  62. patch_width = surface_width;
  63. surface_width = temp;
  64. }
  65. // Make sure (surface_width - 1) is equal to a power_of_two (the -1 is
  66. // there because an LLSurface has a buffer of 1 on its East and North
  67. // edges).
  68. U32 power_of_two = 1;
  69. while (power_of_two < surface_width - 1)
  70. {
  71. power_of_two *= 2;
  72. }
  73. // Variable region size support
  74. if (power_of_two != surface_width - 1)
  75. {
  76. surface_width = power_of_two + 1;
  77. }
  78. mSurfaceWidth = surface_width;
  79. // Make sure that patch_width is a factor of (surface_width - 1)
  80. U32 ratio = (surface_width - 1) / patch_width;
  81. F32 fratio = (F32)(surface_width - 1) / (F32)patch_width;
  82. if (fratio != (F32)ratio)
  83. {
  84. llerrs << "patch_width is not a factor of surface_width-1. Can't proceed further !"
  85. << llendl;
  86. }
  87. // Make sure patch_width is a power of two
  88. power_of_two = 1;
  89. U32 patch_order = 0;
  90. while (power_of_two < patch_width)
  91. {
  92. power_of_two *= 2;
  93. patch_order += 1;
  94. }
  95. // Variable region size support
  96. if (power_of_two != patch_width)
  97. {
  98. patch_width = power_of_two;
  99. }
  100. mPatchWidth = patch_width;
  101. mPatchOrder = patch_order;
  102. // PART 2 -- Allocate memory for the render level table
  103. if (mPatchWidth)
  104. {
  105. mRenderLevelp = new (std::nothrow) U32[2 * mPatchWidth + 1];
  106. mRenderStridep = new (std::nothrow) U32[mPatchOrder + 1];
  107. if (!mRenderLevelp || !mRenderStridep)
  108. {
  109. // init() and some other things all want to deref these
  110. // pointers, so this is serious.
  111. llerrs << "Memory allocation failure, can't proceed further !"
  112. << llendl;
  113. }
  114. }
  115. else
  116. {
  117. llerrs << "Resulting patch width is zero ! Input parameters: surface_width = "
  118. << surface_width << " - patch_width = " << patch_width
  119. << " - meters_per_grid = " << meters_per_grid
  120. << ". Can't proceed further !" << llendl;
  121. }
  122. // Now that we have allocated memory, we can initialize the arrays...
  123. init();
  124. }
  125. void LLPatchVertexArray::destroy()
  126. {
  127. if (mPatchWidth)
  128. {
  129. delete[] mRenderLevelp;
  130. delete[] mRenderStridep;
  131. mSurfaceWidth = mPatchWidth = mPatchOrder = 0;
  132. }
  133. }
  134. // Initializes the triangle strip arrays.
  135. void LLPatchVertexArray::init()
  136. {
  137. // We need to build two look-up tables...
  138. // render_level -> render_stride
  139. // A 16x16 patch has 5 render levels : 2^0 to 2^4
  140. // render_level render_stride
  141. // 4 1
  142. // 3 2
  143. // 2 4
  144. // 1 8
  145. // 0 16
  146. U32 level;
  147. U32 stride = mPatchWidth;
  148. for (level = 0; level < mPatchOrder + 1; ++level)
  149. {
  150. mRenderStridep[level] = stride;
  151. stride /= 2;
  152. }
  153. // render_level <- render_stride.
  154. #if 0
  155. // For a 16x16 patch we'll clamp the render_strides to 0 through 16
  156. // and enter the nearest render_level in the table. Of course, only
  157. // power-of-two render strides are actually used.
  158. //
  159. // render_stride render_level
  160. // 0 4
  161. // 1 4 *
  162. // 2 3 *
  163. // 3 3
  164. // 4 2 *
  165. // 5 2
  166. // 6 2
  167. // 7 1
  168. // 8 1 *
  169. // 9 1
  170. // 10 1
  171. // 11 1
  172. // 12 1
  173. // 13 0
  174. // 14 0
  175. // 15 0
  176. // 16 Always 0
  177. level = mPatchOrder;
  178. for (stride = 0; stride < mPatchWidth; ++stride)
  179. {
  180. if ((F32)stride > 2.1f * mRenderStridep[level])
  181. {
  182. --level;
  183. }
  184. mRenderLevelp[stride] = level;
  185. }
  186. #endif
  187. // This method is more agressive about putting triangles onscreen
  188. level = mPatchOrder;
  189. U32 k = 2;
  190. mRenderLevelp[0] = mPatchOrder;
  191. mRenderLevelp[1] = mPatchOrder;
  192. stride = 2;
  193. while (stride < 2 * mPatchWidth)
  194. {
  195. for (U32 j = 0; j < k && stride < 2 * mPatchWidth; ++j)
  196. {
  197. mRenderLevelp[stride++] = level;
  198. }
  199. k *= 2;
  200. --level;
  201. }
  202. mRenderLevelp[2 * mPatchWidth] = 0;
  203. }
  204. std::ostream& operator<<(std::ostream& s, const LLPatchVertexArray& va)
  205. {
  206. s << "{ \n";
  207. s << " mSurfaceWidth = " << va.mSurfaceWidth << "\n";
  208. s << " mPatchWidth = " << va.mPatchWidth << "\n";
  209. s << " mPatchOrder = " << va.mPatchOrder << "\n";
  210. s << " mRenderStridep = \n";
  211. for (U32 i = 0; i < va.mPatchOrder + 1; ++i)
  212. {
  213. s << " " << i << " " << va.mRenderStridep[i] << "\n";
  214. }
  215. s << " mRenderLevelp = \n";
  216. for (U32 i = 0; i < 2 * va.mPatchWidth + 1; ++i)
  217. {
  218. s << " " << i << " " << va.mRenderLevelp[i] << "\n";
  219. }
  220. s << "}";
  221. return s;
  222. }