void LLVOTextBubble::getGeometry(S32 idx, LLStrider<LLVector3>& verticesp, LLStrider<LLVector3>& normalsp, LLStrider<LLVector2>& texcoordsp, LLStrider<LLColor4U>& colorsp, LLStrider<U16>& indicesp) { if (idx == 0 || idx == 2) { return; } const LLVolumeFace& face = getVolume()->getVolumeFace(idx); LLVector3 pos = getPositionAgent(); LLColor4U color = LLColor4U(getTE(idx)->getColor()); U32 offset = mDrawable->getFace(idx)->getGeomIndex(); for (U32 i = 0; i < face.mVertices.size(); i++) { *verticesp++ = face.mVertices[i].mPosition.scaledVec(getScale()) + pos; *normalsp++ = face.mVertices[i].mNormal; *texcoordsp++ = face.mVertices[i].mTexCoord; *colorsp++ = color; } for (U32 i = 0; i < face.mIndices.size(); i++) { *indicesp++ = face.mIndices[i] + offset; } }
void LLVOTree::setPixelAreaAndAngle(LLAgent &agent) { // First calculate values as for any other object (for mAppAngle) LLViewerObject::setPixelAreaAndAngle(agent); // Re-calculate mPixelArea accurately // This should be the camera's center, as soon as we move to all region-local. LLVector3 relative_position = getPositionAgent() - agent.getCameraPositionAgent(); F32 range = relative_position.length(); // ugh, square root F32 max_scale = mBillboardScale * getMaxScale(); F32 area = max_scale * (max_scale*mBillboardRatio); // Compute pixels per meter at the given range F32 pixels_per_meter = LLViewerCamera::getInstance()->getViewHeightInPixels() / (tan(LLViewerCamera::getInstance()->getView()) * range); mPixelArea = (pixels_per_meter) * (pixels_per_meter) * area; #if 0 // mAppAngle is a bit of voodoo; // use the one calculated LLViewerObject::setPixelAreaAndAngle above // to avoid LOD miscalculations mAppAngle = (F32) atan2( max_scale, range) * RAD_TO_DEG; #endif }
void LLVOPartGroup::updateSpatialExtents(LLVector3& newMin, LLVector3& newMax) { const LLVector3& pos_agent = getPositionAgent(); newMin = pos_agent - mScale; newMax = pos_agent + mScale; mDrawable->setPositionGroup(pos_agent); }
void LLVOTextBubble::updateTextures(LLAgent &agent) { // Update the image levels of all textures... // First we do some quick checks. U32 i; // This doesn't take into account whether the object is in front // or behind... LLVector3 position_local = getPositionAgent() - agent.getCameraPositionAgent(); F32 dot_product = position_local * agent.getFrameAgent().getAtAxis(); F32 cos_angle = dot_product / position_local.magVec(); if (cos_angle > 1.f) { cos_angle = 1.f; } for (i = 0; i < getNumTEs(); i++) { const LLTextureEntry *te = getTE(i); F32 texel_area_ratio = fabs(te->mScaleS * te->mScaleT); LLViewerImage *imagep = getTEImage(i); if (imagep) { imagep->addTextureStats(mPixelArea, texel_area_ratio, cos_angle); } } }
BOOL LLVOClouds::updateGeometry(LLDrawable *drawable) { LLFastTimer ftm(LLFastTimer::FTM_UPDATE_CLOUDS); if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_CLOUDS))) { return TRUE; } dirtySpatialGroup(); LLFace *facep; S32 num_faces = mCloudGroupp->getNumPuffs(); if (num_faces > drawable->getNumFaces()) { drawable->setNumFacesFast(num_faces, NULL, getTEImage(0)); } mDepth = (getPositionAgent()-LLViewerCamera::getInstance()->getOrigin())*LLViewerCamera::getInstance()->getAtAxis(); S32 face_indx = 0; for ( ; face_indx < num_faces; face_indx++) { facep = drawable->getFace(face_indx); if (!facep) { llwarns << "No facep for index " << face_indx << llendl; continue; } facep->setSize(4, 6); facep->setTEOffset(face_indx); facep->setTexture(getTEImage(0)); const LLCloudPuff &puff = mCloudGroupp->getPuff(face_indx); const LLVector3 puff_pos_agent = gAgent.getPosAgentFromGlobal(puff.getPositionGlobal()); facep->mCenterLocal = puff_pos_agent; /// Update cloud color based on sun color. LLColor4 float_color(LLColor3(gSky.getSunDiffuseColor() + gSky.getSunAmbientColor()),puff.getAlpha()); facep->setFaceColor(float_color); } for ( ; face_indx < drawable->getNumFaces(); face_indx++) { facep = drawable->getFace(face_indx); if (!facep) { llwarns << "No facep for index " << face_indx << llendl; continue; } facep->setTEOffset(face_indx); facep->setSize(0,0); } drawable->movePartition(); return TRUE; }
void LLDrawable::updateDistance(LLCamera& camera, bool force_update) { if (LLViewerCamera::sCurCameraID != LLViewerCamera::CAMERA_WORLD) { llwarns << "Attempted to update distance for non-world camera." << llendl; return; } //switch LOD with the spatial group to avoid artifacts //LLSpatialGroup* sg = getSpatialGroup(); LLVector3 pos; //if (!sg || sg->changeLOD()) { LLVOVolume* volume = getVOVolume(); if (volume) { if (getSpatialGroup()) { pos.set(getPositionGroup().getF32ptr()); } else { pos = getPositionAgent(); } if (isState(LLDrawable::HAS_ALPHA)) { for (S32 i = 0; i < getNumFaces(); i++) { LLFace* facep = getFace(i); if (force_update || facep->getPoolType() == LLDrawPool::POOL_ALPHA) { LLVector4a box; box.setSub(facep->mExtents[1], facep->mExtents[0]); box.mul(0.25f); LLVector3 v = (facep->mCenterLocal-camera.getOrigin()); const LLVector3& at = camera.getAtAxis(); for (U32 j = 0; j < 3; j++) { v.mV[j] -= box[j] * at.mV[j]; } facep->mDistance = v * camera.getAtAxis(); } } } } else { pos = LLVector3(getPositionGroup().getF32ptr()); } pos -= camera.getOrigin(); mDistanceWRTCamera = llround(pos.magVec(), 0.01f); mVObjp->updateLOD(); } }
BOOL LLVOClouds::updateGeometry(LLDrawable *drawable) { LLFastTimer ftm(LLFastTimer::FTM_UPDATE_CLOUDS); if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_CLOUDS))) return TRUE; LLFace *facep; S32 num_faces = mCloudGroupp->getNumPuffs(); if (num_faces > drawable->getNumFaces()) { drawable->setNumFacesFast(num_faces, NULL, getTEImage(0)); } mDepth = (getPositionAgent()-gCamera->getOrigin())*gCamera->getAtAxis(); S32 face_indx = 0; for ( ; face_indx < num_faces; face_indx++) { facep = drawable->getFace(face_indx); if (!facep) { llwarns << "No facep for index " << face_indx << llendl; continue; } if (isParticle()) { facep->setSize(1,1); } else { facep->setSize(4, 6); } facep->setTEOffset(face_indx); facep->setTexture(getTEImage(0)); const LLCloudPuff &puff = mCloudGroupp->getPuff(face_indx); const LLVector3 puff_pos_agent = gAgent.getPosAgentFromGlobal(puff.getPositionGlobal()); facep->mCenterLocal = puff_pos_agent; } for ( ; face_indx < drawable->getNumFaces(); face_indx++) { facep = drawable->getFace(face_indx); if (!facep) { llwarns << "No facep for index " << face_indx << llendl; continue; } facep->setTEOffset(face_indx); facep->setSize(0,0); } drawable->movePartition(); return TRUE; }
void LLVOPartGroup::updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) { const LLVector3& pos_agent = getPositionAgent(); newMin.load3( (pos_agent - mScale).mV); newMax.load3( (pos_agent + mScale).mV); LLVector4a pos; pos.load3(pos_agent.mV); mDrawable->setPositionGroup(pos); }
BOOL LLVOTree::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) { if (mDead || !(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_TREE))) { return TRUE; } S32 trunk_LOD = sMAX_NUM_TREE_LOD_LEVELS ; F32 app_angle = getAppAngle()*LLVOTree::sTreeFactor; for (S32 j = 0; j < sMAX_NUM_TREE_LOD_LEVELS; j++) { if (app_angle > LLVOTree::sLODAngles[j]) { trunk_LOD = j; break; } } if (mReferenceBuffer.isNull()) { gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE); } else if (trunk_LOD != mTrunkLOD) { gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, FALSE); } else { // we're not animating but we may *still* need to // regenerate the mesh if we moved, since position // and rotation are baked into the mesh. // *TODO: I don't know what's so special about trees // that they don't get REBUILD_POSITION automatically // at a higher level. const LLVector3 &this_position = getPositionAgent(); if (this_position != mLastPosition) { gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_POSITION); mLastPosition = this_position; } else { const LLQuaternion &this_rotation = getRotation(); if (this_rotation != mLastRotation) { gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_POSITION); mLastRotation = this_rotation; } } } mTrunkLOD = trunk_LOD; return TRUE; }
void LLVOWater::updateSpatialExtents(LLVector3 &newMin, LLVector3& newMax) { LLVector3 pos = getPositionAgent(); LLVector3 scale = getScale(); newMin = pos - scale * 0.5f; newMax = pos + scale * 0.5f; mDrawable->setPositionGroup((newMin + newMax) * 0.5f); }
void LLVOSurfacePatch::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax) { LLVector3 posAgent = getPositionAgent(); LLVector3 scale = getScale(); scale.mV[VZ] = llmax(scale.mV[VZ], 1.f); newMin.load3( (posAgent-scale*0.5f).mV); // Changing to 2.f makes the culling a -little- better, but still wrong newMax.load3( (posAgent+scale*0.5f).mV); LLVector4a pos; pos.setAdd(newMin,newMax); pos.mul(0.5f); mDrawable->setPositionGroup(pos); }
void LLVOWater::updateSpatialExtents(LLVector4a &newMin, LLVector4a& newMax) { LLVector4a pos; pos.load3(getPositionAgent().mV); LLVector4a scale; scale.load3(getScale().mV); scale.mul(0.5f); newMin.setSub(pos, scale); newMax.setAdd(pos, scale); pos.setAdd(newMin,newMax); pos.mul(0.5f); mDrawable->setPositionGroup(pos); }
void LLVOPartGroup::updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) { const LLVector3& pos_agent = getPositionAgent(); LLVector4a scale; LLVector4a p; p.load3(pos_agent.mV); scale.splat(mScale.mV[0]+mViewerPartGroupp->getBoxSide()*0.5f); newMin.setSub(p, scale); newMax.setAdd(p,scale); llassert(newMin.isFinite3()); llassert(newMax.isFinite3()); llassert(p.isFinite3()); mDrawable->setPositionGroup(p); }
BOOL LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius) { //VECTORIZE THIS //get area of circle around face LLVector4a center; center.load3(getPositionAgent().mV); LLVector4a size; size.setSub(mExtents[1], mExtents[0]); size.mul(0.5f); LLViewerCamera* camera = LLViewerCamera::getInstance(); F32 size_squared = size.dot3(size).getF32(); LLVector4a lookAt; LLVector4a t; t.load3(camera->getOrigin().mV); lookAt.setSub(center, t); F32 dist = lookAt.getLength3().getF32(); dist = llmax(dist-size.getLength3().getF32(), 0.f); lookAt.normalize3fast() ; //get area of circle around node F32 app_angle = atanf((F32) sqrt(size_squared) / dist); radius = app_angle*LLDrawable::sCurPixelAngle; mPixelArea = radius*radius * 3.14159f; LLVector4a x_axis; x_axis.load3(camera->getXAxis().mV); cos_angle_to_view_dir = lookAt.dot3(x_axis).getF32(); if(dist < mBoundingSphereRadius) //camera is very close { cos_angle_to_view_dir = 1.0f; mImportanceToCamera = 1.0f; } else { mImportanceToCamera = LLFace::calcImportanceToCamera(cos_angle_to_view_dir, dist); } return true; }
void LLVOTree::setPixelAreaAndAngle(LLAgent &agent) { LLVector3 center = getPositionAgent();//center of tree. LLVector3 viewer_pos_agent = gAgent.getCameraPositionAgent(); LLVector3 lookAt = center - viewer_pos_agent; F32 dist = lookAt.normVec() ; F32 cos_angle_to_view_dir = lookAt * LLViewerCamera::getInstance()->getXAxis() ; F32 range = dist - getMinScale()/2; if (range < F_ALMOST_ZERO) // range == zero { range = 0; mAppAngle = 180.f; } else { mAppAngle = (F32) atan2( getMaxScale(), range) * RAD_TO_DEG; } F32 max_scale = mBillboardScale * getMaxScale(); F32 area = max_scale * (max_scale*mBillboardRatio); // Compute pixels per meter at the given range F32 pixels_per_meter = LLViewerCamera::getInstance()->getViewHeightInPixels() / (tan(LLViewerCamera::getInstance()->getView()) * dist); mPixelArea = pixels_per_meter * pixels_per_meter * area ; F32 importance = LLFace::calcImportanceToCamera(cos_angle_to_view_dir, dist) ; mPixelArea = LLFace::adjustPixelArea(importance, mPixelArea) ; if (mPixelArea > LLViewerCamera::getInstance()->getScreenPixelArea()) { mAppAngle = 180.f; } #if 0 // mAppAngle is a bit of voodoo; // use the one calculated LLViewerObject::setPixelAreaAndAngle above // to avoid LOD miscalculations mAppAngle = (F32) atan2( max_scale, range) * RAD_TO_DEG; #endif }
BOOL LLVOTree::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) { const U16 FRAMES_PER_WIND_UPDATE = 20; // How many frames between wind update per tree const F32 TREE_WIND_SENSITIVITY = 0.005f; const F32 TREE_TRUNK_STIFFNESS = 0.1f; if (mDead || !(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_TREE))) { return TRUE; } //it's cheaper to check if wind is enabled first if (gLLWindEnabled && gSavedSettings.getBOOL("RenderAnimateTrees")) { F32 mass_inv; // For all tree objects, update the trunk bending with the current wind // Walk sprite list in order away from viewer if (!(mFrameCount % FRAMES_PER_WIND_UPDATE)) { // If needed, Get latest wind for this tree mWind = mRegionp->mWind.getVelocity(getPositionRegion()); } mFrameCount++; mass_inv = 1.f/(5.f + mDepth*mBranches*0.2f); mTrunkVel += (mWind * mass_inv * TREE_WIND_SENSITIVITY); // Pull in direction of wind mTrunkVel -= (mTrunkBend * mass_inv * TREE_TRUNK_STIFFNESS); // Restoring force in direction of trunk mTrunkBend += mTrunkVel; mTrunkVel *= 0.99f; // Add damping if (mTrunkBend.length() > 1.f) { mTrunkBend.normalize(); } if (mTrunkVel.length() > 1.f) { mTrunkVel.normalize(); } } S32 trunk_LOD = 0; F32 app_angle = getAppAngle()*LLVOTree::sTreeFactor; for (S32 j = 0; j < 4; j++) { if (app_angle > LLVOTree::sLODAngles[j]) { trunk_LOD = j; break; } } if (!gLLWindEnabled || !gSavedSettings.getBOOL("RenderAnimateTrees")) { if (mReferenceBuffer.isNull()) { gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE); } else if (trunk_LOD != mTrunkLOD) { gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, FALSE); } else { // we're not animating but we may *still* need to // regenerate the mesh if we moved, since position // and rotation are baked into the mesh. // *TODO: I don't know what's so special about trees // that they don't get REBUILD_POSITION automatically // at a higher level. const LLVector3 &this_position = getPositionAgent(); if (this_position != mLastPosition) { gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_POSITION); mLastPosition = this_position; } else { const LLQuaternion &this_rotation = getRotation(); if (this_rotation != mLastRotation) { gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_POSITION); mLastRotation = this_rotation; } } } } mTrunkLOD = trunk_LOD; return TRUE; }
BOOL LLVOWater::updateGeometry(LLDrawable *drawable) { LLFastTimer ftm(LLFastTimer::FTM_UPDATE_WATER); LLFace *face; if (drawable->getNumFaces() < 1) { LLDrawPoolWater *poolp = (LLDrawPoolWater*) gPipeline.getPool(LLDrawPool::POOL_WATER); drawable->addFace(poolp, NULL); } face = drawable->getFace(0); // LLVector2 uvs[4]; // LLVector3 vtx[4]; LLStrider<LLVector3> verticesp, normalsp; LLStrider<LLVector2> texCoordsp; LLStrider<U16> indicesp; U16 index_offset; S32 size = 16; S32 num_quads = size*size; face->setSize(4*num_quads, 6*num_quads); if (face->mVertexBuffer.isNull()) { face->mVertexBuffer = new LLVertexBuffer(LLDrawPoolWater::VERTEX_DATA_MASK, GL_DYNAMIC_DRAW_ARB); face->mVertexBuffer->allocateBuffer(face->getGeomCount(), face->getIndicesCount(), TRUE); face->setIndicesIndex(0); face->setGeomIndex(0); } else { face->mVertexBuffer->resizeBuffer(face->getGeomCount(), face->getIndicesCount()); } index_offset = face->getGeometry(verticesp,normalsp,texCoordsp, indicesp); LLVector3 position_agent; position_agent = getPositionAgent(); face->mCenterAgent = position_agent; face->mCenterLocal = position_agent; S32 x, y; F32 step_x = getScale().mV[0] / size; F32 step_y = getScale().mV[1] / size; const LLVector3 up(0.f, step_y * 0.5f, 0.f); const LLVector3 right(step_x * 0.5f, 0.f, 0.f); const LLVector3 normal(0.f, 0.f, 1.f); F32 size_inv = 1.f / size; for (y = 0; y < size; y++) { for (x = 0; x < size; x++) { S32 toffset = index_offset + 4*(y*size + x); position_agent = getPositionAgent() - getScale() * 0.5f; position_agent.mV[VX] += (x + 0.5f) * step_x; position_agent.mV[VY] += (y + 0.5f) * step_y; *verticesp++ = position_agent - right + up; *verticesp++ = position_agent - right - up; *verticesp++ = position_agent + right + up; *verticesp++ = position_agent + right - up; *texCoordsp++ = LLVector2(x*size_inv, (y+1)*size_inv); *texCoordsp++ = LLVector2(x*size_inv, y*size_inv); *texCoordsp++ = LLVector2((x+1)*size_inv, (y+1)*size_inv); *texCoordsp++ = LLVector2((x+1)*size_inv, y*size_inv); *normalsp++ = normal; *normalsp++ = normal; *normalsp++ = normal; *normalsp++ = normal; *indicesp++ = toffset + 0; *indicesp++ = toffset + 1; *indicesp++ = toffset + 2; *indicesp++ = toffset + 1; *indicesp++ = toffset + 3; *indicesp++ = toffset + 2; } } face->mVertexBuffer->setBuffer(0); mDrawable->movePartition(); LLPipeline::sCompiles++; return TRUE; }
BOOL LLVOTree::updateGeometry(LLDrawable *drawable) { LLFastTimer ftm(LLFastTimer::FTM_UPDATE_TREE); if (mReferenceBuffer.isNull() || mDrawable->getFace(0)->mVertexBuffer.isNull()) { const F32 SRR3 = 0.577350269f; // sqrt(1/3) const F32 SRR2 = 0.707106781f; // sqrt(1/2) U32 i, j; U32 slices = MAX_SLICES; S32 max_indices = LEAF_INDICES; S32 max_vertices = LEAF_VERTICES; S32 lod; LLFace *face = drawable->getFace(0); face->mCenterAgent = getPositionAgent(); face->mCenterLocal = face->mCenterAgent; for (lod = 0; lod < 4; lod++) { slices = sLODSlices[lod]; sLODVertexOffset[lod] = max_vertices; sLODVertexCount[lod] = slices*slices; sLODIndexOffset[lod] = max_indices; sLODIndexCount[lod] = (slices-1)*(slices-1)*6; max_indices += sLODIndexCount[lod]; max_vertices += sLODVertexCount[lod]; } mReferenceBuffer = new LLVertexBuffer(LLDrawPoolTree::VERTEX_DATA_MASK, gSavedSettings.getBOOL("RenderAnimateTrees") ? GL_STATIC_DRAW_ARB : 0); mReferenceBuffer->allocateBuffer(max_vertices, max_indices, TRUE); LLStrider<LLVector3> vertices; LLStrider<LLVector3> normals; LLStrider<LLVector2> tex_coords; LLStrider<U16> indicesp; mReferenceBuffer->getVertexStrider(vertices); mReferenceBuffer->getNormalStrider(normals); mReferenceBuffer->getTexCoord0Strider(tex_coords); mReferenceBuffer->getIndexStrider(indicesp); S32 vertex_count = 0; S32 index_count = 0; // First leaf *(normals++) = LLVector3(-SRR2, -SRR2, 0.f); *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_BOTTOM); *(vertices++) = LLVector3(-0.5f*LEAF_WIDTH, 0.f, 0.f); vertex_count++; *(normals++) = LLVector3(SRR3, -SRR3, SRR3); *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_TOP); *(vertices++) = LLVector3(0.5f*LEAF_WIDTH, 0.f, 1.f); vertex_count++; *(normals++) = LLVector3(-SRR3, -SRR3, SRR3); *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_TOP); *(vertices++) = LLVector3(-0.5f*LEAF_WIDTH, 0.f, 1.f); vertex_count++; *(normals++) = LLVector3(SRR2, -SRR2, 0.f); *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_BOTTOM); *(vertices++) = LLVector3(0.5f*LEAF_WIDTH, 0.f, 0.f); vertex_count++; *(indicesp++) = 0; index_count++; *(indicesp++) = 1; index_count++; *(indicesp++) = 2; index_count++; *(indicesp++) = 0; index_count++; *(indicesp++) = 3; index_count++; *(indicesp++) = 1; index_count++; // Same leaf, inverse winding/normals *(normals++) = LLVector3(-SRR2, SRR2, 0.f); *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_BOTTOM); *(vertices++) = LLVector3(-0.5f*LEAF_WIDTH, 0.f, 0.f); vertex_count++; *(normals++) = LLVector3(SRR3, SRR3, SRR3); *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_TOP); *(vertices++) = LLVector3(0.5f*LEAF_WIDTH, 0.f, 1.f); vertex_count++; *(normals++) = LLVector3(-SRR3, SRR3, SRR3); *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_TOP); *(vertices++) = LLVector3(-0.5f*LEAF_WIDTH, 0.f, 1.f); vertex_count++; *(normals++) = LLVector3(SRR2, SRR2, 0.f); *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_BOTTOM); *(vertices++) = LLVector3(0.5f*LEAF_WIDTH, 0.f, 0.f); vertex_count++; *(indicesp++) = 4; index_count++; *(indicesp++) = 6; index_count++; *(indicesp++) = 5; index_count++; *(indicesp++) = 4; index_count++; *(indicesp++) = 5; index_count++; *(indicesp++) = 7; index_count++; // next leaf *(normals++) = LLVector3(SRR2, -SRR2, 0.f); *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_BOTTOM); *(vertices++) = LLVector3(0.f, -0.5f*LEAF_WIDTH, 0.f); vertex_count++; *(normals++) = LLVector3(SRR3, SRR3, SRR3); *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_TOP); *(vertices++) = LLVector3(0.f, 0.5f*LEAF_WIDTH, 1.f); vertex_count++; *(normals++) = LLVector3(SRR3, -SRR3, SRR3); *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_TOP); *(vertices++) = LLVector3(0.f, -0.5f*LEAF_WIDTH, 1.f); vertex_count++; *(normals++) = LLVector3(SRR2, SRR2, 0.f); *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_BOTTOM); *(vertices++) = LLVector3(0.f, 0.5f*LEAF_WIDTH, 0.f); vertex_count++; *(indicesp++) = 8; index_count++; *(indicesp++) = 9; index_count++; *(indicesp++) = 10; index_count++; *(indicesp++) = 8; index_count++; *(indicesp++) = 11; index_count++; *(indicesp++) = 9; index_count++; // other side of same leaf *(normals++) = LLVector3(-SRR2, -SRR2, 0.f); *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_BOTTOM); *(vertices++) = LLVector3(0.f, -0.5f*LEAF_WIDTH, 0.f); vertex_count++; *(normals++) = LLVector3(-SRR3, SRR3, SRR3); *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_TOP); *(vertices++) = LLVector3(0.f, 0.5f*LEAF_WIDTH, 1.f); vertex_count++; *(normals++) = LLVector3(-SRR3, -SRR3, SRR3); *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_TOP); *(vertices++) = LLVector3(0.f, -0.5f*LEAF_WIDTH, 1.f); vertex_count++; *(normals++) = LLVector3(-SRR2, SRR2, 0.f); *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_BOTTOM); *(vertices++) = LLVector3(0.f, 0.5f*LEAF_WIDTH, 0.f); vertex_count++; *(indicesp++) = 12; index_count++; *(indicesp++) = 14; index_count++; *(indicesp++) = 13; index_count++; *(indicesp++) = 12; index_count++; *(indicesp++) = 13; index_count++; *(indicesp++) = 15; index_count++; // Generate geometry for the cylinders // Different LOD's // Generate the vertices // Generate the indices for (lod = 0; lod < 4; lod++) { slices = sLODSlices[lod]; F32 base_radius = 0.65f; F32 top_radius = base_radius * sSpeciesTable[mSpecies]->mTaper; //llinfos << "Species " << ((U32) mSpecies) << ", taper = " << sSpeciesTable[mSpecies].mTaper << llendl; //llinfos << "Droop " << mDroop << ", branchlength: " << mBranchLength << llendl; F32 angle = 0; F32 angle_inc = 360.f/(slices-1); F32 z = 0.f; F32 z_inc = 1.f; if (slices > 3) { z_inc = 1.f/(slices - 3); } F32 radius = base_radius; F32 x1,y1; F32 noise_scale = sSpeciesTable[mSpecies]->mNoiseMag; LLVector3 nvec; const F32 cap_nudge = 0.1f; // Height to 'peak' the caps on top/bottom of branch const S32 fractal_depth = 5; F32 nvec_scale = 1.f * sSpeciesTable[mSpecies]->mNoiseScale; F32 nvec_scalez = 4.f * sSpeciesTable[mSpecies]->mNoiseScale; F32 tex_z_repeat = sSpeciesTable[mSpecies]->mRepeatTrunkZ; F32 start_radius; F32 nangle = 0; F32 height = 1.f; F32 r0; for (i = 0; i < slices; i++) { if (i == 0) { z = - cap_nudge; r0 = 0.0; } else if (i == (slices - 1)) { z = 1.f + cap_nudge;//((i - 2) * z_inc) + cap_nudge; r0 = 0.0; } else { z = (i - 1) * z_inc; r0 = base_radius + (top_radius - base_radius)*z; } for (j = 0; j < slices; j++) { if (slices - 1 == j) { angle = 0.f; } else { angle = j*angle_inc; } nangle = angle; x1 = cos(angle * DEG_TO_RAD); y1 = sin(angle * DEG_TO_RAD); LLVector2 tc; // This isn't totally accurate. Should compute based on slope as well. start_radius = r0 * (1.f + 1.2f*fabs(z - 0.66f*height)/height); nvec.set( cos(nangle * DEG_TO_RAD)*start_radius*nvec_scale, sin(nangle * DEG_TO_RAD)*start_radius*nvec_scale, z*nvec_scalez); // First and last slice at 0 radius (to bring in top/bottom of structure) radius = start_radius + turbulence3((F32*)&nvec.mV, (F32)fractal_depth)*noise_scale; if (slices - 1 == j) { // Not 0.5 for slight slop factor to avoid edges on leaves tc = LLVector2(0.490f, (1.f - z/2.f)*tex_z_repeat); } else { tc = LLVector2((angle/360.f)*0.5f, (1.f - z/2.f)*tex_z_repeat); } *(vertices++) = LLVector3(x1*radius, y1*radius, z); *(normals++) = LLVector3(x1, y1, 0.f); *(tex_coords++) = tc; vertex_count++; } } for (i = 0; i < (slices - 1); i++) { for (j = 0; j < (slices - 1); j++) { S32 x1_offset = j+1; if ((j+1) == slices) { x1_offset = 0; } // Generate the matching quads *(indicesp) = j + (i*slices) + sLODVertexOffset[lod]; llassert(*(indicesp) < (U32)max_vertices); indicesp++; index_count++; *(indicesp) = x1_offset + ((i+1)*slices) + sLODVertexOffset[lod]; llassert(*(indicesp) < (U32)max_vertices); indicesp++; index_count++; *(indicesp) = j + ((i+1)*slices) + sLODVertexOffset[lod]; llassert(*(indicesp) < (U32)max_vertices); indicesp++; index_count++; *(indicesp) = j + (i*slices) + sLODVertexOffset[lod]; llassert(*(indicesp) < (U32)max_vertices); indicesp++; index_count++; *(indicesp) = x1_offset + (i*slices) + sLODVertexOffset[lod]; llassert(*(indicesp) < (U32)max_vertices); indicesp++; index_count++; *(indicesp) = x1_offset + ((i+1)*slices) + sLODVertexOffset[lod]; llassert(*(indicesp) < (U32)max_vertices); indicesp++; index_count++; } } slices /= 2; } mReferenceBuffer->setBuffer(0); llassert(vertex_count == max_vertices); llassert(index_count == max_indices); } if (gLLWindEnabled || gSavedSettings.getBOOL("RenderAnimateTrees")) { mDrawable->getFace(0)->mVertexBuffer = mReferenceBuffer; } else { //generate tree mesh updateMesh(); } return TRUE; }
BOOL LLVOWater::updateGeometry(LLDrawable *drawable) { LLFastTimer ftm(LLFastTimer::FTM_UPDATE_WATER); LLFace *face; if (drawable->getNumFaces() < 1) { LLDrawPoolWater *poolp = (LLDrawPoolWater*) gPipeline.getPool(LLDrawPool::POOL_WATER); drawable->addFace(poolp, NULL); } face = drawable->getFace(0); // LLVector2 uvs[4]; // LLVector3 vtx[4]; LLStrider<LLVector3> verticesp, normalsp; LLStrider<LLVector2> texCoordsp; LLStrider<U16> indicesp; U16 index_offset; // A quad is 4 vertices and 6 indices (making 2 triangles) static const unsigned int vertices_per_quad = 4; static const unsigned int indices_per_quad = 6; static const LLCachedControl<bool> render_transparent_water("RenderTransparentWater",false); const S32 size = (render_transparent_water && !LLGLSLShader::sNoFixedFunction) ? 16 : 1; const S32 num_quads = size * size; face->setSize(vertices_per_quad * num_quads, indices_per_quad * num_quads); LLVertexBuffer* buff = face->getVertexBuffer(); if (!buff) { buff = new LLVertexBuffer(LLDrawPoolWater::VERTEX_DATA_MASK, GL_DYNAMIC_DRAW_ARB); buff->allocateBuffer(face->getGeomCount(), face->getIndicesCount(), TRUE); face->setIndicesIndex(0); face->setGeomIndex(0); face->setVertexBuffer(buff); } else { buff->resizeBuffer(face->getGeomCount(), face->getIndicesCount()); } index_offset = face->getGeometry(verticesp,normalsp,texCoordsp, indicesp); LLVector3 position_agent; position_agent = getPositionAgent(); face->mCenterAgent = position_agent; face->mCenterLocal = position_agent; S32 x, y; F32 step_x = getScale().mV[0] / size; F32 step_y = getScale().mV[1] / size; const LLVector3 up(0.f, step_y * 0.5f, 0.f); const LLVector3 right(step_x * 0.5f, 0.f, 0.f); const LLVector3 normal(0.f, 0.f, 1.f); F32 size_inv = 1.f / size; for (y = 0; y < size; y++) { for (x = 0; x < size; x++) { S32 toffset = index_offset + 4*(y*size + x); position_agent = getPositionAgent() - getScale() * 0.5f; position_agent.mV[VX] += (x + 0.5f) * step_x; position_agent.mV[VY] += (y + 0.5f) * step_y; *verticesp++ = position_agent - right + up; *verticesp++ = position_agent - right - up; *verticesp++ = position_agent + right + up; *verticesp++ = position_agent + right - up; *texCoordsp++ = LLVector2(x*size_inv, (y+1)*size_inv); *texCoordsp++ = LLVector2(x*size_inv, y*size_inv); *texCoordsp++ = LLVector2((x+1)*size_inv, (y+1)*size_inv); *texCoordsp++ = LLVector2((x+1)*size_inv, y*size_inv); *normalsp++ = normal; *normalsp++ = normal; *normalsp++ = normal; *normalsp++ = normal; *indicesp++ = toffset + 0; *indicesp++ = toffset + 1; *indicesp++ = toffset + 2; *indicesp++ = toffset + 1; *indicesp++ = toffset + 3; *indicesp++ = toffset + 2; } } buff->flush(); mDrawable->movePartition(); LLPipeline::sCompiles++; return TRUE; }
void LLVOTree::updateMesh() { LLMatrix4 matrix; // Translate to tree base HACK - adjustment in Z plants tree underground const LLVector3 &pos_agent = getPositionAgent(); //glTranslatef(pos_agent.mV[VX], pos_agent.mV[VY], pos_agent.mV[VZ] - 0.1f); LLMatrix4 trans_mat; trans_mat.setTranslation(pos_agent.mV[VX], pos_agent.mV[VY], pos_agent.mV[VZ] - 0.1f); trans_mat *= matrix; // Rotate to tree position and bend for current trunk/wind // Note that trunk stiffness controls the amount of bend at the trunk as // opposed to the crown of the tree // const F32 TRUNK_STIFF = 22.f; LLQuaternion rot = LLQuaternion(mTrunkBend.magVec()*TRUNK_STIFF*DEG_TO_RAD, LLVector4(mTrunkBend.mV[VX], mTrunkBend.mV[VY], 0)) * LLQuaternion(90.f*DEG_TO_RAD, LLVector4(0,0,1)) * getRotation(); LLMatrix4 rot_mat(rot); rot_mat *= trans_mat; F32 radius = getScale().magVec()*0.05f; LLMatrix4 scale_mat; scale_mat.mMatrix[0][0] = scale_mat.mMatrix[1][1] = scale_mat.mMatrix[2][2] = radius; scale_mat *= rot_mat; // const F32 THRESH_ANGLE_FOR_BILLBOARD = 15.f; // const F32 BLEND_RANGE_FOR_BILLBOARD = 3.f; F32 droop = mDroop + 25.f*(1.f - mTrunkBend.magVec()); S32 stop_depth = 0; F32 alpha = 1.0; U32 vert_count = 0; U32 index_count = 0; calcNumVerts(vert_count, index_count, mTrunkLOD, stop_depth, mDepth, mTrunkDepth, mBranches); LLFace* facep = mDrawable->getFace(0); facep->mVertexBuffer = new LLVertexBuffer(LLDrawPoolTree::VERTEX_DATA_MASK, GL_STATIC_DRAW_ARB); facep->mVertexBuffer->allocateBuffer(vert_count, index_count, TRUE); LLStrider<LLVector3> vertices; LLStrider<LLVector3> normals; LLStrider<LLVector2> tex_coords; LLStrider<U16> indices; U16 idx_offset = 0; facep->mVertexBuffer->getVertexStrider(vertices); facep->mVertexBuffer->getNormalStrider(normals); facep->mVertexBuffer->getTexCoord0Strider(tex_coords); facep->mVertexBuffer->getIndexStrider(indices); genBranchPipeline(vertices, normals, tex_coords, indices, idx_offset, scale_mat, mTrunkLOD, stop_depth, mDepth, mTrunkDepth, 1.0, mTwist, droop, mBranches, alpha); mReferenceBuffer->setBuffer(0); facep->mVertexBuffer->setBuffer(0); }