PageRenderTime 154ms CodeModel.GetById 32ms app.highlight 112ms RepoModel.GetById 1ms app.codeStats 1ms

/indra/newview/lldrawable.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1565 lines | 1215 code | 240 blank | 110 comment | 229 complexity | e586f4a47880e74cfc42d2f832f06b06 MD5 | raw file
   1/** 
   2 * @file lldrawable.cpp
   3 * @brief LLDrawable 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 "lldrawable.h"
  30
  31// library includes
  32#include "material_codes.h"
  33
  34// viewer includes
  35#include "llcriticaldamp.h"
  36#include "llface.h"
  37#include "lllightconstants.h"
  38#include "llmatrix4a.h"
  39#include "llsky.h"
  40#include "llsurfacepatch.h"
  41#include "llviewercamera.h"
  42#include "llviewerregion.h"
  43#include "llvolume.h"
  44#include "llvoavatar.h"
  45#include "llvovolume.h"
  46#include "llvosurfacepatch.h" // for debugging
  47#include "llworld.h"
  48#include "pipeline.h"
  49#include "llspatialpartition.h"
  50#include "llviewerobjectlist.h"
  51#include "llviewerwindow.h"
  52
  53const F32 MIN_INTERPOLATE_DISTANCE_SQUARED = 0.001f * 0.001f;
  54const F32 MAX_INTERPOLATE_DISTANCE_SQUARED = 10.f * 10.f;
  55const F32 OBJECT_DAMPING_TIME_CONSTANT = 0.06f;
  56const F32 MIN_SHADOW_CASTER_RADIUS = 2.0f;
  57
  58static LLFastTimer::DeclareTimer FTM_CULL_REBOUND("Cull Rebound");
  59
  60
  61////////////////////////
  62//
  63// Inline implementations.
  64//
  65//
  66
  67
  68
  69//////////////////////////////
  70//
  71// Drawable code
  72//
  73//
  74
  75// static
  76U32 LLDrawable::sCurVisible = 0;
  77U32 LLDrawable::sNumZombieDrawables = 0;
  78F32 LLDrawable::sCurPixelAngle = 0;
  79LLDynamicArrayPtr<LLPointer<LLDrawable> > LLDrawable::sDeadList;
  80
  81#define FORCE_INVISIBLE_AREA 16.f
  82
  83// static
  84void LLDrawable::incrementVisible() 
  85{
  86	sCurVisible++;
  87	sCurPixelAngle = (F32) gViewerWindow->getWindowHeightRaw()/LLViewerCamera::getInstance()->getView();
  88}
  89
  90void LLDrawable::init()
  91{
  92	// mXform
  93	mParent = NULL;
  94	mRenderType = 0;
  95	mCurrentScale = LLVector3(1,1,1);
  96	mDistanceWRTCamera = 0.0f;
  97	mPositionGroup.clear();
  98	mExtents[0].clear();
  99	mExtents[1].clear();
 100	mQuietCount = 0;
 101
 102	mState     = 0;
 103	mVObjp   = NULL;
 104	// mFaces
 105	mSpatialGroupp = NULL;
 106	mVisible = sCurVisible - 2;//invisible for the current frame and the last frame.
 107	mRadius = 0.f;
 108	
 109	mGeneration = -1;
 110	mBinRadius = 1.f;
 111	mSpatialBridge = NULL;
 112}
 113
 114// static
 115void LLDrawable::initClass()
 116{
 117}
 118
 119
 120void LLDrawable::destroy()
 121{
 122	if (gDebugGL)
 123	{
 124		gPipeline.checkReferences(this);
 125	}
 126
 127	if (isDead())
 128	{
 129		sNumZombieDrawables--;
 130	}
 131
 132	if (LLSpatialGroup::sNoDelete)
 133	{
 134		llerrs << "Illegal deletion of LLDrawable!" << llendl;
 135	}
 136
 137	std::for_each(mFaces.begin(), mFaces.end(), DeletePointer());
 138	mFaces.clear();
 139		
 140	
 141	/*if (!(sNumZombieDrawables % 10))
 142	{
 143		llinfos << "- Zombie drawables: " << sNumZombieDrawables << llendl;
 144	}*/	
 145
 146}
 147
 148void LLDrawable::markDead()
 149{
 150	if (isDead())
 151	{
 152		llwarns << "Warning!  Marking dead multiple times!" << llendl;
 153		return;
 154	}
 155
 156	if (mSpatialBridge)
 157	{
 158		mSpatialBridge->markDead();
 159		mSpatialBridge = NULL;
 160	}
 161
 162	sNumZombieDrawables++;
 163
 164	// We're dead.  Free up all of our references to other objects
 165	setState(DEAD);
 166	cleanupReferences();
 167//	sDeadList.put(this);
 168}
 169
 170LLVOVolume* LLDrawable::getVOVolume() const
 171{
 172	LLViewerObject* objectp = mVObjp;
 173	if ( !isDead() && objectp && (objectp->getPCode() == LL_PCODE_VOLUME))
 174	{
 175		return ((LLVOVolume*)objectp);
 176	}
 177	else
 178	{
 179		return NULL;
 180	}
 181}
 182
 183const LLMatrix4& LLDrawable::getRenderMatrix() const
 184{ 
 185	return isRoot() ? getWorldMatrix() : getParent()->getWorldMatrix();
 186}
 187
 188BOOL LLDrawable::isLight() const
 189{
 190	LLViewerObject* objectp = mVObjp;
 191	if ( objectp && (objectp->getPCode() == LL_PCODE_VOLUME) && !isDead())
 192	{
 193		return ((LLVOVolume*)objectp)->getIsLight();
 194	}
 195	else
 196	{
 197		return FALSE;
 198	}
 199}
 200
 201static LLFastTimer::DeclareTimer FTM_CLEANUP_DRAWABLE("Cleanup Drawable");
 202static LLFastTimer::DeclareTimer FTM_DEREF_DRAWABLE("Deref");
 203static LLFastTimer::DeclareTimer FTM_DELETE_FACES("Faces");
 204
 205void LLDrawable::cleanupReferences()
 206{
 207	LLFastTimer t(FTM_CLEANUP_DRAWABLE);
 208	
 209	{
 210		LLFastTimer t(FTM_DELETE_FACES);
 211		std::for_each(mFaces.begin(), mFaces.end(), DeletePointer());
 212		mFaces.clear();
 213	}
 214
 215	gObjectList.removeDrawable(this);
 216	
 217	gPipeline.unlinkDrawable(this);
 218	
 219	{
 220		LLFastTimer t(FTM_DEREF_DRAWABLE);
 221		// Cleanup references to other objects
 222		mVObjp = NULL;
 223		mParent = NULL;
 224	}
 225}
 226
 227void LLDrawable::cleanupDeadDrawables()
 228{
 229	/*
 230	S32 i;
 231	for (i = 0; i < sDeadList.count(); i++)
 232	{
 233		if (sDeadList[i]->getNumRefs() > 1)
 234		{
 235			llwarns << "Dead drawable has " << sDeadList[i]->getNumRefs() << " remaining refs" << llendl;
 236			gPipeline.findReferences(sDeadList[i]);
 237		}
 238	}
 239	*/
 240	sDeadList.reset();
 241}
 242
 243S32 LLDrawable::findReferences(LLDrawable *drawablep)
 244{
 245	S32 count = 0;
 246	if (mParent == drawablep)
 247	{
 248		llinfos << this << ": parent reference" << llendl;
 249		count++;
 250	}
 251	return count;
 252}
 253
 254LLFace*	LLDrawable::addFace(LLFacePool *poolp, LLViewerTexture *texturep)
 255{
 256	LLMemType mt(LLMemType::MTYPE_DRAWABLE);
 257	
 258	LLFace *face = new LLFace(this, mVObjp);
 259	if (!face) llerrs << "Allocating new Face: " << mFaces.size() << llendl;
 260	
 261	if (face)
 262	{
 263		mFaces.push_back(face);
 264
 265		if (poolp)
 266		{
 267			face->setPool(poolp, texturep);
 268		}
 269
 270		if (isState(UNLIT))
 271		{
 272			face->setState(LLFace::FULLBRIGHT);
 273		}
 274	}
 275	return face;
 276}
 277
 278LLFace*	LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep)
 279{
 280	LLMemType mt(LLMemType::MTYPE_DRAWABLE);
 281	
 282	LLFace *face;
 283	face = new LLFace(this, mVObjp);
 284
 285	face->setTEOffset(mFaces.size());
 286	face->setTexture(texturep);
 287	face->setPoolType(gPipeline.getPoolTypeFromTE(te, texturep));
 288
 289	mFaces.push_back(face);
 290
 291	if (isState(UNLIT))
 292	{
 293		face->setState(LLFace::FULLBRIGHT);
 294	}
 295
 296	return face;
 297
 298}
 299
 300void LLDrawable::setNumFaces(const S32 newFaces, LLFacePool *poolp, LLViewerTexture *texturep)
 301{
 302	if (newFaces == (S32)mFaces.size())
 303	{
 304		return;
 305	}
 306	else if (newFaces < (S32)mFaces.size())
 307	{
 308		std::for_each(mFaces.begin() + newFaces, mFaces.end(), DeletePointer());
 309		mFaces.erase(mFaces.begin() + newFaces, mFaces.end());
 310	}
 311	else // (newFaces > mFaces.size())
 312	{
 313		mFaces.reserve(newFaces);
 314		for (int i = mFaces.size(); i<newFaces; i++)
 315		{
 316			addFace(poolp, texturep);
 317		}
 318	}
 319
 320	llassert_always(mFaces.size() == newFaces);
 321}
 322
 323void LLDrawable::setNumFacesFast(const S32 newFaces, LLFacePool *poolp, LLViewerTexture *texturep)
 324{
 325	if (newFaces <= (S32)mFaces.size() && newFaces >= (S32)mFaces.size()/2)
 326	{
 327		return;
 328	}
 329	else if (newFaces < (S32)mFaces.size())
 330	{
 331		std::for_each(mFaces.begin() + newFaces, mFaces.end(), DeletePointer());
 332		mFaces.erase(mFaces.begin() + newFaces, mFaces.end());
 333	}
 334	else // (newFaces > mFaces.size())
 335	{
 336		mFaces.reserve(newFaces);
 337		for (int i = mFaces.size(); i<newFaces; i++)
 338		{
 339			addFace(poolp, texturep);
 340		}
 341	}
 342
 343	llassert_always(mFaces.size() == newFaces) ;
 344}
 345
 346void LLDrawable::mergeFaces(LLDrawable* src)
 347{
 348	U32 face_count = mFaces.size() + src->mFaces.size();
 349
 350	mFaces.reserve(face_count);
 351	for (U32 i = 0; i < src->mFaces.size(); i++)
 352	{
 353		LLFace* facep = src->mFaces[i];
 354		facep->setDrawable(this);
 355		mFaces.push_back(facep);
 356	}
 357	src->mFaces.clear();
 358}
 359
 360void LLDrawable::deleteFaces(S32 offset, S32 count)
 361{
 362	face_list_t::iterator face_begin = mFaces.begin() + offset;
 363	face_list_t::iterator face_end = face_begin + count;
 364
 365	std::for_each(face_begin, face_end, DeletePointer());
 366	mFaces.erase(face_begin, face_end);
 367}
 368
 369void LLDrawable::update()
 370{
 371	llerrs << "Shouldn't be called!" << llendl;
 372}
 373
 374
 375void LLDrawable::updateMaterial()
 376{
 377}
 378
 379void LLDrawable::makeActive()
 380{		
 381#if !LL_RELEASE_FOR_DOWNLOAD
 382	if (mVObjp.notNull())
 383	{
 384		U32 pcode = mVObjp->getPCode();
 385		if (pcode == LLViewerObject::LL_VO_WATER ||
 386			pcode == LLViewerObject::LL_VO_VOID_WATER ||
 387			pcode == LLViewerObject::LL_VO_SURFACE_PATCH ||
 388			pcode == LLViewerObject::LL_VO_PART_GROUP ||
 389			pcode == LLViewerObject::LL_VO_HUD_PART_GROUP ||
 390			pcode == LLViewerObject::LL_VO_GROUND ||
 391			pcode == LLViewerObject::LL_VO_SKY)
 392		{
 393			llerrs << "Static viewer object has active drawable!" << llendl;
 394		}
 395	}
 396#endif
 397
 398	if (!isState(ACTIVE)) // && mGeneration > 0)
 399	{
 400		setState(ACTIVE);
 401		
 402		//parent must be made active first
 403		if (!isRoot() && !mParent->isActive())
 404		{
 405			mParent->makeActive();
 406		}
 407
 408		//all child objects must also be active
 409		llassert_always(mVObjp);
 410		
 411		LLViewerObject::const_child_list_t& child_list = mVObjp->getChildren();
 412		for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
 413			 iter != child_list.end(); iter++)
 414		{
 415			LLViewerObject* child = *iter;
 416			LLDrawable* drawable = child->mDrawable;
 417			if (drawable)
 418			{
 419				drawable->makeActive();
 420			}
 421		}
 422
 423		if (mVObjp->getPCode() == LL_PCODE_VOLUME)
 424		{
 425			if (mVObjp->isFlexible())
 426			{
 427				return;
 428			}
 429		}
 430	
 431		if (mVObjp->getPCode() == LL_PCODE_VOLUME)
 432		{
 433			gPipeline.markRebuild(this, LLDrawable::REBUILD_VOLUME, TRUE);
 434		}
 435		updatePartition();
 436	}
 437
 438	if (isRoot())
 439	{
 440		mQuietCount = 0;
 441	}
 442	else
 443	{
 444		getParent()->mQuietCount = 0;
 445	}
 446}
 447
 448
 449void LLDrawable::makeStatic(BOOL warning_enabled)
 450{
 451	if (isState(ACTIVE))
 452	{
 453		clearState(ACTIVE);
 454
 455		if (mParent.notNull() && mParent->isActive() && warning_enabled)
 456		{
 457			LL_WARNS_ONCE("Drawable") << "Drawable becomes static with active parent!" << LL_ENDL;
 458		}
 459
 460		LLViewerObject::const_child_list_t& child_list = mVObjp->getChildren();
 461		for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
 462			 iter != child_list.end(); iter++)
 463		{
 464			LLViewerObject* child = *iter;
 465			LLDrawable* child_drawable = child->mDrawable;
 466			if (child_drawable)
 467			{
 468				if (child_drawable->getParent() != this)
 469				{
 470					llwarns << "Child drawable has unknown parent." << llendl;
 471				}
 472				child_drawable->makeStatic(warning_enabled);
 473			}
 474		}
 475		
 476		if (mVObjp->getPCode() == LL_PCODE_VOLUME)
 477		{
 478			gPipeline.markRebuild(this, LLDrawable::REBUILD_VOLUME, TRUE);
 479		}		
 480		
 481		if (mSpatialBridge)
 482		{
 483			mSpatialBridge->markDead();
 484			setSpatialBridge(NULL);
 485		}
 486	}
 487	updatePartition();
 488}
 489
 490// Returns "distance" between target destination and resulting xfrom
 491F32 LLDrawable::updateXform(BOOL undamped)
 492{
 493	BOOL damped = !undamped;
 494
 495	// Position
 496	LLVector3 old_pos(mXform.getPosition());
 497	LLVector3 target_pos;
 498	if (mXform.isRoot())
 499	{
 500		// get root position in your agent's region
 501		target_pos = mVObjp->getPositionAgent();
 502	}
 503	else
 504	{
 505		// parent-relative position
 506		target_pos = mVObjp->getPosition();
 507	}
 508	
 509	// Rotation
 510	LLQuaternion old_rot(mXform.getRotation());
 511	LLQuaternion target_rot = mVObjp->getRotation();
 512	//scaling
 513	LLVector3 target_scale = mVObjp->getScale();
 514	LLVector3 old_scale = mCurrentScale;
 515	LLVector3 dest_scale = target_scale;
 516	
 517	// Damping
 518	F32 dist_squared = 0.f;
 519	F32 camdist2 = (mDistanceWRTCamera * mDistanceWRTCamera);
 520
 521	if (damped && isVisible())
 522	{
 523		F32 lerp_amt = llclamp(LLCriticalDamp::getInterpolant(OBJECT_DAMPING_TIME_CONSTANT), 0.f, 1.f);
 524		LLVector3 new_pos = lerp(old_pos, target_pos, lerp_amt);
 525		dist_squared = dist_vec_squared(new_pos, target_pos);
 526
 527		LLQuaternion new_rot = nlerp(lerp_amt, old_rot, target_rot);
 528		dist_squared += (1.f - dot(new_rot, target_rot)) * 10.f;
 529
 530		LLVector3 new_scale = lerp(old_scale, target_scale, lerp_amt);
 531		dist_squared += dist_vec_squared(new_scale, target_scale);
 532
 533		if ((dist_squared >= MIN_INTERPOLATE_DISTANCE_SQUARED * camdist2) &&
 534			(dist_squared <= MAX_INTERPOLATE_DISTANCE_SQUARED))
 535		{
 536			// interpolate
 537			target_pos = new_pos;
 538			target_rot = new_rot;
 539			target_scale = new_scale;
 540		}
 541		else
 542		{
 543			// snap to final position
 544			dist_squared = 0.0f;
 545			if (getVOVolume() && !isRoot())
 546			{ //child prim snapping to some position, needs a rebuild
 547				gPipeline.markRebuild(this, LLDrawable::REBUILD_POSITION, TRUE);
 548			}
 549		}
 550	}
 551
 552	if ((mCurrentScale != target_scale) ||
 553		(!isRoot() && 
 554		 (dist_squared >= MIN_INTERPOLATE_DISTANCE_SQUARED || 
 555		 !mVObjp->getAngularVelocity().isExactlyZero() ||
 556		 target_pos != mXform.getPosition() ||
 557		 target_rot != mXform.getRotation())))
 558	{ //child prim moving or scale change requires immediate rebuild
 559		gPipeline.markRebuild(this, LLDrawable::REBUILD_POSITION, TRUE);
 560	}
 561	else if (!getVOVolume() && !isAvatar())
 562	{
 563		movePartition();
 564	}
 565
 566	// Update
 567	mXform.setPosition(target_pos);
 568	mXform.setRotation(target_rot);
 569	mXform.setScale(LLVector3(1,1,1)); //no scale in drawable transforms (IT'S A RULE!)
 570	mXform.updateMatrix();
 571	
 572	mCurrentScale = target_scale;
 573	
 574	if (mSpatialBridge)
 575	{
 576		gPipeline.markMoved(mSpatialBridge, FALSE);
 577	}
 578	return dist_squared;
 579}
 580
 581void LLDrawable::setRadius(F32 radius)
 582{
 583	if (mRadius != radius)
 584	{
 585		mRadius = radius;
 586	}
 587}
 588
 589void LLDrawable::moveUpdatePipeline(BOOL moved)
 590{
 591	if (moved)
 592	{
 593		makeActive();
 594	}
 595	
 596	// Update the face centers.
 597	for (S32 i = 0; i < getNumFaces(); i++)
 598	{
 599		getFace(i)->updateCenterAgent();
 600	}
 601}
 602
 603void LLDrawable::movePartition()
 604{
 605	LLSpatialPartition* part = getSpatialPartition();
 606	if (part)
 607	{
 608		part->move(this, getSpatialGroup());
 609	}
 610}
 611
 612BOOL LLDrawable::updateMove()
 613{
 614	if (isDead())
 615	{
 616		llwarns << "Update move on dead drawable!" << llendl;
 617		return TRUE;
 618	}
 619	
 620	if (mVObjp.isNull())
 621	{
 622		return FALSE;
 623	}
 624	
 625	makeActive();
 626	
 627	BOOL done;
 628
 629	if (isState(MOVE_UNDAMPED))
 630	{
 631		done = updateMoveUndamped();
 632	}
 633	else
 634	{
 635		done = updateMoveDamped();
 636	}
 637	return done;
 638}
 639
 640BOOL LLDrawable::updateMoveUndamped()
 641{
 642	F32 dist_squared = updateXform(TRUE);
 643
 644	mGeneration++;
 645
 646	if (!isState(LLDrawable::INVISIBLE))
 647	{
 648		BOOL moved = (dist_squared > 0.001f && dist_squared < 255.99f);	
 649		moveUpdatePipeline(moved);
 650		mVObjp->updateText();
 651	}
 652
 653	mVObjp->clearChanged(LLXform::MOVED);
 654	
 655	return TRUE;
 656}
 657
 658void LLDrawable::updatePartition()
 659{
 660	if (!getVOVolume())
 661	{
 662		movePartition();
 663	}
 664	else if (mSpatialBridge)
 665	{
 666		gPipeline.markMoved(mSpatialBridge, FALSE);
 667	}
 668	else
 669	{
 670		//a child prim moved and needs its verts regenerated
 671		gPipeline.markRebuild(this, LLDrawable::REBUILD_POSITION, TRUE);
 672	}
 673}
 674
 675BOOL LLDrawable::updateMoveDamped()
 676{
 677	F32 dist_squared = updateXform(FALSE);
 678
 679	mGeneration++;
 680
 681	if (!isState(LLDrawable::INVISIBLE))
 682	{
 683		BOOL moved = (dist_squared > 0.001f && dist_squared < 128.0f);
 684		moveUpdatePipeline(moved);
 685		mVObjp->updateText();
 686	}
 687
 688	BOOL done_moving = (dist_squared == 0.0f) ? TRUE : FALSE;
 689
 690	if (done_moving)
 691	{
 692		mVObjp->clearChanged(LLXform::MOVED);
 693	}
 694	
 695	return done_moving;
 696}
 697
 698void LLDrawable::updateDistance(LLCamera& camera, bool force_update)
 699{
 700	if (LLViewerCamera::sCurCameraID != LLViewerCamera::CAMERA_WORLD)
 701	{
 702		llwarns << "Attempted to update distance for non-world camera." << llendl;
 703		return;
 704	}
 705
 706	//switch LOD with the spatial group to avoid artifacts
 707	//LLSpatialGroup* sg = getSpatialGroup();
 708
 709	LLVector3 pos;
 710
 711	//if (!sg || sg->changeLOD())
 712	{
 713		LLVOVolume* volume = getVOVolume();
 714		if (volume)
 715		{
 716			if (getSpatialGroup())
 717			{
 718				pos.set(getPositionGroup().getF32ptr());
 719			}
 720			else
 721			{
 722				pos = getPositionAgent();
 723			}
 724			
 725			if (isState(LLDrawable::HAS_ALPHA))
 726			{
 727				for (S32 i = 0; i < getNumFaces(); i++)
 728				{
 729					LLFace* facep = getFace(i);
 730					if (force_update || facep->getPoolType() == LLDrawPool::POOL_ALPHA)
 731					{
 732						LLVector4a box;
 733						box.setSub(facep->mExtents[1], facep->mExtents[0]);
 734						box.mul(0.25f);
 735						LLVector3 v = (facep->mCenterLocal-camera.getOrigin());
 736						const LLVector3& at = camera.getAtAxis();
 737						for (U32 j = 0; j < 3; j++)
 738						{
 739							v.mV[j] -= box[j] * at.mV[j];
 740						}
 741						facep->mDistance = v * camera.getAtAxis();
 742					}
 743				}
 744			}	
 745		}
 746		else
 747		{
 748			pos = LLVector3(getPositionGroup().getF32ptr());
 749		}
 750
 751		pos -= camera.getOrigin();	
 752		mDistanceWRTCamera = llround(pos.magVec(), 0.01f);
 753		mVObjp->updateLOD();
 754	}
 755}
 756
 757void LLDrawable::updateTexture()
 758{
 759	LLMemType mt(LLMemType::MTYPE_DRAWABLE);
 760	
 761	if (isDead())
 762	{
 763		llwarns << "Dead drawable updating texture!" << llendl;
 764		return;
 765	}
 766	
 767	if (getNumFaces() != mVObjp->getNumTEs())
 768	{ //drawable is transitioning its face count
 769		return;
 770	}
 771
 772	if (getVOVolume())
 773	{
 774		/*if (isActive())
 775		{
 776			if (isRoot())
 777			{
 778				mQuietCount = 0;
 779			}
 780			else
 781			{
 782				getParent()->mQuietCount = 0;
 783			}
 784		}*/
 785				
 786		gPipeline.markRebuild(this, LLDrawable::REBUILD_MATERIAL, TRUE);
 787	}
 788}
 789
 790BOOL LLDrawable::updateGeometry(BOOL priority)
 791{
 792	llassert(mVObjp.notNull());
 793	BOOL res = mVObjp->updateGeometry(this);
 794	return res;
 795}
 796
 797void LLDrawable::shiftPos(const LLVector4a &shift_vector)
 798{
 799	if (isDead())
 800	{
 801		llwarns << "Shifting dead drawable" << llendl;
 802		return;
 803	}
 804
 805	if (mParent)
 806	{
 807		mXform.setPosition(mVObjp->getPosition());
 808	}
 809	else
 810	{
 811		mXform.setPosition(mVObjp->getPositionAgent());
 812	}
 813
 814	mXform.setRotation(mVObjp->getRotation());
 815	mXform.setScale(1,1,1);
 816	mXform.updateMatrix();
 817
 818	if (isStatic())
 819	{
 820		LLVOVolume* volume = getVOVolume();
 821		if (!volume)
 822		{
 823			gPipeline.markRebuild(this, LLDrawable::REBUILD_ALL, TRUE);
 824		}
 825
 826		for (S32 i = 0; i < getNumFaces(); i++)
 827		{
 828			LLFace *facep = getFace(i);
 829			facep->mCenterAgent += LLVector3(shift_vector.getF32ptr());
 830			facep->mExtents[0].add(shift_vector);
 831			facep->mExtents[1].add(shift_vector);
 832			
 833			if (!volume && facep->hasGeometry())
 834			{
 835				facep->clearVertexBuffer();
 836			}
 837		}
 838		
 839		mExtents[0].add(shift_vector);
 840		mExtents[1].add(shift_vector);
 841		mPositionGroup.add(shift_vector);
 842	}
 843	else if (mSpatialBridge)
 844	{
 845		mSpatialBridge->shiftPos(shift_vector);
 846	}
 847	else if (isAvatar())
 848	{
 849		mExtents[0].add(shift_vector);
 850		mExtents[1].add(shift_vector);
 851		mPositionGroup.add(shift_vector);
 852	}
 853	
 854	mVObjp->onShift(shift_vector);
 855}
 856
 857const LLVector3& LLDrawable::getBounds(LLVector3& min, LLVector3& max) const
 858{
 859	mXform.getMinMax(min,max);
 860	return mXform.getPositionW();
 861}
 862
 863const LLVector4a* LLDrawable::getSpatialExtents() const
 864{
 865	return mExtents;
 866}
 867
 868void LLDrawable::setSpatialExtents(const LLVector3& min, const LLVector3& max)
 869{ 
 870	mExtents[0].load3(min.mV); 
 871	mExtents[1].load3(max.mV);
 872}
 873
 874void LLDrawable::setSpatialExtents(const LLVector4a& min, const LLVector4a& max)
 875{ 
 876	mExtents[0] = min; 
 877	mExtents[1] = max;
 878}
 879
 880void LLDrawable::setPositionGroup(const LLVector4a& pos)
 881{
 882	mPositionGroup = pos;
 883}
 884
 885void LLDrawable::updateSpatialExtents()
 886{
 887	if (mVObjp)
 888	{
 889		mVObjp->updateSpatialExtents(mExtents[0], mExtents[1]);
 890	}
 891	
 892	updateBinRadius();
 893	
 894	if (mSpatialBridge.notNull())
 895	{
 896		mPositionGroup.splat(0.f);
 897	}
 898}
 899
 900
 901void LLDrawable::updateBinRadius()
 902{
 903	if (mVObjp.notNull())
 904	{
 905		mBinRadius = llmin(mVObjp->getBinRadius(), 256.f);
 906	}
 907	else
 908	{
 909		mBinRadius = llmin(getRadius()*4.f, 256.f);
 910	}
 911}
 912
 913void LLDrawable::updateSpecialHoverCursor(BOOL enabled)
 914{
 915	// TODO: maintain a list of objects that have special
 916	// hover cursors, then use that list for per-frame
 917	// hover cursor selection. JC
 918}
 919
 920F32 LLDrawable::getVisibilityRadius() const
 921{
 922	if (isDead())
 923	{
 924		return 0.f;
 925	}
 926	else if (isLight())
 927	{
 928		const LLVOVolume *vov = getVOVolume();
 929		if (vov)
 930		{
 931			return llmax(getRadius(), vov->getLightRadius());
 932		} else {
 933			// llwarns ?
 934		}
 935	}
 936	return getRadius();
 937}
 938
 939void LLDrawable::updateUVMinMax()
 940{
 941}
 942
 943void LLDrawable::setSpatialGroup(LLSpatialGroup *groupp)
 944{
 945/*if (mSpatialGroupp && (groupp != mSpatialGroupp))
 946	{
 947		mSpatialGroupp->setState(LLSpatialGroup::GEOM_DIRTY);
 948	}*/
 949
 950	if (mSpatialGroupp != groupp && getVOVolume())
 951	{ //NULL out vertex buffer references for volumes on spatial group change to maintain
 952		//requirement that every face vertex buffer is either NULL or points to a vertex buffer
 953		//contained by its drawable's spatial group
 954		for (S32 i = 0; i < getNumFaces(); ++i)
 955		{
 956			LLFace* facep = getFace(i);
 957			facep->clearVertexBuffer();
 958		}
 959	}
 960
 961	mSpatialGroupp = groupp;
 962}
 963
 964LLSpatialPartition* LLDrawable::getSpatialPartition()
 965{ 
 966	LLSpatialPartition* retval = NULL;
 967	
 968	if (!mVObjp || 
 969		!getVOVolume() ||
 970		isStatic())
 971	{
 972		retval = gPipeline.getSpatialPartition((LLViewerObject*) mVObjp);
 973	}
 974	else if (isRoot())
 975	{	//must be an active volume
 976		if (!mSpatialBridge)
 977		{
 978			if (mVObjp->isHUDAttachment())
 979			{
 980				setSpatialBridge(new LLHUDBridge(this));
 981			}
 982			else
 983			{
 984				setSpatialBridge(new LLVolumeBridge(this));
 985			}
 986		}
 987		return mSpatialBridge->asPartition();
 988	}
 989	else 
 990	{
 991		retval = getParent()->getSpatialPartition();
 992	}
 993	
 994	if (retval && mSpatialBridge.notNull())
 995	{
 996		mSpatialBridge->markDead();
 997		setSpatialBridge(NULL);
 998	}
 999	
1000	return retval;
1001}
1002
1003const S32 MIN_VIS_FRAME_RANGE = 2 ; //two frames:the current one and the last one.
1004//static 
1005S32 LLDrawable::getMinVisFrameRange()
1006{
1007	return MIN_VIS_FRAME_RANGE ;
1008}
1009
1010BOOL LLDrawable::isRecentlyVisible() const
1011{
1012	//currently visible or visible in the previous frame.
1013	BOOL vis = isVisible() || (sCurVisible - mVisible < MIN_VIS_FRAME_RANGE)  ;
1014
1015	if(!vis)
1016	{
1017		LLSpatialGroup* group = getSpatialGroup();
1018		if (group && group->isRecentlyVisible())
1019		{
1020			mVisible = sCurVisible;
1021			vis = TRUE ;
1022		}
1023	}
1024
1025	return vis ;
1026}
1027
1028BOOL LLDrawable::isVisible() const
1029{
1030	if (mVisible == sCurVisible)
1031	{
1032		return TRUE;
1033	}
1034	
1035#if 0
1036	//disabling this code fixes DEV-20105.  Leaving in place in case some other bug pops up as a a result.
1037	//should be safe to just always ask the spatial group for visibility.
1038	if (isActive())
1039	{
1040		if (isRoot())
1041		{
1042			LLSpatialGroup* group = mSpatialBridge.notNull() ? mSpatialBridge->getSpatialGroup() :
1043									getSpatialGroup();
1044			if (group && group->isVisible())
1045			{
1046				mVisible = sCurVisible;
1047				return TRUE;
1048			}
1049		}
1050		else
1051		{
1052			if (getParent()->isVisible())
1053			{
1054				mVisible = sCurVisible;
1055				return TRUE;
1056			}
1057		}
1058	}
1059	else
1060#endif
1061	{
1062		LLSpatialGroup* group = getSpatialGroup();
1063		if (group && group->isVisible())
1064		{
1065			mVisible = sCurVisible;
1066			return TRUE;
1067		}
1068	}
1069
1070	return FALSE;
1071}
1072
1073//=======================================
1074// Spatial Partition Bridging Drawable
1075//=======================================
1076
1077LLSpatialBridge::LLSpatialBridge(LLDrawable* root, BOOL render_by_group, U32 data_mask)
1078: LLSpatialPartition(data_mask, render_by_group, GL_STREAM_DRAW_ARB)
1079{
1080	mDrawable = root;
1081	root->setSpatialBridge(this);
1082	
1083	mRenderType = mDrawable->mRenderType;
1084	mDrawableType = mDrawable->mRenderType;
1085	
1086	mPartitionType = LLViewerRegion::PARTITION_VOLUME;
1087	
1088	mOctree->balance();
1089
1090	llassert(mDrawable);
1091	llassert(mDrawable->getRegion());
1092	LLSpatialPartition *part = mDrawable->getRegion()->getSpatialPartition(mPartitionType);
1093	llassert(part);
1094	
1095	if (part)
1096	{
1097		part->put(this);
1098	}
1099}
1100
1101LLSpatialBridge::~LLSpatialBridge()
1102{	
1103	LLSpatialGroup* group = getSpatialGroup();
1104	if (group)
1105	{
1106		group->mSpatialPartition->remove(this, group);
1107	}
1108}
1109
1110void LLSpatialBridge::updateSpatialExtents()
1111{
1112	LLSpatialGroup* root = (LLSpatialGroup*) mOctree->getListener(0);
1113	
1114	{
1115		LLFastTimer ftm(FTM_CULL_REBOUND);
1116		root->rebound();
1117	}
1118	
1119	LLVector4a offset;
1120	LLVector4a size = root->mBounds[1];
1121		
1122	//VECTORIZE THIS
1123	LLMatrix4a mat;
1124	mat.loadu(mDrawable->getXform()->getWorldMatrix());
1125
1126	LLVector4a t;
1127	t.splat(0.f);
1128
1129	LLVector4a center;
1130	mat.affineTransform(t, center);
1131	
1132	mat.rotate(root->mBounds[0], offset);
1133	center.add(offset);
1134	
1135	LLVector4a v[4];
1136
1137	//get 4 corners of bounding box
1138	mat.rotate(size,v[0]);
1139
1140	LLVector4a scale;
1141	
1142	scale.set(-1.f, -1.f, 1.f);
1143	scale.mul(size);
1144	mat.rotate(scale, v[1]);
1145	
1146	scale.set(1.f, -1.f, -1.f);
1147	scale.mul(size);
1148	mat.rotate(scale, v[2]);
1149	
1150	scale.set(-1.f, 1.f, -1.f);
1151	scale.mul(size);
1152	mat.rotate(scale, v[3]);
1153
1154	
1155	LLVector4a& newMin = mExtents[0];
1156	LLVector4a& newMax = mExtents[1];
1157	
1158	newMin = newMax = center;
1159	
1160	for (U32 i = 0; i < 4; i++)
1161	{
1162		LLVector4a delta;
1163		delta.setAbs(v[i]);
1164		LLVector4a min;
1165		min.setSub(center, delta);
1166		LLVector4a max;
1167		max.setAdd(center, delta);
1168
1169		newMin.setMin(newMin, min);
1170		newMax.setMax(newMax, max);
1171	}
1172	
1173	LLVector4a diagonal;
1174	diagonal.setSub(newMax, newMin);
1175	mRadius = diagonal.getLength3().getF32() * 0.5f;
1176	
1177	mPositionGroup.setAdd(newMin,newMax);
1178	mPositionGroup.mul(0.5f);
1179	updateBinRadius();
1180}
1181
1182void LLSpatialBridge::updateBinRadius()
1183{
1184	mBinRadius = llmin( mOctree->getSize()[0]*0.5f, 256.f);
1185}
1186
1187LLCamera LLSpatialBridge::transformCamera(LLCamera& camera)
1188{
1189	LLCamera ret = camera;
1190	LLXformMatrix* mat = mDrawable->getXform();
1191	LLVector3 center = LLVector3(0,0,0) * mat->getWorldMatrix();
1192	LLQuaternion rotation = LLQuaternion(mat->getWorldMatrix());
1193
1194	LLVector3 delta = ret.getOrigin() - center;
1195	LLQuaternion rot = ~mat->getRotation();
1196
1197	delta *= rot;
1198	LLVector3 lookAt = ret.getAtAxis();
1199	LLVector3 up_axis = ret.getUpAxis();
1200	LLVector3 left_axis = ret.getLeftAxis();
1201
1202	lookAt *= rot;
1203	up_axis *= rot;
1204	left_axis *= rot;
1205
1206	if (!delta.isFinite())
1207	{
1208		delta.clearVec();
1209	}
1210
1211	ret.setOrigin(delta);
1212	ret.setAxes(lookAt, left_axis, up_axis);
1213		
1214	return ret;
1215}
1216
1217void LLDrawable::setVisible(LLCamera& camera, std::vector<LLDrawable*>* results, BOOL for_select)
1218{
1219	mVisible = sCurVisible;
1220	
1221#if 0 && !LL_RELEASE_FOR_DOWNLOAD
1222	//crazy paranoid rules checking
1223	if (getVOVolume())
1224	{
1225		if (!isRoot())
1226		{
1227			if (isActive() && !mParent->isActive())
1228			{
1229				llerrs << "Active drawable has static parent!" << llendl;
1230			}
1231			
1232			if (isStatic() && !mParent->isStatic())
1233			{
1234				llerrs << "Static drawable has active parent!" << llendl;
1235			}
1236			
1237			if (mSpatialBridge)
1238			{
1239				llerrs << "Child drawable has spatial bridge!" << llendl;
1240			}
1241		}
1242		else if (isActive() && !mSpatialBridge)
1243		{
1244			llerrs << "Active root drawable has no spatial bridge!" << llendl;
1245		}
1246		else if (isStatic() && mSpatialBridge.notNull())
1247		{
1248			llerrs << "Static drawable has spatial bridge!" << llendl;
1249		}
1250	}
1251#endif
1252}
1253
1254class LLOctreeMarkNotCulled: public LLOctreeTraveler<LLDrawable>
1255{
1256public:
1257	LLCamera* mCamera;
1258	
1259	LLOctreeMarkNotCulled(LLCamera* camera_in) : mCamera(camera_in) { }
1260	
1261	virtual void traverse(const LLOctreeNode<LLDrawable>* node)
1262	{
1263		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
1264		group->setVisible();
1265		LLOctreeTraveler<LLDrawable>::traverse(node);
1266	}
1267	
1268	void visit(const LLOctreeNode<LLDrawable>* branch)
1269	{
1270		gPipeline.markNotCulled((LLSpatialGroup*) branch->getListener(0), *mCamera);
1271	}
1272};
1273
1274void LLSpatialBridge::setVisible(LLCamera& camera_in, std::vector<LLDrawable*>* results, BOOL for_select)
1275{
1276	if (!gPipeline.hasRenderType(mDrawableType))
1277	{
1278		return;
1279	}
1280
1281
1282	//HACK don't draw attachments for avatars that haven't been visible in more than a frame
1283	LLViewerObject *vobj = mDrawable->getVObj();
1284	if (vobj && vobj->isAttachment() && !vobj->isHUDAttachment())
1285	{
1286		LLDrawable* av;
1287		LLDrawable* parent = mDrawable->getParent();
1288
1289		if (parent)
1290		{
1291			LLViewerObject* objparent = parent->getVObj();
1292			av = objparent->mDrawable;
1293			LLSpatialGroup* group = av->getSpatialGroup();
1294
1295			BOOL impostor = FALSE;
1296			BOOL loaded = FALSE;
1297			if (objparent->isAvatar())
1298			{
1299				LLVOAvatar* avatarp = (LLVOAvatar*) objparent;
1300				if (avatarp->isVisible())
1301				{
1302					impostor = objparent->isAvatar() && ((LLVOAvatar*) objparent)->isImpostor();
1303					loaded   = objparent->isAvatar() && ((LLVOAvatar*) objparent)->isFullyLoaded();
1304				}
1305				else
1306				{
1307					return;
1308				}
1309			}
1310
1311			if (!group ||
1312				LLDrawable::getCurrentFrame() - av->mVisible > 1 ||
1313				impostor ||
1314				!loaded)
1315			{
1316				return;
1317			}
1318		}
1319	}
1320	
1321
1322	LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0);
1323	group->rebound();
1324	
1325	LLVector4a center;
1326	center.setAdd(mExtents[0], mExtents[1]);
1327	center.mul(0.5f);
1328	LLVector4a size;
1329	size.setSub(mExtents[1], mExtents[0]);
1330	size.mul(0.5f);
1331
1332	if ((LLPipeline::sShadowRender && camera_in.AABBInFrustum(center, size)) ||
1333		LLPipeline::sImpostorRender ||
1334		(camera_in.AABBInFrustumNoFarClip(center, size) && 
1335		AABBSphereIntersect(mExtents[0], mExtents[1], camera_in.getOrigin(), camera_in.mFrustumCornerDist)))
1336	{
1337		if (!LLPipeline::sImpostorRender &&
1338			!LLPipeline::sShadowRender && 
1339			LLPipeline::calcPixelArea(center, size, camera_in) < FORCE_INVISIBLE_AREA)
1340		{
1341			return;
1342		}
1343
1344		LLDrawable::setVisible(camera_in);
1345		
1346		if (for_select)
1347		{
1348			results->push_back(mDrawable);
1349			if (mDrawable->getVObj())
1350			{
1351				LLViewerObject::const_child_list_t& child_list = mDrawable->getVObj()->getChildren();
1352				for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
1353					 iter != child_list.end(); iter++)
1354				{
1355					LLViewerObject* child = *iter;
1356					LLDrawable* drawable = child->mDrawable;					
1357					results->push_back(drawable);
1358				}
1359			}
1360		}
1361		else 
1362		{
1363			LLCamera trans_camera = transformCamera(camera_in);
1364			LLOctreeMarkNotCulled culler(&trans_camera);
1365			culler.traverse(mOctree);
1366		}		
1367	}
1368}
1369
1370void LLSpatialBridge::updateDistance(LLCamera& camera_in, bool force_update)
1371{
1372	if (mDrawable == NULL)
1373	{
1374		markDead();
1375		return;
1376	}
1377
1378	if (mDrawable->getVObj())
1379	{
1380		if (mDrawable->getVObj()->isAttachment())
1381		{
1382			LLDrawable* parent = mDrawable->getParent();
1383			if (parent && parent->getVObj())
1384			{
1385				LLVOAvatar* av = parent->getVObj()->asAvatar();
1386				if (av && av->isImpostor())
1387				{
1388					return;
1389				}
1390			}
1391		}
1392
1393		LLCamera camera = transformCamera(camera_in);
1394	
1395		mDrawable->updateDistance(camera, force_update);
1396	
1397		LLViewerObject::const_child_list_t& child_list = mDrawable->getVObj()->getChildren();
1398		for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
1399			 iter != child_list.end(); iter++)
1400		{
1401			LLViewerObject* child = *iter;
1402			LLDrawable* drawable = child->mDrawable;					
1403			if (!drawable)
1404			{
1405				continue;
1406			}
1407
1408			if (!drawable->isAvatar())
1409			{
1410				drawable->updateDistance(camera, force_update);
1411			}
1412		}
1413	}
1414}
1415
1416void LLSpatialBridge::makeActive()
1417{ //it is an error to make a spatial bridge active (it's already active)
1418	llerrs << "makeActive called on spatial bridge" << llendl;
1419}
1420
1421void LLSpatialBridge::move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL immediate)
1422{
1423	LLSpatialPartition::move(drawablep, curp, immediate);
1424	gPipeline.markMoved(this, FALSE);
1425}
1426
1427BOOL LLSpatialBridge::updateMove()
1428{
1429	llassert_always(mDrawable);
1430	llassert_always(mDrawable->mVObjp);
1431	llassert_always(mDrawable->getRegion());
1432	LLSpatialPartition* part = mDrawable->getRegion()->getSpatialPartition(mPartitionType);
1433	llassert_always(part);
1434
1435	mOctree->balance();
1436	if (part)
1437	{
1438		part->move(this, getSpatialGroup(), TRUE);
1439	}
1440	return TRUE;
1441}
1442
1443void LLSpatialBridge::shiftPos(const LLVector4a& vec)
1444{
1445	mExtents[0].add(vec);
1446	mExtents[1].add(vec);
1447	mPositionGroup.add(vec);
1448}
1449
1450void LLSpatialBridge::cleanupReferences()
1451{	
1452	LLDrawable::cleanupReferences();
1453	if (mDrawable)
1454	{
1455		mDrawable->setSpatialGroup(NULL);
1456		if (mDrawable->getVObj())
1457		{
1458			LLViewerObject::const_child_list_t& child_list = mDrawable->getVObj()->getChildren();
1459			for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
1460				 iter != child_list.end(); iter++)
1461			{
1462				LLViewerObject* child = *iter;
1463				LLDrawable* drawable = child->mDrawable;					
1464				if (drawable)
1465				{
1466					drawable->setSpatialGroup(NULL);
1467				}
1468			}
1469		}
1470
1471		LLDrawable* drawablep = mDrawable;
1472		mDrawable = NULL;
1473		drawablep->setSpatialBridge(NULL);
1474	}
1475}
1476
1477const LLVector3	LLDrawable::getPositionAgent() const
1478{
1479	if (getVOVolume())
1480	{
1481		if (isActive())
1482		{
1483			LLVector3 pos(0,0,0);
1484			if (!isRoot())
1485			{
1486				pos = mVObjp->getPosition();
1487			}
1488			return pos * getRenderMatrix();
1489		}
1490		else
1491		{
1492			return mVObjp->getPositionAgent();
1493		}
1494	}
1495	else
1496	{
1497		return getWorldPosition();
1498	}
1499}
1500
1501BOOL LLDrawable::isAnimating() const
1502{
1503	if (!getVObj())
1504	{
1505		return TRUE;
1506	}
1507
1508	if (getScale() != mVObjp->getScale())
1509	{
1510		return TRUE;
1511	}
1512
1513	if (mVObjp->getPCode() == LLViewerObject::LL_VO_PART_GROUP)
1514	{
1515		return TRUE;
1516	}
1517	if (mVObjp->getPCode() == LLViewerObject::LL_VO_HUD_PART_GROUP)
1518	{
1519		return TRUE;
1520	}
1521
1522	if (!isRoot() && !mVObjp->getAngularVelocity().isExactlyZero())
1523	{
1524		return TRUE;
1525	}
1526
1527	return FALSE;
1528}
1529
1530void LLDrawable::updateFaceSize(S32 idx)
1531{
1532	if (mVObjp.notNull())
1533	{
1534		mVObjp->updateFaceSize(idx);
1535	}
1536}
1537
1538LLBridgePartition::LLBridgePartition()
1539: LLSpatialPartition(0, FALSE, 0) 
1540{ 
1541	mDrawableType = LLPipeline::RENDER_TYPE_AVATAR; 
1542	mPartitionType = LLViewerRegion::PARTITION_BRIDGE;
1543	mLODPeriod = 16;
1544	mSlopRatio = 0.25f;
1545}
1546
1547LLHUDBridge::LLHUDBridge(LLDrawable* drawablep)
1548: LLVolumeBridge(drawablep)
1549{
1550	mDrawableType = LLPipeline::RENDER_TYPE_HUD;
1551	mPartitionType = LLViewerRegion::PARTITION_HUD;
1552	mSlopRatio = 0.0f;
1553}
1554
1555F32 LLHUDBridge::calcPixelArea(LLSpatialGroup* group, LLCamera& camera)
1556{
1557	return 1024.f;
1558}
1559
1560
1561void LLHUDBridge::shiftPos(const LLVector4a& vec)
1562{
1563	//don't shift hud bridges on region crossing
1564}
1565