diff options
| author | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 |
|---|---|---|
| committer | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 |
| commit | 1b67dd855c41f5a0cda7ec2a68d98071986ca703 (patch) | |
| tree | ab243607f74f78200787bba5b9b88f07ef1b966f /indra/newview/llvotree.cpp | |
| parent | 6d6eabca44d08d5b97bfe3e941d2b9687c2246ea (diff) | |
| parent | e1623bb276f83a43ce7a197e388720c05bdefe61 (diff) | |
Merge remote-tracking branch 'origin/main' into DRTVWR-600-maint-A
# Conflicts:
# autobuild.xml
# indra/cmake/CMakeLists.txt
# indra/cmake/GoogleMock.cmake
# indra/llaudio/llaudioengine_fmodstudio.cpp
# indra/llaudio/llaudioengine_fmodstudio.h
# indra/llaudio/lllistener_fmodstudio.cpp
# indra/llaudio/lllistener_fmodstudio.h
# indra/llaudio/llstreamingaudio_fmodstudio.cpp
# indra/llaudio/llstreamingaudio_fmodstudio.h
# indra/llcharacter/llmultigesture.cpp
# indra/llcharacter/llmultigesture.h
# indra/llimage/llimage.cpp
# indra/llimage/llimagepng.cpp
# indra/llimage/llimageworker.cpp
# indra/llimage/tests/llimageworker_test.cpp
# indra/llmessage/tests/llmockhttpclient.h
# indra/llprimitive/llgltfmaterial.h
# indra/llrender/llfontfreetype.cpp
# indra/llui/llcombobox.cpp
# indra/llui/llfolderview.cpp
# indra/llui/llfolderviewmodel.h
# indra/llui/lllineeditor.cpp
# indra/llui/lllineeditor.h
# indra/llui/lltextbase.cpp
# indra/llui/lltextbase.h
# indra/llui/lltexteditor.cpp
# indra/llui/lltextvalidate.cpp
# indra/llui/lltextvalidate.h
# indra/llui/lluictrl.h
# indra/llui/llview.cpp
# indra/llwindow/llwindowmacosx.cpp
# indra/newview/app_settings/settings.xml
# indra/newview/llappearancemgr.cpp
# indra/newview/llappearancemgr.h
# indra/newview/llavatarpropertiesprocessor.cpp
# indra/newview/llavatarpropertiesprocessor.h
# indra/newview/llbreadcrumbview.cpp
# indra/newview/llbreadcrumbview.h
# indra/newview/llbreastmotion.cpp
# indra/newview/llbreastmotion.h
# indra/newview/llconversationmodel.h
# indra/newview/lldensityctrl.cpp
# indra/newview/lldensityctrl.h
# indra/newview/llface.inl
# indra/newview/llfloatereditsky.cpp
# indra/newview/llfloatereditwater.cpp
# indra/newview/llfloateremojipicker.h
# indra/newview/llfloaterimsessiontab.cpp
# indra/newview/llfloaterprofiletexture.cpp
# indra/newview/llfloaterprofiletexture.h
# indra/newview/llgesturemgr.cpp
# indra/newview/llgesturemgr.h
# indra/newview/llimpanel.cpp
# indra/newview/llimpanel.h
# indra/newview/llinventorybridge.cpp
# indra/newview/llinventorybridge.h
# indra/newview/llinventoryclipboard.cpp
# indra/newview/llinventoryclipboard.h
# indra/newview/llinventoryfunctions.cpp
# indra/newview/llinventoryfunctions.h
# indra/newview/llinventorygallery.cpp
# indra/newview/lllistbrowser.cpp
# indra/newview/lllistbrowser.h
# indra/newview/llpanelobjectinventory.cpp
# indra/newview/llpanelprofile.cpp
# indra/newview/llpanelprofile.h
# indra/newview/llpreviewgesture.cpp
# indra/newview/llsavedsettingsglue.cpp
# indra/newview/llsavedsettingsglue.h
# indra/newview/lltooldraganddrop.cpp
# indra/newview/llurllineeditorctrl.cpp
# indra/newview/llvectorperfoptions.cpp
# indra/newview/llvectorperfoptions.h
# indra/newview/llviewerparceloverlay.cpp
# indra/newview/llviewertexlayer.cpp
# indra/newview/llviewertexturelist.cpp
# indra/newview/macmain.h
# indra/test/test.cpp
Diffstat (limited to 'indra/newview/llvotree.cpp')
| -rw-r--r-- | indra/newview/llvotree.cpp | 2474 |
1 files changed, 1237 insertions, 1237 deletions
diff --git a/indra/newview/llvotree.cpp b/indra/newview/llvotree.cpp index caee731ea3..4822b0b7ee 100644 --- a/indra/newview/llvotree.cpp +++ b/indra/newview/llvotree.cpp @@ -1,1237 +1,1237 @@ -/** - * @file llvotree.cpp - * @brief LLVOTree class implementation - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/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 "llagentcamera.h" -#include "lldrawable.h" -#include "llface.h" -#include "llviewercamera.h" -#include "llviewertexturelist.h" -#include "llviewerobjectlist.h" -#include "llviewerregion.h" -#include "llvolumemgr.h" -#include "llvovolume.h" -#include "llworld.h" -#include "noise.h" -#include "pipeline.h" -#include "llspatialpartition.h" -#include "llnotificationsutil.h" -#include "raytrace.h" -#include "llglslshader.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; - -const S32 LLVOTree::sMAX_NUM_TREE_LOD_LEVELS = 4 ; - -S32 LLVOTree::sLODVertexOffset[sMAX_NUM_TREE_LOD_LEVELS]; -S32 LLVOTree::sLODVertexCount[sMAX_NUM_TREE_LOD_LEVELS]; -S32 LLVOTree::sLODIndexOffset[sMAX_NUM_TREE_LOD_LEVELS]; -S32 LLVOTree::sLODIndexCount[sMAX_NUM_TREE_LOD_LEVELS]; -S32 LLVOTree::sLODSlices[sMAX_NUM_TREE_LOD_LEVELS] = {10, 5, 4, 3}; -F32 LLVOTree::sLODAngles[sMAX_NUM_TREE_LOD_LEVELS] = {30.f, 20.f, 15.f, F_ALMOST_ZERO}; - -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; - - // if assert triggers, idleUpdate() needs to be revised and adjusted to new LOD levels - llassert(sMAX_NUM_TREE_LOD_LEVELS == LLVolumeLODGroup::NUM_LODS); -} - - -LLVOTree::~LLVOTree() -{ - if (mData) - { - delete[] mData; - mData = NULL; - } -} - -//static -bool LLVOTree::isTreeRenderingStopped() -{ - return LLVOTree::sTreeFactor < LLVOTree::sLODAngles[sMAX_NUM_TREE_LOD_LEVELS - 1] ; -} - -// 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)) - { - LL_ERRS() << "Failed to parse tree file." << LL_ENDL; - } - - LLXmlTreeNode* rootp = tree_def_tree.getRoot(); - - for (LLXmlTreeNode* tree_def = rootp->getFirstChild(); - tree_def; - tree_def = rootp->getNextChild()) - { - if (!tree_def->hasName("tree")) - { - LL_WARNS() << "Invalid tree definition node " << tree_def->getName() << LL_ENDL; - 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)) - { - LL_WARNS() << "No species id defined" << LL_ENDL; - continue; - } - - if (species < 0) - { - LL_WARNS() << "Invalid species id " << species << LL_ENDL; - continue; - } - - if (sSpeciesTable.count(species)) - { - LL_WARNS() << "Tree species " << species << " already defined! Duplicate discarded." << LL_ENDL; - 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); - LL_WARNS() << "Incomplete definition of tree " << name << LL_ENDL; - } - } - - 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()); - sSpeciesTable.clear(); -} - -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)) - { - LL_INFOS() << "ACK! Moving tree!" << LL_ENDL; - 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 - // - static const S32 MAX_TREE_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL = 32 ; //frames. - mTreeImagep = LLViewerTextureManager::getFetchedTexture(sSpeciesTable[mSpecies]->mTextureID, FTT_DEFAULT, true, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); - mTreeImagep->setMaxVirtualSizeResetInterval(MAX_TREE_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL); //allow to wait for at most 16 frames to reset virtual size. - - 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; -} - -void LLVOTree::idleUpdate(LLAgent &agent, const F64 &time) -{ - if (mDead || !(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_TREE))) - { - return; - } - - S32 trunk_LOD = sMAX_NUM_TREE_LOD_LEVELS ; // disabled - F32 app_angle = getAppAngle()*LLVOTree::sTreeFactor; - F32 distance = mDrawable->mDistanceWRTCamera * LLVOVolume::sDistanceFactor * (F_PI / 3.f); - F32 diameter = getScale().length(); // trees have very broken scale, but length rougtly outlines proper diameter - F32 sz = mBillboardScale * mBillboardRatio * diameter; - - for (S32 j = 0; j < sMAX_NUM_TREE_LOD_LEVELS; j++) - { - if (app_angle > LLVOTree::sLODAngles[j]) - { - trunk_LOD = j; - break; - } - } - - F32 tan_angle = (LLVOTree::sTreeFactor * 64 * sz) / distance; - S32 cur_detail = LLVolumeLODGroup::getDetailFromTan(ll_round(tan_angle, 0.01f)); // larger value, better quality - - // for trunk_LOD lower value means better quality, but both trunk_LOD and cur_detail have 4 levels - trunk_LOD = llmax(trunk_LOD, LLVolumeLODGroup::NUM_LODS - cur_detail - 1); - trunk_LOD = llmin(trunk_LOD, sMAX_NUM_TREE_LOD_LEVELS); - - if (mReferenceBuffer.isNull()) - { - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL); - } - else if (trunk_LOD != mTrunkLOD) - { - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL); - } - 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 = getPositionRegion(); - 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; -} - -void LLVOTree::render(LLAgent &agent) -{ -} - - -void LLVOTree::setPixelAreaAndAngle(LLAgent &agent) -{ - LLVector3 center = getPositionAgent();//center of tree. - LLVector3 viewer_pos_agent = gAgentCamera.getCameraPositionAgent(); - LLVector3 lookAt = center - viewer_pos_agent; - F32 dist = lookAt.normVec() ; - F32 cos_angle_to_view_dir = lookAt * LLViewerCamera::getInstance()->getXAxis() ; - F32 radius = getScale().length()*0.5f; - F32 range = dist - radius; - - if (range < F_ALMOST_ZERO || isHUDAttachment()) // range == zero - { - 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 -} - -void LLVOTree::updateTextures() -{ - if (mTreeImagep) - { - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA)) - { - setDebugText(llformat("%4.0f", (F32) sqrt(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; - -bool LLVOTree::updateGeometry(LLDrawable *drawable) -{ - LL_PROFILE_ZONE_SCOPED; - - if(mTrunkLOD >= sMAX_NUM_TREE_LOD_LEVELS) //do not display the tree. - { - mReferenceBuffer = NULL ; - LLFace * facep = drawable->getFace(0); - if (facep) - { - facep->setVertexBuffer(NULL); - } - return true ; - } - - if (mDrawable->getFace(0) && - (mReferenceBuffer.isNull() || !mDrawable->getFace(0)->getVertexBuffer())) - { - 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); - if (!face) return true; - - face->mCenterAgent = getPositionAgent(); - face->mCenterLocal = face->mCenterAgent; - - for (lod = 0; lod < sMAX_NUM_TREE_LOD_LEVELS; 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); - if (!mReferenceBuffer->allocateBuffer(max_vertices, max_indices)) - { - LL_WARNS() << "Failed to allocate Vertex Buffer on update to " - << max_vertices << " vertices and " - << max_indices << " indices" << LL_ENDL; - mReferenceBuffer = NULL; //unref - return true; - } - - LLStrider<LLVector3> vertices; - LLStrider<LLVector3> normals; - LLStrider<LLColor4U> colors; - LLStrider<LLVector2> tex_coords; - LLStrider<U16> indicesp; - - mReferenceBuffer->getVertexStrider(vertices); - mReferenceBuffer->getNormalStrider(normals); - mReferenceBuffer->getTexCoord0Strider(tex_coords); - mReferenceBuffer->getColorStrider(colors); - 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); - *(colors++) = LLColor4U::white; - vertex_count++; - - *(normals++) = LLVector3(SRR3, -SRR3, SRR3); - *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_TOP); - *(vertices++) = LLVector3(0.5f*LEAF_WIDTH, 0.f, 1.f); - *(colors++) = LLColor4U::white; - vertex_count++; - - *(normals++) = LLVector3(-SRR3, -SRR3, SRR3); - *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_TOP); - *(vertices++) = LLVector3(-0.5f*LEAF_WIDTH, 0.f, 1.f); - *(colors++) = LLColor4U::white; - 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); - *(colors++) = LLColor4U::white; - 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); - *(colors++) = LLColor4U::white; - vertex_count++; - - *(normals++) = LLVector3(SRR3, SRR3, SRR3); - *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_TOP); - *(vertices++) = LLVector3(0.5f*LEAF_WIDTH, 0.f, 1.f); - *(colors++) = LLColor4U::white; - vertex_count++; - - *(normals++) = LLVector3(-SRR3, SRR3, SRR3); - *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_TOP); - *(vertices++) = LLVector3(-0.5f*LEAF_WIDTH, 0.f, 1.f); - *(colors++) = LLColor4U::white; - 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); - *(colors++) = LLColor4U::white; - 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); - *(colors++) = LLColor4U::white; - vertex_count++; - - *(normals++) = LLVector3(SRR3, SRR3, SRR3); - *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_TOP); - *(vertices++) = LLVector3(0.f, 0.5f*LEAF_WIDTH, 1.f); - *(colors++) = LLColor4U::white; - vertex_count++; - - *(normals++) = LLVector3(SRR3, -SRR3, SRR3); - *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_TOP); - *(vertices++) = LLVector3(0.f, -0.5f*LEAF_WIDTH, 1.f); - *(colors++) = LLColor4U::white; - 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); - *(colors++) = LLColor4U::white; - 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); - *(colors++) = LLColor4U::white; - vertex_count++; - - *(normals++) = LLVector3(-SRR3, SRR3, SRR3); - *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_TOP); - *(vertices++) = LLVector3(0.f, 0.5f*LEAF_WIDTH, 1.f); - *(colors++) = LLColor4U::white; - vertex_count++; - - *(normals++) = LLVector3(-SRR3, -SRR3, SRR3); - *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_TOP); - *(vertices++) = LLVector3(0.f, -0.5f*LEAF_WIDTH, 1.f); - *(colors++) = LLColor4U::white; - 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); - *(colors++) = LLColor4U::white; - 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 < sMAX_NUM_TREE_LOD_LEVELS; lod++) - { - slices = sLODSlices[lod]; - F32 base_radius = 0.65f; - F32 top_radius = base_radius * sSpeciesTable[mSpecies]->mTaper; - //LL_INFOS() << "Species " << ((U32) mSpecies) << ", taper = " << sSpeciesTable[mSpecies].mTaper << LL_ENDL; - //LL_INFOS() << "Droop " << mDroop << ", branchlength: " << mBranchLength << LL_ENDL; - 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; - *(colors++) = LLColor4U::white; - 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->unmapBuffer(); - llassert(vertex_count == max_vertices); - llassert(index_count == max_indices); -#ifndef SHOW_ASSERT - (void)vertex_count; - (void)index_count; -#endif - } - - //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_region = getPositionRegion(); - //gGL.translatef(pos_agent.mV[VX], pos_agent.mV[VY], pos_agent.mV[VZ] - 0.1f); - LLMatrix4 trans_mat; - trans_mat.setTranslation(pos_region.mV[VX], pos_region.mV[VY], pos_region.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); - if (!facep) return; - LLVertexBuffer* buff = new LLVertexBuffer(LLDrawPoolTree::VERTEX_DATA_MASK); - if (!buff->allocateBuffer(vert_count, index_count)) - { - LL_WARNS() << "Failed to allocate Vertex Buffer on mesh update to " - << vert_count << " vertices and " - << index_count << " indices" << LL_ENDL; - buff->allocateBuffer(1, 3); - memset((U8*)buff->getMappedData(), 0, buff->getSize()); - memset((U8*)buff->getMappedIndices(), 0, buff->getIndicesSize()); - facep->setSize(1, 3); - facep->setVertexBuffer(buff); - mReferenceBuffer->unmapBuffer(); - buff->unmapBuffer(); - return; - } - - facep->setVertexBuffer(buff); - - LLStrider<LLVector3> vertices; - LLStrider<LLVector3> normals; - LLStrider<LLVector2> tex_coords; - LLStrider<LLColor4U> colors; - LLStrider<U16> indices; - U16 idx_offset = 0; - - buff->getVertexStrider(vertices); - buff->getNormalStrider(normals); - buff->getTexCoord0Strider(tex_coords); - buff->getColorStrider(colors); - buff->getIndexStrider(indices); - - genBranchPipeline(vertices, normals, tex_coords, colors, indices, idx_offset, scale_mat, mTrunkLOD, stop_depth, mDepth, mTrunkDepth, 1.0, mTwist, droop, mBranches, alpha); - - mReferenceBuffer->unmapBuffer(); - buff->unmapBuffer(); -} - -void LLVOTree::appendMesh(LLStrider<LLVector3>& vertices, - LLStrider<LLVector3>& normals, - LLStrider<LLVector2>& tex_coords, - LLStrider<LLColor4U>& colors, - 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<LLColor4U> c; - LLStrider<U16> idx; - - mReferenceBuffer->getVertexStrider(v); - mReferenceBuffer->getNormalStrider(n); - mReferenceBuffer->getTexCoord0Strider(t); - mReferenceBuffer->getColorStrider(c); - 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]; - *colors++ = c[index]; - } - - //copy offset indices into mesh - check - for (S32 i = 0; i < index_count; i++) - { - U16 index = index_offset + i; - *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<LLColor4U>& colors, - 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, colors, 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, colors, 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, colors, 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, colors, 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; - } -} - -void LLVOTree::updateRadius() -{ - if (mDrawable.isNull()) - { - return; - } - - mDrawable->setRadius(32.0f); -} - -void LLVOTree::updateSpatialExtents(LLVector4a& newMin, LLVector4a& 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.load3((center-size).mV); - newMax.load3((center+size).mV); - LLVector4a pos; - pos.load3(center.mV); - mDrawable->setPositionGroup(pos); -} - -bool LLVOTree::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, S32 face, bool pick_transparent, bool pick_rigged, bool pick_unselectable, S32 *face_hitp, - LLVector4a* intersection,LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent) - -{ - - if (!lineSegmentBoundingBox(start, end)) - { - return false; - } - - const LLVector4a* exta = mDrawable->getSpatialExtents(); - - //VECTORIZE THIS - LLVector3 ext[2]; - ext[0].set(exta[0].getF32ptr()); - ext[1].set(exta[1].getF32ptr()); - - 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; - - LLVector3 start3(start.getF32ptr()); - LLVector3 end3(end.getF32ptr()); - - if (linesegment_tetrahedron(start3, end3, center, size, quat, pos, norm)) - { - if (intersection) - { - intersection->load3(pos.mV); - } - - if (normal) - { - normal->load3(norm.mV); - } - return true; - } - - return false; -} - -U32 LLVOTree::getPartitionType() const -{ - return LLViewerRegion::PARTITION_TREE; -} - -LLTreePartition::LLTreePartition(LLViewerRegion* regionp) -: LLSpatialPartition(0, false, regionp) -{ - mDrawableType = LLPipeline::RENDER_TYPE_TREE; - mPartitionType = LLViewerRegion::PARTITION_TREE; - mSlopRatio = 0.f; - mLODPeriod = 1; -} - +/**
+ * @file llvotree.cpp
+ * @brief LLVOTree class implementation
+ *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/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 "llagentcamera.h"
+#include "lldrawable.h"
+#include "llface.h"
+#include "llviewercamera.h"
+#include "llviewertexturelist.h"
+#include "llviewerobjectlist.h"
+#include "llviewerregion.h"
+#include "llvolumemgr.h"
+#include "llvovolume.h"
+#include "llworld.h"
+#include "noise.h"
+#include "pipeline.h"
+#include "llspatialpartition.h"
+#include "llnotificationsutil.h"
+#include "raytrace.h"
+#include "llglslshader.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;
+
+const S32 LLVOTree::sMAX_NUM_TREE_LOD_LEVELS = 4 ;
+
+S32 LLVOTree::sLODVertexOffset[sMAX_NUM_TREE_LOD_LEVELS];
+S32 LLVOTree::sLODVertexCount[sMAX_NUM_TREE_LOD_LEVELS];
+S32 LLVOTree::sLODIndexOffset[sMAX_NUM_TREE_LOD_LEVELS];
+S32 LLVOTree::sLODIndexCount[sMAX_NUM_TREE_LOD_LEVELS];
+S32 LLVOTree::sLODSlices[sMAX_NUM_TREE_LOD_LEVELS] = {10, 5, 4, 3};
+F32 LLVOTree::sLODAngles[sMAX_NUM_TREE_LOD_LEVELS] = {30.f, 20.f, 15.f, F_ALMOST_ZERO};
+
+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;
+
+ // if assert triggers, idleUpdate() needs to be revised and adjusted to new LOD levels
+ llassert(sMAX_NUM_TREE_LOD_LEVELS == LLVolumeLODGroup::NUM_LODS);
+}
+
+
+LLVOTree::~LLVOTree()
+{
+ if (mData)
+ {
+ delete[] mData;
+ mData = NULL;
+ }
+}
+
+//static
+bool LLVOTree::isTreeRenderingStopped()
+{
+ return LLVOTree::sTreeFactor < LLVOTree::sLODAngles[sMAX_NUM_TREE_LOD_LEVELS - 1] ;
+}
+
+// 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))
+ {
+ LL_ERRS() << "Failed to parse tree file." << LL_ENDL;
+ }
+
+ LLXmlTreeNode* rootp = tree_def_tree.getRoot();
+
+ for (LLXmlTreeNode* tree_def = rootp->getFirstChild();
+ tree_def;
+ tree_def = rootp->getNextChild())
+ {
+ if (!tree_def->hasName("tree"))
+ {
+ LL_WARNS() << "Invalid tree definition node " << tree_def->getName() << LL_ENDL;
+ 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))
+ {
+ LL_WARNS() << "No species id defined" << LL_ENDL;
+ continue;
+ }
+
+ if (species < 0)
+ {
+ LL_WARNS() << "Invalid species id " << species << LL_ENDL;
+ continue;
+ }
+
+ if (sSpeciesTable.count(species))
+ {
+ LL_WARNS() << "Tree species " << species << " already defined! Duplicate discarded." << LL_ENDL;
+ 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);
+ LL_WARNS() << "Incomplete definition of tree " << name << LL_ENDL;
+ }
+ }
+
+ 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());
+ sSpeciesTable.clear();
+}
+
+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))
+ {
+ LL_INFOS() << "ACK! Moving tree!" << LL_ENDL;
+ 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
+ //
+ static const S32 MAX_TREE_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL = 32 ; //frames.
+ mTreeImagep = LLViewerTextureManager::getFetchedTexture(sSpeciesTable[mSpecies]->mTextureID, FTT_DEFAULT, true, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
+ mTreeImagep->setMaxVirtualSizeResetInterval(MAX_TREE_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL); //allow to wait for at most 16 frames to reset virtual size.
+
+ 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;
+}
+
+void LLVOTree::idleUpdate(LLAgent &agent, const F64 &time)
+{
+ if (mDead || !(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_TREE)))
+ {
+ return;
+ }
+
+ S32 trunk_LOD = sMAX_NUM_TREE_LOD_LEVELS ; // disabled
+ F32 app_angle = getAppAngle()*LLVOTree::sTreeFactor;
+ F32 distance = mDrawable->mDistanceWRTCamera * LLVOVolume::sDistanceFactor * (F_PI / 3.f);
+ F32 diameter = getScale().length(); // trees have very broken scale, but length rougtly outlines proper diameter
+ F32 sz = mBillboardScale * mBillboardRatio * diameter;
+
+ for (S32 j = 0; j < sMAX_NUM_TREE_LOD_LEVELS; j++)
+ {
+ if (app_angle > LLVOTree::sLODAngles[j])
+ {
+ trunk_LOD = j;
+ break;
+ }
+ }
+
+ F32 tan_angle = (LLVOTree::sTreeFactor * 64 * sz) / distance;
+ S32 cur_detail = LLVolumeLODGroup::getDetailFromTan(ll_round(tan_angle, 0.01f)); // larger value, better quality
+
+ // for trunk_LOD lower value means better quality, but both trunk_LOD and cur_detail have 4 levels
+ trunk_LOD = llmax(trunk_LOD, LLVolumeLODGroup::NUM_LODS - cur_detail - 1);
+ trunk_LOD = llmin(trunk_LOD, sMAX_NUM_TREE_LOD_LEVELS);
+
+ if (mReferenceBuffer.isNull())
+ {
+ gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL);
+ }
+ else if (trunk_LOD != mTrunkLOD)
+ {
+ gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL);
+ }
+ 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 = getPositionRegion();
+ 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;
+}
+
+void LLVOTree::render(LLAgent &agent)
+{
+}
+
+
+void LLVOTree::setPixelAreaAndAngle(LLAgent &agent)
+{
+ LLVector3 center = getPositionAgent();//center of tree.
+ LLVector3 viewer_pos_agent = gAgentCamera.getCameraPositionAgent();
+ LLVector3 lookAt = center - viewer_pos_agent;
+ F32 dist = lookAt.normVec() ;
+ F32 cos_angle_to_view_dir = lookAt * LLViewerCamera::getInstance()->getXAxis() ;
+ F32 radius = getScale().length()*0.5f;
+ F32 range = dist - radius;
+
+ if (range < F_ALMOST_ZERO || isHUDAttachment()) // range == zero
+ {
+ 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
+}
+
+void LLVOTree::updateTextures()
+{
+ if (mTreeImagep)
+ {
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA))
+ {
+ setDebugText(llformat("%4.0f", (F32) sqrt(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;
+
+bool LLVOTree::updateGeometry(LLDrawable *drawable)
+{
+ LL_PROFILE_ZONE_SCOPED;
+
+ if(mTrunkLOD >= sMAX_NUM_TREE_LOD_LEVELS) //do not display the tree.
+ {
+ mReferenceBuffer = NULL ;
+ LLFace * facep = drawable->getFace(0);
+ if (facep)
+ {
+ facep->setVertexBuffer(NULL);
+ }
+ return true ;
+ }
+
+ if (mDrawable->getFace(0) &&
+ (mReferenceBuffer.isNull() || !mDrawable->getFace(0)->getVertexBuffer()))
+ {
+ 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);
+ if (!face) return true;
+
+ face->mCenterAgent = getPositionAgent();
+ face->mCenterLocal = face->mCenterAgent;
+
+ for (lod = 0; lod < sMAX_NUM_TREE_LOD_LEVELS; 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);
+ if (!mReferenceBuffer->allocateBuffer(max_vertices, max_indices))
+ {
+ LL_WARNS() << "Failed to allocate Vertex Buffer on update to "
+ << max_vertices << " vertices and "
+ << max_indices << " indices" << LL_ENDL;
+ mReferenceBuffer = NULL; //unref
+ return true;
+ }
+
+ LLStrider<LLVector3> vertices;
+ LLStrider<LLVector3> normals;
+ LLStrider<LLColor4U> colors;
+ LLStrider<LLVector2> tex_coords;
+ LLStrider<U16> indicesp;
+
+ mReferenceBuffer->getVertexStrider(vertices);
+ mReferenceBuffer->getNormalStrider(normals);
+ mReferenceBuffer->getTexCoord0Strider(tex_coords);
+ mReferenceBuffer->getColorStrider(colors);
+ 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);
+ *(colors++) = LLColor4U::white;
+ vertex_count++;
+
+ *(normals++) = LLVector3(SRR3, -SRR3, SRR3);
+ *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_TOP);
+ *(vertices++) = LLVector3(0.5f*LEAF_WIDTH, 0.f, 1.f);
+ *(colors++) = LLColor4U::white;
+ vertex_count++;
+
+ *(normals++) = LLVector3(-SRR3, -SRR3, SRR3);
+ *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_TOP);
+ *(vertices++) = LLVector3(-0.5f*LEAF_WIDTH, 0.f, 1.f);
+ *(colors++) = LLColor4U::white;
+ 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);
+ *(colors++) = LLColor4U::white;
+ 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);
+ *(colors++) = LLColor4U::white;
+ vertex_count++;
+
+ *(normals++) = LLVector3(SRR3, SRR3, SRR3);
+ *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_TOP);
+ *(vertices++) = LLVector3(0.5f*LEAF_WIDTH, 0.f, 1.f);
+ *(colors++) = LLColor4U::white;
+ vertex_count++;
+
+ *(normals++) = LLVector3(-SRR3, SRR3, SRR3);
+ *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_TOP);
+ *(vertices++) = LLVector3(-0.5f*LEAF_WIDTH, 0.f, 1.f);
+ *(colors++) = LLColor4U::white;
+ 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);
+ *(colors++) = LLColor4U::white;
+ 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);
+ *(colors++) = LLColor4U::white;
+ vertex_count++;
+
+ *(normals++) = LLVector3(SRR3, SRR3, SRR3);
+ *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_TOP);
+ *(vertices++) = LLVector3(0.f, 0.5f*LEAF_WIDTH, 1.f);
+ *(colors++) = LLColor4U::white;
+ vertex_count++;
+
+ *(normals++) = LLVector3(SRR3, -SRR3, SRR3);
+ *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_TOP);
+ *(vertices++) = LLVector3(0.f, -0.5f*LEAF_WIDTH, 1.f);
+ *(colors++) = LLColor4U::white;
+ 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);
+ *(colors++) = LLColor4U::white;
+ 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);
+ *(colors++) = LLColor4U::white;
+ vertex_count++;
+
+ *(normals++) = LLVector3(-SRR3, SRR3, SRR3);
+ *(tex_coords++) = LLVector2(LEAF_RIGHT, LEAF_TOP);
+ *(vertices++) = LLVector3(0.f, 0.5f*LEAF_WIDTH, 1.f);
+ *(colors++) = LLColor4U::white;
+ vertex_count++;
+
+ *(normals++) = LLVector3(-SRR3, -SRR3, SRR3);
+ *(tex_coords++) = LLVector2(LEAF_LEFT, LEAF_TOP);
+ *(vertices++) = LLVector3(0.f, -0.5f*LEAF_WIDTH, 1.f);
+ *(colors++) = LLColor4U::white;
+ 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);
+ *(colors++) = LLColor4U::white;
+ 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 < sMAX_NUM_TREE_LOD_LEVELS; lod++)
+ {
+ slices = sLODSlices[lod];
+ F32 base_radius = 0.65f;
+ F32 top_radius = base_radius * sSpeciesTable[mSpecies]->mTaper;
+ //LL_INFOS() << "Species " << ((U32) mSpecies) << ", taper = " << sSpeciesTable[mSpecies].mTaper << LL_ENDL;
+ //LL_INFOS() << "Droop " << mDroop << ", branchlength: " << mBranchLength << LL_ENDL;
+ 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;
+ *(colors++) = LLColor4U::white;
+ 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->unmapBuffer();
+ llassert(vertex_count == max_vertices);
+ llassert(index_count == max_indices);
+#ifndef SHOW_ASSERT
+ (void)vertex_count;
+ (void)index_count;
+#endif
+ }
+
+ //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_region = getPositionRegion();
+ //gGL.translatef(pos_agent.mV[VX], pos_agent.mV[VY], pos_agent.mV[VZ] - 0.1f);
+ LLMatrix4 trans_mat;
+ trans_mat.setTranslation(pos_region.mV[VX], pos_region.mV[VY], pos_region.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);
+ if (!facep) return;
+ LLVertexBuffer* buff = new LLVertexBuffer(LLDrawPoolTree::VERTEX_DATA_MASK);
+ if (!buff->allocateBuffer(vert_count, index_count))
+ {
+ LL_WARNS() << "Failed to allocate Vertex Buffer on mesh update to "
+ << vert_count << " vertices and "
+ << index_count << " indices" << LL_ENDL;
+ buff->allocateBuffer(1, 3);
+ memset((U8*)buff->getMappedData(), 0, buff->getSize());
+ memset((U8*)buff->getMappedIndices(), 0, buff->getIndicesSize());
+ facep->setSize(1, 3);
+ facep->setVertexBuffer(buff);
+ mReferenceBuffer->unmapBuffer();
+ buff->unmapBuffer();
+ return;
+ }
+
+ facep->setVertexBuffer(buff);
+
+ LLStrider<LLVector3> vertices;
+ LLStrider<LLVector3> normals;
+ LLStrider<LLVector2> tex_coords;
+ LLStrider<LLColor4U> colors;
+ LLStrider<U16> indices;
+ U16 idx_offset = 0;
+
+ buff->getVertexStrider(vertices);
+ buff->getNormalStrider(normals);
+ buff->getTexCoord0Strider(tex_coords);
+ buff->getColorStrider(colors);
+ buff->getIndexStrider(indices);
+
+ genBranchPipeline(vertices, normals, tex_coords, colors, indices, idx_offset, scale_mat, mTrunkLOD, stop_depth, mDepth, mTrunkDepth, 1.0, mTwist, droop, mBranches, alpha);
+
+ mReferenceBuffer->unmapBuffer();
+ buff->unmapBuffer();
+}
+
+void LLVOTree::appendMesh(LLStrider<LLVector3>& vertices,
+ LLStrider<LLVector3>& normals,
+ LLStrider<LLVector2>& tex_coords,
+ LLStrider<LLColor4U>& colors,
+ 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<LLColor4U> c;
+ LLStrider<U16> idx;
+
+ mReferenceBuffer->getVertexStrider(v);
+ mReferenceBuffer->getNormalStrider(n);
+ mReferenceBuffer->getTexCoord0Strider(t);
+ mReferenceBuffer->getColorStrider(c);
+ 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];
+ *colors++ = c[index];
+ }
+
+ //copy offset indices into mesh - check
+ for (S32 i = 0; i < index_count; i++)
+ {
+ U16 index = index_offset + i;
+ *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<LLColor4U>& colors,
+ 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, colors, 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, colors, 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, colors, 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, colors, 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;
+ }
+}
+
+void LLVOTree::updateRadius()
+{
+ if (mDrawable.isNull())
+ {
+ return;
+ }
+
+ mDrawable->setRadius(32.0f);
+}
+
+void LLVOTree::updateSpatialExtents(LLVector4a& newMin, LLVector4a& 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.load3((center-size).mV);
+ newMax.load3((center+size).mV);
+ LLVector4a pos;
+ pos.load3(center.mV);
+ mDrawable->setPositionGroup(pos);
+}
+
+bool LLVOTree::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, S32 face, bool pick_transparent, bool pick_rigged, bool pick_unselectable, S32 *face_hitp,
+ LLVector4a* intersection,LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent)
+
+{
+
+ if (!lineSegmentBoundingBox(start, end))
+ {
+ return false;
+ }
+
+ const LLVector4a* exta = mDrawable->getSpatialExtents();
+
+ //VECTORIZE THIS
+ LLVector3 ext[2];
+ ext[0].set(exta[0].getF32ptr());
+ ext[1].set(exta[1].getF32ptr());
+
+ 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;
+
+ LLVector3 start3(start.getF32ptr());
+ LLVector3 end3(end.getF32ptr());
+
+ if (linesegment_tetrahedron(start3, end3, center, size, quat, pos, norm))
+ {
+ if (intersection)
+ {
+ intersection->load3(pos.mV);
+ }
+
+ if (normal)
+ {
+ normal->load3(norm.mV);
+ }
+ return true;
+ }
+
+ return false;
+}
+
+U32 LLVOTree::getPartitionType() const
+{
+ return LLViewerRegion::PARTITION_TREE;
+}
+
+LLTreePartition::LLTreePartition(LLViewerRegion* regionp)
+: LLSpatialPartition(0, false, regionp)
+{
+ mDrawableType = LLPipeline::RENDER_TYPE_TREE;
+ mPartitionType = LLViewerRegion::PARTITION_TREE;
+ mSlopRatio = 0.f;
+ mLODPeriod = 1;
+}
+
|
