/indra/newview/llpatchvertexarray.cpp
C++ | 257 lines | 144 code | 28 blank | 85 comment | 24 complexity | 7d07e2ac6fa843aff28d69b285739495 MD5 | raw file
Possible License(s): LGPL-2.1
1/** 2 * @file llpatchvertexarray.cpp 3 * @brief Implementation of the LLSurfaceVertexArray class. 4 * 5 * $LicenseInfo:firstyear=2001&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 27#include "llviewerprecompiledheaders.h" 28 29#include "llpatchvertexarray.h" 30#include "llsurfacepatch.h" 31 32// constructors 33 34LLPatchVertexArray::LLPatchVertexArray() : 35 mSurfaceWidth(0), 36 mPatchWidth(0), 37 mPatchOrder(0), 38 mRenderLevelp(NULL), 39 mRenderStridep(NULL) 40{ 41} 42 43LLPatchVertexArray::LLPatchVertexArray(U32 surface_width, U32 patch_width, F32 meters_per_grid) : 44 mRenderLevelp(NULL), 45 mRenderStridep(NULL) 46{ 47 create(surface_width, patch_width, meters_per_grid); 48} 49 50 51LLPatchVertexArray::~LLPatchVertexArray() 52{ 53 destroy(); 54} 55 56 57void LLPatchVertexArray::create(U32 surface_width, U32 patch_width, F32 meters_per_grid) 58{ 59 // PART 1 -- Make sure the arguments are good... 60 // Make sure patch_width is not greater than surface_width 61 if (patch_width > surface_width) 62 { 63 U32 temp = patch_width; 64 patch_width = surface_width; 65 surface_width = temp; 66 } 67 68 // Make sure (surface_width-1) is equal to a power_of_two. 69 // (The -1 is there because an LLSurface has a buffer of 1 on 70 // its East and North edges). 71 U32 power_of_two = 1; 72 U32 surface_order = 0; 73 while (power_of_two < (surface_width-1)) 74 { 75 power_of_two *= 2; 76 surface_order += 1; 77 } 78 79 if (power_of_two == (surface_width-1)) 80 { 81 mSurfaceWidth = surface_width; 82 83 // Make sure patch_width is a factor of (surface_width - 1) 84 U32 ratio = (surface_width - 1) / patch_width; 85 F32 fratio = ((float)(surface_width - 1)) / ((float)(patch_width)); 86 if ( fratio == (float)(ratio)) 87 { 88 // Make sure patch_width is a power of two 89 power_of_two = 1; 90 U32 patch_order = 0; 91 while (power_of_two < patch_width) 92 { 93 power_of_two *= 2; 94 patch_order += 1; 95 } 96 if (power_of_two == patch_width) 97 { 98 mPatchWidth = patch_width; 99 mPatchOrder = patch_order; 100 } 101 else // patch_width is not a power of two... 102 { 103 mPatchWidth = 0; 104 mPatchOrder = 0; 105 } 106 } 107 else // patch_width is not a factor of (surface_width - 1)... 108 { 109 mPatchWidth = 0; 110 mPatchOrder = 0; 111 } 112 } 113 else // surface_width is not a power of two... 114 { 115 mSurfaceWidth = 0; 116 mPatchWidth = 0; 117 mPatchOrder = 0; 118 } 119 120 // PART 2 -- Allocate memory for the render level table 121 if (mPatchWidth > 0) 122 { 123 mRenderLevelp = new U32 [2*mPatchWidth + 1]; 124 mRenderStridep = new U32 [mPatchOrder + 1]; 125 } 126 127 if (NULL == mRenderLevelp || NULL == mRenderStridep) 128 { 129 // init() and some other things all want to deref these 130 // pointers, so this is serious. 131 llerrs << "mRenderLevelp or mRenderStridep was NULL; we'd crash soon." << llendl; 132 return; 133 } 134 135 // Now that we've allocated memory, we can initialize 136 // the arrays... 137 init(); 138} 139 140 141void LLPatchVertexArray::destroy() 142{ 143 if (mPatchWidth == 0) 144 { 145 return; 146 } 147 148 delete [] mRenderLevelp; 149 delete [] mRenderStridep; 150 mSurfaceWidth = 0; 151 mPatchWidth = 0; 152 mPatchOrder = 0; 153} 154 155 156void LLPatchVertexArray::init() 157// Initializes the triangle strip arrays. 158{ 159 U32 j; 160 U32 level, stride; 161 U32 k; 162 163 // We need to build two look-up tables... 164 165 // render_level -> render_stride 166 // A 16x16 patch has 5 render levels : 2^0 to 2^4 167 // render_level render_stride 168 // 4 1 169 // 3 2 170 // 2 4 171 // 1 8 172 // 0 16 173 stride = mPatchWidth; 174 for (level=0; level<mPatchOrder + 1; level++) 175 { 176 mRenderStridep[level] = stride; 177 stride /= 2; 178 } 179 180 // render_level <- render_stride. 181/* 182 // For a 16x16 patch we'll clamp the render_strides to 0 through 16 183 // and enter the nearest render_level in the table. Of course, only 184 // power-of-two render strides are actually used. 185 // 186 // render_stride render_level 187 // 0 4 188 // 1 4 * 189 // 2 3 * 190 // 3 3 191 // 4 2 * 192 // 5 2 193 // 6 2 194 // 7 1 195 // 8 1 * 196 // 9 1 197 // 10 1 198 // 11 1 199 // 12 1 200 // 13 0 201 // 14 0 202 // 15 0 203 // 16 Always 0 204 205 level = mPatchOrder; 206 for (stride=0; stride<mPatchWidth; stride++) 207 { 208 if ((F32) stride > 2.1f * mRenderStridep[level]) 209 { 210 level--; 211 }; 212 mRenderLevelp[stride] = level; 213 } 214 */ 215 216 // This method is more agressive about putting triangles onscreen 217 level = mPatchOrder; 218 k = 2; 219 mRenderLevelp[0] = mPatchOrder; 220 mRenderLevelp[1] = mPatchOrder; 221 stride = 2; 222 while(stride < 2*mPatchWidth) 223 { 224 for (j=0; j<k && stride<2*mPatchWidth; j++) 225 { 226 mRenderLevelp[stride++] = level; 227 } 228 k *= 2; 229 level--; 230 } 231 mRenderLevelp[2*mPatchWidth] = 0; 232} 233 234 235std::ostream& operator<<(std::ostream &s, const LLPatchVertexArray &va) 236{ 237 U32 i; 238 s << "{ \n"; 239 s << " mSurfaceWidth = " << va.mSurfaceWidth << "\n"; 240 s << " mPatchWidth = " << va.mPatchWidth << "\n"; 241 s << " mPatchOrder = " << va.mPatchOrder << "\n"; 242 s << " mRenderStridep = \n"; 243 for (i=0; i<va.mPatchOrder+1; i++) 244 { 245 s << " " << i << " " << va.mRenderStridep[i] << "\n"; 246 } 247 s << " mRenderLevelp = \n"; 248 for (i=0; i < 2*va.mPatchWidth + 1; i++) 249 { 250 s << " " << i << " " << va.mRenderLevelp[i] << "\n"; 251 } 252 s << "}"; 253 return s; 254} 255 256 257// EOF