PageRenderTime 1380ms CodeModel.GetById 171ms app.highlight 923ms RepoModel.GetById 165ms app.codeStats 1ms

/indra/newview/llvotree.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1296 lines | 959 code | 234 blank | 103 comment | 87 complexity | eaace767def6319f7ec9aa09e3a32f90 MD5 | raw file
   1/** 
   2 * @file llvotree.cpp
   3 * @brief LLVOTree class implementation
   4 *
   5 * $LicenseInfo:firstyear=2002&license=viewerlgpl$
   6 * Second Life Viewer Source Code
   7 * Copyright (C) 2010, Linden Research, Inc.
   8 * 
   9 * This library is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU Lesser General Public
  11 * License as published by the Free Software Foundation;
  12 * version 2.1 of the License only.
  13 * 
  14 * This library is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * Lesser General Public License for more details.
  18 * 
  19 * You should have received a copy of the GNU Lesser General Public
  20 * License along with this library; if not, write to the Free Software
  21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  22 * 
  23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  24 * $/LicenseInfo$
  25 */
  26
  27#include "llviewerprecompiledheaders.h"
  28
  29#include "llvotree.h"
  30
  31#include "lldrawpooltree.h"
  32
  33#include "llviewercontrol.h"
  34#include "lldir.h"
  35#include "llprimitive.h"
  36#include "lltree_common.h"
  37#include "llxmltree.h"
  38#include "material_codes.h"
  39#include "object_flags.h"
  40
  41#include "llagentcamera.h"
  42#include "lldrawable.h"
  43#include "llface.h"
  44#include "llviewercamera.h"
  45#include "llviewertexturelist.h"
  46#include "llviewerobjectlist.h"
  47#include "llviewerregion.h"
  48#include "llworld.h"
  49#include "noise.h"
  50#include "pipeline.h"
  51#include "llspatialpartition.h"
  52#include "llnotificationsutil.h"
  53#include "raytrace.h"
  54#include "llglslshader.h"
  55
  56extern LLPipeline gPipeline;
  57
  58const S32 MAX_SLICES = 32;
  59const F32 LEAF_LEFT = 0.52f;
  60const F32 LEAF_RIGHT = 0.98f;
  61const F32 LEAF_TOP = 1.0f;
  62const F32 LEAF_BOTTOM = 0.52f;
  63const F32 LEAF_WIDTH = 1.f;
  64
  65const S32 LLVOTree::sMAX_NUM_TREE_LOD_LEVELS = 4 ;
  66
  67S32 LLVOTree::sLODVertexOffset[sMAX_NUM_TREE_LOD_LEVELS];
  68S32 LLVOTree::sLODVertexCount[sMAX_NUM_TREE_LOD_LEVELS];
  69S32 LLVOTree::sLODIndexOffset[sMAX_NUM_TREE_LOD_LEVELS];
  70S32 LLVOTree::sLODIndexCount[sMAX_NUM_TREE_LOD_LEVELS];
  71S32 LLVOTree::sLODSlices[sMAX_NUM_TREE_LOD_LEVELS] = {10, 5, 4, 3};
  72F32 LLVOTree::sLODAngles[sMAX_NUM_TREE_LOD_LEVELS] = {30.f, 20.f, 15.f, F_ALMOST_ZERO};
  73
  74F32 LLVOTree::sTreeFactor = 1.f;
  75
  76LLVOTree::SpeciesMap LLVOTree::sSpeciesTable;
  77S32 LLVOTree::sMaxTreeSpecies = 0;
  78
  79// Tree variables and functions
  80
  81LLVOTree::LLVOTree(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp):
  82						LLViewerObject(id, pcode, regionp)
  83{
  84	mSpecies = 0;
  85	mFrameCount = 0;
  86	mWind = mRegionp->mWind.getVelocity(getPositionRegion());
  87	mTrunkLOD = 0;
  88}
  89
  90
  91LLVOTree::~LLVOTree()
  92{
  93	if (mData)
  94	{
  95		delete[] mData;
  96		mData = NULL;
  97	}
  98}
  99
 100//static
 101bool LLVOTree::isTreeRenderingStopped()
 102{
 103	return LLVOTree::sTreeFactor < LLVOTree::sLODAngles[sMAX_NUM_TREE_LOD_LEVELS - 1] ;
 104}
 105
 106// static
 107void LLVOTree::initClass()
 108{
 109	std::string xml_filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"trees.xml");
 110	
 111	LLXmlTree tree_def_tree;
 112
 113	if (!tree_def_tree.parseFile(xml_filename))
 114	{
 115		llerrs << "Failed to parse tree file." << llendl;
 116	}
 117
 118	LLXmlTreeNode* rootp = tree_def_tree.getRoot();
 119
 120	for (LLXmlTreeNode* tree_def = rootp->getFirstChild();
 121		tree_def;
 122		tree_def = rootp->getNextChild())
 123		{
 124			if (!tree_def->hasName("tree"))
 125			{
 126				llwarns << "Invalid tree definition node " << tree_def->getName() << llendl;
 127				continue;
 128			}
 129			F32 F32_val;
 130			LLUUID id;
 131			S32 S32_val;
 132
 133			BOOL success = TRUE;
 134
 135
 136
 137			S32 species;
 138			static LLStdStringHandle species_id_string = LLXmlTree::addAttributeString("species_id");
 139			if (!tree_def->getFastAttributeS32(species_id_string, species))
 140			{
 141				llwarns << "No species id defined" << llendl;
 142				continue;
 143			}
 144
 145			if (species < 0)
 146			{
 147				llwarns << "Invalid species id " << species << llendl;
 148				continue;
 149			}
 150
 151			if (sSpeciesTable.count(species))
 152			{
 153				llwarns << "Tree species " << species << " already defined! Duplicate discarded." << llendl;
 154				continue;
 155			}
 156
 157			TreeSpeciesData* newTree = new TreeSpeciesData();
 158
 159			static LLStdStringHandle texture_id_string = LLXmlTree::addAttributeString("texture_id");
 160			success &= tree_def->getFastAttributeUUID(texture_id_string, id);
 161			newTree->mTextureID = id;
 162			
 163			static LLStdStringHandle droop_string = LLXmlTree::addAttributeString("droop");
 164			success &= tree_def->getFastAttributeF32(droop_string, F32_val);
 165			newTree->mDroop = F32_val;
 166
 167			static LLStdStringHandle twist_string = LLXmlTree::addAttributeString("twist");
 168			success &= tree_def->getFastAttributeF32(twist_string, F32_val);
 169			newTree->mTwist = F32_val;
 170			
 171			static LLStdStringHandle branches_string = LLXmlTree::addAttributeString("branches");
 172			success &= tree_def->getFastAttributeF32(branches_string, F32_val);
 173			newTree->mBranches = F32_val;
 174
 175			static LLStdStringHandle depth_string = LLXmlTree::addAttributeString("depth");
 176			success &= tree_def->getFastAttributeS32(depth_string, S32_val);
 177			newTree->mDepth = S32_val;
 178
 179			static LLStdStringHandle scale_step_string = LLXmlTree::addAttributeString("scale_step");
 180			success &= tree_def->getFastAttributeF32(scale_step_string, F32_val);
 181			newTree->mScaleStep = F32_val;
 182			
 183			static LLStdStringHandle trunk_depth_string = LLXmlTree::addAttributeString("trunk_depth");
 184			success &= tree_def->getFastAttributeS32(trunk_depth_string, S32_val);
 185			newTree->mTrunkDepth = S32_val;
 186			
 187			static LLStdStringHandle branch_length_string = LLXmlTree::addAttributeString("branch_length");
 188			success &= tree_def->getFastAttributeF32(branch_length_string, F32_val);
 189			newTree->mBranchLength = F32_val;
 190
 191			static LLStdStringHandle trunk_length_string = LLXmlTree::addAttributeString("trunk_length");
 192			success &= tree_def->getFastAttributeF32(trunk_length_string, F32_val);
 193			newTree->mTrunkLength = F32_val;
 194
 195			static LLStdStringHandle leaf_scale_string = LLXmlTree::addAttributeString("leaf_scale");
 196			success &= tree_def->getFastAttributeF32(leaf_scale_string, F32_val);
 197			newTree->mLeafScale = F32_val;
 198			
 199			static LLStdStringHandle billboard_scale_string = LLXmlTree::addAttributeString("billboard_scale");
 200			success &= tree_def->getFastAttributeF32(billboard_scale_string, F32_val);
 201			newTree->mBillboardScale = F32_val;
 202			
 203			static LLStdStringHandle billboard_ratio_string = LLXmlTree::addAttributeString("billboard_ratio");
 204			success &= tree_def->getFastAttributeF32(billboard_ratio_string, F32_val);
 205			newTree->mBillboardRatio = F32_val;
 206			
 207			static LLStdStringHandle trunk_aspect_string = LLXmlTree::addAttributeString("trunk_aspect");
 208			success &= tree_def->getFastAttributeF32(trunk_aspect_string, F32_val);
 209			newTree->mTrunkAspect = F32_val;
 210
 211			static LLStdStringHandle branch_aspect_string = LLXmlTree::addAttributeString("branch_aspect");
 212			success &= tree_def->getFastAttributeF32(branch_aspect_string, F32_val);
 213			newTree->mBranchAspect = F32_val;
 214
 215			static LLStdStringHandle leaf_rotate_string = LLXmlTree::addAttributeString("leaf_rotate");
 216			success &= tree_def->getFastAttributeF32(leaf_rotate_string, F32_val);
 217			newTree->mRandomLeafRotate = F32_val;
 218			
 219			static LLStdStringHandle noise_mag_string = LLXmlTree::addAttributeString("noise_mag");
 220			success &= tree_def->getFastAttributeF32(noise_mag_string, F32_val);
 221			newTree->mNoiseMag = F32_val;
 222
 223			static LLStdStringHandle noise_scale_string = LLXmlTree::addAttributeString("noise_scale");
 224			success &= tree_def->getFastAttributeF32(noise_scale_string, F32_val);
 225			newTree->mNoiseScale = F32_val;
 226
 227			static LLStdStringHandle taper_string = LLXmlTree::addAttributeString("taper");
 228			success &= tree_def->getFastAttributeF32(taper_string, F32_val);
 229			newTree->mTaper = F32_val;
 230
 231			static LLStdStringHandle repeat_z_string = LLXmlTree::addAttributeString("repeat_z");
 232			success &= tree_def->getFastAttributeF32(repeat_z_string, F32_val);
 233			newTree->mRepeatTrunkZ = F32_val;
 234
 235			sSpeciesTable[species] = newTree;
 236
 237			if (species >= sMaxTreeSpecies) sMaxTreeSpecies = species + 1;
 238
 239			if (!success)
 240			{
 241				std::string name;
 242				static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
 243				tree_def->getFastAttributeString(name_string, name);
 244				llwarns << "Incomplete definition of tree " << name << llendl;
 245			}
 246		}
 247		
 248		BOOL have_all_trees = TRUE;
 249		std::string err;
 250
 251		for (S32 i=0;i<sMaxTreeSpecies;++i)
 252		{
 253			if (!sSpeciesTable.count(i))
 254			{
 255				err.append(llformat(" %d",i));
 256				have_all_trees = FALSE;
 257			}
 258		}
 259
 260		if (!have_all_trees) 
 261		{
 262			LLSD args;
 263			args["SPECIES"] = err;
 264			LLNotificationsUtil::add("ErrorUndefinedTrees", args);
 265		}
 266};
 267
 268//static
 269void LLVOTree::cleanupClass()
 270{
 271	std::for_each(sSpeciesTable.begin(), sSpeciesTable.end(), DeletePairedPointer());
 272}
 273
 274U32 LLVOTree::processUpdateMessage(LLMessageSystem *mesgsys,
 275										  void **user_data,
 276										  U32 block_num, EObjectUpdateType update_type,
 277										  LLDataPacker *dp)
 278{
 279	// Do base class updates...
 280	U32 retval = LLViewerObject::processUpdateMessage(mesgsys, user_data, block_num, update_type, dp);
 281
 282	if (  (getVelocity().lengthSquared() > 0.f)
 283		||(getAcceleration().lengthSquared() > 0.f)
 284		||(getAngularVelocity().lengthSquared() > 0.f))
 285	{
 286		llinfos << "ACK! Moving tree!" << llendl;
 287		setVelocity(LLVector3::zero);
 288		setAcceleration(LLVector3::zero);
 289		setAngularVelocity(LLVector3::zero);
 290	}
 291
 292	if (update_type == OUT_TERSE_IMPROVED)
 293	{
 294		// Nothing else needs to be done for the terse message.
 295		return retval;
 296	}
 297
 298	// 
 299	//  Load Instance-Specific data 
 300	//
 301	if (mData)
 302	{
 303		mSpecies = ((U8 *)mData)[0];
 304	}
 305	
 306	if (!sSpeciesTable.count(mSpecies))
 307	{
 308		if (sSpeciesTable.size())
 309		{
 310			SpeciesMap::const_iterator it = sSpeciesTable.begin();
 311			mSpecies = (*it).first;
 312		}
 313	}
 314
 315	//
 316	//  Load Species-Specific data 
 317	//
 318	static const S32 MAX_TREE_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL = 32 ; //frames.
 319	mTreeImagep = LLViewerTextureManager::getFetchedTexture(sSpeciesTable[mSpecies]->mTextureID, TRUE, LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
 320	mTreeImagep->setMaxVirtualSizeResetInterval(MAX_TREE_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL); //allow to wait for at most 16 frames to reset virtual size.
 321
 322	mBranchLength = sSpeciesTable[mSpecies]->mBranchLength;
 323	mTrunkLength = sSpeciesTable[mSpecies]->mTrunkLength;
 324	mLeafScale = sSpeciesTable[mSpecies]->mLeafScale;
 325	mDroop = sSpeciesTable[mSpecies]->mDroop;
 326	mTwist = sSpeciesTable[mSpecies]->mTwist;
 327	mBranches = sSpeciesTable[mSpecies]->mBranches;
 328	mDepth = sSpeciesTable[mSpecies]->mDepth;
 329	mScaleStep = sSpeciesTable[mSpecies]->mScaleStep;
 330	mTrunkDepth = sSpeciesTable[mSpecies]->mTrunkDepth;
 331	mBillboardScale = sSpeciesTable[mSpecies]->mBillboardScale;
 332	mBillboardRatio = sSpeciesTable[mSpecies]->mBillboardRatio;
 333	mTrunkAspect = sSpeciesTable[mSpecies]->mTrunkAspect;
 334	mBranchAspect = sSpeciesTable[mSpecies]->mBranchAspect;
 335	
 336	// position change not caused by us, etc.  make sure to rebuild.
 337	gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL);
 338
 339	return retval;
 340}
 341
 342BOOL LLVOTree::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
 343{
 344 	if (mDead || !(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_TREE)))
 345	{
 346		return TRUE;
 347	}
 348	
 349	S32 trunk_LOD = sMAX_NUM_TREE_LOD_LEVELS ;
 350	F32 app_angle = getAppAngle()*LLVOTree::sTreeFactor;
 351
 352	for (S32 j = 0; j < sMAX_NUM_TREE_LOD_LEVELS; j++)
 353	{
 354		if (app_angle > LLVOTree::sLODAngles[j])
 355		{
 356			trunk_LOD = j;
 357			break;
 358		}
 359	} 
 360
 361	if (mReferenceBuffer.isNull())
 362	{
 363		gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE);
 364	}
 365	else if (trunk_LOD != mTrunkLOD)
 366	{
 367		gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, FALSE);
 368	}
 369	else
 370	{
 371		// we're not animating but we may *still* need to
 372		// regenerate the mesh if we moved, since position
 373		// and rotation are baked into the mesh.
 374		// *TODO: I don't know what's so special about trees
 375		// that they don't get REBUILD_POSITION automatically
 376		// at a higher level.
 377		const LLVector3 &this_position = getPositionAgent();
 378		if (this_position != mLastPosition)
 379		{
 380			gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_POSITION);
 381			mLastPosition = this_position;
 382		}
 383		else
 384		{
 385			const LLQuaternion &this_rotation = getRotation();
 386			
 387			if (this_rotation != mLastRotation)
 388			{
 389				gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_POSITION);
 390				mLastRotation = this_rotation;
 391			}
 392		}
 393	}
 394
 395	mTrunkLOD = trunk_LOD;
 396
 397	return TRUE;
 398}
 399
 400const F32 TREE_BLEND_MIN = 1.f;
 401const F32 TREE_BLEND_RANGE = 1.f;
 402
 403void LLVOTree::render(LLAgent &agent)
 404{
 405}
 406
 407
 408void LLVOTree::setPixelAreaAndAngle(LLAgent &agent)
 409{
 410	LLVector3 center = getPositionAgent();//center of tree.
 411	LLVector3 viewer_pos_agent = gAgentCamera.getCameraPositionAgent();
 412	LLVector3 lookAt = center - viewer_pos_agent;
 413	F32 dist = lookAt.normVec() ;	
 414	F32 cos_angle_to_view_dir = lookAt * LLViewerCamera::getInstance()->getXAxis() ;	
 415	
 416	F32 range = dist - getMinScale()/2;
 417	if (range < F_ALMOST_ZERO || isHUDAttachment())		// range == zero
 418	{
 419		mAppAngle = 180.f;
 420	}
 421	else
 422	{
 423		mAppAngle = (F32) atan2( getMaxScale(), range) * RAD_TO_DEG;		
 424	}
 425
 426	F32 max_scale = mBillboardScale * getMaxScale();
 427	F32 area = max_scale * (max_scale*mBillboardRatio);
 428	// Compute pixels per meter at the given range
 429	F32 pixels_per_meter = LLViewerCamera::getInstance()->getViewHeightInPixels() / (tan(LLViewerCamera::getInstance()->getView()) * dist);
 430	mPixelArea = pixels_per_meter * pixels_per_meter * area ;	
 431
 432	F32 importance = LLFace::calcImportanceToCamera(cos_angle_to_view_dir, dist) ;
 433	mPixelArea = LLFace::adjustPixelArea(importance, mPixelArea) ;
 434	if (mPixelArea > LLViewerCamera::getInstance()->getScreenPixelArea())
 435	{
 436		mAppAngle = 180.f;
 437	}
 438
 439#if 0
 440	// mAppAngle is a bit of voodoo;
 441	// use the one calculated LLViewerObject::setPixelAreaAndAngle above
 442	// to avoid LOD miscalculations
 443	mAppAngle = (F32) atan2( max_scale, range) * RAD_TO_DEG;
 444#endif
 445}
 446
 447void LLVOTree::updateTextures()
 448{
 449	if (mTreeImagep)
 450	{
 451		if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA))
 452		{
 453			setDebugText(llformat("%4.0f", (F32) sqrt(mPixelArea)));
 454		}
 455		mTreeImagep->addTextureStats(mPixelArea);
 456	}
 457
 458}
 459
 460
 461LLDrawable* LLVOTree::createDrawable(LLPipeline *pipeline)
 462{
 463	pipeline->allocDrawable(this);
 464	mDrawable->setLit(FALSE);
 465
 466	mDrawable->setRenderType(LLPipeline::RENDER_TYPE_TREE);
 467
 468	LLDrawPoolTree *poolp = (LLDrawPoolTree*) gPipeline.getPool(LLDrawPool::POOL_TREE, mTreeImagep);
 469
 470	// Just a placeholder for an actual object...
 471	LLFace *facep = mDrawable->addFace(poolp, mTreeImagep);
 472	facep->setSize(1, 3);
 473
 474	updateRadius();
 475
 476	return mDrawable;
 477}
 478
 479
 480// Yes, I know this is bad.  I'll clean this up soon. - djs 04/02/02
 481const S32 LEAF_INDICES = 24;
 482const S32 LEAF_VERTICES = 16;
 483
 484static LLFastTimer::DeclareTimer FTM_UPDATE_TREE("Update Tree");
 485
 486BOOL LLVOTree::updateGeometry(LLDrawable *drawable)
 487{
 488	LLFastTimer ftm(FTM_UPDATE_TREE);
 489
 490	if(mTrunkLOD >= sMAX_NUM_TREE_LOD_LEVELS) //do not display the tree.
 491	{
 492		mReferenceBuffer = NULL ;
 493		mDrawable->getFace(0)->setVertexBuffer(NULL);
 494		return TRUE ;
 495	}
 496
 497	if (mReferenceBuffer.isNull() || !mDrawable->getFace(0)->getVertexBuffer())
 498	{
 499		const F32 SRR3 = 0.577350269f; // sqrt(1/3)
 500		const F32 SRR2 = 0.707106781f; // sqrt(1/2)
 501		U32 i, j;
 502
 503		U32 slices = MAX_SLICES;
 504
 505		S32 max_indices = LEAF_INDICES;
 506		S32 max_vertices = LEAF_VERTICES;
 507		S32 lod;
 508
 509		LLFace *face = drawable->getFace(0);
 510
 511		face->mCenterAgent = getPositionAgent();
 512		face->mCenterLocal = face->mCenterAgent;
 513
 514		for (lod = 0; lod < sMAX_NUM_TREE_LOD_LEVELS; lod++)
 515		{
 516			slices = sLODSlices[lod];
 517			sLODVertexOffset[lod] = max_vertices;
 518			sLODVertexCount[lod] = slices*slices;
 519			sLODIndexOffset[lod] = max_indices;
 520			sLODIndexCount[lod] = (slices-1)*(slices-1)*6;
 521			max_indices += sLODIndexCount[lod];
 522			max_vertices += sLODVertexCount[lod];
 523		}
 524
 525		mReferenceBuffer = new LLVertexBuffer(LLDrawPoolTree::VERTEX_DATA_MASK, 0);
 526		mReferenceBuffer->allocateBuffer(max_vertices, max_indices, TRUE);
 527
 528		LLStrider<LLVector3> vertices;
 529		LLStrider<LLVector3> normals;
 530		LLStrider<LLVector2> tex_coords;
 531		LLStrider<U16> indicesp;
 532
 533		mReferenceBuffer->getVertexStrider(vertices);
 534		mReferenceBuffer->getNormalStrider(normals);
 535		mReferenceBuffer->getTexCoord0Strider(tex_coords);
 536		mReferenceBuffer->getIndexStrider(indicesp);
 537				
 538		S32 vertex_count = 0;
 539		S32 index_count = 0;
 540		
 541		// First leaf
 542		*(normals++) =		LLVector3(-SRR2, -SRR2, 0.f);
 543		*(tex_coords++) =	LLVector2(LEAF_LEFT, LEAF_BOTTOM);
 544		*(vertices++) =		LLVector3(-0.5f*LEAF_WIDTH, 0.f, 0.f);
 545		vertex_count++;
 546
 547		*(normals++) =		LLVector3(SRR3, -SRR3, SRR3);
 548		*(tex_coords++) =	LLVector2(LEAF_RIGHT, LEAF_TOP);
 549		*(vertices++) =		LLVector3(0.5f*LEAF_WIDTH, 0.f, 1.f);
 550		vertex_count++;
 551
 552		*(normals++) =		LLVector3(-SRR3, -SRR3, SRR3);
 553		*(tex_coords++) =	LLVector2(LEAF_LEFT, LEAF_TOP);
 554		*(vertices++) =		LLVector3(-0.5f*LEAF_WIDTH, 0.f, 1.f);
 555		vertex_count++;
 556
 557		*(normals++) =		LLVector3(SRR2, -SRR2, 0.f);
 558		*(tex_coords++) =	LLVector2(LEAF_RIGHT, LEAF_BOTTOM);
 559		*(vertices++) =		LLVector3(0.5f*LEAF_WIDTH, 0.f, 0.f);
 560		vertex_count++;
 561
 562
 563		*(indicesp++) = 0;
 564		index_count++;
 565		*(indicesp++) = 1;
 566		index_count++;
 567		*(indicesp++) = 2;
 568		index_count++;
 569
 570		*(indicesp++) = 0;
 571		index_count++;
 572		*(indicesp++) = 3;
 573		index_count++;
 574		*(indicesp++) = 1;
 575		index_count++;
 576
 577		// Same leaf, inverse winding/normals
 578		*(normals++) =		LLVector3(-SRR2, SRR2, 0.f);
 579		*(tex_coords++) =	LLVector2(LEAF_LEFT, LEAF_BOTTOM);
 580		*(vertices++) =		LLVector3(-0.5f*LEAF_WIDTH, 0.f, 0.f);
 581		vertex_count++;
 582
 583		*(normals++) =		LLVector3(SRR3, SRR3, SRR3);
 584		*(tex_coords++) =	LLVector2(LEAF_RIGHT, LEAF_TOP);
 585		*(vertices++) =		LLVector3(0.5f*LEAF_WIDTH, 0.f, 1.f);
 586		vertex_count++;
 587
 588		*(normals++) =		LLVector3(-SRR3, SRR3, SRR3);
 589		*(tex_coords++) =	LLVector2(LEAF_LEFT, LEAF_TOP);
 590		*(vertices++) =		LLVector3(-0.5f*LEAF_WIDTH, 0.f, 1.f);
 591		vertex_count++;
 592
 593		*(normals++) =		LLVector3(SRR2, SRR2, 0.f);
 594		*(tex_coords++) =	LLVector2(LEAF_RIGHT, LEAF_BOTTOM);
 595		*(vertices++) =		LLVector3(0.5f*LEAF_WIDTH, 0.f, 0.f);
 596		vertex_count++;
 597
 598		*(indicesp++) = 4;
 599		index_count++;
 600		*(indicesp++) = 6;
 601		index_count++;
 602		*(indicesp++) = 5;
 603		index_count++;
 604
 605		*(indicesp++) = 4;
 606		index_count++;
 607		*(indicesp++) = 5;
 608		index_count++;
 609		*(indicesp++) = 7;
 610		index_count++;
 611
 612
 613		// next leaf
 614		*(normals++) =		LLVector3(SRR2, -SRR2, 0.f);
 615		*(tex_coords++) =	LLVector2(LEAF_LEFT, LEAF_BOTTOM);
 616		*(vertices++) =		LLVector3(0.f, -0.5f*LEAF_WIDTH, 0.f);
 617		vertex_count++;
 618
 619		*(normals++) =		LLVector3(SRR3, SRR3, SRR3);
 620		*(tex_coords++) =	LLVector2(LEAF_RIGHT, LEAF_TOP);
 621		*(vertices++) =		LLVector3(0.f, 0.5f*LEAF_WIDTH, 1.f);
 622		vertex_count++;
 623
 624		*(normals++) =		LLVector3(SRR3, -SRR3, SRR3);
 625		*(tex_coords++) =	LLVector2(LEAF_LEFT, LEAF_TOP);
 626		*(vertices++) =		LLVector3(0.f, -0.5f*LEAF_WIDTH, 1.f);
 627		vertex_count++;
 628
 629		*(normals++) =		LLVector3(SRR2, SRR2, 0.f);
 630		*(tex_coords++) =	LLVector2(LEAF_RIGHT, LEAF_BOTTOM);
 631		*(vertices++) =		LLVector3(0.f, 0.5f*LEAF_WIDTH, 0.f);
 632		vertex_count++;
 633
 634		*(indicesp++) = 8;
 635		index_count++;
 636		*(indicesp++) = 9;
 637		index_count++;
 638		*(indicesp++) = 10;
 639		index_count++;
 640
 641		*(indicesp++) = 8;
 642		index_count++;
 643		*(indicesp++) = 11;
 644		index_count++;
 645		*(indicesp++) = 9;
 646		index_count++;
 647
 648
 649		// other side of same leaf
 650		*(normals++) =		LLVector3(-SRR2, -SRR2, 0.f);
 651		*(tex_coords++) =	LLVector2(LEAF_LEFT, LEAF_BOTTOM);
 652		*(vertices++) =		LLVector3(0.f, -0.5f*LEAF_WIDTH, 0.f);
 653		vertex_count++;
 654
 655		*(normals++) =		LLVector3(-SRR3, SRR3, SRR3);
 656		*(tex_coords++) =	LLVector2(LEAF_RIGHT, LEAF_TOP);
 657		*(vertices++) =		LLVector3(0.f, 0.5f*LEAF_WIDTH, 1.f);
 658		vertex_count++;
 659
 660		*(normals++) =		LLVector3(-SRR3, -SRR3, SRR3);
 661		*(tex_coords++) =	LLVector2(LEAF_LEFT, LEAF_TOP);
 662		*(vertices++) =		LLVector3(0.f, -0.5f*LEAF_WIDTH, 1.f);
 663		vertex_count++;
 664
 665		*(normals++) =		LLVector3(-SRR2, SRR2, 0.f);
 666		*(tex_coords++) =	LLVector2(LEAF_RIGHT, LEAF_BOTTOM);
 667		*(vertices++) =		LLVector3(0.f, 0.5f*LEAF_WIDTH, 0.f);
 668		vertex_count++;
 669
 670		*(indicesp++) = 12;
 671		index_count++;
 672		*(indicesp++) = 14;
 673		index_count++;
 674		*(indicesp++) = 13;
 675		index_count++;
 676
 677		*(indicesp++) = 12;
 678		index_count++;
 679		*(indicesp++) = 13;
 680		index_count++;
 681		*(indicesp++) = 15;
 682		index_count++;
 683
 684		// Generate geometry for the cylinders
 685
 686		// Different LOD's
 687
 688		// Generate the vertices
 689		// Generate the indices
 690
 691		for (lod = 0; lod < sMAX_NUM_TREE_LOD_LEVELS; lod++)
 692		{
 693			slices = sLODSlices[lod];
 694			F32 base_radius = 0.65f;
 695			F32 top_radius = base_radius * sSpeciesTable[mSpecies]->mTaper;
 696			//llinfos << "Species " << ((U32) mSpecies) << ", taper = " << sSpeciesTable[mSpecies].mTaper << llendl;
 697			//llinfos << "Droop " << mDroop << ", branchlength: " << mBranchLength << llendl;
 698			F32 angle = 0;
 699			F32 angle_inc = 360.f/(slices-1);
 700			F32 z = 0.f;
 701			F32 z_inc = 1.f;
 702			if (slices > 3)
 703			{
 704				z_inc = 1.f/(slices - 3);
 705			}
 706			F32 radius = base_radius;
 707
 708			F32 x1,y1;
 709			F32 noise_scale = sSpeciesTable[mSpecies]->mNoiseMag;
 710			LLVector3 nvec;
 711
 712			const F32 cap_nudge = 0.1f;			// Height to 'peak' the caps on top/bottom of branch
 713
 714			const S32 fractal_depth = 5;
 715			F32 nvec_scale = 1.f * sSpeciesTable[mSpecies]->mNoiseScale;
 716			F32 nvec_scalez = 4.f * sSpeciesTable[mSpecies]->mNoiseScale;
 717
 718			F32 tex_z_repeat = sSpeciesTable[mSpecies]->mRepeatTrunkZ;
 719
 720			F32 start_radius;
 721			F32 nangle = 0;
 722			F32 height = 1.f;
 723			F32 r0;
 724
 725			for (i = 0; i < slices; i++)
 726			{
 727				if (i == 0) 
 728				{
 729					z = - cap_nudge;
 730					r0 = 0.0;
 731				}
 732				else if (i == (slices - 1))
 733				{
 734					z = 1.f + cap_nudge;//((i - 2) * z_inc) + cap_nudge;
 735					r0 = 0.0;
 736				}
 737				else  
 738				{
 739					z = (i - 1) * z_inc;
 740					r0 = base_radius + (top_radius - base_radius)*z;
 741				}
 742
 743				for (j = 0; j < slices; j++)
 744				{
 745					if (slices - 1 == j)
 746					{
 747						angle = 0.f;
 748					}
 749					else
 750					{
 751						angle =  j*angle_inc;
 752					}
 753				
 754					nangle = angle;
 755					
 756					x1 = cos(angle * DEG_TO_RAD);
 757					y1 = sin(angle * DEG_TO_RAD);
 758					LLVector2 tc;
 759					// This isn't totally accurate.  Should compute based on slope as well.
 760					start_radius = r0 * (1.f + 1.2f*fabs(z - 0.66f*height)/height);
 761					nvec.set(	cos(nangle * DEG_TO_RAD)*start_radius*nvec_scale, 
 762								sin(nangle * DEG_TO_RAD)*start_radius*nvec_scale, 
 763								z*nvec_scalez); 
 764					// First and last slice at 0 radius (to bring in top/bottom of structure)
 765					radius = start_radius + turbulence3((F32*)&nvec.mV, (F32)fractal_depth)*noise_scale;
 766
 767					if (slices - 1 == j)
 768					{
 769						// Not 0.5 for slight slop factor to avoid edges on leaves
 770						tc = LLVector2(0.490f, (1.f - z/2.f)*tex_z_repeat);
 771					}
 772					else
 773					{
 774						tc = LLVector2((angle/360.f)*0.5f, (1.f - z/2.f)*tex_z_repeat);
 775					}
 776
 777					*(vertices++) =		LLVector3(x1*radius, y1*radius, z);
 778					*(normals++) =		LLVector3(x1, y1, 0.f);
 779					*(tex_coords++) = tc;
 780					vertex_count++;
 781				}
 782			}
 783
 784			for (i = 0; i < (slices - 1); i++)
 785			{
 786				for (j = 0; j < (slices - 1); j++)
 787				{
 788					S32 x1_offset = j+1;
 789					if ((j+1) == slices)
 790					{
 791						x1_offset = 0;
 792					}
 793					// Generate the matching quads
 794					*(indicesp) = j + (i*slices) + sLODVertexOffset[lod];
 795					llassert(*(indicesp) < (U32)max_vertices);
 796					indicesp++;
 797					index_count++;
 798					*(indicesp) = x1_offset + ((i+1)*slices) + sLODVertexOffset[lod];
 799					llassert(*(indicesp) < (U32)max_vertices);
 800					indicesp++;
 801					index_count++;
 802					*(indicesp) = j + ((i+1)*slices) + sLODVertexOffset[lod];
 803					llassert(*(indicesp) < (U32)max_vertices);
 804					indicesp++;
 805					index_count++;
 806
 807					*(indicesp) = j + (i*slices) + sLODVertexOffset[lod];
 808					llassert(*(indicesp) < (U32)max_vertices);
 809					indicesp++;
 810					index_count++;
 811					*(indicesp) = x1_offset + (i*slices) + sLODVertexOffset[lod];
 812					llassert(*(indicesp) < (U32)max_vertices);
 813					indicesp++;
 814					index_count++;
 815					*(indicesp) = x1_offset + ((i+1)*slices) + sLODVertexOffset[lod];
 816					llassert(*(indicesp) < (U32)max_vertices);
 817					indicesp++;
 818					index_count++;
 819				}
 820			}
 821			slices /= 2; 
 822		}
 823
 824		mReferenceBuffer->flush();
 825		llassert(vertex_count == max_vertices);
 826		llassert(index_count == max_indices);
 827	}
 828
 829	//generate tree mesh
 830	updateMesh();
 831	
 832	return TRUE;
 833}
 834
 835void LLVOTree::updateMesh()
 836{
 837	LLMatrix4 matrix;
 838	
 839	// Translate to tree base  HACK - adjustment in Z plants tree underground
 840	const LLVector3 &pos_agent = getPositionAgent();
 841	//gGL.translatef(pos_agent.mV[VX], pos_agent.mV[VY], pos_agent.mV[VZ] - 0.1f);
 842	LLMatrix4 trans_mat;
 843	trans_mat.setTranslation(pos_agent.mV[VX], pos_agent.mV[VY], pos_agent.mV[VZ] - 0.1f);
 844	trans_mat *= matrix;
 845	
 846	// Rotate to tree position and bend for current trunk/wind
 847	// Note that trunk stiffness controls the amount of bend at the trunk as 
 848	// opposed to the crown of the tree
 849	// 
 850	const F32 TRUNK_STIFF = 22.f;
 851	
 852	LLQuaternion rot = 
 853		LLQuaternion(mTrunkBend.magVec()*TRUNK_STIFF*DEG_TO_RAD, LLVector4(mTrunkBend.mV[VX], mTrunkBend.mV[VY], 0)) *
 854		LLQuaternion(90.f*DEG_TO_RAD, LLVector4(0,0,1)) *
 855		getRotation();
 856
 857	LLMatrix4 rot_mat(rot);
 858	rot_mat *= trans_mat;
 859
 860	F32 radius = getScale().magVec()*0.05f;
 861	LLMatrix4 scale_mat;
 862	scale_mat.mMatrix[0][0] = 
 863		scale_mat.mMatrix[1][1] =
 864		scale_mat.mMatrix[2][2] = radius;
 865
 866	scale_mat *= rot_mat;
 867
 868//	const F32 THRESH_ANGLE_FOR_BILLBOARD = 15.f;
 869//	const F32 BLEND_RANGE_FOR_BILLBOARD = 3.f;
 870
 871	F32 droop = mDroop + 25.f*(1.f - mTrunkBend.magVec());
 872	
 873	S32 stop_depth = 0;
 874	F32 alpha = 1.0;
 875	
 876	U32 vert_count = 0;
 877	U32 index_count = 0;
 878	
 879	calcNumVerts(vert_count, index_count, mTrunkLOD, stop_depth, mDepth, mTrunkDepth, mBranches);
 880
 881	LLFace* facep = mDrawable->getFace(0);
 882	LLVertexBuffer* buff = new LLVertexBuffer(LLDrawPoolTree::VERTEX_DATA_MASK, GL_STATIC_DRAW_ARB);
 883	buff->allocateBuffer(vert_count, index_count, TRUE);
 884	facep->setVertexBuffer(buff);
 885	
 886	LLStrider<LLVector3> vertices;
 887	LLStrider<LLVector3> normals;
 888	LLStrider<LLVector2> tex_coords;
 889	LLStrider<U16> indices;
 890	U16 idx_offset = 0;
 891
 892	buff->getVertexStrider(vertices);
 893	buff->getNormalStrider(normals);
 894	buff->getTexCoord0Strider(tex_coords);
 895	buff->getIndexStrider(indices);
 896
 897	genBranchPipeline(vertices, normals, tex_coords, indices, idx_offset, scale_mat, mTrunkLOD, stop_depth, mDepth, mTrunkDepth, 1.0, mTwist, droop, mBranches, alpha);
 898	
 899	mReferenceBuffer->flush();
 900	buff->flush();
 901}
 902
 903void LLVOTree::appendMesh(LLStrider<LLVector3>& vertices, 
 904						 LLStrider<LLVector3>& normals, 
 905						 LLStrider<LLVector2>& tex_coords, 
 906						 LLStrider<U16>& indices,
 907						 U16& cur_idx,
 908						 LLMatrix4& matrix,
 909						 LLMatrix4& norm_mat,
 910						 S32 vert_start,
 911						 S32 vert_count,
 912						 S32 index_count,
 913						 S32 index_offset)
 914{
 915	LLStrider<LLVector3> v;
 916	LLStrider<LLVector3> n;
 917	LLStrider<LLVector2> t;
 918	LLStrider<U16> idx;
 919
 920	mReferenceBuffer->getVertexStrider(v);
 921	mReferenceBuffer->getNormalStrider(n);
 922	mReferenceBuffer->getTexCoord0Strider(t);
 923	mReferenceBuffer->getIndexStrider(idx);
 924	
 925	//copy/transform vertices into mesh - check
 926	for (S32 i = 0; i < vert_count; i++)
 927	{ 
 928		U16 index = vert_start + i;
 929		*vertices++ = v[index] * matrix;
 930		LLVector3 norm = n[index] * norm_mat;
 931		norm.normalize();
 932		*normals++ = norm;
 933		*tex_coords++ = t[index];
 934	}
 935
 936	//copy offset indices into mesh - check
 937	for (S32 i = 0; i < index_count; i++)
 938	{
 939		U16 index = index_offset + i;
 940		*indices++ = idx[index]-vert_start+cur_idx;
 941	}
 942
 943	//increment index offset - check
 944	cur_idx += vert_count;
 945}
 946								 
 947
 948void LLVOTree::genBranchPipeline(LLStrider<LLVector3>& vertices, 
 949								 LLStrider<LLVector3>& normals, 
 950								 LLStrider<LLVector2>& tex_coords, 
 951								 LLStrider<U16>& indices,
 952								 U16& index_offset,
 953								 LLMatrix4& matrix, 
 954								 S32 trunk_LOD, 
 955								 S32 stop_level, 
 956								 U16 depth, 
 957								 U16 trunk_depth,  
 958								 F32 scale, 
 959								 F32 twist, 
 960								 F32 droop,  
 961								 F32 branches, 
 962								 F32 alpha)
 963{
 964	//
 965	//  Generates a tree mesh by recursing, generating branches and then a 'leaf' texture.
 966	
 967	static F32 constant_twist;
 968	static F32 width = 0;
 969
 970	F32 length = ((trunk_depth || (scale == 1.f))? mTrunkLength:mBranchLength);
 971	F32 aspect = ((trunk_depth || (scale == 1.f))? mTrunkAspect:mBranchAspect);
 972	
 973	constant_twist = 360.f/branches;
 974
 975	if (stop_level >= 0)
 976	{
 977		if (depth > stop_level)
 978		{
 979			{
 980				llassert(sLODIndexCount[trunk_LOD] > 0);
 981				width = scale * length * aspect;
 982				LLMatrix4 scale_mat;
 983				scale_mat.mMatrix[0][0] = width;
 984				scale_mat.mMatrix[1][1] = width;
 985				scale_mat.mMatrix[2][2] = scale*length;
 986				scale_mat *= matrix;
 987
 988				glh::matrix4f norm((F32*) scale_mat.mMatrix);
 989				LLMatrix4 norm_mat = LLMatrix4(norm.inverse().transpose().m);
 990
 991				norm_mat.invert();
 992				appendMesh(vertices, normals, tex_coords, indices, index_offset, scale_mat, norm_mat, 
 993							sLODVertexOffset[trunk_LOD], sLODVertexCount[trunk_LOD], sLODIndexCount[trunk_LOD], sLODIndexOffset[trunk_LOD]);
 994			}
 995			
 996			// Recurse to create more branches
 997			for (S32 i=0; i < (S32)branches; i++) 
 998			{
 999				LLMatrix4 trans_mat;
1000				trans_mat.setTranslation(0,0,scale*length);
1001				trans_mat *= matrix;
1002
1003				LLQuaternion rot = 
1004					LLQuaternion(20.f*DEG_TO_RAD, LLVector4(0.f, 0.f, 1.f)) *
1005					LLQuaternion(droop*DEG_TO_RAD, LLVector4(0.f, 1.f, 0.f)) *
1006					LLQuaternion(((constant_twist + ((i%2==0)?twist:-twist))*i)*DEG_TO_RAD, LLVector4(0.f, 0.f, 1.f));
1007				
1008				LLMatrix4 rot_mat(rot);
1009				rot_mat *= trans_mat;
1010
1011				genBranchPipeline(vertices, normals, tex_coords, indices, index_offset, rot_mat, trunk_LOD, stop_level, depth - 1, 0, scale*mScaleStep, twist, droop, branches, alpha);
1012			}
1013			//  Recurse to continue trunk
1014			if (trunk_depth)
1015			{
1016				LLMatrix4 trans_mat;
1017				trans_mat.setTranslation(0,0,scale*length);
1018				trans_mat *= matrix;
1019
1020				LLMatrix4 rot_mat(70.5f*DEG_TO_RAD, LLVector4(0,0,1));
1021				rot_mat *= trans_mat; // rotate a bit around Z when ascending 
1022				genBranchPipeline(vertices, normals, tex_coords, indices, index_offset, rot_mat, trunk_LOD, stop_level, depth, trunk_depth-1, scale*mScaleStep, twist, droop, branches, alpha);
1023			}
1024		}
1025		else
1026		{
1027			//
1028			//  Append leaves as two 90 deg crossed quads with leaf textures
1029			//
1030			{
1031				LLMatrix4 scale_mat;
1032				scale_mat.mMatrix[0][0] = 
1033					scale_mat.mMatrix[1][1] =
1034					scale_mat.mMatrix[2][2] = scale*mLeafScale;
1035
1036				scale_mat *= matrix;
1037
1038				glh::matrix4f norm((F32*) scale_mat.mMatrix);
1039				LLMatrix4 norm_mat = LLMatrix4(norm.inverse().transpose().m);
1040
1041				appendMesh(vertices, normals, tex_coords, indices, index_offset, scale_mat, norm_mat, 0, LEAF_VERTICES, LEAF_INDICES, 0);	
1042			}
1043		}
1044	}
1045}
1046
1047
1048
1049void LLVOTree::calcNumVerts(U32& vert_count, U32& index_count, S32 trunk_LOD, S32 stop_level, U16 depth, U16 trunk_depth, F32 branches)
1050{
1051	if (stop_level >= 0)
1052	{
1053		if (depth > stop_level)
1054		{
1055			index_count += sLODIndexCount[trunk_LOD];
1056			vert_count += sLODVertexCount[trunk_LOD];
1057
1058			// Recurse to create more branches
1059			for (S32 i=0; i < (S32)branches; i++) 
1060			{
1061				calcNumVerts(vert_count, index_count, trunk_LOD, stop_level, depth - 1, 0, branches);
1062			}
1063			
1064			//  Recurse to continue trunk
1065			if (trunk_depth)
1066			{
1067				calcNumVerts(vert_count, index_count, trunk_LOD, stop_level, depth, trunk_depth-1, branches);
1068			}
1069		}
1070		else
1071		{
1072			index_count += LEAF_INDICES;
1073			vert_count += LEAF_VERTICES;
1074		}
1075	}
1076	else
1077	{
1078		index_count += LEAF_INDICES;
1079		vert_count += LEAF_VERTICES;
1080	}
1081}
1082
1083U32 LLVOTree::drawBranchPipeline(LLMatrix4& matrix, U16* indicesp, S32 trunk_LOD, S32 stop_level, U16 depth, U16 trunk_depth,  F32 scale, F32 twist, F32 droop,  F32 branches, F32 alpha)
1084{
1085	U32 ret = 0;
1086	//
1087	//  Draws a tree by recursing, drawing branches and then a 'leaf' texture.
1088	//  If stop_level = -1, simply draws the whole tree as a billboarded texture
1089	//
1090	
1091	static F32 constant_twist;
1092	static F32 width = 0;
1093
1094	//F32 length = ((scale == 1.f)? mTrunkLength:mBranchLength);
1095	//F32 aspect = ((scale == 1.f)? mTrunkAspect:mBranchAspect);
1096	F32 length = ((trunk_depth || (scale == 1.f))? mTrunkLength:mBranchLength);
1097	F32 aspect = ((trunk_depth || (scale == 1.f))? mTrunkAspect:mBranchAspect);
1098	
1099	constant_twist = 360.f/branches;
1100
1101	if (!LLPipeline::sReflectionRender && stop_level >= 0)
1102	{
1103		//
1104		//  Draw the tree using recursion
1105		//
1106		if (depth > stop_level)
1107		{
1108			{
1109				llassert(sLODIndexCount[trunk_LOD] > 0);
1110				width = scale * length * aspect;
1111				LLMatrix4 scale_mat;
1112				scale_mat.mMatrix[0][0] = width;
1113				scale_mat.mMatrix[1][1] = width;
1114				scale_mat.mMatrix[2][2] = scale*length;
1115				scale_mat *= matrix;
1116
1117				gGL.loadMatrix((F32*) scale_mat.mMatrix);
1118				gGL.syncMatrices();
1119 				glDrawElements(GL_TRIANGLES, sLODIndexCount[trunk_LOD], GL_UNSIGNED_SHORT, indicesp + sLODIndexOffset[trunk_LOD]);
1120				gPipeline.addTrianglesDrawn(LEAF_INDICES);
1121				stop_glerror();
1122				ret += sLODIndexCount[trunk_LOD];
1123			}
1124			
1125			// Recurse to create more branches
1126			for (S32 i=0; i < (S32)branches; i++) 
1127			{
1128				LLMatrix4 trans_mat;
1129				trans_mat.setTranslation(0,0,scale*length);
1130				trans_mat *= matrix;
1131
1132				LLQuaternion rot = 
1133					LLQuaternion(20.f*DEG_TO_RAD, LLVector4(0.f, 0.f, 1.f)) *
1134					LLQuaternion(droop*DEG_TO_RAD, LLVector4(0.f, 1.f, 0.f)) *
1135					LLQuaternion(((constant_twist + ((i%2==0)?twist:-twist))*i)*DEG_TO_RAD, LLVector4(0.f, 0.f, 1.f));
1136				
1137				LLMatrix4 rot_mat(rot);
1138				rot_mat *= trans_mat;
1139
1140				ret += drawBranchPipeline(rot_mat, indicesp, trunk_LOD, stop_level, depth - 1, 0, scale*mScaleStep, twist, droop, branches, alpha);
1141			}
1142			//  Recurse to continue trunk
1143			if (trunk_depth)
1144			{
1145				LLMatrix4 trans_mat;
1146				trans_mat.setTranslation(0,0,scale*length);
1147				trans_mat *= matrix;
1148
1149				LLMatrix4 rot_mat(70.5f*DEG_TO_RAD, LLVector4(0,0,1));
1150				rot_mat *= trans_mat; // rotate a bit around Z when ascending 
1151				ret += drawBranchPipeline(rot_mat, indicesp, trunk_LOD, stop_level, depth, trunk_depth-1, scale*mScaleStep, twist, droop, branches, alpha);
1152			}
1153		}
1154		else
1155		{
1156			//
1157			//  Draw leaves as two 90 deg crossed quads with leaf textures
1158			//
1159			{
1160				LLMatrix4 scale_mat;
1161				scale_mat.mMatrix[0][0] = 
1162					scale_mat.mMatrix[1][1] =
1163					scale_mat.mMatrix[2][2] = scale*mLeafScale;
1164
1165				scale_mat *= matrix;
1166
1167			
1168				gGL.loadMatrix((F32*) scale_mat.mMatrix);
1169				gGL.syncMatrices();
1170				glDrawElements(GL_TRIANGLES, LEAF_INDICES, GL_UNSIGNED_SHORT, indicesp);
1171				gPipeline.addTrianglesDrawn(LEAF_INDICES);							
1172				stop_glerror();
1173				ret += LEAF_INDICES;
1174			}
1175		}
1176	}
1177	else
1178	{
1179		//
1180		//  Draw the tree as a single billboard texture 
1181		//
1182
1183		LLMatrix4 scale_mat;
1184		scale_mat.mMatrix[0][0] = 
1185			scale_mat.mMatrix[1][1] =
1186			scale_mat.mMatrix[2][2] = mBillboardScale*mBillboardRatio;
1187
1188		scale_mat *= matrix;
1189	
1190		gGL.matrixMode(LLRender::MM_TEXTURE);
1191		gGL.translatef(0.0, -0.5, 0.0);
1192		gGL.matrixMode(LLRender::MM_MODELVIEW);
1193					
1194		gGL.loadMatrix((F32*) scale_mat.mMatrix);
1195		gGL.syncMatrices();
1196		glDrawElements(GL_TRIANGLES, LEAF_INDICES, GL_UNSIGNED_SHORT, indicesp);
1197		gPipeline.addTrianglesDrawn(LEAF_INDICES);
1198		stop_glerror();
1199		ret += LEAF_INDICES;
1200
1201		gGL.matrixMode(LLRender::MM_TEXTURE);
1202		gGL.loadIdentity();
1203		gGL.matrixMode(LLRender::MM_MODELVIEW);
1204	}
1205
1206	return ret;
1207}
1208
1209void LLVOTree::updateRadius()
1210{
1211	if (mDrawable.isNull())
1212	{
1213		return;
1214	}
1215		
1216	mDrawable->setRadius(32.0f);
1217}
1218
1219void LLVOTree::updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
1220{
1221	F32 radius = getScale().length()*0.05f;
1222	LLVector3 center = getRenderPosition();
1223
1224	F32 sz = mBillboardScale*mBillboardRatio*radius*0.5f; 
1225	LLVector3 size(sz,sz,sz);
1226
1227	center += LLVector3(0, 0, size.mV[2]) * getRotation();
1228	
1229	newMin.load3((center-size).mV);
1230	newMax.load3((center+size).mV);
1231	LLVector4a pos;
1232	pos.load3(center.mV);
1233	mDrawable->setPositionGroup(pos);
1234}
1235
1236BOOL LLVOTree::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, S32 face, BOOL pick_transparent, S32 *face_hitp,
1237									  LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal)
1238	
1239{
1240
1241	if (!lineSegmentBoundingBox(start, end))
1242	{
1243		return FALSE;
1244	}
1245
1246	const LLVector4a* exta = mDrawable->getSpatialExtents();
1247
1248	//VECTORIZE THIS
1249	LLVector3 ext[2];
1250	ext[0].set(exta[0].getF32ptr());
1251	ext[1].set(exta[1].getF32ptr());
1252	
1253	LLVector3 center = (ext[1]+ext[0])*0.5f;
1254	LLVector3 size = (ext[1]-ext[0]);
1255
1256	LLQuaternion quat = getRotation();
1257
1258	center -= LLVector3(0,0,size.magVec() * 0.25f)*quat;
1259
1260	size.scaleVec(LLVector3(0.25f, 0.25f, 1.f));
1261	size.mV[0] = llmin(size.mV[0], 1.f);
1262	size.mV[1] = llmin(size.mV[1], 1.f);
1263
1264	LLVector3 pos, norm;
1265		
1266	if (linesegment_tetrahedron(start, end, center, size, quat, pos, norm))
1267	{
1268		if (intersection)
1269		{
1270			*intersection = pos;
1271		}
1272
1273		if (normal)
1274		{
1275			*normal = norm;
1276		}
1277		return TRUE;
1278	}
1279	
1280	return FALSE;
1281}
1282
1283U32 LLVOTree::getPartitionType() const
1284{ 
1285	return LLViewerRegion::PARTITION_TREE; 
1286}
1287
1288LLTreePartition::LLTreePartition()
1289: LLSpatialPartition(0, FALSE, GL_DYNAMIC_DRAW_ARB)
1290{
1291	mDrawableType = LLPipeline::RENDER_TYPE_TREE;
1292	mPartitionType = LLViewerRegion::PARTITION_TREE;
1293	mSlopRatio = 0.f;
1294	mLODPeriod = 1;
1295}
1296