llvotree.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:36k
- /**
- * @file llvotree.cpp
- * @brief LLVOTree class implementation
- *
- * $LicenseInfo:firstyear=2002&license=viewergpl$
- *
- * Copyright (c) 2002-2010, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
- #include "llviewerprecompiledheaders.h"
- #include "llvotree.h"
- #include "lldrawpooltree.h"
- #include "llviewercontrol.h"
- #include "lldir.h"
- #include "llprimitive.h"
- #include "lltree_common.h"
- #include "llxmltree.h"
- #include "material_codes.h"
- #include "object_flags.h"
- #include "llagent.h"
- #include "lldrawable.h"
- #include "llface.h"
- #include "llviewercamera.h"
- #include "llviewertexturelist.h"
- #include "llviewerobjectlist.h"
- #include "llviewerregion.h"
- #include "llworld.h"
- #include "noise.h"
- #include "pipeline.h"
- #include "llspatialpartition.h"
- #include "llnotificationsutil.h"
- extern LLPipeline gPipeline;
- const S32 MAX_SLICES = 32;
- const F32 LEAF_LEFT = 0.52f;
- const F32 LEAF_RIGHT = 0.98f;
- const F32 LEAF_TOP = 1.0f;
- const F32 LEAF_BOTTOM = 0.52f;
- const F32 LEAF_WIDTH = 1.f;
- S32 LLVOTree::sLODVertexOffset[4];
- S32 LLVOTree::sLODVertexCount[4];
- S32 LLVOTree::sLODIndexOffset[4];
- S32 LLVOTree::sLODIndexCount[4];
- S32 LLVOTree::sLODSlices[4] = {10, 5, 4, 3};
- F32 LLVOTree::sLODAngles[4] = {30.f, 20.f, 15.f, 0.f};
- F32 LLVOTree::sTreeFactor = 1.f;
- LLVOTree::SpeciesMap LLVOTree::sSpeciesTable;
- S32 LLVOTree::sMaxTreeSpecies = 0;
- // Tree variables and functions
- LLVOTree::LLVOTree(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp):
- LLViewerObject(id, pcode, regionp)
- {
- mSpecies = 0;
- mFrameCount = 0;
- mWind = mRegionp->mWind.getVelocity(getPositionRegion());
- mTrunkLOD = 0;
- }
- LLVOTree::~LLVOTree()
- {
- if (mData)
- {
- delete[] mData;
- mData = NULL;
- }
- }
- // static
- void LLVOTree::initClass()
- {
- std::string xml_filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"trees.xml");
-
- LLXmlTree tree_def_tree;
- if (!tree_def_tree.parseFile(xml_filename))
- {
- llerrs << "Failed to parse tree file." << llendl;
- }
- LLXmlTreeNode* rootp = tree_def_tree.getRoot();
- for (LLXmlTreeNode* tree_def = rootp->getFirstChild();
- tree_def;
- tree_def = rootp->getNextChild())
- {
- if (!tree_def->hasName("tree"))
- {
- llwarns << "Invalid tree definition node " << tree_def->getName() << llendl;
- continue;
- }
- F32 F32_val;
- LLUUID id;
- S32 S32_val;
- BOOL success = TRUE;
- S32 species;
- static LLStdStringHandle species_id_string = LLXmlTree::addAttributeString("species_id");
- if (!tree_def->getFastAttributeS32(species_id_string, species))
- {
- llwarns << "No species id defined" << llendl;
- continue;
- }
- if (species < 0)
- {
- llwarns << "Invalid species id " << species << llendl;
- continue;
- }
- if (sSpeciesTable.count(species))
- {
- llwarns << "Tree species " << species << " already defined! Duplicate discarded." << llendl;
- continue;
- }
- TreeSpeciesData* newTree = new TreeSpeciesData();
- static LLStdStringHandle texture_id_string = LLXmlTree::addAttributeString("texture_id");
- success &= tree_def->getFastAttributeUUID(texture_id_string, id);
- newTree->mTextureID = id;
-
- static LLStdStringHandle droop_string = LLXmlTree::addAttributeString("droop");
- success &= tree_def->getFastAttributeF32(droop_string, F32_val);
- newTree->mDroop = F32_val;
- static LLStdStringHandle twist_string = LLXmlTree::addAttributeString("twist");
- success &= tree_def->getFastAttributeF32(twist_string, F32_val);
- newTree->mTwist = F32_val;
-
- static LLStdStringHandle branches_string = LLXmlTree::addAttributeString("branches");
- success &= tree_def->getFastAttributeF32(branches_string, F32_val);
- newTree->mBranches = F32_val;
- static LLStdStringHandle depth_string = LLXmlTree::addAttributeString("depth");
- success &= tree_def->getFastAttributeS32(depth_string, S32_val);
- newTree->mDepth = S32_val;
- static LLStdStringHandle scale_step_string = LLXmlTree::addAttributeString("scale_step");
- success &= tree_def->getFastAttributeF32(scale_step_string, F32_val);
- newTree->mScaleStep = F32_val;
-
- static LLStdStringHandle trunk_depth_string = LLXmlTree::addAttributeString("trunk_depth");
- success &= tree_def->getFastAttributeS32(trunk_depth_string, S32_val);
- newTree->mTrunkDepth = S32_val;
-
- static LLStdStringHandle branch_length_string = LLXmlTree::addAttributeString("branch_length");
- success &= tree_def->getFastAttributeF32(branch_length_string, F32_val);
- newTree->mBranchLength = F32_val;
- static LLStdStringHandle trunk_length_string = LLXmlTree::addAttributeString("trunk_length");
- success &= tree_def->getFastAttributeF32(trunk_length_string, F32_val);
- newTree->mTrunkLength = F32_val;
- static LLStdStringHandle leaf_scale_string = LLXmlTree::addAttributeString("leaf_scale");
- success &= tree_def->getFastAttributeF32(leaf_scale_string, F32_val);
- newTree->mLeafScale = F32_val;
-
- static LLStdStringHandle billboard_scale_string = LLXmlTree::addAttributeString("billboard_scale");
- success &= tree_def->getFastAttributeF32(billboard_scale_string, F32_val);
- newTree->mBillboardScale = F32_val;
-
- static LLStdStringHandle billboard_ratio_string = LLXmlTree::addAttributeString("billboard_ratio");
- success &= tree_def->getFastAttributeF32(billboard_ratio_string, F32_val);
- newTree->mBillboardRatio = F32_val;
-
- static LLStdStringHandle trunk_aspect_string = LLXmlTree::addAttributeString("trunk_aspect");
- success &= tree_def->getFastAttributeF32(trunk_aspect_string, F32_val);
- newTree->mTrunkAspect = F32_val;
- static LLStdStringHandle branch_aspect_string = LLXmlTree::addAttributeString("branch_aspect");
- success &= tree_def->getFastAttributeF32(branch_aspect_string, F32_val);
- newTree->mBranchAspect = F32_val;
- static LLStdStringHandle leaf_rotate_string = LLXmlTree::addAttributeString("leaf_rotate");
- success &= tree_def->getFastAttributeF32(leaf_rotate_string, F32_val);
- newTree->mRandomLeafRotate = F32_val;
-
- static LLStdStringHandle noise_mag_string = LLXmlTree::addAttributeString("noise_mag");
- success &= tree_def->getFastAttributeF32(noise_mag_string, F32_val);
- newTree->mNoiseMag = F32_val;
- static LLStdStringHandle noise_scale_string = LLXmlTree::addAttributeString("noise_scale");
- success &= tree_def->getFastAttributeF32(noise_scale_string, F32_val);
- newTree->mNoiseScale = F32_val;
- static LLStdStringHandle taper_string = LLXmlTree::addAttributeString("taper");
- success &= tree_def->getFastAttributeF32(taper_string, F32_val);
- newTree->mTaper = F32_val;
- static LLStdStringHandle repeat_z_string = LLXmlTree::addAttributeString("repeat_z");
- success &= tree_def->getFastAttributeF32(repeat_z_string, F32_val);
- newTree->mRepeatTrunkZ = F32_val;
- sSpeciesTable[species] = newTree;
- if (species >= sMaxTreeSpecies) sMaxTreeSpecies = species + 1;
- if (!success)
- {
- std::string name;
- static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
- tree_def->getFastAttributeString(name_string, name);
- llwarns << "Incomplete definition of tree " << name << llendl;
- }
- }
-
- BOOL have_all_trees = TRUE;
- std::string err;
- for (S32 i=0;i<sMaxTreeSpecies;++i)
- {
- if (!sSpeciesTable.count(i))
- {
- err.append(llformat(" %d",i));
- have_all_trees = FALSE;
- }
- }
- if (!have_all_trees)
- {
- LLSD args;
- args["SPECIES"] = err;
- LLNotificationsUtil::add("ErrorUndefinedTrees", args);
- }
- };
- //static
- void LLVOTree::cleanupClass()
- {
- std::for_each(sSpeciesTable.begin(), sSpeciesTable.end(), DeletePairedPointer());
- }
- U32 LLVOTree::processUpdateMessage(LLMessageSystem *mesgsys,
- void **user_data,
- U32 block_num, EObjectUpdateType update_type,
- LLDataPacker *dp)
- {
- // Do base class updates...
- U32 retval = LLViewerObject::processUpdateMessage(mesgsys, user_data, block_num, update_type, dp);
- if ( (getVelocity().lengthSquared() > 0.f)
- ||(getAcceleration().lengthSquared() > 0.f)
- ||(getAngularVelocity().lengthSquared() > 0.f))
- {
- llinfos << "ACK! Moving tree!" << llendl;
- setVelocity(LLVector3::zero);
- setAcceleration(LLVector3::zero);
- setAngularVelocity(LLVector3::zero);
- }
- if (update_type == OUT_TERSE_IMPROVED)
- {
- // Nothing else needs to be done for the terse message.
- return retval;
- }
- //
- // Load Instance-Specific data
- //
- if (mData)
- {
- mSpecies = ((U8 *)mData)[0];
- }
-
- if (!sSpeciesTable.count(mSpecies))
- {
- if (sSpeciesTable.size())
- {
- SpeciesMap::const_iterator it = sSpeciesTable.begin();
- mSpecies = (*it).first;
- }
- }
- //
- // Load Species-Specific data
- //
- mTreeImagep = LLViewerTextureManager::getFetchedTexture(sSpeciesTable[mSpecies]->mTextureID, TRUE, LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
- mBranchLength = sSpeciesTable[mSpecies]->mBranchLength;
- mTrunkLength = sSpeciesTable[mSpecies]->mTrunkLength;
- mLeafScale = sSpeciesTable[mSpecies]->mLeafScale;
- mDroop = sSpeciesTable[mSpecies]->mDroop;
- mTwist = sSpeciesTable[mSpecies]->mTwist;
- mBranches = sSpeciesTable[mSpecies]->mBranches;
- mDepth = sSpeciesTable[mSpecies]->mDepth;
- mScaleStep = sSpeciesTable[mSpecies]->mScaleStep;
- mTrunkDepth = sSpeciesTable[mSpecies]->mTrunkDepth;
- mBillboardScale = sSpeciesTable[mSpecies]->mBillboardScale;
- mBillboardRatio = sSpeciesTable[mSpecies]->mBillboardRatio;
- mTrunkAspect = sSpeciesTable[mSpecies]->mTrunkAspect;
- mBranchAspect = sSpeciesTable[mSpecies]->mBranchAspect;
-
- // position change not caused by us, etc. make sure to rebuild.
- gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL);
- return retval;
- }
- 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;
- }
-
- if (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 (!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;
- }
- const F32 TREE_BLEND_MIN = 1.f;
- const F32 TREE_BLEND_RANGE = 1.f;
- void LLVOTree::render(LLAgent &agent)
- {
- }
- 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 LLVOTree::updateTextures()
- {
- if (mTreeImagep)
- {
- if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA))
- {
- setDebugText(llformat("%4.0f", fsqrtf(mPixelArea)));
- }
- mTreeImagep->addTextureStats(mPixelArea);
- }
- }
- LLDrawable* LLVOTree::createDrawable(LLPipeline *pipeline)
- {
- pipeline->allocDrawable(this);
- mDrawable->setLit(FALSE);
- mDrawable->setRenderType(LLPipeline::RENDER_TYPE_TREE);
- LLDrawPoolTree *poolp = (LLDrawPoolTree*) gPipeline.getPool(LLDrawPool::POOL_TREE, mTreeImagep);
- // Just a placeholder for an actual object...
- LLFace *facep = mDrawable->addFace(poolp, mTreeImagep);
- facep->setSize(1, 3);
- updateRadius();
- return mDrawable;
- }
- // Yes, I know this is bad. I'll clean this up soon. - djs 04/02/02
- const S32 LEAF_INDICES = 24;
- const S32 LEAF_VERTICES = 16;
- static LLFastTimer::DeclareTimer FTM_UPDATE_TREE("Update Tree");
- BOOL LLVOTree::updateGeometry(LLDrawable *drawable)
- {
- LLFastTimer ftm(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 (gSavedSettings.getBOOL("RenderAnimateTrees"))
- {
- mDrawable->getFace(0)->mVertexBuffer = mReferenceBuffer;
- }
- else
- {
- //generate tree mesh
- updateMesh();
- }
-
- 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);
- }
- void LLVOTree::appendMesh(LLStrider<LLVector3>& vertices,
- LLStrider<LLVector3>& normals,
- LLStrider<LLVector2>& tex_coords,
- LLStrider<U16>& indices,
- U16& cur_idx,
- LLMatrix4& matrix,
- LLMatrix4& norm_mat,
- S32 vert_start,
- S32 vert_count,
- S32 index_count,
- S32 index_offset)
- {
- LLStrider<LLVector3> v;
- LLStrider<LLVector3> n;
- LLStrider<LLVector2> t;
- LLStrider<U16> idx;
- mReferenceBuffer->getVertexStrider(v);
- mReferenceBuffer->getNormalStrider(n);
- mReferenceBuffer->getTexCoord0Strider(t);
- mReferenceBuffer->getIndexStrider(idx);
-
- //copy/transform vertices into mesh - check
- for (S32 i = 0; i < vert_count; i++)
- {
- U16 index = vert_start + i;
- *vertices++ = v[index] * matrix;
- LLVector3 norm = n[index] * norm_mat;
- norm.normalize();
- *normals++ = norm;
- *tex_coords++ = t[index];
- }
- //copy offset indices into mesh - check
- for (S32 i = 0; i < index_count; i++)
- {
- U16 index = index_offset + i;
- if (idx[index] >= vert_start + vert_count ||
- idx[index] < vert_start)
- {
- llerrs << "WTF?" << llendl;
- }
- *indices++ = idx[index]-vert_start+cur_idx;
- }
- //increment index offset - check
- cur_idx += vert_count;
- }
-
- void LLVOTree::genBranchPipeline(LLStrider<LLVector3>& vertices,
- LLStrider<LLVector3>& normals,
- LLStrider<LLVector2>& tex_coords,
- LLStrider<U16>& indices,
- U16& index_offset,
- LLMatrix4& matrix,
- S32 trunk_LOD,
- S32 stop_level,
- U16 depth,
- U16 trunk_depth,
- F32 scale,
- F32 twist,
- F32 droop,
- F32 branches,
- F32 alpha)
- {
- //
- // Generates a tree mesh by recursing, generating branches and then a 'leaf' texture.
-
- static F32 constant_twist;
- static F32 width = 0;
- F32 length = ((trunk_depth || (scale == 1.f))? mTrunkLength:mBranchLength);
- F32 aspect = ((trunk_depth || (scale == 1.f))? mTrunkAspect:mBranchAspect);
-
- constant_twist = 360.f/branches;
- if (stop_level >= 0)
- {
- if (depth > stop_level)
- {
- {
- llassert(sLODIndexCount[trunk_LOD] > 0);
- width = scale * length * aspect;
- LLMatrix4 scale_mat;
- scale_mat.mMatrix[0][0] = width;
- scale_mat.mMatrix[1][1] = width;
- scale_mat.mMatrix[2][2] = scale*length;
- scale_mat *= matrix;
- glh::matrix4f norm((F32*) scale_mat.mMatrix);
- LLMatrix4 norm_mat = LLMatrix4(norm.inverse().transpose().m);
- norm_mat.invert();
- appendMesh(vertices, normals, tex_coords, indices, index_offset, scale_mat, norm_mat,
- sLODVertexOffset[trunk_LOD], sLODVertexCount[trunk_LOD], sLODIndexCount[trunk_LOD], sLODIndexOffset[trunk_LOD]);
- }
-
- // Recurse to create more branches
- for (S32 i=0; i < (S32)branches; i++)
- {
- LLMatrix4 trans_mat;
- trans_mat.setTranslation(0,0,scale*length);
- trans_mat *= matrix;
- LLQuaternion rot =
- LLQuaternion(20.f*DEG_TO_RAD, LLVector4(0.f, 0.f, 1.f)) *
- LLQuaternion(droop*DEG_TO_RAD, LLVector4(0.f, 1.f, 0.f)) *
- LLQuaternion(((constant_twist + ((i%2==0)?twist:-twist))*i)*DEG_TO_RAD, LLVector4(0.f, 0.f, 1.f));
-
- LLMatrix4 rot_mat(rot);
- rot_mat *= trans_mat;
- genBranchPipeline(vertices, normals, tex_coords, indices, index_offset, rot_mat, trunk_LOD, stop_level, depth - 1, 0, scale*mScaleStep, twist, droop, branches, alpha);
- }
- // Recurse to continue trunk
- if (trunk_depth)
- {
- LLMatrix4 trans_mat;
- trans_mat.setTranslation(0,0,scale*length);
- trans_mat *= matrix;
- LLMatrix4 rot_mat(70.5f*DEG_TO_RAD, LLVector4(0,0,1));
- rot_mat *= trans_mat; // rotate a bit around Z when ascending
- genBranchPipeline(vertices, normals, tex_coords, indices, index_offset, rot_mat, trunk_LOD, stop_level, depth, trunk_depth-1, scale*mScaleStep, twist, droop, branches, alpha);
- }
- }
- else
- {
- //
- // Append leaves as two 90 deg crossed quads with leaf textures
- //
- {
- LLMatrix4 scale_mat;
- scale_mat.mMatrix[0][0] =
- scale_mat.mMatrix[1][1] =
- scale_mat.mMatrix[2][2] = scale*mLeafScale;
- scale_mat *= matrix;
- glh::matrix4f norm((F32*) scale_mat.mMatrix);
- LLMatrix4 norm_mat = LLMatrix4(norm.inverse().transpose().m);
- appendMesh(vertices, normals, tex_coords, indices, index_offset, scale_mat, norm_mat, 0, LEAF_VERTICES, LEAF_INDICES, 0);
- }
- }
- }
- }
- void LLVOTree::calcNumVerts(U32& vert_count, U32& index_count, S32 trunk_LOD, S32 stop_level, U16 depth, U16 trunk_depth, F32 branches)
- {
- if (stop_level >= 0)
- {
- if (depth > stop_level)
- {
- index_count += sLODIndexCount[trunk_LOD];
- vert_count += sLODVertexCount[trunk_LOD];
- // Recurse to create more branches
- for (S32 i=0; i < (S32)branches; i++)
- {
- calcNumVerts(vert_count, index_count, trunk_LOD, stop_level, depth - 1, 0, branches);
- }
-
- // Recurse to continue trunk
- if (trunk_depth)
- {
- calcNumVerts(vert_count, index_count, trunk_LOD, stop_level, depth, trunk_depth-1, branches);
- }
- }
- else
- {
- index_count += LEAF_INDICES;
- vert_count += LEAF_VERTICES;
- }
- }
- else
- {
- index_count += LEAF_INDICES;
- vert_count += LEAF_VERTICES;
- }
- }
- U32 LLVOTree::drawBranchPipeline(LLMatrix4& matrix, U16* indicesp, S32 trunk_LOD, S32 stop_level, U16 depth, U16 trunk_depth, F32 scale, F32 twist, F32 droop, F32 branches, F32 alpha)
- {
- U32 ret = 0;
- //
- // Draws a tree by recursing, drawing branches and then a 'leaf' texture.
- // If stop_level = -1, simply draws the whole tree as a billboarded texture
- //
-
- static F32 constant_twist;
- static F32 width = 0;
- //F32 length = ((scale == 1.f)? mTrunkLength:mBranchLength);
- //F32 aspect = ((scale == 1.f)? mTrunkAspect:mBranchAspect);
- F32 length = ((trunk_depth || (scale == 1.f))? mTrunkLength:mBranchLength);
- F32 aspect = ((trunk_depth || (scale == 1.f))? mTrunkAspect:mBranchAspect);
-
- constant_twist = 360.f/branches;
- if (!LLPipeline::sReflectionRender && stop_level >= 0)
- {
- //
- // Draw the tree using recursion
- //
- if (depth > stop_level)
- {
- {
- llassert(sLODIndexCount[trunk_LOD] > 0);
- width = scale * length * aspect;
- LLMatrix4 scale_mat;
- scale_mat.mMatrix[0][0] = width;
- scale_mat.mMatrix[1][1] = width;
- scale_mat.mMatrix[2][2] = scale*length;
- scale_mat *= matrix;
- glLoadMatrixf((F32*) scale_mat.mMatrix);
- glDrawElements(GL_TRIANGLES, sLODIndexCount[trunk_LOD], GL_UNSIGNED_SHORT, indicesp + sLODIndexOffset[trunk_LOD]);
- gPipeline.addTrianglesDrawn(LEAF_INDICES/3);
- stop_glerror();
- ret += sLODIndexCount[trunk_LOD];
- }
-
- // Recurse to create more branches
- for (S32 i=0; i < (S32)branches; i++)
- {
- LLMatrix4 trans_mat;
- trans_mat.setTranslation(0,0,scale*length);
- trans_mat *= matrix;
- LLQuaternion rot =
- LLQuaternion(20.f*DEG_TO_RAD, LLVector4(0.f, 0.f, 1.f)) *
- LLQuaternion(droop*DEG_TO_RAD, LLVector4(0.f, 1.f, 0.f)) *
- LLQuaternion(((constant_twist + ((i%2==0)?twist:-twist))*i)*DEG_TO_RAD, LLVector4(0.f, 0.f, 1.f));
-
- LLMatrix4 rot_mat(rot);
- rot_mat *= trans_mat;
- ret += drawBranchPipeline(rot_mat, indicesp, trunk_LOD, stop_level, depth - 1, 0, scale*mScaleStep, twist, droop, branches, alpha);
- }
- // Recurse to continue trunk
- if (trunk_depth)
- {
- LLMatrix4 trans_mat;
- trans_mat.setTranslation(0,0,scale*length);
- trans_mat *= matrix;
- LLMatrix4 rot_mat(70.5f*DEG_TO_RAD, LLVector4(0,0,1));
- rot_mat *= trans_mat; // rotate a bit around Z when ascending
- ret += drawBranchPipeline(rot_mat, indicesp, trunk_LOD, stop_level, depth, trunk_depth-1, scale*mScaleStep, twist, droop, branches, alpha);
- }
- }
- else
- {
- //
- // Draw leaves as two 90 deg crossed quads with leaf textures
- //
- {
- LLMatrix4 scale_mat;
- scale_mat.mMatrix[0][0] =
- scale_mat.mMatrix[1][1] =
- scale_mat.mMatrix[2][2] = scale*mLeafScale;
- scale_mat *= matrix;
-
- glLoadMatrixf((F32*) scale_mat.mMatrix);
- glDrawElements(GL_TRIANGLES, LEAF_INDICES, GL_UNSIGNED_SHORT, indicesp);
- gPipeline.addTrianglesDrawn(LEAF_INDICES/3);
- stop_glerror();
- ret += LEAF_INDICES;
- }
- }
- }
- else
- {
- //
- // Draw the tree as a single billboard texture
- //
- LLMatrix4 scale_mat;
- scale_mat.mMatrix[0][0] =
- scale_mat.mMatrix[1][1] =
- scale_mat.mMatrix[2][2] = mBillboardScale*mBillboardRatio;
- scale_mat *= matrix;
-
- glMatrixMode(GL_TEXTURE);
- glTranslatef(0.0, -0.5, 0.0);
- glMatrixMode(GL_MODELVIEW);
-
- glLoadMatrixf((F32*) scale_mat.mMatrix);
- glDrawElements(GL_TRIANGLES, LEAF_INDICES, GL_UNSIGNED_SHORT, indicesp);
- gPipeline.addTrianglesDrawn(LEAF_INDICES/3);
- stop_glerror();
- ret += LEAF_INDICES;
- glMatrixMode(GL_TEXTURE);
- glLoadIdentity();
- glMatrixMode(GL_MODELVIEW);
- }
- return ret;
- }
- void LLVOTree::updateRadius()
- {
- if (mDrawable.isNull())
- {
- return;
- }
-
- mDrawable->setRadius(32.0f);
- }
- void LLVOTree::updateSpatialExtents(LLVector3& newMin, LLVector3& newMax)
- {
- F32 radius = getScale().length()*0.05f;
- LLVector3 center = getRenderPosition();
- F32 sz = mBillboardScale*mBillboardRatio*radius*0.5f;
- LLVector3 size(sz,sz,sz);
- center += LLVector3(0, 0, size.mV[2]) * getRotation();
-
- newMin.set(center-size);
- newMax.set(center+size);
- mDrawable->setPositionGroup(center);
- }
- BOOL LLVOTree::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, S32 face, BOOL pick_transparent, S32 *face_hitp,
- LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal)
-
- {
- if (!lineSegmentBoundingBox(start, end))
- {
- return FALSE;
- }
- const LLVector3* ext = mDrawable->getSpatialExtents();
- LLVector3 center = (ext[1]+ext[0])*0.5f;
- LLVector3 size = (ext[1]-ext[0]);
- LLQuaternion quat = getRotation();
- center -= LLVector3(0,0,size.magVec() * 0.25f)*quat;
- size.scaleVec(LLVector3(0.25f, 0.25f, 1.f));
- size.mV[0] = llmin(size.mV[0], 1.f);
- size.mV[1] = llmin(size.mV[1], 1.f);
- LLVector3 pos, norm;
-
- if (linesegment_tetrahedron(start, end, center, size, quat, pos, norm))
- {
- if (intersection)
- {
- *intersection = pos;
- }
- if (normal)
- {
- *normal = norm;
- }
- return TRUE;
- }
-
- return FALSE;
- }
- U32 LLVOTree::getPartitionType() const
- {
- return LLViewerRegion::PARTITION_TREE;
- }
- LLTreePartition::LLTreePartition()
- : LLSpatialPartition(0, FALSE, 0)
- {
- mDrawableType = LLPipeline::RENDER_TYPE_TREE;
- mPartitionType = LLViewerRegion::PARTITION_TREE;
- mSlopRatio = 0.f;
- mLODPeriod = 1;
- }