diff options
| -rw-r--r-- | indra/newview/lldrawpoolalpha.cpp | 8 | ||||
| -rw-r--r-- | indra/newview/llface.cpp | 32 | ||||
| -rw-r--r-- | indra/newview/llvovolume.cpp | 9402 | 
3 files changed, 4728 insertions, 4714 deletions
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index a2a109d5ee..2cfd3b0a33 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -210,7 +210,7 @@ void LLDrawPoolAlpha::render(S32 pass)  		gGL.setColorMask(true, true);  	} -	if (LLPipeline::sAutoMaskAlphaNonDeferred && !deferred_render) +	if (LLPipeline::sAutoMaskAlphaNonDeferred)  	{  		mColorSFactor = LLRender::BF_ONE;  // }  		mColorDFactor = LLRender::BF_ZERO; // } these are like disabling blend on the color channels, but we're still blending on the alpha channel so that we can suppress glow @@ -226,7 +226,10 @@ void LLDrawPoolAlpha::render(S32 pass)  				simple_shader->bind();  				pushBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask());  			} -			fullbright_shader->bind(); +			if (fullbright_shader) +			{ +				fullbright_shader->bind(); +			}  			pushBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, getVertexDataMask());  			LLGLSLShader::bindNoShader();  		} @@ -273,6 +276,7 @@ void LLDrawPoolAlpha::render(S32 pass)  	if (deferred_render && pass == 1)  	{  		gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); +		gGL.setSceneBlendType(LLRender::BT_ALPHA);  	}  	if (deferred_render && current_shader != NULL) diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index ae455a8287..5398c13c44 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -979,19 +979,29 @@ bool LLFace::canRenderAsMask()  	}  	const LLTextureEntry* te = getTextureEntry(); -	return ( -		( -		 (LLPipeline::sRenderDeferred && LLPipeline::sAutoMaskAlphaDeferred) || -		  -		 (!LLPipeline::sRenderDeferred && LLPipeline::sAutoMaskAlphaNonDeferred)		  -		 ) // do we want masks at all? -		&& -		(te->getColor().mV[3] == 1.0f) && // can't treat as mask if we have face alpha -		!(LLPipeline::sRenderDeferred && te->getFullbright()) && // hack: alpha masking renders fullbright faces invisible in deferred rendering mode, need to figure out why - for now, avoid + +	if ((te->getColor().mV[3] == 1.0f) && // can't treat as mask if we have face alpha  		(te->getGlow() == 0.f) && // glowing masks are hard to implement - don't mask +		getTexture()->getIsAlphaMask()) // texture actually qualifies for masking (lazily recalculated but expensive) +	{ +		if (LLPipeline::sRenderDeferred) +		{ +			if (getViewerObject()->isHUDAttachment() || te->getFullbright()) +			{ //hud attachments and fullbright objects are NOT subject to the deferred rendering pipe +				return LLPipeline::sAutoMaskAlphaNonDeferred; +			} +			else +			{ +				return LLPipeline::sAutoMaskAlphaDeferred; +			} +		} +		else +		{ +			return LLPipeline::sAutoMaskAlphaNonDeferred; +		} +	} -		getTexture()->getIsAlphaMask() // texture actually qualifies for masking (lazily recalculated but expensive) -		); +	return false;  } diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 45277265df..9d2887d2e8 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -1,4709 +1,4709 @@ -/** 
 - * @file llvovolume.cpp
 - * @brief LLVOVolume class implementation
 - *
 - * $LicenseInfo:firstyear=2001&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$
 - */
 -
 -// A "volume" is a box, cylinder, sphere, or other primitive shape.
 -
 -#include "llviewerprecompiledheaders.h"
 -
 -#include "llvovolume.h"
 -
 -#include <sstream>
 -
 -#include "llviewercontrol.h"
 -#include "lldir.h"
 -#include "llflexibleobject.h"
 -#include "llfloatertools.h"
 -#include "llmaterialtable.h"
 -#include "llprimitive.h"
 -#include "llvolume.h"
 -#include "llvolumeoctree.h"
 -#include "llvolumemgr.h"
 -#include "llvolumemessage.h"
 -#include "material_codes.h"
 -#include "message.h"
 -#include "llpluginclassmedia.h" // for code in the mediaEvent handler
 -#include "object_flags.h"
 -#include "llagentconstants.h"
 -#include "lldrawable.h"
 -#include "lldrawpoolavatar.h"
 -#include "lldrawpoolbump.h"
 -#include "llface.h"
 -#include "llspatialpartition.h"
 -#include "llhudmanager.h"
 -#include "llflexibleobject.h"
 -#include "llsky.h"
 -#include "lltexturefetch.h"
 -#include "llvector4a.h"
 -#include "llviewercamera.h"
 -#include "llviewertexturelist.h"
 -#include "llviewerobjectlist.h"
 -#include "llviewerregion.h"
 -#include "llviewertextureanim.h"
 -#include "llworld.h"
 -#include "llselectmgr.h"
 -#include "pipeline.h"
 -#include "llsdutil.h"
 -#include "llmatrix4a.h"
 -#include "llmediaentry.h"
 -#include "llmediadataclient.h"
 -#include "llmeshrepository.h"
 -#include "llagent.h"
 -#include "llviewermediafocus.h"
 -#include "llvoavatar.h"
 -
 -const S32 MIN_QUIET_FRAMES_COALESCE = 30;
 -const F32 FORCE_SIMPLE_RENDER_AREA = 512.f;
 -const F32 FORCE_CULL_AREA = 8.f;
 -const F32 MAX_LOD_DISTANCE = 24.f;
 -
 -
 -BOOL gAnimateTextures = TRUE;
 -//extern BOOL gHideSelectedObjects;
 -
 -F32 LLVOVolume::sLODFactor = 1.f;
 -F32	LLVOVolume::sLODSlopDistanceFactor = 0.5f; //Changing this to zero, effectively disables the LOD transition slop 
 -F32 LLVOVolume::sDistanceFactor = 1.0f;
 -S32 LLVOVolume::sNumLODChanges = 0;
 -LLPointer<LLObjectMediaDataClient> LLVOVolume::sObjectMediaClient = NULL;
 -LLPointer<LLObjectMediaNavigateClient> LLVOVolume::sObjectMediaNavigateClient = NULL;
 -
 -static LLFastTimer::DeclareTimer FTM_GEN_TRIANGLES("Generate Triangles");
 -static LLFastTimer::DeclareTimer FTM_GEN_VOLUME("Generate Volumes");
 -static LLFastTimer::DeclareTimer FTM_VOLUME_TEXTURES("Volume Textures");
 -
 -// Implementation class of LLMediaDataClientObject.  See llmediadataclient.h
 -class LLMediaDataClientObjectImpl : public LLMediaDataClientObject
 -{
 -public:
 -	LLMediaDataClientObjectImpl(LLVOVolume *obj, bool isNew) : mObject(obj), mNew(isNew) 
 -	{
 -		mObject->addMDCImpl();
 -	}
 -	~LLMediaDataClientObjectImpl()
 -	{
 -		mObject->removeMDCImpl();
 -	}
 -	
 -	virtual U8 getMediaDataCount() const 
 -		{ return mObject->getNumTEs(); }
 -
 -	virtual LLSD getMediaDataLLSD(U8 index) const 
 -		{
 -			LLSD result;
 -			LLTextureEntry *te = mObject->getTE(index); 
 -			if (NULL != te)
 -			{
 -				llassert((te->getMediaData() != NULL) == te->hasMedia());
 -				if (te->getMediaData() != NULL)
 -				{
 -					result = te->getMediaData()->asLLSD();
 -					// XXX HACK: workaround bug in asLLSD() where whitelist is not set properly
 -					// See DEV-41949
 -					if (!result.has(LLMediaEntry::WHITELIST_KEY))
 -					{
 -						result[LLMediaEntry::WHITELIST_KEY] = LLSD::emptyArray();
 -					}
 -				}
 -			}
 -			return result;
 -		}
 -	virtual bool isCurrentMediaUrl(U8 index, const std::string &url) const
 -		{
 -			LLTextureEntry *te = mObject->getTE(index); 
 -			if (te)
 -			{
 -				if (te->getMediaData())
 -				{
 -					return (te->getMediaData()->getCurrentURL() == url);
 -				}
 -			}
 -			return url.empty();
 -		}
 -
 -	virtual LLUUID getID() const
 -		{ return mObject->getID(); }
 -
 -	virtual void mediaNavigateBounceBack(U8 index)
 -		{ mObject->mediaNavigateBounceBack(index); }
 -	
 -	virtual bool hasMedia() const
 -		{ return mObject->hasMedia(); }
 -	
 -	virtual void updateObjectMediaData(LLSD const &data, const std::string &version_string) 
 -		{ mObject->updateObjectMediaData(data, version_string); }
 -	
 -	virtual F64 getMediaInterest() const 
 -		{ 
 -			F64 interest = mObject->getTotalMediaInterest();
 -			if (interest < (F64)0.0)
 -			{
 -				// media interest not valid yet, try pixel area
 -				interest = mObject->getPixelArea();
 -				// HACK: force recalculation of pixel area if interest is the "magic default" of 1024.
 -				if (interest == 1024.f)
 -				{
 -					const_cast<LLVOVolume*>(static_cast<LLVOVolume*>(mObject))->setPixelAreaAndAngle(gAgent);
 -					interest = mObject->getPixelArea();
 -				}
 -			}
 -			return interest; 
 -		}
 -	
 -	virtual bool isInterestingEnough() const
 -		{
 -			return LLViewerMedia::isInterestingEnough(mObject, getMediaInterest());
 -		}
 -
 -	virtual std::string getCapabilityUrl(const std::string &name) const
 -		{ return mObject->getRegion()->getCapability(name); }
 -	
 -	virtual bool isDead() const
 -		{ return mObject->isDead(); }
 -	
 -	virtual U32 getMediaVersion() const
 -		{ return LLTextureEntry::getVersionFromMediaVersionString(mObject->getMediaURL()); }
 -	
 -	virtual bool isNew() const
 -		{ return mNew; }
 -
 -private:
 -	LLPointer<LLVOVolume> mObject;
 -	bool mNew;
 -};
 -
 -
 -LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
 -	: LLViewerObject(id, pcode, regionp),
 -	  mVolumeImpl(NULL)
 -{
 -	mTexAnimMode = 0;
 -	mRelativeXform.setIdentity();
 -	mRelativeXformInvTrans.setIdentity();
 -
 -	mFaceMappingChanged = FALSE;
 -	mLOD = MIN_LOD;
 -	mTextureAnimp = NULL;
 -	mVolumeChanged = FALSE;
 -	mVObjRadius = LLVector3(1,1,0.5f).length();
 -	mNumFaces = 0;
 -	mLODChanged = FALSE;
 -	mSculptChanged = FALSE;
 -	mSpotLightPriority = 0.f;
 -
 -	mMediaImplList.resize(getNumTEs());
 -	mLastFetchedMediaVersion = -1;
 -	mIndexInTex = 0;
 -	mMDCImplCount = 0;
 -}
 -
 -LLVOVolume::~LLVOVolume()
 -{
 -	delete mTextureAnimp;
 -	mTextureAnimp = NULL;
 -	delete mVolumeImpl;
 -	mVolumeImpl = NULL;
 -
 -	if(!mMediaImplList.empty())
 -	{
 -		for(U32 i = 0 ; i < mMediaImplList.size() ; i++)
 -		{
 -			if(mMediaImplList[i].notNull())
 -			{
 -				mMediaImplList[i]->removeObject(this) ;
 -			}
 -		}
 -	}
 -}
 -
 -void LLVOVolume::markDead()
 -{
 -	if (!mDead)
 -	{
 -		if(getMDCImplCount() > 0)
 -		{
 -			LLMediaDataClientObject::ptr_t obj = new LLMediaDataClientObjectImpl(const_cast<LLVOVolume*>(this), false);
 -			if (sObjectMediaClient) sObjectMediaClient->removeFromQueue(obj);
 -			if (sObjectMediaNavigateClient) sObjectMediaNavigateClient->removeFromQueue(obj);
 -		}
 -		
 -		// Detach all media impls from this object
 -		for(U32 i = 0 ; i < mMediaImplList.size() ; i++)
 -		{
 -			removeMediaImpl(i);
 -		}
 -
 -		if (mSculptTexture.notNull())
 -		{
 -			mSculptTexture->removeVolume(this);
 -		}
 -	}
 -	
 -	LLViewerObject::markDead();
 -}
 -
 -
 -// static
 -void LLVOVolume::initClass()
 -{
 -	// gSavedSettings better be around
 -	if (gSavedSettings.getBOOL("PrimMediaMasterEnabled"))
 -	{
 -		const F32 queue_timer_delay = gSavedSettings.getF32("PrimMediaRequestQueueDelay");
 -		const F32 retry_timer_delay = gSavedSettings.getF32("PrimMediaRetryTimerDelay");
 -		const U32 max_retries = gSavedSettings.getU32("PrimMediaMaxRetries");
 -		const U32 max_sorted_queue_size = gSavedSettings.getU32("PrimMediaMaxSortedQueueSize");
 -		const U32 max_round_robin_queue_size = gSavedSettings.getU32("PrimMediaMaxRoundRobinQueueSize");
 -		sObjectMediaClient = new LLObjectMediaDataClient(queue_timer_delay, retry_timer_delay, max_retries, 
 -														 max_sorted_queue_size, max_round_robin_queue_size);
 -		sObjectMediaNavigateClient = new LLObjectMediaNavigateClient(queue_timer_delay, retry_timer_delay, 
 -																	 max_retries, max_sorted_queue_size, max_round_robin_queue_size);
 -	}
 -}
 -
 -// static
 -void LLVOVolume::cleanupClass()
 -{
 -    sObjectMediaClient = NULL;
 -    sObjectMediaNavigateClient = NULL;
 -}
 -
 -U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys,
 -										  void **user_data,
 -										  U32 block_num, EObjectUpdateType update_type,
 -										  LLDataPacker *dp)
 -{
 -	LLColor4U color;
 -	const S32 teDirtyBits = (TEM_CHANGE_TEXTURE|TEM_CHANGE_COLOR|TEM_CHANGE_MEDIA);
 -
 -	// Do base class updates...
 -	U32 retval = LLViewerObject::processUpdateMessage(mesgsys, user_data, block_num, update_type, dp);
 -
 -	LLUUID sculpt_id;
 -	U8 sculpt_type = 0;
 -	if (isSculpted())
 -	{
 -		LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT);
 -		sculpt_id = sculpt_params->getSculptTexture();
 -		sculpt_type = sculpt_params->getSculptType();
 -	}
 -
 -	if (!dp)
 -	{
 -		if (update_type == OUT_FULL)
 -		{
 -			////////////////////////////////
 -			//
 -			// Unpack texture animation data
 -			//
 -			//
 -
 -			if (mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_TextureAnim))
 -			{
 -				if (!mTextureAnimp)
 -				{
 -					mTextureAnimp = new LLViewerTextureAnim();
 -				}
 -				else
 -				{
 -					if (!(mTextureAnimp->mMode & LLTextureAnim::SMOOTH))
 -					{
 -						mTextureAnimp->reset();
 -					}
 -				}
 -				mTexAnimMode = 0;
 -				mTextureAnimp->unpackTAMessage(mesgsys, block_num);
 -			}
 -			else
 -			{
 -				if (mTextureAnimp)
 -				{
 -					delete mTextureAnimp;
 -					mTextureAnimp = NULL;
 -					gPipeline.markTextured(mDrawable);
 -					mFaceMappingChanged = TRUE;
 -					mTexAnimMode = 0;
 -				}
 -			}
 -
 -			// Unpack volume data
 -			LLVolumeParams volume_params;
 -			LLVolumeMessage::unpackVolumeParams(&volume_params, mesgsys, _PREHASH_ObjectData, block_num);
 -			volume_params.setSculptID(sculpt_id, sculpt_type);
 -
 -			if (setVolume(volume_params, 0))
 -			{
 -				markForUpdate(TRUE);
 -			}
 -		}
 -
 -		// Sigh, this needs to be done AFTER the volume is set as well, otherwise bad stuff happens...
 -		////////////////////////////
 -		//
 -		// Unpack texture entry data
 -		//
 -		S32 result = unpackTEMessage(mesgsys, _PREHASH_ObjectData, block_num);
 -		if (result & teDirtyBits)
 -		{
 -			updateTEData();
 -		}
 -		if (result & TEM_CHANGE_MEDIA)
 -		{
 -			retval |= MEDIA_FLAGS_CHANGED;
 -		}
 -	}
 -	else
 -	{
 -		// CORY TO DO: Figure out how to get the value here
 -		if (update_type != OUT_TERSE_IMPROVED)
 -		{
 -			LLVolumeParams volume_params;
 -			BOOL res = LLVolumeMessage::unpackVolumeParams(&volume_params, *dp);
 -			if (!res)
 -			{
 -				llwarns << "Bogus volume parameters in object " << getID() << llendl;
 -				llwarns << getRegion()->getOriginGlobal() << llendl;
 -			}
 -
 -			volume_params.setSculptID(sculpt_id, sculpt_type);
 -
 -			if (setVolume(volume_params, 0))
 -			{
 -				markForUpdate(TRUE);
 -			}
 -			S32 res2 = unpackTEMessage(*dp);
 -			if (TEM_INVALID == res2)
 -			{
 -				// There's something bogus in the data that we're unpacking.
 -				dp->dumpBufferToLog();
 -				llwarns << "Flushing cache files" << llendl;
 -
 -				if(LLVOCache::hasInstance() && getRegion())
 -				{
 -					LLVOCache::getInstance()->removeEntry(getRegion()->getHandle()) ;
 -				}
 -				
 -				llwarns << "Bogus TE data in " << getID() << llendl;
 -			}
 -			else 
 -			{
 -				if (res2 & teDirtyBits) 
 -				{
 -					updateTEData();
 -				}
 -				if (res2 & TEM_CHANGE_MEDIA)
 -				{
 -					retval |= MEDIA_FLAGS_CHANGED;
 -				}
 -			}
 -
 -			U32 value = dp->getPassFlags();
 -
 -			if (value & 0x40)
 -			{
 -				if (!mTextureAnimp)
 -				{
 -					mTextureAnimp = new LLViewerTextureAnim();
 -				}
 -				else
 -				{
 -					if (!(mTextureAnimp->mMode & LLTextureAnim::SMOOTH))
 -					{
 -						mTextureAnimp->reset();
 -					}
 -				}
 -				mTexAnimMode = 0;
 -				mTextureAnimp->unpackTAMessage(*dp);
 -			}
 -			else if (mTextureAnimp)
 -			{
 -				delete mTextureAnimp;
 -				mTextureAnimp = NULL;
 -				gPipeline.markTextured(mDrawable);
 -				mFaceMappingChanged = TRUE;
 -				mTexAnimMode = 0;
 -			}
 -		}
 -		else
 -		{
 -			S32 texture_length = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_TextureEntry);
 -			if (texture_length)
 -			{
 -				U8							tdpbuffer[1024];
 -				LLDataPackerBinaryBuffer	tdp(tdpbuffer, 1024);
 -				mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_TextureEntry, tdpbuffer, 0, block_num);
 -				S32 result = unpackTEMessage(tdp);
 -				if (result & teDirtyBits)
 -				{
 -					updateTEData();
 -				}
 -				if (result & TEM_CHANGE_MEDIA)
 -				{
 -					retval |= MEDIA_FLAGS_CHANGED;
 -				}
 -			}
 -		}
 -	}
 -	if (retval & (MEDIA_URL_REMOVED | MEDIA_URL_ADDED | MEDIA_URL_UPDATED | MEDIA_FLAGS_CHANGED)) 
 -	{
 -		// If only the media URL changed, and it isn't a media version URL,
 -		// ignore it
 -		if ( ! ( retval & (MEDIA_URL_ADDED | MEDIA_URL_UPDATED) &&
 -				 mMedia && ! mMedia->mMediaURL.empty() &&
 -				 ! LLTextureEntry::isMediaVersionString(mMedia->mMediaURL) ) )
 -		{
 -			// If the media changed at all, request new media data
 -			LL_DEBUGS("MediaOnAPrim") << "Media update: " << getID() << ": retval=" << retval << " Media URL: " <<
 -                ((mMedia) ?  mMedia->mMediaURL : std::string("")) << LL_ENDL;
 -			requestMediaDataUpdate(retval & MEDIA_FLAGS_CHANGED);
 -		}
 -        else {
 -            LL_INFOS("MediaOnAPrim") << "Ignoring media update for: " << getID() << " Media URL: " <<
 -                ((mMedia) ?  mMedia->mMediaURL : std::string("")) << LL_ENDL;
 -        }
 -	}
 -	// ...and clean up any media impls
 -	cleanUpMediaImpls();
 -
 -	return retval;
 -}
 -
 -
 -void LLVOVolume::animateTextures()
 -{
 -	F32 off_s = 0.f, off_t = 0.f, scale_s = 1.f, scale_t = 1.f, rot = 0.f;
 -	S32 result = mTextureAnimp->animateTextures(off_s, off_t, scale_s, scale_t, rot);
 -	
 -	if (result)
 -	{
 -		if (!mTexAnimMode)
 -		{
 -			mFaceMappingChanged = TRUE;
 -			gPipeline.markTextured(mDrawable);
 -		}
 -		mTexAnimMode = result | mTextureAnimp->mMode;
 -				
 -		S32 start=0, end=mDrawable->getNumFaces()-1;
 -		if (mTextureAnimp->mFace >= 0 && mTextureAnimp->mFace <= end)
 -		{
 -			start = end = mTextureAnimp->mFace;
 -		}
 -		
 -		for (S32 i = start; i <= end; i++)
 -		{
 -			LLFace* facep = mDrawable->getFace(i);
 -			if(facep->getVirtualSize() <= MIN_TEX_ANIM_SIZE && facep->mTextureMatrix) continue;
 -
 -			const LLTextureEntry* te = facep->getTextureEntry();
 -			
 -			if (!te)
 -			{
 -				continue;
 -			}
 -		
 -			if (!(result & LLViewerTextureAnim::ROTATE))
 -			{
 -				te->getRotation(&rot);
 -			}
 -			if (!(result & LLViewerTextureAnim::TRANSLATE))
 -			{
 -				te->getOffset(&off_s,&off_t);
 -			}			
 -			if (!(result & LLViewerTextureAnim::SCALE))
 -			{
 -				te->getScale(&scale_s, &scale_t);
 -			}
 -
 -			if (!facep->mTextureMatrix)
 -			{
 -				facep->mTextureMatrix = new LLMatrix4();
 -			}
 -
 -			LLMatrix4& tex_mat = *facep->mTextureMatrix;
 -			tex_mat.setIdentity();
 -			LLVector3 trans ;
 -
 -			if(facep->isAtlasInUse())
 -			{
 -				//
 -				//if use atlas for animated texture
 -				//apply the following transform to the animation matrix.
 -				//
 -
 -				F32 tcoord_xoffset = 0.f ;
 -				F32 tcoord_yoffset = 0.f ;
 -				F32 tcoord_xscale = 1.f ;
 -				F32 tcoord_yscale = 1.f ;			
 -				if(facep->isAtlasInUse())
 -				{
 -					const LLVector2* tmp = facep->getTexCoordOffset() ;
 -					tcoord_xoffset = tmp->mV[0] ; 
 -					tcoord_yoffset = tmp->mV[1] ;
 -
 -					tmp = facep->getTexCoordScale() ;
 -					tcoord_xscale = tmp->mV[0] ; 
 -					tcoord_yscale = tmp->mV[1] ;	
 -				}
 -				trans.set(LLVector3(tcoord_xoffset + tcoord_xscale * (off_s+0.5f), tcoord_yoffset + tcoord_yscale * (off_t+0.5f), 0.f));
 -
 -				tex_mat.translate(LLVector3(-(tcoord_xoffset + tcoord_xscale * 0.5f), -(tcoord_yoffset + tcoord_yscale * 0.5f), 0.f));
 -			}
 -			else	//non atlas
 -			{
 -				trans.set(LLVector3(off_s+0.5f, off_t+0.5f, 0.f));			
 -				tex_mat.translate(LLVector3(-0.5f, -0.5f, 0.f));
 -			}
 -
 -			LLVector3 scale(scale_s, scale_t, 1.f);			
 -			LLQuaternion quat;
 -			quat.setQuat(rot, 0, 0, -1.f);
 -		
 -			tex_mat.rotate(quat);				
 -
 -			LLMatrix4 mat;
 -			mat.initAll(scale, LLQuaternion(), LLVector3());
 -			tex_mat *= mat;
 -		
 -			tex_mat.translate(trans);
 -		}
 -	}
 -	else
 -	{
 -		if (mTexAnimMode && mTextureAnimp->mRate == 0)
 -		{
 -			U8 start, count;
 -
 -			if (mTextureAnimp->mFace == -1)
 -			{
 -				start = 0;
 -				count = getNumTEs();
 -			}
 -			else
 -			{
 -				start = (U8) mTextureAnimp->mFace;
 -				count = 1;
 -			}
 -
 -			for (S32 i = start; i < start + count; i++)
 -			{
 -				if (mTexAnimMode & LLViewerTextureAnim::TRANSLATE)
 -				{
 -					setTEOffset(i, mTextureAnimp->mOffS, mTextureAnimp->mOffT);				
 -				}
 -				if (mTexAnimMode & LLViewerTextureAnim::SCALE)
 -				{
 -					setTEScale(i, mTextureAnimp->mScaleS, mTextureAnimp->mScaleT);	
 -				}
 -				if (mTexAnimMode & LLViewerTextureAnim::ROTATE)
 -				{
 -					setTERotation(i, mTextureAnimp->mRot);
 -				}
 -			}
 -
 -			gPipeline.markTextured(mDrawable);
 -			mFaceMappingChanged = TRUE;
 -			mTexAnimMode = 0;
 -		}
 -	}
 -}
 -BOOL LLVOVolume::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
 -{
 -	LLViewerObject::idleUpdate(agent, world, time);
 -
 -	static LLFastTimer::DeclareTimer ftm("Volume");
 -	LLFastTimer t(ftm);
 -
 -	if (mDead || mDrawable.isNull())
 -	{
 -		return TRUE;
 -	}
 -	
 -	///////////////////////
 -	//
 -	// Do texture animation stuff
 -	//
 -
 -	if (mTextureAnimp && gAnimateTextures)
 -	{
 -		animateTextures();
 -	}
 -
 -	// Dispatch to implementation
 -	if (mVolumeImpl)
 -	{
 -		mVolumeImpl->doIdleUpdate(agent, world, time);
 -	}
 -
 -	const S32 MAX_ACTIVE_OBJECT_QUIET_FRAMES = 40;
 -
 -	if (mDrawable->isActive())
 -	{
 -		if (mDrawable->isRoot() && 
 -			mDrawable->mQuietCount++ > MAX_ACTIVE_OBJECT_QUIET_FRAMES && 
 -			(!mDrawable->getParent() || !mDrawable->getParent()->isActive()))
 -		{
 -			mDrawable->makeStatic();
 -		}
 -	}
 -
 -	return TRUE;
 -}
 -
 -void LLVOVolume::updateTextures()
 -{
 -	const F32 TEXTURE_AREA_REFRESH_TIME = 5.f; // seconds
 -	if (mTextureUpdateTimer.getElapsedTimeF32() > TEXTURE_AREA_REFRESH_TIME)
 -	{
 -		updateTextureVirtualSize();		
 -	}
 -}
 -
 -BOOL LLVOVolume::isVisible() const 
 -{
 -	if(mDrawable.notNull() && mDrawable->isVisible())
 -	{
 -		return TRUE ;
 -	}
 -
 -	if(isAttachment())
 -	{
 -		LLViewerObject* objp = (LLViewerObject*)getParent() ;
 -		while(objp && !objp->isAvatar())
 -		{
 -			objp = (LLViewerObject*)objp->getParent() ;
 -		}
 -
 -		return objp && objp->mDrawable.notNull() && objp->mDrawable->isVisible() ;
 -	}
 -
 -	return FALSE ;
 -}
 -
 -void LLVOVolume::updateTextureVirtualSize()
 -{
 -	LLFastTimer ftm(FTM_VOLUME_TEXTURES);
 -	// Update the pixel area of all faces
 -
 -	if(!isVisible())
 -	{
 -		return ;
 -	}
 -
 -	if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SIMPLE))
 -	{
 -		return;
 -	}
 -
 -	static LLCachedControl<bool> dont_load_textures(gSavedSettings,"TextureDisable");
 -		
 -	if (dont_load_textures || LLAppViewer::getTextureFetch()->mDebugPause) // || !mDrawable->isVisible())
 -	{
 -		return;
 -	}
 -
 -	mTextureUpdateTimer.reset();
 -	
 -	F32 old_area = mPixelArea;
 -	mPixelArea = 0.f;
 -
 -	const S32 num_faces = mDrawable->getNumFaces();
 -	F32 min_vsize=999999999.f, max_vsize=0.f;
 -	LLViewerCamera* camera = LLViewerCamera::getInstance();
 -	for (S32 i = 0; i < num_faces; i++)
 -	{
 -		LLFace* face = mDrawable->getFace(i);
 -		const LLTextureEntry *te = face->getTextureEntry();
 -		LLViewerTexture *imagep = face->getTexture();
 -		if (!imagep || !te ||			
 -			face->mExtents[0].equals3(face->mExtents[1]))
 -		{
 -			continue;
 -		}
 -		
 -		F32 vsize;
 -		F32 old_size = face->getVirtualSize();
 -
 -		if (isHUDAttachment())
 -		{
 -			F32 area = (F32) camera->getScreenPixelArea();
 -			vsize = area;
 -			imagep->setBoostLevel(LLViewerTexture::BOOST_HUD);
 - 			face->setPixelArea(area); // treat as full screen
 -			face->setVirtualSize(vsize);
 -		}
 -		else
 -		{
 -			vsize = face->getTextureVirtualSize();
 -		}
 -
 -		mPixelArea = llmax(mPixelArea, face->getPixelArea());		
 -
 -		if (face->mTextureMatrix != NULL)
 -		{
 -			if ((vsize < MIN_TEX_ANIM_SIZE && old_size > MIN_TEX_ANIM_SIZE) ||
 -				(vsize > MIN_TEX_ANIM_SIZE && old_size < MIN_TEX_ANIM_SIZE))
 -			{
 -				gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD, FALSE);
 -			}
 -		}
 -				
 -		if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA))
 -		{
 -			if (vsize < min_vsize) min_vsize = vsize;
 -			if (vsize > max_vsize) max_vsize = vsize;
 -		}
 -		else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY))
 -		{
 -			LLViewerFetchedTexture* img = LLViewerTextureManager::staticCastToFetchedTexture(imagep) ;
 -			if(img)
 -			{
 -				F32 pri = img->getDecodePriority();
 -				pri = llmax(pri, 0.0f);
 -				if (pri < min_vsize) min_vsize = pri;
 -				if (pri > max_vsize) max_vsize = pri;
 -			}
 -		}
 -		else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_FACE_AREA))
 -		{
 -			F32 pri = mPixelArea;
 -			if (pri < min_vsize) min_vsize = pri;
 -			if (pri > max_vsize) max_vsize = pri;
 -		}	
 -	}
 -	
 -	if (isSculpted())
 -	{
 -		LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT);
 -		LLUUID id =  sculpt_params->getSculptTexture();
 -		
 -		updateSculptTexture();
 -		
 -		
 -
 -		if (mSculptTexture.notNull())
 -		{
 -			mSculptTexture->setBoostLevel(llmax((S32)mSculptTexture->getBoostLevel(),
 -												(S32)LLViewerTexture::BOOST_SCULPTED));
 -			mSculptTexture->setForSculpt() ;
 -			
 -			if(!mSculptTexture->isCachedRawImageReady())
 -			{
 -				S32 lod = llmin(mLOD, 3);
 -				F32 lodf = ((F32)(lod + 1.0f)/4.f);
 -				F32 tex_size = lodf * LLViewerTexture::sMaxSculptRez ;
 -				mSculptTexture->addTextureStats(2.f * tex_size * tex_size, FALSE);
 -			
 -				//if the sculpty very close to the view point, load first
 -				{				
 -					LLVector3 lookAt = getPositionAgent() - camera->getOrigin();
 -					F32 dist = lookAt.normVec() ;
 -					F32 cos_angle_to_view_dir = lookAt * camera->getXAxis() ;				
 -					mSculptTexture->setAdditionalDecodePriority(0.8f * LLFace::calcImportanceToCamera(cos_angle_to_view_dir, dist)) ;
 -				}
 -			}
 -	
 -			S32 texture_discard = mSculptTexture->getDiscardLevel(); //try to match the texture
 -			S32 current_discard = getVolume() ? getVolume()->getSculptLevel() : -2 ;
 -
 -			if (texture_discard >= 0 && //texture has some data available
 -				(texture_discard < current_discard || //texture has more data than last rebuild
 -				current_discard < 0)) //no previous rebuild
 -			{
 -				gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, FALSE);
 -				mSculptChanged = TRUE;
 -			}
 -
 -			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SCULPTED))
 -			{
 -				setDebugText(llformat("T%d C%d V%d\n%dx%d",
 -										  texture_discard, current_discard, getVolume()->getSculptLevel(),
 -										  mSculptTexture->getHeight(), mSculptTexture->getWidth()));
 -			}
 -		}
 -
 -	}
 -
 -	if (getLightTextureID().notNull())
 -	{
 -		LLLightImageParams* params = (LLLightImageParams*) getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE);
 -		LLUUID id = params->getLightTexture();
 -		mLightTexture = LLViewerTextureManager::getFetchedTexture(id);
 -		if (mLightTexture.notNull())
 -		{
 -			F32 rad = getLightRadius();
 -			mLightTexture->addTextureStats(gPipeline.calcPixelArea(getPositionAgent(), 
 -																	LLVector3(rad,rad,rad),
 -																	*camera));
 -		}	
 -	}
 -	
 -	if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA))
 -	{
 -		setDebugText(llformat("%.0f:%.0f", (F32) sqrt(min_vsize),(F32) sqrt(max_vsize)));
 -	}
 - 	else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY))
 - 	{
 - 		setDebugText(llformat("%.0f:%.0f", (F32) sqrt(min_vsize),(F32) sqrt(max_vsize)));
 - 	}
 -	else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_FACE_AREA))
 -	{
 -		setDebugText(llformat("%.0f:%.0f", (F32) sqrt(min_vsize),(F32) sqrt(max_vsize)));
 -	}
 -
 -	if (mPixelArea == 0)
 -	{ //flexi phasing issues make this happen
 -		mPixelArea = old_area;
 -	}
 -}
 -
 -BOOL LLVOVolume::isActive() const
 -{
 -	return !mStatic || mTextureAnimp || (mVolumeImpl && mVolumeImpl->isActive()) || 
 -		(mDrawable.notNull() && mDrawable->isActive());
 -}
 -
 -BOOL LLVOVolume::setMaterial(const U8 material)
 -{
 -	BOOL res = LLViewerObject::setMaterial(material);
 -	
 -	return res;
 -}
 -
 -void LLVOVolume::setTexture(const S32 face)
 -{
 -	llassert(face < getNumTEs());
 -	gGL.getTexUnit(0)->bind(getTEImage(face));
 -}
 -
 -void LLVOVolume::setScale(const LLVector3 &scale, BOOL damped)
 -{
 -	if (scale != getScale())
 -	{
 -		// store local radius
 -		LLViewerObject::setScale(scale);
 -
 -		if (mVolumeImpl)
 -		{
 -			mVolumeImpl->onSetScale(scale, damped);
 -		}
 -		
 -		updateRadius();
 -
 -		//since drawable transforms do not include scale, changing volume scale
 -		//requires an immediate rebuild of volume verts.
 -		gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_POSITION, TRUE);
 -	}
 -}
 -
 -LLFace* LLVOVolume::addFace(S32 f)
 -{
 -	const LLTextureEntry* te = getTE(f);
 -	LLViewerTexture* imagep = getTEImage(f);
 -	return mDrawable->addFace(te, imagep);
 -}
 -
 -LLDrawable *LLVOVolume::createDrawable(LLPipeline *pipeline)
 -{
 -	pipeline->allocDrawable(this);
 -		
 -	mDrawable->setRenderType(LLPipeline::RENDER_TYPE_VOLUME);
 -
 -	S32 max_tes_to_set = getNumTEs();
 -	for (S32 i = 0; i < max_tes_to_set; i++)
 -	{
 -		addFace(i);
 -	}
 -	mNumFaces = max_tes_to_set;
 -
 -	if (isAttachment())
 -	{
 -		mDrawable->makeActive();
 -	}
 -
 -	if (getIsLight())
 -	{
 -		// Add it to the pipeline mLightSet
 -		gPipeline.setLight(mDrawable, TRUE);
 -	}
 -	
 -	updateRadius();
 -	bool force_update = true; // avoid non-alpha mDistance update being optimized away
 -	mDrawable->updateDistance(*LLViewerCamera::getInstance(), force_update);
 -
 -	return mDrawable;
 -}
 -
 -BOOL LLVOVolume::setVolume(const LLVolumeParams ¶ms_in, const S32 detail, bool unique_volume)
 -{
 -	LLVolumeParams volume_params = params_in;
 -
 -	S32 last_lod = mVolumep.notNull() ? LLVolumeLODGroup::getVolumeDetailFromScale(mVolumep->getDetail()) : -1;
 -	S32 lod = mLOD;
 -
 -	BOOL is404 = FALSE;
 -
 -	if (isSculpted())
 -	{
 -		// if it's a mesh
 -		if ((volume_params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)
 -		{ //meshes might not have all LODs, get the force detail to best existing LOD
 -
 -			LLUUID mesh_id = volume_params.getSculptID();
 -
 -			//profile and path params don't matter for meshes
 -			volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
 -
 -			lod = gMeshRepo.getActualMeshLOD(volume_params, lod);
 -			if (lod == -1)
 -			{
 -				is404 = TRUE;
 -				lod = 0;
 -			}
 -		}
 -	}
 -
 -	// Check if we need to change implementations
 -	bool is_flexible = (volume_params.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE);
 -	if (is_flexible)
 -	{
 -		setParameterEntryInUse(LLNetworkData::PARAMS_FLEXIBLE, TRUE, false);
 -		if (!mVolumeImpl)
 -		{
 -			LLFlexibleObjectData* data = (LLFlexibleObjectData*)getParameterEntry(LLNetworkData::PARAMS_FLEXIBLE);
 -			mVolumeImpl = new LLVolumeImplFlexible(this, data);
 -		}
 -	}
 -	else
 -	{
 -		// Mark the parameter not in use
 -		setParameterEntryInUse(LLNetworkData::PARAMS_FLEXIBLE, FALSE, false);
 -		if (mVolumeImpl)
 -		{
 -			delete mVolumeImpl;
 -			mVolumeImpl = NULL;
 -			if (mDrawable.notNull())
 -			{
 -				// Undo the damage we did to this matrix
 -				mDrawable->updateXform(FALSE);
 -			}
 -		}
 -	}
 -	
 -	if (is404)
 -	{
 -		setIcon(LLViewerTextureManager::getFetchedTextureFromFile("icons/Inv_Mesh.png", TRUE, LLViewerTexture::BOOST_UI));
 -	}
 -
 -	if ((LLPrimitive::setVolume(volume_params, lod, (mVolumeImpl && mVolumeImpl->isVolumeUnique()))) || mSculptChanged)
 -	{
 -		mFaceMappingChanged = TRUE;
 -		
 -		if (mVolumeImpl)
 -		{
 -			mVolumeImpl->onSetVolume(volume_params, mLOD);
 -		}
 -	
 -		updateSculptTexture();
 -
 -
 -		if (isSculpted())
 -		{
 -			updateSculptTexture();
 -			// if it's a mesh
 -			if ((volume_params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)
 -			{
 -				if (getVolume()->getNumVolumeFaces() == 0 || getVolume()->isTetrahedron())
 -				{ 
 -					//load request not yet issued, request pipeline load this mesh
 -					LLUUID asset_id = volume_params.getSculptID();
 -					S32 available_lod = gMeshRepo.loadMesh(this, volume_params, lod, last_lod);
 -					if (available_lod != lod)
 -					{
 -						LLPrimitive::setVolume(volume_params, available_lod);
 -					}
 -				}
 -				
 -			}
 -			else // otherwise is sculptie
 -			{
 -				if (mSculptTexture.notNull())
 -				{
 -					sculpt();
 -				}
 -			}
 -		}
 -
 -		return TRUE;
 -	}
 -
 -	return FALSE;
 -}
 -
 -void LLVOVolume::updateSculptTexture()
 -{
 -	LLPointer<LLViewerFetchedTexture> old_sculpt = mSculptTexture;
 -
 -	if (isSculpted() && !isMesh())
 -	{
 -		LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT);
 -		LLUUID id =  sculpt_params->getSculptTexture();
 -		if (id.notNull())
 -		{
 -			mSculptTexture = LLViewerTextureManager::getFetchedTexture(id, TRUE, LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
 -		}
 -	}
 -	else
 -	{
 -		mSculptTexture = NULL;
 -	}
 -
 -	if (mSculptTexture != old_sculpt)
 -	{
 -		if (old_sculpt.notNull())
 -		{
 -			old_sculpt->removeVolume(this);
 -		}
 -		if (mSculptTexture.notNull())
 -		{
 -			mSculptTexture->addVolume(this);
 -		}
 -	}
 -	
 -}
 -
 -
 -
 -void LLVOVolume::notifyMeshLoaded()
 -{ 
 -	mSculptChanged = TRUE;
 -	gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE);
 -}
 -
 -// sculpt replaces generate() for sculpted surfaces
 -void LLVOVolume::sculpt()
 -{	
 -	if (mSculptTexture.notNull())
 -	{				
 -		U16 sculpt_height = 0;
 -		U16 sculpt_width = 0;
 -		S8 sculpt_components = 0;
 -		const U8* sculpt_data = NULL;
 -	
 -		S32 discard_level = mSculptTexture->getDiscardLevel() ;
 -		LLImageRaw* raw_image = mSculptTexture->getCachedRawImage() ;
 -		
 -		S32 max_discard = mSculptTexture->getMaxDiscardLevel();
 -		if (discard_level > max_discard)
 -			discard_level = max_discard;    // clamp to the best we can do
 -
 -		S32 current_discard = getVolume()->getSculptLevel() ;
 -		if(current_discard < -2)
 -		{
 -			llwarns << "WARNING!!: Current discard of sculpty at " << current_discard 
 -				<< " is less than -2." << llendl;
 -			
 -			// corrupted volume... don't update the sculpty
 -			return;
 -		}
 -		else if (current_discard > MAX_DISCARD_LEVEL)
 -		{
 -			llwarns << "WARNING!!: Current discard of sculpty at " << current_discard 
 -				<< " is more than than allowed max of " << MAX_DISCARD_LEVEL << llendl;
 -			
 -			// corrupted volume... don't update the sculpty			
 -			return;
 -		}
 -
 -		if (current_discard == discard_level)  // no work to do here
 -			return;
 -		
 -		if(!raw_image)
 -		{
 -			llassert(discard_level < 0) ;
 -
 -			sculpt_width = 0;
 -			sculpt_height = 0;
 -			sculpt_data = NULL ;
 -
 -			if(LLViewerTextureManager::sTesterp)
 -			{
 -				LLViewerTextureManager::sTesterp->updateGrayTextureBinding();
 -			}
 -		}
 -		else
 -		{					
 -			sculpt_height = raw_image->getHeight();
 -			sculpt_width = raw_image->getWidth();
 -			sculpt_components = raw_image->getComponents();		
 -					   
 -			sculpt_data = raw_image->getData();
 -
 -			if(LLViewerTextureManager::sTesterp)
 -			{
 -				mSculptTexture->updateBindStatsForTester() ;
 -			}
 -		}
 -		getVolume()->sculpt(sculpt_width, sculpt_height, sculpt_components, sculpt_data, discard_level);
 -
 -		//notify rebuild any other VOVolumes that reference this sculpty volume
 -		for (S32 i = 0; i < mSculptTexture->getNumVolumes(); ++i)
 -		{
 -			LLVOVolume* volume = (*(mSculptTexture->getVolumeList()))[i];
 -			if (volume != this && volume->getVolume() == getVolume())
 -			{
 -				gPipeline.markRebuild(volume->mDrawable, LLDrawable::REBUILD_GEOMETRY, FALSE);
 -			}
 -		}
 -	}
 -}
 -
 -S32	LLVOVolume::computeLODDetail(F32 distance, F32 radius)
 -{
 -	S32	cur_detail;
 -	if (LLPipeline::sDynamicLOD)
 -	{
 -		// We've got LOD in the profile, and in the twist.  Use radius.
 -		F32 tan_angle = (LLVOVolume::sLODFactor*radius)/distance;
 -		cur_detail = LLVolumeLODGroup::getDetailFromTan(llround(tan_angle, 0.01f));
 -	}
 -	else
 -	{
 -		cur_detail = llclamp((S32) (sqrtf(radius)*LLVOVolume::sLODFactor*4.f), 0, 3);		
 -	}
 -	return cur_detail;
 -}
 -
 -BOOL LLVOVolume::calcLOD()
 -{
 -	if (mDrawable.isNull())
 -	{
 -		return FALSE;
 -	}
 -
 -	S32 cur_detail = 0;
 -	
 -	F32 radius;
 -	F32 distance;
 -
 -	if (mDrawable->isState(LLDrawable::RIGGED))
 -	{
 -		LLVOAvatar* avatar = getAvatar(); 
 -		distance = avatar->mDrawable->mDistanceWRTCamera;
 -		radius = avatar->getBinRadius();
 -	}
 -	else
 -	{
 -		distance = mDrawable->mDistanceWRTCamera;
 -		radius = getVolume()->mLODScaleBias.scaledVec(getScale()).length();
 -	}
 -	
 -	//hold onto unmodified distance for debugging
 -	F32 debug_distance = distance;
 -	
 -	distance *= sDistanceFactor;
 -
 -	F32 rampDist = LLVOVolume::sLODFactor * 2;
 -	
 -	if (distance < rampDist)
 -	{
 -		// Boost LOD when you're REALLY close
 -		distance *= 1.0f/rampDist;
 -		distance *= distance;
 -		distance *= rampDist;
 -	}
 -	
 -	// DON'T Compensate for field of view changing on FOV zoom.
 -	distance *= F_PI/3.f;
 -
 -	cur_detail = computeLODDetail(llround(distance, 0.01f), 
 -									llround(radius, 0.01f));
 -
 -
 -	if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_LOD_INFO))
 -	{
 -		setDebugText(llformat("%.2f:%.2f, %d", debug_distance, radius, cur_detail));
 -	}
 -
 -	if (cur_detail != mLOD)
 -	{
 -		mAppAngle = llround((F32) atan2( mDrawable->getRadius(), mDrawable->mDistanceWRTCamera) * RAD_TO_DEG, 0.01f);
 -		mLOD = cur_detail;		
 -		return TRUE;
 -	}
 -	else
 -	{
 -		return FALSE;
 -	}
 -}
 -
 -BOOL LLVOVolume::updateLOD()
 -{
 -	if (mDrawable.isNull())
 -	{
 -		return FALSE;
 -	}
 -	
 -	BOOL lod_changed = calcLOD();
 -
 -	if (lod_changed)
 -	{
 -		gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, FALSE);
 -		mLODChanged = TRUE;
 -	}
 -
 -	lod_changed = lod_changed || LLViewerObject::updateLOD();
 -	
 -	return lod_changed;
 -}
 -
 -BOOL LLVOVolume::setDrawableParent(LLDrawable* parentp)
 -{
 -	if (!LLViewerObject::setDrawableParent(parentp))
 -	{
 -		// no change in drawable parent
 -		return FALSE;
 -	}
 -
 -	if (!mDrawable->isRoot())
 -	{
 -		// rebuild vertices in parent relative space
 -		gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE);
 -
 -		if (mDrawable->isActive() && !parentp->isActive())
 -		{
 -			parentp->makeActive();
 -		}
 -		else if (mDrawable->isStatic() && parentp->isActive())
 -		{
 -			mDrawable->makeActive();
 -		}
 -	}
 -	
 -	return TRUE;
 -}
 -
 -void LLVOVolume::updateFaceFlags()
 -{
 -	for (S32 i = 0; i < getVolume()->getNumFaces(); i++)
 -	{
 -		LLFace *face = mDrawable->getFace(i);
 -		if (!face)
 -		{
 -			return;
 -		}
 -
 -		BOOL fullbright = getTE(i)->getFullbright();
 -		face->clearState(LLFace::FULLBRIGHT | LLFace::HUD_RENDER | LLFace::LIGHT);
 -
 -		if (fullbright || (mMaterial == LL_MCODE_LIGHT))
 -		{
 -			face->setState(LLFace::FULLBRIGHT);
 -		}
 -		if (mDrawable->isLight())
 -		{
 -			face->setState(LLFace::LIGHT);
 -		}
 -		if (isHUDAttachment())
 -		{
 -			face->setState(LLFace::HUD_RENDER);
 -		}
 -	}
 -}
 -
 -BOOL LLVOVolume::setParent(LLViewerObject* parent)
 -{
 -	BOOL ret = FALSE ;
 -	if (parent != getParent())
 -	{
 -		ret = LLViewerObject::setParent(parent);
 -		if (ret && mDrawable)
 -		{
 -			gPipeline.markMoved(mDrawable);
 -			gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE);
 -		}
 -	}
 -
 -	return ret ;
 -}
 -
 -// NOTE: regenFaces() MUST be followed by genTriangles()!
 -void LLVOVolume::regenFaces()
 -{
 -	// remove existing faces
 -	BOOL count_changed = mNumFaces != getNumTEs();
 -	
 -	if (count_changed)
 -	{
 -		deleteFaces();		
 -		// add new faces
 -		mNumFaces = getNumTEs();
 -	}
 -		
 -	for (S32 i = 0; i < mNumFaces; i++)
 -	{
 -		LLFace* facep = count_changed ? addFace(i) : mDrawable->getFace(i);
 -		facep->setTEOffset(i);
 -		facep->setTexture(getTEImage(i));
 -		facep->setViewerObject(this);
 -		
 -		// If the face had media on it, this will have broken the link between the LLViewerMediaTexture and the face.
 -		// Re-establish the link.
 -		if((int)mMediaImplList.size() > i)
 -		{
 -			if(mMediaImplList[i])
 -			{
 -				LLViewerMediaTexture* media_tex = LLViewerTextureManager::findMediaTexture(mMediaImplList[i]->getMediaTextureID()) ;
 -				if(media_tex)
 -				{
 -					media_tex->addMediaToFace(facep) ;
 -				}
 -			}
 -		}
 -	}
 -	
 -	if (!count_changed)
 -	{
 -		updateFaceFlags();
 -	}
 -}
 -
 -BOOL LLVOVolume::genBBoxes(BOOL force_global)
 -{
 -	BOOL res = TRUE;
 -
 -	LLVector4a min,max;
 -
 -	min.clear();
 -	max.clear();
 -
 -	BOOL rebuild = mDrawable->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION | LLDrawable::REBUILD_RIGGED);
 -
 -//	bool rigged = false;
 -	LLVolume* volume = mRiggedVolume;
 -	if (!volume)
 -	{
 -		volume = getVolume();
 -	}
 -
 -	for (S32 i = 0; i < getVolume()->getNumVolumeFaces(); i++)
 -	{
 -		LLFace *face = mDrawable->getFace(i);
 -		if (!face)
 -		{
 -			continue;
 -		}
 -		res &= face->genVolumeBBoxes(*volume, i,
 -										mRelativeXform, mRelativeXformInvTrans,
 -										(mVolumeImpl && mVolumeImpl->isVolumeGlobal()) || force_global);
 -		
 -		if (rebuild)
 -		{
 -			if (i == 0)
 -			{
 -				min = face->mExtents[0];
 -				max = face->mExtents[1];
 -			}
 -			else
 -			{
 -				min.setMin(min, face->mExtents[0]);
 -				max.setMax(max, face->mExtents[1]);
 -			}
 -		}
 -	}
 -	
 -	if (rebuild)
 -	{
 -		mDrawable->setSpatialExtents(min,max);
 -		min.add(max);
 -		min.mul(0.5f);
 -		mDrawable->setPositionGroup(min);	
 -	}
 -
 -	updateRadius();
 -	mDrawable->movePartition();
 -			
 -	return res;
 -}
 -
 -void LLVOVolume::preRebuild()
 -{
 -	if (mVolumeImpl != NULL)
 -	{
 -		mVolumeImpl->preRebuild();
 -	}
 -}
 -
 -void LLVOVolume::updateRelativeXform()
 -{
 -	if (mVolumeImpl)
 -	{
 -		mVolumeImpl->updateRelativeXform();
 -		return;
 -	}
 -	
 -	LLDrawable* drawable = mDrawable;
 -	
 -	if (drawable->isState(LLDrawable::RIGGED) && mRiggedVolume.notNull())
 -	{ //rigged volume (which is in agent space) is used for generating bounding boxes etc
 -	  //inverse of render matrix should go to partition space
 -		mRelativeXform = getRenderMatrix();
 -
 -		F32* dst = (F32*) mRelativeXformInvTrans.mMatrix;
 -		F32* src = (F32*) mRelativeXform.mMatrix;
 -		dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2];
 -		dst[3] = src[4]; dst[4] = src[5]; dst[5] = src[6];
 -		dst[6] = src[8]; dst[7] = src[9]; dst[8] = src[10];
 -		
 -		mRelativeXform.invert();
 -		mRelativeXformInvTrans.transpose();
 -	}
 -	else if (drawable->isActive())
 -	{				
 -		// setup relative transforms
 -		LLQuaternion delta_rot;
 -		LLVector3 delta_pos, delta_scale;
 -		
 -		//matrix from local space to parent relative/global space
 -		delta_rot = drawable->isSpatialRoot() ? LLQuaternion() : mDrawable->getRotation();
 -		delta_pos = drawable->isSpatialRoot() ? LLVector3(0,0,0) : mDrawable->getPosition();
 -		delta_scale = mDrawable->getScale();
 -
 -		// Vertex transform (4x4)
 -		LLVector3 x_axis = LLVector3(delta_scale.mV[VX], 0.f, 0.f) * delta_rot;
 -		LLVector3 y_axis = LLVector3(0.f, delta_scale.mV[VY], 0.f) * delta_rot;
 -		LLVector3 z_axis = LLVector3(0.f, 0.f, delta_scale.mV[VZ]) * delta_rot;
 -
 -		mRelativeXform.initRows(LLVector4(x_axis, 0.f),
 -								LLVector4(y_axis, 0.f),
 -								LLVector4(z_axis, 0.f),
 -								LLVector4(delta_pos, 1.f));
 -
 -		
 -		// compute inverse transpose for normals
 -		// mRelativeXformInvTrans.setRows(x_axis, y_axis, z_axis);
 -		// mRelativeXformInvTrans.invert(); 
 -		// mRelativeXformInvTrans.setRows(x_axis, y_axis, z_axis);
 -		// grumble - invert is NOT a matrix invert, so we do it by hand:
 -
 -		LLMatrix3 rot_inverse = LLMatrix3(~delta_rot);
 -
 -		LLMatrix3 scale_inverse;
 -		scale_inverse.setRows(LLVector3(1.0, 0.0, 0.0) / delta_scale.mV[VX],
 -							  LLVector3(0.0, 1.0, 0.0) / delta_scale.mV[VY],
 -							  LLVector3(0.0, 0.0, 1.0) / delta_scale.mV[VZ]);
 -							   
 -		
 -		mRelativeXformInvTrans = rot_inverse * scale_inverse;
 -
 -		mRelativeXformInvTrans.transpose();
 -	}
 -	else
 -	{
 -		LLVector3 pos = getPosition();
 -		LLVector3 scale = getScale();
 -		LLQuaternion rot = getRotation();
 -	
 -		if (mParent)
 -		{
 -			pos *= mParent->getRotation();
 -			pos += mParent->getPosition();
 -			rot *= mParent->getRotation();
 -		}
 -		
 -		//LLViewerRegion* region = getRegion();
 -		//pos += region->getOriginAgent();
 -		
 -		LLVector3 x_axis = LLVector3(scale.mV[VX], 0.f, 0.f) * rot;
 -		LLVector3 y_axis = LLVector3(0.f, scale.mV[VY], 0.f) * rot;
 -		LLVector3 z_axis = LLVector3(0.f, 0.f, scale.mV[VZ]) * rot;
 -
 -		mRelativeXform.initRows(LLVector4(x_axis, 0.f),
 -								LLVector4(y_axis, 0.f),
 -								LLVector4(z_axis, 0.f),
 -								LLVector4(pos, 1.f));
 -
 -		// compute inverse transpose for normals
 -		LLMatrix3 rot_inverse = LLMatrix3(~rot);
 -
 -		LLMatrix3 scale_inverse;
 -		scale_inverse.setRows(LLVector3(1.0, 0.0, 0.0) / scale.mV[VX],
 -							  LLVector3(0.0, 1.0, 0.0) / scale.mV[VY],
 -							  LLVector3(0.0, 0.0, 1.0) / scale.mV[VZ]);
 -							   
 -		
 -		mRelativeXformInvTrans = rot_inverse * scale_inverse;
 -
 -		mRelativeXformInvTrans.transpose();
 -	}
 -}
 -
 -static LLFastTimer::DeclareTimer FTM_GEN_FLEX("Generate Flexies");
 -static LLFastTimer::DeclareTimer FTM_UPDATE_PRIMITIVES("Update Primitives");
 -static LLFastTimer::DeclareTimer FTM_UPDATE_RIGGED_VOLUME("Update Rigged");
 -
 -BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
 -{
 -	LLFastTimer t(FTM_UPDATE_PRIMITIVES);
 -	
 -	if (mDrawable->isState(LLDrawable::REBUILD_RIGGED))
 -	{
 -		{
 -			LLFastTimer t(FTM_UPDATE_RIGGED_VOLUME);
 -			updateRiggedVolume();
 -		}
 -		genBBoxes(FALSE);
 -		mDrawable->clearState(LLDrawable::REBUILD_RIGGED);
 -	}
 -
 -	if (mVolumeImpl != NULL)
 -	{
 -		BOOL res;
 -		{
 -			LLFastTimer t(FTM_GEN_FLEX);
 -			res = mVolumeImpl->doUpdateGeometry(drawable);
 -		}
 -		updateFaceFlags();
 -		return res;
 -	}
 -	
 -	dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1));
 -
 -	BOOL compiled = FALSE;
 -			
 -	updateRelativeXform();
 -	
 -	if (mDrawable.isNull()) // Not sure why this is happening, but it is...
 -	{
 -		return TRUE; // No update to complete
 -	}
 -
 -	if (mVolumeChanged || mFaceMappingChanged )
 -	{
 -		compiled = TRUE;
 -
 -		if (mVolumeChanged)
 -		{
 -			LLFastTimer ftm(FTM_GEN_VOLUME);
 -			LLVolumeParams volume_params = getVolume()->getParams();
 -			setVolume(volume_params, 0);
 -			drawable->setState(LLDrawable::REBUILD_VOLUME);
 -		}
 -
 -		{
 -			LLFastTimer t(FTM_GEN_TRIANGLES);
 -			regenFaces();
 -			genBBoxes(FALSE);
 -		}
 -	}
 -	else if ((mLODChanged) || (mSculptChanged))
 -	{
 -		LLVolume *old_volumep, *new_volumep;
 -		F32 old_lod, new_lod;
 -		S32 old_num_faces, new_num_faces ;
 -
 -		old_volumep = getVolume();
 -		old_lod = old_volumep->getDetail();
 -		old_num_faces = old_volumep->getNumFaces() ;
 -		old_volumep = NULL ;
 -
 -		{
 -			LLFastTimer ftm(FTM_GEN_VOLUME);
 -			LLVolumeParams volume_params = getVolume()->getParams();
 -			setVolume(volume_params, 0);
 -		}
 -
 -		new_volumep = getVolume();
 -		new_lod = new_volumep->getDetail();
 -		new_num_faces = new_volumep->getNumFaces() ;
 -		new_volumep = NULL ;
 -
 -		if ((new_lod != old_lod) || mSculptChanged)
 -		{
 -			compiled = TRUE;
 -			sNumLODChanges += new_num_faces ;
 -	
 -			drawable->setState(LLDrawable::REBUILD_VOLUME); // for face->genVolumeTriangles()
 -
 -			{
 -				LLFastTimer t(FTM_GEN_TRIANGLES);
 -				if (new_num_faces != old_num_faces)
 -				{
 -					regenFaces();
 -				}
 -				genBBoxes(FALSE);
 -
 -				if (mSculptChanged)
 -				{ //changes in sculpt maps can thrash an object bounding box without 
 -				  //triggering a spatial group bounding box update -- force spatial group
 -				  //to update bounding boxes
 -					LLSpatialGroup* group = mDrawable->getSpatialGroup();
 -					if (group)
 -					{
 -						group->unbound();
 -					}
 -				}
 -			}
 -		}
 -	}
 -	// it has its own drawable (it's moved) or it has changed UVs or it has changed xforms from global<->local
 -	else
 -	{
 -		compiled = TRUE;
 -		// All it did was move or we changed the texture coordinate offset
 -		LLFastTimer t(FTM_GEN_TRIANGLES);
 -		genBBoxes(FALSE);
 -	}
 -
 -	// Update face flags
 -	updateFaceFlags();
 -	
 -	if(compiled)
 -	{
 -		LLPipeline::sCompiles++;
 -	}
 -		
 -	mVolumeChanged = FALSE;
 -	mLODChanged = FALSE;
 -	mSculptChanged = FALSE;
 -	mFaceMappingChanged = FALSE;
 -	
 -	return LLViewerObject::updateGeometry(drawable);
 -}
 -
 -void LLVOVolume::updateFaceSize(S32 idx)
 -{
 -	LLFace* facep = mDrawable->getFace(idx);
 -	if (idx >= getVolume()->getNumVolumeFaces())
 -	{
 -		facep->setSize(0,0, true);
 -	}
 -	else
 -	{
 -		const LLVolumeFace& vol_face = getVolume()->getVolumeFace(idx);
 -		facep->setSize(vol_face.mNumVertices, vol_face.mNumIndices, 
 -						true); // <--- volume faces should be padded for 16-byte alignment
 -		
 -	}
 -}
 -
 -BOOL LLVOVolume::isRootEdit() const
 -{
 -	if (mParent && !((LLViewerObject*)mParent)->isAvatar())
 -	{
 -		return FALSE;
 -	}
 -	return TRUE;
 -}
 -
 -//virtual
 -void LLVOVolume::setNumTEs(const U8 num_tes)
 -{
 -	const U8 old_num_tes = getNumTEs() ;
 -	
 -	if(old_num_tes && old_num_tes < num_tes) //new faces added
 -	{
 -		LLViewerObject::setNumTEs(num_tes) ;
 -
 -		if(mMediaImplList.size() >= old_num_tes && mMediaImplList[old_num_tes -1].notNull())//duplicate the last media textures if exists.
 -		{
 -			mMediaImplList.resize(num_tes) ;
 -			const LLTextureEntry* te = getTE(old_num_tes - 1) ;
 -			for(U8 i = old_num_tes; i < num_tes ; i++)
 -			{
 -				setTE(i, *te) ;
 -				mMediaImplList[i] = mMediaImplList[old_num_tes -1] ;
 -			}
 -			mMediaImplList[old_num_tes -1]->setUpdated(TRUE) ;
 -		}
 -	}
 -	else if(old_num_tes > num_tes && mMediaImplList.size() > num_tes) //old faces removed
 -	{
 -		U8 end = mMediaImplList.size() ;
 -		for(U8 i = num_tes; i < end ; i++)
 -		{
 -			removeMediaImpl(i) ;				
 -		}
 -		mMediaImplList.resize(num_tes) ;
 -
 -		LLViewerObject::setNumTEs(num_tes) ;
 -	}
 -	else
 -	{
 -		LLViewerObject::setNumTEs(num_tes) ;
 -	}
 -
 -	return ;
 -}
 -
 -void LLVOVolume::setTEImage(const U8 te, LLViewerTexture *imagep)
 -{
 -	BOOL changed = (mTEImages[te] != imagep);
 -	LLViewerObject::setTEImage(te, imagep);
 -	if (changed)
 -	{
 -		gPipeline.markTextured(mDrawable);
 -		mFaceMappingChanged = TRUE;
 -	}
 -}
 -
 -S32 LLVOVolume::setTETexture(const U8 te, const LLUUID &uuid)
 -{
 -	S32 res = LLViewerObject::setTETexture(te, uuid);
 -	if (res)
 -	{
 -		gPipeline.markTextured(mDrawable);
 -		mFaceMappingChanged = TRUE;
 -	}
 -	return res;
 -}
 -
 -S32 LLVOVolume::setTEColor(const U8 te, const LLColor3& color)
 -{
 -	return setTEColor(te, LLColor4(color));
 -}
 -
 -S32 LLVOVolume::setTEColor(const U8 te, const LLColor4& color)
 -{
 -	S32 retval = 0;
 -	const LLTextureEntry *tep = getTE(te);
 -	if (!tep)
 -	{
 -		llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl;
 -	}
 -	else if (color != tep->getColor())
 -	{
 -		if (color.mV[3] != tep->getColor().mV[3])
 -		{
 -			gPipeline.markTextured(mDrawable);
 -		}
 -		retval = LLPrimitive::setTEColor(te, color);
 -		if (mDrawable.notNull() && retval)
 -		{
 -			// These should only happen on updates which are not the initial update.
 -			mDrawable->setState(LLDrawable::REBUILD_COLOR);
 -			dirtyMesh();
 -		}
 -	}
 -
 -	return  retval;
 -}
 -
 -S32 LLVOVolume::setTEBumpmap(const U8 te, const U8 bumpmap)
 -{
 -	S32 res = LLViewerObject::setTEBumpmap(te, bumpmap);
 -	if (res)
 -	{
 -		gPipeline.markTextured(mDrawable);
 -		mFaceMappingChanged = TRUE;
 -	}
 -	return  res;
 -}
 -
 -S32 LLVOVolume::setTETexGen(const U8 te, const U8 texgen)
 -{
 -	S32 res = LLViewerObject::setTETexGen(te, texgen);
 -	if (res)
 -	{
 -		gPipeline.markTextured(mDrawable);
 -		mFaceMappingChanged = TRUE;
 -	}
 -	return  res;
 -}
 -
 -S32 LLVOVolume::setTEMediaTexGen(const U8 te, const U8 media)
 -{
 -	S32 res = LLViewerObject::setTEMediaTexGen(te, media);
 -	if (res)
 -	{
 -		gPipeline.markTextured(mDrawable);
 -		mFaceMappingChanged = TRUE;
 -	}
 -	return  res;
 -}
 -
 -S32 LLVOVolume::setTEShiny(const U8 te, const U8 shiny)
 -{
 -	S32 res = LLViewerObject::setTEShiny(te, shiny);
 -	if (res)
 -	{
 -		gPipeline.markTextured(mDrawable);
 -		mFaceMappingChanged = TRUE;
 -	}
 -	return  res;
 -}
 -
 -S32 LLVOVolume::setTEFullbright(const U8 te, const U8 fullbright)
 -{
 -	S32 res = LLViewerObject::setTEFullbright(te, fullbright);
 -	if (res)
 -	{
 -		gPipeline.markTextured(mDrawable);
 -		mFaceMappingChanged = TRUE;
 -	}
 -	return  res;
 -}
 -
 -S32 LLVOVolume::setTEBumpShinyFullbright(const U8 te, const U8 bump)
 -{
 -	S32 res = LLViewerObject::setTEBumpShinyFullbright(te, bump);
 -	if (res)
 -	{
 -		gPipeline.markTextured(mDrawable);
 -		mFaceMappingChanged = TRUE;
 -	}
 -	return res;
 -}
 -
 -S32 LLVOVolume::setTEMediaFlags(const U8 te, const U8 media_flags)
 -{
 -	S32 res = LLViewerObject::setTEMediaFlags(te, media_flags);
 -	if (res)
 -	{
 -		gPipeline.markTextured(mDrawable);
 -		mFaceMappingChanged = TRUE;
 -	}
 -	return  res;
 -}
 -
 -S32 LLVOVolume::setTEGlow(const U8 te, const F32 glow)
 -{
 -	S32 res = LLViewerObject::setTEGlow(te, glow);
 -	if (res)
 -	{
 -		gPipeline.markTextured(mDrawable);
 -		mFaceMappingChanged = TRUE;
 -	}
 -	return  res;
 -}
 -
 -S32 LLVOVolume::setTEScale(const U8 te, const F32 s, const F32 t)
 -{
 -	S32 res = LLViewerObject::setTEScale(te, s, t);
 -	if (res)
 -	{
 -		gPipeline.markTextured(mDrawable);
 -		mFaceMappingChanged = TRUE;
 -	}
 -	return res;
 -}
 -
 -S32 LLVOVolume::setTEScaleS(const U8 te, const F32 s)
 -{
 -	S32 res = LLViewerObject::setTEScaleS(te, s);
 -	if (res)
 -	{
 -		gPipeline.markTextured(mDrawable);
 -		mFaceMappingChanged = TRUE;
 -	}
 -	return res;
 -}
 -
 -S32 LLVOVolume::setTEScaleT(const U8 te, const F32 t)
 -{
 -	S32 res = LLViewerObject::setTEScaleT(te, t);
 -	if (res)
 -	{
 -		gPipeline.markTextured(mDrawable);
 -		mFaceMappingChanged = TRUE;
 -	}
 -	return res;
 -}
 -
 -void LLVOVolume::updateTEData()
 -{
 -	/*if (mDrawable.notNull())
 -	{
 -		mFaceMappingChanged = TRUE;
 -		gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_MATERIAL, TRUE);
 -	}*/
 -}
 -
 -bool LLVOVolume::hasMedia() const
 -{
 -	bool result = false;
 -	const U8 numTEs = getNumTEs();
 -	for (U8 i = 0; i < numTEs; i++)
 -	{
 -		const LLTextureEntry* te = getTE(i);
 -		if(te->hasMedia())
 -		{
 -			result = true;
 -			break;
 -		}
 -	}
 -	return result;
 -}
 -
 -LLVector3 LLVOVolume::getApproximateFaceNormal(U8 face_id)
 -{
 -	LLVolume* volume = getVolume();
 -	LLVector4a result;
 -	result.clear();
 -
 -	LLVector3 ret;
 -
 -	if (volume && face_id < volume->getNumVolumeFaces())
 -	{
 -		const LLVolumeFace& face = volume->getVolumeFace(face_id);
 -		for (S32 i = 0; i < (S32)face.mNumVertices; ++i)
 -		{
 -			result.add(face.mNormals[i]);
 -		}
 -
 -		LLVector3 ret(result.getF32ptr());
 -		ret = volumeDirectionToAgent(ret);
 -		ret.normVec();
 -	}
 -	
 -	return ret;
 -}
 -
 -void LLVOVolume::requestMediaDataUpdate(bool isNew)
 -{
 -    if (sObjectMediaClient)
 -		sObjectMediaClient->fetchMedia(new LLMediaDataClientObjectImpl(this, isNew));
 -}
 -
 -bool LLVOVolume::isMediaDataBeingFetched() const
 -{
 -	// I know what I'm doing by const_casting this away: this is just 
 -	// a wrapper class that is only going to do a lookup.
 -	return (sObjectMediaClient) ? sObjectMediaClient->isInQueue(new LLMediaDataClientObjectImpl(const_cast<LLVOVolume*>(this), false)) : false;
 -}
 -
 -void LLVOVolume::cleanUpMediaImpls()
 -{
 -	// Iterate through our TEs and remove any Impls that are no longer used
 -	const U8 numTEs = getNumTEs();
 -	for (U8 i = 0; i < numTEs; i++)
 -	{
 -		const LLTextureEntry* te = getTE(i);
 -		if( ! te->hasMedia())
 -		{
 -			// Delete the media IMPL!
 -			removeMediaImpl(i) ;
 -		}
 -	}
 -}
 -
 -void LLVOVolume::updateObjectMediaData(const LLSD &media_data_array, const std::string &media_version)
 -{
 -	// media_data_array is an array of media entry maps
 -	// media_version is the version string in the response.
 -	U32 fetched_version = LLTextureEntry::getVersionFromMediaVersionString(media_version);
 -
 -	// Only update it if it is newer!
 -	if ( (S32)fetched_version > mLastFetchedMediaVersion)
 -	{
 -		mLastFetchedMediaVersion = fetched_version;
 -		//llinfos << "updating:" << this->getID() << " " << ll_pretty_print_sd(media_data_array) << llendl;
 -		
 -		LLSD::array_const_iterator iter = media_data_array.beginArray();
 -		LLSD::array_const_iterator end = media_data_array.endArray();
 -		U8 texture_index = 0;
 -		for (; iter != end; ++iter, ++texture_index)
 -		{
 -			syncMediaData(texture_index, *iter, false/*merge*/, false/*ignore_agent*/);
 -		}
 -	}
 -}
 -
 -void LLVOVolume::syncMediaData(S32 texture_index, const LLSD &media_data, bool merge, bool ignore_agent)
 -{
 -	if(mDead)
 -	{
 -		// If the object has been marked dead, don't process media updates.
 -		return;
 -	}
 -	
 -	LLTextureEntry *te = getTE(texture_index);
 -	if(!te)
 -	{
 -		return ;
 -	}
 -
 -	LL_DEBUGS("MediaOnAPrim") << "BEFORE: texture_index = " << texture_index
 -		<< " hasMedia = " << te->hasMedia() << " : " 
 -		<< ((NULL == te->getMediaData()) ? "NULL MEDIA DATA" : ll_pretty_print_sd(te->getMediaData()->asLLSD())) << llendl;
 -
 -	std::string previous_url;
 -	LLMediaEntry* mep = te->getMediaData();
 -	if(mep)
 -	{
 -		// Save the "current url" from before the update so we can tell if
 -		// it changes. 
 -		previous_url = mep->getCurrentURL();
 -	}
 -
 -	if (merge)
 -	{
 -		te->mergeIntoMediaData(media_data);
 -	}
 -	else {
 -		// XXX Question: what if the media data is undefined LLSD, but the
 -		// update we got above said that we have media flags??	Here we clobber
 -		// that, assuming the data from the service is more up-to-date. 
 -		te->updateMediaData(media_data);
 -	}
 -
 -	mep = te->getMediaData();
 -	if(mep)
 -	{
 -		bool update_from_self = false;
 -		if (!ignore_agent) 
 -		{
 -			LLUUID updating_agent = LLTextureEntry::getAgentIDFromMediaVersionString(getMediaURL());
 -			update_from_self = (updating_agent == gAgent.getID());
 -		}
 -		viewer_media_t media_impl = LLViewerMedia::updateMediaImpl(mep, previous_url, update_from_self);
 -			
 -		addMediaImpl(media_impl, texture_index) ;
 -	}
 -	else
 -	{
 -		removeMediaImpl(texture_index);
 -	}
 -
 -	LL_DEBUGS("MediaOnAPrim") << "AFTER: texture_index = " << texture_index
 -		<< " hasMedia = " << te->hasMedia() << " : " 
 -		<< ((NULL == te->getMediaData()) ? "NULL MEDIA DATA" : ll_pretty_print_sd(te->getMediaData()->asLLSD())) << llendl;
 -}
 -
 -void LLVOVolume::mediaNavigateBounceBack(U8 texture_index)
 -{
 -	// Find the media entry for this navigate
 -	const LLMediaEntry* mep = NULL;
 -	viewer_media_t impl = getMediaImpl(texture_index);
 -	LLTextureEntry *te = getTE(texture_index);
 -	if(te)
 -	{
 -		mep = te->getMediaData();
 -	}
 -	
 -	if (mep && impl)
 -	{
 -        std::string url = mep->getCurrentURL();
 -		// Look for a ":", if not there, assume "http://"
 -		if (!url.empty() && std::string::npos == url.find(':')) 
 -		{
 -			url = "http://" + url;
 -		}
 -		// If the url we're trying to "bounce back" to is either empty or not
 -		// allowed by the whitelist, try the home url.  If *that* doesn't work,
 -		// set the media as failed and unload it
 -        if (url.empty() || !mep->checkCandidateUrl(url))
 -        {
 -            url = mep->getHomeURL();
 -			// Look for a ":", if not there, assume "http://"
 -			if (!url.empty() && std::string::npos == url.find(':')) 
 -			{
 -				url = "http://" + url;
 -			}
 -        }
 -        if (url.empty() || !mep->checkCandidateUrl(url))
 -		{
 -			// The url to navigate back to is not good, and we have nowhere else
 -			// to go.
 -			LL_WARNS("MediaOnAPrim") << "FAILED to bounce back URL \"" << url << "\" -- unloading impl" << LL_ENDL;
 -			impl->setMediaFailed(true);
 -		}
 -		else {
 -			// Okay, navigate now
 -            LL_INFOS("MediaOnAPrim") << "bouncing back to URL: " << url << LL_ENDL;
 -            impl->navigateTo(url, "", false, true);
 -        }
 -    }
 -}
 -
 -bool LLVOVolume::hasMediaPermission(const LLMediaEntry* media_entry, MediaPermType perm_type)
 -{
 -    // NOTE: This logic ALMOST duplicates the logic in the server (in particular, in llmediaservice.cpp).
 -    if (NULL == media_entry ) return false; // XXX should we assert here?
 -    
 -    // The agent has permissions if:
 -    // - world permissions are on, or
 -    // - group permissions are on, and agent_id is in the group, or
 -    // - agent permissions are on, and agent_id is the owner
 -    
 -	// *NOTE: We *used* to check for modify permissions here (i.e. permissions were
 -	// granted if permModify() was true).  However, this doesn't make sense in the
 -	// viewer: we don't want to show controls or allow interaction if the author
 -	// has deemed it so.  See DEV-42115.
 -	
 -    U8 media_perms = (perm_type == MEDIA_PERM_INTERACT) ? media_entry->getPermsInteract() : media_entry->getPermsControl();
 -    
 -    // World permissions
 -    if (0 != (media_perms & LLMediaEntry::PERM_ANYONE)) 
 -    {
 -        return true;
 -    }
 -    
 -    // Group permissions
 -    else if (0 != (media_perms & LLMediaEntry::PERM_GROUP))
 -    {
 -		LLPermissions* obj_perm = LLSelectMgr::getInstance()->findObjectPermissions(this);
 -		if (obj_perm && gAgent.isInGroup(obj_perm->getGroup()))
 -		{
 -			return true;
 -		}
 -    }
 -    
 -    // Owner permissions
 -    else if (0 != (media_perms & LLMediaEntry::PERM_OWNER) && permYouOwner()) 
 -    {
 -        return true;
 -    }
 -    
 -    return false;
 -    
 -}
 -
 -void LLVOVolume::mediaNavigated(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin, std::string new_location)
 -{
 -	bool block_navigation = false;
 -	// FIXME: if/when we allow the same media impl to be used by multiple faces, the logic here will need to be fixed
 -	// to deal with multiple face indices.
 -	int face_index = getFaceIndexWithMediaImpl(impl, -1);
 -	
 -	// Find the media entry for this navigate
 -	LLMediaEntry* mep = NULL;
 -	LLTextureEntry *te = getTE(face_index);
 -	if(te)
 -	{
 -		mep = te->getMediaData();
 -	}
 -	
 -	if(mep)
 -	{
 -		if(!mep->checkCandidateUrl(new_location))
 -		{
 -			block_navigation = true;
 -		}
 -		if (!block_navigation && !hasMediaPermission(mep, MEDIA_PERM_INTERACT))
 -		{
 -			block_navigation = true;
 -		}
 -	}
 -	else
 -	{
 -		LL_WARNS("MediaOnAPrim") << "Couldn't find media entry!" << LL_ENDL;
 -	}
 -						
 -	if(block_navigation)
 -	{
 -		LL_INFOS("MediaOnAPrim") << "blocking navigate to URI " << new_location << LL_ENDL;
 -
 -		// "bounce back" to the current URL from the media entry
 -		mediaNavigateBounceBack(face_index);
 -	}
 -	else if (sObjectMediaNavigateClient)
 -	{
 -		
 -		LL_DEBUGS("MediaOnAPrim") << "broadcasting navigate with URI " << new_location << LL_ENDL;
 -
 -		sObjectMediaNavigateClient->navigate(new LLMediaDataClientObjectImpl(this, false), face_index, new_location);
 -	}
 -}
 -
 -void LLVOVolume::mediaEvent(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin, LLViewerMediaObserver::EMediaEvent event)
 -{
 -	switch(event)
 -	{
 -		
 -		case LLViewerMediaObserver::MEDIA_EVENT_LOCATION_CHANGED:
 -		{			
 -			switch(impl->getNavState())
 -			{
 -				case LLViewerMediaImpl::MEDIANAVSTATE_FIRST_LOCATION_CHANGED:
 -				{
 -					// This is the first location changed event after the start of a non-server-directed nav.  It may need to be broadcast or bounced back.
 -					mediaNavigated(impl, plugin, plugin->getLocation());
 -				}
 -				break;
 -				
 -				case LLViewerMediaImpl::MEDIANAVSTATE_FIRST_LOCATION_CHANGED_SPURIOUS:
 -					// This navigate didn't change the current URL.  
 -					LL_DEBUGS("MediaOnAPrim") << "	NOT broadcasting navigate (spurious)" << LL_ENDL;
 -				break;
 -				
 -				case LLViewerMediaImpl::MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED:
 -					// This is the first location changed event after the start of a server-directed nav.  Don't broadcast it.
 -					LL_INFOS("MediaOnAPrim") << "	NOT broadcasting navigate (server-directed)" << LL_ENDL;
 -				break;
 -				
 -				default:
 -					// This is a subsequent location-changed due to a redirect.	 Don't broadcast.
 -					LL_INFOS("MediaOnAPrim") << "	NOT broadcasting navigate (redirect)" << LL_ENDL;
 -				break;
 -			}
 -		}
 -		break;
 -		
 -		case LLViewerMediaObserver::MEDIA_EVENT_NAVIGATE_COMPLETE:
 -		{
 -			switch(impl->getNavState())
 -			{
 -				case LLViewerMediaImpl::MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED:
 -				{
 -					// This is the first location changed event after the start of a non-server-directed nav.  It may need to be broadcast or bounced back.
 -					mediaNavigated(impl, plugin, plugin->getNavigateURI());
 -				}
 -				break;
 -				
 -				case LLViewerMediaImpl::MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED_SPURIOUS:
 -					// This navigate didn't change the current URL.  
 -					LL_DEBUGS("MediaOnAPrim") << "	NOT broadcasting navigate (spurious)" << LL_ENDL;
 -				break;
 -
 -				case LLViewerMediaImpl::MEDIANAVSTATE_SERVER_COMPLETE_BEFORE_LOCATION_CHANGED:
 -					// This is the the navigate complete event from a server-directed nav.  Don't broadcast it.
 -					LL_INFOS("MediaOnAPrim") << "	NOT broadcasting navigate (server-directed)" << LL_ENDL;
 -				break;
 -				
 -				default:
 -					// For all other states, the navigate should have been handled by LOCATION_CHANGED events already.
 -				break;
 -			}
 -		}
 -		break;
 -		
 -		default:
 -		break;
 -	}
 -
 -}
 -
 -void LLVOVolume::sendMediaDataUpdate()
 -{
 -    if (sObjectMediaClient)
 -		sObjectMediaClient->updateMedia(new LLMediaDataClientObjectImpl(this, false));
 -}
 -
 -void LLVOVolume::removeMediaImpl(S32 texture_index)
 -{
 -	if(mMediaImplList.size() <= (U32)texture_index || mMediaImplList[texture_index].isNull())
 -	{
 -		return ;
 -	}
 -
 -	//make the face referencing to mMediaImplList[texture_index] to point back to the old texture.
 -	if(mDrawable && texture_index < mDrawable->getNumFaces())
 -	{
 -		LLFace* facep = mDrawable->getFace(texture_index) ;
 -		if(facep)
 -		{
 -			LLViewerMediaTexture* media_tex = LLViewerTextureManager::findMediaTexture(mMediaImplList[texture_index]->getMediaTextureID()) ;
 -			if(media_tex)
 -			{
 -				media_tex->removeMediaFromFace(facep) ;
 -			}
 -		}
 -	}		
 -	
 -	//check if some other face(s) of this object reference(s)to this media impl.
 -	S32 i ;
 -	S32 end = (S32)mMediaImplList.size() ;
 -	for(i = 0; i < end ; i++)
 -	{
 -		if( i != texture_index && mMediaImplList[i] == mMediaImplList[texture_index])
 -		{
 -			break ;
 -		}
 -	}
 -
 -	if(i == end) //this object does not need this media impl.
 -	{
 -		mMediaImplList[texture_index]->removeObject(this) ;
 -	}
 -
 -	mMediaImplList[texture_index] = NULL ;
 -	return ;
 -}
 -
 -void LLVOVolume::addMediaImpl(LLViewerMediaImpl* media_impl, S32 texture_index)
 -{
 -	if((S32)mMediaImplList.size() < texture_index + 1)
 -	{
 -		mMediaImplList.resize(texture_index + 1) ;
 -	}
 -	
 -	if(mMediaImplList[texture_index].notNull())
 -	{
 -		if(mMediaImplList[texture_index] == media_impl)
 -		{
 -			return ;
 -		}
 -
 -		removeMediaImpl(texture_index) ;
 -	}
 -
 -	mMediaImplList[texture_index] = media_impl;
 -	media_impl->addObject(this) ;	
 -
 -	//add the face to show the media if it is in playing
 -	if(mDrawable)
 -	{
 -		LLFace* facep = mDrawable->getFace(texture_index) ;
 -		if(facep)
 -		{
 -			LLViewerMediaTexture* media_tex = LLViewerTextureManager::findMediaTexture(mMediaImplList[texture_index]->getMediaTextureID()) ;
 -			if(media_tex)
 -			{
 -				media_tex->addMediaToFace(facep) ;
 -			}
 -		}
 -		else //the face is not available now, start media on this face later.
 -		{
 -			media_impl->setUpdated(TRUE) ;
 -		}
 -	}
 -	return ;
 -}
 -
 -viewer_media_t LLVOVolume::getMediaImpl(U8 face_id) const
 -{
 -	if(mMediaImplList.size() > face_id)
 -	{
 -		return mMediaImplList[face_id];
 -	}
 -	return NULL;
 -}
 -
 -F64 LLVOVolume::getTotalMediaInterest() const
 -{
 -	// If this object is currently focused, this object has "high" interest
 -	if (LLViewerMediaFocus::getInstance()->getFocusedObjectID() == getID())
 -		return F64_MAX;
 -	
 -	F64 interest = (F64)-1.0;  // means not interested;
 -    
 -	// If this object is selected, this object has "high" interest, but since 
 -	// there can be more than one, we still add in calculated impl interest
 -	// XXX Sadly, 'contains()' doesn't take a const :(
 -	if (LLSelectMgr::getInstance()->getSelection()->contains(const_cast<LLVOVolume*>(this)))
 -		interest = F64_MAX / 2.0;
 -	
 -	int i = 0;
 -	const int end = getNumTEs();
 -	for ( ; i < end; ++i)
 -	{
 -		const viewer_media_t &impl = getMediaImpl(i);
 -		if (!impl.isNull())
 -		{
 -			if (interest == (F64)-1.0) interest = (F64)0.0;
 -			interest += impl->getInterest();
 -		}
 -	}
 -	return interest;
 -}
 -
 -S32 LLVOVolume::getFaceIndexWithMediaImpl(const LLViewerMediaImpl* media_impl, S32 start_face_id)
 -{
 -	S32 end = (S32)mMediaImplList.size() ;
 -	for(S32 face_id = start_face_id + 1; face_id < end; face_id++)
 -	{
 -		if(mMediaImplList[face_id] == media_impl)
 -		{
 -			return face_id ;
 -		}
 -	}
 -	return -1 ;
 -}
 -
 -//----------------------------------------------------------------------------
 -
 -void LLVOVolume::setLightTextureID(LLUUID id)
 -{
 -	if (id.notNull())
 -	{
 -		if (!hasLightTexture())
 -		{
 -			setParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE, TRUE, true);
 -		}
 -		LLLightImageParams* param_block = (LLLightImageParams*) getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE);
 -		if (param_block && param_block->getLightTexture() != id)
 -		{
 -			param_block->setLightTexture(id);
 -			parameterChanged(LLNetworkData::PARAMS_LIGHT_IMAGE, true);
 -		}
 -	}
 -	else
 -	{
 -		if (hasLightTexture())
 -		{
 -			setParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE, FALSE, true);
 -			mLightTexture = NULL;
 -		}
 -	}		
 -}
 -
 -void LLVOVolume::setSpotLightParams(LLVector3 params)
 -{
 -	LLLightImageParams* param_block = (LLLightImageParams*) getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE);
 -	if (param_block && param_block->getParams() != params)
 -	{
 -		param_block->setParams(params);
 -		parameterChanged(LLNetworkData::PARAMS_LIGHT_IMAGE, true);
 -	}
 -}
 -		
 -void LLVOVolume::setIsLight(BOOL is_light)
 -{
 -	if (is_light != getIsLight())
 -	{
 -		if (is_light)
 -		{
 -			setParameterEntryInUse(LLNetworkData::PARAMS_LIGHT, TRUE, true);
 -		}
 -		else
 -		{
 -			setParameterEntryInUse(LLNetworkData::PARAMS_LIGHT, FALSE, true);
 -		}
 -
 -		if (is_light)
 -		{
 -			// Add it to the pipeline mLightSet
 -			gPipeline.setLight(mDrawable, TRUE);
 -		}
 -		else
 -		{
 -			// Not a light.  Remove it from the pipeline's light set.
 -			gPipeline.setLight(mDrawable, FALSE);
 -		}
 -	}
 -}
 -
 -void LLVOVolume::setLightColor(const LLColor3& color)
 -{
 -	LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
 -	if (param_block)
 -	{
 -		if (param_block->getColor() != color)
 -		{
 -			param_block->setColor(LLColor4(color, param_block->getColor().mV[3]));
 -			parameterChanged(LLNetworkData::PARAMS_LIGHT, true);
 -			gPipeline.markTextured(mDrawable);
 -			mFaceMappingChanged = TRUE;
 -		}
 -	}
 -}
 -
 -void LLVOVolume::setLightIntensity(F32 intensity)
 -{
 -	LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
 -	if (param_block)
 -	{
 -		if (param_block->getColor().mV[3] != intensity)
 -		{
 -			param_block->setColor(LLColor4(LLColor3(param_block->getColor()), intensity));
 -			parameterChanged(LLNetworkData::PARAMS_LIGHT, true);
 -		}
 -	}
 -}
 -
 -void LLVOVolume::setLightRadius(F32 radius)
 -{
 -	LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
 -	if (param_block)
 -	{
 -		if (param_block->getRadius() != radius)
 -		{
 -			param_block->setRadius(radius);
 -			parameterChanged(LLNetworkData::PARAMS_LIGHT, true);
 -		}
 -	}
 -}
 -
 -void LLVOVolume::setLightFalloff(F32 falloff)
 -{
 -	LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
 -	if (param_block)
 -	{
 -		if (param_block->getFalloff() != falloff)
 -		{
 -			param_block->setFalloff(falloff);
 -			parameterChanged(LLNetworkData::PARAMS_LIGHT, true);
 -		}
 -	}
 -}
 -
 -void LLVOVolume::setLightCutoff(F32 cutoff)
 -{
 -	LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
 -	if (param_block)
 -	{
 -		if (param_block->getCutoff() != cutoff)
 -		{
 -			param_block->setCutoff(cutoff);
 -			parameterChanged(LLNetworkData::PARAMS_LIGHT, true);
 -		}
 -	}
 -}
 -
 -//----------------------------------------------------------------------------
 -
 -BOOL LLVOVolume::getIsLight() const
 -{
 -	return getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT);
 -}
 -
 -LLColor3 LLVOVolume::getLightBaseColor() const
 -{
 -	const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
 -	if (param_block)
 -	{
 -		return LLColor3(param_block->getColor());
 -	}
 -	else
 -	{
 -		return LLColor3(1,1,1);
 -	}
 -}
 -
 -LLColor3 LLVOVolume::getLightColor() const
 -{
 -	const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
 -	if (param_block)
 -	{
 -		return LLColor3(param_block->getColor()) * param_block->getColor().mV[3];
 -	}
 -	else
 -	{
 -		return LLColor3(1,1,1);
 -	}
 -}
 -
 -LLUUID LLVOVolume::getLightTextureID() const
 -{
 -	if (getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE))
 -	{
 -		const LLLightImageParams *param_block = (const LLLightImageParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE);
 -		if (param_block)
 -		{
 -			return param_block->getLightTexture();
 -		}
 -	}
 -	
 -	return LLUUID::null;
 -}
 -
 -
 -LLVector3 LLVOVolume::getSpotLightParams() const
 -{
 -	if (getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE))
 -	{
 -		const LLLightImageParams *param_block = (const LLLightImageParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE);
 -		if (param_block)
 -		{
 -			return param_block->getParams();
 -		}
 -	}
 -	
 -	return LLVector3();
 -}
 -
 -F32 LLVOVolume::getSpotLightPriority() const
 -{
 -	return mSpotLightPriority;
 -}
 -
 -void LLVOVolume::updateSpotLightPriority()
 -{
 -	LLVector3 pos = mDrawable->getPositionAgent();
 -	LLVector3 at(0,0,-1);
 -	at *= getRenderRotation();
 -
 -	F32 r = getLightRadius()*0.5f;
 -
 -	pos += at * r;
 -
 -	at = LLViewerCamera::getInstance()->getAtAxis();
 -
 -	pos -= at * r;
 -	
 -	mSpotLightPriority = gPipeline.calcPixelArea(pos, LLVector3(r,r,r), *LLViewerCamera::getInstance());
 -
 -	if (mLightTexture.notNull())
 -	{
 -		mLightTexture->addTextureStats(mSpotLightPriority);
 -		mLightTexture->setBoostLevel(LLViewerTexture::BOOST_CLOUDS);
 -	}
 -}
 -
 -
 -bool LLVOVolume::isLightSpotlight() const
 -{
 -	LLLightImageParams* params = (LLLightImageParams*) getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE);
 -	if (params)
 -	{
 -		return params->isLightSpotlight();
 -	}
 -	return false;
 -}
 -
 -
 -LLViewerTexture* LLVOVolume::getLightTexture()
 -{
 -	LLUUID id = getLightTextureID();
 -
 -	if (id.notNull())
 -	{
 -		if (mLightTexture.isNull() || id != mLightTexture->getID())
 -		{
 -			mLightTexture = LLViewerTextureManager::getFetchedTexture(id);
 -		}
 -	}
 -	else
 -	{
 -		mLightTexture = NULL;
 -	}
 -
 -	return mLightTexture;
 -}
 -
 -F32 LLVOVolume::getLightIntensity() const
 -{
 -	const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
 -	if (param_block)
 -	{
 -		return param_block->getColor().mV[3];
 -	}
 -	else
 -	{
 -		return 1.f;
 -	}
 -}
 -
 -F32 LLVOVolume::getLightRadius() const
 -{
 -	const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
 -	if (param_block)
 -	{
 -		return param_block->getRadius();
 -	}
 -	else
 -	{
 -		return 0.f;
 -	}
 -}
 -
 -F32 LLVOVolume::getLightFalloff() const
 -{
 -	const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
 -	if (param_block)
 -	{
 -		return param_block->getFalloff();
 -	}
 -	else
 -	{
 -		return 0.f;
 -	}
 -}
 -
 -F32 LLVOVolume::getLightCutoff() const
 -{
 -	const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
 -	if (param_block)
 -	{
 -		return param_block->getCutoff();
 -	}
 -	else
 -	{
 -		return 0.f;
 -	}
 -}
 -
 -U32 LLVOVolume::getVolumeInterfaceID() const
 -{
 -	if (mVolumeImpl)
 -	{
 -		return mVolumeImpl->getID();
 -	}
 -
 -	return 0;
 -}
 -
 -BOOL LLVOVolume::isFlexible() const
 -{
 -	if (getParameterEntryInUse(LLNetworkData::PARAMS_FLEXIBLE))
 -	{
 -		LLVolume* volume = getVolume();
 -		if (volume && volume->getParams().getPathParams().getCurveType() != LL_PCODE_PATH_FLEXIBLE)
 -		{
 -			LLVolumeParams volume_params = getVolume()->getParams();
 -			U8 profile_and_hole = volume_params.getProfileParams().getCurveType();
 -			volume_params.setType(profile_and_hole, LL_PCODE_PATH_FLEXIBLE);
 -		}
 -		return TRUE;
 -	}
 -	else
 -	{
 -		return FALSE;
 -	}
 -}
 -
 -BOOL LLVOVolume::isSculpted() const
 -{
 -	if (getParameterEntryInUse(LLNetworkData::PARAMS_SCULPT))
 -	{
 -		return TRUE;
 -	}
 -	
 -	return FALSE;
 -}
 -
 -BOOL LLVOVolume::isMesh() const
 -{
 -	if (isSculpted())
 -	{
 -		LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT);
 -		U8 sculpt_type = sculpt_params->getSculptType();
 -
 -		if ((sculpt_type & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)
 -			// mesh is a mesh
 -		{
 -			return TRUE;	
 -		}
 -	}
 -
 -	return FALSE;
 -}
 -
 -BOOL LLVOVolume::hasLightTexture() const
 -{
 -	if (getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE))
 -	{
 -		return TRUE;
 -	}
 -
 -	return FALSE;
 -}
 -
 -BOOL LLVOVolume::isVolumeGlobal() const
 -{
 -	if (mVolumeImpl)
 -	{
 -		return mVolumeImpl->isVolumeGlobal() ? TRUE : FALSE;
 -	}
 -	else if (mRiggedVolume.notNull())
 -	{
 -		return TRUE;
 -	}
 -
 -	return FALSE;
 -}
 -
 -BOOL LLVOVolume::canBeFlexible() const
 -{
 -	U8 path = getVolume()->getParams().getPathParams().getCurveType();
 -	return (path == LL_PCODE_PATH_FLEXIBLE || path == LL_PCODE_PATH_LINE);
 -}
 -
 -BOOL LLVOVolume::setIsFlexible(BOOL is_flexible)
 -{
 -	BOOL res = FALSE;
 -	BOOL was_flexible = isFlexible();
 -	LLVolumeParams volume_params;
 -	if (is_flexible)
 -	{
 -		if (!was_flexible)
 -		{
 -			volume_params = getVolume()->getParams();
 -			U8 profile_and_hole = volume_params.getProfileParams().getCurveType();
 -			volume_params.setType(profile_and_hole, LL_PCODE_PATH_FLEXIBLE);
 -			res = TRUE;
 -			setFlags(FLAGS_USE_PHYSICS, FALSE);
 -			setFlags(FLAGS_PHANTOM, TRUE);
 -			setParameterEntryInUse(LLNetworkData::PARAMS_FLEXIBLE, TRUE, true);
 -			if (mDrawable)
 -			{
 -				mDrawable->makeActive();
 -			}
 -		}
 -	}
 -	else
 -	{
 -		if (was_flexible)
 -		{
 -			volume_params = getVolume()->getParams();
 -			U8 profile_and_hole = volume_params.getProfileParams().getCurveType();
 -			volume_params.setType(profile_and_hole, LL_PCODE_PATH_LINE);
 -			res = TRUE;
 -			setFlags(FLAGS_PHANTOM, FALSE);
 -			setParameterEntryInUse(LLNetworkData::PARAMS_FLEXIBLE, FALSE, true);
 -		}
 -	}
 -	if (res)
 -	{
 -		res = setVolume(volume_params, 1);
 -		if (res)
 -		{
 -			markForUpdate(TRUE);
 -		}
 -	}
 -	return res;
 -}
 -
 -//----------------------------------------------------------------------------
 -
 -void LLVOVolume::generateSilhouette(LLSelectNode* nodep, const LLVector3& view_point)
 -{
 -	LLVolume *volume = getVolume();
 -
 -	if (volume)
 -	{
 -		LLVector3 view_vector;
 -		view_vector = view_point; 
 -
 -		//transform view vector into volume space
 -		view_vector -= getRenderPosition();
 -		mDrawable->mDistanceWRTCamera = view_vector.length();
 -		LLQuaternion worldRot = getRenderRotation();
 -		view_vector = view_vector * ~worldRot;
 -		if (!isVolumeGlobal())
 -		{
 -			LLVector3 objScale = getScale();
 -			LLVector3 invObjScale(1.f / objScale.mV[VX], 1.f / objScale.mV[VY], 1.f / objScale.mV[VZ]);
 -			view_vector.scaleVec(invObjScale);
 -		}
 -		
 -		updateRelativeXform();
 -		LLMatrix4 trans_mat = mRelativeXform;
 -		if (mDrawable->isStatic())
 -		{
 -			trans_mat.translate(getRegion()->getOriginAgent());
 -		}
 -
 -		volume->generateSilhouetteVertices(nodep->mSilhouetteVertices, nodep->mSilhouetteNormals, view_vector, trans_mat, mRelativeXformInvTrans, nodep->getTESelectMask());
 -
 -		nodep->mSilhouetteExists = TRUE;
 -	}
 -}
 -
 -void LLVOVolume::deleteFaces()
 -{
 -	S32 face_count = mNumFaces;
 -	if (mDrawable.notNull())
 -	{
 -		mDrawable->deleteFaces(0, face_count);
 -	}
 -
 -	mNumFaces = 0;
 -}
 -
 -void LLVOVolume::updateRadius()
 -{
 -	if (mDrawable.isNull())
 -	{
 -		return;
 -	}
 -	
 -	mVObjRadius = getScale().length();
 -	mDrawable->setRadius(mVObjRadius);
 -}
 -
 -
 -BOOL LLVOVolume::isAttachment() const
 -{
 -	return mState != 0 ;
 -}
 -
 -BOOL LLVOVolume::isHUDAttachment() const
 -{
 -	// *NOTE: we assume hud attachment points are in defined range
 -	// since this range is constant for backwards compatibility
 -	// reasons this is probably a reasonable assumption to make
 -	S32 attachment_id = ATTACHMENT_ID_FROM_STATE(mState);
 -	return ( attachment_id >= 31 && attachment_id <= 38 );
 -}
 -
 -
 -const LLMatrix4 LLVOVolume::getRenderMatrix() const
 -{
 -	if (mDrawable->isActive() && !mDrawable->isRoot())
 -	{
 -		return mDrawable->getParent()->getWorldMatrix();
 -	}
 -	return mDrawable->getWorldMatrix();
 -}
 -
 -// Returns a base cost and adds textures to passed in set.
 -// total cost is returned value + 5 * size of the resulting set.
 -// Cannot include cost of textures, as they may be re-used in linked
 -// children, and cost should only be increased for unique textures  -Nyx
 -U32 LLVOVolume::getRenderCost(std::set<LLUUID> &textures) const
 -{
 -	// base cost of each prim should be 10 points
 -	static const U32 ARC_PRIM_COST = 10;
 -	// per-prim costs
 -	static const U32 ARC_INVISI_COST = 1;
 -	static const U32 ARC_SHINY_COST = 1;
 -	static const U32 ARC_GLOW_COST = 1;
 -	static const U32 ARC_FLEXI_COST = 8;
 -	static const U32 ARC_PARTICLE_COST = 16;
 -	static const U32 ARC_BUMP_COST = 4;
 -
 -	// per-face costs
 -	static const U32 ARC_PLANAR_COST = 1;
 -	static const U32 ARC_ANIM_TEX_COST = 4;
 -	static const U32 ARC_ALPHA_COST = 4;
 -
 -	U32 shame = ARC_PRIM_COST;
 -
 -	U32 invisi = 0;
 -	U32 shiny = 0;
 -	U32 glow = 0;
 -	U32 alpha = 0;
 -	U32 flexi = 0;
 -	U32 animtex = 0;
 -	U32 particles = 0;
 -	U32 scale = 0;
 -	U32 bump = 0;
 -	U32 planar = 0;
 -
 -	if (isFlexible())
 -	{
 -		flexi = 1;
 -	}
 -	if (isParticleSource())
 -	{
 -		particles = 1;
 -	}
 -
 -	const LLVector3& sc = getScale();
 -	scale += (U32) sc.mV[0] + (U32) sc.mV[1] + (U32) sc.mV[2];
 -
 -	const LLDrawable* drawablep = mDrawable;
 -
 -	if (isSculpted())
 -	{
 -		const LLSculptParams *sculpt_params = (LLSculptParams *) getParameterEntry(LLNetworkData::PARAMS_SCULPT);
 -		LLUUID sculpt_id = sculpt_params->getSculptTexture();
 -		textures.insert(sculpt_id);
 -	}
 -
 -	for (S32 i = 0; i < drawablep->getNumFaces(); ++i)
 -	{
 -		const LLFace* face = drawablep->getFace(i);
 -		const LLTextureEntry* te = face->getTextureEntry();
 -		const LLViewerTexture* img = face->getTexture();
 -
 -		if (img)
 -		{
 -			textures.insert(img->getID());
 -		}
 -
 -		if (face->getPoolType() == LLDrawPool::POOL_ALPHA)
 -		{
 -			alpha++;
 -		}
 -		else if (img && img->getPrimaryFormat() == GL_ALPHA)
 -		{
 -			invisi = 1;
 -		}
 -
 -		if (te)
 -		{
 -			if (te->getBumpmap())
 -			{
 -				bump = 1;
 -			}
 -			if (te->getShiny())
 -			{
 -				shiny = 1;
 -			}
 -			if (te->getGlow() > 0.f)
 -			{
 -				glow = 1;
 -			}
 -			if (face->mTextureMatrix != NULL)
 -			{
 -				animtex++;
 -			}
 -			if (te->getTexGen())
 -			{
 -				planar++;
 -			}
 -		}
 -	}
 -
 -
 -	shame += invisi * ARC_INVISI_COST;
 -	shame += shiny * ARC_SHINY_COST;
 -	shame += glow * ARC_GLOW_COST;
 -	shame += alpha * ARC_ALPHA_COST;
 -	shame += flexi * ARC_FLEXI_COST;
 -	shame += animtex * ARC_ANIM_TEX_COST;
 -	shame += particles * ARC_PARTICLE_COST;
 -	shame += bump * ARC_BUMP_COST;
 -	shame += planar * ARC_PLANAR_COST;
 -	shame += scale;
 -
 -	LLViewerObject::const_child_list_t& child_list = getChildren();
 -	for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
 -		 iter != child_list.end(); 
 -		 ++iter)
 -	{
 -		const LLViewerObject* child_objectp = *iter;
 -		const LLDrawable* child_drawablep = child_objectp->mDrawable;
 -		if (child_drawablep)
 -		{
 -			const LLVOVolume* child_volumep = child_drawablep->getVOVolume();
 -			if (child_volumep)
 -			{
 -				shame += child_volumep->getRenderCost(textures);
 -			}
 -		}
 -	}
 -
 -	return shame;
 -
 -}
 -
 -F32 LLVOVolume::getStreamingCost(S32* bytes, S32* visible_bytes)
 -{
 -	if (isMesh())
 -	{	
 -		LLSD& header = gMeshRepo.getMeshHeader(getVolume()->getParams().getSculptID());
 -
 -		F32 radius = getScale().length();
 -		
 -		return LLMeshRepository::getStreamingCost(header, radius, bytes, visible_bytes, mLOD);
 -	}
 -		
 -	return 0.f;
 -}
 -
 -U32 LLVOVolume::getTriangleCount()
 -{
 -	U32 count = 0;
 -	LLVolume* volume = getVolume();
 -	if (volume)
 -	{
 -		count = volume->getNumTriangles();
 -	}
 -
 -	return count;
 -}
 -
 -U32 LLVOVolume::getHighLODTriangleCount()
 -{
 -	U32 ret = 0;
 -
 -	LLVolume* volume = getVolume();
 -
 -	if (!isSculpted())
 -	{
 +/**  + * @file llvovolume.cpp + * @brief LLVOVolume class implementation + * + * $LicenseInfo:firstyear=2001&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$ + */ + +// A "volume" is a box, cylinder, sphere, or other primitive shape. + +#include "llviewerprecompiledheaders.h" + +#include "llvovolume.h" + +#include <sstream> + +#include "llviewercontrol.h" +#include "lldir.h" +#include "llflexibleobject.h" +#include "llfloatertools.h" +#include "llmaterialtable.h" +#include "llprimitive.h" +#include "llvolume.h" +#include "llvolumeoctree.h" +#include "llvolumemgr.h" +#include "llvolumemessage.h" +#include "material_codes.h" +#include "message.h" +#include "llpluginclassmedia.h" // for code in the mediaEvent handler +#include "object_flags.h" +#include "llagentconstants.h" +#include "lldrawable.h" +#include "lldrawpoolavatar.h" +#include "lldrawpoolbump.h" +#include "llface.h" +#include "llspatialpartition.h" +#include "llhudmanager.h" +#include "llflexibleobject.h" +#include "llsky.h" +#include "lltexturefetch.h" +#include "llvector4a.h" +#include "llviewercamera.h" +#include "llviewertexturelist.h" +#include "llviewerobjectlist.h" +#include "llviewerregion.h" +#include "llviewertextureanim.h" +#include "llworld.h" +#include "llselectmgr.h" +#include "pipeline.h" +#include "llsdutil.h" +#include "llmatrix4a.h" +#include "llmediaentry.h" +#include "llmediadataclient.h" +#include "llmeshrepository.h" +#include "llagent.h" +#include "llviewermediafocus.h" +#include "llvoavatar.h" + +const S32 MIN_QUIET_FRAMES_COALESCE = 30; +const F32 FORCE_SIMPLE_RENDER_AREA = 512.f; +const F32 FORCE_CULL_AREA = 8.f; +const F32 MAX_LOD_DISTANCE = 24.f; + + +BOOL gAnimateTextures = TRUE; +//extern BOOL gHideSelectedObjects; + +F32 LLVOVolume::sLODFactor = 1.f; +F32	LLVOVolume::sLODSlopDistanceFactor = 0.5f; //Changing this to zero, effectively disables the LOD transition slop  +F32 LLVOVolume::sDistanceFactor = 1.0f; +S32 LLVOVolume::sNumLODChanges = 0; +LLPointer<LLObjectMediaDataClient> LLVOVolume::sObjectMediaClient = NULL; +LLPointer<LLObjectMediaNavigateClient> LLVOVolume::sObjectMediaNavigateClient = NULL; + +static LLFastTimer::DeclareTimer FTM_GEN_TRIANGLES("Generate Triangles"); +static LLFastTimer::DeclareTimer FTM_GEN_VOLUME("Generate Volumes"); +static LLFastTimer::DeclareTimer FTM_VOLUME_TEXTURES("Volume Textures"); + +// Implementation class of LLMediaDataClientObject.  See llmediadataclient.h +class LLMediaDataClientObjectImpl : public LLMediaDataClientObject +{ +public: +	LLMediaDataClientObjectImpl(LLVOVolume *obj, bool isNew) : mObject(obj), mNew(isNew)  +	{ +		mObject->addMDCImpl(); +	} +	~LLMediaDataClientObjectImpl() +	{ +		mObject->removeMDCImpl(); +	} +	 +	virtual U8 getMediaDataCount() const  +		{ return mObject->getNumTEs(); } + +	virtual LLSD getMediaDataLLSD(U8 index) const  +		{ +			LLSD result; +			LLTextureEntry *te = mObject->getTE(index);  +			if (NULL != te) +			{ +				llassert((te->getMediaData() != NULL) == te->hasMedia()); +				if (te->getMediaData() != NULL) +				{ +					result = te->getMediaData()->asLLSD(); +					// XXX HACK: workaround bug in asLLSD() where whitelist is not set properly +					// See DEV-41949 +					if (!result.has(LLMediaEntry::WHITELIST_KEY)) +					{ +						result[LLMediaEntry::WHITELIST_KEY] = LLSD::emptyArray(); +					} +				} +			} +			return result; +		} +	virtual bool isCurrentMediaUrl(U8 index, const std::string &url) const +		{ +			LLTextureEntry *te = mObject->getTE(index);  +			if (te) +			{ +				if (te->getMediaData()) +				{ +					return (te->getMediaData()->getCurrentURL() == url); +				} +			} +			return url.empty(); +		} + +	virtual LLUUID getID() const +		{ return mObject->getID(); } + +	virtual void mediaNavigateBounceBack(U8 index) +		{ mObject->mediaNavigateBounceBack(index); } +	 +	virtual bool hasMedia() const +		{ return mObject->hasMedia(); } +	 +	virtual void updateObjectMediaData(LLSD const &data, const std::string &version_string)  +		{ mObject->updateObjectMediaData(data, version_string); } +	 +	virtual F64 getMediaInterest() const  +		{  +			F64 interest = mObject->getTotalMediaInterest(); +			if (interest < (F64)0.0) +			{ +				// media interest not valid yet, try pixel area +				interest = mObject->getPixelArea(); +				// HACK: force recalculation of pixel area if interest is the "magic default" of 1024. +				if (interest == 1024.f) +				{ +					const_cast<LLVOVolume*>(static_cast<LLVOVolume*>(mObject))->setPixelAreaAndAngle(gAgent); +					interest = mObject->getPixelArea(); +				} +			} +			return interest;  +		} +	 +	virtual bool isInterestingEnough() const +		{ +			return LLViewerMedia::isInterestingEnough(mObject, getMediaInterest()); +		} + +	virtual std::string getCapabilityUrl(const std::string &name) const +		{ return mObject->getRegion()->getCapability(name); } +	 +	virtual bool isDead() const +		{ return mObject->isDead(); } +	 +	virtual U32 getMediaVersion() const +		{ return LLTextureEntry::getVersionFromMediaVersionString(mObject->getMediaURL()); } +	 +	virtual bool isNew() const +		{ return mNew; } + +private: +	LLPointer<LLVOVolume> mObject; +	bool mNew; +}; + + +LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) +	: LLViewerObject(id, pcode, regionp), +	  mVolumeImpl(NULL) +{ +	mTexAnimMode = 0; +	mRelativeXform.setIdentity(); +	mRelativeXformInvTrans.setIdentity(); + +	mFaceMappingChanged = FALSE; +	mLOD = MIN_LOD; +	mTextureAnimp = NULL; +	mVolumeChanged = FALSE; +	mVObjRadius = LLVector3(1,1,0.5f).length(); +	mNumFaces = 0; +	mLODChanged = FALSE; +	mSculptChanged = FALSE; +	mSpotLightPriority = 0.f; + +	mMediaImplList.resize(getNumTEs()); +	mLastFetchedMediaVersion = -1; +	mIndexInTex = 0; +	mMDCImplCount = 0; +} + +LLVOVolume::~LLVOVolume() +{ +	delete mTextureAnimp; +	mTextureAnimp = NULL; +	delete mVolumeImpl; +	mVolumeImpl = NULL; + +	if(!mMediaImplList.empty()) +	{ +		for(U32 i = 0 ; i < mMediaImplList.size() ; i++) +		{ +			if(mMediaImplList[i].notNull()) +			{ +				mMediaImplList[i]->removeObject(this) ; +			} +		} +	} +} + +void LLVOVolume::markDead() +{ +	if (!mDead) +	{ +		if(getMDCImplCount() > 0) +		{ +			LLMediaDataClientObject::ptr_t obj = new LLMediaDataClientObjectImpl(const_cast<LLVOVolume*>(this), false); +			if (sObjectMediaClient) sObjectMediaClient->removeFromQueue(obj); +			if (sObjectMediaNavigateClient) sObjectMediaNavigateClient->removeFromQueue(obj); +		} +		 +		// Detach all media impls from this object +		for(U32 i = 0 ; i < mMediaImplList.size() ; i++) +		{ +			removeMediaImpl(i); +		} + +		if (mSculptTexture.notNull()) +		{ +			mSculptTexture->removeVolume(this); +		} +	} +	 +	LLViewerObject::markDead(); +} + + +// static +void LLVOVolume::initClass() +{ +	// gSavedSettings better be around +	if (gSavedSettings.getBOOL("PrimMediaMasterEnabled")) +	{ +		const F32 queue_timer_delay = gSavedSettings.getF32("PrimMediaRequestQueueDelay"); +		const F32 retry_timer_delay = gSavedSettings.getF32("PrimMediaRetryTimerDelay"); +		const U32 max_retries = gSavedSettings.getU32("PrimMediaMaxRetries"); +		const U32 max_sorted_queue_size = gSavedSettings.getU32("PrimMediaMaxSortedQueueSize"); +		const U32 max_round_robin_queue_size = gSavedSettings.getU32("PrimMediaMaxRoundRobinQueueSize"); +		sObjectMediaClient = new LLObjectMediaDataClient(queue_timer_delay, retry_timer_delay, max_retries,  +														 max_sorted_queue_size, max_round_robin_queue_size); +		sObjectMediaNavigateClient = new LLObjectMediaNavigateClient(queue_timer_delay, retry_timer_delay,  +																	 max_retries, max_sorted_queue_size, max_round_robin_queue_size); +	} +} + +// static +void LLVOVolume::cleanupClass() +{ +    sObjectMediaClient = NULL; +    sObjectMediaNavigateClient = NULL; +} + +U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys, +										  void **user_data, +										  U32 block_num, EObjectUpdateType update_type, +										  LLDataPacker *dp) +{ +	LLColor4U color; +	const S32 teDirtyBits = (TEM_CHANGE_TEXTURE|TEM_CHANGE_COLOR|TEM_CHANGE_MEDIA); + +	// Do base class updates... +	U32 retval = LLViewerObject::processUpdateMessage(mesgsys, user_data, block_num, update_type, dp); + +	LLUUID sculpt_id; +	U8 sculpt_type = 0; +	if (isSculpted()) +	{ +		LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT); +		sculpt_id = sculpt_params->getSculptTexture(); +		sculpt_type = sculpt_params->getSculptType(); +	} + +	if (!dp) +	{ +		if (update_type == OUT_FULL) +		{ +			//////////////////////////////// +			// +			// Unpack texture animation data +			// +			// + +			if (mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_TextureAnim)) +			{ +				if (!mTextureAnimp) +				{ +					mTextureAnimp = new LLViewerTextureAnim(); +				} +				else +				{ +					if (!(mTextureAnimp->mMode & LLTextureAnim::SMOOTH)) +					{ +						mTextureAnimp->reset(); +					} +				} +				mTexAnimMode = 0; +				mTextureAnimp->unpackTAMessage(mesgsys, block_num); +			} +			else +			{ +				if (mTextureAnimp) +				{ +					delete mTextureAnimp; +					mTextureAnimp = NULL; +					gPipeline.markTextured(mDrawable); +					mFaceMappingChanged = TRUE; +					mTexAnimMode = 0; +				} +			} + +			// Unpack volume data +			LLVolumeParams volume_params; +			LLVolumeMessage::unpackVolumeParams(&volume_params, mesgsys, _PREHASH_ObjectData, block_num); +			volume_params.setSculptID(sculpt_id, sculpt_type); + +			if (setVolume(volume_params, 0)) +			{ +				markForUpdate(TRUE); +			} +		} + +		// Sigh, this needs to be done AFTER the volume is set as well, otherwise bad stuff happens... +		//////////////////////////// +		// +		// Unpack texture entry data +		// +		S32 result = unpackTEMessage(mesgsys, _PREHASH_ObjectData, block_num); +		if (result & teDirtyBits) +		{ +			updateTEData(); +		} +		if (result & TEM_CHANGE_MEDIA) +		{ +			retval |= MEDIA_FLAGS_CHANGED; +		} +	} +	else +	{ +		// CORY TO DO: Figure out how to get the value here +		if (update_type != OUT_TERSE_IMPROVED) +		{ +			LLVolumeParams volume_params; +			BOOL res = LLVolumeMessage::unpackVolumeParams(&volume_params, *dp); +			if (!res) +			{ +				llwarns << "Bogus volume parameters in object " << getID() << llendl; +				llwarns << getRegion()->getOriginGlobal() << llendl; +			} + +			volume_params.setSculptID(sculpt_id, sculpt_type); + +			if (setVolume(volume_params, 0)) +			{ +				markForUpdate(TRUE); +			} +			S32 res2 = unpackTEMessage(*dp); +			if (TEM_INVALID == res2) +			{ +				// There's something bogus in the data that we're unpacking. +				dp->dumpBufferToLog(); +				llwarns << "Flushing cache files" << llendl; + +				if(LLVOCache::hasInstance() && getRegion()) +				{ +					LLVOCache::getInstance()->removeEntry(getRegion()->getHandle()) ; +				} +				 +				llwarns << "Bogus TE data in " << getID() << llendl; +			} +			else  +			{ +				if (res2 & teDirtyBits)  +				{ +					updateTEData(); +				} +				if (res2 & TEM_CHANGE_MEDIA) +				{ +					retval |= MEDIA_FLAGS_CHANGED; +				} +			} + +			U32 value = dp->getPassFlags(); + +			if (value & 0x40) +			{ +				if (!mTextureAnimp) +				{ +					mTextureAnimp = new LLViewerTextureAnim(); +				} +				else +				{ +					if (!(mTextureAnimp->mMode & LLTextureAnim::SMOOTH)) +					{ +						mTextureAnimp->reset(); +					} +				} +				mTexAnimMode = 0; +				mTextureAnimp->unpackTAMessage(*dp); +			} +			else if (mTextureAnimp) +			{ +				delete mTextureAnimp; +				mTextureAnimp = NULL; +				gPipeline.markTextured(mDrawable); +				mFaceMappingChanged = TRUE; +				mTexAnimMode = 0; +			} +		} +		else +		{ +			S32 texture_length = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_TextureEntry); +			if (texture_length) +			{ +				U8							tdpbuffer[1024]; +				LLDataPackerBinaryBuffer	tdp(tdpbuffer, 1024); +				mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_TextureEntry, tdpbuffer, 0, block_num); +				S32 result = unpackTEMessage(tdp); +				if (result & teDirtyBits) +				{ +					updateTEData(); +				} +				if (result & TEM_CHANGE_MEDIA) +				{ +					retval |= MEDIA_FLAGS_CHANGED; +				} +			} +		} +	} +	if (retval & (MEDIA_URL_REMOVED | MEDIA_URL_ADDED | MEDIA_URL_UPDATED | MEDIA_FLAGS_CHANGED))  +	{ +		// If only the media URL changed, and it isn't a media version URL, +		// ignore it +		if ( ! ( retval & (MEDIA_URL_ADDED | MEDIA_URL_UPDATED) && +				 mMedia && ! mMedia->mMediaURL.empty() && +				 ! LLTextureEntry::isMediaVersionString(mMedia->mMediaURL) ) ) +		{ +			// If the media changed at all, request new media data +			LL_DEBUGS("MediaOnAPrim") << "Media update: " << getID() << ": retval=" << retval << " Media URL: " << +                ((mMedia) ?  mMedia->mMediaURL : std::string("")) << LL_ENDL; +			requestMediaDataUpdate(retval & MEDIA_FLAGS_CHANGED); +		} +        else { +            LL_INFOS("MediaOnAPrim") << "Ignoring media update for: " << getID() << " Media URL: " << +                ((mMedia) ?  mMedia->mMediaURL : std::string("")) << LL_ENDL; +        } +	} +	// ...and clean up any media impls +	cleanUpMediaImpls(); + +	return retval; +} + + +void LLVOVolume::animateTextures() +{ +	F32 off_s = 0.f, off_t = 0.f, scale_s = 1.f, scale_t = 1.f, rot = 0.f; +	S32 result = mTextureAnimp->animateTextures(off_s, off_t, scale_s, scale_t, rot); +	 +	if (result) +	{ +		if (!mTexAnimMode) +		{ +			mFaceMappingChanged = TRUE; +			gPipeline.markTextured(mDrawable); +		} +		mTexAnimMode = result | mTextureAnimp->mMode; +				 +		S32 start=0, end=mDrawable->getNumFaces()-1; +		if (mTextureAnimp->mFace >= 0 && mTextureAnimp->mFace <= end) +		{ +			start = end = mTextureAnimp->mFace; +		} +		 +		for (S32 i = start; i <= end; i++) +		{ +			LLFace* facep = mDrawable->getFace(i); +			if(facep->getVirtualSize() <= MIN_TEX_ANIM_SIZE && facep->mTextureMatrix) continue; + +			const LLTextureEntry* te = facep->getTextureEntry(); +			 +			if (!te) +			{ +				continue; +			} +		 +			if (!(result & LLViewerTextureAnim::ROTATE)) +			{ +				te->getRotation(&rot); +			} +			if (!(result & LLViewerTextureAnim::TRANSLATE)) +			{ +				te->getOffset(&off_s,&off_t); +			}			 +			if (!(result & LLViewerTextureAnim::SCALE)) +			{ +				te->getScale(&scale_s, &scale_t); +			} + +			if (!facep->mTextureMatrix) +			{ +				facep->mTextureMatrix = new LLMatrix4(); +			} + +			LLMatrix4& tex_mat = *facep->mTextureMatrix; +			tex_mat.setIdentity(); +			LLVector3 trans ; + +			if(facep->isAtlasInUse()) +			{ +				// +				//if use atlas for animated texture +				//apply the following transform to the animation matrix. +				// + +				F32 tcoord_xoffset = 0.f ; +				F32 tcoord_yoffset = 0.f ; +				F32 tcoord_xscale = 1.f ; +				F32 tcoord_yscale = 1.f ;			 +				if(facep->isAtlasInUse()) +				{ +					const LLVector2* tmp = facep->getTexCoordOffset() ; +					tcoord_xoffset = tmp->mV[0] ;  +					tcoord_yoffset = tmp->mV[1] ; + +					tmp = facep->getTexCoordScale() ; +					tcoord_xscale = tmp->mV[0] ;  +					tcoord_yscale = tmp->mV[1] ;	 +				} +				trans.set(LLVector3(tcoord_xoffset + tcoord_xscale * (off_s+0.5f), tcoord_yoffset + tcoord_yscale * (off_t+0.5f), 0.f)); + +				tex_mat.translate(LLVector3(-(tcoord_xoffset + tcoord_xscale * 0.5f), -(tcoord_yoffset + tcoord_yscale * 0.5f), 0.f)); +			} +			else	//non atlas +			{ +				trans.set(LLVector3(off_s+0.5f, off_t+0.5f, 0.f));			 +				tex_mat.translate(LLVector3(-0.5f, -0.5f, 0.f)); +			} + +			LLVector3 scale(scale_s, scale_t, 1.f);			 +			LLQuaternion quat; +			quat.setQuat(rot, 0, 0, -1.f); +		 +			tex_mat.rotate(quat);				 + +			LLMatrix4 mat; +			mat.initAll(scale, LLQuaternion(), LLVector3()); +			tex_mat *= mat; +		 +			tex_mat.translate(trans); +		} +	} +	else +	{ +		if (mTexAnimMode && mTextureAnimp->mRate == 0) +		{ +			U8 start, count; + +			if (mTextureAnimp->mFace == -1) +			{ +				start = 0; +				count = getNumTEs(); +			} +			else +			{ +				start = (U8) mTextureAnimp->mFace; +				count = 1; +			} + +			for (S32 i = start; i < start + count; i++) +			{ +				if (mTexAnimMode & LLViewerTextureAnim::TRANSLATE) +				{ +					setTEOffset(i, mTextureAnimp->mOffS, mTextureAnimp->mOffT);				 +				} +				if (mTexAnimMode & LLViewerTextureAnim::SCALE) +				{ +					setTEScale(i, mTextureAnimp->mScaleS, mTextureAnimp->mScaleT);	 +				} +				if (mTexAnimMode & LLViewerTextureAnim::ROTATE) +				{ +					setTERotation(i, mTextureAnimp->mRot); +				} +			} + +			gPipeline.markTextured(mDrawable); +			mFaceMappingChanged = TRUE; +			mTexAnimMode = 0; +		} +	} +} +BOOL LLVOVolume::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) +{ +	LLViewerObject::idleUpdate(agent, world, time); + +	static LLFastTimer::DeclareTimer ftm("Volume"); +	LLFastTimer t(ftm); + +	if (mDead || mDrawable.isNull()) +	{ +		return TRUE; +	} +	 +	/////////////////////// +	// +	// Do texture animation stuff +	// + +	if (mTextureAnimp && gAnimateTextures) +	{ +		animateTextures(); +	} + +	// Dispatch to implementation +	if (mVolumeImpl) +	{ +		mVolumeImpl->doIdleUpdate(agent, world, time); +	} + +	const S32 MAX_ACTIVE_OBJECT_QUIET_FRAMES = 40; + +	if (mDrawable->isActive()) +	{ +		if (mDrawable->isRoot() &&  +			mDrawable->mQuietCount++ > MAX_ACTIVE_OBJECT_QUIET_FRAMES &&  +			(!mDrawable->getParent() || !mDrawable->getParent()->isActive())) +		{ +			mDrawable->makeStatic(); +		} +	} + +	return TRUE; +} + +void LLVOVolume::updateTextures() +{ +	const F32 TEXTURE_AREA_REFRESH_TIME = 5.f; // seconds +	if (mTextureUpdateTimer.getElapsedTimeF32() > TEXTURE_AREA_REFRESH_TIME) +	{ +		updateTextureVirtualSize();		 +	} +} + +BOOL LLVOVolume::isVisible() const  +{ +	if(mDrawable.notNull() && mDrawable->isVisible()) +	{ +		return TRUE ; +	} + +	if(isAttachment()) +	{ +		LLViewerObject* objp = (LLViewerObject*)getParent() ; +		while(objp && !objp->isAvatar()) +		{ +			objp = (LLViewerObject*)objp->getParent() ; +		} + +		return objp && objp->mDrawable.notNull() && objp->mDrawable->isVisible() ; +	} + +	return FALSE ; +} + +void LLVOVolume::updateTextureVirtualSize() +{ +	LLFastTimer ftm(FTM_VOLUME_TEXTURES); +	// Update the pixel area of all faces + +	if(!isVisible()) +	{ +		return ; +	} + +	if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SIMPLE)) +	{ +		return; +	} + +	static LLCachedControl<bool> dont_load_textures(gSavedSettings,"TextureDisable"); +		 +	if (dont_load_textures || LLAppViewer::getTextureFetch()->mDebugPause) // || !mDrawable->isVisible()) +	{ +		return; +	} + +	mTextureUpdateTimer.reset(); +	 +	F32 old_area = mPixelArea; +	mPixelArea = 0.f; + +	const S32 num_faces = mDrawable->getNumFaces(); +	F32 min_vsize=999999999.f, max_vsize=0.f; +	LLViewerCamera* camera = LLViewerCamera::getInstance(); +	for (S32 i = 0; i < num_faces; i++) +	{ +		LLFace* face = mDrawable->getFace(i); +		const LLTextureEntry *te = face->getTextureEntry(); +		LLViewerTexture *imagep = face->getTexture(); +		if (!imagep || !te ||			 +			face->mExtents[0].equals3(face->mExtents[1])) +		{ +			continue; +		} +		 +		F32 vsize; +		F32 old_size = face->getVirtualSize(); + +		if (isHUDAttachment()) +		{ +			F32 area = (F32) camera->getScreenPixelArea(); +			vsize = area; +			imagep->setBoostLevel(LLViewerTexture::BOOST_HUD); + 			face->setPixelArea(area); // treat as full screen +			face->setVirtualSize(vsize); +		} +		else +		{ +			vsize = face->getTextureVirtualSize(); +		} + +		mPixelArea = llmax(mPixelArea, face->getPixelArea());		 + +		if (face->mTextureMatrix != NULL) +		{ +			if ((vsize < MIN_TEX_ANIM_SIZE && old_size > MIN_TEX_ANIM_SIZE) || +				(vsize > MIN_TEX_ANIM_SIZE && old_size < MIN_TEX_ANIM_SIZE)) +			{ +				gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD, FALSE); +			} +		} +				 +		if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA)) +		{ +			if (vsize < min_vsize) min_vsize = vsize; +			if (vsize > max_vsize) max_vsize = vsize; +		} +		else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY)) +		{ +			LLViewerFetchedTexture* img = LLViewerTextureManager::staticCastToFetchedTexture(imagep) ; +			if(img) +			{ +				F32 pri = img->getDecodePriority(); +				pri = llmax(pri, 0.0f); +				if (pri < min_vsize) min_vsize = pri; +				if (pri > max_vsize) max_vsize = pri; +			} +		} +		else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_FACE_AREA)) +		{ +			F32 pri = mPixelArea; +			if (pri < min_vsize) min_vsize = pri; +			if (pri > max_vsize) max_vsize = pri; +		}	 +	} +	 +	if (isSculpted()) +	{ +		LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT); +		LLUUID id =  sculpt_params->getSculptTexture(); +		 +		updateSculptTexture(); +		 +		 + +		if (mSculptTexture.notNull()) +		{ +			mSculptTexture->setBoostLevel(llmax((S32)mSculptTexture->getBoostLevel(), +												(S32)LLViewerTexture::BOOST_SCULPTED)); +			mSculptTexture->setForSculpt() ; +			 +			if(!mSculptTexture->isCachedRawImageReady()) +			{ +				S32 lod = llmin(mLOD, 3); +				F32 lodf = ((F32)(lod + 1.0f)/4.f); +				F32 tex_size = lodf * LLViewerTexture::sMaxSculptRez ; +				mSculptTexture->addTextureStats(2.f * tex_size * tex_size, FALSE); +			 +				//if the sculpty very close to the view point, load first +				{				 +					LLVector3 lookAt = getPositionAgent() - camera->getOrigin(); +					F32 dist = lookAt.normVec() ; +					F32 cos_angle_to_view_dir = lookAt * camera->getXAxis() ;				 +					mSculptTexture->setAdditionalDecodePriority(0.8f * LLFace::calcImportanceToCamera(cos_angle_to_view_dir, dist)) ; +				} +			} +	 +			S32 texture_discard = mSculptTexture->getDiscardLevel(); //try to match the texture +			S32 current_discard = getVolume() ? getVolume()->getSculptLevel() : -2 ; + +			if (texture_discard >= 0 && //texture has some data available +				(texture_discard < current_discard || //texture has more data than last rebuild +				current_discard < 0)) //no previous rebuild +			{ +				gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, FALSE); +				mSculptChanged = TRUE; +			} + +			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SCULPTED)) +			{ +				setDebugText(llformat("T%d C%d V%d\n%dx%d", +										  texture_discard, current_discard, getVolume()->getSculptLevel(), +										  mSculptTexture->getHeight(), mSculptTexture->getWidth())); +			} +		} + +	} + +	if (getLightTextureID().notNull()) +	{ +		LLLightImageParams* params = (LLLightImageParams*) getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE); +		LLUUID id = params->getLightTexture(); +		mLightTexture = LLViewerTextureManager::getFetchedTexture(id); +		if (mLightTexture.notNull()) +		{ +			F32 rad = getLightRadius(); +			mLightTexture->addTextureStats(gPipeline.calcPixelArea(getPositionAgent(),  +																	LLVector3(rad,rad,rad), +																	*camera)); +		}	 +	} +	 +	if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA)) +	{ +		setDebugText(llformat("%.0f:%.0f", (F32) sqrt(min_vsize),(F32) sqrt(max_vsize))); +	} + 	else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY)) + 	{ + 		setDebugText(llformat("%.0f:%.0f", (F32) sqrt(min_vsize),(F32) sqrt(max_vsize))); + 	} +	else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_FACE_AREA)) +	{ +		setDebugText(llformat("%.0f:%.0f", (F32) sqrt(min_vsize),(F32) sqrt(max_vsize))); +	} + +	if (mPixelArea == 0) +	{ //flexi phasing issues make this happen +		mPixelArea = old_area; +	} +} + +BOOL LLVOVolume::isActive() const +{ +	return !mStatic || mTextureAnimp || (mVolumeImpl && mVolumeImpl->isActive()) ||  +		(mDrawable.notNull() && mDrawable->isActive()); +} + +BOOL LLVOVolume::setMaterial(const U8 material) +{ +	BOOL res = LLViewerObject::setMaterial(material); +	 +	return res; +} + +void LLVOVolume::setTexture(const S32 face) +{ +	llassert(face < getNumTEs()); +	gGL.getTexUnit(0)->bind(getTEImage(face)); +} + +void LLVOVolume::setScale(const LLVector3 &scale, BOOL damped) +{ +	if (scale != getScale()) +	{ +		// store local radius +		LLViewerObject::setScale(scale); + +		if (mVolumeImpl) +		{ +			mVolumeImpl->onSetScale(scale, damped); +		} +		 +		updateRadius(); + +		//since drawable transforms do not include scale, changing volume scale +		//requires an immediate rebuild of volume verts. +		gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_POSITION, TRUE); +	} +} + +LLFace* LLVOVolume::addFace(S32 f) +{ +	const LLTextureEntry* te = getTE(f); +	LLViewerTexture* imagep = getTEImage(f); +	return mDrawable->addFace(te, imagep); +} + +LLDrawable *LLVOVolume::createDrawable(LLPipeline *pipeline) +{ +	pipeline->allocDrawable(this); +		 +	mDrawable->setRenderType(LLPipeline::RENDER_TYPE_VOLUME); + +	S32 max_tes_to_set = getNumTEs(); +	for (S32 i = 0; i < max_tes_to_set; i++) +	{ +		addFace(i); +	} +	mNumFaces = max_tes_to_set; + +	if (isAttachment()) +	{ +		mDrawable->makeActive(); +	} + +	if (getIsLight()) +	{ +		// Add it to the pipeline mLightSet +		gPipeline.setLight(mDrawable, TRUE); +	} +	 +	updateRadius(); +	bool force_update = true; // avoid non-alpha mDistance update being optimized away +	mDrawable->updateDistance(*LLViewerCamera::getInstance(), force_update); + +	return mDrawable; +} + +BOOL LLVOVolume::setVolume(const LLVolumeParams ¶ms_in, const S32 detail, bool unique_volume) +{ +	LLVolumeParams volume_params = params_in; + +	S32 last_lod = mVolumep.notNull() ? LLVolumeLODGroup::getVolumeDetailFromScale(mVolumep->getDetail()) : -1; +	S32 lod = mLOD; + +	BOOL is404 = FALSE; + +	if (isSculpted()) +	{ +		// if it's a mesh +		if ((volume_params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH) +		{ //meshes might not have all LODs, get the force detail to best existing LOD + +			LLUUID mesh_id = volume_params.getSculptID(); + +			//profile and path params don't matter for meshes +			volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); + +			lod = gMeshRepo.getActualMeshLOD(volume_params, lod); +			if (lod == -1) +			{ +				is404 = TRUE; +				lod = 0; +			} +		} +	} + +	// Check if we need to change implementations +	bool is_flexible = (volume_params.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE); +	if (is_flexible) +	{ +		setParameterEntryInUse(LLNetworkData::PARAMS_FLEXIBLE, TRUE, false); +		if (!mVolumeImpl) +		{ +			LLFlexibleObjectData* data = (LLFlexibleObjectData*)getParameterEntry(LLNetworkData::PARAMS_FLEXIBLE); +			mVolumeImpl = new LLVolumeImplFlexible(this, data); +		} +	} +	else +	{ +		// Mark the parameter not in use +		setParameterEntryInUse(LLNetworkData::PARAMS_FLEXIBLE, FALSE, false); +		if (mVolumeImpl) +		{ +			delete mVolumeImpl; +			mVolumeImpl = NULL; +			if (mDrawable.notNull()) +			{ +				// Undo the damage we did to this matrix +				mDrawable->updateXform(FALSE); +			} +		} +	} +	 +	if (is404) +	{ +		setIcon(LLViewerTextureManager::getFetchedTextureFromFile("icons/Inv_Mesh.png", TRUE, LLViewerTexture::BOOST_UI)); +	} + +	if ((LLPrimitive::setVolume(volume_params, lod, (mVolumeImpl && mVolumeImpl->isVolumeUnique()))) || mSculptChanged) +	{ +		mFaceMappingChanged = TRUE; +		 +		if (mVolumeImpl) +		{ +			mVolumeImpl->onSetVolume(volume_params, mLOD); +		} +	 +		updateSculptTexture(); + + +		if (isSculpted()) +		{ +			updateSculptTexture(); +			// if it's a mesh +			if ((volume_params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH) +			{ +				if (getVolume()->getNumVolumeFaces() == 0 || getVolume()->isTetrahedron()) +				{  +					//load request not yet issued, request pipeline load this mesh +					LLUUID asset_id = volume_params.getSculptID(); +					S32 available_lod = gMeshRepo.loadMesh(this, volume_params, lod, last_lod); +					if (available_lod != lod) +					{ +						LLPrimitive::setVolume(volume_params, available_lod); +					} +				} +				 +			} +			else // otherwise is sculptie +			{ +				if (mSculptTexture.notNull()) +				{ +					sculpt(); +				} +			} +		} + +		return TRUE; +	} + +	return FALSE; +} + +void LLVOVolume::updateSculptTexture() +{ +	LLPointer<LLViewerFetchedTexture> old_sculpt = mSculptTexture; + +	if (isSculpted() && !isMesh()) +	{ +		LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT); +		LLUUID id =  sculpt_params->getSculptTexture(); +		if (id.notNull()) +		{ +			mSculptTexture = LLViewerTextureManager::getFetchedTexture(id, TRUE, LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); +		} +	} +	else +	{ +		mSculptTexture = NULL; +	} + +	if (mSculptTexture != old_sculpt) +	{ +		if (old_sculpt.notNull()) +		{ +			old_sculpt->removeVolume(this); +		} +		if (mSculptTexture.notNull()) +		{ +			mSculptTexture->addVolume(this); +		} +	} +	 +} + + + +void LLVOVolume::notifyMeshLoaded() +{  +	mSculptChanged = TRUE; +	gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE); +} + +// sculpt replaces generate() for sculpted surfaces +void LLVOVolume::sculpt() +{	 +	if (mSculptTexture.notNull()) +	{				 +		U16 sculpt_height = 0; +		U16 sculpt_width = 0; +		S8 sculpt_components = 0; +		const U8* sculpt_data = NULL; +	 +		S32 discard_level = mSculptTexture->getDiscardLevel() ; +		LLImageRaw* raw_image = mSculptTexture->getCachedRawImage() ; +		 +		S32 max_discard = mSculptTexture->getMaxDiscardLevel(); +		if (discard_level > max_discard) +			discard_level = max_discard;    // clamp to the best we can do + +		S32 current_discard = getVolume()->getSculptLevel() ; +		if(current_discard < -2) +		{ +			llwarns << "WARNING!!: Current discard of sculpty at " << current_discard  +				<< " is less than -2." << llendl; +			 +			// corrupted volume... don't update the sculpty +			return; +		} +		else if (current_discard > MAX_DISCARD_LEVEL) +		{ +			llwarns << "WARNING!!: Current discard of sculpty at " << current_discard  +				<< " is more than than allowed max of " << MAX_DISCARD_LEVEL << llendl; +			 +			// corrupted volume... don't update the sculpty			 +			return; +		} + +		if (current_discard == discard_level)  // no work to do here +			return; +		 +		if(!raw_image) +		{ +			llassert(discard_level < 0) ; + +			sculpt_width = 0; +			sculpt_height = 0; +			sculpt_data = NULL ; + +			if(LLViewerTextureManager::sTesterp) +			{ +				LLViewerTextureManager::sTesterp->updateGrayTextureBinding(); +			} +		} +		else +		{					 +			sculpt_height = raw_image->getHeight(); +			sculpt_width = raw_image->getWidth(); +			sculpt_components = raw_image->getComponents();		 +					    +			sculpt_data = raw_image->getData(); + +			if(LLViewerTextureManager::sTesterp) +			{ +				mSculptTexture->updateBindStatsForTester() ; +			} +		} +		getVolume()->sculpt(sculpt_width, sculpt_height, sculpt_components, sculpt_data, discard_level); + +		//notify rebuild any other VOVolumes that reference this sculpty volume +		for (S32 i = 0; i < mSculptTexture->getNumVolumes(); ++i) +		{ +			LLVOVolume* volume = (*(mSculptTexture->getVolumeList()))[i]; +			if (volume != this && volume->getVolume() == getVolume()) +			{ +				gPipeline.markRebuild(volume->mDrawable, LLDrawable::REBUILD_GEOMETRY, FALSE); +			} +		} +	} +} + +S32	LLVOVolume::computeLODDetail(F32 distance, F32 radius) +{ +	S32	cur_detail; +	if (LLPipeline::sDynamicLOD) +	{ +		// We've got LOD in the profile, and in the twist.  Use radius. +		F32 tan_angle = (LLVOVolume::sLODFactor*radius)/distance; +		cur_detail = LLVolumeLODGroup::getDetailFromTan(llround(tan_angle, 0.01f)); +	} +	else +	{ +		cur_detail = llclamp((S32) (sqrtf(radius)*LLVOVolume::sLODFactor*4.f), 0, 3);		 +	} +	return cur_detail; +} + +BOOL LLVOVolume::calcLOD() +{ +	if (mDrawable.isNull()) +	{ +		return FALSE; +	} + +	S32 cur_detail = 0; +	 +	F32 radius; +	F32 distance; + +	if (mDrawable->isState(LLDrawable::RIGGED)) +	{ +		LLVOAvatar* avatar = getAvatar();  +		distance = avatar->mDrawable->mDistanceWRTCamera; +		radius = avatar->getBinRadius(); +	} +	else +	{ +		distance = mDrawable->mDistanceWRTCamera; +		radius = getVolume()->mLODScaleBias.scaledVec(getScale()).length(); +	} +	 +	//hold onto unmodified distance for debugging +	F32 debug_distance = distance; +	 +	distance *= sDistanceFactor; + +	F32 rampDist = LLVOVolume::sLODFactor * 2; +	 +	if (distance < rampDist) +	{ +		// Boost LOD when you're REALLY close +		distance *= 1.0f/rampDist; +		distance *= distance; +		distance *= rampDist; +	} +	 +	// DON'T Compensate for field of view changing on FOV zoom. +	distance *= F_PI/3.f; + +	cur_detail = computeLODDetail(llround(distance, 0.01f),  +									llround(radius, 0.01f)); + + +	if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_LOD_INFO)) +	{ +		setDebugText(llformat("%.2f:%.2f, %d", debug_distance, radius, cur_detail)); +	} + +	if (cur_detail != mLOD) +	{ +		mAppAngle = llround((F32) atan2( mDrawable->getRadius(), mDrawable->mDistanceWRTCamera) * RAD_TO_DEG, 0.01f); +		mLOD = cur_detail;		 +		return TRUE; +	} +	else +	{ +		return FALSE; +	} +} + +BOOL LLVOVolume::updateLOD() +{ +	if (mDrawable.isNull()) +	{ +		return FALSE; +	} +	 +	BOOL lod_changed = calcLOD(); + +	if (lod_changed) +	{ +		gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, FALSE); +		mLODChanged = TRUE; +	} + +	lod_changed = lod_changed || LLViewerObject::updateLOD(); +	 +	return lod_changed; +} + +BOOL LLVOVolume::setDrawableParent(LLDrawable* parentp) +{ +	if (!LLViewerObject::setDrawableParent(parentp)) +	{ +		// no change in drawable parent +		return FALSE; +	} + +	if (!mDrawable->isRoot()) +	{ +		// rebuild vertices in parent relative space +		gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE); + +		if (mDrawable->isActive() && !parentp->isActive()) +		{ +			parentp->makeActive(); +		} +		else if (mDrawable->isStatic() && parentp->isActive()) +		{ +			mDrawable->makeActive(); +		} +	} +	 +	return TRUE; +} + +void LLVOVolume::updateFaceFlags() +{ +	for (S32 i = 0; i < getVolume()->getNumFaces(); i++) +	{ +		LLFace *face = mDrawable->getFace(i); +		if (!face) +		{ +			return; +		} + +		BOOL fullbright = getTE(i)->getFullbright(); +		face->clearState(LLFace::FULLBRIGHT | LLFace::HUD_RENDER | LLFace::LIGHT); + +		if (fullbright || (mMaterial == LL_MCODE_LIGHT)) +		{ +			face->setState(LLFace::FULLBRIGHT); +		} +		if (mDrawable->isLight()) +		{ +			face->setState(LLFace::LIGHT); +		} +		if (isHUDAttachment()) +		{ +			face->setState(LLFace::HUD_RENDER); +		} +	} +} + +BOOL LLVOVolume::setParent(LLViewerObject* parent) +{ +	BOOL ret = FALSE ; +	if (parent != getParent()) +	{ +		ret = LLViewerObject::setParent(parent); +		if (ret && mDrawable) +		{ +			gPipeline.markMoved(mDrawable); +			gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE); +		} +	} + +	return ret ; +} + +// NOTE: regenFaces() MUST be followed by genTriangles()! +void LLVOVolume::regenFaces() +{ +	// remove existing faces +	BOOL count_changed = mNumFaces != getNumTEs(); +	 +	if (count_changed) +	{ +		deleteFaces();		 +		// add new faces +		mNumFaces = getNumTEs(); +	} +		 +	for (S32 i = 0; i < mNumFaces; i++) +	{ +		LLFace* facep = count_changed ? addFace(i) : mDrawable->getFace(i); +		facep->setTEOffset(i); +		facep->setTexture(getTEImage(i)); +		facep->setViewerObject(this); +		 +		// If the face had media on it, this will have broken the link between the LLViewerMediaTexture and the face. +		// Re-establish the link. +		if((int)mMediaImplList.size() > i) +		{ +			if(mMediaImplList[i]) +			{ +				LLViewerMediaTexture* media_tex = LLViewerTextureManager::findMediaTexture(mMediaImplList[i]->getMediaTextureID()) ; +				if(media_tex) +				{ +					media_tex->addMediaToFace(facep) ; +				} +			} +		} +	} +	 +	if (!count_changed) +	{ +		updateFaceFlags(); +	} +} + +BOOL LLVOVolume::genBBoxes(BOOL force_global) +{ +	BOOL res = TRUE; + +	LLVector4a min,max; + +	min.clear(); +	max.clear(); + +	BOOL rebuild = mDrawable->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION | LLDrawable::REBUILD_RIGGED); + +//	bool rigged = false; +	LLVolume* volume = mRiggedVolume; +	if (!volume) +	{ +		volume = getVolume(); +	} + +	for (S32 i = 0; i < getVolume()->getNumVolumeFaces(); i++) +	{ +		LLFace *face = mDrawable->getFace(i); +		if (!face) +		{ +			continue; +		} +		res &= face->genVolumeBBoxes(*volume, i, +										mRelativeXform, mRelativeXformInvTrans, +										(mVolumeImpl && mVolumeImpl->isVolumeGlobal()) || force_global); +		 +		if (rebuild) +		{ +			if (i == 0) +			{ +				min = face->mExtents[0]; +				max = face->mExtents[1]; +			} +			else +			{ +				min.setMin(min, face->mExtents[0]); +				max.setMax(max, face->mExtents[1]); +			} +		} +	} +	 +	if (rebuild) +	{ +		mDrawable->setSpatialExtents(min,max); +		min.add(max); +		min.mul(0.5f); +		mDrawable->setPositionGroup(min);	 +	} + +	updateRadius(); +	mDrawable->movePartition(); +			 +	return res; +} + +void LLVOVolume::preRebuild() +{ +	if (mVolumeImpl != NULL) +	{ +		mVolumeImpl->preRebuild(); +	} +} + +void LLVOVolume::updateRelativeXform() +{ +	if (mVolumeImpl) +	{ +		mVolumeImpl->updateRelativeXform(); +		return; +	} +	 +	LLDrawable* drawable = mDrawable; +	 +	if (drawable->isState(LLDrawable::RIGGED) && mRiggedVolume.notNull()) +	{ //rigged volume (which is in agent space) is used for generating bounding boxes etc +	  //inverse of render matrix should go to partition space +		mRelativeXform = getRenderMatrix(); + +		F32* dst = (F32*) mRelativeXformInvTrans.mMatrix; +		F32* src = (F32*) mRelativeXform.mMatrix; +		dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; +		dst[3] = src[4]; dst[4] = src[5]; dst[5] = src[6]; +		dst[6] = src[8]; dst[7] = src[9]; dst[8] = src[10]; +		 +		mRelativeXform.invert(); +		mRelativeXformInvTrans.transpose(); +	} +	else if (drawable->isActive()) +	{				 +		// setup relative transforms +		LLQuaternion delta_rot; +		LLVector3 delta_pos, delta_scale; +		 +		//matrix from local space to parent relative/global space +		delta_rot = drawable->isSpatialRoot() ? LLQuaternion() : mDrawable->getRotation(); +		delta_pos = drawable->isSpatialRoot() ? LLVector3(0,0,0) : mDrawable->getPosition(); +		delta_scale = mDrawable->getScale(); + +		// Vertex transform (4x4) +		LLVector3 x_axis = LLVector3(delta_scale.mV[VX], 0.f, 0.f) * delta_rot; +		LLVector3 y_axis = LLVector3(0.f, delta_scale.mV[VY], 0.f) * delta_rot; +		LLVector3 z_axis = LLVector3(0.f, 0.f, delta_scale.mV[VZ]) * delta_rot; + +		mRelativeXform.initRows(LLVector4(x_axis, 0.f), +								LLVector4(y_axis, 0.f), +								LLVector4(z_axis, 0.f), +								LLVector4(delta_pos, 1.f)); + +		 +		// compute inverse transpose for normals +		// mRelativeXformInvTrans.setRows(x_axis, y_axis, z_axis); +		// mRelativeXformInvTrans.invert();  +		// mRelativeXformInvTrans.setRows(x_axis, y_axis, z_axis); +		// grumble - invert is NOT a matrix invert, so we do it by hand: + +		LLMatrix3 rot_inverse = LLMatrix3(~delta_rot); + +		LLMatrix3 scale_inverse; +		scale_inverse.setRows(LLVector3(1.0, 0.0, 0.0) / delta_scale.mV[VX], +							  LLVector3(0.0, 1.0, 0.0) / delta_scale.mV[VY], +							  LLVector3(0.0, 0.0, 1.0) / delta_scale.mV[VZ]); +							    +		 +		mRelativeXformInvTrans = rot_inverse * scale_inverse; + +		mRelativeXformInvTrans.transpose(); +	} +	else +	{ +		LLVector3 pos = getPosition(); +		LLVector3 scale = getScale(); +		LLQuaternion rot = getRotation(); +	 +		if (mParent) +		{ +			pos *= mParent->getRotation(); +			pos += mParent->getPosition(); +			rot *= mParent->getRotation(); +		} +		 +		//LLViewerRegion* region = getRegion(); +		//pos += region->getOriginAgent(); +		 +		LLVector3 x_axis = LLVector3(scale.mV[VX], 0.f, 0.f) * rot; +		LLVector3 y_axis = LLVector3(0.f, scale.mV[VY], 0.f) * rot; +		LLVector3 z_axis = LLVector3(0.f, 0.f, scale.mV[VZ]) * rot; + +		mRelativeXform.initRows(LLVector4(x_axis, 0.f), +								LLVector4(y_axis, 0.f), +								LLVector4(z_axis, 0.f), +								LLVector4(pos, 1.f)); + +		// compute inverse transpose for normals +		LLMatrix3 rot_inverse = LLMatrix3(~rot); + +		LLMatrix3 scale_inverse; +		scale_inverse.setRows(LLVector3(1.0, 0.0, 0.0) / scale.mV[VX], +							  LLVector3(0.0, 1.0, 0.0) / scale.mV[VY], +							  LLVector3(0.0, 0.0, 1.0) / scale.mV[VZ]); +							    +		 +		mRelativeXformInvTrans = rot_inverse * scale_inverse; + +		mRelativeXformInvTrans.transpose(); +	} +} + +static LLFastTimer::DeclareTimer FTM_GEN_FLEX("Generate Flexies"); +static LLFastTimer::DeclareTimer FTM_UPDATE_PRIMITIVES("Update Primitives"); +static LLFastTimer::DeclareTimer FTM_UPDATE_RIGGED_VOLUME("Update Rigged"); + +BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) +{ +	LLFastTimer t(FTM_UPDATE_PRIMITIVES); +	 +	if (mDrawable->isState(LLDrawable::REBUILD_RIGGED)) +	{ +		{ +			LLFastTimer t(FTM_UPDATE_RIGGED_VOLUME); +			updateRiggedVolume(); +		} +		genBBoxes(FALSE); +		mDrawable->clearState(LLDrawable::REBUILD_RIGGED); +	} + +	if (mVolumeImpl != NULL) +	{ +		BOOL res; +		{ +			LLFastTimer t(FTM_GEN_FLEX); +			res = mVolumeImpl->doUpdateGeometry(drawable); +		} +		updateFaceFlags(); +		return res; +	} +	 +	dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1)); + +	BOOL compiled = FALSE; +			 +	updateRelativeXform(); +	 +	if (mDrawable.isNull()) // Not sure why this is happening, but it is... +	{ +		return TRUE; // No update to complete +	} + +	if (mVolumeChanged || mFaceMappingChanged ) +	{ +		compiled = TRUE; + +		if (mVolumeChanged) +		{ +			LLFastTimer ftm(FTM_GEN_VOLUME); +			LLVolumeParams volume_params = getVolume()->getParams(); +			setVolume(volume_params, 0); +			drawable->setState(LLDrawable::REBUILD_VOLUME); +		} + +		{ +			LLFastTimer t(FTM_GEN_TRIANGLES); +			regenFaces(); +			genBBoxes(FALSE); +		} +	} +	else if ((mLODChanged) || (mSculptChanged)) +	{ +		LLVolume *old_volumep, *new_volumep; +		F32 old_lod, new_lod; +		S32 old_num_faces, new_num_faces ; + +		old_volumep = getVolume(); +		old_lod = old_volumep->getDetail(); +		old_num_faces = old_volumep->getNumFaces() ; +		old_volumep = NULL ; + +		{ +			LLFastTimer ftm(FTM_GEN_VOLUME); +			LLVolumeParams volume_params = getVolume()->getParams(); +			setVolume(volume_params, 0); +		} + +		new_volumep = getVolume(); +		new_lod = new_volumep->getDetail(); +		new_num_faces = new_volumep->getNumFaces() ; +		new_volumep = NULL ; + +		if ((new_lod != old_lod) || mSculptChanged) +		{ +			compiled = TRUE; +			sNumLODChanges += new_num_faces ; +	 +			drawable->setState(LLDrawable::REBUILD_VOLUME); // for face->genVolumeTriangles() + +			{ +				LLFastTimer t(FTM_GEN_TRIANGLES); +				if (new_num_faces != old_num_faces) +				{ +					regenFaces(); +				} +				genBBoxes(FALSE); + +				if (mSculptChanged) +				{ //changes in sculpt maps can thrash an object bounding box without  +				  //triggering a spatial group bounding box update -- force spatial group +				  //to update bounding boxes +					LLSpatialGroup* group = mDrawable->getSpatialGroup(); +					if (group) +					{ +						group->unbound(); +					} +				} +			} +		} +	} +	// it has its own drawable (it's moved) or it has changed UVs or it has changed xforms from global<->local +	else +	{ +		compiled = TRUE; +		// All it did was move or we changed the texture coordinate offset +		LLFastTimer t(FTM_GEN_TRIANGLES); +		genBBoxes(FALSE); +	} + +	// Update face flags +	updateFaceFlags(); +	 +	if(compiled) +	{ +		LLPipeline::sCompiles++; +	} +		 +	mVolumeChanged = FALSE; +	mLODChanged = FALSE; +	mSculptChanged = FALSE; +	mFaceMappingChanged = FALSE; +	 +	return LLViewerObject::updateGeometry(drawable); +} + +void LLVOVolume::updateFaceSize(S32 idx) +{ +	LLFace* facep = mDrawable->getFace(idx); +	if (idx >= getVolume()->getNumVolumeFaces()) +	{ +		facep->setSize(0,0, true); +	} +	else +	{ +		const LLVolumeFace& vol_face = getVolume()->getVolumeFace(idx); +		facep->setSize(vol_face.mNumVertices, vol_face.mNumIndices,  +						true); // <--- volume faces should be padded for 16-byte alignment +		 +	} +} + +BOOL LLVOVolume::isRootEdit() const +{ +	if (mParent && !((LLViewerObject*)mParent)->isAvatar()) +	{ +		return FALSE; +	} +	return TRUE; +} + +//virtual +void LLVOVolume::setNumTEs(const U8 num_tes) +{ +	const U8 old_num_tes = getNumTEs() ; +	 +	if(old_num_tes && old_num_tes < num_tes) //new faces added +	{ +		LLViewerObject::setNumTEs(num_tes) ; + +		if(mMediaImplList.size() >= old_num_tes && mMediaImplList[old_num_tes -1].notNull())//duplicate the last media textures if exists. +		{ +			mMediaImplList.resize(num_tes) ; +			const LLTextureEntry* te = getTE(old_num_tes - 1) ; +			for(U8 i = old_num_tes; i < num_tes ; i++) +			{ +				setTE(i, *te) ; +				mMediaImplList[i] = mMediaImplList[old_num_tes -1] ; +			} +			mMediaImplList[old_num_tes -1]->setUpdated(TRUE) ; +		} +	} +	else if(old_num_tes > num_tes && mMediaImplList.size() > num_tes) //old faces removed +	{ +		U8 end = mMediaImplList.size() ; +		for(U8 i = num_tes; i < end ; i++) +		{ +			removeMediaImpl(i) ;				 +		} +		mMediaImplList.resize(num_tes) ; + +		LLViewerObject::setNumTEs(num_tes) ; +	} +	else +	{ +		LLViewerObject::setNumTEs(num_tes) ; +	} + +	return ; +} + +void LLVOVolume::setTEImage(const U8 te, LLViewerTexture *imagep) +{ +	BOOL changed = (mTEImages[te] != imagep); +	LLViewerObject::setTEImage(te, imagep); +	if (changed) +	{ +		gPipeline.markTextured(mDrawable); +		mFaceMappingChanged = TRUE; +	} +} + +S32 LLVOVolume::setTETexture(const U8 te, const LLUUID &uuid) +{ +	S32 res = LLViewerObject::setTETexture(te, uuid); +	if (res) +	{ +		gPipeline.markTextured(mDrawable); +		mFaceMappingChanged = TRUE; +	} +	return res; +} + +S32 LLVOVolume::setTEColor(const U8 te, const LLColor3& color) +{ +	return setTEColor(te, LLColor4(color)); +} + +S32 LLVOVolume::setTEColor(const U8 te, const LLColor4& color) +{ +	S32 retval = 0; +	const LLTextureEntry *tep = getTE(te); +	if (!tep) +	{ +		llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl; +	} +	else if (color != tep->getColor()) +	{ +		if (color.mV[3] != tep->getColor().mV[3]) +		{ +			gPipeline.markTextured(mDrawable); +		} +		retval = LLPrimitive::setTEColor(te, color); +		if (mDrawable.notNull() && retval) +		{ +			// These should only happen on updates which are not the initial update. +			mDrawable->setState(LLDrawable::REBUILD_COLOR); +			dirtyMesh(); +		} +	} + +	return  retval; +} + +S32 LLVOVolume::setTEBumpmap(const U8 te, const U8 bumpmap) +{ +	S32 res = LLViewerObject::setTEBumpmap(te, bumpmap); +	if (res) +	{ +		gPipeline.markTextured(mDrawable); +		mFaceMappingChanged = TRUE; +	} +	return  res; +} + +S32 LLVOVolume::setTETexGen(const U8 te, const U8 texgen) +{ +	S32 res = LLViewerObject::setTETexGen(te, texgen); +	if (res) +	{ +		gPipeline.markTextured(mDrawable); +		mFaceMappingChanged = TRUE; +	} +	return  res; +} + +S32 LLVOVolume::setTEMediaTexGen(const U8 te, const U8 media) +{ +	S32 res = LLViewerObject::setTEMediaTexGen(te, media); +	if (res) +	{ +		gPipeline.markTextured(mDrawable); +		mFaceMappingChanged = TRUE; +	} +	return  res; +} + +S32 LLVOVolume::setTEShiny(const U8 te, const U8 shiny) +{ +	S32 res = LLViewerObject::setTEShiny(te, shiny); +	if (res) +	{ +		gPipeline.markTextured(mDrawable); +		mFaceMappingChanged = TRUE; +	} +	return  res; +} + +S32 LLVOVolume::setTEFullbright(const U8 te, const U8 fullbright) +{ +	S32 res = LLViewerObject::setTEFullbright(te, fullbright); +	if (res) +	{ +		gPipeline.markTextured(mDrawable); +		mFaceMappingChanged = TRUE; +	} +	return  res; +} + +S32 LLVOVolume::setTEBumpShinyFullbright(const U8 te, const U8 bump) +{ +	S32 res = LLViewerObject::setTEBumpShinyFullbright(te, bump); +	if (res) +	{ +		gPipeline.markTextured(mDrawable); +		mFaceMappingChanged = TRUE; +	} +	return res; +} + +S32 LLVOVolume::setTEMediaFlags(const U8 te, const U8 media_flags) +{ +	S32 res = LLViewerObject::setTEMediaFlags(te, media_flags); +	if (res) +	{ +		gPipeline.markTextured(mDrawable); +		mFaceMappingChanged = TRUE; +	} +	return  res; +} + +S32 LLVOVolume::setTEGlow(const U8 te, const F32 glow) +{ +	S32 res = LLViewerObject::setTEGlow(te, glow); +	if (res) +	{ +		gPipeline.markTextured(mDrawable); +		mFaceMappingChanged = TRUE; +	} +	return  res; +} + +S32 LLVOVolume::setTEScale(const U8 te, const F32 s, const F32 t) +{ +	S32 res = LLViewerObject::setTEScale(te, s, t); +	if (res) +	{ +		gPipeline.markTextured(mDrawable); +		mFaceMappingChanged = TRUE; +	} +	return res; +} + +S32 LLVOVolume::setTEScaleS(const U8 te, const F32 s) +{ +	S32 res = LLViewerObject::setTEScaleS(te, s); +	if (res) +	{ +		gPipeline.markTextured(mDrawable); +		mFaceMappingChanged = TRUE; +	} +	return res; +} + +S32 LLVOVolume::setTEScaleT(const U8 te, const F32 t) +{ +	S32 res = LLViewerObject::setTEScaleT(te, t); +	if (res) +	{ +		gPipeline.markTextured(mDrawable); +		mFaceMappingChanged = TRUE; +	} +	return res; +} + +void LLVOVolume::updateTEData() +{ +	/*if (mDrawable.notNull()) +	{ +		mFaceMappingChanged = TRUE; +		gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_MATERIAL, TRUE); +	}*/ +} + +bool LLVOVolume::hasMedia() const +{ +	bool result = false; +	const U8 numTEs = getNumTEs(); +	for (U8 i = 0; i < numTEs; i++) +	{ +		const LLTextureEntry* te = getTE(i); +		if(te->hasMedia()) +		{ +			result = true; +			break; +		} +	} +	return result; +} + +LLVector3 LLVOVolume::getApproximateFaceNormal(U8 face_id) +{ +	LLVolume* volume = getVolume(); +	LLVector4a result; +	result.clear(); + +	LLVector3 ret; + +	if (volume && face_id < volume->getNumVolumeFaces()) +	{ +		const LLVolumeFace& face = volume->getVolumeFace(face_id); +		for (S32 i = 0; i < (S32)face.mNumVertices; ++i) +		{ +			result.add(face.mNormals[i]); +		} + +		LLVector3 ret(result.getF32ptr()); +		ret = volumeDirectionToAgent(ret); +		ret.normVec(); +	} +	 +	return ret; +} + +void LLVOVolume::requestMediaDataUpdate(bool isNew) +{ +    if (sObjectMediaClient) +		sObjectMediaClient->fetchMedia(new LLMediaDataClientObjectImpl(this, isNew)); +} + +bool LLVOVolume::isMediaDataBeingFetched() const +{ +	// I know what I'm doing by const_casting this away: this is just  +	// a wrapper class that is only going to do a lookup. +	return (sObjectMediaClient) ? sObjectMediaClient->isInQueue(new LLMediaDataClientObjectImpl(const_cast<LLVOVolume*>(this), false)) : false; +} + +void LLVOVolume::cleanUpMediaImpls() +{ +	// Iterate through our TEs and remove any Impls that are no longer used +	const U8 numTEs = getNumTEs(); +	for (U8 i = 0; i < numTEs; i++) +	{ +		const LLTextureEntry* te = getTE(i); +		if( ! te->hasMedia()) +		{ +			// Delete the media IMPL! +			removeMediaImpl(i) ; +		} +	} +} + +void LLVOVolume::updateObjectMediaData(const LLSD &media_data_array, const std::string &media_version) +{ +	// media_data_array is an array of media entry maps +	// media_version is the version string in the response. +	U32 fetched_version = LLTextureEntry::getVersionFromMediaVersionString(media_version); + +	// Only update it if it is newer! +	if ( (S32)fetched_version > mLastFetchedMediaVersion) +	{ +		mLastFetchedMediaVersion = fetched_version; +		//llinfos << "updating:" << this->getID() << " " << ll_pretty_print_sd(media_data_array) << llendl; +		 +		LLSD::array_const_iterator iter = media_data_array.beginArray(); +		LLSD::array_const_iterator end = media_data_array.endArray(); +		U8 texture_index = 0; +		for (; iter != end; ++iter, ++texture_index) +		{ +			syncMediaData(texture_index, *iter, false/*merge*/, false/*ignore_agent*/); +		} +	} +} + +void LLVOVolume::syncMediaData(S32 texture_index, const LLSD &media_data, bool merge, bool ignore_agent) +{ +	if(mDead) +	{ +		// If the object has been marked dead, don't process media updates. +		return; +	} +	 +	LLTextureEntry *te = getTE(texture_index); +	if(!te) +	{ +		return ; +	} + +	LL_DEBUGS("MediaOnAPrim") << "BEFORE: texture_index = " << texture_index +		<< " hasMedia = " << te->hasMedia() << " : "  +		<< ((NULL == te->getMediaData()) ? "NULL MEDIA DATA" : ll_pretty_print_sd(te->getMediaData()->asLLSD())) << llendl; + +	std::string previous_url; +	LLMediaEntry* mep = te->getMediaData(); +	if(mep) +	{ +		// Save the "current url" from before the update so we can tell if +		// it changes.  +		previous_url = mep->getCurrentURL(); +	} + +	if (merge) +	{ +		te->mergeIntoMediaData(media_data); +	} +	else { +		// XXX Question: what if the media data is undefined LLSD, but the +		// update we got above said that we have media flags??	Here we clobber +		// that, assuming the data from the service is more up-to-date.  +		te->updateMediaData(media_data); +	} + +	mep = te->getMediaData(); +	if(mep) +	{ +		bool update_from_self = false; +		if (!ignore_agent)  +		{ +			LLUUID updating_agent = LLTextureEntry::getAgentIDFromMediaVersionString(getMediaURL()); +			update_from_self = (updating_agent == gAgent.getID()); +		} +		viewer_media_t media_impl = LLViewerMedia::updateMediaImpl(mep, previous_url, update_from_self); +			 +		addMediaImpl(media_impl, texture_index) ; +	} +	else +	{ +		removeMediaImpl(texture_index); +	} + +	LL_DEBUGS("MediaOnAPrim") << "AFTER: texture_index = " << texture_index +		<< " hasMedia = " << te->hasMedia() << " : "  +		<< ((NULL == te->getMediaData()) ? "NULL MEDIA DATA" : ll_pretty_print_sd(te->getMediaData()->asLLSD())) << llendl; +} + +void LLVOVolume::mediaNavigateBounceBack(U8 texture_index) +{ +	// Find the media entry for this navigate +	const LLMediaEntry* mep = NULL; +	viewer_media_t impl = getMediaImpl(texture_index); +	LLTextureEntry *te = getTE(texture_index); +	if(te) +	{ +		mep = te->getMediaData(); +	} +	 +	if (mep && impl) +	{ +        std::string url = mep->getCurrentURL(); +		// Look for a ":", if not there, assume "http://" +		if (!url.empty() && std::string::npos == url.find(':'))  +		{ +			url = "http://" + url; +		} +		// If the url we're trying to "bounce back" to is either empty or not +		// allowed by the whitelist, try the home url.  If *that* doesn't work, +		// set the media as failed and unload it +        if (url.empty() || !mep->checkCandidateUrl(url)) +        { +            url = mep->getHomeURL(); +			// Look for a ":", if not there, assume "http://" +			if (!url.empty() && std::string::npos == url.find(':'))  +			{ +				url = "http://" + url; +			} +        } +        if (url.empty() || !mep->checkCandidateUrl(url)) +		{ +			// The url to navigate back to is not good, and we have nowhere else +			// to go. +			LL_WARNS("MediaOnAPrim") << "FAILED to bounce back URL \"" << url << "\" -- unloading impl" << LL_ENDL; +			impl->setMediaFailed(true); +		} +		else { +			// Okay, navigate now +            LL_INFOS("MediaOnAPrim") << "bouncing back to URL: " << url << LL_ENDL; +            impl->navigateTo(url, "", false, true); +        } +    } +} + +bool LLVOVolume::hasMediaPermission(const LLMediaEntry* media_entry, MediaPermType perm_type) +{ +    // NOTE: This logic ALMOST duplicates the logic in the server (in particular, in llmediaservice.cpp). +    if (NULL == media_entry ) return false; // XXX should we assert here? +     +    // The agent has permissions if: +    // - world permissions are on, or +    // - group permissions are on, and agent_id is in the group, or +    // - agent permissions are on, and agent_id is the owner +     +	// *NOTE: We *used* to check for modify permissions here (i.e. permissions were +	// granted if permModify() was true).  However, this doesn't make sense in the +	// viewer: we don't want to show controls or allow interaction if the author +	// has deemed it so.  See DEV-42115. +	 +    U8 media_perms = (perm_type == MEDIA_PERM_INTERACT) ? media_entry->getPermsInteract() : media_entry->getPermsControl(); +     +    // World permissions +    if (0 != (media_perms & LLMediaEntry::PERM_ANYONE))  +    { +        return true; +    } +     +    // Group permissions +    else if (0 != (media_perms & LLMediaEntry::PERM_GROUP)) +    { +		LLPermissions* obj_perm = LLSelectMgr::getInstance()->findObjectPermissions(this); +		if (obj_perm && gAgent.isInGroup(obj_perm->getGroup())) +		{ +			return true; +		} +    } +     +    // Owner permissions +    else if (0 != (media_perms & LLMediaEntry::PERM_OWNER) && permYouOwner())  +    { +        return true; +    } +     +    return false; +     +} + +void LLVOVolume::mediaNavigated(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin, std::string new_location) +{ +	bool block_navigation = false; +	// FIXME: if/when we allow the same media impl to be used by multiple faces, the logic here will need to be fixed +	// to deal with multiple face indices. +	int face_index = getFaceIndexWithMediaImpl(impl, -1); +	 +	// Find the media entry for this navigate +	LLMediaEntry* mep = NULL; +	LLTextureEntry *te = getTE(face_index); +	if(te) +	{ +		mep = te->getMediaData(); +	} +	 +	if(mep) +	{ +		if(!mep->checkCandidateUrl(new_location)) +		{ +			block_navigation = true; +		} +		if (!block_navigation && !hasMediaPermission(mep, MEDIA_PERM_INTERACT)) +		{ +			block_navigation = true; +		} +	} +	else +	{ +		LL_WARNS("MediaOnAPrim") << "Couldn't find media entry!" << LL_ENDL; +	} +						 +	if(block_navigation) +	{ +		LL_INFOS("MediaOnAPrim") << "blocking navigate to URI " << new_location << LL_ENDL; + +		// "bounce back" to the current URL from the media entry +		mediaNavigateBounceBack(face_index); +	} +	else if (sObjectMediaNavigateClient) +	{ +		 +		LL_DEBUGS("MediaOnAPrim") << "broadcasting navigate with URI " << new_location << LL_ENDL; + +		sObjectMediaNavigateClient->navigate(new LLMediaDataClientObjectImpl(this, false), face_index, new_location); +	} +} + +void LLVOVolume::mediaEvent(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin, LLViewerMediaObserver::EMediaEvent event) +{ +	switch(event) +	{ +		 +		case LLViewerMediaObserver::MEDIA_EVENT_LOCATION_CHANGED: +		{			 +			switch(impl->getNavState()) +			{ +				case LLViewerMediaImpl::MEDIANAVSTATE_FIRST_LOCATION_CHANGED: +				{ +					// This is the first location changed event after the start of a non-server-directed nav.  It may need to be broadcast or bounced back. +					mediaNavigated(impl, plugin, plugin->getLocation()); +				} +				break; +				 +				case LLViewerMediaImpl::MEDIANAVSTATE_FIRST_LOCATION_CHANGED_SPURIOUS: +					// This navigate didn't change the current URL.   +					LL_DEBUGS("MediaOnAPrim") << "	NOT broadcasting navigate (spurious)" << LL_ENDL; +				break; +				 +				case LLViewerMediaImpl::MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED: +					// This is the first location changed event after the start of a server-directed nav.  Don't broadcast it. +					LL_INFOS("MediaOnAPrim") << "	NOT broadcasting navigate (server-directed)" << LL_ENDL; +				break; +				 +				default: +					// This is a subsequent location-changed due to a redirect.	 Don't broadcast. +					LL_INFOS("MediaOnAPrim") << "	NOT broadcasting navigate (redirect)" << LL_ENDL; +				break; +			} +		} +		break; +		 +		case LLViewerMediaObserver::MEDIA_EVENT_NAVIGATE_COMPLETE: +		{ +			switch(impl->getNavState()) +			{ +				case LLViewerMediaImpl::MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED: +				{ +					// This is the first location changed event after the start of a non-server-directed nav.  It may need to be broadcast or bounced back. +					mediaNavigated(impl, plugin, plugin->getNavigateURI()); +				} +				break; +				 +				case LLViewerMediaImpl::MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED_SPURIOUS: +					// This navigate didn't change the current URL.   +					LL_DEBUGS("MediaOnAPrim") << "	NOT broadcasting navigate (spurious)" << LL_ENDL; +				break; + +				case LLViewerMediaImpl::MEDIANAVSTATE_SERVER_COMPLETE_BEFORE_LOCATION_CHANGED: +					// This is the the navigate complete event from a server-directed nav.  Don't broadcast it. +					LL_INFOS("MediaOnAPrim") << "	NOT broadcasting navigate (server-directed)" << LL_ENDL; +				break; +				 +				default: +					// For all other states, the navigate should have been handled by LOCATION_CHANGED events already. +				break; +			} +		} +		break; +		 +		default: +		break; +	} + +} + +void LLVOVolume::sendMediaDataUpdate() +{ +    if (sObjectMediaClient) +		sObjectMediaClient->updateMedia(new LLMediaDataClientObjectImpl(this, false)); +} + +void LLVOVolume::removeMediaImpl(S32 texture_index) +{ +	if(mMediaImplList.size() <= (U32)texture_index || mMediaImplList[texture_index].isNull()) +	{ +		return ; +	} + +	//make the face referencing to mMediaImplList[texture_index] to point back to the old texture. +	if(mDrawable && texture_index < mDrawable->getNumFaces()) +	{ +		LLFace* facep = mDrawable->getFace(texture_index) ; +		if(facep) +		{ +			LLViewerMediaTexture* media_tex = LLViewerTextureManager::findMediaTexture(mMediaImplList[texture_index]->getMediaTextureID()) ; +			if(media_tex) +			{ +				media_tex->removeMediaFromFace(facep) ; +			} +		} +	}		 +	 +	//check if some other face(s) of this object reference(s)to this media impl. +	S32 i ; +	S32 end = (S32)mMediaImplList.size() ; +	for(i = 0; i < end ; i++) +	{ +		if( i != texture_index && mMediaImplList[i] == mMediaImplList[texture_index]) +		{ +			break ; +		} +	} + +	if(i == end) //this object does not need this media impl. +	{ +		mMediaImplList[texture_index]->removeObject(this) ; +	} + +	mMediaImplList[texture_index] = NULL ; +	return ; +} + +void LLVOVolume::addMediaImpl(LLViewerMediaImpl* media_impl, S32 texture_index) +{ +	if((S32)mMediaImplList.size() < texture_index + 1) +	{ +		mMediaImplList.resize(texture_index + 1) ; +	} +	 +	if(mMediaImplList[texture_index].notNull()) +	{ +		if(mMediaImplList[texture_index] == media_impl) +		{ +			return ; +		} + +		removeMediaImpl(texture_index) ; +	} + +	mMediaImplList[texture_index] = media_impl; +	media_impl->addObject(this) ;	 + +	//add the face to show the media if it is in playing +	if(mDrawable) +	{ +		LLFace* facep = mDrawable->getFace(texture_index) ; +		if(facep) +		{ +			LLViewerMediaTexture* media_tex = LLViewerTextureManager::findMediaTexture(mMediaImplList[texture_index]->getMediaTextureID()) ; +			if(media_tex) +			{ +				media_tex->addMediaToFace(facep) ; +			} +		} +		else //the face is not available now, start media on this face later. +		{ +			media_impl->setUpdated(TRUE) ; +		} +	} +	return ; +} + +viewer_media_t LLVOVolume::getMediaImpl(U8 face_id) const +{ +	if(mMediaImplList.size() > face_id) +	{ +		return mMediaImplList[face_id]; +	} +	return NULL; +} + +F64 LLVOVolume::getTotalMediaInterest() const +{ +	// If this object is currently focused, this object has "high" interest +	if (LLViewerMediaFocus::getInstance()->getFocusedObjectID() == getID()) +		return F64_MAX; +	 +	F64 interest = (F64)-1.0;  // means not interested; +     +	// If this object is selected, this object has "high" interest, but since  +	// there can be more than one, we still add in calculated impl interest +	// XXX Sadly, 'contains()' doesn't take a const :( +	if (LLSelectMgr::getInstance()->getSelection()->contains(const_cast<LLVOVolume*>(this))) +		interest = F64_MAX / 2.0; +	 +	int i = 0; +	const int end = getNumTEs(); +	for ( ; i < end; ++i) +	{ +		const viewer_media_t &impl = getMediaImpl(i); +		if (!impl.isNull()) +		{ +			if (interest == (F64)-1.0) interest = (F64)0.0; +			interest += impl->getInterest(); +		} +	} +	return interest; +} + +S32 LLVOVolume::getFaceIndexWithMediaImpl(const LLViewerMediaImpl* media_impl, S32 start_face_id) +{ +	S32 end = (S32)mMediaImplList.size() ; +	for(S32 face_id = start_face_id + 1; face_id < end; face_id++) +	{ +		if(mMediaImplList[face_id] == media_impl) +		{ +			return face_id ; +		} +	} +	return -1 ; +} + +//---------------------------------------------------------------------------- + +void LLVOVolume::setLightTextureID(LLUUID id) +{ +	if (id.notNull()) +	{ +		if (!hasLightTexture()) +		{ +			setParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE, TRUE, true); +		} +		LLLightImageParams* param_block = (LLLightImageParams*) getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE); +		if (param_block && param_block->getLightTexture() != id) +		{ +			param_block->setLightTexture(id); +			parameterChanged(LLNetworkData::PARAMS_LIGHT_IMAGE, true); +		} +	} +	else +	{ +		if (hasLightTexture()) +		{ +			setParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE, FALSE, true); +			mLightTexture = NULL; +		} +	}		 +} + +void LLVOVolume::setSpotLightParams(LLVector3 params) +{ +	LLLightImageParams* param_block = (LLLightImageParams*) getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE); +	if (param_block && param_block->getParams() != params) +	{ +		param_block->setParams(params); +		parameterChanged(LLNetworkData::PARAMS_LIGHT_IMAGE, true); +	} +} +		 +void LLVOVolume::setIsLight(BOOL is_light) +{ +	if (is_light != getIsLight()) +	{ +		if (is_light) +		{ +			setParameterEntryInUse(LLNetworkData::PARAMS_LIGHT, TRUE, true); +		} +		else +		{ +			setParameterEntryInUse(LLNetworkData::PARAMS_LIGHT, FALSE, true); +		} + +		if (is_light) +		{ +			// Add it to the pipeline mLightSet +			gPipeline.setLight(mDrawable, TRUE); +		} +		else +		{ +			// Not a light.  Remove it from the pipeline's light set. +			gPipeline.setLight(mDrawable, FALSE); +		} +	} +} + +void LLVOVolume::setLightColor(const LLColor3& color) +{ +	LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); +	if (param_block) +	{ +		if (param_block->getColor() != color) +		{ +			param_block->setColor(LLColor4(color, param_block->getColor().mV[3])); +			parameterChanged(LLNetworkData::PARAMS_LIGHT, true); +			gPipeline.markTextured(mDrawable); +			mFaceMappingChanged = TRUE; +		} +	} +} + +void LLVOVolume::setLightIntensity(F32 intensity) +{ +	LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); +	if (param_block) +	{ +		if (param_block->getColor().mV[3] != intensity) +		{ +			param_block->setColor(LLColor4(LLColor3(param_block->getColor()), intensity)); +			parameterChanged(LLNetworkData::PARAMS_LIGHT, true); +		} +	} +} + +void LLVOVolume::setLightRadius(F32 radius) +{ +	LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); +	if (param_block) +	{ +		if (param_block->getRadius() != radius) +		{ +			param_block->setRadius(radius); +			parameterChanged(LLNetworkData::PARAMS_LIGHT, true); +		} +	} +} + +void LLVOVolume::setLightFalloff(F32 falloff) +{ +	LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); +	if (param_block) +	{ +		if (param_block->getFalloff() != falloff) +		{ +			param_block->setFalloff(falloff); +			parameterChanged(LLNetworkData::PARAMS_LIGHT, true); +		} +	} +} + +void LLVOVolume::setLightCutoff(F32 cutoff) +{ +	LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); +	if (param_block) +	{ +		if (param_block->getCutoff() != cutoff) +		{ +			param_block->setCutoff(cutoff); +			parameterChanged(LLNetworkData::PARAMS_LIGHT, true); +		} +	} +} + +//---------------------------------------------------------------------------- + +BOOL LLVOVolume::getIsLight() const +{ +	return getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT); +} + +LLColor3 LLVOVolume::getLightBaseColor() const +{ +	const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); +	if (param_block) +	{ +		return LLColor3(param_block->getColor()); +	} +	else +	{ +		return LLColor3(1,1,1); +	} +} + +LLColor3 LLVOVolume::getLightColor() const +{ +	const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); +	if (param_block) +	{ +		return LLColor3(param_block->getColor()) * param_block->getColor().mV[3]; +	} +	else +	{ +		return LLColor3(1,1,1); +	} +} + +LLUUID LLVOVolume::getLightTextureID() const +{ +	if (getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE)) +	{ +		const LLLightImageParams *param_block = (const LLLightImageParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE); +		if (param_block) +		{ +			return param_block->getLightTexture(); +		} +	} +	 +	return LLUUID::null; +} + + +LLVector3 LLVOVolume::getSpotLightParams() const +{ +	if (getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE)) +	{ +		const LLLightImageParams *param_block = (const LLLightImageParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE); +		if (param_block) +		{ +			return param_block->getParams(); +		} +	} +	 +	return LLVector3(); +} + +F32 LLVOVolume::getSpotLightPriority() const +{ +	return mSpotLightPriority; +} + +void LLVOVolume::updateSpotLightPriority() +{ +	LLVector3 pos = mDrawable->getPositionAgent(); +	LLVector3 at(0,0,-1); +	at *= getRenderRotation(); + +	F32 r = getLightRadius()*0.5f; + +	pos += at * r; + +	at = LLViewerCamera::getInstance()->getAtAxis(); + +	pos -= at * r; +	 +	mSpotLightPriority = gPipeline.calcPixelArea(pos, LLVector3(r,r,r), *LLViewerCamera::getInstance()); + +	if (mLightTexture.notNull()) +	{ +		mLightTexture->addTextureStats(mSpotLightPriority); +		mLightTexture->setBoostLevel(LLViewerTexture::BOOST_CLOUDS); +	} +} + + +bool LLVOVolume::isLightSpotlight() const +{ +	LLLightImageParams* params = (LLLightImageParams*) getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE); +	if (params) +	{ +		return params->isLightSpotlight(); +	} +	return false; +} + + +LLViewerTexture* LLVOVolume::getLightTexture() +{ +	LLUUID id = getLightTextureID(); + +	if (id.notNull()) +	{ +		if (mLightTexture.isNull() || id != mLightTexture->getID()) +		{ +			mLightTexture = LLViewerTextureManager::getFetchedTexture(id); +		} +	} +	else +	{ +		mLightTexture = NULL; +	} + +	return mLightTexture; +} + +F32 LLVOVolume::getLightIntensity() const +{ +	const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); +	if (param_block) +	{ +		return param_block->getColor().mV[3]; +	} +	else +	{ +		return 1.f; +	} +} + +F32 LLVOVolume::getLightRadius() const +{ +	const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); +	if (param_block) +	{ +		return param_block->getRadius(); +	} +	else +	{ +		return 0.f; +	} +} + +F32 LLVOVolume::getLightFalloff() const +{ +	const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); +	if (param_block) +	{ +		return param_block->getFalloff(); +	} +	else +	{ +		return 0.f; +	} +} + +F32 LLVOVolume::getLightCutoff() const +{ +	const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); +	if (param_block) +	{ +		return param_block->getCutoff(); +	} +	else +	{ +		return 0.f; +	} +} + +U32 LLVOVolume::getVolumeInterfaceID() const +{ +	if (mVolumeImpl) +	{ +		return mVolumeImpl->getID(); +	} + +	return 0; +} + +BOOL LLVOVolume::isFlexible() const +{ +	if (getParameterEntryInUse(LLNetworkData::PARAMS_FLEXIBLE)) +	{ +		LLVolume* volume = getVolume(); +		if (volume && volume->getParams().getPathParams().getCurveType() != LL_PCODE_PATH_FLEXIBLE) +		{ +			LLVolumeParams volume_params = getVolume()->getParams(); +			U8 profile_and_hole = volume_params.getProfileParams().getCurveType(); +			volume_params.setType(profile_and_hole, LL_PCODE_PATH_FLEXIBLE); +		} +		return TRUE; +	} +	else +	{ +		return FALSE; +	} +} + +BOOL LLVOVolume::isSculpted() const +{ +	if (getParameterEntryInUse(LLNetworkData::PARAMS_SCULPT)) +	{ +		return TRUE; +	} +	 +	return FALSE; +} + +BOOL LLVOVolume::isMesh() const +{ +	if (isSculpted()) +	{ +		LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT); +		U8 sculpt_type = sculpt_params->getSculptType(); + +		if ((sculpt_type & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH) +			// mesh is a mesh +		{ +			return TRUE;	 +		} +	} + +	return FALSE; +} + +BOOL LLVOVolume::hasLightTexture() const +{ +	if (getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE)) +	{ +		return TRUE; +	} + +	return FALSE; +} + +BOOL LLVOVolume::isVolumeGlobal() const +{ +	if (mVolumeImpl) +	{ +		return mVolumeImpl->isVolumeGlobal() ? TRUE : FALSE; +	} +	else if (mRiggedVolume.notNull()) +	{ +		return TRUE; +	} + +	return FALSE; +} + +BOOL LLVOVolume::canBeFlexible() const +{ +	U8 path = getVolume()->getParams().getPathParams().getCurveType(); +	return (path == LL_PCODE_PATH_FLEXIBLE || path == LL_PCODE_PATH_LINE); +} + +BOOL LLVOVolume::setIsFlexible(BOOL is_flexible) +{ +	BOOL res = FALSE; +	BOOL was_flexible = isFlexible(); +	LLVolumeParams volume_params; +	if (is_flexible) +	{ +		if (!was_flexible) +		{ +			volume_params = getVolume()->getParams(); +			U8 profile_and_hole = volume_params.getProfileParams().getCurveType(); +			volume_params.setType(profile_and_hole, LL_PCODE_PATH_FLEXIBLE); +			res = TRUE; +			setFlags(FLAGS_USE_PHYSICS, FALSE); +			setFlags(FLAGS_PHANTOM, TRUE); +			setParameterEntryInUse(LLNetworkData::PARAMS_FLEXIBLE, TRUE, true); +			if (mDrawable) +			{ +				mDrawable->makeActive(); +			} +		} +	} +	else +	{ +		if (was_flexible) +		{ +			volume_params = getVolume()->getParams(); +			U8 profile_and_hole = volume_params.getProfileParams().getCurveType(); +			volume_params.setType(profile_and_hole, LL_PCODE_PATH_LINE); +			res = TRUE; +			setFlags(FLAGS_PHANTOM, FALSE); +			setParameterEntryInUse(LLNetworkData::PARAMS_FLEXIBLE, FALSE, true); +		} +	} +	if (res) +	{ +		res = setVolume(volume_params, 1); +		if (res) +		{ +			markForUpdate(TRUE); +		} +	} +	return res; +} + +//---------------------------------------------------------------------------- + +void LLVOVolume::generateSilhouette(LLSelectNode* nodep, const LLVector3& view_point) +{ +	LLVolume *volume = getVolume(); + +	if (volume) +	{ +		LLVector3 view_vector; +		view_vector = view_point;  + +		//transform view vector into volume space +		view_vector -= getRenderPosition(); +		mDrawable->mDistanceWRTCamera = view_vector.length(); +		LLQuaternion worldRot = getRenderRotation(); +		view_vector = view_vector * ~worldRot; +		if (!isVolumeGlobal()) +		{ +			LLVector3 objScale = getScale(); +			LLVector3 invObjScale(1.f / objScale.mV[VX], 1.f / objScale.mV[VY], 1.f / objScale.mV[VZ]); +			view_vector.scaleVec(invObjScale); +		} +		 +		updateRelativeXform(); +		LLMatrix4 trans_mat = mRelativeXform; +		if (mDrawable->isStatic()) +		{ +			trans_mat.translate(getRegion()->getOriginAgent()); +		} + +		volume->generateSilhouetteVertices(nodep->mSilhouetteVertices, nodep->mSilhouetteNormals, view_vector, trans_mat, mRelativeXformInvTrans, nodep->getTESelectMask()); + +		nodep->mSilhouetteExists = TRUE; +	} +} + +void LLVOVolume::deleteFaces() +{ +	S32 face_count = mNumFaces; +	if (mDrawable.notNull()) +	{ +		mDrawable->deleteFaces(0, face_count); +	} + +	mNumFaces = 0; +} + +void LLVOVolume::updateRadius() +{ +	if (mDrawable.isNull()) +	{ +		return; +	} +	 +	mVObjRadius = getScale().length(); +	mDrawable->setRadius(mVObjRadius); +} + + +BOOL LLVOVolume::isAttachment() const +{ +	return mState != 0 ; +} + +BOOL LLVOVolume::isHUDAttachment() const +{ +	// *NOTE: we assume hud attachment points are in defined range +	// since this range is constant for backwards compatibility +	// reasons this is probably a reasonable assumption to make +	S32 attachment_id = ATTACHMENT_ID_FROM_STATE(mState); +	return ( attachment_id >= 31 && attachment_id <= 38 ); +} + + +const LLMatrix4 LLVOVolume::getRenderMatrix() const +{ +	if (mDrawable->isActive() && !mDrawable->isRoot()) +	{ +		return mDrawable->getParent()->getWorldMatrix(); +	} +	return mDrawable->getWorldMatrix(); +} + +// Returns a base cost and adds textures to passed in set. +// total cost is returned value + 5 * size of the resulting set. +// Cannot include cost of textures, as they may be re-used in linked +// children, and cost should only be increased for unique textures  -Nyx +U32 LLVOVolume::getRenderCost(std::set<LLUUID> &textures) const +{ +	// base cost of each prim should be 10 points +	static const U32 ARC_PRIM_COST = 10; +	// per-prim costs +	static const U32 ARC_INVISI_COST = 1; +	static const U32 ARC_SHINY_COST = 1; +	static const U32 ARC_GLOW_COST = 1; +	static const U32 ARC_FLEXI_COST = 8; +	static const U32 ARC_PARTICLE_COST = 16; +	static const U32 ARC_BUMP_COST = 4; + +	// per-face costs +	static const U32 ARC_PLANAR_COST = 1; +	static const U32 ARC_ANIM_TEX_COST = 4; +	static const U32 ARC_ALPHA_COST = 4; + +	U32 shame = ARC_PRIM_COST; + +	U32 invisi = 0; +	U32 shiny = 0; +	U32 glow = 0; +	U32 alpha = 0; +	U32 flexi = 0; +	U32 animtex = 0; +	U32 particles = 0; +	U32 scale = 0; +	U32 bump = 0; +	U32 planar = 0; + +	if (isFlexible()) +	{ +		flexi = 1; +	} +	if (isParticleSource()) +	{ +		particles = 1; +	} + +	const LLVector3& sc = getScale(); +	scale += (U32) sc.mV[0] + (U32) sc.mV[1] + (U32) sc.mV[2]; + +	const LLDrawable* drawablep = mDrawable; + +	if (isSculpted()) +	{ +		const LLSculptParams *sculpt_params = (LLSculptParams *) getParameterEntry(LLNetworkData::PARAMS_SCULPT); +		LLUUID sculpt_id = sculpt_params->getSculptTexture(); +		textures.insert(sculpt_id); +	} + +	for (S32 i = 0; i < drawablep->getNumFaces(); ++i) +	{ +		const LLFace* face = drawablep->getFace(i); +		const LLTextureEntry* te = face->getTextureEntry(); +		const LLViewerTexture* img = face->getTexture(); + +		if (img) +		{ +			textures.insert(img->getID()); +		} + +		if (face->getPoolType() == LLDrawPool::POOL_ALPHA) +		{ +			alpha++; +		} +		else if (img && img->getPrimaryFormat() == GL_ALPHA) +		{ +			invisi = 1; +		} + +		if (te) +		{ +			if (te->getBumpmap()) +			{ +				bump = 1; +			} +			if (te->getShiny()) +			{ +				shiny = 1; +			} +			if (te->getGlow() > 0.f) +			{ +				glow = 1; +			} +			if (face->mTextureMatrix != NULL) +			{ +				animtex++; +			} +			if (te->getTexGen()) +			{ +				planar++; +			} +		} +	} + + +	shame += invisi * ARC_INVISI_COST; +	shame += shiny * ARC_SHINY_COST; +	shame += glow * ARC_GLOW_COST; +	shame += alpha * ARC_ALPHA_COST; +	shame += flexi * ARC_FLEXI_COST; +	shame += animtex * ARC_ANIM_TEX_COST; +	shame += particles * ARC_PARTICLE_COST; +	shame += bump * ARC_BUMP_COST; +	shame += planar * ARC_PLANAR_COST; +	shame += scale; + +	LLViewerObject::const_child_list_t& child_list = getChildren(); +	for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); +		 iter != child_list.end();  +		 ++iter) +	{ +		const LLViewerObject* child_objectp = *iter; +		const LLDrawable* child_drawablep = child_objectp->mDrawable; +		if (child_drawablep) +		{ +			const LLVOVolume* child_volumep = child_drawablep->getVOVolume(); +			if (child_volumep) +			{ +				shame += child_volumep->getRenderCost(textures); +			} +		} +	} + +	return shame; + +} + +F32 LLVOVolume::getStreamingCost(S32* bytes, S32* visible_bytes) +{ +	if (isMesh()) +	{	 +		LLSD& header = gMeshRepo.getMeshHeader(getVolume()->getParams().getSculptID()); + +		F32 radius = getScale().length(); +		 +		return LLMeshRepository::getStreamingCost(header, radius, bytes, visible_bytes, mLOD); +	} +		 +	return 0.f; +} + +U32 LLVOVolume::getTriangleCount() +{ +	U32 count = 0; +	LLVolume* volume = getVolume(); +	if (volume) +	{ +		count = volume->getNumTriangles(); +	} + +	return count; +} + +U32 LLVOVolume::getHighLODTriangleCount() +{ +	U32 ret = 0; + +	LLVolume* volume = getVolume(); + +	if (!isSculpted()) +	{  		LLVolume* ref = LLPrimitive::getVolumeManager()->refVolume(volume->getParams(), 3);  		ret = ref->getNumTriangles(); -		LLPrimitive::getVolumeManager()->unrefVolume(ref);
 -	}
 -	else if (isMesh())
 -	{
 +		LLPrimitive::getVolumeManager()->unrefVolume(ref); +	} +	else if (isMesh()) +	{  		LLVolume* ref = LLPrimitive::getVolumeManager()->refVolume(volume->getParams(), 3);  		if (ref->isTetrahedron() || ref->getNumVolumeFaces() == 0)  		{  			gMeshRepo.loadMesh(this, volume->getParams(), LLModel::LOD_HIGH);  		}  		ret = ref->getNumTriangles(); -		LLPrimitive::getVolumeManager()->unrefVolume(ref);
 -	}
 -	else
 -	{ //default sculpts have a constant number of triangles
 -		ret = 31*2*31;  //31 rows of 31 columns of quads for a 32x32 vertex patch
 -	}
 -
 -	return ret;
 -}
 -
 -//static
 -void LLVOVolume::preUpdateGeom()
 -{
 -	sNumLODChanges = 0;
 -}
 -
 -void LLVOVolume::parameterChanged(U16 param_type, bool local_origin)
 -{
 -	LLViewerObject::parameterChanged(param_type, local_origin);
 -}
 -
 -void LLVOVolume::parameterChanged(U16 param_type, LLNetworkData* data, BOOL in_use, bool local_origin)
 -{
 -	LLViewerObject::parameterChanged(param_type, data, in_use, local_origin);
 -	if (mVolumeImpl)
 -	{
 -		mVolumeImpl->onParameterChanged(param_type, data, in_use, local_origin);
 -	}
 -	if (mDrawable.notNull())
 -	{
 -		BOOL is_light = getIsLight();
 -		if (is_light != mDrawable->isState(LLDrawable::LIGHT))
 -		{
 -			gPipeline.setLight(mDrawable, is_light);
 -		}
 -	}
 -}
 -
 -void LLVOVolume::setSelected(BOOL sel)
 -{
 -	LLViewerObject::setSelected(sel);
 -	if (mDrawable.notNull())
 -	{
 -		markForUpdate(TRUE);
 -	}
 -}
 -
 -void LLVOVolume::updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
 -{		
 -}
 -
 -F32 LLVOVolume::getBinRadius()
 -{
 -	F32 radius;
 -	
 -	F32 scale = 1.f;
 -
 -	const LLVector4a* ext = mDrawable->getSpatialExtents();
 -	
 -	BOOL shrink_wrap = mDrawable->isAnimating();
 -	BOOL alpha_wrap = FALSE;
 -
 -	if (!isHUDAttachment())
 -	{
 -		for (S32 i = 0; i < mDrawable->getNumFaces(); i++)
 -		{
 -			LLFace* face = mDrawable->getFace(i);
 -			if (face->getPoolType() == LLDrawPool::POOL_ALPHA &&
 -			    !face->canRenderAsMask())
 -			{
 -				alpha_wrap = TRUE;
 -				break;
 -			}
 -		}
 -	}
 -	else
 -	{
 -		shrink_wrap = FALSE;
 -	}
 -
 -	if (alpha_wrap)
 -	{
 -		LLVector3 bounds = getScale();
 -		radius = llmin(bounds.mV[1], bounds.mV[2]);
 -		radius = llmin(radius, bounds.mV[0]);
 -		radius *= 0.5f;
 -	}
 -	else if (shrink_wrap)
 -	{
 -		LLVector4a rad;
 -		rad.setSub(ext[1], ext[0]);
 -		
 -		radius = rad.getLength3().getF32()*0.5f;
 -	}
 -	else if (mDrawable->isStatic())
 -	{
 -		/*if (mDrawable->getRadius() < 2.0f)
 -		{
 -			radius = 16.f;
 -		}
 -		else
 -		{
 -			radius = llmax(mDrawable->getRadius(), 32.f);
 -		}*/
 -
 -		radius = (((S32) mDrawable->getRadius())/2+1)*8;
 -	}
 -	else if (mDrawable->getVObj()->isAttachment())
 -	{
 -		radius = (((S32) (mDrawable->getRadius()*4)+1))*2;
 -	}
 -	else
 -	{
 -		radius = 8.f;
 -	}
 -
 -	return llclamp(radius*scale, 0.5f, 256.f);
 -}
 -
 -const LLVector3 LLVOVolume::getPivotPositionAgent() const
 -{
 -	if (mVolumeImpl)
 -	{
 -		return mVolumeImpl->getPivotPosition();
 -	}
 -	return LLViewerObject::getPivotPositionAgent();
 -}
 -
 -void LLVOVolume::onShift(const LLVector4a &shift_vector)
 -{
 -	if (mVolumeImpl)
 -	{
 -		mVolumeImpl->onShift(shift_vector);
 -	}
 -
 -	updateRelativeXform();
 -}
 -
 -const LLMatrix4& LLVOVolume::getWorldMatrix(LLXformMatrix* xform) const
 -{
 -	if (mVolumeImpl)
 -	{
 -		return mVolumeImpl->getWorldMatrix(xform);
 -	}
 -	return xform->getWorldMatrix();
 -}
 -
 -LLVector3 LLVOVolume::agentPositionToVolume(const LLVector3& pos) const
 -{
 -	LLVector3 ret = pos - getRenderPosition();
 -	ret = ret * ~getRenderRotation();
 -	LLVector3 objScale = isVolumeGlobal() ? LLVector3(1,1,1) : getScale();
 -	LLVector3 invObjScale(1.f / objScale.mV[VX], 1.f / objScale.mV[VY], 1.f / objScale.mV[VZ]);
 -	ret.scaleVec(invObjScale);
 -	
 -	return ret;
 -}
 -
 -LLVector3 LLVOVolume::agentDirectionToVolume(const LLVector3& dir) const
 -{
 -	LLVector3 ret = dir * ~getRenderRotation();
 -	
 -	LLVector3 objScale = isVolumeGlobal() ? LLVector3(1,1,1) : getScale();
 -	ret.scaleVec(objScale);
 -
 -	return ret;
 -}
 -
 -LLVector3 LLVOVolume::volumePositionToAgent(const LLVector3& dir) const
 -{
 -	LLVector3 ret = dir;
 -	LLVector3 objScale = isVolumeGlobal() ? LLVector3(1,1,1) : getScale();
 -	ret.scaleVec(objScale);
 -	ret = ret * getRenderRotation();
 -	ret += getRenderPosition();
 -	
 -	return ret;
 -}
 -
 -LLVector3 LLVOVolume::volumeDirectionToAgent(const LLVector3& dir) const
 -{
 -	LLVector3 ret = dir;
 -	LLVector3 objScale = isVolumeGlobal() ? LLVector3(1,1,1) : getScale();
 -	LLVector3 invObjScale(1.f / objScale.mV[VX], 1.f / objScale.mV[VY], 1.f / objScale.mV[VZ]);
 -	ret.scaleVec(invObjScale);
 -	ret = ret * getRenderRotation();
 -
 -	return ret;
 -}
 -
 -
 -BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, S32 face, BOOL pick_transparent, S32 *face_hitp,
 -									  LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal)
 -	
 -{
 -	if (!mbCanSelect 
 -		|| mDrawable->isDead() 
 -		|| !gPipeline.hasRenderType(mDrawable->getRenderType()))
 -	{
 -		return FALSE;
 -	}
 -
 -	BOOL ret = FALSE;
 -
 -	LLVolume* volume = getVolume();
 -
 -	bool transform = true;
 -
 -	if (mDrawable->isState(LLDrawable::RIGGED))
 -	{
 -		if (LLFloater::isVisible(gFloaterTools) && getAvatar()->isSelf())
 -		{
 -			gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_RIGGED, TRUE);
 -			volume = mRiggedVolume;
 -			transform = false;
 -		}
 -		else
 -		{ //cannot pick rigged attachments on other avatars or when not in build mode
 -			return FALSE;
 -		}
 -	}
 -	
 -	if (volume)
 -	{	
 -		LLVector3 v_start, v_end, v_dir;
 -	
 -		if (transform)
 -		{
 -			v_start = agentPositionToVolume(start);
 -			v_end = agentPositionToVolume(end);
 -		}
 -		else
 -		{
 -			v_start = start;
 -			v_end = end;
 -		}
 -		
 -		LLVector3 p;
 -		LLVector3 n;
 -		LLVector2 tc;
 -		LLVector3 bn;
 -
 -		if (intersection != NULL)
 -		{
 -			p = *intersection;
 -		}
 -
 -		if (tex_coord != NULL)
 -		{
 -			tc = *tex_coord;
 -		}
 -
 -		if (normal != NULL)
 -		{
 -			n = *normal;
 -		}
 -
 -		if (bi_normal != NULL)
 -		{
 -			bn = *bi_normal;
 -		}
 -
 -		S32 face_hit = -1;
 -
 -		S32 start_face, end_face;
 -		if (face == -1)
 -		{
 -			start_face = 0;
 -			end_face = volume->getNumVolumeFaces();
 -		}
 -		else
 -		{
 -			start_face = face;
 -			end_face = face+1;
 -		}
 -
 -		bool special_cursor = specialHoverCursor();
 -		for (S32 i = start_face; i < end_face; ++i)
 -		{
 -			if (!special_cursor && !pick_transparent && getTE(i)->getColor().mV[3] == 0.f)
 -			{ //don't attempt to pick completely transparent faces unless
 -				//pick_transparent is true
 -				continue;
 -			}
 -
 -			face_hit = volume->lineSegmentIntersect(v_start, v_end, i,
 -													&p, &tc, &n, &bn);
 -			
 -			if (face_hit >= 0 && mDrawable->getNumFaces() > face_hit)
 -			{
 -				LLFace* face = mDrawable->getFace(face_hit);				
 -
 -				if (pick_transparent || !face->getTexture() || !face->getTexture()->hasGLTexture() || face->getTexture()->getMask(face->surfaceToTexture(tc, p, n)))
 -				{
 -					v_end = p;
 -					if (face_hitp != NULL)
 -					{
 -						*face_hitp = face_hit;
 -					}
 -					
 -					if (intersection != NULL)
 -					{
 -						if (transform)
 -						{
 -							*intersection = volumePositionToAgent(p);  // must map back to agent space
 -						}
 -						else
 -						{
 -							*intersection = p;
 -						}
 -					}
 -
 -					if (normal != NULL)
 -					{
 -						if (transform)
 -						{
 -							*normal = volumeDirectionToAgent(n);
 -						}
 -						else
 -						{
 -							*normal = n;
 -						}
 -
 -						(*normal).normVec();
 -					}
 -
 -					if (bi_normal != NULL)
 -					{
 -						if (transform)
 -						{
 -							*bi_normal = volumeDirectionToAgent(bn);
 -						}
 -						else
 -						{
 -							*bi_normal = bn;
 -						}
 -						(*bi_normal).normVec();
 -					}
 -
 -					if (tex_coord != NULL)
 -					{
 -						*tex_coord = tc;
 -					}
 -					
 -					ret = TRUE;
 -				}
 -			}
 -		}
 -	}
 -		
 -	return ret;
 -}
 -
 -bool LLVOVolume::treatAsRigged()
 -{
 -	return LLFloater::isVisible(gFloaterTools) && 
 -			isAttachment() && 
 -			getAvatar() &&
 -			getAvatar()->isSelf() &&
 -			mDrawable.notNull() &&
 -			mDrawable->isState(LLDrawable::RIGGED);
 -}
 -
 -LLRiggedVolume* LLVOVolume::getRiggedVolume()
 -{
 -	return mRiggedVolume;
 -}
 -
 -void LLVOVolume::clearRiggedVolume()
 -{
 -	if (mRiggedVolume.notNull())
 -	{
 -		mRiggedVolume = NULL;
 -		updateRelativeXform();
 -	}
 -}
 -
 -void LLVOVolume::updateRiggedVolume()
 -{
 -	//Update mRiggedVolume to match current animation frame of avatar. 
 -	//Also update position/size in octree.  
 -
 -	if (!treatAsRigged())
 -	{
 -		clearRiggedVolume();
 -		
 -		return;
 -	}
 -
 -	LLVolume* volume = getVolume();
 -
 -	const LLMeshSkinInfo* skin = gMeshRepo.getSkinInfo(volume->getParams().getSculptID());
 -
 -	if (!skin)
 -	{
 -		clearRiggedVolume();
 -		return;
 -	}
 -
 -	LLVOAvatar* avatar = getAvatar();
 -
 -	if (!avatar)
 -	{
 -		clearRiggedVolume();
 -		return;
 -	}
 -
 -	if (!mRiggedVolume)
 -	{
 -		LLVolumeParams p;
 -		mRiggedVolume = new LLRiggedVolume(p);
 -		updateRelativeXform();
 -	}
 -
 -	mRiggedVolume->update(skin, avatar, volume);
 -
 -}
 -
 -static LLFastTimer::DeclareTimer FTM_SKIN_RIGGED("Skin");
 -static LLFastTimer::DeclareTimer FTM_RIGGED_OCTREE("Octree");
 -
 -void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, const LLVolume* volume)
 -{
 -	bool copy = false;
 -	if (volume->getNumVolumeFaces() != getNumVolumeFaces())
 -	{ 
 -		copy = true;
 -	}
 -
 -	for (S32 i = 0; i < volume->getNumVolumeFaces() && !copy; ++i)
 -	{
 -		const LLVolumeFace& src_face = volume->getVolumeFace(i);
 -		const LLVolumeFace& dst_face = getVolumeFace(i);
 -
 -		if (src_face.mNumIndices != dst_face.mNumIndices ||
 -			src_face.mNumVertices != dst_face.mNumVertices)
 -		{
 -			copy = true;
 -		}
 -	}
 -
 -	if (copy)
 -	{
 -		copyVolumeFaces(volume);	
 -	}
 -
 -	//build matrix palette
 -	LLMatrix4a mp[64];
 -	LLMatrix4* mat = (LLMatrix4*) mp;
 -	
 -	for (U32 j = 0; j < skin->mJointNames.size(); ++j)
 -	{
 -		LLJoint* joint = avatar->getJoint(skin->mJointNames[j]);
 -		if (joint)
 -		{
 -			mat[j] = skin->mInvBindMatrix[j];
 -			mat[j] *= joint->getWorldMatrix();
 -		}
 -	}
 -
 -	for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
 -	{
 -		const LLVolumeFace& vol_face = volume->getVolumeFace(i);
 -		
 -		LLVolumeFace& dst_face = mVolumeFaces[i];
 -		
 -		LLVector4a* weight = vol_face.mWeights;
 -
 -		LLMatrix4a bind_shape_matrix;
 -		bind_shape_matrix.loadu(skin->mBindShapeMatrix);
 -
 -		LLVector4a* pos = dst_face.mPositions;
 -
 -		{
 -			LLFastTimer t(FTM_SKIN_RIGGED);
 -
 -			for (U32 j = 0; j < dst_face.mNumVertices; ++j)
 -			{
 -				LLMatrix4a final_mat;
 -				final_mat.clear();
 -
 -				S32 idx[4];
 -
 -				LLVector4 wght;
 -
 -				F32 scale = 0.f;
 -				for (U32 k = 0; k < 4; k++)
 -				{
 -					F32 w = weight[j][k];
 -
 -					idx[k] = (S32) floorf(w);
 -					wght[k] = w - floorf(w);
 -					scale += wght[k];
 -				}
 -
 -				wght *= 1.f/scale;
 -
 -				for (U32 k = 0; k < 4; k++)
 -				{
 -					F32 w = wght[k];
 -
 -					LLMatrix4a src;
 -					src.setMul(mp[idx[k]], w);
 -
 -					final_mat.add(src);
 -				}
 -
 -				
 -				LLVector4a& v = vol_face.mPositions[j];
 -				LLVector4a t;
 -				LLVector4a dst;
 -				bind_shape_matrix.affineTransform(v, t);
 -				final_mat.affineTransform(t, dst);
 -				pos[j] = dst;
 -			}
 -
 -			//update bounding box
 -			LLVector4a& min = dst_face.mExtents[0];
 -			LLVector4a& max = dst_face.mExtents[1];
 -
 -			min = pos[0];
 -			max = pos[1];
 -
 -			for (U32 j = 1; j < dst_face.mNumVertices; ++j)
 -			{
 -				min.setMin(min, pos[j]);
 -				max.setMax(max, pos[j]);
 -			}
 -
 -			dst_face.mCenter->setAdd(dst_face.mExtents[0], dst_face.mExtents[1]);
 -			dst_face.mCenter->mul(0.5f);
 -
 -		}
 -
 -		{
 -			LLFastTimer t(FTM_RIGGED_OCTREE);
 -			delete dst_face.mOctree;
 -			dst_face.mOctree = NULL;
 -
 -			LLVector4a size;
 -			size.setSub(dst_face.mExtents[1], dst_face.mExtents[0]);
 -			size.splat(size.getLength3().getF32()*0.5f);
 -			
 -			dst_face.createOctree(1.f);
 -		}
 -	}
 -}
 -
 -U32 LLVOVolume::getPartitionType() const
 -{
 -	if (isHUDAttachment())
 -	{
 -		return LLViewerRegion::PARTITION_HUD;
 -	}
 -
 -	return LLViewerRegion::PARTITION_VOLUME;
 -}
 -
 -LLVolumePartition::LLVolumePartition()
 -: LLSpatialPartition(LLVOVolume::VERTEX_DATA_MASK, TRUE, GL_DYNAMIC_DRAW_ARB)
 -{
 -	mLODPeriod = 32;
 -	mDepthMask = FALSE;
 -	mDrawableType = LLPipeline::RENDER_TYPE_VOLUME;
 -	mPartitionType = LLViewerRegion::PARTITION_VOLUME;
 -	mSlopRatio = 0.25f;
 -	mBufferUsage = GL_DYNAMIC_DRAW_ARB;
 -}
 -
 -LLVolumeBridge::LLVolumeBridge(LLDrawable* drawablep)
 -: LLSpatialBridge(drawablep, TRUE, LLVOVolume::VERTEX_DATA_MASK)
 -{
 -	mDepthMask = FALSE;
 -	mLODPeriod = 32;
 -	mDrawableType = LLPipeline::RENDER_TYPE_VOLUME;
 -	mPartitionType = LLViewerRegion::PARTITION_BRIDGE;
 -	
 -	mBufferUsage = GL_DYNAMIC_DRAW_ARB;
 -
 -	mSlopRatio = 0.25f;
 -}
 -
 -void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, U32 type)
 -{
 -	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 -
 -	if (facep->getViewerObject()->isSelected() && LLSelectMgr::getInstance()->mHideSelectedObjects)
 -	{
 -		return;
 -	}
 -
 -	//add face to drawmap
 -	LLSpatialGroup::drawmap_elem_t& draw_vec = group->mDrawMap[type];	
 -
 -	S32 idx = draw_vec.size()-1;
 -
 -	BOOL fullbright = (type == LLRenderPass::PASS_FULLBRIGHT) ||
 -		(type == LLRenderPass::PASS_INVISIBLE) ||
 -		(type == LLRenderPass::PASS_ALPHA && facep->isState(LLFace::FULLBRIGHT));
 -	
 -	if (!fullbright && type != LLRenderPass::PASS_GLOW && !facep->getVertexBuffer()->hasDataType(LLVertexBuffer::TYPE_NORMAL))
 -	{
 -		llwarns << "Non fullbright face has no normals!" << llendl;
 -		return;
 -	}
 -
 -	const LLMatrix4* tex_mat = NULL;
 -	if (facep->isState(LLFace::TEXTURE_ANIM) && facep->getVirtualSize() > MIN_TEX_ANIM_SIZE)
 -	{
 -		tex_mat = facep->mTextureMatrix;	
 -	}
 -
 -	const LLMatrix4* model_mat = NULL;
 -
 -	LLDrawable* drawable = facep->getDrawable();
 -	if (drawable->isActive())
 -	{
 -		model_mat = &(drawable->getRenderMatrix());
 -	}
 -	else
 -	{
 -		model_mat = &(drawable->getRegion()->mRenderMatrix);
 -		if (model_mat->isIdentity())
 -		{
 -			model_mat = NULL;
 -		}
 -	}
 -
 -	U8 bump = (type == LLRenderPass::PASS_BUMP || type == LLRenderPass::PASS_POST_BUMP) ? facep->getTextureEntry()->getBumpmap() : 0;
 -	
 -	LLViewerTexture* tex = facep->getTexture();
 -
 -	U8 glow = (U8) (facep->getTextureEntry()->getGlow() * 255);
 -
 -	if (idx >= 0 && 
 -		draw_vec[idx]->mVertexBuffer == facep->getVertexBuffer() &&
 -		draw_vec[idx]->mEnd == facep->getGeomIndex()-1 &&
 -		(LLPipeline::sTextureBindTest || draw_vec[idx]->mTexture == tex) &&
 -#if LL_DARWIN
 -		draw_vec[idx]->mEnd - draw_vec[idx]->mStart + facep->getGeomCount() <= (U32) gGLManager.mGLMaxVertexRange &&
 -		draw_vec[idx]->mCount + facep->getIndicesCount() <= (U32) gGLManager.mGLMaxIndexRange &&
 -#endif
 -		draw_vec[idx]->mGlowColor.mV[3] == glow &&
 -		draw_vec[idx]->mFullbright == fullbright &&
 -		draw_vec[idx]->mBump == bump &&
 -		draw_vec[idx]->mTextureMatrix == tex_mat &&
 -		draw_vec[idx]->mModelMatrix == model_mat)
 -	{
 -		draw_vec[idx]->mCount += facep->getIndicesCount();
 -		draw_vec[idx]->mEnd += facep->getGeomCount();
 -		draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, facep->getVirtualSize());
 -		draw_vec[idx]->validate();
 -		update_min_max(draw_vec[idx]->mExtents[0], draw_vec[idx]->mExtents[1], facep->mExtents[0]);
 -		update_min_max(draw_vec[idx]->mExtents[0], draw_vec[idx]->mExtents[1], facep->mExtents[1]);
 -	}
 -	else
 -	{
 -		U32 start = facep->getGeomIndex();
 -		U32 end = start + facep->getGeomCount()-1;
 -		U32 offset = facep->getIndicesStart();
 -		U32 count = facep->getIndicesCount();
 -		LLPointer<LLDrawInfo> draw_info = new LLDrawInfo(start,end,count,offset, tex, 
 -			facep->getVertexBuffer(), fullbright, bump); 
 -		draw_info->mGroup = group;
 -		draw_info->mVSize = facep->getVirtualSize();
 -		draw_vec.push_back(draw_info);
 -		draw_info->mTextureMatrix = tex_mat;
 -		draw_info->mModelMatrix = model_mat;
 -		draw_info->mGlowColor.setVec(0,0,0,glow);
 -		if (type == LLRenderPass::PASS_ALPHA)
 -		{ //for alpha sorting
 -			facep->setDrawInfo(draw_info);
 -		}
 -		draw_info->mExtents[0] = facep->mExtents[0];
 -		draw_info->mExtents[1] = facep->mExtents[1];
 -
 -		if (LLPipeline::sUseTriStrips)
 -		{
 -			draw_info->mDrawMode = LLRender::TRIANGLE_STRIP;
 -		}
 -
 -		draw_info->validate();
 -	}
 -}
 -
 -void LLVolumeGeometryManager::getGeometry(LLSpatialGroup* group)
 -{
 -
 -}
 -
 -static LLFastTimer::DeclareTimer FTM_REBUILD_VOLUME_VB("Volume");
 -static LLFastTimer::DeclareTimer FTM_REBUILD_VBO("VBO Rebuilt");
 -
 -static LLDrawPoolAvatar* get_avatar_drawpool(LLViewerObject* vobj)
 -{
 -	LLVOAvatar* avatar = vobj->getAvatar();
 -					
 -	if (avatar)
 -	{
 -		LLDrawable* drawable = avatar->mDrawable;
 -		if (drawable && drawable->getNumFaces() > 0)
 -		{
 -			LLFace* face = drawable->getFace(0);
 -			if (face)
 -			{
 -				LLDrawPool* drawpool = face->getPool();
 -				if (drawpool)
 -				{
 -					if (drawpool->getType() == LLDrawPool::POOL_AVATAR)
 -					{
 -						return (LLDrawPoolAvatar*) drawpool;
 -					}
 -				}
 -			}
 -		}
 -	}
 -
 -	return NULL;
 -}
 -
 -void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 -{
 -	if (group->changeLOD())
 -	{
 -		group->mLastUpdateDistance = group->mDistance;
 -	}
 -
 -	group->mLastUpdateViewAngle = group->mViewAngle;
 -
 -	if (!group->isState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::ALPHA_DIRTY))
 -	{
 -		if (group->isState(LLSpatialGroup::MESH_DIRTY) && !LLPipeline::sDelayVBUpdate)
 -		{
 -			LLFastTimer ftm(FTM_REBUILD_VBO);	
 -			LLFastTimer ftm2(FTM_REBUILD_VOLUME_VB);
 -		
 -			rebuildMesh(group);
 -		}
 -		return;
 -	}
 -
 -	group->mBuilt = 1.f;
 -	LLFastTimer ftm(FTM_REBUILD_VBO);	
 -
 -	LLFastTimer ftm2(FTM_REBUILD_VOLUME_VB);
 -
 -	group->clearDrawMap();
 -
 -	mFaceList.clear();
 -
 -	std::vector<LLFace*> fullbright_faces;
 -	std::vector<LLFace*> bump_faces;
 -	std::vector<LLFace*> simple_faces;
 -
 -	std::vector<LLFace*> alpha_faces;
 -	U32 useage = group->mSpatialPartition->mBufferUsage;
 -
 -	U32 max_vertices = (gSavedSettings.getS32("RenderMaxVBOSize")*1024)/LLVertexBuffer::calcVertexSize(group->mSpatialPartition->mVertexDataMask);
 -	U32 max_total = (gSavedSettings.getS32("RenderMaxNodeSize")*1024)/LLVertexBuffer::calcVertexSize(group->mSpatialPartition->mVertexDataMask);
 -	max_vertices = llmin(max_vertices, (U32) 65535);
 -
 -	U32 cur_total = 0;
 -
 -	//get all the faces into a list
 -	for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter)
 -	{
 -		LLDrawable* drawablep = *drawable_iter;
 -		
 -		if (drawablep->isDead() || drawablep->isState(LLDrawable::FORCE_INVISIBLE) )
 -		{
 -			continue;
 -		}
 -	
 -		if (drawablep->isAnimating())
 -		{ //fall back to stream draw for animating verts
 -			useage = GL_STREAM_DRAW_ARB;
 -		}
 -
 -		LLVOVolume* vobj = drawablep->getVOVolume();
 -
 -		if (vobj->getVolume() && vobj->getVolume()->isTetrahedron())
 -		{
 -			continue;
 -		}
 -
 -		llassert_always(vobj);
 -		vobj->updateTextureVirtualSize();
 -		vobj->preRebuild();
 -
 -		drawablep->clearState(LLDrawable::HAS_ALPHA);
 -
 -		bool rigged = vobj->isAttachment() && 
 -					vobj->isMesh() && 
 -					gMeshRepo.getSkinInfo(vobj->getVolume()->getParams().getSculptID());
 -
 -		bool bake_sunlight = LLPipeline::sBakeSunlight && drawablep->isStatic();
 -
 -		bool is_rigged = false;
 -
 -		//for each face
 -		for (S32 i = 0; i < drawablep->getNumFaces(); i++)
 -		{
 -			LLFace* facep = drawablep->getFace(i);
 -
 -			//ALWAYS null out vertex buffer on rebuild -- if the face lands in a render
 -			// batch, it will recover its vertex buffer reference from the spatial group
 -			facep->setVertexBuffer(NULL);
 -			
 -			//sum up face verts and indices
 -			drawablep->updateFaceSize(i);
 -			
 -			
 -
 -			if (rigged) 
 -			{
 -				if (!facep->isState(LLFace::RIGGED))
 -				{ //completely reset vertex buffer
 -					facep->clearVertexBuffer();
 -				}
 -		
 -				facep->setState(LLFace::RIGGED);
 -				is_rigged = true;
 -				
 -				//get drawpool of avatar with rigged face
 -				LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj);
 -				
 -				//Determine if we've received skininfo that contains an
 -				//alternate bind matrix - if it does then apply the translational component
 -				//to the joints of the avatar.
 -				LLVOAvatar* pAvatarVO = vobj->getAvatar();
 -				bool pelvisGotSet = false;
 -
 -				if ( pAvatarVO )
 -				{
 -					LLUUID currentId = vobj->getVolume()->getParams().getSculptID();
 -					const LLMeshSkinInfo*  pSkinData = gMeshRepo.getSkinInfo( currentId );
 -					
 -					if ( pSkinData )
 -					{
 -						const int bindCnt = pSkinData->mAlternateBindMatrix.size();								
 -						if ( bindCnt > 0 )
 -						{					
 -							const int jointCnt = pSkinData->mJointNames.size();
 -							const F32 pelvisZOffset = pSkinData->mPelvisOffset;
 -							bool fullRig = (jointCnt>=20) ? true : false;
 -							if ( fullRig )
 -							{
 -								for ( int i=0; i<jointCnt; ++i )
 -								{
 -									std::string lookingForJoint = pSkinData->mJointNames[i].c_str();
 -									//llinfos<<"joint name "<<lookingForJoint.c_str()<<llendl;
 -									LLJoint* pJoint = pAvatarVO->getJoint( lookingForJoint );
 -									if ( pJoint && pJoint->getId() != currentId )
 -									{   									
 -										pJoint->setId( currentId );
 -										const LLVector3& jointPos = pSkinData->mAlternateBindMatrix[i].getTranslation();									
 -										//Set the joint position
 -										pJoint->storeCurrentXform( jointPos );																																
 -										//If joint is a pelvis then handle old/new pelvis to foot values
 -										if ( lookingForJoint == "mPelvis" )
 -										{	
 -											pJoint->storeCurrentXform( jointPos );																																
 -											if ( !pAvatarVO->hasPelvisOffset() )
 -											{										
 -												pAvatarVO->setPelvisOffset( true, jointPos, pelvisZOffset );
 -												//Trigger to rebuild viewer AV
 -												pelvisGotSet = true;											
 -											}										
 -										}										
 -									}
 -								}
 -							}							
 -						}
 -					}
 -				}
 -				//If we've set the pelvis to a new position we need to also rebuild some information that the
 -				//viewer does at launch (e.g. body size etc.)
 -				if ( pelvisGotSet )
 -				{
 -					pAvatarVO->postPelvisSetRecalc();
 -				}
 -
 -				if (pool)
 -				{
 -					const LLTextureEntry* te = facep->getTextureEntry();
 -
 -					//remove face from old pool if it exists
 -					LLDrawPool* old_pool = facep->getPool();
 -					if (old_pool && old_pool->getType() == LLDrawPool::POOL_AVATAR)
 -					{
 -						((LLDrawPoolAvatar*) old_pool)->removeRiggedFace(facep);
 -					}
 -
 -					//add face to new pool
 -					LLViewerTexture* tex = facep->getTexture();
 -					U32 type = gPipeline.getPoolTypeFromTE(te, tex);
 -
 -					if (type == LLDrawPool::POOL_ALPHA)
 -					{
 -						if (te->getFullbright())
 -						{
 -							pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA);
 -						}
 -						else
 -						{
 -							pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_ALPHA);
 -						}
 -					}
 -					else if (te->getShiny())
 -					{
 -						if (te->getFullbright())
 -						{
 -							pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY);
 -						}
 -						else
 -						{
 -							if (LLPipeline::sRenderDeferred)
 -							{
 -								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE);
 -							}
 -							else
 -							{
 -								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SHINY);
 -							}
 -						}
 -					}
 -					else
 -					{
 -						if (te->getFullbright())
 -						{
 -							pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT);
 -						}
 -						else
 -						{
 -							pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE);
 -						}
 -					}
 -
 -					if (te->getGlow())
 -					{
 -						pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_GLOW);
 -					}
 -
 -					if (LLPipeline::sRenderDeferred)
 -					{
 -						if (type != LLDrawPool::POOL_ALPHA && !te->getFullbright())
 -						{
 -							if (te->getBumpmap())
 -							{
 -								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_BUMP);
 -							}
 -							else
 -							{
 -								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_SIMPLE);
 -							}
 -						}
 -					}
 -				}
 -
 -				continue;
 -			}
 -			else
 -			{
 -				if (facep->isState(LLFace::RIGGED))
 -				{ //face is not rigged but used to be, remove from rigged face pool
 -					LLDrawPoolAvatar* pool = (LLDrawPoolAvatar*) facep->getPool();
 -					if (pool)
 -					{
 -						pool->removeRiggedFace(facep);
 -					}
 -					facep->clearState(LLFace::RIGGED);
 -				}
 -			}
 -
 -			if (cur_total > max_total || facep->getIndicesCount() <= 0 || facep->getGeomCount() <= 0)
 -			{
 -				facep->clearVertexBuffer();
 -				continue;
 -			}
 -
 -			cur_total += facep->getGeomCount();
 -
 -			if (facep->hasGeometry() && facep->getPixelArea() > FORCE_CULL_AREA)
 -			{
 -				const LLTextureEntry* te = facep->getTextureEntry();
 -				LLViewerTexture* tex = facep->getTexture();
 -
 -				if (facep->isState(LLFace::TEXTURE_ANIM))
 -				{
 -					if (!vobj->mTexAnimMode)
 -					{
 -						facep->clearState(LLFace::TEXTURE_ANIM);
 -					}
 -				}
 -
 -				BOOL force_simple = (facep->getPixelArea() < FORCE_SIMPLE_RENDER_AREA);
 -				U32 type = gPipeline.getPoolTypeFromTE(te, tex);
 -				if (type != LLDrawPool::POOL_ALPHA && force_simple)
 -				{
 -					type = LLDrawPool::POOL_SIMPLE;
 -				}
 -				facep->setPoolType(type);
 -
 -				if (vobj->isHUDAttachment())
 -				{
 -					facep->setState(LLFace::FULLBRIGHT);
 -				}
 -
 -				if (vobj->mTextureAnimp && vobj->mTexAnimMode)
 -				{
 -					if (vobj->mTextureAnimp->mFace <= -1)
 -					{
 -						S32 face;
 -						for (face = 0; face < vobj->getNumTEs(); face++)
 -						{
 -							drawablep->getFace(face)->setState(LLFace::TEXTURE_ANIM);
 -						}
 -					}
 -					else if (vobj->mTextureAnimp->mFace < vobj->getNumTEs())
 -					{
 -						drawablep->getFace(vobj->mTextureAnimp->mFace)->setState(LLFace::TEXTURE_ANIM);
 -					}
 -				}
 -
 -				if (type == LLDrawPool::POOL_ALPHA)
 -				{
 -					if (facep->canRenderAsMask())
 -					{ //can be treated as alpha mask
 -						simple_faces.push_back(facep);
 -					}
 -					else
 -					{
 -						drawablep->setState(LLDrawable::HAS_ALPHA);
 -						alpha_faces.push_back(facep);
 -					}
 -				}
 -				else
 -				{
 -					if (drawablep->isState(LLDrawable::REBUILD_VOLUME))
 -					{
 -						facep->mLastUpdateTime = gFrameTimeSeconds;
 -					}
 -
 -					if (gPipeline.canUseWindLightShadersOnObjects()
 -						&& LLPipeline::sRenderBump)
 -					{
 -						if (te->getBumpmap())
 -						{ //needs normal + binormal
 -							bump_faces.push_back(facep);
 -						}
 -						else if (te->getShiny() || !te->getFullbright())
 -						{ //needs normal
 -							simple_faces.push_back(facep);
 -						}
 -						else 
 -						{ //doesn't need normal
 -							facep->setState(LLFace::FULLBRIGHT);
 -							fullbright_faces.push_back(facep);
 -						}
 -					}
 -					else
 -					{
 -						if (te->getBumpmap() && LLPipeline::sRenderBump)
 -						{ //needs normal + binormal
 -							bump_faces.push_back(facep);
 -						}
 -						else if ((te->getShiny() && LLPipeline::sRenderBump) ||
 -							!(te->getFullbright() || bake_sunlight))
 -						{ //needs normal
 -							simple_faces.push_back(facep);
 -						}
 -						else 
 -						{ //doesn't need normal
 -							facep->setState(LLFace::FULLBRIGHT);
 -							fullbright_faces.push_back(facep);
 -						}
 -					}
 -				}
 -			}
 -			else
 -			{	//face has no renderable geometry
 -				facep->clearVertexBuffer();
 -			}		
 -		}
 -
 -		if (is_rigged)
 -		{
 -			drawablep->setState(LLDrawable::RIGGED);
 -		}
 -		else
 -		{
 -			drawablep->clearState(LLDrawable::RIGGED);
 -		}
 -	}
 -
 -	group->mBufferUsage = useage;
 -
 -	//PROCESS NON-ALPHA FACES
 -	U32 simple_mask = LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR;
 -	U32 alpha_mask = simple_mask | 0x80000000; //hack to give alpha verts their own VBO
 -	U32 bump_mask = LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR;
 -	U32 fullbright_mask = LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR;
 -
 -	if (LLPipeline::sRenderDeferred)
 -	{
 -		bump_mask |= LLVertexBuffer::MAP_BINORMAL;
 -	}
 -	
 -	genDrawInfo(group, simple_mask, simple_faces);
 -	genDrawInfo(group, bump_mask, bump_faces);
 -	genDrawInfo(group, fullbright_mask, fullbright_faces);
 -	genDrawInfo(group, alpha_mask, alpha_faces, TRUE);
 -
 -	if (!LLPipeline::sDelayVBUpdate)
 -	{
 -		//drawables have been rebuilt, clear rebuild status
 -		for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter)
 -		{
 -			LLDrawable* drawablep = *drawable_iter;
 -			drawablep->clearState(LLDrawable::REBUILD_ALL);
 -		}
 -	}
 -
 -	group->mLastUpdateTime = gFrameTimeSeconds;
 -	group->mBuilt = 1.f;
 -	group->clearState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::ALPHA_DIRTY);
 -
 -	if (LLPipeline::sDelayVBUpdate)
 -	{
 -		group->setState(LLSpatialGroup::MESH_DIRTY | LLSpatialGroup::NEW_DRAWINFO);
 -	}
 -
 -	mFaceList.clear();
 -}
 -
 -static LLFastTimer::DeclareTimer FTM_VOLUME_GEOM("Volume Geometry");
 -static LLFastTimer::DeclareTimer FTM_VOLUME_GEOM_PARTIAL("Terse Rebuild");
 -
 -void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
 -{
 -	llassert(group);
 -	if (group && group->isState(LLSpatialGroup::MESH_DIRTY) && !group->isState(LLSpatialGroup::GEOM_DIRTY))
 -	{
 -		LLFastTimer tm(FTM_VOLUME_GEOM);
 -		S32 num_mapped_veretx_buffer = LLVertexBuffer::sMappedCount ;
 -
 -		group->mBuilt = 1.f;
 -		
 -		for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter)
 -		{
 -			LLFastTimer t(FTM_VOLUME_GEOM_PARTIAL);
 -			LLDrawable* drawablep = *drawable_iter;
 -
 -			if (!drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) )
 -			{
 -				LLVOVolume* vobj = drawablep->getVOVolume();
 -				vobj->preRebuild();
 -
 -				LLVolume* volume = vobj->getVolume();
 -				for (S32 i = 0; i < drawablep->getNumFaces(); ++i)
 -				{
 -					LLFace* face = drawablep->getFace(i);
 -					if (face && face->getVertexBuffer())
 -					{
 -						face->getGeometryVolume(*volume, face->getTEOffset(), 
 -							vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), face->getGeomIndex());
 -					}
 -
 -					if (!face)
 -					{
 -						llerrs << "WTF?" << llendl;
 -					}
 -				}
 -
 -				drawablep->clearState(LLDrawable::REBUILD_ALL);
 -			}
 -		}
 -		
 -		//unmap all the buffers
 -		for (LLSpatialGroup::buffer_map_t::iterator i = group->mBufferMap.begin(); i != group->mBufferMap.end(); ++i)
 -		{
 -			LLSpatialGroup::buffer_texture_map_t& map = i->second;
 -			for (LLSpatialGroup::buffer_texture_map_t::iterator j = map.begin(); j != map.end(); ++j)
 -			{
 -				LLSpatialGroup::buffer_list_t& list = j->second;
 -				for (LLSpatialGroup::buffer_list_t::iterator k = list.begin(); k != list.end(); ++k)
 -				{
 -					LLVertexBuffer* buffer = *k;
 -					if (buffer->isLocked())
 -					{
 -						buffer->setBuffer(0);
 -					}
 -				}
 -			}
 -		}
 -		
 -		// don't forget alpha
 -		if(group != NULL && 
 -		   !group->mVertexBuffer.isNull() && 
 -		   group->mVertexBuffer->isLocked())
 -		{
 -			group->mVertexBuffer->setBuffer(0);
 -		}
 -
 -		//if not all buffers are unmapped
 -		if(num_mapped_veretx_buffer != LLVertexBuffer::sMappedCount) 
 -		{
 -			llwarns << "Not all mapped vertex buffers are unmapped!" << llendl ; 
 -			for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter)
 -			{
 -				LLDrawable* drawablep = *drawable_iter;
 -				for (S32 i = 0; i < drawablep->getNumFaces(); ++i)
 -				{
 -					LLFace* face = drawablep->getFace(i);
 -					LLVertexBuffer* buff = face->getVertexBuffer();
 -					if (face && buff && buff->isLocked())
 -					{
 -						buff->setBuffer(0) ;
 -					}
 -				}
 -			} 
 -		}
 -
 -		group->clearState(LLSpatialGroup::MESH_DIRTY | LLSpatialGroup::NEW_DRAWINFO);
 -	}
 -
 -	if (group && group->isState(LLSpatialGroup::NEW_DRAWINFO))
 -	{
 -		llerrs << "WTF?" << llendl;
 -	}
 -}
 -
 -void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::vector<LLFace*>& faces, BOOL distance_sort)
 -{
 -	//calculate maximum number of vertices to store in a single buffer
 -	U32 max_vertices = (gSavedSettings.getS32("RenderMaxVBOSize")*1024)/LLVertexBuffer::calcVertexSize(group->mSpatialPartition->mVertexDataMask);
 -	max_vertices = llmin(max_vertices, (U32) 65535);
 -
 -	if (!distance_sort)
 -	{
 -		//sort faces by things that break batches
 -		std::sort(faces.begin(), faces.end(), LLFace::CompareBatchBreaker());
 -	}
 -	else
 -	{
 -		//sort faces by distance
 -		std::sort(faces.begin(), faces.end(), LLFace::CompareDistanceGreater());
 -	}
 -				
 -	std::vector<LLFace*>::iterator face_iter = faces.begin();
 -	
 -	LLSpatialGroup::buffer_map_t buffer_map;
 -
 -	LLViewerTexture* last_tex = NULL;
 -	S32 buffer_index = 0;
 -
 -	if (distance_sort)
 -	{
 -		buffer_index = -1;
 -	}
 -
 -	while (face_iter != faces.end())
 -	{
 -		//pull off next face
 -		LLFace* facep = *face_iter;
 -		LLViewerTexture* tex = facep->getTexture();
 -
 -		if (distance_sort)
 -		{
 -			tex = NULL;
 -		}
 -
 -		if (last_tex == tex)
 -		{
 -			buffer_index++;
 -		}
 -		else
 -		{
 -			last_tex = tex;
 -			buffer_index = 0;
 -		}
 -
 -		bool bake_sunlight = LLPipeline::sBakeSunlight && facep->getDrawable()->isStatic(); 
 -
 -		U32 index_count = facep->getIndicesCount();
 -		U32 geom_count = facep->getGeomCount();
 -
 -		//sum up vertices needed for this render batch
 -		std::vector<LLFace*>::iterator i = face_iter;
 -		++i;
 -		
 -		while (i != faces.end() && 
 -			(LLPipeline::sTextureBindTest || (distance_sort || (*i)->getTexture() == tex)))
 -		{
 -			facep = *i;
 -			
 -			if (geom_count + facep->getGeomCount() > max_vertices)
 -			{ //cut batches on geom count too big
 -				break;
 -			}
 -
 -			++i;
 -			index_count += facep->getIndicesCount();
 -			geom_count += facep->getGeomCount();
 -		}
 -	
 -		//create/delete/resize vertex buffer if needed
 -		LLVertexBuffer* buffer = NULL;
 -		LLSpatialGroup::buffer_texture_map_t::iterator found_iter = group->mBufferMap[mask].find(tex);
 -		
 -		if (found_iter != group->mBufferMap[mask].end())
 -		{
 -			if ((U32) buffer_index < found_iter->second.size())
 -			{
 -				buffer = found_iter->second[buffer_index];
 -			}
 -		}
 -						
 -		if (!buffer)
 -		{ //create new buffer if needed
 -			buffer = createVertexBuffer(mask, 
 -											group->mBufferUsage);
 -			buffer->allocateBuffer(geom_count, index_count, TRUE);
 -		}
 -		else 
 -		{ //resize pre-existing buffer
 -			if (LLVertexBuffer::sEnableVBOs && buffer->getUsage() != group->mBufferUsage ||
 -				buffer->getTypeMask() != mask)
 -			{
 -				buffer = createVertexBuffer(mask, 
 -											group->mBufferUsage);
 -				buffer->allocateBuffer(geom_count, index_count, TRUE);
 -			}
 -			else
 -			{
 -				buffer->resizeBuffer(geom_count, index_count);
 -			}
 -		}
 -
 -		buffer_map[mask][tex].push_back(buffer);
 -
 -		//add face geometry
 -
 -		U32 indices_index = 0;
 -		U16 index_offset = 0;
 -
 -		while (face_iter < i)
 -		{ //update face indices for new buffer
 -			facep = *face_iter;
 -			facep->setIndicesIndex(indices_index);
 -			facep->setGeomIndex(index_offset);
 -			facep->setVertexBuffer(buffer);	
 -			
 -			{
 -				//for debugging, set last time face was updated vs moved
 -				facep->updateRebuildFlags();
 -
 -				if (!LLPipeline::sDelayVBUpdate)
 -				{ //copy face geometry into vertex buffer
 -					LLDrawable* drawablep = facep->getDrawable();
 -					LLVOVolume* vobj = drawablep->getVOVolume();
 -					LLVolume* volume = vobj->getVolume();
 -
 -					U32 te_idx = facep->getTEOffset();
 -
 -					if (facep->getGeometryVolume(*volume, te_idx, 
 -						vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), index_offset))
 -					{
 -						buffer->markDirty(facep->getGeomIndex(), facep->getGeomCount(), 
 -							facep->getIndicesStart(), facep->getIndicesCount());
 -					}
 -				}
 -			}
 -
 -			index_offset += facep->getGeomCount();
 -			indices_index += facep->getIndicesCount();
 -
 -
 -			//append face to appropriate render batch
 -
 -			BOOL force_simple = facep->getPixelArea() < FORCE_SIMPLE_RENDER_AREA;
 -			BOOL fullbright = facep->isState(LLFace::FULLBRIGHT);
 -			if ((mask & LLVertexBuffer::MAP_NORMAL) == 0)
 -			{ //paranoia check to make sure GL doesn't try to read non-existant normals
 -				fullbright = TRUE;
 -			}
 -
 -			const LLTextureEntry* te = facep->getTextureEntry();
 -
 -			BOOL is_alpha = (facep->getPoolType() == LLDrawPool::POOL_ALPHA) ? TRUE : FALSE;
 -		
 -			if (is_alpha)
 -			{
 -				// can we safely treat this as an alpha mask?
 -				if (facep->canRenderAsMask())
 -				{
 -					if (te->getFullbright() || LLPipeline::sNoAlpha)
 -					{
 -						registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK);
 -					}
 -					else
 -					{
 -						registerFace(group, facep, LLRenderPass::PASS_ALPHA_MASK);
 -					}
 -				}
 -				else
 -				{
 -					registerFace(group, facep, LLRenderPass::PASS_ALPHA);
 -				}
 -
 -				if (LLPipeline::sRenderDeferred)
 -				{
 -					registerFace(group, facep, LLRenderPass::PASS_ALPHA_SHADOW);
 -				}
 -			}
 -			else if (gPipeline.canUseVertexShaders()
 -				&& group->mSpatialPartition->mPartitionType != LLViewerRegion::PARTITION_HUD 
 -				&& LLPipeline::sRenderBump 
 -				&& te->getShiny())
 -			{ //shiny
 -				if (tex->getPrimaryFormat() == GL_ALPHA)
 -				{ //invisiprim+shiny
 -					registerFace(group, facep, LLRenderPass::PASS_INVISI_SHINY);
 -					registerFace(group, facep, LLRenderPass::PASS_INVISIBLE);
 -				}
 -				else if (LLPipeline::sRenderDeferred)
 -				{ //deferred rendering
 -					if (te->getFullbright())
 -					{ //register in post deferred fullbright shiny pass
 -						registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT_SHINY);
 -						if (te->getBumpmap())
 -						{ //register in post deferred bump pass
 -							registerFace(group, facep, LLRenderPass::PASS_POST_BUMP);
 -						}
 -					}
 -					else if (te->getBumpmap())
 -					{ //register in deferred bump pass
 -						registerFace(group, facep, LLRenderPass::PASS_BUMP);
 -					}
 -					else
 -					{ //register in deferred simple pass (deferred simple includes shiny)
 -						llassert(mask & LLVertexBuffer::MAP_NORMAL);
 -						registerFace(group, facep, LLRenderPass::PASS_SIMPLE);
 -					}
 -				}
 -				else if (fullbright)
 -				{	//not deferred, register in standard fullbright shiny pass					
 -					registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT_SHINY);
 -				}
 -				else
 -				{ //not deferred or fullbright, register in standard shiny pass
 -					registerFace(group, facep, LLRenderPass::PASS_SHINY);
 -				}
 -			}
 -			else
 -			{ //not alpha and not shiny
 -				if (!is_alpha && tex->getPrimaryFormat() == GL_ALPHA)
 -				{ //invisiprim
 -					registerFace(group, facep, LLRenderPass::PASS_INVISIBLE);
 -				}
 -				else if (fullbright || bake_sunlight)
 -				{ //fullbright
 -					registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT);
 -					if (LLPipeline::sRenderDeferred && LLPipeline::sRenderBump && te->getBumpmap())
 -					{ //if this is the deferred render and a bump map is present, register in post deferred bump
 -						registerFace(group, facep, LLRenderPass::PASS_POST_BUMP);
 -					}
 -				}
 -				else
 -				{
 -					if (LLPipeline::sRenderDeferred && LLPipeline::sRenderBump && te->getBumpmap())
 -					{ //non-shiny or fullbright deferred bump
 -						registerFace(group, facep, LLRenderPass::PASS_BUMP);
 -					}
 -					else
 -					{ //all around simple
 -						llassert(mask & LLVertexBuffer::MAP_NORMAL);
 -						registerFace(group, facep, LLRenderPass::PASS_SIMPLE);
 -					}
 -				}
 -				
 -				//not sure why this is here -- shiny HUD attachments maybe?  -- davep 5/11/2010
 -				if (!is_alpha && te->getShiny() && LLPipeline::sRenderBump)
 -				{
 -					registerFace(group, facep, LLRenderPass::PASS_SHINY);
 -				}
 -			}
 -			
 -			//not sure why this is here, and looks like it might cause bump mapped objects to get rendered redundantly -- davep 5/11/2010
 -			if (!is_alpha && !LLPipeline::sRenderDeferred)
 -			{
 -				llassert((mask & LLVertexBuffer::MAP_NORMAL) || fullbright);
 -				facep->setPoolType((fullbright) ? LLDrawPool::POOL_FULLBRIGHT : LLDrawPool::POOL_SIMPLE);
 -				
 -				if (!force_simple && te->getBumpmap() && LLPipeline::sRenderBump)
 -				{
 -					registerFace(group, facep, LLRenderPass::PASS_BUMP);
 -				}
 -			}
 -
 -			if (!is_alpha && LLPipeline::sRenderGlow && te->getGlow() > 0.f)
 -			{
 -				registerFace(group, facep, LLRenderPass::PASS_GLOW);
 -			}
 -						
 -			++face_iter;
 -		}
 -
 -		buffer->setBuffer(0);
 -	}
 -
 -	group->mBufferMap[mask].clear();
 -	for (LLSpatialGroup::buffer_texture_map_t::iterator i = buffer_map[mask].begin(); i != buffer_map[mask].end(); ++i)
 -	{
 -		group->mBufferMap[mask][i->first] = i->second;
 -	}
 -}
 -
 -void LLGeometryManager::addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32 &index_count)
 -{	
 -	//initialize to default usage for this partition
 -	U32 usage = group->mSpatialPartition->mBufferUsage;
 -	
 -	//clear off any old faces
 -	mFaceList.clear();
 -
 -	//for each drawable
 -	for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter)
 -	{
 -		LLDrawable* drawablep = *drawable_iter;
 -		
 -		if (drawablep->isDead())
 -		{
 -			continue;
 -		}
 -	
 -		if (drawablep->isAnimating())
 -		{ //fall back to stream draw for animating verts
 -			usage = GL_STREAM_DRAW_ARB;
 -		}
 -
 -		//for each face
 -		for (S32 i = 0; i < drawablep->getNumFaces(); i++)
 -		{
 -			//sum up face verts and indices
 -			drawablep->updateFaceSize(i);
 -			LLFace* facep = drawablep->getFace(i);
 -			if (facep->hasGeometry() && facep->getPixelArea() > FORCE_CULL_AREA)
 -			{
 -				vertex_count += facep->getGeomCount();
 -				index_count += facep->getIndicesCount();
 -
 -				//remember face (for sorting)
 -				mFaceList.push_back(facep);
 -			}
 -			else
 -			{
 -				facep->clearVertexBuffer();
 -			}
 -		}
 -	}
 -	
 -	group->mBufferUsage = usage;
 -}
 -
 -LLHUDPartition::LLHUDPartition()
 -{
 -	mPartitionType = LLViewerRegion::PARTITION_HUD;
 -	mDrawableType = LLPipeline::RENDER_TYPE_HUD;
 -	mSlopRatio = 0.f;
 -	mLODPeriod = 1;
 -}
 -
 -void LLHUDPartition::shift(const LLVector4a &offset)
 -{
 -	//HUD objects don't shift with region crossing.  That would be silly.
 -}
 -
 -
 +		LLPrimitive::getVolumeManager()->unrefVolume(ref); +	} +	else +	{ //default sculpts have a constant number of triangles +		ret = 31*2*31;  //31 rows of 31 columns of quads for a 32x32 vertex patch +	} + +	return ret; +} + +//static +void LLVOVolume::preUpdateGeom() +{ +	sNumLODChanges = 0; +} + +void LLVOVolume::parameterChanged(U16 param_type, bool local_origin) +{ +	LLViewerObject::parameterChanged(param_type, local_origin); +} + +void LLVOVolume::parameterChanged(U16 param_type, LLNetworkData* data, BOOL in_use, bool local_origin) +{ +	LLViewerObject::parameterChanged(param_type, data, in_use, local_origin); +	if (mVolumeImpl) +	{ +		mVolumeImpl->onParameterChanged(param_type, data, in_use, local_origin); +	} +	if (mDrawable.notNull()) +	{ +		BOOL is_light = getIsLight(); +		if (is_light != mDrawable->isState(LLDrawable::LIGHT)) +		{ +			gPipeline.setLight(mDrawable, is_light); +		} +	} +} + +void LLVOVolume::setSelected(BOOL sel) +{ +	LLViewerObject::setSelected(sel); +	if (mDrawable.notNull()) +	{ +		markForUpdate(TRUE); +	} +} + +void LLVOVolume::updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) +{		 +} + +F32 LLVOVolume::getBinRadius() +{ +	F32 radius; +	 +	F32 scale = 1.f; + +	const LLVector4a* ext = mDrawable->getSpatialExtents(); +	 +	BOOL shrink_wrap = mDrawable->isAnimating(); +	BOOL alpha_wrap = FALSE; + +	if (!isHUDAttachment()) +	{ +		for (S32 i = 0; i < mDrawable->getNumFaces(); i++) +		{ +			LLFace* face = mDrawable->getFace(i); +			if (face->getPoolType() == LLDrawPool::POOL_ALPHA && +			    !face->canRenderAsMask()) +			{ +				alpha_wrap = TRUE; +				break; +			} +		} +	} +	else +	{ +		shrink_wrap = FALSE; +	} + +	if (alpha_wrap) +	{ +		LLVector3 bounds = getScale(); +		radius = llmin(bounds.mV[1], bounds.mV[2]); +		radius = llmin(radius, bounds.mV[0]); +		radius *= 0.5f; +	} +	else if (shrink_wrap) +	{ +		LLVector4a rad; +		rad.setSub(ext[1], ext[0]); +		 +		radius = rad.getLength3().getF32()*0.5f; +	} +	else if (mDrawable->isStatic()) +	{ +		/*if (mDrawable->getRadius() < 2.0f) +		{ +			radius = 16.f; +		} +		else +		{ +			radius = llmax(mDrawable->getRadius(), 32.f); +		}*/ + +		radius = (((S32) mDrawable->getRadius())/2+1)*8; +	} +	else if (mDrawable->getVObj()->isAttachment()) +	{ +		radius = (((S32) (mDrawable->getRadius()*4)+1))*2; +	} +	else +	{ +		radius = 8.f; +	} + +	return llclamp(radius*scale, 0.5f, 256.f); +} + +const LLVector3 LLVOVolume::getPivotPositionAgent() const +{ +	if (mVolumeImpl) +	{ +		return mVolumeImpl->getPivotPosition(); +	} +	return LLViewerObject::getPivotPositionAgent(); +} + +void LLVOVolume::onShift(const LLVector4a &shift_vector) +{ +	if (mVolumeImpl) +	{ +		mVolumeImpl->onShift(shift_vector); +	} + +	updateRelativeXform(); +} + +const LLMatrix4& LLVOVolume::getWorldMatrix(LLXformMatrix* xform) const +{ +	if (mVolumeImpl) +	{ +		return mVolumeImpl->getWorldMatrix(xform); +	} +	return xform->getWorldMatrix(); +} + +LLVector3 LLVOVolume::agentPositionToVolume(const LLVector3& pos) const +{ +	LLVector3 ret = pos - getRenderPosition(); +	ret = ret * ~getRenderRotation(); +	LLVector3 objScale = isVolumeGlobal() ? LLVector3(1,1,1) : getScale(); +	LLVector3 invObjScale(1.f / objScale.mV[VX], 1.f / objScale.mV[VY], 1.f / objScale.mV[VZ]); +	ret.scaleVec(invObjScale); +	 +	return ret; +} + +LLVector3 LLVOVolume::agentDirectionToVolume(const LLVector3& dir) const +{ +	LLVector3 ret = dir * ~getRenderRotation(); +	 +	LLVector3 objScale = isVolumeGlobal() ? LLVector3(1,1,1) : getScale(); +	ret.scaleVec(objScale); + +	return ret; +} + +LLVector3 LLVOVolume::volumePositionToAgent(const LLVector3& dir) const +{ +	LLVector3 ret = dir; +	LLVector3 objScale = isVolumeGlobal() ? LLVector3(1,1,1) : getScale(); +	ret.scaleVec(objScale); +	ret = ret * getRenderRotation(); +	ret += getRenderPosition(); +	 +	return ret; +} + +LLVector3 LLVOVolume::volumeDirectionToAgent(const LLVector3& dir) const +{ +	LLVector3 ret = dir; +	LLVector3 objScale = isVolumeGlobal() ? LLVector3(1,1,1) : getScale(); +	LLVector3 invObjScale(1.f / objScale.mV[VX], 1.f / objScale.mV[VY], 1.f / objScale.mV[VZ]); +	ret.scaleVec(invObjScale); +	ret = ret * getRenderRotation(); + +	return ret; +} + + +BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, S32 face, BOOL pick_transparent, S32 *face_hitp, +									  LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal) +	 +{ +	if (!mbCanSelect  +		|| mDrawable->isDead()  +		|| !gPipeline.hasRenderType(mDrawable->getRenderType())) +	{ +		return FALSE; +	} + +	BOOL ret = FALSE; + +	LLVolume* volume = getVolume(); + +	bool transform = true; + +	if (mDrawable->isState(LLDrawable::RIGGED)) +	{ +		if (LLFloater::isVisible(gFloaterTools) && getAvatar()->isSelf()) +		{ +			gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_RIGGED, TRUE); +			volume = mRiggedVolume; +			transform = false; +		} +		else +		{ //cannot pick rigged attachments on other avatars or when not in build mode +			return FALSE; +		} +	} +	 +	if (volume) +	{	 +		LLVector3 v_start, v_end, v_dir; +	 +		if (transform) +		{ +			v_start = agentPositionToVolume(start); +			v_end = agentPositionToVolume(end); +		} +		else +		{ +			v_start = start; +			v_end = end; +		} +		 +		LLVector3 p; +		LLVector3 n; +		LLVector2 tc; +		LLVector3 bn; + +		if (intersection != NULL) +		{ +			p = *intersection; +		} + +		if (tex_coord != NULL) +		{ +			tc = *tex_coord; +		} + +		if (normal != NULL) +		{ +			n = *normal; +		} + +		if (bi_normal != NULL) +		{ +			bn = *bi_normal; +		} + +		S32 face_hit = -1; + +		S32 start_face, end_face; +		if (face == -1) +		{ +			start_face = 0; +			end_face = volume->getNumVolumeFaces(); +		} +		else +		{ +			start_face = face; +			end_face = face+1; +		} + +		bool special_cursor = specialHoverCursor(); +		for (S32 i = start_face; i < end_face; ++i) +		{ +			if (!special_cursor && !pick_transparent && getTE(i)->getColor().mV[3] == 0.f) +			{ //don't attempt to pick completely transparent faces unless +				//pick_transparent is true +				continue; +			} + +			face_hit = volume->lineSegmentIntersect(v_start, v_end, i, +													&p, &tc, &n, &bn); +			 +			if (face_hit >= 0 && mDrawable->getNumFaces() > face_hit) +			{ +				LLFace* face = mDrawable->getFace(face_hit);				 + +				if (pick_transparent || !face->getTexture() || !face->getTexture()->hasGLTexture() || face->getTexture()->getMask(face->surfaceToTexture(tc, p, n))) +				{ +					v_end = p; +					if (face_hitp != NULL) +					{ +						*face_hitp = face_hit; +					} +					 +					if (intersection != NULL) +					{ +						if (transform) +						{ +							*intersection = volumePositionToAgent(p);  // must map back to agent space +						} +						else +						{ +							*intersection = p; +						} +					} + +					if (normal != NULL) +					{ +						if (transform) +						{ +							*normal = volumeDirectionToAgent(n); +						} +						else +						{ +							*normal = n; +						} + +						(*normal).normVec(); +					} + +					if (bi_normal != NULL) +					{ +						if (transform) +						{ +							*bi_normal = volumeDirectionToAgent(bn); +						} +						else +						{ +							*bi_normal = bn; +						} +						(*bi_normal).normVec(); +					} + +					if (tex_coord != NULL) +					{ +						*tex_coord = tc; +					} +					 +					ret = TRUE; +				} +			} +		} +	} +		 +	return ret; +} + +bool LLVOVolume::treatAsRigged() +{ +	return LLFloater::isVisible(gFloaterTools) &&  +			isAttachment() &&  +			getAvatar() && +			getAvatar()->isSelf() && +			mDrawable.notNull() && +			mDrawable->isState(LLDrawable::RIGGED); +} + +LLRiggedVolume* LLVOVolume::getRiggedVolume() +{ +	return mRiggedVolume; +} + +void LLVOVolume::clearRiggedVolume() +{ +	if (mRiggedVolume.notNull()) +	{ +		mRiggedVolume = NULL; +		updateRelativeXform(); +	} +} + +void LLVOVolume::updateRiggedVolume() +{ +	//Update mRiggedVolume to match current animation frame of avatar.  +	//Also update position/size in octree.   + +	if (!treatAsRigged()) +	{ +		clearRiggedVolume(); +		 +		return; +	} + +	LLVolume* volume = getVolume(); + +	const LLMeshSkinInfo* skin = gMeshRepo.getSkinInfo(volume->getParams().getSculptID()); + +	if (!skin) +	{ +		clearRiggedVolume(); +		return; +	} + +	LLVOAvatar* avatar = getAvatar(); + +	if (!avatar) +	{ +		clearRiggedVolume(); +		return; +	} + +	if (!mRiggedVolume) +	{ +		LLVolumeParams p; +		mRiggedVolume = new LLRiggedVolume(p); +		updateRelativeXform(); +	} + +	mRiggedVolume->update(skin, avatar, volume); + +} + +static LLFastTimer::DeclareTimer FTM_SKIN_RIGGED("Skin"); +static LLFastTimer::DeclareTimer FTM_RIGGED_OCTREE("Octree"); + +void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, const LLVolume* volume) +{ +	bool copy = false; +	if (volume->getNumVolumeFaces() != getNumVolumeFaces()) +	{  +		copy = true; +	} + +	for (S32 i = 0; i < volume->getNumVolumeFaces() && !copy; ++i) +	{ +		const LLVolumeFace& src_face = volume->getVolumeFace(i); +		const LLVolumeFace& dst_face = getVolumeFace(i); + +		if (src_face.mNumIndices != dst_face.mNumIndices || +			src_face.mNumVertices != dst_face.mNumVertices) +		{ +			copy = true; +		} +	} + +	if (copy) +	{ +		copyVolumeFaces(volume);	 +	} + +	//build matrix palette +	LLMatrix4a mp[64]; +	LLMatrix4* mat = (LLMatrix4*) mp; +	 +	for (U32 j = 0; j < skin->mJointNames.size(); ++j) +	{ +		LLJoint* joint = avatar->getJoint(skin->mJointNames[j]); +		if (joint) +		{ +			mat[j] = skin->mInvBindMatrix[j]; +			mat[j] *= joint->getWorldMatrix(); +		} +	} + +	for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i) +	{ +		const LLVolumeFace& vol_face = volume->getVolumeFace(i); +		 +		LLVolumeFace& dst_face = mVolumeFaces[i]; +		 +		LLVector4a* weight = vol_face.mWeights; + +		LLMatrix4a bind_shape_matrix; +		bind_shape_matrix.loadu(skin->mBindShapeMatrix); + +		LLVector4a* pos = dst_face.mPositions; + +		{ +			LLFastTimer t(FTM_SKIN_RIGGED); + +			for (U32 j = 0; j < dst_face.mNumVertices; ++j) +			{ +				LLMatrix4a final_mat; +				final_mat.clear(); + +				S32 idx[4]; + +				LLVector4 wght; + +				F32 scale = 0.f; +				for (U32 k = 0; k < 4; k++) +				{ +					F32 w = weight[j][k]; + +					idx[k] = (S32) floorf(w); +					wght[k] = w - floorf(w); +					scale += wght[k]; +				} + +				wght *= 1.f/scale; + +				for (U32 k = 0; k < 4; k++) +				{ +					F32 w = wght[k]; + +					LLMatrix4a src; +					src.setMul(mp[idx[k]], w); + +					final_mat.add(src); +				} + +				 +				LLVector4a& v = vol_face.mPositions[j]; +				LLVector4a t; +				LLVector4a dst; +				bind_shape_matrix.affineTransform(v, t); +				final_mat.affineTransform(t, dst); +				pos[j] = dst; +			} + +			//update bounding box +			LLVector4a& min = dst_face.mExtents[0]; +			LLVector4a& max = dst_face.mExtents[1]; + +			min = pos[0]; +			max = pos[1]; + +			for (U32 j = 1; j < dst_face.mNumVertices; ++j) +			{ +				min.setMin(min, pos[j]); +				max.setMax(max, pos[j]); +			} + +			dst_face.mCenter->setAdd(dst_face.mExtents[0], dst_face.mExtents[1]); +			dst_face.mCenter->mul(0.5f); + +		} + +		{ +			LLFastTimer t(FTM_RIGGED_OCTREE); +			delete dst_face.mOctree; +			dst_face.mOctree = NULL; + +			LLVector4a size; +			size.setSub(dst_face.mExtents[1], dst_face.mExtents[0]); +			size.splat(size.getLength3().getF32()*0.5f); +			 +			dst_face.createOctree(1.f); +		} +	} +} + +U32 LLVOVolume::getPartitionType() const +{ +	if (isHUDAttachment()) +	{ +		return LLViewerRegion::PARTITION_HUD; +	} + +	return LLViewerRegion::PARTITION_VOLUME; +} + +LLVolumePartition::LLVolumePartition() +: LLSpatialPartition(LLVOVolume::VERTEX_DATA_MASK, TRUE, GL_DYNAMIC_DRAW_ARB) +{ +	mLODPeriod = 32; +	mDepthMask = FALSE; +	mDrawableType = LLPipeline::RENDER_TYPE_VOLUME; +	mPartitionType = LLViewerRegion::PARTITION_VOLUME; +	mSlopRatio = 0.25f; +	mBufferUsage = GL_DYNAMIC_DRAW_ARB; +} + +LLVolumeBridge::LLVolumeBridge(LLDrawable* drawablep) +: LLSpatialBridge(drawablep, TRUE, LLVOVolume::VERTEX_DATA_MASK) +{ +	mDepthMask = FALSE; +	mLODPeriod = 32; +	mDrawableType = LLPipeline::RENDER_TYPE_VOLUME; +	mPartitionType = LLViewerRegion::PARTITION_BRIDGE; +	 +	mBufferUsage = GL_DYNAMIC_DRAW_ARB; + +	mSlopRatio = 0.25f; +} + +void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, U32 type) +{ +	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); + +	if (facep->getViewerObject()->isSelected() && LLSelectMgr::getInstance()->mHideSelectedObjects) +	{ +		return; +	} + +	//add face to drawmap +	LLSpatialGroup::drawmap_elem_t& draw_vec = group->mDrawMap[type];	 + +	S32 idx = draw_vec.size()-1; + +	BOOL fullbright = (type == LLRenderPass::PASS_FULLBRIGHT) || +		(type == LLRenderPass::PASS_INVISIBLE) || +		(type == LLRenderPass::PASS_ALPHA && facep->isState(LLFace::FULLBRIGHT)); +	 +	if (!fullbright && type != LLRenderPass::PASS_GLOW && !facep->getVertexBuffer()->hasDataType(LLVertexBuffer::TYPE_NORMAL)) +	{ +		llwarns << "Non fullbright face has no normals!" << llendl; +		return; +	} + +	const LLMatrix4* tex_mat = NULL; +	if (facep->isState(LLFace::TEXTURE_ANIM) && facep->getVirtualSize() > MIN_TEX_ANIM_SIZE) +	{ +		tex_mat = facep->mTextureMatrix;	 +	} + +	const LLMatrix4* model_mat = NULL; + +	LLDrawable* drawable = facep->getDrawable(); +	if (drawable->isActive()) +	{ +		model_mat = &(drawable->getRenderMatrix()); +	} +	else +	{ +		model_mat = &(drawable->getRegion()->mRenderMatrix); +		if (model_mat->isIdentity()) +		{ +			model_mat = NULL; +		} +	} + +	U8 bump = (type == LLRenderPass::PASS_BUMP || type == LLRenderPass::PASS_POST_BUMP) ? facep->getTextureEntry()->getBumpmap() : 0; +	 +	LLViewerTexture* tex = facep->getTexture(); + +	U8 glow = (U8) (facep->getTextureEntry()->getGlow() * 255); + +	if (idx >= 0 &&  +		draw_vec[idx]->mVertexBuffer == facep->getVertexBuffer() && +		draw_vec[idx]->mEnd == facep->getGeomIndex()-1 && +		(LLPipeline::sTextureBindTest || draw_vec[idx]->mTexture == tex) && +#if LL_DARWIN +		draw_vec[idx]->mEnd - draw_vec[idx]->mStart + facep->getGeomCount() <= (U32) gGLManager.mGLMaxVertexRange && +		draw_vec[idx]->mCount + facep->getIndicesCount() <= (U32) gGLManager.mGLMaxIndexRange && +#endif +		draw_vec[idx]->mGlowColor.mV[3] == glow && +		draw_vec[idx]->mFullbright == fullbright && +		draw_vec[idx]->mBump == bump && +		draw_vec[idx]->mTextureMatrix == tex_mat && +		draw_vec[idx]->mModelMatrix == model_mat) +	{ +		draw_vec[idx]->mCount += facep->getIndicesCount(); +		draw_vec[idx]->mEnd += facep->getGeomCount(); +		draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, facep->getVirtualSize()); +		draw_vec[idx]->validate(); +		update_min_max(draw_vec[idx]->mExtents[0], draw_vec[idx]->mExtents[1], facep->mExtents[0]); +		update_min_max(draw_vec[idx]->mExtents[0], draw_vec[idx]->mExtents[1], facep->mExtents[1]); +	} +	else +	{ +		U32 start = facep->getGeomIndex(); +		U32 end = start + facep->getGeomCount()-1; +		U32 offset = facep->getIndicesStart(); +		U32 count = facep->getIndicesCount(); +		LLPointer<LLDrawInfo> draw_info = new LLDrawInfo(start,end,count,offset, tex,  +			facep->getVertexBuffer(), fullbright, bump);  +		draw_info->mGroup = group; +		draw_info->mVSize = facep->getVirtualSize(); +		draw_vec.push_back(draw_info); +		draw_info->mTextureMatrix = tex_mat; +		draw_info->mModelMatrix = model_mat; +		draw_info->mGlowColor.setVec(0,0,0,glow); +		if (type == LLRenderPass::PASS_ALPHA) +		{ //for alpha sorting +			facep->setDrawInfo(draw_info); +		} +		draw_info->mExtents[0] = facep->mExtents[0]; +		draw_info->mExtents[1] = facep->mExtents[1]; + +		if (LLPipeline::sUseTriStrips) +		{ +			draw_info->mDrawMode = LLRender::TRIANGLE_STRIP; +		} + +		draw_info->validate(); +	} +} + +void LLVolumeGeometryManager::getGeometry(LLSpatialGroup* group) +{ + +} + +static LLFastTimer::DeclareTimer FTM_REBUILD_VOLUME_VB("Volume"); +static LLFastTimer::DeclareTimer FTM_REBUILD_VBO("VBO Rebuilt"); + +static LLDrawPoolAvatar* get_avatar_drawpool(LLViewerObject* vobj) +{ +	LLVOAvatar* avatar = vobj->getAvatar(); +					 +	if (avatar) +	{ +		LLDrawable* drawable = avatar->mDrawable; +		if (drawable && drawable->getNumFaces() > 0) +		{ +			LLFace* face = drawable->getFace(0); +			if (face) +			{ +				LLDrawPool* drawpool = face->getPool(); +				if (drawpool) +				{ +					if (drawpool->getType() == LLDrawPool::POOL_AVATAR) +					{ +						return (LLDrawPoolAvatar*) drawpool; +					} +				} +			} +		} +	} + +	return NULL; +} + +void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) +{ +	if (group->changeLOD()) +	{ +		group->mLastUpdateDistance = group->mDistance; +	} + +	group->mLastUpdateViewAngle = group->mViewAngle; + +	if (!group->isState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::ALPHA_DIRTY)) +	{ +		if (group->isState(LLSpatialGroup::MESH_DIRTY) && !LLPipeline::sDelayVBUpdate) +		{ +			LLFastTimer ftm(FTM_REBUILD_VBO);	 +			LLFastTimer ftm2(FTM_REBUILD_VOLUME_VB); +		 +			rebuildMesh(group); +		} +		return; +	} + +	group->mBuilt = 1.f; +	LLFastTimer ftm(FTM_REBUILD_VBO);	 + +	LLFastTimer ftm2(FTM_REBUILD_VOLUME_VB); + +	group->clearDrawMap(); + +	mFaceList.clear(); + +	std::vector<LLFace*> fullbright_faces; +	std::vector<LLFace*> bump_faces; +	std::vector<LLFace*> simple_faces; + +	std::vector<LLFace*> alpha_faces; +	U32 useage = group->mSpatialPartition->mBufferUsage; + +	U32 max_vertices = (gSavedSettings.getS32("RenderMaxVBOSize")*1024)/LLVertexBuffer::calcVertexSize(group->mSpatialPartition->mVertexDataMask); +	U32 max_total = (gSavedSettings.getS32("RenderMaxNodeSize")*1024)/LLVertexBuffer::calcVertexSize(group->mSpatialPartition->mVertexDataMask); +	max_vertices = llmin(max_vertices, (U32) 65535); + +	U32 cur_total = 0; + +	//get all the faces into a list +	for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter) +	{ +		LLDrawable* drawablep = *drawable_iter; +		 +		if (drawablep->isDead() || drawablep->isState(LLDrawable::FORCE_INVISIBLE) ) +		{ +			continue; +		} +	 +		if (drawablep->isAnimating()) +		{ //fall back to stream draw for animating verts +			useage = GL_STREAM_DRAW_ARB; +		} + +		LLVOVolume* vobj = drawablep->getVOVolume(); + +		if (vobj->getVolume() && vobj->getVolume()->isTetrahedron()) +		{ +			continue; +		} + +		llassert_always(vobj); +		vobj->updateTextureVirtualSize(); +		vobj->preRebuild(); + +		drawablep->clearState(LLDrawable::HAS_ALPHA); + +		bool rigged = vobj->isAttachment() &&  +					vobj->isMesh() &&  +					gMeshRepo.getSkinInfo(vobj->getVolume()->getParams().getSculptID()); + +		bool bake_sunlight = LLPipeline::sBakeSunlight && drawablep->isStatic(); + +		bool is_rigged = false; + +		//for each face +		for (S32 i = 0; i < drawablep->getNumFaces(); i++) +		{ +			LLFace* facep = drawablep->getFace(i); + +			//ALWAYS null out vertex buffer on rebuild -- if the face lands in a render +			// batch, it will recover its vertex buffer reference from the spatial group +			facep->setVertexBuffer(NULL); +			 +			//sum up face verts and indices +			drawablep->updateFaceSize(i); +			 +			 + +			if (rigged)  +			{ +				if (!facep->isState(LLFace::RIGGED)) +				{ //completely reset vertex buffer +					facep->clearVertexBuffer(); +				} +		 +				facep->setState(LLFace::RIGGED); +				is_rigged = true; +				 +				//get drawpool of avatar with rigged face +				LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj); +				 +				//Determine if we've received skininfo that contains an +				//alternate bind matrix - if it does then apply the translational component +				//to the joints of the avatar. +				LLVOAvatar* pAvatarVO = vobj->getAvatar(); +				bool pelvisGotSet = false; + +				if ( pAvatarVO ) +				{ +					LLUUID currentId = vobj->getVolume()->getParams().getSculptID(); +					const LLMeshSkinInfo*  pSkinData = gMeshRepo.getSkinInfo( currentId ); +					 +					if ( pSkinData ) +					{ +						const int bindCnt = pSkinData->mAlternateBindMatrix.size();								 +						if ( bindCnt > 0 ) +						{					 +							const int jointCnt = pSkinData->mJointNames.size(); +							const F32 pelvisZOffset = pSkinData->mPelvisOffset; +							bool fullRig = (jointCnt>=20) ? true : false; +							if ( fullRig ) +							{ +								for ( int i=0; i<jointCnt; ++i ) +								{ +									std::string lookingForJoint = pSkinData->mJointNames[i].c_str(); +									//llinfos<<"joint name "<<lookingForJoint.c_str()<<llendl; +									LLJoint* pJoint = pAvatarVO->getJoint( lookingForJoint ); +									if ( pJoint && pJoint->getId() != currentId ) +									{   									 +										pJoint->setId( currentId ); +										const LLVector3& jointPos = pSkinData->mAlternateBindMatrix[i].getTranslation();									 +										//Set the joint position +										pJoint->storeCurrentXform( jointPos );																																 +										//If joint is a pelvis then handle old/new pelvis to foot values +										if ( lookingForJoint == "mPelvis" ) +										{	 +											pJoint->storeCurrentXform( jointPos );																																 +											if ( !pAvatarVO->hasPelvisOffset() ) +											{										 +												pAvatarVO->setPelvisOffset( true, jointPos, pelvisZOffset ); +												//Trigger to rebuild viewer AV +												pelvisGotSet = true;											 +											}										 +										}										 +									} +								} +							}							 +						} +					} +				} +				//If we've set the pelvis to a new position we need to also rebuild some information that the +				//viewer does at launch (e.g. body size etc.) +				if ( pelvisGotSet ) +				{ +					pAvatarVO->postPelvisSetRecalc(); +				} + +				if (pool) +				{ +					const LLTextureEntry* te = facep->getTextureEntry(); + +					//remove face from old pool if it exists +					LLDrawPool* old_pool = facep->getPool(); +					if (old_pool && old_pool->getType() == LLDrawPool::POOL_AVATAR) +					{ +						((LLDrawPoolAvatar*) old_pool)->removeRiggedFace(facep); +					} + +					//add face to new pool +					LLViewerTexture* tex = facep->getTexture(); +					U32 type = gPipeline.getPoolTypeFromTE(te, tex); + +					if (type == LLDrawPool::POOL_ALPHA) +					{ +						if (te->getFullbright()) +						{ +							pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA); +						} +						else +						{ +							pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_ALPHA); +						} +					} +					else if (te->getShiny()) +					{ +						if (te->getFullbright()) +						{ +							pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY); +						} +						else +						{ +							if (LLPipeline::sRenderDeferred) +							{ +								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE); +							} +							else +							{ +								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SHINY); +							} +						} +					} +					else +					{ +						if (te->getFullbright()) +						{ +							pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT); +						} +						else +						{ +							pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE); +						} +					} + +					if (te->getGlow()) +					{ +						pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_GLOW); +					} + +					if (LLPipeline::sRenderDeferred) +					{ +						if (type != LLDrawPool::POOL_ALPHA && !te->getFullbright()) +						{ +							if (te->getBumpmap()) +							{ +								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_BUMP); +							} +							else +							{ +								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_SIMPLE); +							} +						} +					} +				} + +				continue; +			} +			else +			{ +				if (facep->isState(LLFace::RIGGED)) +				{ //face is not rigged but used to be, remove from rigged face pool +					LLDrawPoolAvatar* pool = (LLDrawPoolAvatar*) facep->getPool(); +					if (pool) +					{ +						pool->removeRiggedFace(facep); +					} +					facep->clearState(LLFace::RIGGED); +				} +			} + +			if (cur_total > max_total || facep->getIndicesCount() <= 0 || facep->getGeomCount() <= 0) +			{ +				facep->clearVertexBuffer(); +				continue; +			} + +			cur_total += facep->getGeomCount(); + +			if (facep->hasGeometry() && facep->getPixelArea() > FORCE_CULL_AREA) +			{ +				const LLTextureEntry* te = facep->getTextureEntry(); +				LLViewerTexture* tex = facep->getTexture(); + +				if (facep->isState(LLFace::TEXTURE_ANIM)) +				{ +					if (!vobj->mTexAnimMode) +					{ +						facep->clearState(LLFace::TEXTURE_ANIM); +					} +				} + +				BOOL force_simple = (facep->getPixelArea() < FORCE_SIMPLE_RENDER_AREA); +				U32 type = gPipeline.getPoolTypeFromTE(te, tex); +				if (type != LLDrawPool::POOL_ALPHA && force_simple) +				{ +					type = LLDrawPool::POOL_SIMPLE; +				} +				facep->setPoolType(type); + +				if (vobj->isHUDAttachment()) +				{ +					facep->setState(LLFace::FULLBRIGHT); +				} + +				if (vobj->mTextureAnimp && vobj->mTexAnimMode) +				{ +					if (vobj->mTextureAnimp->mFace <= -1) +					{ +						S32 face; +						for (face = 0; face < vobj->getNumTEs(); face++) +						{ +							drawablep->getFace(face)->setState(LLFace::TEXTURE_ANIM); +						} +					} +					else if (vobj->mTextureAnimp->mFace < vobj->getNumTEs()) +					{ +						drawablep->getFace(vobj->mTextureAnimp->mFace)->setState(LLFace::TEXTURE_ANIM); +					} +				} + +				if (type == LLDrawPool::POOL_ALPHA) +				{ +					if (facep->canRenderAsMask()) +					{ //can be treated as alpha mask +						simple_faces.push_back(facep); +					} +					else +					{ +						drawablep->setState(LLDrawable::HAS_ALPHA); +						alpha_faces.push_back(facep); +					} +				} +				else +				{ +					if (drawablep->isState(LLDrawable::REBUILD_VOLUME)) +					{ +						facep->mLastUpdateTime = gFrameTimeSeconds; +					} + +					if (gPipeline.canUseWindLightShadersOnObjects() +						&& LLPipeline::sRenderBump) +					{ +						if (te->getBumpmap()) +						{ //needs normal + binormal +							bump_faces.push_back(facep); +						} +						else if (te->getShiny() || !te->getFullbright()) +						{ //needs normal +							simple_faces.push_back(facep); +						} +						else  +						{ //doesn't need normal +							facep->setState(LLFace::FULLBRIGHT); +							fullbright_faces.push_back(facep); +						} +					} +					else +					{ +						if (te->getBumpmap() && LLPipeline::sRenderBump) +						{ //needs normal + binormal +							bump_faces.push_back(facep); +						} +						else if ((te->getShiny() && LLPipeline::sRenderBump) || +							!(te->getFullbright() || bake_sunlight)) +						{ //needs normal +							simple_faces.push_back(facep); +						} +						else  +						{ //doesn't need normal +							facep->setState(LLFace::FULLBRIGHT); +							fullbright_faces.push_back(facep); +						} +					} +				} +			} +			else +			{	//face has no renderable geometry +				facep->clearVertexBuffer(); +			}		 +		} + +		if (is_rigged) +		{ +			drawablep->setState(LLDrawable::RIGGED); +		} +		else +		{ +			drawablep->clearState(LLDrawable::RIGGED); +		} +	} + +	group->mBufferUsage = useage; + +	//PROCESS NON-ALPHA FACES +	U32 simple_mask = LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR; +	U32 alpha_mask = simple_mask | 0x80000000; //hack to give alpha verts their own VBO +	U32 bump_mask = LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR; +	U32 fullbright_mask = LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR; + +	if (LLPipeline::sRenderDeferred) +	{ +		bump_mask |= LLVertexBuffer::MAP_BINORMAL; +	} +	 +	genDrawInfo(group, simple_mask, simple_faces); +	genDrawInfo(group, bump_mask, bump_faces); +	genDrawInfo(group, fullbright_mask, fullbright_faces); +	genDrawInfo(group, alpha_mask, alpha_faces, TRUE); + +	if (!LLPipeline::sDelayVBUpdate) +	{ +		//drawables have been rebuilt, clear rebuild status +		for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter) +		{ +			LLDrawable* drawablep = *drawable_iter; +			drawablep->clearState(LLDrawable::REBUILD_ALL); +		} +	} + +	group->mLastUpdateTime = gFrameTimeSeconds; +	group->mBuilt = 1.f; +	group->clearState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::ALPHA_DIRTY); + +	if (LLPipeline::sDelayVBUpdate) +	{ +		group->setState(LLSpatialGroup::MESH_DIRTY | LLSpatialGroup::NEW_DRAWINFO); +	} + +	mFaceList.clear(); +} + +static LLFastTimer::DeclareTimer FTM_VOLUME_GEOM("Volume Geometry"); +static LLFastTimer::DeclareTimer FTM_VOLUME_GEOM_PARTIAL("Terse Rebuild"); + +void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) +{ +	llassert(group); +	if (group && group->isState(LLSpatialGroup::MESH_DIRTY) && !group->isState(LLSpatialGroup::GEOM_DIRTY)) +	{ +		LLFastTimer tm(FTM_VOLUME_GEOM); +		S32 num_mapped_veretx_buffer = LLVertexBuffer::sMappedCount ; + +		group->mBuilt = 1.f; +		 +		for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter) +		{ +			LLFastTimer t(FTM_VOLUME_GEOM_PARTIAL); +			LLDrawable* drawablep = *drawable_iter; + +			if (!drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) ) +			{ +				LLVOVolume* vobj = drawablep->getVOVolume(); +				vobj->preRebuild(); + +				LLVolume* volume = vobj->getVolume(); +				for (S32 i = 0; i < drawablep->getNumFaces(); ++i) +				{ +					LLFace* face = drawablep->getFace(i); +					if (face && face->getVertexBuffer()) +					{ +						face->getGeometryVolume(*volume, face->getTEOffset(),  +							vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), face->getGeomIndex()); +					} + +					if (!face) +					{ +						llerrs << "WTF?" << llendl; +					} +				} + +				drawablep->clearState(LLDrawable::REBUILD_ALL); +			} +		} +		 +		//unmap all the buffers +		for (LLSpatialGroup::buffer_map_t::iterator i = group->mBufferMap.begin(); i != group->mBufferMap.end(); ++i) +		{ +			LLSpatialGroup::buffer_texture_map_t& map = i->second; +			for (LLSpatialGroup::buffer_texture_map_t::iterator j = map.begin(); j != map.end(); ++j) +			{ +				LLSpatialGroup::buffer_list_t& list = j->second; +				for (LLSpatialGroup::buffer_list_t::iterator k = list.begin(); k != list.end(); ++k) +				{ +					LLVertexBuffer* buffer = *k; +					if (buffer->isLocked()) +					{ +						buffer->setBuffer(0); +					} +				} +			} +		} +		 +		// don't forget alpha +		if(group != NULL &&  +		   !group->mVertexBuffer.isNull() &&  +		   group->mVertexBuffer->isLocked()) +		{ +			group->mVertexBuffer->setBuffer(0); +		} + +		//if not all buffers are unmapped +		if(num_mapped_veretx_buffer != LLVertexBuffer::sMappedCount)  +		{ +			llwarns << "Not all mapped vertex buffers are unmapped!" << llendl ;  +			for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter) +			{ +				LLDrawable* drawablep = *drawable_iter; +				for (S32 i = 0; i < drawablep->getNumFaces(); ++i) +				{ +					LLFace* face = drawablep->getFace(i); +					LLVertexBuffer* buff = face->getVertexBuffer(); +					if (face && buff && buff->isLocked()) +					{ +						buff->setBuffer(0) ; +					} +				} +			}  +		} + +		group->clearState(LLSpatialGroup::MESH_DIRTY | LLSpatialGroup::NEW_DRAWINFO); +	} + +	if (group && group->isState(LLSpatialGroup::NEW_DRAWINFO)) +	{ +		llerrs << "WTF?" << llendl; +	} +} + +void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::vector<LLFace*>& faces, BOOL distance_sort) +{ +	//calculate maximum number of vertices to store in a single buffer +	U32 max_vertices = (gSavedSettings.getS32("RenderMaxVBOSize")*1024)/LLVertexBuffer::calcVertexSize(group->mSpatialPartition->mVertexDataMask); +	max_vertices = llmin(max_vertices, (U32) 65535); + +	if (!distance_sort) +	{ +		//sort faces by things that break batches +		std::sort(faces.begin(), faces.end(), LLFace::CompareBatchBreaker()); +	} +	else +	{ +		//sort faces by distance +		std::sort(faces.begin(), faces.end(), LLFace::CompareDistanceGreater()); +	} +				 +	std::vector<LLFace*>::iterator face_iter = faces.begin(); +	 +	LLSpatialGroup::buffer_map_t buffer_map; + +	LLViewerTexture* last_tex = NULL; +	S32 buffer_index = 0; + +	if (distance_sort) +	{ +		buffer_index = -1; +	} + +	while (face_iter != faces.end()) +	{ +		//pull off next face +		LLFace* facep = *face_iter; +		LLViewerTexture* tex = facep->getTexture(); + +		if (distance_sort) +		{ +			tex = NULL; +		} + +		if (last_tex == tex) +		{ +			buffer_index++; +		} +		else +		{ +			last_tex = tex; +			buffer_index = 0; +		} + +		bool bake_sunlight = LLPipeline::sBakeSunlight && facep->getDrawable()->isStatic();  + +		U32 index_count = facep->getIndicesCount(); +		U32 geom_count = facep->getGeomCount(); + +		//sum up vertices needed for this render batch +		std::vector<LLFace*>::iterator i = face_iter; +		++i; +		 +		while (i != faces.end() &&  +			(LLPipeline::sTextureBindTest || (distance_sort || (*i)->getTexture() == tex))) +		{ +			facep = *i; +			 +			if (geom_count + facep->getGeomCount() > max_vertices) +			{ //cut batches on geom count too big +				break; +			} + +			++i; +			index_count += facep->getIndicesCount(); +			geom_count += facep->getGeomCount(); +		} +	 +		//create/delete/resize vertex buffer if needed +		LLVertexBuffer* buffer = NULL; +		LLSpatialGroup::buffer_texture_map_t::iterator found_iter = group->mBufferMap[mask].find(tex); +		 +		if (found_iter != group->mBufferMap[mask].end()) +		{ +			if ((U32) buffer_index < found_iter->second.size()) +			{ +				buffer = found_iter->second[buffer_index]; +			} +		} +						 +		if (!buffer) +		{ //create new buffer if needed +			buffer = createVertexBuffer(mask,  +											group->mBufferUsage); +			buffer->allocateBuffer(geom_count, index_count, TRUE); +		} +		else  +		{ //resize pre-existing buffer +			if (LLVertexBuffer::sEnableVBOs && buffer->getUsage() != group->mBufferUsage || +				buffer->getTypeMask() != mask) +			{ +				buffer = createVertexBuffer(mask,  +											group->mBufferUsage); +				buffer->allocateBuffer(geom_count, index_count, TRUE); +			} +			else +			{ +				buffer->resizeBuffer(geom_count, index_count); +			} +		} + +		buffer_map[mask][tex].push_back(buffer); + +		//add face geometry + +		U32 indices_index = 0; +		U16 index_offset = 0; + +		while (face_iter < i) +		{ //update face indices for new buffer +			facep = *face_iter; +			facep->setIndicesIndex(indices_index); +			facep->setGeomIndex(index_offset); +			facep->setVertexBuffer(buffer);	 +			 +			{ +				//for debugging, set last time face was updated vs moved +				facep->updateRebuildFlags(); + +				if (!LLPipeline::sDelayVBUpdate) +				{ //copy face geometry into vertex buffer +					LLDrawable* drawablep = facep->getDrawable(); +					LLVOVolume* vobj = drawablep->getVOVolume(); +					LLVolume* volume = vobj->getVolume(); + +					U32 te_idx = facep->getTEOffset(); + +					if (facep->getGeometryVolume(*volume, te_idx,  +						vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), index_offset)) +					{ +						buffer->markDirty(facep->getGeomIndex(), facep->getGeomCount(),  +							facep->getIndicesStart(), facep->getIndicesCount()); +					} +				} +			} + +			index_offset += facep->getGeomCount(); +			indices_index += facep->getIndicesCount(); + + +			//append face to appropriate render batch + +			BOOL force_simple = facep->getPixelArea() < FORCE_SIMPLE_RENDER_AREA; +			BOOL fullbright = facep->isState(LLFace::FULLBRIGHT); +			if ((mask & LLVertexBuffer::MAP_NORMAL) == 0) +			{ //paranoia check to make sure GL doesn't try to read non-existant normals +				fullbright = TRUE; +			} + +			const LLTextureEntry* te = facep->getTextureEntry(); + +			BOOL is_alpha = (facep->getPoolType() == LLDrawPool::POOL_ALPHA) ? TRUE : FALSE; +		 +			if (is_alpha) +			{ +				// can we safely treat this as an alpha mask? +				if (facep->canRenderAsMask()) +				{ +					if (te->getFullbright() || LLPipeline::sNoAlpha) +					{ +						registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK); +					} +					else +					{ +						registerFace(group, facep, LLRenderPass::PASS_ALPHA_MASK); +					} +				} +				else +				{ +					registerFace(group, facep, LLRenderPass::PASS_ALPHA); +				} + +				if (LLPipeline::sRenderDeferred) +				{ +					registerFace(group, facep, LLRenderPass::PASS_ALPHA_SHADOW); +				} +			} +			else if (gPipeline.canUseVertexShaders() +				&& group->mSpatialPartition->mPartitionType != LLViewerRegion::PARTITION_HUD  +				&& LLPipeline::sRenderBump  +				&& te->getShiny()) +			{ //shiny +				if (tex->getPrimaryFormat() == GL_ALPHA) +				{ //invisiprim+shiny +					registerFace(group, facep, LLRenderPass::PASS_INVISI_SHINY); +					registerFace(group, facep, LLRenderPass::PASS_INVISIBLE); +				} +				else if (LLPipeline::sRenderDeferred) +				{ //deferred rendering +					if (te->getFullbright()) +					{ //register in post deferred fullbright shiny pass +						registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT_SHINY); +						if (te->getBumpmap()) +						{ //register in post deferred bump pass +							registerFace(group, facep, LLRenderPass::PASS_POST_BUMP); +						} +					} +					else if (te->getBumpmap()) +					{ //register in deferred bump pass +						registerFace(group, facep, LLRenderPass::PASS_BUMP); +					} +					else +					{ //register in deferred simple pass (deferred simple includes shiny) +						llassert(mask & LLVertexBuffer::MAP_NORMAL); +						registerFace(group, facep, LLRenderPass::PASS_SIMPLE); +					} +				} +				else if (fullbright) +				{	//not deferred, register in standard fullbright shiny pass					 +					registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT_SHINY); +				} +				else +				{ //not deferred or fullbright, register in standard shiny pass +					registerFace(group, facep, LLRenderPass::PASS_SHINY); +				} +			} +			else +			{ //not alpha and not shiny +				if (!is_alpha && tex->getPrimaryFormat() == GL_ALPHA) +				{ //invisiprim +					registerFace(group, facep, LLRenderPass::PASS_INVISIBLE); +				} +				else if (fullbright || bake_sunlight) +				{ //fullbright +					registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT); +					if (LLPipeline::sRenderDeferred && LLPipeline::sRenderBump && te->getBumpmap()) +					{ //if this is the deferred render and a bump map is present, register in post deferred bump +						registerFace(group, facep, LLRenderPass::PASS_POST_BUMP); +					} +				} +				else +				{ +					if (LLPipeline::sRenderDeferred && LLPipeline::sRenderBump && te->getBumpmap()) +					{ //non-shiny or fullbright deferred bump +						registerFace(group, facep, LLRenderPass::PASS_BUMP); +					} +					else +					{ //all around simple +						llassert(mask & LLVertexBuffer::MAP_NORMAL); +						registerFace(group, facep, LLRenderPass::PASS_SIMPLE); +					} +				} +				 +				//not sure why this is here -- shiny HUD attachments maybe?  -- davep 5/11/2010 +				if (!is_alpha && te->getShiny() && LLPipeline::sRenderBump) +				{ +					registerFace(group, facep, LLRenderPass::PASS_SHINY); +				} +			} +			 +			//not sure why this is here, and looks like it might cause bump mapped objects to get rendered redundantly -- davep 5/11/2010 +			if (!is_alpha && !LLPipeline::sRenderDeferred) +			{ +				llassert((mask & LLVertexBuffer::MAP_NORMAL) || fullbright); +				facep->setPoolType((fullbright) ? LLDrawPool::POOL_FULLBRIGHT : LLDrawPool::POOL_SIMPLE); +				 +				if (!force_simple && te->getBumpmap() && LLPipeline::sRenderBump) +				{ +					registerFace(group, facep, LLRenderPass::PASS_BUMP); +				} +			} + +			if (!is_alpha && LLPipeline::sRenderGlow && te->getGlow() > 0.f) +			{ +				registerFace(group, facep, LLRenderPass::PASS_GLOW); +			} +						 +			++face_iter; +		} + +		buffer->setBuffer(0); +	} + +	group->mBufferMap[mask].clear(); +	for (LLSpatialGroup::buffer_texture_map_t::iterator i = buffer_map[mask].begin(); i != buffer_map[mask].end(); ++i) +	{ +		group->mBufferMap[mask][i->first] = i->second; +	} +} + +void LLGeometryManager::addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32 &index_count) +{	 +	//initialize to default usage for this partition +	U32 usage = group->mSpatialPartition->mBufferUsage; +	 +	//clear off any old faces +	mFaceList.clear(); + +	//for each drawable +	for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter) +	{ +		LLDrawable* drawablep = *drawable_iter; +		 +		if (drawablep->isDead()) +		{ +			continue; +		} +	 +		if (drawablep->isAnimating()) +		{ //fall back to stream draw for animating verts +			usage = GL_STREAM_DRAW_ARB; +		} + +		//for each face +		for (S32 i = 0; i < drawablep->getNumFaces(); i++) +		{ +			//sum up face verts and indices +			drawablep->updateFaceSize(i); +			LLFace* facep = drawablep->getFace(i); +			if (facep->hasGeometry() && facep->getPixelArea() > FORCE_CULL_AREA) +			{ +				vertex_count += facep->getGeomCount(); +				index_count += facep->getIndicesCount(); + +				//remember face (for sorting) +				mFaceList.push_back(facep); +			} +			else +			{ +				facep->clearVertexBuffer(); +			} +		} +	} +	 +	group->mBufferUsage = usage; +} + +LLHUDPartition::LLHUDPartition() +{ +	mPartitionType = LLViewerRegion::PARTITION_HUD; +	mDrawableType = LLPipeline::RENDER_TYPE_HUD; +	mSlopRatio = 0.f; +	mLODPeriod = 1; +} + +void LLHUDPartition::shift(const LLVector4a &offset) +{ +	//HUD objects don't shift with region crossing.  That would be silly. +} + +  | 
