void LLVOWLSky::buildStripsBuffer(U32 begin_stack, U32 end_stack, LLStrider<LLVector3> & vertices, LLStrider<LLVector2> & texCoords, LLStrider<U16> & indices) { const F32 RADIUS = LLWLParamManager::getInstance()->getDomeRadius(); U32 i, j, num_slices, num_stacks; F32 phi0, theta, x0, y0, z0; // paranoia checking for SL-55986/SL-55833 U32 count_verts = 0; U32 count_indices = 0; num_slices = getNumSlices(); num_stacks = getNumStacks(); llassert(end_stack <= num_stacks); // stacks are iterated one-indexed since phi(0) was handled by the fan above for(i = begin_stack + 1; i <= end_stack+1; ++i) { phi0 = calcPhi(i); for(j = 0; j < num_slices; ++j) { theta = F_TWO_PI * (float(j) / float(num_slices)); // standard transformation from spherical to // rectangular coordinates x0 = sin(phi0) * cos(theta); y0 = cos(phi0); z0 = sin(phi0) * sin(theta); if (i == num_stacks-2) { *vertices++ = LLVector3(x0*RADIUS, y0*RADIUS-1024.f*2.f, z0*RADIUS); } else if (i == num_stacks-1) { *vertices++ = LLVector3(0, y0*RADIUS-1024.f*2.f, 0); } else { *vertices++ = LLVector3(x0 * RADIUS, y0 * RADIUS, z0 * RADIUS); } ++count_verts; // generate planar uv coordinates // note: x and z are transposed in order for things to animate // correctly in the global coordinate system where +x is east and // +y is north *texCoords++ = LLVector2((-z0 + 1.f) / 2.f, (-x0 + 1.f) / 2.f); } } //build triangle strip... *indices++ = 0 ; count_indices++ ; S32 k = 0 ; for(i = 1; i <= end_stack - begin_stack; ++i) { *indices++ = i * num_slices + k ; count_indices++ ; k = (k+1) % num_slices ; for(j = 0; j < num_slices ; ++j) { *indices++ = (i-1) * num_slices + k ; *indices++ = i * num_slices + k ; count_indices += 2 ; k = (k+1) % num_slices ; } if((--k) < 0) { k = num_slices - 1 ; } *indices++ = i * num_slices + k ; count_indices++ ; } }
inline U32 LLVOWLSky::getStripsNumVerts(void) { return (getNumStacks() - 1) * getNumSlices(); }
inline U32 LLVOWLSky::getFanNumIndices(void) { return getNumSlices() * 3; }
inline U32 LLVOWLSky::getFanNumVerts(void) { return getNumSlices() + 1; }
BOOL LLVOWLSky::updateGeometry(LLDrawable * drawable) { LLFastTimer ftm(FTM_GEO_SKY); LLStrider<LLVector3> vertices; LLStrider<LLVector2> texCoords; LLStrider<U16> indices; #if DOME_SLICES { mFanVerts = new LLVertexBuffer(LLDrawPoolWLSky::SKY_VERTEX_DATA_MASK, GL_STATIC_DRAW_ARB); mFanVerts->allocateBuffer(getFanNumVerts(), getFanNumIndices(), TRUE); BOOL success = mFanVerts->getVertexStrider(vertices) && mFanVerts->getTexCoord0Strider(texCoords) && mFanVerts->getIndexStrider(indices); if(!success) { llerrs << "Failed updating WindLight sky geometry." << llendl; } buildFanBuffer(vertices, texCoords, indices); mFanVerts->flush(); } { const U32 max_buffer_bytes = gSavedSettings.getS32("RenderMaxVBOSize")*1024; const U32 data_mask = LLDrawPoolWLSky::SKY_VERTEX_DATA_MASK; const U32 max_verts = max_buffer_bytes / LLVertexBuffer::calcVertexSize(data_mask); const U32 total_stacks = getNumStacks(); const U32 verts_per_stack = getNumSlices(); // each seg has to have one more row of verts than it has stacks // then round down const U32 stacks_per_seg = (max_verts - verts_per_stack) / verts_per_stack; // round up to a whole number of segments const U32 strips_segments = (total_stacks+stacks_per_seg-1) / stacks_per_seg; llinfos << "WL Skydome strips in " << strips_segments << " batches." << llendl; mStripsVerts.resize(strips_segments, NULL); LLTimer timer; timer.start(); for (U32 i = 0; i < strips_segments ;++i) { LLVertexBuffer * segment = new LLVertexBuffer(LLDrawPoolWLSky::SKY_VERTEX_DATA_MASK, GL_STATIC_DRAW_ARB); mStripsVerts[i] = segment; U32 num_stacks_this_seg = stacks_per_seg; if ((i == strips_segments - 1) && (total_stacks % stacks_per_seg) != 0) { // for the last buffer only allocate what we'll use num_stacks_this_seg = total_stacks % stacks_per_seg; } // figure out what range of the sky we're filling const U32 begin_stack = i * stacks_per_seg; const U32 end_stack = begin_stack + num_stacks_this_seg; llassert(end_stack <= total_stacks); const U32 num_verts_this_seg = verts_per_stack * (num_stacks_this_seg+1); llassert(num_verts_this_seg <= max_verts); const U32 num_indices_this_seg = 1+num_stacks_this_seg*(2+2*verts_per_stack); llassert(num_indices_this_seg * sizeof(U16) <= max_buffer_bytes); segment->allocateBuffer(num_verts_this_seg, num_indices_this_seg, TRUE); // lock the buffer BOOL success = segment->getVertexStrider(vertices) && segment->getTexCoord0Strider(texCoords) && segment->getIndexStrider(indices); if(!success) { llerrs << "Failed updating WindLight sky geometry." << llendl; } // fill it buildStripsBuffer(begin_stack, end_stack, vertices, texCoords, indices); // and unlock the buffer segment->flush(); } llinfos << "completed in " << llformat("%.2f", timer.getElapsedTimeF32()) << "seconds" << llendl; } #else mStripsVerts = new LLVertexBuffer(LLDrawPoolWLSky::SKY_VERTEX_DATA_MASK, GL_STATIC_DRAW_ARB); const F32 RADIUS = LLWLParamManager::sParamMgr->getDomeRadius(); LLPointer<LLVertexBuffer> temp = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX, 0); temp->allocateBuffer(12, 60, TRUE); BOOL success = temp->getVertexStrider(vertices) && temp->getIndexStrider(indices); if (success) { for (U32 i = 0; i < 12; i++) { *vertices++ = icosahedron_vert[i]; } for (U32 i = 0; i < 60; i++) { *indices++ = icosahedron_ind[i]; } } LLPointer<LLVertexBuffer> temp2; for (U32 i = 0; i < 8; i++) { temp2 = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX, 0); subdivide(*temp, temp2); temp = temp2; } temp->getVertexStrider(vertices); for (S32 i = 0; i < temp->getNumVerts(); i++) { LLVector3 v = vertices[i]; v.normVec(); vertices[i] = v*RADIUS; } temp2 = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX, 0); chop(*temp, temp2); mStripsVerts->allocateBuffer(temp2->getNumVerts(), temp2->getNumIndices(), TRUE); success = mStripsVerts->getVertexStrider(vertices) && mStripsVerts->getTexCoordStrider(texCoords) && mStripsVerts->getIndexStrider(indices); LLStrider<LLVector3> v; temp2->getVertexStrider(v); LLStrider<U16> ind; temp2->getIndexStrider(ind); if (success) { for (S32 i = 0; i < temp2->getNumVerts(); ++i) { LLVector3 vert = *v++; vert.normVec(); F32 z0 = vert.mV[2]; F32 x0 = vert.mV[0]; vert *= RADIUS; *vertices++ = vert; *texCoords++ = LLVector2((-z0 + 1.f) / 2.f, (-x0 + 1.f) / 2.f); } for (S32 i = 0; i < temp2->getNumIndices(); ++i) { *indices++ = *ind++; } } mStripsVerts->flush(); #endif updateStarColors(); updateStarGeometry(drawable); LLPipeline::sCompiles++; return TRUE; }
inline U32 LLVOWLSky::getStripsNumIndices(void) { return 2 * ((getNumStacks() - 2) * (getNumSlices() + 1)) + 1 ; }