summaryrefslogtreecommitdiff
path: root/indra/newview/llvotree.cpp
diff options
context:
space:
mode:
authorJames Cook <james@lindenlab.com>2007-01-02 08:33:20 +0000
committerJames Cook <james@lindenlab.com>2007-01-02 08:33:20 +0000
commit420b91db29485df39fd6e724e782c449158811cb (patch)
treeb471a94563af914d3ed3edd3e856d21cb1b69945 /indra/newview/llvotree.cpp
Print done when done.
Diffstat (limited to 'indra/newview/llvotree.cpp')
-rw-r--r--indra/newview/llvotree.cpp906
1 files changed, 906 insertions, 0 deletions
diff --git a/indra/newview/llvotree.cpp b/indra/newview/llvotree.cpp
new file mode 100644
index 0000000000..d2c7ed9b6a
--- /dev/null
+++ b/indra/newview/llvotree.cpp
@@ -0,0 +1,906 @@
+/**
+ * @file llvotree.cpp
+ * @brief LLVOTree class implementation
+ *
+ * Copyright (c) 2002-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llvotree.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 "llagparray.h"
+#include "llcylinder.h"
+#include "lldrawable.h"
+#include "llface.h"
+#include "llviewercamera.h"
+#include "llviewerimagelist.h"
+#include "llviewerobjectlist.h"
+#include "llviewerregion.h"
+#include "llworld.h"
+#include "noise.h"
+#include "pipeline.h"
+#include "llviewerwindow.h"
+
+extern LLPipeline gPipeline;
+
+LLGLuint mLeafDList;
+
+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());
+}
+
+
+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)
+ {
+ LLString 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;
+ LLString err;
+ char buffer[10];
+
+ for (S32 i=0;i<sMaxTreeSpecies;++i)
+ {
+ if (!sSpeciesTable.count(i))
+ {
+ snprintf(buffer,10," %d",i);
+ err.append(buffer);
+ have_all_trees = FALSE;
+ }
+ }
+
+ if (!have_all_trees)
+ {
+ LLStringBase<char>::format_map_t args;
+ args["[SPECIES]"] = err;
+ gViewerWindow->alertXml("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().magVecSquared() > 0.f)
+ ||(getAcceleration().magVecSquared() > 0.f)
+ ||(getAngularVelocity().magVecSquared() > 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 = gImageList.getImage(sSpeciesTable[mSpecies]->mTextureID);
+ if (mTreeImagep)
+ {
+ mTreeImagep->bindTexture(0);
+ mTreeImagep->setClamp(TRUE, TRUE);
+ }
+ 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;
+
+ 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;
+ }
+
+ 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.magVec() > 1.f)
+ {
+ mTrunkBend.normVec();
+ }
+
+ if (mTrunkVel.magVec() > 1.f)
+ {
+ mTrunkVel.normVec();
+ }
+
+ 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.magVec(); // 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 = gCamera->getViewHeightInPixels() /
+ (tan(gCamera->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(LLAgent &agent)
+{
+ F32 texel_area_ratio = 1.f;
+ F32 cos_angle = 1.f;
+ if (mTreeImagep)
+ {
+ mTreeImagep->addTextureStats(mPixelArea, texel_area_ratio, cos_angle);
+ }
+
+}
+
+
+LLDrawable* LLVOTree::createDrawable(LLPipeline *pipeline)
+{
+ pipeline->allocDrawable(this);
+ mDrawable->setLit(FALSE);
+
+ mDrawable->setRenderType(LLPipeline::RENDER_TYPE_TREE);
+
+ LLDrawPool *poolp = gPipeline.getPool(LLDrawPool::POOL_TREE, mTreeImagep);
+
+ // Just a placeholder for an actual object...
+ LLFace *facep = mDrawable->addFace(poolp, mTreeImagep, TRUE);
+ facep->setSize(1, 3);
+
+ gPipeline.markMaterialed(mDrawable);
+
+ 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;
+
+BOOL LLVOTree::updateGeometry(LLDrawable *drawable)
+{
+ U32 i, j;
+ 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;
+
+
+ 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;
+
+ LLDrawPool *poolp = face->getPool();
+
+ if (poolp->getVertexCount())
+ {
+ return TRUE;
+ }
+
+ if (!face->getDirty())
+ {
+ return FALSE;
+ }
+
+ poolp->setDirty();
+
+ 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];
+ }
+
+ LLStrider<LLVector3> vertices;
+ LLStrider<LLVector3> normals;
+ LLStrider<LLVector2> tex_coords;
+ U32 *indicesp;
+
+ face->setSize(max_vertices, max_indices);
+ face->getGeometry(vertices, normals, tex_coords, indicesp);
+
+ S32 vertex_count = 0;
+ S32 index_count = 0;
+
+ // First leaf
+ for (i = 0; i < 4; i++)
+ {
+ *(normals++) = LLVector3(0.f, 0.f, 1.f);
+ }
+
+ *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_BOTTOM);
+ *(vertices++) = LLVector3(-0.5f*LEAF_WIDTH, 0.f, 0.f);
+ vertex_count++;
+
+ *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_TOP);
+ *(vertices++) = LLVector3(0.5f*LEAF_WIDTH, 0.f, 1.f);
+ vertex_count++;
+
+ *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_TOP);
+ *(vertices++) = LLVector3(-0.5f*LEAF_WIDTH, 0.f, 1.f);
+ vertex_count++;
+
+ *(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
+ for (i = 0; i < 4; i++)
+ {
+ *(normals++) = LLVector3(0.f, 0.f, 1.f);
+ }
+
+ *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_BOTTOM);
+ *(vertices++) = LLVector3(-0.5f*LEAF_WIDTH, 0.f, 0.f);
+ vertex_count++;
+
+ //*(tex_coords++) = LLVector2(1.f, 1.0f);
+ *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_TOP);
+ *(vertices++) = LLVector3(0.5f*LEAF_WIDTH, 0.f, 1.f);
+ vertex_count++;
+
+ //*(tex_coords++) = LLVector2(0.52f, 1.0f);
+ *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_TOP);
+ *(vertices++) = LLVector3(-0.5f*LEAF_WIDTH, 0.f, 1.f);
+ vertex_count++;
+
+ //*(tex_coords++) = LLVector2(1.f, 0.52f);
+ *(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++;
+
+
+ for (i = 0; i < 4; i++)
+ {
+ *(normals++) = LLVector3(0.f, 0.f, 1.f);
+ }
+
+ *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_BOTTOM);
+ *(vertices++) = LLVector3(0.f, -0.5f*LEAF_WIDTH, 0.f);
+ vertex_count++;
+
+ *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_TOP);
+ *(vertices++) = LLVector3(0.f, 0.5f*LEAF_WIDTH, 1.f);
+ vertex_count++;
+
+ *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_TOP);
+ *(vertices++) = LLVector3(0.f, -0.5f*LEAF_WIDTH, 1.f);
+ vertex_count++;
+
+ *(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++;
+
+ for (i = 0; i < 4; i++)
+ {
+ *(normals++) = LLVector3(0.f, 0.f, 1.f);
+ }
+
+ *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_BOTTOM);
+ *(vertices++) = LLVector3(0.f, -0.5f*LEAF_WIDTH, 0.f);
+ vertex_count++;
+
+ *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_TOP);
+ *(vertices++) = LLVector3(0.f, 0.5f*LEAF_WIDTH, 1.f);
+ vertex_count++;
+
+ *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_TOP);
+ *(vertices++) = LLVector3(0.f, -0.5f*LEAF_WIDTH, 1.f);
+ vertex_count++;
+
+ *(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.setVec( 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;
+ }
+
+ llassert(vertex_count == max_vertices);
+ llassert(index_count == max_indices);
+
+ return TRUE;
+}
+
+void LLVOTree::drawBranchPipeline(LLDrawPool *draw_pool, S32 trunk_LOD, S32 stop_level, U16 depth, U16 trunk_depth, F32 scale, F32 twist, F32 droop, F32 branches, F32 alpha)
+{
+ //
+ // 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
+ //
+
+ if (!draw_pool->getIndexCount())
+ {
+ return; // safety net
+ }
+
+ 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 (stop_level >= 0)
+ {
+ //
+ // Draw the tree using recursion
+ //
+ if (depth > stop_level)
+ {
+ {
+ llassert(sLODIndexCount[trunk_LOD] > 0);
+ width = scale * length * aspect;
+ glPushMatrix();
+ glScalef(width,width,scale * length);
+ //glDrawElements(GL_TRIANGLES, sLODIndexCount[trunk_LOD], GL_UNSIGNED_INT, draw_pool.getRawIndices() + sLODIndexOffset[trunk_LOD]);
+ glDrawRangeElements(GL_TRIANGLES,
+ sLODVertexOffset[trunk_LOD],
+ sLODVertexOffset[trunk_LOD] + sLODVertexCount[trunk_LOD]-1,
+ sLODIndexCount[trunk_LOD],
+ GL_UNSIGNED_INT,
+ draw_pool->getRawIndices() + sLODIndexOffset[trunk_LOD]);
+ stop_glerror();
+ draw_pool->addIndicesDrawn(sLODIndexCount[trunk_LOD]);
+ glPopMatrix();
+ }
+
+ // Recurse to create more branches
+ for (S32 i=0; i < (S32)branches; i++)
+ {
+ glPushMatrix();
+ glTranslatef(0.f, 0.f, scale * length);
+ glRotatef((constant_twist + ((i%2==0)?twist:-twist))*i, 0.f, 0.f, 1.f);
+ glRotatef(droop, 0.f, 1.f, 0.f);
+ glRotatef(20.f, 0.f, 0.f, 1.f); // rotate 20deg about axis of new branch to add some random variation
+ drawBranchPipeline(draw_pool, trunk_LOD, stop_level, depth - 1, 0, scale*mScaleStep, twist, droop, branches, alpha);
+ glPopMatrix();
+ }
+ // Recurse to continue trunk
+ if (trunk_depth)
+ {
+ glPushMatrix();
+ glTranslatef(0.f, 0.f, scale * length);
+ glRotatef(70.5f, 0.f, 0.f, 1.f); // rotate a bit around Z when ascending
+ drawBranchPipeline(draw_pool, trunk_LOD, stop_level, depth, trunk_depth-1, scale*mScaleStep, twist, droop, branches, alpha);
+ glPopMatrix();
+ }
+ }
+ else
+ {
+ //
+ // Draw leaves as two 90 deg crossed quads with leaf textures
+ //
+ {
+ glPushMatrix();
+ //glRotatef(llFrand(50.0), llFrand(1.0), llFrand(1.0), llFrand(1.0);
+ //width = scale * (TREE_BRANCH_ASPECT + TREE_LEAF_ASPECT);
+ glScalef(scale*mLeafScale, scale*mLeafScale, scale*mLeafScale);
+ //glScalef(1.5f*width*mLeafScale,1,1.5f*scale*mLeafScale);
+// glDrawElements(GL_TRIANGLES, LEAF_INDICES, GL_UNSIGNED_INT, draw_pool.getRawIndices());
+ glDrawRangeElements(GL_TRIANGLES,
+ 0,
+ LEAF_VERTICES-1,
+ LEAF_INDICES,
+ GL_UNSIGNED_INT,
+ draw_pool->getRawIndices());
+ stop_glerror();
+ draw_pool->addIndicesDrawn(LEAF_INDICES);
+ glPopMatrix();
+ }
+ }
+ }
+ else
+ {
+ //
+ // Draw the tree as a single billboard texture
+ //
+
+ glMatrixMode(GL_TEXTURE);
+ glPushMatrix();
+ glTranslatef(0.0, -0.5, 0.0);
+ glMatrixMode(GL_MODELVIEW);
+ {
+ glPushMatrix();
+ glScalef(mBillboardScale*mBillboardRatio, mBillboardScale*mBillboardRatio, mBillboardScale);
+// glDrawElements(GL_TRIANGLES, LEAF_INDICES, GL_UNSIGNED_INT, draw_pool.getRawIndices());
+ glDrawRangeElements(GL_TRIANGLES,
+ 0,
+ LEAF_VERTICES-1,
+ LEAF_INDICES,
+ GL_UNSIGNED_INT,
+ draw_pool->getRawIndices());
+ stop_glerror();
+ draw_pool->addIndicesDrawn(LEAF_INDICES);
+ glPopMatrix();
+ }
+ glMatrixMode(GL_TEXTURE);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ }
+}
+
+void LLVOTree::updateRadius()
+{
+ if (mDrawable.isNull())
+ {
+ return;
+ }
+
+ mDrawable->setRadius(32.0f);
+}