diff options
author | James Cook <james@lindenlab.com> | 2007-01-02 08:33:20 +0000 |
---|---|---|
committer | James Cook <james@lindenlab.com> | 2007-01-02 08:33:20 +0000 |
commit | 420b91db29485df39fd6e724e782c449158811cb (patch) | |
tree | b471a94563af914d3ed3edd3e856d21cb1b69945 /indra/newview/llvotree.cpp |
Print done when done.
Diffstat (limited to 'indra/newview/llvotree.cpp')
-rw-r--r-- | indra/newview/llvotree.cpp | 906 |
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); +} |