diff options
| -rw-r--r-- | autobuild.xml | 24 | ||||
| -rw-r--r-- | indra/llmath/llmatrix3a.inl | 1 | ||||
| -rw-r--r-- | indra/llmath/m3math.h | 2 | ||||
| -rw-r--r-- | indra/llmath/v3color.h | 2 | ||||
| -rw-r--r-- | indra/llmath/v3dmath.h | 2 | ||||
| -rw-r--r-- | indra/llmath/v3math.h | 2 | ||||
| -rw-r--r-- | indra/llmath/v4color.h | 2 | ||||
| -rw-r--r-- | indra/llmath/v4math.h | 2 | ||||
| -rw-r--r-- | indra/llrender/llvertexbuffer.cpp | 4583 | ||||
| -rwxr-xr-x | indra/newview/llagent.cpp | 3 | ||||
| -rw-r--r-- | indra/newview/llspatialpartition.cpp | 9592 | ||||
| -rw-r--r-- | indra/newview/llviewerdisplay.cpp | 3131 | ||||
| -rw-r--r-- | indra/newview/llviewermenufile.cpp | 2596 | ||||
| -rwxr-xr-x | indra/newview/llviewermessage.cpp | 4 | ||||
| -rw-r--r-- | indra/newview/llviewerobject.cpp | 20 | ||||
| -rw-r--r-- | indra/newview/llviewerobject.h | 1 | ||||
| -rw-r--r-- | indra/newview/llviewerregion.cpp | 2 | ||||
| -rw-r--r-- | indra/newview/llvoavatarself.cpp | 2 | ||||
| -rw-r--r-- | indra/newview/skins/default/xui/en/menu_viewer.xml | 9 | 
19 files changed, 9989 insertions, 9991 deletions
diff --git a/autobuild.xml b/autobuild.xml index 89763c8973..b172779f28 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -1110,9 +1110,9 @@              <key>archive</key>              <map>                <key>hash</key> -              <string>8a63df01cf6cd4d8bf0ef25d82ef434e</string> +              <string>37c2422417783af029c9e8354b1270d8</string>                <key>url</key> -              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/stinson_llpathinglibrary/rev/251260/arch/Darwin/installer/llphysicsextensions-0.1-darwin-20120314.tar.bz2</string> +              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/stinson_llpathinglibrary/rev/251688/arch/Darwin/installer/llphysicsextensions-0.1-darwin-20120320.tar.bz2</string>              </map>              <key>name</key>              <string>darwin</string> @@ -1122,9 +1122,9 @@              <key>archive</key>              <map>                <key>hash</key> -              <string>f275fcd33f64e89a998b6362b4108c8d</string> +              <string>ab03e96012656552e6029801e8b728cd</string>                <key>url</key> -              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/stinson_llpathinglibrary/rev/251260/arch/Linux/installer/llphysicsextensions-0.1-linux-20120314.tar.bz2</string> +              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/stinson_llpathinglibrary/rev/251688/arch/Linux/installer/llphysicsextensions-0.1-linux-20120321.tar.bz2</string>              </map>              <key>name</key>              <string>linux</string> @@ -1134,9 +1134,9 @@              <key>archive</key>              <map>                <key>hash</key> -              <string>1aeda36feecac847cdbaa523ada4990f</string> +              <string>337d3eee03fc79a8a948decea54a3887</string>                <key>url</key> -              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/stinson_llpathinglibrary/rev/251260/arch/CYGWIN/installer/llphysicsextensions-0.1-windows-20120314.tar.bz2</string> +              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/stinson_llpathinglibrary/rev/251688/arch/CYGWIN/installer/llphysicsextensions-0.1-windows-20120320.tar.bz2</string>              </map>              <key>name</key>              <string>windows</string> @@ -1861,6 +1861,10 @@                <map>                  <key>command</key>                  <string>xcodebuild</string> +                <key>filters</key> +                <array> +                  <string>setenv</string> +                </array>                  <key>options</key>                  <array>                    <string>-configuration Debug</string> @@ -1911,6 +1915,10 @@                <map>                  <key>command</key>                  <string>xcodebuild</string> +                <key>filters</key> +                <array> +                  <string>setenv</string> +                </array>                  <key>options</key>                  <array>                    <string>-configuration RelWithDebInfo</string> @@ -1963,6 +1971,10 @@                <map>                  <key>command</key>                  <string>xcodebuild</string> +                <key>filters</key> +                <array> +                  <string>setenv</string> +                </array>                  <key>options</key>                  <array>                    <string>-configuration Release</string> diff --git a/indra/llmath/llmatrix3a.inl b/indra/llmath/llmatrix3a.inl index 270f1e905b..37819fea3c 100644 --- a/indra/llmath/llmatrix3a.inl +++ b/indra/llmath/llmatrix3a.inl @@ -66,6 +66,7 @@ inline void LLMatrix3a::setTranspose(const LLMatrix3a& src)  inline const LLVector4a& LLMatrix3a::getColumn(const U32 column) const  { +	llassert( column < 3 );  	return mColumns[column];  } diff --git a/indra/llmath/m3math.h b/indra/llmath/m3math.h index 3970a5de31..2be5452f8d 100644 --- a/indra/llmath/m3math.h +++ b/indra/llmath/m3math.h @@ -27,7 +27,7 @@  #ifndef LL_M3MATH_H  #define LL_M3MATH_H -//#include "llerror.h" +#include "llerror.h"  #include "stdtypes.h"  class LLVector4; diff --git a/indra/llmath/v3color.h b/indra/llmath/v3color.h index 4e77d9e5ff..56cb2ae73e 100644 --- a/indra/llmath/v3color.h +++ b/indra/llmath/v3color.h @@ -30,7 +30,7 @@  class LLColor4;  class LLVector4; -//#include "llerror.h" +#include "llerror.h"  #include "llmath.h"  #include "llsd.h" diff --git a/indra/llmath/v3dmath.h b/indra/llmath/v3dmath.h index fba549a3b7..578dcdc8ea 100644 --- a/indra/llmath/v3dmath.h +++ b/indra/llmath/v3dmath.h @@ -27,7 +27,7 @@  #ifndef LL_V3DMATH_H  #define LL_V3DMATH_H -//#include "llerror.h" +#include "llerror.h"  #include "v3math.h"  class LLVector3d diff --git a/indra/llmath/v3math.h b/indra/llmath/v3math.h index 206a99b567..0432aeba4c 100644 --- a/indra/llmath/v3math.h +++ b/indra/llmath/v3math.h @@ -27,7 +27,7 @@  #ifndef LL_V3MATH_H  #define LL_V3MATH_H -//#include "llerror.h" +#include "llerror.h"  #include "llmath.h"  #include "llsd.h" diff --git a/indra/llmath/v4color.h b/indra/llmath/v4color.h index 6946b570ab..b047f86e6e 100644 --- a/indra/llmath/v4color.h +++ b/indra/llmath/v4color.h @@ -27,7 +27,7 @@  #ifndef LL_V4COLOR_H  #define LL_V4COLOR_H -//#include "llerror.h" +#include "llerror.h"  //#include "vmath.h"  #include "llmath.h"  #include "llsd.h" diff --git a/indra/llmath/v4math.h b/indra/llmath/v4math.h index f999e0533e..623c8b2003 100644 --- a/indra/llmath/v4math.h +++ b/indra/llmath/v4math.h @@ -27,7 +27,7 @@  #ifndef LL_V4MATH_H  #define LL_V4MATH_H -//#include "llerror.h" +#include "llerror.h"  #include "llmath.h"  #include "v3math.h" diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index b562c91e3e..e4a5cd0299 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -1,2293 +1,2290 @@ -/** 
 - * @file llvertexbuffer.cpp
 - * @brief LLVertexBuffer implementation
 - *
 - * $LicenseInfo:firstyear=2003&license=viewerlgpl$
 - * Second Life Viewer Source Code
 - * Copyright (C) 2010, Linden Research, Inc.
 - * 
 - * This library is free software; you can redistribute it and/or
 - * modify it under the terms of the GNU Lesser General Public
 - * License as published by the Free Software Foundation;
 - * version 2.1 of the License only.
 - * 
 - * This library is distributed in the hope that it will be useful,
 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 - * Lesser General Public License for more details.
 - * 
 - * You should have received a copy of the GNU Lesser General Public
 - * License along with this library; if not, write to the Free Software
 - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 - * 
 - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 - * $/LicenseInfo$
 - */
 -
 -#include "linden_common.h"
 -
 -#include <boost/static_assert.hpp>
 -#include "llsys.h"
 -#include "llvertexbuffer.h"
 -// #include "llrender.h"
 -#include "llglheaders.h"
 -#include "llmemtype.h"
 -#include "llrender.h"
 -#include "llvector4a.h"
 -#include "llshadermgr.h"
 -#include "llglslshader.h"
 -#include "llmemory.h"
 -
 -//Next Highest Power Of Two
 -//helper function, returns first number > v that is a power of 2, or v if v is already a power of 2
 -U32 nhpo2(U32 v)
 -{
 -	U32 r = 1;
 -	while (r < v) {
 -		r *= 2;
 -	}
 -	return r;
 -}
 -
 -
 -//============================================================================
 -
 -//static
 -LLVBOPool LLVertexBuffer::sStreamVBOPool(GL_STREAM_DRAW_ARB, GL_ARRAY_BUFFER_ARB);
 -LLVBOPool LLVertexBuffer::sDynamicVBOPool(GL_DYNAMIC_DRAW_ARB, GL_ARRAY_BUFFER_ARB);
 -LLVBOPool LLVertexBuffer::sStreamIBOPool(GL_STREAM_DRAW_ARB, GL_ELEMENT_ARRAY_BUFFER_ARB);
 -LLVBOPool LLVertexBuffer::sDynamicIBOPool(GL_DYNAMIC_DRAW_ARB, GL_ELEMENT_ARRAY_BUFFER_ARB);
 -U32 LLVBOPool::sBytesPooled = 0;
 -
 -LLPrivateMemoryPool* LLVertexBuffer::sPrivatePoolp = NULL;
 -U32 LLVertexBuffer::sBindCount = 0;
 -U32 LLVertexBuffer::sSetCount = 0;
 -S32 LLVertexBuffer::sCount = 0;
 -S32 LLVertexBuffer::sGLCount = 0;
 -S32 LLVertexBuffer::sMappedCount = 0;
 -bool LLVertexBuffer::sDisableVBOMapping = false;
 -bool LLVertexBuffer::sEnableVBOs = true;
 -U32 LLVertexBuffer::sGLRenderBuffer = 0;
 -U32 LLVertexBuffer::sGLRenderArray = 0;
 -U32 LLVertexBuffer::sGLRenderIndices = 0;
 -U32 LLVertexBuffer::sLastMask = 0;
 -bool LLVertexBuffer::sVBOActive = false;
 -bool LLVertexBuffer::sIBOActive = false;
 -U32 LLVertexBuffer::sAllocatedBytes = 0;
 -bool LLVertexBuffer::sMapped = false;
 -bool LLVertexBuffer::sUseStreamDraw = true;
 -bool LLVertexBuffer::sUseVAO = false;
 -bool LLVertexBuffer::sPreferStreamDraw = false;
 -
 -const U32 FENCE_WAIT_TIME_NANOSECONDS = 10000;  //1 ms
 -
 -class LLGLSyncFence : public LLGLFence
 -{
 -public:
 -#ifdef GL_ARB_sync
 -	GLsync mSync;
 -#endif
 -	
 -	LLGLSyncFence()
 -	{
 -#ifdef GL_ARB_sync
 -		mSync = 0;
 -#endif
 -	}
 -
 -	virtual ~LLGLSyncFence()
 -	{
 -#ifdef GL_ARB_sync
 -		if (mSync)
 -		{
 -			glDeleteSync(mSync);
 -		}
 -#endif
 -	}
 -
 -	void placeFence()
 -	{
 -#ifdef GL_ARB_sync
 -		if (mSync)
 -		{
 -			glDeleteSync(mSync);
 -		}
 -		mSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
 -#endif
 -	}
 -
 -	void wait()
 -	{
 -#ifdef GL_ARB_sync
 -		if (mSync)
 -		{
 -			while (glClientWaitSync(mSync, 0, FENCE_WAIT_TIME_NANOSECONDS) == GL_TIMEOUT_EXPIRED)
 -			{ //track the number of times we've waited here
 -				static S32 waits = 0;
 -				waits++;
 -			}
 -		}
 -#endif
 -	}
 -
 -
 -};
 -
 -
 -//which power of 2 is i?
 -//assumes i is a power of 2 > 0
 -U32 wpo2(U32 i)
 -{
 -	llassert(i > 0);
 -	llassert(nhpo2(i) == i);
 -
 -	U32 r = 0;
 -
 -	while (i >>= 1) ++r;
 -
 -	return r;
 -}
 -
 -volatile U8* LLVBOPool::allocate(U32& name, U32 size)
 -{
 -	llassert(nhpo2(size) == size);
 -
 -	U32 i = wpo2(size);
 -
 -	if (mFreeList.size() <= i)
 -	{
 -		mFreeList.resize(i+1);
 -	}
 -
 -	volatile U8* ret = NULL;
 -
 -	if (mFreeList[i].empty())
 -	{
 -		//make a new buffer
 -		glGenBuffersARB(1, &name);
 -		glBindBufferARB(mType, name);
 -		LLVertexBuffer::sAllocatedBytes += size;
 -
 -		if (LLVertexBuffer::sDisableVBOMapping || mUsage != GL_DYNAMIC_DRAW_ARB)
 -		{
 -			glBufferDataARB(mType, size, 0, mUsage);
 -			ret = (U8*) ll_aligned_malloc_16(size);
 -		}
 -		else
 -		{ //always use a true hint of static draw when allocating non-client-backed buffers
 -			glBufferDataARB(mType, size, 0, GL_STATIC_DRAW_ARB);
 -		}
 -
 -		glBindBufferARB(mType, 0);
 -	}
 -	else
 -	{
 -		name = mFreeList[i].front().mGLName;
 -		ret = mFreeList[i].front().mClientData;
 -
 -		sBytesPooled -= size;
 -
 -		mFreeList[i].pop_front();
 -	}
 -
 -	return ret;
 -}
 -
 -void LLVBOPool::release(U32 name, volatile U8* buffer, U32 size)
 -{
 -	llassert(nhpo2(size) == size);
 -
 -	U32 i = wpo2(size);
 -
 -	llassert(mFreeList.size() > i);
 -
 -	Record rec;
 -	rec.mGLName = name;
 -	rec.mClientData = buffer;
 -	
 -	if (buffer == NULL)
 -	
 -	{
 -		glDeleteBuffersARB(1, &rec.mGLName);
 -	}
 -	else
 -	{
 -		sBytesPooled += size;
 -	mFreeList[i].push_back(rec);
 -}
 -}
 -
 -void LLVBOPool::cleanup()
 -{
 -	U32 size = 1;
 -
 -	for (U32 i = 0; i < mFreeList.size(); ++i)
 -	{
 -		record_list_t& l = mFreeList[i];
 -
 -		while (!l.empty())
 -		{
 -			Record& r = l.front();
 -
 -			glDeleteBuffersARB(1, &r.mGLName);
 -
 -			if (r.mClientData)
 -			{
 -				ll_aligned_free_16((void*) r.mClientData);
 -			}
 -
 -			l.pop_front();
 -
 -			LLVertexBuffer::sAllocatedBytes -= size;
 -			sBytesPooled -= size;
 -		}
 -
 -		size *= 2;
 -	}
 -}
 -
 -
 -//NOTE: each component must be AT LEAST 4 bytes in size to avoid a performance penalty on AMD hardware
 -S32 LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_MAX] =
 -{
 -	sizeof(LLVector4), // TYPE_VERTEX,
 -	sizeof(LLVector4), // TYPE_NORMAL,
 -	sizeof(LLVector2), // TYPE_TEXCOORD0,
 -	sizeof(LLVector2), // TYPE_TEXCOORD1,
 -	sizeof(LLVector2), // TYPE_TEXCOORD2,
 -	sizeof(LLVector2), // TYPE_TEXCOORD3,
 -	sizeof(LLColor4U), // TYPE_COLOR,
 -	sizeof(LLColor4U), // TYPE_EMISSIVE, only alpha is used currently
 -	sizeof(LLVector4), // TYPE_BINORMAL,
 -	sizeof(F32),	   // TYPE_WEIGHT,
 -	sizeof(LLVector4), // TYPE_WEIGHT4,
 -	sizeof(LLVector4), // TYPE_CLOTHWEIGHT,
 -	sizeof(LLVector4), // TYPE_TEXTURE_INDEX (actually exists as position.w), no extra data, but stride is 16 bytes
 -};
 -
 -U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] = 
 -{
 -	GL_TRIANGLES,
 -	GL_TRIANGLE_STRIP,
 -	GL_TRIANGLE_FAN,
 -	GL_POINTS,
 -	GL_LINES,
 -	GL_LINE_STRIP,
 -	GL_QUADS,
 -	GL_LINE_LOOP,
 -};
 -
 -
 -//static
 -void LLVertexBuffer::setupClientArrays(U32 data_mask)
 -{
 -	if (sLastMask != data_mask)
 -	{
 -		bool error = false;
 -
 -		if (LLGLSLShader::sNoFixedFunction)
 -		{
 -			for (U32 i = 0; i < TYPE_MAX; ++i)
 -			{
 -				S32 loc = i;
 -										
 -				U32 mask = 1 << i;
 -
 -				if (sLastMask & (1 << i))
 -				{ //was enabled
 -					if (!(data_mask & mask))
 -					{ //needs to be disabled
 -						glDisableVertexAttribArrayARB(loc);
 -					}
 -				}
 -				else 
 -				{	//was disabled
 -					if (data_mask & mask)
 -					{ //needs to be enabled
 -						glEnableVertexAttribArrayARB(loc);
 -					}
 -				}
 -			}
 -		}
 -		else
 -		{
 -
 -			GLenum array[] =
 -			{
 -				GL_VERTEX_ARRAY,
 -				GL_NORMAL_ARRAY,
 -				GL_TEXTURE_COORD_ARRAY,
 -				GL_COLOR_ARRAY,
 -			};
 -
 -			GLenum mask[] = 
 -			{
 -				MAP_VERTEX,
 -				MAP_NORMAL,
 -				MAP_TEXCOORD0,
 -				MAP_COLOR
 -			};
 -
 -
 -
 -			for (U32 i = 0; i < 4; ++i)
 -			{
 -				if (sLastMask & mask[i])
 -				{ //was enabled
 -					if (!(data_mask & mask[i]))
 -					{ //needs to be disabled
 -						glDisableClientState(array[i]);
 -					}
 -					else if (gDebugGL)
 -					{ //needs to be enabled, make sure it was (DEBUG)
 -						if (!glIsEnabled(array[i]))
 -						{
 -							if (gDebugSession)
 -							{
 -								error = true;
 -								gFailLog << "Bad client state! " << array[i] << " disabled." << std::endl;
 -							}
 -							else
 -							{
 -								llerrs << "Bad client state! " << array[i] << " disabled." << llendl;
 -							}
 -						}
 -					}
 -				}
 -				else 
 -				{	//was disabled
 -					if (data_mask & mask[i])
 -					{ //needs to be enabled
 -						glEnableClientState(array[i]);
 -					}
 -					else if (gDebugGL && glIsEnabled(array[i]))
 -					{ //needs to be disabled, make sure it was (DEBUG TEMPORARY)
 -						if (gDebugSession)
 -						{
 -							error = true;
 -							gFailLog << "Bad client state! " << array[i] << " enabled." << std::endl;
 -						}
 -						else
 -						{
 -							llerrs << "Bad client state! " << array[i] << " enabled." << llendl;
 -						}
 -					}
 -				}
 -			}
 -		
 -			U32 map_tc[] = 
 -			{
 -				MAP_TEXCOORD1,
 -				MAP_TEXCOORD2,
 -				MAP_TEXCOORD3
 -			};
 -
 -			for (U32 i = 0; i < 3; i++)
 -			{
 -				if (sLastMask & map_tc[i])
 -				{
 -					if (!(data_mask & map_tc[i]))
 -					{ //disable
 -						glClientActiveTextureARB(GL_TEXTURE1_ARB+i);
 -						glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 -						glClientActiveTextureARB(GL_TEXTURE0_ARB);
 -					}
 -				}
 -				else if (data_mask & map_tc[i])
 -				{
 -					glClientActiveTextureARB(GL_TEXTURE1_ARB+i);
 -					glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 -					glClientActiveTextureARB(GL_TEXTURE0_ARB);
 -				}
 -			}
 -
 -			if (sLastMask & MAP_BINORMAL)
 -			{
 -				if (!(data_mask & MAP_BINORMAL))
 -				{
 -					glClientActiveTextureARB(GL_TEXTURE2_ARB);
 -					glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 -					glClientActiveTextureARB(GL_TEXTURE0_ARB);
 -				}
 -			}
 -			else if (data_mask & MAP_BINORMAL)
 -			{
 -				glClientActiveTextureARB(GL_TEXTURE2_ARB);
 -				glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 -				glClientActiveTextureARB(GL_TEXTURE0_ARB);
 -			}
 -		}
 -				
 -		sLastMask = data_mask;
 -	}
 -}
 -
 -//static
 -void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm)
 -{
 -	llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
 -	gGL.syncMatrices();
 -
 -	U32 count = pos.size();
 -	llassert_always(norm.size() >= pos.size());
 -	llassert_always(count > 0);
 -
 -	unbind();
 -	
 -	setupClientArrays(MAP_VERTEX | MAP_NORMAL);
 -
 -	LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
 -
 -	if (shader)
 -	{
 -		S32 loc = LLVertexBuffer::TYPE_VERTEX;
 -		if (loc > -1)
 -		{
 -			glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 0, pos[0].mV);
 -		}
 -		loc = LLVertexBuffer::TYPE_NORMAL;
 -		if (loc > -1)
 -		{
 -			glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 0, norm[0].mV);
 -		}
 -	}
 -	else
 -	{
 -		glVertexPointer(3, GL_FLOAT, 0, pos[0].mV);
 -		glNormalPointer(GL_FLOAT, 0, norm[0].mV);
 -	}
 -
 -	glDrawArrays(sGLMode[mode], 0, count);
 -}
 -
 -//static
 -void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp)
 -{
 -	llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
 -
 -	gGL.syncMatrices();
 -
 -	U32 mask = LLVertexBuffer::MAP_VERTEX;
 -	if (tc)
 -	{
 -		mask = mask | LLVertexBuffer::MAP_TEXCOORD0;
 -	}
 -
 -	unbind();
 -	
 -	setupClientArrays(mask);
 -
 -	if (LLGLSLShader::sNoFixedFunction)
 -	{
 -		S32 loc = LLVertexBuffer::TYPE_VERTEX;
 -		glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 16, pos);
 -
 -		if (tc)
 -		{
 -			loc = LLVertexBuffer::TYPE_TEXCOORD0;
 -			glVertexAttribPointerARB(loc, 2, GL_FLOAT, GL_FALSE, 0, tc);
 -		}
 -	}
 -	else
 -	{
 -		glTexCoordPointer(2, GL_FLOAT, 0, tc);
 -		glVertexPointer(3, GL_FLOAT, 16, pos);
 -	}
 -
 -	glDrawElements(sGLMode[mode], num_indices, GL_UNSIGNED_SHORT, indicesp);
 -}
 -
 -void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_offset) const
 -{
 -	if (start >= (U32) mNumVerts ||
 -	    end >= (U32) mNumVerts)
 -	{
 -		llerrs << "Bad vertex buffer draw range: [" << start << ", " << end << "] vs " << mNumVerts << llendl;
 -	}
 -
 -	llassert(mNumIndices >= 0);
 -
 -	if (indices_offset >= (U32) mNumIndices ||
 -	    indices_offset + count > (U32) mNumIndices)
 -	{
 -		llerrs << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << llendl;
 -	}
 -
 -	if (gDebugGL && !useVBOs())
 -	{
 -		U16* idx = ((U16*) getIndicesPointer())+indices_offset;
 -		for (U32 i = 0; i < count; ++i)
 -		{
 -			if (idx[i] < start || idx[i] > end)
 -			{
 -				llerrs << "Index out of range: " << idx[i] << " not in [" << start << ", " << end << "]" << llendl;
 -			}
 -		}
 -
 -		LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
 -
 -		if (shader && shader->mFeatures.mIndexedTextureChannels > 1)
 -		{
 -			LLStrider<LLVector4a> v;
 -			//hack to get non-const reference
 -			LLVertexBuffer* vb = (LLVertexBuffer*) this;
 -			vb->getVertexStrider(v);
 -
 -			for (U32 i = start; i < end; i++)
 -			{
 -				S32 idx = (S32) (v[i][3]+0.25f);
 -				if (idx < 0 || idx >= shader->mFeatures.mIndexedTextureChannels)
 -				{
 -					llerrs << "Bad texture index found in vertex data stream." << llendl;
 -				}
 -			}
 -		}
 -	}
 -}
 -
 -void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const
 -{
 -	validateRange(start, end, count, indices_offset);
 -	mMappable = false;
 -	gGL.syncMatrices();
 -
 -	llassert(mNumVerts >= 0);
 -	llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
 -
 -	if (mGLArray)
 -	{
 -		if (mGLArray != sGLRenderArray)
 -		{
 -			llerrs << "Wrong vertex array bound." << llendl;
 -		}
 -	}
 -	else
 -	{
 -		if (mGLIndices != sGLRenderIndices)
 -		{
 -			llerrs << "Wrong index buffer bound." << llendl;
 -		}
 -
 -		if (mGLBuffer != sGLRenderBuffer)
 -		{
 -			llerrs << "Wrong vertex buffer bound." << llendl;
 -		}
 -	}
 -
 -	if (gDebugGL && !mGLArray && useVBOs())
 -	{
 -		GLint elem = 0;
 -		glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &elem);
 -
 -		if (elem != mGLIndices)
 -		{
 -			llerrs << "Wrong index buffer bound!" << llendl;
 -		}
 -	}
 -
 -	if (mode >= LLRender::NUM_MODES)
 -	{
 -		llerrs << "Invalid draw mode: " << mode << llendl;
 -		return;
 -	}
 -
 -	U16* idx = ((U16*) getIndicesPointer())+indices_offset;
 -
 -	stop_glerror();
 -	glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT, 
 -		idx);
 -	stop_glerror();
 -	placeFence();
 -}
 -
 -void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
 -{
 -	llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
 -	mMappable = false;
 -	gGL.syncMatrices();
 -
 -	llassert(mNumIndices >= 0);
 -	if (indices_offset >= (U32) mNumIndices ||
 -	    indices_offset + count > (U32) mNumIndices)
 -	{
 -		llerrs << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << llendl;
 -	}
 -
 -	if (mGLArray)
 -	{
 -		if (mGLArray != sGLRenderArray)
 -		{
 -			llerrs << "Wrong vertex array bound." << llendl;
 -		}
 -	}
 -	else
 -	{
 -		if (mGLIndices != sGLRenderIndices)
 -		{
 -			llerrs << "Wrong index buffer bound." << llendl;
 -		}
 -
 -		if (mGLBuffer != sGLRenderBuffer)
 -		{
 -			llerrs << "Wrong vertex buffer bound." << llendl;
 -		}
 -	}
 -
 -	if (mode >= LLRender::NUM_MODES)
 -	{
 -		llerrs << "Invalid draw mode: " << mode << llendl;
 -		return;
 -	}
 -
 -	stop_glerror();
 -	glDrawElements(sGLMode[mode], count, GL_UNSIGNED_SHORT,
 -		((U16*) getIndicesPointer()) + indices_offset);
 -	stop_glerror();
 -	placeFence();
 -}
 -
 -void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
 -{
 -	llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
 -	mMappable = false;
 -	gGL.syncMatrices();
 -	
 -	llassert(mNumVerts >= 0);
 -	if (first >= (U32) mNumVerts ||
 -	    first + count > (U32) mNumVerts)
 -	{
 -		llerrs << "Bad vertex buffer draw range: [" << first << ", " << first+count << "]" << llendl;
 -	}
 -
 -	if (mGLArray)
 -	{
 -		if (mGLArray != sGLRenderArray)
 -		{
 -			llerrs << "Wrong vertex array bound." << llendl;
 -		}
 -	}
 -	else
 -	{
 -		bool uvb = useVBOs();
 -		if (mGLBuffer != sGLRenderBuffer || uvb != sVBOActive)
 -		{
 -			llerrs << "Wrong vertex buffer bound." << llendl;
 -		}
 -	}
 -
 -	if (mode >= LLRender::NUM_MODES)
 -	{
 -		llerrs << "Invalid draw mode: " << mode << llendl;
 -		return;
 -	}
 -
 -	stop_glerror();
 -	glDrawArrays(sGLMode[mode], first, count);
 -	stop_glerror();
 -	placeFence();
 -}
 -
 -//static
 -void LLVertexBuffer::initClass(bool use_vbo, bool no_vbo_mapping)
 -{
 -	sEnableVBOs = use_vbo && gGLManager.mHasVertexBufferObject;
 -	sDisableVBOMapping = sEnableVBOs && no_vbo_mapping;
 -
 -	if (!sPrivatePoolp)
 -	{ 
 -		sPrivatePoolp = LLPrivateMemoryPoolManager::getInstance()->newPool(LLPrivateMemoryPool::STATIC);
 -	}
 -}
 -
 -//static 
 -void LLVertexBuffer::unbind()
 -{
 -	if (sGLRenderArray)
 -	{
 -#if GL_ARB_vertex_array_object
 -		glBindVertexArray(0);
 -#endif
 -		sGLRenderArray = 0;
 -		sGLRenderIndices = 0;
 -		sIBOActive = false;
 -	}
 -
 -	if (sVBOActive)
 -	{
 -		glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
 -		sVBOActive = false;
 -	}
 -	if (sIBOActive)
 -	{
 -		glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
 -		sIBOActive = false;
 -	}
 -
 -	sGLRenderBuffer = 0;
 -	sGLRenderIndices = 0;
 -
 -	setupClientArrays(0);
 -}
 -
 -//static
 -void LLVertexBuffer::cleanupClass()
 -{
 -	LLMemType mt2(LLMemType::MTYPE_VERTEX_CLEANUP_CLASS);
 -	unbind();
 -	
 -	sStreamIBOPool.cleanup();
 -	sDynamicIBOPool.cleanup();
 -	sStreamVBOPool.cleanup();
 -	sDynamicVBOPool.cleanup();
 -
 -	if(sPrivatePoolp)
 -	{
 -		LLPrivateMemoryPoolManager::getInstance()->deletePool(sPrivatePoolp);
 -		sPrivatePoolp = NULL;
 -	}
 -}
 -
 -//----------------------------------------------------------------------------
 -
 -S32 LLVertexBuffer::determineUsage(S32 usage)
 -{
 -	S32 ret_usage = usage;
 -
 -	if (!sEnableVBOs)
 -	{
 -		ret_usage = 0;
 -	}
 -	
 -	if (ret_usage == GL_STREAM_DRAW_ARB && !sUseStreamDraw)
 -	{
 -		ret_usage = 0;
 -	}
 -	
 -	if (ret_usage == GL_DYNAMIC_DRAW_ARB && sPreferStreamDraw)
 -	{
 -		ret_usage = GL_STREAM_DRAW_ARB;
 -	}
 -	
 -	if (ret_usage == 0 && LLRender::sGLCoreProfile)
 -	{ //MUST use VBOs for all rendering
 -		ret_usage = GL_STREAM_DRAW_ARB;
 -	}
 -	
 -	if (ret_usage && ret_usage != GL_STREAM_DRAW_ARB)
 -	{ //only stream_draw and dynamic_draw are supported when using VBOs, dynamic draw is the default
 -		if (sDisableVBOMapping)
 -		{ //always use stream draw if VBO mapping is disabled
 -			ret_usage = GL_STREAM_DRAW_ARB;
 -		}
 -		else
 -		{
 -ret_usage = GL_DYNAMIC_DRAW_ARB;
 -
 -	}
 -	}
 -		
 -	return ret_usage;
 -}
 -
 -LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) :
 -	LLRefCount(),
 -
 -	mNumVerts(0),
 -	mNumIndices(0),
 -	mAlignedOffset(0),
 -	mAlignedIndexOffset(0),
 -	mSize(0),
 -	mIndicesSize(0),
 -	mTypeMask(typemask),
 -	mUsage(LLVertexBuffer::determineUsage(usage)),
 -	mGLBuffer(0),
 -	mGLIndices(0),
 -	mGLArray(0),
 -	mMappedData(NULL),
 -	mMappedIndexData(NULL),
 -	mMappedDataUsingVBOs(false),
 -	mMappedIndexDataUsingVBOs(false),
 -	mVertexLocked(false),
 -	mIndexLocked(false),
 -	mFinal(false),
 -	mEmpty(true),
 -	mMappable(false),
 -	mFence(NULL)
 -{
 -	LLMemType mt2(LLMemType::MTYPE_VERTEX_CONSTRUCTOR);
 -
 -	mMappable = (mUsage == GL_DYNAMIC_DRAW_ARB && !sDisableVBOMapping);
 -
 -	//zero out offsets
 -	for (U32 i = 0; i < TYPE_MAX; i++)
 -	{
 -		mOffsets[i] = 0;
 -	}
 -
 -	sCount++;
 -}
 -
 -//static
 -S32 LLVertexBuffer::calcOffsets(const U32& typemask, S32* offsets, S32 num_vertices)
 -{
 -	S32 offset = 0;
 -	for (S32 i=0; i<TYPE_TEXTURE_INDEX; i++)
 -	{
 -		U32 mask = 1<<i;
 -		if (typemask & mask)
 -		{
 -			if (offsets && LLVertexBuffer::sTypeSize[i])
 -			{
 -				offsets[i] = offset;
 -				offset += LLVertexBuffer::sTypeSize[i]*num_vertices;
 -				offset = (offset + 0xF) & ~0xF;
 -			}
 -		}
 -	}
 -
 -	offsets[TYPE_TEXTURE_INDEX] = offsets[TYPE_VERTEX] + 12;
 -	
 -	return offset+16;
 -}
 -
 -//static 
 -S32 LLVertexBuffer::calcVertexSize(const U32& typemask)
 -{
 -	S32 size = 0;
 -	for (S32 i = 0; i < TYPE_TEXTURE_INDEX; i++)
 -	{
 -		U32 mask = 1<<i;
 -		if (typemask & mask)
 -		{
 -			size += LLVertexBuffer::sTypeSize[i];
 -		}
 -	}
 -
 -	return size;
 -}
 -
 -S32 LLVertexBuffer::getSize() const
 -{
 -	return mSize;
 -}
 -
 -// protected, use unref()
 -//virtual
 -LLVertexBuffer::~LLVertexBuffer()
 -{
 -	LLMemType mt2(LLMemType::MTYPE_VERTEX_DESTRUCTOR);
 -	destroyGLBuffer();
 -	destroyGLIndices();
 -
 -	if (mGLArray)
 -	{
 -#if GL_ARB_vertex_array_object
 -		glDeleteVertexArrays(1, &mGLArray);
 -#endif
 -	}
 -
 -	sCount--;
 -
 -	if (mFence)
 -	{
 -		delete mFence;
 -	}
 -	
 -	mFence = NULL;
 -
 -	llassert_always(!mMappedData && !mMappedIndexData);
 -};
 -
 -void LLVertexBuffer::placeFence() const
 -{
 -	/*if (!mFence && useVBOs())
 -	{
 -		if (gGLManager.mHasSync)
 -		{
 -			mFence = new LLGLSyncFence();
 -		}
 -	}
 -
 -	if (mFence)
 -	{
 -		mFence->placeFence();
 -	}*/
 -}
 -
 -void LLVertexBuffer::waitFence() const
 -{
 -	/*if (mFence)
 -	{
 -		mFence->wait();
 -	}*/
 -}
 -
 -//----------------------------------------------------------------------------
 -
 -void LLVertexBuffer::genBuffer(U32 size)
 -{
 -	mSize = nhpo2(size);
 -
 -	if (mUsage == GL_STREAM_DRAW_ARB)
 -	{
 -		mMappedData = sStreamVBOPool.allocate(mGLBuffer, mSize);
 -	}
 -	else
 -	{
 -		mMappedData = sDynamicVBOPool.allocate(mGLBuffer, mSize);
 -	}
 -	
 -	sGLCount++;
 -}
 -
 -void LLVertexBuffer::genIndices(U32 size)
 -{
 -	mIndicesSize = nhpo2(size);
 -
 -	if (mUsage == GL_STREAM_DRAW_ARB)
 -	{
 -		mMappedIndexData = sStreamIBOPool.allocate(mGLIndices, mIndicesSize);
 -	}
 -	else
 -	{
 -		mMappedIndexData = sDynamicIBOPool.allocate(mGLIndices, mIndicesSize);
 -	}
 -	
 -	sGLCount++;
 -}
 -
 -void LLVertexBuffer::releaseBuffer()
 -{
 -	if (mUsage == GL_STREAM_DRAW_ARB)
 -	{
 -		sStreamVBOPool.release(mGLBuffer, mMappedData, mSize);
 -	}
 -	else
 -	{
 -		sDynamicVBOPool.release(mGLBuffer, mMappedData, mSize);
 -	}
 -	
 -	mGLBuffer = 0;
 -	mMappedData = NULL;
 -
 -	sGLCount--;
 -}
 -
 -void LLVertexBuffer::releaseIndices()
 -{
 -	if (mUsage == GL_STREAM_DRAW_ARB)
 -	{
 -		sStreamIBOPool.release(mGLIndices, mMappedIndexData, mIndicesSize);
 -	}
 -	else
 -	{
 -		sDynamicIBOPool.release(mGLIndices, mMappedIndexData, mIndicesSize);
 -	}
 -
 -	mGLIndices = 0;
 -	mMappedIndexData = NULL;
 -	
 -	sGLCount--;
 -}
 -
 -void LLVertexBuffer::createGLBuffer(U32 size)
 -{
 -	LLMemType mt2(LLMemType::MTYPE_VERTEX_CREATE_VERTICES);
 -	
 -	if (mGLBuffer)
 -	{
 -		destroyGLBuffer();
 -	}
 -
 -	if (size == 0)
 -	{
 -		return;
 -	}
 -
 -	mEmpty = true;
 -
 -	mMappedDataUsingVBOs = useVBOs();
 -	
 -	if (mMappedDataUsingVBOs)
 -	{
 -		genBuffer(size);
 -	}
 -	else
 -	{
 -		static int gl_buffer_idx = 0;
 -		mGLBuffer = ++gl_buffer_idx;
 -		mMappedData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size);
 -		mSize = size;
 -	}
 -}
 -
 -void LLVertexBuffer::createGLIndices(U32 size)
 -{
 -	LLMemType mt2(LLMemType::MTYPE_VERTEX_CREATE_INDICES);
 -	
 -	if (mGLIndices)
 -	{
 -		destroyGLIndices();
 -	}
 -	
 -	if (size == 0)
 -	{
 -		return;
 -	}
 -
 -	mEmpty = true;
 -
 -	//pad by 16 bytes for aligned copies
 -	size += 16;
 -
 -	mMappedIndexDataUsingVBOs = useVBOs();
 -
 -	if (mMappedIndexDataUsingVBOs)
 -	{
 -		//pad by another 16 bytes for VBO pointer adjustment
 -		size += 16;
 -		genIndices(size);
 -	}
 -	else
 -	{
 -		mMappedIndexData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size);
 -		static int gl_buffer_idx = 0;
 -		mGLIndices = ++gl_buffer_idx;
 -		mIndicesSize = size;
 -	}
 -}
 -
 -void LLVertexBuffer::destroyGLBuffer()
 -{
 -	LLMemType mt2(LLMemType::MTYPE_VERTEX_DESTROY_BUFFER);
 -	if (mGLBuffer)
 -	{
 -		if (mMappedDataUsingVBOs)
 -		{
 -			releaseBuffer();
 -		}
 -		else
 -		{
 -			FREE_MEM(sPrivatePoolp, (void*) mMappedData);
 -			mMappedData = NULL;
 -			mEmpty = true;
 -		}
 -	}
 -	
 -	mGLBuffer = 0;
 -	//unbind();
 -}
 -
 -void LLVertexBuffer::destroyGLIndices()
 -{
 -	LLMemType mt2(LLMemType::MTYPE_VERTEX_DESTROY_INDICES);
 -	if (mGLIndices)
 -	{
 -		if (mMappedIndexDataUsingVBOs)
 -		{
 -			releaseIndices();
 -		}
 -		else
 -		{
 -			FREE_MEM(sPrivatePoolp, (void*) mMappedIndexData);
 -			mMappedIndexData = NULL;
 -			mEmpty = true;
 -		}
 -	}
 -
 -	mGLIndices = 0;
 -	//unbind();
 -}
 -
 -void LLVertexBuffer::updateNumVerts(S32 nverts)
 -{
 -	LLMemType mt2(LLMemType::MTYPE_VERTEX_UPDATE_VERTS);
 -
 -	llassert(nverts >= 0);
 -
 -	if (nverts >= 65535)
 -	{
 -		llwarns << "Vertex buffer overflow!" << llendl;
 -		nverts = 65535;
 -	}
 -
 -	U32 needed_size = calcOffsets(mTypeMask, mOffsets, nverts);
 -
 -	if (needed_size > mSize || needed_size <= mSize/2)
 -	{
 -		createGLBuffer(needed_size);
 -	}
 -
 -	mNumVerts = nverts;
 -}
 -
 -void LLVertexBuffer::updateNumIndices(S32 nindices)
 -{
 -	LLMemType mt2(LLMemType::MTYPE_VERTEX_UPDATE_INDICES);
 -
 -	llassert(nindices >= 0);
 -
 -	U32 needed_size = sizeof(U16) * nindices;
 -
 -	if (needed_size > mIndicesSize || needed_size <= mIndicesSize/2)
 -	{
 -		createGLIndices(needed_size);
 -	}
 -
 -	mNumIndices = nindices;
 -}
 -
 -void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create)
 -{
 -	LLMemType mt2(LLMemType::MTYPE_VERTEX_ALLOCATE_BUFFER);
 -	
 -	stop_glerror();
 -
 -	if (nverts < 0 || nindices < 0 ||
 -		nverts > 65536)
 -	{
 -		llerrs << "Bad vertex buffer allocation: " << nverts << " : " << nindices << llendl;
 -	}
 -
 -	updateNumVerts(nverts);
 -	updateNumIndices(nindices);
 -	
 -	if (create && (nverts || nindices))
 -	{
 -		//actually allocate space for the vertex buffer if using VBO mapping
 -		flush();
 -
 -		if (gGLManager.mHasVertexArrayObject && useVBOs() && (LLRender::sGLCoreProfile || sUseVAO))
 -		{
 -#if GL_ARB_vertex_array_object
 -			glGenVertexArrays(1, &mGLArray);
 -#endif
 -			setupVertexArray();
 -		}
 -	}
 -}
 -
 -static LLFastTimer::DeclareTimer FTM_SETUP_VERTEX_ARRAY("Setup VAO");
 -
 -void LLVertexBuffer::setupVertexArray()
 -{
 -	if (!mGLArray)
 -	{
 -		return;
 -	}
 -
 -	LLFastTimer t(FTM_SETUP_VERTEX_ARRAY);
 -#if GL_ARB_vertex_array_object
 -	glBindVertexArray(mGLArray);
 -#endif
 -	sGLRenderArray = mGLArray;
 -
 -	U32 attrib_size[] = 
 -	{
 -		3, //TYPE_VERTEX,
 -		3, //TYPE_NORMAL,
 -		2, //TYPE_TEXCOORD0,
 -		2, //TYPE_TEXCOORD1,
 -		2, //TYPE_TEXCOORD2,
 -		2, //TYPE_TEXCOORD3,
 -		4, //TYPE_COLOR,
 -		4, //TYPE_EMISSIVE,
 -		3, //TYPE_BINORMAL,
 -		1, //TYPE_WEIGHT,
 -		4, //TYPE_WEIGHT4,
 -		4, //TYPE_CLOTHWEIGHT,
 -		1, //TYPE_TEXTURE_INDEX
 -	};
 -
 -	U32 attrib_type[] =
 -	{
 -		GL_FLOAT, //TYPE_VERTEX,
 -		GL_FLOAT, //TYPE_NORMAL,
 -		GL_FLOAT, //TYPE_TEXCOORD0,
 -		GL_FLOAT, //TYPE_TEXCOORD1,
 -		GL_FLOAT, //TYPE_TEXCOORD2,
 -		GL_FLOAT, //TYPE_TEXCOORD3,
 -		GL_UNSIGNED_BYTE, //TYPE_COLOR,
 -		GL_UNSIGNED_BYTE, //TYPE_EMISSIVE,
 -		GL_FLOAT,   //TYPE_BINORMAL,
 -		GL_FLOAT, //TYPE_WEIGHT,
 -		GL_FLOAT, //TYPE_WEIGHT4,
 -		GL_FLOAT, //TYPE_CLOTHWEIGHT,
 -		GL_FLOAT, //TYPE_TEXTURE_INDEX
 -	};
 -
 -	U32 attrib_normalized[] =
 -	{
 -		GL_FALSE, //TYPE_VERTEX,
 -		GL_FALSE, //TYPE_NORMAL,
 -		GL_FALSE, //TYPE_TEXCOORD0,
 -		GL_FALSE, //TYPE_TEXCOORD1,
 -		GL_FALSE, //TYPE_TEXCOORD2,
 -		GL_FALSE, //TYPE_TEXCOORD3,
 -		GL_TRUE, //TYPE_COLOR,
 -		GL_TRUE, //TYPE_EMISSIVE,
 -		GL_FALSE,   //TYPE_BINORMAL,
 -		GL_FALSE, //TYPE_WEIGHT,
 -		GL_FALSE, //TYPE_WEIGHT4,
 -		GL_FALSE, //TYPE_CLOTHWEIGHT,
 -		GL_FALSE, //TYPE_TEXTURE_INDEX
 -	};
 -
 -	bindGLBuffer(true);
 -	bindGLIndices(true);
 -
 -	for (U32 i = 0; i < TYPE_MAX; ++i)
 -	{
 -		if (mTypeMask & (1 << i))
 -		{
 -			glEnableVertexAttribArrayARB(i);
 -			glVertexAttribPointerARB(i, attrib_size[i], attrib_type[i], attrib_normalized[i], sTypeSize[i], (void*) mOffsets[i]); 
 -		}
 -		else
 -		{
 -			glDisableVertexAttribArrayARB(i);
 -		}
 -	}
 -
 -	//draw a dummy triangle to set index array pointer
 -	//glDrawElements(GL_TRIANGLES, 0, GL_UNSIGNED_SHORT, NULL);
 -
 -	unbind();
 -}
 -
 -void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices)
 -{
 -	llassert(newnverts >= 0);
 -	llassert(newnindices >= 0);
 -
 -	LLMemType mt2(LLMemType::MTYPE_VERTEX_RESIZE_BUFFER);
 -	
 -	updateNumVerts(newnverts);		
 -	updateNumIndices(newnindices);
 -	
 -	if (useVBOs())
 -	{
 -		flush();
 -
 -		if (mGLArray)
 -		{ //if size changed, offsets changed
 -			setupVertexArray();
 -		}
 -	}
 -}
 -
 -bool LLVertexBuffer::useVBOs() const
 -{
 -	//it's generally ineffective to use VBO for things that are streaming on apple
 -	return (mUsage != 0);
 -}
 -
 -//----------------------------------------------------------------------------
 -
 -bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count)
 -{
 -	S32 end = index+count;
 -	S32 region_end = region.mIndex+region.mCount;
 -	
 -	if (end < region.mIndex ||
 -		index > region_end)
 -	{ //gap exists, do not merge
 -		return false;
 -	}
 -
 -	S32 new_end = llmax(end, region_end);
 -	S32 new_index = llmin(index, region.mIndex);
 -	region.mIndex = new_index;
 -	region.mCount = new_end-new_index;
 -	return true;
 -}
 -
 -static LLFastTimer::DeclareTimer FTM_VBO_MAP_BUFFER_RANGE("VBO Map Range");
 -static LLFastTimer::DeclareTimer FTM_VBO_MAP_BUFFER("VBO Map");
 -
 -// Map for data access
 -volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range)
 -{
 -	bindGLBuffer(true);
 -	LLMemType mt2(LLMemType::MTYPE_VERTEX_MAP_BUFFER);
 -	if (mFinal)
 -	{
 -		llerrs << "LLVertexBuffer::mapVeretxBuffer() called on a finalized buffer." << llendl;
 -	}
 -	if (!useVBOs() && !mMappedData && !mMappedIndexData)
 -	{
 -		llerrs << "LLVertexBuffer::mapVertexBuffer() called on unallocated buffer." << llendl;
 -	}
 -		
 -	if (useVBOs())
 -	{
 -		if (!mMappable || gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange)
 -		{
 -			if (count == -1)
 -			{
 -				count = mNumVerts-index;
 -			}
 -
 -			bool mapped = false;
 -			//see if range is already mapped
 -			for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
 -			{
 -				MappedRegion& region = mMappedVertexRegions[i];
 -				if (region.mType == type)
 -				{
 -					if (expand_region(region, index, count))
 -					{
 -						mapped = true;
 -						break;
 -					}
 -				}
 -			}
 -
 -			if (!mapped)
 -			{
 -				//not already mapped, map new region
 -				MappedRegion region(type, mMappable && map_range ? -1 : index, count);
 -				mMappedVertexRegions.push_back(region);
 -			}
 -		}
 -
 -		if (mVertexLocked && map_range)
 -		{
 -			llerrs << "Attempted to map a specific range of a buffer that was already mapped." << llendl;
 -		}
 -
 -		if (!mVertexLocked)
 -		{
 -			LLMemType mt_v(LLMemType::MTYPE_VERTEX_MAP_BUFFER_VERTICES);
 -			mVertexLocked = true;
 -			sMappedCount++;
 -			stop_glerror();	
 -
 -			if(!mMappable)
 -			{
 -				map_range = false;
 -			}
 -			else
 -			{
 -				volatile U8* src = NULL;
 -				waitFence();
 -				if (gGLManager.mHasMapBufferRange)
 -				{
 -					if (map_range)
 -					{
 -#ifdef GL_ARB_map_buffer_range
 -						LLFastTimer t(FTM_VBO_MAP_BUFFER_RANGE);
 -						S32 offset = mOffsets[type] + sTypeSize[type]*index;
 -						S32 length = (sTypeSize[type]*count+0xF) & ~0xF;
 -						src = (U8*) glMapBufferRange(GL_ARRAY_BUFFER_ARB, offset, length, 
 -							GL_MAP_WRITE_BIT | 
 -							GL_MAP_FLUSH_EXPLICIT_BIT | 
 -							GL_MAP_INVALIDATE_RANGE_BIT);
 -#endif
 -					}
 -					else
 -					{
 -#ifdef GL_ARB_map_buffer_range
 -
 -						if (gDebugGL)
 -						{
 -							GLint size = 0;
 -							glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SIZE_ARB, &size);
 -
 -							if (size < mSize)
 -							{
 -								llerrs << "Invalid buffer size." << llendl;
 -							}
 -						}
 -
 -						LLFastTimer t(FTM_VBO_MAP_BUFFER);
 -						src = (U8*) glMapBufferRange(GL_ARRAY_BUFFER_ARB, 0, mSize, 
 -							GL_MAP_WRITE_BIT | 
 -							GL_MAP_FLUSH_EXPLICIT_BIT);
 -#endif
 -					}
 -				}
 -				else if (gGLManager.mHasFlushBufferRange)
 -				{
 -					if (map_range)
 -					{
 -						glBufferParameteriAPPLE(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_FALSE);
 -						glBufferParameteriAPPLE(GL_ARRAY_BUFFER_ARB, GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE);
 -						src = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
 -					}
 -					else
 -					{
 -						src = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
 -					}
 -				}
 -				else
 -				{
 -					map_range = false;
 -					src = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
 -				}
 -
 -				llassert(src != NULL);
 -
 -				mMappedData = LL_NEXT_ALIGNED_ADDRESS<volatile U8>(src);
 -				mAlignedOffset = mMappedData - src;
 -			
 -				stop_glerror();
 -			}
 -				
 -			if (!mMappedData)
 -			{
 -				log_glerror();
 -
 -				//check the availability of memory
 -				LLMemory::logMemoryInfo(true);
 -			
 -				if(mMappable)
 -				{			
 -					//--------------------
 -					//print out more debug info before crash
 -					llinfos << "vertex buffer size: (num verts : num indices) = " << getNumVerts() << " : " << getNumIndices() << llendl;
 -					GLint size;
 -					glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SIZE_ARB, &size);
 -					llinfos << "GL_ARRAY_BUFFER_ARB size is " << size << llendl;
 -					//--------------------
 -
 -					GLint buff;
 -					glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB, &buff);
 -					if ((GLuint)buff != mGLBuffer)
 -					{
 -						llerrs << "Invalid GL vertex buffer bound: " << buff << llendl;
 -					}
 -
 -							
 -					llerrs << "glMapBuffer returned NULL (no vertex data)" << llendl;
 -				}
 -				else
 -				{
 -					llerrs << "memory allocation for vertex data failed." << llendl;
 -				}
 -			}
 -		}
 -	}
 -	else
 -	{
 -		map_range = false;
 -	}
 -	
 -	if (map_range && gGLManager.mHasMapBufferRange && mMappable)
 -	{
 -		return mMappedData;
 -	}
 -	else
 -	{
 -		return mMappedData+mOffsets[type]+sTypeSize[type]*index;
 -	}
 -}
 -
 -
 -static LLFastTimer::DeclareTimer FTM_VBO_MAP_INDEX_RANGE("IBO Map Range");
 -static LLFastTimer::DeclareTimer FTM_VBO_MAP_INDEX("IBO Map");
 -
 -volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range)
 -{
 -	LLMemType mt2(LLMemType::MTYPE_VERTEX_MAP_BUFFER);
 -	bindGLIndices(true);
 -	if (mFinal)
 -	{
 -		llerrs << "LLVertexBuffer::mapIndexBuffer() called on a finalized buffer." << llendl;
 -	}
 -	if (!useVBOs() && !mMappedData && !mMappedIndexData)
 -	{
 -		llerrs << "LLVertexBuffer::mapIndexBuffer() called on unallocated buffer." << llendl;
 -	}
 -
 -	if (useVBOs())
 -	{
 -		if (!mMappable || gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange)
 -		{
 -			if (count == -1)
 -			{
 -				count = mNumIndices-index;
 -			}
 -
 -			bool mapped = false;
 -			//see if range is already mapped
 -			for (U32 i = 0; i < mMappedIndexRegions.size(); ++i)
 -			{
 -				MappedRegion& region = mMappedIndexRegions[i];
 -				if (expand_region(region, index, count))
 -				{
 -					mapped = true;
 -					break;
 -				}
 -			}
 -
 -			if (!mapped)
 -			{
 -				//not already mapped, map new region
 -				MappedRegion region(TYPE_INDEX, mMappable && map_range ? -1 : index, count);
 -				mMappedIndexRegions.push_back(region);
 -			}
 -		}
 -
 -		if (mIndexLocked && map_range)
 -		{
 -			llerrs << "Attempted to map a specific range of a buffer that was already mapped." << llendl;
 -		}
 -
 -		if (!mIndexLocked)
 -		{
 -			LLMemType mt_v(LLMemType::MTYPE_VERTEX_MAP_BUFFER_INDICES);
 -
 -			mIndexLocked = true;
 -			sMappedCount++;
 -			stop_glerror();	
 -
 -			if (gDebugGL && useVBOs())
 -			{
 -				GLint elem = 0;
 -				glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &elem);
 -
 -				if (elem != mGLIndices)
 -				{
 -					llerrs << "Wrong index buffer bound!" << llendl;
 -				}
 -			}
 -
 -			if(!mMappable)
 -			{
 -				map_range = false;
 -			}
 -			else
 -			{
 -				volatile U8* src = NULL;
 -				waitFence();
 -				if (gGLManager.mHasMapBufferRange)
 -				{
 -					if (map_range)
 -					{
 -#ifdef GL_ARB_map_buffer_range
 -						LLFastTimer t(FTM_VBO_MAP_INDEX_RANGE);
 -						S32 offset = sizeof(U16)*index;
 -						S32 length = sizeof(U16)*count;
 -						src = (U8*) glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length, 
 -							GL_MAP_WRITE_BIT | 
 -							GL_MAP_FLUSH_EXPLICIT_BIT | 
 -							GL_MAP_INVALIDATE_RANGE_BIT);
 -#endif
 -					}
 -					else
 -					{
 -#ifdef GL_ARB_map_buffer_range
 -						LLFastTimer t(FTM_VBO_MAP_INDEX);
 -						src = (U8*) glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, sizeof(U16)*mNumIndices, 
 -							GL_MAP_WRITE_BIT | 
 -							GL_MAP_FLUSH_EXPLICIT_BIT);
 -#endif
 -					}
 -				}
 -				else if (gGLManager.mHasFlushBufferRange)
 -				{
 -					if (map_range)
 -					{
 -						glBufferParameteriAPPLE(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_FALSE);
 -						glBufferParameteriAPPLE(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE);
 -						src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
 -					}
 -					else
 -					{
 -						src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
 -					}
 -				}
 -				else
 -				{
 -					LLFastTimer t(FTM_VBO_MAP_INDEX);
 -					map_range = false;
 -					src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
 -				}
 -
 -				llassert(src != NULL);
 -
 -
 -				mMappedIndexData = src; //LL_NEXT_ALIGNED_ADDRESS<U8>(src);
 -				mAlignedIndexOffset = mMappedIndexData - src;
 -				stop_glerror();
 -			}
 -		}
 -
 -		if (!mMappedIndexData)
 -		{
 -			log_glerror();
 -			LLMemory::logMemoryInfo(true);
 -
 -			if(mMappable)
 -			{
 -				GLint buff;
 -				glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff);
 -				if ((GLuint)buff != mGLIndices)
 -				{
 -					llerrs << "Invalid GL index buffer bound: " << buff << llendl;
 -				}
 -
 -				llerrs << "glMapBuffer returned NULL (no index data)" << llendl;
 -			}
 -			else
 -			{
 -				llerrs << "memory allocation for Index data failed. " << llendl;
 -			}
 -		}
 -	}
 -	else
 -	{
 -		map_range = false;
 -	}
 -
 -	if (map_range && gGLManager.mHasMapBufferRange && mMappable)
 -	{
 -		return mMappedIndexData;
 -	}
 -	else
 -	{
 -		return mMappedIndexData + sizeof(U16)*index;
 -	}
 -}
 -
 -static LLFastTimer::DeclareTimer FTM_VBO_UNMAP("VBO Unmap");
 -static LLFastTimer::DeclareTimer FTM_VBO_FLUSH_RANGE("Flush VBO Range");
 -
 -
 -static LLFastTimer::DeclareTimer FTM_IBO_UNMAP("IBO Unmap");
 -static LLFastTimer::DeclareTimer FTM_IBO_FLUSH_RANGE("Flush IBO Range");
 -
 -void LLVertexBuffer::unmapBuffer()
 -{
 -	LLMemType mt2(LLMemType::MTYPE_VERTEX_UNMAP_BUFFER);
 -	if (!useVBOs())
 -	{
 -		return; //nothing to unmap
 -	}
 -
 -	bool updated_all = false;
 -
 -	if (mMappedData && mVertexLocked)
 -	{
 -		LLFastTimer t(FTM_VBO_UNMAP);
 -		bindGLBuffer(true);
 -		updated_all = mIndexLocked; //both vertex and index buffers done updating
 -
 -		if(!mMappable)
 -		{
 -			if (!mMappedVertexRegions.empty())
 -			{
 -				stop_glerror();
 -				for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
 -				{
 -					const MappedRegion& region = mMappedVertexRegions[i];
 -					S32 offset = region.mIndex >= 0 ? mOffsets[region.mType]+sTypeSize[region.mType]*region.mIndex : 0;
 -					S32 length = sTypeSize[region.mType]*region.mCount;
 -					glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, offset, length, (U8*) mMappedData+offset);
 -					stop_glerror();
 -				}
 -
 -				mMappedVertexRegions.clear();
 -			}
 -			else
 -			{
 -				stop_glerror();
 -				glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, getSize(), (U8*) mMappedData);
 -				stop_glerror();
 -			}
 -		}
 -		else
 -		{
 -			if (gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange)
 -			{
 -				if (!mMappedVertexRegions.empty())
 -				{
 -					stop_glerror();
 -					for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
 -					{
 -						const MappedRegion& region = mMappedVertexRegions[i];
 -						S32 offset = region.mIndex >= 0 ? mOffsets[region.mType]+sTypeSize[region.mType]*region.mIndex : 0;
 -						S32 length = sTypeSize[region.mType]*region.mCount;
 -						if (gGLManager.mHasMapBufferRange)
 -						{
 -							LLFastTimer t(FTM_VBO_FLUSH_RANGE);
 -#ifdef GL_ARB_map_buffer_range
 -							glFlushMappedBufferRange(GL_ARRAY_BUFFER_ARB, offset, length);
 -#endif
 -						}
 -						else if (gGLManager.mHasFlushBufferRange)
 -						{
 -							glFlushMappedBufferRangeAPPLE(GL_ARRAY_BUFFER_ARB, offset, length);
 -						}
 -						stop_glerror();
 -					}
 -
 -					mMappedVertexRegions.clear();
 -				}
 -			}
 -			stop_glerror();
 -			glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
 -			stop_glerror();
 -
 -			mMappedData = NULL;
 -		}
 -
 -		mVertexLocked = false;
 -		sMappedCount--;
 -	}
 -	
 -	if (mMappedIndexData && mIndexLocked)
 -	{
 -		LLFastTimer t(FTM_IBO_UNMAP);
 -		bindGLIndices();
 -		if(!mMappable)
 -		{
 -			if (!mMappedIndexRegions.empty())
 -			{
 -				for (U32 i = 0; i < mMappedIndexRegions.size(); ++i)
 -				{
 -					const MappedRegion& region = mMappedIndexRegions[i];
 -					S32 offset = region.mIndex >= 0 ? sizeof(U16)*region.mIndex : 0;
 -					S32 length = sizeof(U16)*region.mCount;
 -					glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length, (U8*) mMappedIndexData+offset);
 -					stop_glerror();
 -				}
 -
 -				mMappedIndexRegions.clear();
 -			}
 -			else
 -			{
 -				stop_glerror();
 -				glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, getIndicesSize(), (U8*) mMappedIndexData);
 -				stop_glerror();
 -			}
 -		}
 -		else
 -		{
 -			if (gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange)
 -			{
 -				if (!mMappedIndexRegions.empty())
 -				{
 -					for (U32 i = 0; i < mMappedIndexRegions.size(); ++i)
 -					{
 -						const MappedRegion& region = mMappedIndexRegions[i];
 -						S32 offset = region.mIndex >= 0 ? sizeof(U16)*region.mIndex : 0;
 -						S32 length = sizeof(U16)*region.mCount;
 -						if (gGLManager.mHasMapBufferRange)
 -						{
 -							LLFastTimer t(FTM_IBO_FLUSH_RANGE);
 -#ifdef GL_ARB_map_buffer_range
 -							glFlushMappedBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length);
 -#endif
 -						}
 -						else if (gGLManager.mHasFlushBufferRange)
 -						{
 -#ifdef GL_APPLE_flush_buffer_range
 -							glFlushMappedBufferRangeAPPLE(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length);
 -#endif
 -						}
 -						stop_glerror();
 -					}
 -
 -					mMappedIndexRegions.clear();
 -				}
 -			}
 -			stop_glerror();
 -			glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);
 -			stop_glerror();
 -
 -			mMappedIndexData = NULL;
 -		}
 -
 -		mIndexLocked = false;
 -		sMappedCount--;
 -	}
 -
 -	if(updated_all)
 -	{
 -		mEmpty = false;
 -	}
 -}
 -
 -//----------------------------------------------------------------------------
 -
 -template <class T,S32 type> struct VertexBufferStrider
 -{
 -	typedef LLStrider<T> strider_t;
 -	static bool get(LLVertexBuffer& vbo, 
 -					strider_t& strider, 
 -					S32 index, S32 count, bool map_range)
 -	{
 -		if (type == LLVertexBuffer::TYPE_INDEX)
 -		{
 -			volatile U8* ptr = vbo.mapIndexBuffer(index, count, map_range);
 -
 -			if (ptr == NULL)
 -			{
 -				llwarns << "mapIndexBuffer failed!" << llendl;
 -				return false;
 -			}
 -
 -			strider = (T*)ptr;
 -			strider.setStride(0);
 -			return true;
 -		}
 -		else if (vbo.hasDataType(type))
 -		{
 -			S32 stride = LLVertexBuffer::sTypeSize[type];
 -
 -			volatile U8* ptr = vbo.mapVertexBuffer(type, index, count, map_range);
 -
 -			if (ptr == NULL)
 -			{
 -				llwarns << "mapVertexBuffer failed!" << llendl;
 -				return false;
 -			}
 -
 -			strider = (T*)ptr;
 -			strider.setStride(stride);
 -			return true;
 -		}
 -		else
 -		{
 -			llerrs << "VertexBufferStrider could not find valid vertex data." << llendl;
 -		}
 -		return false;
 -	}
 -};
 -
 -bool LLVertexBuffer::getVertexStrider(LLStrider<LLVector3>& strider, S32 index, S32 count, bool map_range)
 -{
 -	return VertexBufferStrider<LLVector3,TYPE_VERTEX>::get(*this, strider, index, count, map_range);
 -}
 -bool LLVertexBuffer::getVertexStrider(LLStrider<LLVector4a>& strider, S32 index, S32 count, bool map_range)
 -{
 -	return VertexBufferStrider<LLVector4a,TYPE_VERTEX>::get(*this, strider, index, count, map_range);
 -}
 -bool LLVertexBuffer::getIndexStrider(LLStrider<U16>& strider, S32 index, S32 count, bool map_range)
 -{
 -	return VertexBufferStrider<U16,TYPE_INDEX>::get(*this, strider, index, count, map_range);
 -}
 -bool LLVertexBuffer::getTexCoord0Strider(LLStrider<LLVector2>& strider, S32 index, S32 count, bool map_range)
 -{
 -	return VertexBufferStrider<LLVector2,TYPE_TEXCOORD0>::get(*this, strider, index, count, map_range);
 -}
 -bool LLVertexBuffer::getTexCoord1Strider(LLStrider<LLVector2>& strider, S32 index, S32 count, bool map_range)
 -{
 -	return VertexBufferStrider<LLVector2,TYPE_TEXCOORD1>::get(*this, strider, index, count, map_range);
 -}
 -
 -bool LLVertexBuffer::getNormalStrider(LLStrider<LLVector3>& strider, S32 index, S32 count, bool map_range)
 -{
 -	return VertexBufferStrider<LLVector3,TYPE_NORMAL>::get(*this, strider, index, count, map_range);
 -}
 -bool LLVertexBuffer::getBinormalStrider(LLStrider<LLVector3>& strider, S32 index, S32 count, bool map_range)
 -{
 -	return VertexBufferStrider<LLVector3,TYPE_BINORMAL>::get(*this, strider, index, count, map_range);
 -}
 -bool LLVertexBuffer::getColorStrider(LLStrider<LLColor4U>& strider, S32 index, S32 count, bool map_range)
 -{
 -	return VertexBufferStrider<LLColor4U,TYPE_COLOR>::get(*this, strider, index, count, map_range);
 -}
 -bool LLVertexBuffer::getEmissiveStrider(LLStrider<LLColor4U>& strider, S32 index, S32 count, bool map_range)
 -{
 -	return VertexBufferStrider<LLColor4U,TYPE_EMISSIVE>::get(*this, strider, index, count, map_range);
 -}
 -bool LLVertexBuffer::getWeightStrider(LLStrider<F32>& strider, S32 index, S32 count, bool map_range)
 -{
 -	return VertexBufferStrider<F32,TYPE_WEIGHT>::get(*this, strider, index, count, map_range);
 -}
 -
 -bool LLVertexBuffer::getWeight4Strider(LLStrider<LLVector4>& strider, S32 index, S32 count, bool map_range)
 -{
 -	return VertexBufferStrider<LLVector4,TYPE_WEIGHT4>::get(*this, strider, index, count, map_range);
 -}
 -
 -bool LLVertexBuffer::getClothWeightStrider(LLStrider<LLVector4>& strider, S32 index, S32 count, bool map_range)
 -{
 -	return VertexBufferStrider<LLVector4,TYPE_CLOTHWEIGHT>::get(*this, strider, index, count, map_range);
 -}
 -
 -//----------------------------------------------------------------------------
 -
 -static LLFastTimer::DeclareTimer FTM_BIND_GL_ARRAY("Bind Array");
 -bool LLVertexBuffer::bindGLArray()
 -{
 -	if (mGLArray && sGLRenderArray != mGLArray)
 -	{
 -		{
 -			LLFastTimer t(FTM_BIND_GL_ARRAY);
 -#if GL_ARB_vertex_array_object
 -			glBindVertexArray(mGLArray);
 -#endif
 -			sGLRenderArray = mGLArray;
 -		}
 -
 -		//really shouldn't be necessary, but some drivers don't properly restore the
 -		//state of GL_ELEMENT_ARRAY_BUFFER_BINDING
 -		bindGLIndices();
 -		
 -		return true;
 -	}
 -		
 -	return false;
 -}
 -
 -static LLFastTimer::DeclareTimer FTM_BIND_GL_BUFFER("Bind Buffer");
 -
 -bool LLVertexBuffer::bindGLBuffer(bool force_bind)
 -{
 -	bindGLArray();
 -
 -	bool ret = false;
 -
 -	if (useVBOs() && (force_bind || (mGLBuffer && (mGLBuffer != sGLRenderBuffer || !sVBOActive))))
 -	{
 -		LLFastTimer t(FTM_BIND_GL_BUFFER);
 -		/*if (sMapped)
 -		{
 -			llerrs << "VBO bound while another VBO mapped!" << llendl;
 -		}*/
 -		glBindBufferARB(GL_ARRAY_BUFFER_ARB, mGLBuffer);
 -		sGLRenderBuffer = mGLBuffer;
 -		sBindCount++;
 -		sVBOActive = true;
 -
 -		if (mGLArray)
 -		{
 -			llassert(sGLRenderArray == mGLArray);
 -			//mCachedRenderBuffer = mGLBuffer;
 -		}
 -
 -		ret = true;
 -	}
 -
 -	return ret;
 -}
 -
 -static LLFastTimer::DeclareTimer FTM_BIND_GL_INDICES("Bind Indices");
 -
 -bool LLVertexBuffer::bindGLIndices(bool force_bind)
 -{
 -	bindGLArray();
 -
 -	bool ret = false;
 -	if (useVBOs() && (force_bind || (mGLIndices && (mGLIndices != sGLRenderIndices || !sIBOActive))))
 -	{
 -		LLFastTimer t(FTM_BIND_GL_INDICES);
 -		/*if (sMapped)
 -		{
 -			llerrs << "VBO bound while another VBO mapped!" << llendl;
 -		}*/
 -		glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, mGLIndices);
 -		sGLRenderIndices = mGLIndices;
 -		stop_glerror();
 -		sBindCount++;
 -		sIBOActive = true;
 -		ret = true;
 -	}
 -
 -	return ret;
 -}
 -
 -void LLVertexBuffer::flush()
 -{
 -	if (useVBOs())
 -	{
 -		unmapBuffer();
 -	}
 -}
 -
 -// Set for rendering
 -void LLVertexBuffer::setBuffer(U32 data_mask)
 -{
 -	flush();
 -
 -	LLMemType mt2(LLMemType::MTYPE_VERTEX_SET_BUFFER);
 -	//set up pointers if the data mask is different ...
 -	bool setup = (sLastMask != data_mask);
 -
 -	if (gDebugGL && data_mask != 0)
 -	{ //make sure data requirements are fulfilled
 -		LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
 -		if (shader)
 -		{
 -			U32 required_mask = 0;
 -			for (U32 i = 0; i < LLVertexBuffer::TYPE_TEXTURE_INDEX; ++i)
 -			{
 -				if (shader->getAttribLocation(i) > -1)
 -				{
 -					U32 required = 1 << i;
 -					if ((data_mask & required) == 0)
 -					{
 -						llwarns << "Missing attribute: " << LLShaderMgr::instance()->mReservedAttribs[i] << llendl;
 -					}
 -
 -					required_mask |= required;
 -				}
 -			}
 -
 -			if ((data_mask & required_mask) != required_mask)
 -			{
 -				llerrs << "Shader consumption mismatches data provision." << llendl;
 -			}
 -		}
 -	}
 -
 -	if (useVBOs())
 -	{
 -		if (mGLArray)
 -		{
 -			bindGLArray();
 -			setup = false; //do NOT perform pointer setup if using VAO
 -		}
 -		else
 -		{
 -			const bool bindBuffer = bindGLBuffer();
 -			const bool bindIndices = bindGLIndices();
 -			
 -			setup = setup || bindBuffer || bindIndices;
 -		}
 -
 -		bool error = false;
 -		if (gDebugGL && !mGLArray)
 -		{
 -			GLint buff;
 -			glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB, &buff);
 -			if ((GLuint)buff != mGLBuffer)
 -			{
 -				if (gDebugSession)
 -				{
 -					error = true;
 -					gFailLog << "Invalid GL vertex buffer bound: " << buff << std::endl;
 -				}
 -				else
 -				{
 -					llerrs << "Invalid GL vertex buffer bound: " << buff << llendl;
 -				}
 -			}
 -
 -			if (mGLIndices)
 -			{
 -				glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff);
 -				if ((GLuint)buff != mGLIndices)
 -				{
 -					if (gDebugSession)
 -					{
 -						error = true;
 -						gFailLog << "Invalid GL index buffer bound: " << buff <<  std::endl;
 -					}
 -					else
 -					{
 -						llerrs << "Invalid GL index buffer bound: " << buff << llendl;
 -					}
 -				}
 -			}
 -		}
 -
 -		
 -	}
 -	else
 -	{	
 -		if (sGLRenderArray)
 -		{
 -#if GL_ARB_vertex_array_object
 -			glBindVertexArray(0);
 -#endif
 -			sGLRenderArray = 0;
 -			sGLRenderIndices = 0;
 -			sIBOActive = false;
 -		}
 -
 -		if (mGLBuffer)
 -		{
 -			if (sVBOActive)
 -			{
 -				glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
 -				sBindCount++;
 -				sVBOActive = false;
 -				setup = true; // ... or a VBO is deactivated
 -			}
 -			if (sGLRenderBuffer != mGLBuffer)
 -			{
 -				sGLRenderBuffer = mGLBuffer;
 -				setup = true; // ... or a client memory pointer changed
 -			}
 -		}
 -		if (mGLIndices)
 -		{
 -			if (sIBOActive)
 -			{
 -				glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
 -				sBindCount++;
 -				sIBOActive = false;
 -			}
 -			
 -			sGLRenderIndices = mGLIndices;
 -		}
 -	}
 -
 -	if (!mGLArray)
 -	{
 -		setupClientArrays(data_mask);
 -	}
 -			
 -	if (mGLBuffer)
 -	{
 -		if (data_mask && setup)
 -		{
 -			setupVertexBuffer(data_mask); // subclass specific setup (virtual function)
 -			sSetCount++;
 -		}
 -	}
 -}
 -
 -// virtual (default)
 -void LLVertexBuffer::setupVertexBuffer(U32 data_mask)
 -{
 -	LLMemType mt2(LLMemType::MTYPE_VERTEX_SETUP_VERTEX_BUFFER);
 -	stop_glerror();
 -	volatile U8* base = useVBOs() ? (U8*) mAlignedOffset : mMappedData;
 -
 -	/*if ((data_mask & mTypeMask) != data_mask)
 -	{
 -		llerrs << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << llendl;
 -	}*/
 -
 -	if (LLGLSLShader::sNoFixedFunction)
 -	{
 -		if (data_mask & MAP_NORMAL)
 -		{
 -			S32 loc = TYPE_NORMAL;
 -			void* ptr = (void*)(base + mOffsets[TYPE_NORMAL]);
 -			glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_NORMAL], ptr);
 -		}
 -		if (data_mask & MAP_TEXCOORD3)
 -		{
 -			S32 loc = TYPE_TEXCOORD3;
 -			void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD3]);
 -			glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], ptr);
 -		}
 -		if (data_mask & MAP_TEXCOORD2)
 -		{
 -			S32 loc = TYPE_TEXCOORD2;
 -			void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD2]);
 -			glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], ptr);
 -		}
 -		if (data_mask & MAP_TEXCOORD1)
 -		{
 -			S32 loc = TYPE_TEXCOORD1;
 -			void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD1]);
 -			glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], ptr);
 -		}
 -		if (data_mask & MAP_BINORMAL)
 -		{
 -			S32 loc = TYPE_BINORMAL;
 -			void* ptr = (void*)(base + mOffsets[TYPE_BINORMAL]);
 -			glVertexAttribPointerARB(loc, 3,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_BINORMAL], ptr);
 -		}
 -		if (data_mask & MAP_TEXCOORD0)
 -		{
 -			S32 loc = TYPE_TEXCOORD0;
 -			void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD0]);
 -			glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], ptr);
 -		}
 -		if (data_mask & MAP_COLOR)
 -		{
 -			S32 loc = TYPE_COLOR;
 -			void* ptr = (void*)(base + mOffsets[TYPE_COLOR]);
 -			glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_COLOR], ptr);
 -		}
 -		if (data_mask & MAP_EMISSIVE)
 -		{
 -			S32 loc = TYPE_EMISSIVE;
 -			void* ptr = (void*)(base + mOffsets[TYPE_EMISSIVE]);
 -			glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_EMISSIVE], ptr);
 -		}
 -		if (data_mask & MAP_WEIGHT)
 -		{
 -			S32 loc = TYPE_WEIGHT;
 -			void* ptr = (void*)(base + mOffsets[TYPE_WEIGHT]);
 -			glVertexAttribPointerARB(loc, 1, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT], ptr);
 -		}
 -		if (data_mask & MAP_WEIGHT4)
 -		{
 -			S32 loc = TYPE_WEIGHT4;
 -			void* ptr = (void*)(base+mOffsets[TYPE_WEIGHT4]);
 -			glVertexAttribPointerARB(loc, 4, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT4], ptr);
 -		}
 -		if (data_mask & MAP_CLOTHWEIGHT)
 -		{
 -			S32 loc = TYPE_CLOTHWEIGHT;
 -			void* ptr = (void*)(base + mOffsets[TYPE_CLOTHWEIGHT]);
 -			glVertexAttribPointerARB(loc, 4, GL_FLOAT, GL_TRUE,  LLVertexBuffer::sTypeSize[TYPE_CLOTHWEIGHT], ptr);
 -		}
 -		if (data_mask & MAP_TEXTURE_INDEX)
 -		{
 -			S32 loc = TYPE_TEXTURE_INDEX;
 -			void *ptr = (void*) (base + mOffsets[TYPE_VERTEX] + 12);
 -			glVertexAttribPointerARB(loc, 1, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);
 -		}
 -		if (data_mask & MAP_VERTEX)
 -		{
 -			S32 loc = TYPE_VERTEX;
 -			void* ptr = (void*)(base + mOffsets[TYPE_VERTEX]);
 -			glVertexAttribPointerARB(loc, 3,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);
 -		}	
 -	}	
 -	else
 -	{
 -		if (data_mask & MAP_NORMAL)
 -		{
 -			glNormalPointer(GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_NORMAL], (void*)(base + mOffsets[TYPE_NORMAL]));
 -		}
 -		if (data_mask & MAP_TEXCOORD3)
 -		{
 -			glClientActiveTextureARB(GL_TEXTURE3_ARB);
 -			glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], (void*)(base + mOffsets[TYPE_TEXCOORD3]));
 -			glClientActiveTextureARB(GL_TEXTURE0_ARB);
 -		}
 -		if (data_mask & MAP_TEXCOORD2)
 -		{
 -			glClientActiveTextureARB(GL_TEXTURE2_ARB);
 -			glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], (void*)(base + mOffsets[TYPE_TEXCOORD2]));
 -			glClientActiveTextureARB(GL_TEXTURE0_ARB);
 -		}
 -		if (data_mask & MAP_TEXCOORD1)
 -		{
 -			glClientActiveTextureARB(GL_TEXTURE1_ARB);
 -			glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], (void*)(base + mOffsets[TYPE_TEXCOORD1]));
 -			glClientActiveTextureARB(GL_TEXTURE0_ARB);
 -		}
 -		if (data_mask & MAP_BINORMAL)
 -		{
 -			glClientActiveTextureARB(GL_TEXTURE2_ARB);
 -			glTexCoordPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_BINORMAL], (void*)(base + mOffsets[TYPE_BINORMAL]));
 -			glClientActiveTextureARB(GL_TEXTURE0_ARB);
 -		}
 -		if (data_mask & MAP_TEXCOORD0)
 -		{
 -			glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0]));
 -		}
 -		if (data_mask & MAP_COLOR)
 -		{
 -			glColorPointer(4, GL_UNSIGNED_BYTE, LLVertexBuffer::sTypeSize[TYPE_COLOR], (void*)(base + mOffsets[TYPE_COLOR]));
 -		}
 -		if (data_mask & MAP_VERTEX)
 -		{
 -			glVertexPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], (void*)(base + 0));
 -		}	
 -	}
 -
 -	llglassertok();
 -}
 -
 -LLVertexBuffer::MappedRegion::MappedRegion(S32 type, S32 index, S32 count)
 -: mType(type), mIndex(index), mCount(count)
 -{ 
 -	llassert(mType == LLVertexBuffer::TYPE_INDEX || 
 -			mType < LLVertexBuffer::TYPE_TEXTURE_INDEX);
 -}	
 -
 -
 +/**  + * @file llvertexbuffer.cpp + * @brief LLVertexBuffer implementation + * + * $LicenseInfo:firstyear=2003&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + *  + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include <boost/static_assert.hpp> +#include "llsys.h" +#include "llvertexbuffer.h" +// #include "llrender.h" +#include "llglheaders.h" +#include "llmemtype.h" +#include "llrender.h" +#include "llvector4a.h" +#include "llshadermgr.h" +#include "llglslshader.h" +#include "llmemory.h" + +//Next Highest Power Of Two +//helper function, returns first number > v that is a power of 2, or v if v is already a power of 2 +U32 nhpo2(U32 v) +{ +	U32 r = 1; +	while (r < v) { +		r *= 2; +	} +	return r; +} + + +//============================================================================ + +//static +LLVBOPool LLVertexBuffer::sStreamVBOPool(GL_STREAM_DRAW_ARB, GL_ARRAY_BUFFER_ARB); +LLVBOPool LLVertexBuffer::sDynamicVBOPool(GL_DYNAMIC_DRAW_ARB, GL_ARRAY_BUFFER_ARB); +LLVBOPool LLVertexBuffer::sStreamIBOPool(GL_STREAM_DRAW_ARB, GL_ELEMENT_ARRAY_BUFFER_ARB); +LLVBOPool LLVertexBuffer::sDynamicIBOPool(GL_DYNAMIC_DRAW_ARB, GL_ELEMENT_ARRAY_BUFFER_ARB); +U32 LLVBOPool::sBytesPooled = 0; + +LLPrivateMemoryPool* LLVertexBuffer::sPrivatePoolp = NULL; +U32 LLVertexBuffer::sBindCount = 0; +U32 LLVertexBuffer::sSetCount = 0; +S32 LLVertexBuffer::sCount = 0; +S32 LLVertexBuffer::sGLCount = 0; +S32 LLVertexBuffer::sMappedCount = 0; +bool LLVertexBuffer::sDisableVBOMapping = false; +bool LLVertexBuffer::sEnableVBOs = true; +U32 LLVertexBuffer::sGLRenderBuffer = 0; +U32 LLVertexBuffer::sGLRenderArray = 0; +U32 LLVertexBuffer::sGLRenderIndices = 0; +U32 LLVertexBuffer::sLastMask = 0; +bool LLVertexBuffer::sVBOActive = false; +bool LLVertexBuffer::sIBOActive = false; +U32 LLVertexBuffer::sAllocatedBytes = 0; +bool LLVertexBuffer::sMapped = false; +bool LLVertexBuffer::sUseStreamDraw = true; +bool LLVertexBuffer::sUseVAO = false; +bool LLVertexBuffer::sPreferStreamDraw = false; + +const U32 FENCE_WAIT_TIME_NANOSECONDS = 10000;  //1 ms + +class LLGLSyncFence : public LLGLFence +{ +public: +#ifdef GL_ARB_sync +	GLsync mSync; +#endif +	 +	LLGLSyncFence() +	{ +#ifdef GL_ARB_sync +		mSync = 0; +#endif +	} + +	virtual ~LLGLSyncFence() +	{ +#ifdef GL_ARB_sync +		if (mSync) +		{ +			glDeleteSync(mSync); +		} +#endif +	} + +	void placeFence() +	{ +#ifdef GL_ARB_sync +		if (mSync) +		{ +			glDeleteSync(mSync); +		} +		mSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); +#endif +	} + +	void wait() +	{ +#ifdef GL_ARB_sync +		if (mSync) +		{ +			while (glClientWaitSync(mSync, 0, FENCE_WAIT_TIME_NANOSECONDS) == GL_TIMEOUT_EXPIRED) +			{ //track the number of times we've waited here +				static S32 waits = 0; +				waits++; +			} +		} +#endif +	} + + +}; + + +//which power of 2 is i? +//assumes i is a power of 2 > 0 +U32 wpo2(U32 i) +{ +	llassert(i > 0); +	llassert(nhpo2(i) == i); + +	U32 r = 0; + +	while (i >>= 1) ++r; + +	return r; +} + +volatile U8* LLVBOPool::allocate(U32& name, U32 size) +{ +	llassert(nhpo2(size) == size); + +	U32 i = wpo2(size); + +	if (mFreeList.size() <= i) +	{ +		mFreeList.resize(i+1); +	} + +	volatile U8* ret = NULL; + +	if (mFreeList[i].empty()) +	{ +		//make a new buffer +		glGenBuffersARB(1, &name); +		glBindBufferARB(mType, name); +		LLVertexBuffer::sAllocatedBytes += size; + +		if (LLVertexBuffer::sDisableVBOMapping || mUsage != GL_DYNAMIC_DRAW_ARB) +		{ +			glBufferDataARB(mType, size, 0, mUsage); +			ret = (U8*) ll_aligned_malloc_16(size); +		} +		else +		{ //always use a true hint of static draw when allocating non-client-backed buffers +			glBufferDataARB(mType, size, 0, GL_STATIC_DRAW_ARB); +		} + +		glBindBufferARB(mType, 0); +	} +	else +	{ +		name = mFreeList[i].front().mGLName; +		ret = mFreeList[i].front().mClientData; + +		sBytesPooled -= size; + +		mFreeList[i].pop_front(); +	} + +	return ret; +} + +void LLVBOPool::release(U32 name, volatile U8* buffer, U32 size) +{ +	llassert(nhpo2(size) == size); + +	U32 i = wpo2(size); + +	llassert(mFreeList.size() > i); + +	Record rec; +	rec.mGLName = name; +	rec.mClientData = buffer; +	 +	if (buffer == NULL) +	{ +		glDeleteBuffersARB(1, &rec.mGLName); +	} +	else +	{ +		sBytesPooled += size; +		mFreeList[i].push_back(rec); +	} +} + +void LLVBOPool::cleanup() +{ +	U32 size = 1; + +	for (U32 i = 0; i < mFreeList.size(); ++i) +	{ +		record_list_t& l = mFreeList[i]; + +		while (!l.empty()) +		{ +			Record& r = l.front(); + +			glDeleteBuffersARB(1, &r.mGLName); + +			if (r.mClientData) +			{ +				ll_aligned_free_16((void*) r.mClientData); +			} + +			l.pop_front(); + +			LLVertexBuffer::sAllocatedBytes -= size; +			sBytesPooled -= size; +		} + +		size *= 2; +	} +} + + +//NOTE: each component must be AT LEAST 4 bytes in size to avoid a performance penalty on AMD hardware +S32 LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_MAX] = +{ +	sizeof(LLVector4), // TYPE_VERTEX, +	sizeof(LLVector4), // TYPE_NORMAL, +	sizeof(LLVector2), // TYPE_TEXCOORD0, +	sizeof(LLVector2), // TYPE_TEXCOORD1, +	sizeof(LLVector2), // TYPE_TEXCOORD2, +	sizeof(LLVector2), // TYPE_TEXCOORD3, +	sizeof(LLColor4U), // TYPE_COLOR, +	sizeof(LLColor4U), // TYPE_EMISSIVE, only alpha is used currently +	sizeof(LLVector4), // TYPE_BINORMAL, +	sizeof(F32),	   // TYPE_WEIGHT, +	sizeof(LLVector4), // TYPE_WEIGHT4, +	sizeof(LLVector4), // TYPE_CLOTHWEIGHT, +	sizeof(LLVector4), // TYPE_TEXTURE_INDEX (actually exists as position.w), no extra data, but stride is 16 bytes +}; + +U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] =  +{ +	GL_TRIANGLES, +	GL_TRIANGLE_STRIP, +	GL_TRIANGLE_FAN, +	GL_POINTS, +	GL_LINES, +	GL_LINE_STRIP, +	GL_QUADS, +	GL_LINE_LOOP, +}; + + +//static +void LLVertexBuffer::setupClientArrays(U32 data_mask) +{ +	if (sLastMask != data_mask) +	{ +		bool error = false; + +		if (LLGLSLShader::sNoFixedFunction) +		{ +			for (U32 i = 0; i < TYPE_MAX; ++i) +			{ +				S32 loc = i; +										 +				U32 mask = 1 << i; + +				if (sLastMask & (1 << i)) +				{ //was enabled +					if (!(data_mask & mask)) +					{ //needs to be disabled +						glDisableVertexAttribArrayARB(loc); +					} +				} +				else  +				{	//was disabled +					if (data_mask & mask) +					{ //needs to be enabled +						glEnableVertexAttribArrayARB(loc); +					} +				} +			} +		} +		else +		{ + +			GLenum array[] = +			{ +				GL_VERTEX_ARRAY, +				GL_NORMAL_ARRAY, +				GL_TEXTURE_COORD_ARRAY, +				GL_COLOR_ARRAY, +			}; + +			GLenum mask[] =  +			{ +				MAP_VERTEX, +				MAP_NORMAL, +				MAP_TEXCOORD0, +				MAP_COLOR +			}; + + + +			for (U32 i = 0; i < 4; ++i) +			{ +				if (sLastMask & mask[i]) +				{ //was enabled +					if (!(data_mask & mask[i])) +					{ //needs to be disabled +						glDisableClientState(array[i]); +					} +					else if (gDebugGL) +					{ //needs to be enabled, make sure it was (DEBUG) +						if (!glIsEnabled(array[i])) +						{ +							if (gDebugSession) +							{ +								error = true; +								gFailLog << "Bad client state! " << array[i] << " disabled." << std::endl; +							} +							else +							{ +								llerrs << "Bad client state! " << array[i] << " disabled." << llendl; +							} +						} +					} +				} +				else  +				{	//was disabled +					if (data_mask & mask[i]) +					{ //needs to be enabled +						glEnableClientState(array[i]); +					} +					else if (gDebugGL && glIsEnabled(array[i])) +					{ //needs to be disabled, make sure it was (DEBUG TEMPORARY) +						if (gDebugSession) +						{ +							error = true; +							gFailLog << "Bad client state! " << array[i] << " enabled." << std::endl; +						} +						else +						{ +							llerrs << "Bad client state! " << array[i] << " enabled." << llendl; +						} +					} +				} +			} +		 +			U32 map_tc[] =  +			{ +				MAP_TEXCOORD1, +				MAP_TEXCOORD2, +				MAP_TEXCOORD3 +			}; + +			for (U32 i = 0; i < 3; i++) +			{ +				if (sLastMask & map_tc[i]) +				{ +					if (!(data_mask & map_tc[i])) +					{ //disable +						glClientActiveTextureARB(GL_TEXTURE1_ARB+i); +						glDisableClientState(GL_TEXTURE_COORD_ARRAY); +						glClientActiveTextureARB(GL_TEXTURE0_ARB); +					} +				} +				else if (data_mask & map_tc[i]) +				{ +					glClientActiveTextureARB(GL_TEXTURE1_ARB+i); +					glEnableClientState(GL_TEXTURE_COORD_ARRAY); +					glClientActiveTextureARB(GL_TEXTURE0_ARB); +				} +			} + +			if (sLastMask & MAP_BINORMAL) +			{ +				if (!(data_mask & MAP_BINORMAL)) +				{ +					glClientActiveTextureARB(GL_TEXTURE2_ARB); +					glDisableClientState(GL_TEXTURE_COORD_ARRAY); +					glClientActiveTextureARB(GL_TEXTURE0_ARB); +				} +			} +			else if (data_mask & MAP_BINORMAL) +			{ +				glClientActiveTextureARB(GL_TEXTURE2_ARB); +				glEnableClientState(GL_TEXTURE_COORD_ARRAY); +				glClientActiveTextureARB(GL_TEXTURE0_ARB); +			} +		} +				 +		sLastMask = data_mask; +	} +} + +//static +void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm) +{ +	llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL); +	gGL.syncMatrices(); + +	U32 count = pos.size(); +	llassert_always(norm.size() >= pos.size()); +	llassert_always(count > 0); + +	unbind(); +	 +	setupClientArrays(MAP_VERTEX | MAP_NORMAL); + +	LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + +	if (shader) +	{ +		S32 loc = LLVertexBuffer::TYPE_VERTEX; +		if (loc > -1) +		{ +			glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 0, pos[0].mV); +		} +		loc = LLVertexBuffer::TYPE_NORMAL; +		if (loc > -1) +		{ +			glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 0, norm[0].mV); +		} +	} +	else +	{ +		glVertexPointer(3, GL_FLOAT, 0, pos[0].mV); +		glNormalPointer(GL_FLOAT, 0, norm[0].mV); +	} + +	glDrawArrays(sGLMode[mode], 0, count); +} + +//static +void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp) +{ +	llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL); + +	gGL.syncMatrices(); + +	U32 mask = LLVertexBuffer::MAP_VERTEX; +	if (tc) +	{ +		mask = mask | LLVertexBuffer::MAP_TEXCOORD0; +	} + +	unbind(); +	 +	setupClientArrays(mask); + +	if (LLGLSLShader::sNoFixedFunction) +	{ +		S32 loc = LLVertexBuffer::TYPE_VERTEX; +		glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 16, pos); + +		if (tc) +		{ +			loc = LLVertexBuffer::TYPE_TEXCOORD0; +			glVertexAttribPointerARB(loc, 2, GL_FLOAT, GL_FALSE, 0, tc); +		} +	} +	else +	{ +		glTexCoordPointer(2, GL_FLOAT, 0, tc); +		glVertexPointer(3, GL_FLOAT, 16, pos); +	} + +	glDrawElements(sGLMode[mode], num_indices, GL_UNSIGNED_SHORT, indicesp); +} + +void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_offset) const +{ +	if (start >= (U32) mNumVerts || +	    end >= (U32) mNumVerts) +	{ +		llerrs << "Bad vertex buffer draw range: [" << start << ", " << end << "] vs " << mNumVerts << llendl; +	} + +	llassert(mNumIndices >= 0); + +	if (indices_offset >= (U32) mNumIndices || +	    indices_offset + count > (U32) mNumIndices) +	{ +		llerrs << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << llendl; +	} + +	if (gDebugGL && !useVBOs()) +	{ +		U16* idx = ((U16*) getIndicesPointer())+indices_offset; +		for (U32 i = 0; i < count; ++i) +		{ +			if (idx[i] < start || idx[i] > end) +			{ +				llerrs << "Index out of range: " << idx[i] << " not in [" << start << ", " << end << "]" << llendl; +			} +		} + +		LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + +		if (shader && shader->mFeatures.mIndexedTextureChannels > 1) +		{ +			LLStrider<LLVector4a> v; +			//hack to get non-const reference +			LLVertexBuffer* vb = (LLVertexBuffer*) this; +			vb->getVertexStrider(v); + +			for (U32 i = start; i < end; i++) +			{ +				S32 idx = (S32) (v[i][3]+0.25f); +				if (idx < 0 || idx >= shader->mFeatures.mIndexedTextureChannels) +				{ +					llerrs << "Bad texture index found in vertex data stream." << llendl; +				} +			} +		} +	} +} + +void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const +{ +	validateRange(start, end, count, indices_offset); +	mMappable = false; +	gGL.syncMatrices(); + +	llassert(mNumVerts >= 0); +	llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL); + +	if (mGLArray) +	{ +		if (mGLArray != sGLRenderArray) +		{ +			llerrs << "Wrong vertex array bound." << llendl; +		} +	} +	else +	{ +		if (mGLIndices != sGLRenderIndices) +		{ +			llerrs << "Wrong index buffer bound." << llendl; +		} + +		if (mGLBuffer != sGLRenderBuffer) +		{ +			llerrs << "Wrong vertex buffer bound." << llendl; +		} +	} + +	if (gDebugGL && !mGLArray && useVBOs()) +	{ +		GLint elem = 0; +		glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &elem); + +		if (elem != mGLIndices) +		{ +			llerrs << "Wrong index buffer bound!" << llendl; +		} +	} + +	if (mode >= LLRender::NUM_MODES) +	{ +		llerrs << "Invalid draw mode: " << mode << llendl; +		return; +	} + +	U16* idx = ((U16*) getIndicesPointer())+indices_offset; + +	stop_glerror(); +	glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT,  +		idx); +	stop_glerror(); +	placeFence(); +} + +void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const +{ +	llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL); +	mMappable = false; +	gGL.syncMatrices(); + +	llassert(mNumIndices >= 0); +	if (indices_offset >= (U32) mNumIndices || +	    indices_offset + count > (U32) mNumIndices) +	{ +		llerrs << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << llendl; +	} + +	if (mGLArray) +	{ +		if (mGLArray != sGLRenderArray) +		{ +			llerrs << "Wrong vertex array bound." << llendl; +		} +	} +	else +	{ +		if (mGLIndices != sGLRenderIndices) +		{ +			llerrs << "Wrong index buffer bound." << llendl; +		} + +		if (mGLBuffer != sGLRenderBuffer) +		{ +			llerrs << "Wrong vertex buffer bound." << llendl; +		} +	} + +	if (mode >= LLRender::NUM_MODES) +	{ +		llerrs << "Invalid draw mode: " << mode << llendl; +		return; +	} + +	stop_glerror(); +	glDrawElements(sGLMode[mode], count, GL_UNSIGNED_SHORT, +		((U16*) getIndicesPointer()) + indices_offset); +	stop_glerror(); +	placeFence(); +} + +void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const +{ +	llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL); +	mMappable = false; +	gGL.syncMatrices(); +	 +	llassert(mNumVerts >= 0); +	if (first >= (U32) mNumVerts || +	    first + count > (U32) mNumVerts) +	{ +		llerrs << "Bad vertex buffer draw range: [" << first << ", " << first+count << "]" << llendl; +	} + +	if (mGLArray) +	{ +		if (mGLArray != sGLRenderArray) +		{ +			llerrs << "Wrong vertex array bound." << llendl; +		} +	} +	else +	{ +		if (mGLBuffer != sGLRenderBuffer || useVBOs() != sVBOActive) +		{ +			llerrs << "Wrong vertex buffer bound." << llendl; +		} +	} + +	if (mode >= LLRender::NUM_MODES) +	{ +		llerrs << "Invalid draw mode: " << mode << llendl; +		return; +	} + +	stop_glerror(); +	glDrawArrays(sGLMode[mode], first, count); +	stop_glerror(); +	placeFence(); +} + +//static +void LLVertexBuffer::initClass(bool use_vbo, bool no_vbo_mapping) +{ +	sEnableVBOs = use_vbo && gGLManager.mHasVertexBufferObject; +	sDisableVBOMapping = sEnableVBOs && no_vbo_mapping; + +	if (!sPrivatePoolp) +	{  +		sPrivatePoolp = LLPrivateMemoryPoolManager::getInstance()->newPool(LLPrivateMemoryPool::STATIC); +	} +} + +//static  +void LLVertexBuffer::unbind() +{ +	if (sGLRenderArray) +	{ +#if GL_ARB_vertex_array_object +		glBindVertexArray(0); +#endif +		sGLRenderArray = 0; +		sGLRenderIndices = 0; +		sIBOActive = false; +	} + +	if (sVBOActive) +	{ +		glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); +		sVBOActive = false; +	} +	if (sIBOActive) +	{ +		glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); +		sIBOActive = false; +	} + +	sGLRenderBuffer = 0; +	sGLRenderIndices = 0; + +	setupClientArrays(0); +} + +//static +void LLVertexBuffer::cleanupClass() +{ +	LLMemType mt2(LLMemType::MTYPE_VERTEX_CLEANUP_CLASS); +	unbind(); +	 +	sStreamIBOPool.cleanup(); +	sDynamicIBOPool.cleanup(); +	sStreamVBOPool.cleanup(); +	sDynamicVBOPool.cleanup(); + +	if(sPrivatePoolp) +	{ +		LLPrivateMemoryPoolManager::getInstance()->deletePool(sPrivatePoolp); +		sPrivatePoolp = NULL; +	} +} + +//---------------------------------------------------------------------------- + +S32 LLVertexBuffer::determineUsage(S32 usage) +{ +	S32 ret_usage = usage; + +	if (!sEnableVBOs) +	{ +		ret_usage = 0; +	} +	 +	if (ret_usage == GL_STREAM_DRAW_ARB && !sUseStreamDraw) +	{ +		ret_usage = 0; +	} +	 +	if (ret_usage == GL_DYNAMIC_DRAW_ARB && sPreferStreamDraw) +	{ +		ret_usage = GL_STREAM_DRAW_ARB; +	} +	 +	if (ret_usage == 0 && LLRender::sGLCoreProfile) +	{ //MUST use VBOs for all rendering +		ret_usage = GL_STREAM_DRAW_ARB; +	} +	 +	if (ret_usage && ret_usage != GL_STREAM_DRAW_ARB) +	{ //only stream_draw and dynamic_draw are supported when using VBOs, dynamic draw is the default +		if (sDisableVBOMapping) +		{ //always use stream draw if VBO mapping is disabled +			ret_usage = GL_STREAM_DRAW_ARB; +		} +		else +		{ +			ret_usage = GL_DYNAMIC_DRAW_ARB; +		} +	} +	 +	return ret_usage; +} + +LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) : +	LLRefCount(), + +	mNumVerts(0), +	mNumIndices(0), +	mAlignedOffset(0), +	mAlignedIndexOffset(0), +	mSize(0), +	mIndicesSize(0), +	mTypeMask(typemask), +	mUsage(LLVertexBuffer::determineUsage(usage)), +	mGLBuffer(0), +	mGLIndices(0), +	mGLArray(0), +	mMappedData(NULL), +	mMappedIndexData(NULL), +	mMappedDataUsingVBOs(false), +	mMappedIndexDataUsingVBOs(false), +	mVertexLocked(false), +	mIndexLocked(false), +	mFinal(false), +	mEmpty(true), +	mMappable(false), +	mFence(NULL) +{ +	LLMemType mt2(LLMemType::MTYPE_VERTEX_CONSTRUCTOR); + +	mMappable = (mUsage == GL_DYNAMIC_DRAW_ARB && !sDisableVBOMapping); + +	//zero out offsets +	for (U32 i = 0; i < TYPE_MAX; i++) +	{ +		mOffsets[i] = 0; +	} + +	sCount++; +} + +//static +S32 LLVertexBuffer::calcOffsets(const U32& typemask, S32* offsets, S32 num_vertices) +{ +	S32 offset = 0; +	for (S32 i=0; i<TYPE_TEXTURE_INDEX; i++) +	{ +		U32 mask = 1<<i; +		if (typemask & mask) +		{ +			if (offsets && LLVertexBuffer::sTypeSize[i]) +			{ +				offsets[i] = offset; +				offset += LLVertexBuffer::sTypeSize[i]*num_vertices; +				offset = (offset + 0xF) & ~0xF; +			} +		} +	} + +	offsets[TYPE_TEXTURE_INDEX] = offsets[TYPE_VERTEX] + 12; +	 +	return offset+16; +} + +//static  +S32 LLVertexBuffer::calcVertexSize(const U32& typemask) +{ +	S32 size = 0; +	for (S32 i = 0; i < TYPE_TEXTURE_INDEX; i++) +	{ +		U32 mask = 1<<i; +		if (typemask & mask) +		{ +			size += LLVertexBuffer::sTypeSize[i]; +		} +	} + +	return size; +} + +S32 LLVertexBuffer::getSize() const +{ +	return mSize; +} + +// protected, use unref() +//virtual +LLVertexBuffer::~LLVertexBuffer() +{ +	LLMemType mt2(LLMemType::MTYPE_VERTEX_DESTRUCTOR); +	destroyGLBuffer(); +	destroyGLIndices(); + +	if (mGLArray) +	{ +#if GL_ARB_vertex_array_object +		glDeleteVertexArrays(1, &mGLArray); +#endif +	} + +	sCount--; + +	if (mFence) +	{ +		delete mFence; +	} +	 +	mFence = NULL; + +	llassert_always(!mMappedData && !mMappedIndexData); +}; + +void LLVertexBuffer::placeFence() const +{ +	/*if (!mFence && useVBOs()) +	{ +		if (gGLManager.mHasSync) +		{ +			mFence = new LLGLSyncFence(); +		} +	} + +	if (mFence) +	{ +		mFence->placeFence(); +	}*/ +} + +void LLVertexBuffer::waitFence() const +{ +	/*if (mFence) +	{ +		mFence->wait(); +	}*/ +} + +//---------------------------------------------------------------------------- + +void LLVertexBuffer::genBuffer(U32 size) +{ +	mSize = nhpo2(size); + +	if (mUsage == GL_STREAM_DRAW_ARB) +	{ +		mMappedData = sStreamVBOPool.allocate(mGLBuffer, mSize); +	} +	else +	{ +		mMappedData = sDynamicVBOPool.allocate(mGLBuffer, mSize); +	} +	 +	sGLCount++; +} + +void LLVertexBuffer::genIndices(U32 size) +{ +	mIndicesSize = nhpo2(size); + +	if (mUsage == GL_STREAM_DRAW_ARB) +	{ +		mMappedIndexData = sStreamIBOPool.allocate(mGLIndices, mIndicesSize); +	} +	else +	{ +		mMappedIndexData = sDynamicIBOPool.allocate(mGLIndices, mIndicesSize); +	} +	 +	sGLCount++; +} + +void LLVertexBuffer::releaseBuffer() +{ +	if (mUsage == GL_STREAM_DRAW_ARB) +	{ +		sStreamVBOPool.release(mGLBuffer, mMappedData, mSize); +	} +	else +	{ +		sDynamicVBOPool.release(mGLBuffer, mMappedData, mSize); +	} +	 +	mGLBuffer = 0; +	mMappedData = NULL; + +	sGLCount--; +} + +void LLVertexBuffer::releaseIndices() +{ +	if (mUsage == GL_STREAM_DRAW_ARB) +	{ +		sStreamIBOPool.release(mGLIndices, mMappedIndexData, mIndicesSize); +	} +	else +	{ +		sDynamicIBOPool.release(mGLIndices, mMappedIndexData, mIndicesSize); +	} + +	mGLIndices = 0; +	mMappedIndexData = NULL; +	 +	sGLCount--; +} + +void LLVertexBuffer::createGLBuffer(U32 size) +{ +	LLMemType mt2(LLMemType::MTYPE_VERTEX_CREATE_VERTICES); +	 +	if (mGLBuffer) +	{ +		destroyGLBuffer(); +	} + +	if (size == 0) +	{ +		return; +	} + +	mEmpty = true; + +	mMappedDataUsingVBOs = useVBOs(); +	 +	if (mMappedDataUsingVBOs) +	{ +		genBuffer(size); +	} +	else +	{ +		static int gl_buffer_idx = 0; +		mGLBuffer = ++gl_buffer_idx; +		mMappedData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size); +		mSize = size; +	} +} + +void LLVertexBuffer::createGLIndices(U32 size) +{ +	LLMemType mt2(LLMemType::MTYPE_VERTEX_CREATE_INDICES); +	 +	if (mGLIndices) +	{ +		destroyGLIndices(); +	} +	 +	if (size == 0) +	{ +		return; +	} + +	mEmpty = true; + +	//pad by 16 bytes for aligned copies +	size += 16; + +	mMappedIndexDataUsingVBOs = useVBOs(); + +	if (mMappedIndexDataUsingVBOs) +	{ +		//pad by another 16 bytes for VBO pointer adjustment +		size += 16; +		genIndices(size); +	} +	else +	{ +		mMappedIndexData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size); +		static int gl_buffer_idx = 0; +		mGLIndices = ++gl_buffer_idx; +		mIndicesSize = size; +	} +} + +void LLVertexBuffer::destroyGLBuffer() +{ +	LLMemType mt2(LLMemType::MTYPE_VERTEX_DESTROY_BUFFER); +	if (mGLBuffer) +	{ +		if (mMappedDataUsingVBOs) +		{ +			releaseBuffer(); +		} +		else +		{ +			FREE_MEM(sPrivatePoolp, (void*) mMappedData); +			mMappedData = NULL; +			mEmpty = true; +		} +	} +	 +	mGLBuffer = 0; +	//unbind(); +} + +void LLVertexBuffer::destroyGLIndices() +{ +	LLMemType mt2(LLMemType::MTYPE_VERTEX_DESTROY_INDICES); +	if (mGLIndices) +	{ +		if (mMappedIndexDataUsingVBOs) +		{ +			releaseIndices(); +		} +		else +		{ +			FREE_MEM(sPrivatePoolp, (void*) mMappedIndexData); +			mMappedIndexData = NULL; +			mEmpty = true; +		} +	} + +	mGLIndices = 0; +	//unbind(); +} + +void LLVertexBuffer::updateNumVerts(S32 nverts) +{ +	LLMemType mt2(LLMemType::MTYPE_VERTEX_UPDATE_VERTS); + +	llassert(nverts >= 0); + +	if (nverts >= 65535) +	{ +		llwarns << "Vertex buffer overflow!" << llendl; +		nverts = 65535; +	} + +	U32 needed_size = calcOffsets(mTypeMask, mOffsets, nverts); + +	if (needed_size > mSize || needed_size <= mSize/2) +	{ +		createGLBuffer(needed_size); +	} + +	mNumVerts = nverts; +} + +void LLVertexBuffer::updateNumIndices(S32 nindices) +{ +	LLMemType mt2(LLMemType::MTYPE_VERTEX_UPDATE_INDICES); + +	llassert(nindices >= 0); + +	U32 needed_size = sizeof(U16) * nindices; + +	if (needed_size > mIndicesSize || needed_size <= mIndicesSize/2) +	{ +		createGLIndices(needed_size); +	} + +	mNumIndices = nindices; +} + +void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create) +{ +	LLMemType mt2(LLMemType::MTYPE_VERTEX_ALLOCATE_BUFFER); +	 +	stop_glerror(); + +	if (nverts < 0 || nindices < 0 || +		nverts > 65536) +	{ +		llerrs << "Bad vertex buffer allocation: " << nverts << " : " << nindices << llendl; +	} + +	updateNumVerts(nverts); +	updateNumIndices(nindices); +	 +	if (create && (nverts || nindices)) +	{ +		//actually allocate space for the vertex buffer if using VBO mapping +		flush(); + +		if (gGLManager.mHasVertexArrayObject && useVBOs() && (LLRender::sGLCoreProfile || sUseVAO)) +		{ +#if GL_ARB_vertex_array_object +			glGenVertexArrays(1, &mGLArray); +#endif +			setupVertexArray(); +		} +	} +} + +static LLFastTimer::DeclareTimer FTM_SETUP_VERTEX_ARRAY("Setup VAO"); + +void LLVertexBuffer::setupVertexArray() +{ +	if (!mGLArray) +	{ +		return; +	} + +	LLFastTimer t(FTM_SETUP_VERTEX_ARRAY); +#if GL_ARB_vertex_array_object +	glBindVertexArray(mGLArray); +#endif +	sGLRenderArray = mGLArray; + +	U32 attrib_size[] =  +	{ +		3, //TYPE_VERTEX, +		3, //TYPE_NORMAL, +		2, //TYPE_TEXCOORD0, +		2, //TYPE_TEXCOORD1, +		2, //TYPE_TEXCOORD2, +		2, //TYPE_TEXCOORD3, +		4, //TYPE_COLOR, +		4, //TYPE_EMISSIVE, +		3, //TYPE_BINORMAL, +		1, //TYPE_WEIGHT, +		4, //TYPE_WEIGHT4, +		4, //TYPE_CLOTHWEIGHT, +		1, //TYPE_TEXTURE_INDEX +	}; + +	U32 attrib_type[] = +	{ +		GL_FLOAT, //TYPE_VERTEX, +		GL_FLOAT, //TYPE_NORMAL, +		GL_FLOAT, //TYPE_TEXCOORD0, +		GL_FLOAT, //TYPE_TEXCOORD1, +		GL_FLOAT, //TYPE_TEXCOORD2, +		GL_FLOAT, //TYPE_TEXCOORD3, +		GL_UNSIGNED_BYTE, //TYPE_COLOR, +		GL_UNSIGNED_BYTE, //TYPE_EMISSIVE, +		GL_FLOAT,   //TYPE_BINORMAL, +		GL_FLOAT, //TYPE_WEIGHT, +		GL_FLOAT, //TYPE_WEIGHT4, +		GL_FLOAT, //TYPE_CLOTHWEIGHT, +		GL_FLOAT, //TYPE_TEXTURE_INDEX +	}; + +	U32 attrib_normalized[] = +	{ +		GL_FALSE, //TYPE_VERTEX, +		GL_FALSE, //TYPE_NORMAL, +		GL_FALSE, //TYPE_TEXCOORD0, +		GL_FALSE, //TYPE_TEXCOORD1, +		GL_FALSE, //TYPE_TEXCOORD2, +		GL_FALSE, //TYPE_TEXCOORD3, +		GL_TRUE, //TYPE_COLOR, +		GL_TRUE, //TYPE_EMISSIVE, +		GL_FALSE,   //TYPE_BINORMAL, +		GL_FALSE, //TYPE_WEIGHT, +		GL_FALSE, //TYPE_WEIGHT4, +		GL_FALSE, //TYPE_CLOTHWEIGHT, +		GL_FALSE, //TYPE_TEXTURE_INDEX +	}; + +	bindGLBuffer(true); +	bindGLIndices(true); + +	for (U32 i = 0; i < TYPE_MAX; ++i) +	{ +		if (mTypeMask & (1 << i)) +		{ +			glEnableVertexAttribArrayARB(i); +			glVertexAttribPointerARB(i, attrib_size[i], attrib_type[i], attrib_normalized[i], sTypeSize[i], (void*) mOffsets[i]);  +		} +		else +		{ +			glDisableVertexAttribArrayARB(i); +		} +	} + +	//draw a dummy triangle to set index array pointer +	//glDrawElements(GL_TRIANGLES, 0, GL_UNSIGNED_SHORT, NULL); + +	unbind(); +} + +void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices) +{ +	llassert(newnverts >= 0); +	llassert(newnindices >= 0); + +	LLMemType mt2(LLMemType::MTYPE_VERTEX_RESIZE_BUFFER); +	 +	updateNumVerts(newnverts);		 +	updateNumIndices(newnindices); +	 +	if (useVBOs()) +	{ +		flush(); + +		if (mGLArray) +		{ //if size changed, offsets changed +			setupVertexArray(); +		} +	} +} + +bool LLVertexBuffer::useVBOs() const +{ +	//it's generally ineffective to use VBO for things that are streaming on apple +	return (mUsage != 0); +} + +//---------------------------------------------------------------------------- + +bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count) +{ +	S32 end = index+count; +	S32 region_end = region.mIndex+region.mCount; +	 +	if (end < region.mIndex || +		index > region_end) +	{ //gap exists, do not merge +		return false; +	} + +	S32 new_end = llmax(end, region_end); +	S32 new_index = llmin(index, region.mIndex); +	region.mIndex = new_index; +	region.mCount = new_end-new_index; +	return true; +} + +static LLFastTimer::DeclareTimer FTM_VBO_MAP_BUFFER_RANGE("VBO Map Range"); +static LLFastTimer::DeclareTimer FTM_VBO_MAP_BUFFER("VBO Map"); + +// Map for data access +volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range) +{ +	bindGLBuffer(true); +	LLMemType mt2(LLMemType::MTYPE_VERTEX_MAP_BUFFER); +	if (mFinal) +	{ +		llerrs << "LLVertexBuffer::mapVeretxBuffer() called on a finalized buffer." << llendl; +	} +	if (!useVBOs() && !mMappedData && !mMappedIndexData) +	{ +		llerrs << "LLVertexBuffer::mapVertexBuffer() called on unallocated buffer." << llendl; +	} +		 +	if (useVBOs()) +	{ +		if (!mMappable || gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange) +		{ +			if (count == -1) +			{ +				count = mNumVerts-index; +			} + +			bool mapped = false; +			//see if range is already mapped +			for (U32 i = 0; i < mMappedVertexRegions.size(); ++i) +			{ +				MappedRegion& region = mMappedVertexRegions[i]; +				if (region.mType == type) +				{ +					if (expand_region(region, index, count)) +					{ +						mapped = true; +						break; +					} +				} +			} + +			if (!mapped) +			{ +				//not already mapped, map new region +				MappedRegion region(type, mMappable && map_range ? -1 : index, count); +				mMappedVertexRegions.push_back(region); +			} +		} + +		if (mVertexLocked && map_range) +		{ +			llerrs << "Attempted to map a specific range of a buffer that was already mapped." << llendl; +		} + +		if (!mVertexLocked) +		{ +			LLMemType mt_v(LLMemType::MTYPE_VERTEX_MAP_BUFFER_VERTICES); +			mVertexLocked = true; +			sMappedCount++; +			stop_glerror();	 + +			if(!mMappable) +			{ +				map_range = false; +			} +			else +			{ +				volatile U8* src = NULL; +				waitFence(); +				if (gGLManager.mHasMapBufferRange) +				{ +					if (map_range) +					{ +#ifdef GL_ARB_map_buffer_range +						LLFastTimer t(FTM_VBO_MAP_BUFFER_RANGE); +						S32 offset = mOffsets[type] + sTypeSize[type]*index; +						S32 length = (sTypeSize[type]*count+0xF) & ~0xF; +						src = (U8*) glMapBufferRange(GL_ARRAY_BUFFER_ARB, offset, length,  +							GL_MAP_WRITE_BIT |  +							GL_MAP_FLUSH_EXPLICIT_BIT |  +							GL_MAP_INVALIDATE_RANGE_BIT); +#endif +					} +					else +					{ +#ifdef GL_ARB_map_buffer_range + +						if (gDebugGL) +						{ +							GLint size = 0; +							glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SIZE_ARB, &size); + +							if (size < mSize) +							{ +								llerrs << "Invalid buffer size." << llendl; +							} +						} + +						LLFastTimer t(FTM_VBO_MAP_BUFFER); +						src = (U8*) glMapBufferRange(GL_ARRAY_BUFFER_ARB, 0, mSize,  +							GL_MAP_WRITE_BIT |  +							GL_MAP_FLUSH_EXPLICIT_BIT); +#endif +					} +				} +				else if (gGLManager.mHasFlushBufferRange) +				{ +					if (map_range) +					{ +						glBufferParameteriAPPLE(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_FALSE); +						glBufferParameteriAPPLE(GL_ARRAY_BUFFER_ARB, GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE); +						src = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); +					} +					else +					{ +						src = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); +					} +				} +				else +				{ +					map_range = false; +					src = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); +				} + +				llassert(src != NULL); + +				mMappedData = LL_NEXT_ALIGNED_ADDRESS<volatile U8>(src); +				mAlignedOffset = mMappedData - src; +			 +				stop_glerror(); +			} +				 +			if (!mMappedData) +			{ +				log_glerror(); + +				//check the availability of memory +				LLMemory::logMemoryInfo(true); +			 +				if(mMappable) +				{			 +					//-------------------- +					//print out more debug info before crash +					llinfos << "vertex buffer size: (num verts : num indices) = " << getNumVerts() << " : " << getNumIndices() << llendl; +					GLint size; +					glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SIZE_ARB, &size); +					llinfos << "GL_ARRAY_BUFFER_ARB size is " << size << llendl; +					//-------------------- + +					GLint buff; +					glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB, &buff); +					if ((GLuint)buff != mGLBuffer) +					{ +						llerrs << "Invalid GL vertex buffer bound: " << buff << llendl; +					} + +							 +					llerrs << "glMapBuffer returned NULL (no vertex data)" << llendl; +				} +				else +				{ +					llerrs << "memory allocation for vertex data failed." << llendl; +				} +			} +		} +	} +	else +	{ +		map_range = false; +	} +	 +	if (map_range && gGLManager.mHasMapBufferRange && mMappable) +	{ +		return mMappedData; +	} +	else +	{ +		return mMappedData+mOffsets[type]+sTypeSize[type]*index; +	} +} + + +static LLFastTimer::DeclareTimer FTM_VBO_MAP_INDEX_RANGE("IBO Map Range"); +static LLFastTimer::DeclareTimer FTM_VBO_MAP_INDEX("IBO Map"); + +volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range) +{ +	LLMemType mt2(LLMemType::MTYPE_VERTEX_MAP_BUFFER); +	bindGLIndices(true); +	if (mFinal) +	{ +		llerrs << "LLVertexBuffer::mapIndexBuffer() called on a finalized buffer." << llendl; +	} +	if (!useVBOs() && !mMappedData && !mMappedIndexData) +	{ +		llerrs << "LLVertexBuffer::mapIndexBuffer() called on unallocated buffer." << llendl; +	} + +	if (useVBOs()) +	{ +		if (!mMappable || gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange) +		{ +			if (count == -1) +			{ +				count = mNumIndices-index; +			} + +			bool mapped = false; +			//see if range is already mapped +			for (U32 i = 0; i < mMappedIndexRegions.size(); ++i) +			{ +				MappedRegion& region = mMappedIndexRegions[i]; +				if (expand_region(region, index, count)) +				{ +					mapped = true; +					break; +				} +			} + +			if (!mapped) +			{ +				//not already mapped, map new region +				MappedRegion region(TYPE_INDEX, mMappable && map_range ? -1 : index, count); +				mMappedIndexRegions.push_back(region); +			} +		} + +		if (mIndexLocked && map_range) +		{ +			llerrs << "Attempted to map a specific range of a buffer that was already mapped." << llendl; +		} + +		if (!mIndexLocked) +		{ +			LLMemType mt_v(LLMemType::MTYPE_VERTEX_MAP_BUFFER_INDICES); + +			mIndexLocked = true; +			sMappedCount++; +			stop_glerror();	 + +			if (gDebugGL && useVBOs()) +			{ +				GLint elem = 0; +				glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &elem); + +				if (elem != mGLIndices) +				{ +					llerrs << "Wrong index buffer bound!" << llendl; +				} +			} + +			if(!mMappable) +			{ +				map_range = false; +			} +			else +			{ +				volatile U8* src = NULL; +				waitFence(); +				if (gGLManager.mHasMapBufferRange) +				{ +					if (map_range) +					{ +#ifdef GL_ARB_map_buffer_range +						LLFastTimer t(FTM_VBO_MAP_INDEX_RANGE); +						S32 offset = sizeof(U16)*index; +						S32 length = sizeof(U16)*count; +						src = (U8*) glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length,  +							GL_MAP_WRITE_BIT |  +							GL_MAP_FLUSH_EXPLICIT_BIT |  +							GL_MAP_INVALIDATE_RANGE_BIT); +#endif +					} +					else +					{ +#ifdef GL_ARB_map_buffer_range +						LLFastTimer t(FTM_VBO_MAP_INDEX); +						src = (U8*) glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, sizeof(U16)*mNumIndices,  +							GL_MAP_WRITE_BIT |  +							GL_MAP_FLUSH_EXPLICIT_BIT); +#endif +					} +				} +				else if (gGLManager.mHasFlushBufferRange) +				{ +					if (map_range) +					{ +						glBufferParameteriAPPLE(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_FALSE); +						glBufferParameteriAPPLE(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE); +						src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); +					} +					else +					{ +						src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); +					} +				} +				else +				{ +					LLFastTimer t(FTM_VBO_MAP_INDEX); +					map_range = false; +					src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); +				} + +				llassert(src != NULL); + + +				mMappedIndexData = src; //LL_NEXT_ALIGNED_ADDRESS<U8>(src); +				mAlignedIndexOffset = mMappedIndexData - src; +				stop_glerror(); +			} +		} + +		if (!mMappedIndexData) +		{ +			log_glerror(); +			LLMemory::logMemoryInfo(true); + +			if(mMappable) +			{ +				GLint buff; +				glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff); +				if ((GLuint)buff != mGLIndices) +				{ +					llerrs << "Invalid GL index buffer bound: " << buff << llendl; +				} + +				llerrs << "glMapBuffer returned NULL (no index data)" << llendl; +			} +			else +			{ +				llerrs << "memory allocation for Index data failed. " << llendl; +			} +		} +	} +	else +	{ +		map_range = false; +	} + +	if (map_range && gGLManager.mHasMapBufferRange && mMappable) +	{ +		return mMappedIndexData; +	} +	else +	{ +		return mMappedIndexData + sizeof(U16)*index; +	} +} + +static LLFastTimer::DeclareTimer FTM_VBO_UNMAP("VBO Unmap"); +static LLFastTimer::DeclareTimer FTM_VBO_FLUSH_RANGE("Flush VBO Range"); + + +static LLFastTimer::DeclareTimer FTM_IBO_UNMAP("IBO Unmap"); +static LLFastTimer::DeclareTimer FTM_IBO_FLUSH_RANGE("Flush IBO Range"); + +void LLVertexBuffer::unmapBuffer() +{ +	LLMemType mt2(LLMemType::MTYPE_VERTEX_UNMAP_BUFFER); +	if (!useVBOs()) +	{ +		return; //nothing to unmap +	} + +	bool updated_all = false; + +	if (mMappedData && mVertexLocked) +	{ +		LLFastTimer t(FTM_VBO_UNMAP); +		bindGLBuffer(true); +		updated_all = mIndexLocked; //both vertex and index buffers done updating + +		if(!mMappable) +		{ +			if (!mMappedVertexRegions.empty()) +			{ +				stop_glerror(); +				for (U32 i = 0; i < mMappedVertexRegions.size(); ++i) +				{ +					const MappedRegion& region = mMappedVertexRegions[i]; +					S32 offset = region.mIndex >= 0 ? mOffsets[region.mType]+sTypeSize[region.mType]*region.mIndex : 0; +					S32 length = sTypeSize[region.mType]*region.mCount; +					glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, offset, length, (U8*) mMappedData+offset); +					stop_glerror(); +				} + +				mMappedVertexRegions.clear(); +			} +			else +			{ +				stop_glerror(); +				glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, getSize(), (U8*) mMappedData); +				stop_glerror(); +			} +		} +		else +		{ +			if (gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange) +			{ +				if (!mMappedVertexRegions.empty()) +				{ +					stop_glerror(); +					for (U32 i = 0; i < mMappedVertexRegions.size(); ++i) +					{ +						const MappedRegion& region = mMappedVertexRegions[i]; +						S32 offset = region.mIndex >= 0 ? mOffsets[region.mType]+sTypeSize[region.mType]*region.mIndex : 0; +						S32 length = sTypeSize[region.mType]*region.mCount; +						if (gGLManager.mHasMapBufferRange) +						{ +							LLFastTimer t(FTM_VBO_FLUSH_RANGE); +#ifdef GL_ARB_map_buffer_range +							glFlushMappedBufferRange(GL_ARRAY_BUFFER_ARB, offset, length); +#endif +						} +						else if (gGLManager.mHasFlushBufferRange) +						{ +							glFlushMappedBufferRangeAPPLE(GL_ARRAY_BUFFER_ARB, offset, length); +						} +						stop_glerror(); +					} + +					mMappedVertexRegions.clear(); +				} +			} +			stop_glerror(); +			glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); +			stop_glerror(); + +			mMappedData = NULL; +		} + +		mVertexLocked = false; +		sMappedCount--; +	} +	 +	if (mMappedIndexData && mIndexLocked) +	{ +		LLFastTimer t(FTM_IBO_UNMAP); +		bindGLIndices(); +		if(!mMappable) +		{ +			if (!mMappedIndexRegions.empty()) +			{ +				for (U32 i = 0; i < mMappedIndexRegions.size(); ++i) +				{ +					const MappedRegion& region = mMappedIndexRegions[i]; +					S32 offset = region.mIndex >= 0 ? sizeof(U16)*region.mIndex : 0; +					S32 length = sizeof(U16)*region.mCount; +					glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length, (U8*) mMappedIndexData+offset); +					stop_glerror(); +				} + +				mMappedIndexRegions.clear(); +			} +			else +			{ +				stop_glerror(); +				glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, getIndicesSize(), (U8*) mMappedIndexData); +				stop_glerror(); +			} +		} +		else +		{ +			if (gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange) +			{ +				if (!mMappedIndexRegions.empty()) +				{ +					for (U32 i = 0; i < mMappedIndexRegions.size(); ++i) +					{ +						const MappedRegion& region = mMappedIndexRegions[i]; +						S32 offset = region.mIndex >= 0 ? sizeof(U16)*region.mIndex : 0; +						S32 length = sizeof(U16)*region.mCount; +						if (gGLManager.mHasMapBufferRange) +						{ +							LLFastTimer t(FTM_IBO_FLUSH_RANGE); +#ifdef GL_ARB_map_buffer_range +							glFlushMappedBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length); +#endif +						} +						else if (gGLManager.mHasFlushBufferRange) +						{ +#ifdef GL_APPLE_flush_buffer_range +							glFlushMappedBufferRangeAPPLE(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length); +#endif +						} +						stop_glerror(); +					} + +					mMappedIndexRegions.clear(); +				} +			} +			stop_glerror(); +			glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB); +			stop_glerror(); + +			mMappedIndexData = NULL; +		} + +		mIndexLocked = false; +		sMappedCount--; +	} + +	if(updated_all) +	{ +		mEmpty = false; +	} +} + +//---------------------------------------------------------------------------- + +template <class T,S32 type> struct VertexBufferStrider +{ +	typedef LLStrider<T> strider_t; +	static bool get(LLVertexBuffer& vbo,  +					strider_t& strider,  +					S32 index, S32 count, bool map_range) +	{ +		if (type == LLVertexBuffer::TYPE_INDEX) +		{ +			volatile U8* ptr = vbo.mapIndexBuffer(index, count, map_range); + +			if (ptr == NULL) +			{ +				llwarns << "mapIndexBuffer failed!" << llendl; +				return false; +			} + +			strider = (T*)ptr; +			strider.setStride(0); +			return true; +		} +		else if (vbo.hasDataType(type)) +		{ +			S32 stride = LLVertexBuffer::sTypeSize[type]; + +			volatile U8* ptr = vbo.mapVertexBuffer(type, index, count, map_range); + +			if (ptr == NULL) +			{ +				llwarns << "mapVertexBuffer failed!" << llendl; +				return false; +			} + +			strider = (T*)ptr; +			strider.setStride(stride); +			return true; +		} +		else +		{ +			llerrs << "VertexBufferStrider could not find valid vertex data." << llendl; +		} +		return false; +	} +}; + +bool LLVertexBuffer::getVertexStrider(LLStrider<LLVector3>& strider, S32 index, S32 count, bool map_range) +{ +	return VertexBufferStrider<LLVector3,TYPE_VERTEX>::get(*this, strider, index, count, map_range); +} +bool LLVertexBuffer::getVertexStrider(LLStrider<LLVector4a>& strider, S32 index, S32 count, bool map_range) +{ +	return VertexBufferStrider<LLVector4a,TYPE_VERTEX>::get(*this, strider, index, count, map_range); +} +bool LLVertexBuffer::getIndexStrider(LLStrider<U16>& strider, S32 index, S32 count, bool map_range) +{ +	return VertexBufferStrider<U16,TYPE_INDEX>::get(*this, strider, index, count, map_range); +} +bool LLVertexBuffer::getTexCoord0Strider(LLStrider<LLVector2>& strider, S32 index, S32 count, bool map_range) +{ +	return VertexBufferStrider<LLVector2,TYPE_TEXCOORD0>::get(*this, strider, index, count, map_range); +} +bool LLVertexBuffer::getTexCoord1Strider(LLStrider<LLVector2>& strider, S32 index, S32 count, bool map_range) +{ +	return VertexBufferStrider<LLVector2,TYPE_TEXCOORD1>::get(*this, strider, index, count, map_range); +} + +bool LLVertexBuffer::getNormalStrider(LLStrider<LLVector3>& strider, S32 index, S32 count, bool map_range) +{ +	return VertexBufferStrider<LLVector3,TYPE_NORMAL>::get(*this, strider, index, count, map_range); +} +bool LLVertexBuffer::getBinormalStrider(LLStrider<LLVector3>& strider, S32 index, S32 count, bool map_range) +{ +	return VertexBufferStrider<LLVector3,TYPE_BINORMAL>::get(*this, strider, index, count, map_range); +} +bool LLVertexBuffer::getColorStrider(LLStrider<LLColor4U>& strider, S32 index, S32 count, bool map_range) +{ +	return VertexBufferStrider<LLColor4U,TYPE_COLOR>::get(*this, strider, index, count, map_range); +} +bool LLVertexBuffer::getEmissiveStrider(LLStrider<LLColor4U>& strider, S32 index, S32 count, bool map_range) +{ +	return VertexBufferStrider<LLColor4U,TYPE_EMISSIVE>::get(*this, strider, index, count, map_range); +} +bool LLVertexBuffer::getWeightStrider(LLStrider<F32>& strider, S32 index, S32 count, bool map_range) +{ +	return VertexBufferStrider<F32,TYPE_WEIGHT>::get(*this, strider, index, count, map_range); +} + +bool LLVertexBuffer::getWeight4Strider(LLStrider<LLVector4>& strider, S32 index, S32 count, bool map_range) +{ +	return VertexBufferStrider<LLVector4,TYPE_WEIGHT4>::get(*this, strider, index, count, map_range); +} + +bool LLVertexBuffer::getClothWeightStrider(LLStrider<LLVector4>& strider, S32 index, S32 count, bool map_range) +{ +	return VertexBufferStrider<LLVector4,TYPE_CLOTHWEIGHT>::get(*this, strider, index, count, map_range); +} + +//---------------------------------------------------------------------------- + +static LLFastTimer::DeclareTimer FTM_BIND_GL_ARRAY("Bind Array"); +bool LLVertexBuffer::bindGLArray() +{ +	if (mGLArray && sGLRenderArray != mGLArray) +	{ +		{ +			LLFastTimer t(FTM_BIND_GL_ARRAY); +#if GL_ARB_vertex_array_object +			glBindVertexArray(mGLArray); +#endif +			sGLRenderArray = mGLArray; +		} + +		//really shouldn't be necessary, but some drivers don't properly restore the +		//state of GL_ELEMENT_ARRAY_BUFFER_BINDING +		bindGLIndices(); +		 +		return true; +	} +		 +	return false; +} + +static LLFastTimer::DeclareTimer FTM_BIND_GL_BUFFER("Bind Buffer"); + +bool LLVertexBuffer::bindGLBuffer(bool force_bind) +{ +	bindGLArray(); + +	bool ret = false; + +	if (useVBOs() && (force_bind || (mGLBuffer && (mGLBuffer != sGLRenderBuffer || !sVBOActive)))) +	{ +		LLFastTimer t(FTM_BIND_GL_BUFFER); +		/*if (sMapped) +		{ +			llerrs << "VBO bound while another VBO mapped!" << llendl; +		}*/ +		glBindBufferARB(GL_ARRAY_BUFFER_ARB, mGLBuffer); +		sGLRenderBuffer = mGLBuffer; +		sBindCount++; +		sVBOActive = true; + +		if (mGLArray) +		{ +			llassert(sGLRenderArray == mGLArray); +			//mCachedRenderBuffer = mGLBuffer; +		} + +		ret = true; +	} + +	return ret; +} + +static LLFastTimer::DeclareTimer FTM_BIND_GL_INDICES("Bind Indices"); + +bool LLVertexBuffer::bindGLIndices(bool force_bind) +{ +	bindGLArray(); + +	bool ret = false; +	if (useVBOs() && (force_bind || (mGLIndices && (mGLIndices != sGLRenderIndices || !sIBOActive)))) +	{ +		LLFastTimer t(FTM_BIND_GL_INDICES); +		/*if (sMapped) +		{ +			llerrs << "VBO bound while another VBO mapped!" << llendl; +		}*/ +		glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, mGLIndices); +		sGLRenderIndices = mGLIndices; +		stop_glerror(); +		sBindCount++; +		sIBOActive = true; +		ret = true; +	} + +	return ret; +} + +void LLVertexBuffer::flush() +{ +	if (useVBOs()) +	{ +		unmapBuffer(); +	} +} + +// Set for rendering +void LLVertexBuffer::setBuffer(U32 data_mask) +{ +	flush(); + +	LLMemType mt2(LLMemType::MTYPE_VERTEX_SET_BUFFER); +	//set up pointers if the data mask is different ... +	bool setup = (sLastMask != data_mask); + +	if (gDebugGL && data_mask != 0) +	{ //make sure data requirements are fulfilled +		LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; +		if (shader) +		{ +			U32 required_mask = 0; +			for (U32 i = 0; i < LLVertexBuffer::TYPE_TEXTURE_INDEX; ++i) +			{ +				if (shader->getAttribLocation(i) > -1) +				{ +					U32 required = 1 << i; +					if ((data_mask & required) == 0) +					{ +						llwarns << "Missing attribute: " << LLShaderMgr::instance()->mReservedAttribs[i] << llendl; +					} + +					required_mask |= required; +				} +			} + +			if ((data_mask & required_mask) != required_mask) +			{ +				llerrs << "Shader consumption mismatches data provision." << llendl; +			} +		} +	} + +	if (useVBOs()) +	{ +		if (mGLArray) +		{ +			bindGLArray(); +			setup = false; //do NOT perform pointer setup if using VAO +		} +		else +		{ +			const bool bindBuffer = bindGLBuffer(); +			const bool bindIndices = bindGLIndices(); +			 +			setup = setup || bindBuffer || bindIndices; +		} + +		bool error = false; +		if (gDebugGL && !mGLArray) +		{ +			GLint buff; +			glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB, &buff); +			if ((GLuint)buff != mGLBuffer) +			{ +				if (gDebugSession) +				{ +					error = true; +					gFailLog << "Invalid GL vertex buffer bound: " << buff << std::endl; +				} +				else +				{ +					llerrs << "Invalid GL vertex buffer bound: " << buff << llendl; +				} +			} + +			if (mGLIndices) +			{ +				glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff); +				if ((GLuint)buff != mGLIndices) +				{ +					if (gDebugSession) +					{ +						error = true; +						gFailLog << "Invalid GL index buffer bound: " << buff <<  std::endl; +					} +					else +					{ +						llerrs << "Invalid GL index buffer bound: " << buff << llendl; +					} +				} +			} +		} + +		 +	} +	else +	{	 +		if (sGLRenderArray) +		{ +#if GL_ARB_vertex_array_object +			glBindVertexArray(0); +#endif +			sGLRenderArray = 0; +			sGLRenderIndices = 0; +			sIBOActive = false; +		} + +		if (mGLBuffer) +		{ +			if (sVBOActive) +			{ +				glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); +				sBindCount++; +				sVBOActive = false; +				setup = true; // ... or a VBO is deactivated +			} +			if (sGLRenderBuffer != mGLBuffer) +			{ +				sGLRenderBuffer = mGLBuffer; +				setup = true; // ... or a client memory pointer changed +			} +		} +		if (mGLIndices) +		{ +			if (sIBOActive) +			{ +				glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); +				sBindCount++; +				sIBOActive = false; +			} +			 +			sGLRenderIndices = mGLIndices; +		} +	} + +	if (!mGLArray) +	{ +		setupClientArrays(data_mask); +	} +			 +	if (mGLBuffer) +	{ +		if (data_mask && setup) +		{ +			setupVertexBuffer(data_mask); // subclass specific setup (virtual function) +			sSetCount++; +		} +	} +} + +// virtual (default) +void LLVertexBuffer::setupVertexBuffer(U32 data_mask) +{ +	LLMemType mt2(LLMemType::MTYPE_VERTEX_SETUP_VERTEX_BUFFER); +	stop_glerror(); +	volatile U8* base = useVBOs() ? (U8*) mAlignedOffset : mMappedData; + +	/*if ((data_mask & mTypeMask) != data_mask) +	{ +		llerrs << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << llendl; +	}*/ + +	if (LLGLSLShader::sNoFixedFunction) +	{ +		if (data_mask & MAP_NORMAL) +		{ +			S32 loc = TYPE_NORMAL; +			void* ptr = (void*)(base + mOffsets[TYPE_NORMAL]); +			glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_NORMAL], ptr); +		} +		if (data_mask & MAP_TEXCOORD3) +		{ +			S32 loc = TYPE_TEXCOORD3; +			void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD3]); +			glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], ptr); +		} +		if (data_mask & MAP_TEXCOORD2) +		{ +			S32 loc = TYPE_TEXCOORD2; +			void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD2]); +			glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], ptr); +		} +		if (data_mask & MAP_TEXCOORD1) +		{ +			S32 loc = TYPE_TEXCOORD1; +			void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD1]); +			glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], ptr); +		} +		if (data_mask & MAP_BINORMAL) +		{ +			S32 loc = TYPE_BINORMAL; +			void* ptr = (void*)(base + mOffsets[TYPE_BINORMAL]); +			glVertexAttribPointerARB(loc, 3,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_BINORMAL], ptr); +		} +		if (data_mask & MAP_TEXCOORD0) +		{ +			S32 loc = TYPE_TEXCOORD0; +			void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD0]); +			glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], ptr); +		} +		if (data_mask & MAP_COLOR) +		{ +			S32 loc = TYPE_COLOR; +			void* ptr = (void*)(base + mOffsets[TYPE_COLOR]); +			glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_COLOR], ptr); +		} +		if (data_mask & MAP_EMISSIVE) +		{ +			S32 loc = TYPE_EMISSIVE; +			void* ptr = (void*)(base + mOffsets[TYPE_EMISSIVE]); +			glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_EMISSIVE], ptr); +		} +		if (data_mask & MAP_WEIGHT) +		{ +			S32 loc = TYPE_WEIGHT; +			void* ptr = (void*)(base + mOffsets[TYPE_WEIGHT]); +			glVertexAttribPointerARB(loc, 1, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT], ptr); +		} +		if (data_mask & MAP_WEIGHT4) +		{ +			S32 loc = TYPE_WEIGHT4; +			void* ptr = (void*)(base+mOffsets[TYPE_WEIGHT4]); +			glVertexAttribPointerARB(loc, 4, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT4], ptr); +		} +		if (data_mask & MAP_CLOTHWEIGHT) +		{ +			S32 loc = TYPE_CLOTHWEIGHT; +			void* ptr = (void*)(base + mOffsets[TYPE_CLOTHWEIGHT]); +			glVertexAttribPointerARB(loc, 4, GL_FLOAT, GL_TRUE,  LLVertexBuffer::sTypeSize[TYPE_CLOTHWEIGHT], ptr); +		} +		if (data_mask & MAP_TEXTURE_INDEX) +		{ +			S32 loc = TYPE_TEXTURE_INDEX; +			void *ptr = (void*) (base + mOffsets[TYPE_VERTEX] + 12); +			glVertexAttribPointerARB(loc, 1, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr); +		} +		if (data_mask & MAP_VERTEX) +		{ +			S32 loc = TYPE_VERTEX; +			void* ptr = (void*)(base + mOffsets[TYPE_VERTEX]); +			glVertexAttribPointerARB(loc, 3,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr); +		}	 +	}	 +	else +	{ +		if (data_mask & MAP_NORMAL) +		{ +			glNormalPointer(GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_NORMAL], (void*)(base + mOffsets[TYPE_NORMAL])); +		} +		if (data_mask & MAP_TEXCOORD3) +		{ +			glClientActiveTextureARB(GL_TEXTURE3_ARB); +			glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], (void*)(base + mOffsets[TYPE_TEXCOORD3])); +			glClientActiveTextureARB(GL_TEXTURE0_ARB); +		} +		if (data_mask & MAP_TEXCOORD2) +		{ +			glClientActiveTextureARB(GL_TEXTURE2_ARB); +			glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], (void*)(base + mOffsets[TYPE_TEXCOORD2])); +			glClientActiveTextureARB(GL_TEXTURE0_ARB); +		} +		if (data_mask & MAP_TEXCOORD1) +		{ +			glClientActiveTextureARB(GL_TEXTURE1_ARB); +			glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], (void*)(base + mOffsets[TYPE_TEXCOORD1])); +			glClientActiveTextureARB(GL_TEXTURE0_ARB); +		} +		if (data_mask & MAP_BINORMAL) +		{ +			glClientActiveTextureARB(GL_TEXTURE2_ARB); +			glTexCoordPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_BINORMAL], (void*)(base + mOffsets[TYPE_BINORMAL])); +			glClientActiveTextureARB(GL_TEXTURE0_ARB); +		} +		if (data_mask & MAP_TEXCOORD0) +		{ +			glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0])); +		} +		if (data_mask & MAP_COLOR) +		{ +			glColorPointer(4, GL_UNSIGNED_BYTE, LLVertexBuffer::sTypeSize[TYPE_COLOR], (void*)(base + mOffsets[TYPE_COLOR])); +		} +		if (data_mask & MAP_VERTEX) +		{ +			glVertexPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], (void*)(base + 0)); +		}	 +	} + +	llglassertok(); +} + +LLVertexBuffer::MappedRegion::MappedRegion(S32 type, S32 index, S32 count) +: mType(type), mIndex(index), mCount(count) +{  +	llassert(mType == LLVertexBuffer::TYPE_INDEX ||  +			mType < LLVertexBuffer::TYPE_TEXTURE_INDEX); +}	 + + diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 8fd6c2605f..0102fb8270 100755 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -396,7 +396,6 @@ void LLAgent::ageChat()  //-----------------------------------------------------------------------------  void LLAgent::moveAt(S32 direction, bool reset)  { -	  	mMoveTimer.reset();  	LLFirstUse::notMoving(false); @@ -646,7 +645,6 @@ void LLAgent::setFlying(BOOL fly)  // static  void LLAgent::toggleFlying()  { -  	if ( gAgent.mAutoPilot )  	{  		LLToolPie::instance().stopClickToWalk(); @@ -2705,7 +2703,6 @@ void LLAgent::sendAnimationRequest(const LLUUID &anim_id, EAnimRequest request)  void LLAgent::sendWalkRun(bool running)  { -	  	LLMessageSystem* msgsys = gMessageSystem;  	if (msgsys)  	{ diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 746320f887..5d196a465f 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -1,4797 +1,4795 @@ -/** 
 - * @file llspatialpartition.cpp
 - * @brief LLSpatialGroup class implementation and supporting functions
 - *
 - * $LicenseInfo:firstyear=2003&license=viewerlgpl$
 - * Second Life Viewer Source Code
 - * Copyright (C) 2010, Linden Research, Inc.
 - * 
 - * This library is free software; you can redistribute it and/or
 - * modify it under the terms of the GNU Lesser General Public
 - * License as published by the Free Software Foundation;
 - * version 2.1 of the License only.
 - * 
 - * This library is distributed in the hope that it will be useful,
 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 - * Lesser General Public License for more details.
 - * 
 - * You should have received a copy of the GNU Lesser General Public
 - * License along with this library; if not, write to the Free Software
 - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 - * 
 - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 - * $/LicenseInfo$
 - */
 -
 -#include "llviewerprecompiledheaders.h"
 -
 -#include "llspatialpartition.h"
 -
 -#include "llappviewer.h"
 -#include "lltexturecache.h"
 -#include "lltexturefetch.h"
 -#include "llimageworker.h"
 -#include "llviewerwindow.h"
 -#include "llviewerobjectlist.h"
 -#include "llvovolume.h"
 -#include "llvolume.h"
 -#include "llvolumeoctree.h"
 -#include "llviewercamera.h"
 -#include "llface.h"
 -#include "llfloatertools.h"
 -#include "llviewercontrol.h"
 -#include "llviewerregion.h"
 -#include "llcamera.h"
 -#include "pipeline.h"
 -#include "llmeshrepository.h"
 -#include "llrender.h"
 -#include "lloctree.h"
 -#include "llphysicsshapebuilderutil.h"
 -#include "llvoavatar.h"
 -#include "llvolumemgr.h"
 -#include "lltextureatlas.h"
 -#include "llglslshader.h"
 -#include "llagent.h"
 -#include "llviewershadermgr.h"
 -
 -static LLFastTimer::DeclareTimer FTM_FRUSTUM_CULL("Frustum Culling");
 -static LLFastTimer::DeclareTimer FTM_CULL_REBOUND("Cull Rebound");
 -
 -const F32 SG_OCCLUSION_FUDGE = 0.25f;
 -#define SG_DISCARD_TOLERANCE 0.01f
 -
 -#if LL_OCTREE_PARANOIA_CHECK
 -#define assert_octree_valid(x) x->validate()
 -#define assert_states_valid(x) ((LLSpatialGroup*) x->mSpatialPartition->mOctree->getListener(0))->checkStates()
 -#else
 -#define assert_octree_valid(x)
 -#define assert_states_valid(x)
 -#endif
 -
 -
 -static U32 sZombieGroups = 0;
 -U32 LLSpatialGroup::sNodeCount = 0;
 -
 -#define LL_TRACK_PENDING_OCCLUSION_QUERIES 0
 -
 -std::set<GLuint> LLSpatialGroup::sPendingQueries;
 -
 -U32 gOctreeMaxCapacity;
 -
 -BOOL LLSpatialGroup::sNoDelete = FALSE;
 -
 -static F32 sLastMaxTexPriority = 1.f;
 -static F32 sCurMaxTexPriority = 1.f;
 -
 -class LLOcclusionQueryPool : public LLGLNamePool
 -{
 -protected:
 -	virtual GLuint allocateName()
 -	{
 -		GLuint name;
 -		glGenQueriesARB(1, &name);
 -		return name;
 -	}
 -
 -	virtual void releaseName(GLuint name)
 -	{
 -#if LL_TRACK_PENDING_OCCLUSION_QUERIES
 -		LLSpatialGroup::sPendingQueries.erase(name);
 -#endif
 -		glDeleteQueriesARB(1, &name);
 -	}
 -};
 -
 -static LLOcclusionQueryPool sQueryPool;
 -
 -//static counter for frame to switch LOD on
 -
 -void sg_assert(BOOL expr)
 -{
 -#if LL_OCTREE_PARANOIA_CHECK
 -	if (!expr)
 -	{
 -		llerrs << "Octree invalid!" << llendl;
 -	}
 -#endif
 -}
 -
 -S32 AABBSphereIntersect(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &rad)
 -{
 -	return AABBSphereIntersectR2(min, max, origin, rad*rad);
 -}
 -
 -S32 AABBSphereIntersectR2(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &r)
 -{
 -	F32 d = 0.f;
 -	F32 t;
 -	
 -	if ((min-origin).magVecSquared() < r &&
 -		(max-origin).magVecSquared() < r)
 -	{
 -		return 2;
 -	}
 -
 -	for (U32 i = 0; i < 3; i++)
 -	{
 -		if (origin.mV[i] < min.mV[i])
 -		{
 -			t = min.mV[i] - origin.mV[i];
 -			d += t*t;
 -		}
 -		else if (origin.mV[i] > max.mV[i])
 -		{
 -			t = origin.mV[i] - max.mV[i];
 -			d += t*t;
 -		}
 -
 -		if (d > r)
 -		{
 -			return 0;
 -		}
 -	}
 -
 -	return 1;
 -}
 -
 -
 -S32 AABBSphereIntersect(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &rad)
 -{
 -	return AABBSphereIntersectR2(min, max, origin, rad*rad);
 -}
 -
 -S32 AABBSphereIntersectR2(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &r)
 -{
 -	F32 d = 0.f;
 -	F32 t;
 -	
 -	LLVector4a origina;
 -	origina.load3(origin.mV);
 -
 -	LLVector4a v;
 -	v.setSub(min, origina);
 -	
 -	if (v.dot3(v) < r)
 -	{
 -		v.setSub(max, origina);
 -		if (v.dot3(v) < r)
 -		{
 -			return 2;
 -		}
 -	}
 -
 -
 -	for (U32 i = 0; i < 3; i++)
 -	{
 -		if (origin.mV[i] < min[i])
 -		{
 -			t = min[i] - origin.mV[i];
 -			d += t*t;
 -		}
 -		else if (origin.mV[i] > max[i])
 -		{
 -			t = origin.mV[i] - max[i];
 -			d += t*t;
 -		}
 -
 -		if (d > r)
 -		{
 -			return 0;
 -		}
 -	}
 -
 -	return 1;
 -}
 -
 -
 -typedef enum
 -{
 -	b000 = 0x00,
 -	b001 = 0x01,
 -	b010 = 0x02,
 -	b011 = 0x03,
 -	b100 = 0x04,
 -	b101 = 0x05,
 -	b110 = 0x06,
 -	b111 = 0x07,
 -} eLoveTheBits;
 -
 -//contact Runitai Linden for a copy of the SL object used to write this table
 -//basically, you give the table a bitmask of the look-at vector to a node and it
 -//gives you a triangle fan index array
 -static U16 sOcclusionIndices[] =
 -{
 -	 //000
 -		b111, b110, b010, b011, b001, b101, b100, b110,
 -	 //001 
 -		b011, b010, b000, b001, b101, b111, b110, b010,
 -	 //010
 -		b101, b100, b110, b111, b011, b001, b000, b100,
 -	 //011 
 -		b001, b000, b100, b101, b111, b011, b010, b000,
 -	 //100 
 -		b110, b000, b010, b011, b111, b101, b100, b000,
 -	 //101 
 -		b010, b100, b000, b001, b011, b111, b110, b100,
 -	 //110
 -		b100, b010, b110, b111, b101, b001, b000, b010,
 -	 //111
 -		b000, b110, b100, b101, b001, b011, b010, b110,
 -};
 -
 -U32 get_box_fan_indices(LLCamera* camera, const LLVector4a& center)
 -{
 -	LLVector4a origin;
 -	origin.load3(camera->getOrigin().mV);
 -
 -	S32 cypher = center.greaterThan(origin).getGatheredBits() & 0x7;
 -	
 -	return cypher*8;
 -}
 -
 -U8* get_box_fan_indices_ptr(LLCamera* camera, const LLVector4a& center)
 -{
 -	LLVector4a origin;
 -	origin.load3(camera->getOrigin().mV);
 -
 -	S32 cypher = center.greaterThan(origin).getGatheredBits() & 0x7;
 -	
 -	return (U8*) (sOcclusionIndices+cypher*8);
 -}
 -
 -
 -static LLFastTimer::DeclareTimer FTM_BUILD_OCCLUSION("Build Occlusion");
 -
 -void LLSpatialGroup::buildOcclusion()
 -{
 -	//if (mOcclusionVerts.isNull())
 -	{
 -		mOcclusionVerts = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX, 
 -			LLVertexBuffer::sUseStreamDraw ? mBufferUsage : 0); //if GL has a hard time with VBOs, don't use them for occlusion culling.
 -		mOcclusionVerts->allocateBuffer(8, 64, true);
 -	
 -		LLStrider<U16> idx;
 -		mOcclusionVerts->getIndexStrider(idx);
 -		for (U32 i = 0; i < 64; i++)
 -		{
 -			*idx++ = sOcclusionIndices[i];
 -		}
 -	}
 -
 -	LLVector4a fudge;
 -	fudge.splat(SG_OCCLUSION_FUDGE);
 -
 -	LLVector4a r;
 -	r.setAdd(mBounds[1], fudge);
 -
 -	LLStrider<LLVector3> pos;
 -	
 -	{
 -		LLFastTimer t(FTM_BUILD_OCCLUSION);
 -		mOcclusionVerts->getVertexStrider(pos);
 -	}
 -
 -	{
 -		LLVector4a* v = (LLVector4a*) pos.get();
 -
 -		const LLVector4a& c = mBounds[0];
 -		const LLVector4a& s = r;
 -		
 -		static const LLVector4a octant[] =
 -		{
 -			LLVector4a(-1.f, -1.f, -1.f),
 -			LLVector4a(-1.f, -1.f, 1.f),
 -			LLVector4a(-1.f, 1.f, -1.f),
 -			LLVector4a(-1.f, 1.f, 1.f),
 -
 -			LLVector4a(1.f, -1.f, -1.f),
 -			LLVector4a(1.f, -1.f, 1.f),
 -			LLVector4a(1.f, 1.f, -1.f),
 -			LLVector4a(1.f, 1.f, 1.f),
 -		};
 -
 -		//vertex positions are encoded so the 3 bits of their vertex index 
 -		//correspond to their axis facing, with bit position 3,2,1 matching
 -		//axis facing x,y,z, bit set meaning positive facing, bit clear 
 -		//meaning negative facing
 -		
 -		for (S32 i = 0; i < 8; ++i)
 -		{
 -			LLVector4a p;
 -			p.setMul(s, octant[i]);
 -			p.add(c);
 -			v[i] = p;
 -		}
 -	}
 -	
 -	{
 -		mOcclusionVerts->flush();
 -		LLVertexBuffer::unbind();
 -	}
 -
 -	clearState(LLSpatialGroup::OCCLUSION_DIRTY);
 -}
 -
 -
 -BOOL earlyFail(LLCamera* camera, LLSpatialGroup* group);
 -
 -//returns:
 -//	0 if sphere and AABB are not intersecting 
 -//	1 if they are
 -//	2 if AABB is entirely inside sphere
 -
 -S32 LLSphereAABB(const LLVector3& center, const LLVector3& size, const LLVector3& pos, const F32 &rad)
 -{
 -	S32 ret = 2;
 -
 -	LLVector3 min = center - size;
 -	LLVector3 max = center + size;
 -	for (U32 i = 0; i < 3; i++)
 -	{
 -		if (min.mV[i] > pos.mV[i] + rad ||
 -			max.mV[i] < pos.mV[i] - rad)
 -		{	//totally outside
 -			return 0;
 -		}
 -		
 -		if (min.mV[i] < pos.mV[i] - rad ||
 -			max.mV[i] > pos.mV[i] + rad)
 -		{	//intersecting
 -			ret = 1;
 -		}
 -	}
 -
 -	return ret;
 -}
 -
 -LLSpatialGroup::~LLSpatialGroup()
 -{
 -	/*if (sNoDelete)
 -	{
 -		llerrs << "Illegal deletion of LLSpatialGroup!" << llendl;
 -	}*/
 -
 -	if (gDebugGL)
 -	{
 -		gPipeline.checkReferences(this);
 -	}
 -
 -	if (isState(DEAD))
 -	{
 -		sZombieGroups--;
 -	}
 -	
 -	sNodeCount--;
 -
 -	if (gGLManager.mHasOcclusionQuery)
 -	{
 -		for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; ++i)
 -		{
 -			if (mOcclusionQuery[i])
 -			{
 -				sQueryPool.release(mOcclusionQuery[i]);
 -			}
 -		}
 -	}
 -
 -	mOcclusionVerts = NULL;
 -
 -	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 -	clearDrawMap();
 -	clearAtlasList() ;
 -}
 -
 -BOOL LLSpatialGroup::hasAtlas(LLTextureAtlas* atlasp)
 -{
 -	S8 type = atlasp->getComponents() - 1 ;
 -	for(std::list<LLTextureAtlas*>::iterator iter = mAtlasList[type].begin(); iter != mAtlasList[type].end() ; ++iter)
 -	{
 -		if(atlasp == *iter)
 -		{
 -			return TRUE ;
 -		}
 -	}
 -	return FALSE ;
 -}
 -
 -void LLSpatialGroup::addAtlas(LLTextureAtlas* atlasp, S8 recursive_level) 
 -{		
 -	if(!hasAtlas(atlasp))
 -	{
 -		mAtlasList[atlasp->getComponents() - 1].push_back(atlasp) ;
 -		atlasp->addSpatialGroup(this) ;
 -	}
 -	
 -	--recursive_level;
 -	if(recursive_level)//levels propagating up.
 -	{
 -		LLSpatialGroup* parent = getParent() ;
 -		if(parent)
 -		{
 -			parent->addAtlas(atlasp, recursive_level) ;
 -		}
 -	}	
 -}
 -
 -void LLSpatialGroup::removeAtlas(LLTextureAtlas* atlasp, BOOL remove_group, S8 recursive_level) 
 -{
 -	mAtlasList[atlasp->getComponents() - 1].remove(atlasp) ;
 -	if(remove_group)
 -	{
 -		atlasp->removeSpatialGroup(this) ;
 -	}
 -
 -	--recursive_level;
 -	if(recursive_level)//levels propagating up.
 -	{
 -		LLSpatialGroup* parent = getParent() ;
 -		if(parent)
 -		{
 -			parent->removeAtlas(atlasp, recursive_level) ;
 -		}
 -	}	
 -}
 -
 -void LLSpatialGroup::clearAtlasList() 
 -{
 -	std::list<LLTextureAtlas*>::iterator iter ;
 -	for(S8 i = 0 ; i < 4 ; i++)
 -	{
 -		if(mAtlasList[i].size() > 0)
 -		{
 -			for(iter = mAtlasList[i].begin(); iter != mAtlasList[i].end() ; ++iter)
 -			{
 -				((LLTextureAtlas*)*iter)->removeSpatialGroup(this) ;			
 -			}
 -			mAtlasList[i].clear() ;
 -		}
 -	}
 -}
 -
 -LLTextureAtlas* LLSpatialGroup::getAtlas(S8 ncomponents, S8 to_be_reserved, S8 recursive_level)
 -{
 -	S8 type = ncomponents - 1 ;
 -	if(mAtlasList[type].size() > 0)
 -	{
 -		for(std::list<LLTextureAtlas*>::iterator iter = mAtlasList[type].begin(); iter != mAtlasList[type].end() ; ++iter)
 -		{
 -			if(!((LLTextureAtlas*)*iter)->isFull(to_be_reserved))
 -			{
 -				return *iter ;
 -			}
 -		}
 -	}
 -
 -	--recursive_level;
 -	if(recursive_level)
 -	{
 -		LLSpatialGroup* parent = getParent() ;
 -		if(parent)
 -		{
 -			return parent->getAtlas(ncomponents, to_be_reserved, recursive_level) ;
 -		}
 -	}
 -	return NULL ;
 -}
 -
 -void LLSpatialGroup::setCurUpdatingSlot(LLTextureAtlasSlot* slotp) 
 -{ 
 -	mCurUpdatingSlotp = slotp;
 -
 -	//if(!hasAtlas(mCurUpdatingSlotp->getAtlas()))
 -	//{
 -	//	addAtlas(mCurUpdatingSlotp->getAtlas()) ;
 -	//}
 -}
 -
 -LLTextureAtlasSlot* LLSpatialGroup::getCurUpdatingSlot(LLViewerTexture* imagep, S8 recursive_level) 
 -{ 
 -	if(gFrameCount && mCurUpdatingTime == gFrameCount && mCurUpdatingTexture == imagep)
 -	{
 -		return mCurUpdatingSlotp ;
 -	}
 -
 -	//--recursive_level ;
 -	//if(recursive_level)
 -	//{
 -	//	LLSpatialGroup* parent = getParent() ;
 -	//	if(parent)
 -	//	{
 -	//		return parent->getCurUpdatingSlot(imagep, recursive_level) ;
 -	//	}
 -	//}
 -	return NULL ;
 -}
 -
 -void LLSpatialGroup::clearDrawMap()
 -{
 -	mDrawMap.clear();
 -}
 -
 -BOOL LLSpatialGroup::isHUDGroup() 
 -{
 -	return mSpatialPartition && mSpatialPartition->isHUDPartition() ; 
 -}
 -
 -BOOL LLSpatialGroup::isRecentlyVisible() const
 -{
 -	return (LLDrawable::getCurrentFrame() - mVisible[LLViewerCamera::sCurCameraID]) < LLDrawable::getMinVisFrameRange() ;
 -}
 -
 -BOOL LLSpatialGroup::isVisible() const
 -{
 -	return mVisible[LLViewerCamera::sCurCameraID] >= LLDrawable::getCurrentFrame() ? TRUE : FALSE;
 -}
 -
 -void LLSpatialGroup::setVisible()
 -{
 -	mVisible[LLViewerCamera::sCurCameraID] = LLDrawable::getCurrentFrame();
 -}
 -
 -void LLSpatialGroup::validate()
 -{
 -#if LL_OCTREE_PARANOIA_CHECK
 -
 -	sg_assert(!isState(DIRTY));
 -	sg_assert(!isDead());
 -
 -	LLVector4a myMin;
 -	myMin.setSub(mBounds[0], mBounds[1]);
 -	LLVector4a myMax;
 -	myMax.setAdd(mBounds[0], mBounds[1]);
 -
 -	validateDrawMap();
 -
 -	for (element_iter i = getData().begin(); i != getData().end(); ++i)
 -	{
 -		LLDrawable* drawable = *i;
 -		sg_assert(drawable->getSpatialGroup() == this);
 -		if (drawable->getSpatialBridge())
 -		{
 -			sg_assert(drawable->getSpatialBridge() == mSpatialPartition->asBridge());
 -		}
 -
 -		/*if (drawable->isSpatialBridge())
 -		{
 -			LLSpatialPartition* part = drawable->asPartition();
 -			if (!part)
 -			{
 -				llerrs << "Drawable reports it is a spatial bridge but not a partition." << llendl;
 -			}
 -			LLSpatialGroup* group = (LLSpatialGroup*) part->mOctree->getListener(0);
 -			group->validate();
 -		}*/
 -	}
 -
 -	for (U32 i = 0; i < mOctreeNode->getChildCount(); ++i)
 -	{
 -		LLSpatialGroup* group = (LLSpatialGroup*) mOctreeNode->getChild(i)->getListener(0);
 -
 -		group->validate();
 -		
 -		//ensure all children are enclosed in this node
 -		LLVector4a center = group->mBounds[0];
 -		LLVector4a size = group->mBounds[1];
 -		
 -		LLVector4a min;
 -		min.setSub(center, size);
 -		LLVector4a max;
 -		max.setAdd(center, size);
 -		
 -		for (U32 j = 0; j < 3; j++)
 -		{
 -			sg_assert(min[j] >= myMin[j]-0.02f);
 -			sg_assert(max[j] <= myMax[j]+0.02f);
 -		}
 -	}
 -
 -#endif
 -}
 -
 -void LLSpatialGroup::checkStates()
 -{
 -#if LL_OCTREE_PARANOIA_CHECK
 -	//LLOctreeStateCheck checker;
 -	//checker.traverse(mOctreeNode);
 -#endif
 -}
 -
 -void LLSpatialGroup::validateDrawMap()
 -{
 -#if LL_OCTREE_PARANOIA_CHECK
 -	for (draw_map_t::iterator i = mDrawMap.begin(); i != mDrawMap.end(); ++i)
 -	{
 -		LLSpatialGroup::drawmap_elem_t& draw_vec = i->second;
 -		for (drawmap_elem_t::iterator j = draw_vec.begin(); j != draw_vec.end(); ++j)
 -		{
 -			LLDrawInfo& params = **j;
 -		
 -			params.validate();
 -		}
 -	}
 -#endif
 -}
 -
 -BOOL LLSpatialGroup::updateInGroup(LLDrawable *drawablep, BOOL immediate)
 -{
 -	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 -		
 -	drawablep->updateSpatialExtents();
 -
 -	OctreeNode* parent = mOctreeNode->getOctParent();
 -	
 -	if (mOctreeNode->isInside(drawablep->getPositionGroup()) && 
 -		(mOctreeNode->contains(drawablep) ||
 -		 (drawablep->getBinRadius() > mOctreeNode->getSize()[0] &&
 -				parent && parent->getElementCount() >= gOctreeMaxCapacity)))
 -	{
 -		unbound();
 -		setState(OBJECT_DIRTY);
 -		//setState(GEOM_DIRTY);
 -		return TRUE;
 -	}
 -		
 -	return FALSE;
 -}
 -
 -
 -BOOL LLSpatialGroup::addObject(LLDrawable *drawablep, BOOL add_all, BOOL from_octree)
 -{
 -	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 -	if (!from_octree)
 -	{
 -		mOctreeNode->insert(drawablep);
 -	}
 -	else
 -	{
 -		drawablep->setSpatialGroup(this);
 -		setState(OBJECT_DIRTY | GEOM_DIRTY);
 -		setOcclusionState(LLSpatialGroup::DISCARD_QUERY, LLSpatialGroup::STATE_MODE_ALL_CAMERAS);
 -		gPipeline.markRebuild(this, TRUE);
 -		if (drawablep->isSpatialBridge())
 -		{
 -			mBridgeList.push_back((LLSpatialBridge*) drawablep);
 -		}
 -		if (drawablep->getRadius() > 1.f)
 -		{
 -			setState(IMAGE_DIRTY);
 -		}
 -	}
 -
 -	return TRUE;
 -}
 -
 -void LLSpatialGroup::rebuildGeom()
 -{
 -	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 -	if (!isDead())
 -	{
 -		mSpatialPartition->rebuildGeom(this);
 -	}
 -}
 -
 -void LLSpatialGroup::rebuildMesh()
 -{
 -	if (!isDead())
 -	{
 -		mSpatialPartition->rebuildMesh(this);
 -	}
 -}
 -
 -static LLFastTimer::DeclareTimer FTM_REBUILD_VBO("VBO Rebuilt");
 -
 -void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group)
 -{
 -	if (group->isDead() || !group->isState(LLSpatialGroup::GEOM_DIRTY))
 -	{
 -		return;
 -	}
 -
 -	if (group->changeLOD())
 -	{
 -		group->mLastUpdateDistance = group->mDistance;
 -		group->mLastUpdateViewAngle = group->mViewAngle;
 -	}
 -	
 -	LLFastTimer ftm(FTM_REBUILD_VBO);	
 -
 -	group->clearDrawMap();
 -	
 -	//get geometry count
 -	U32 index_count = 0;
 -	U32 vertex_count = 0;
 -	
 -	addGeometryCount(group, vertex_count, index_count);
 -
 -	if (vertex_count > 0 && index_count > 0)
 -	{ //create vertex buffer containing volume geometry for this node
 -		group->mBuilt = 1.f;
 -		if (group->mVertexBuffer.isNull() ||
 -			!group->mVertexBuffer->isWriteable() ||
 -			(group->mBufferUsage != group->mVertexBuffer->getUsage() && LLVertexBuffer::sEnableVBOs))
 -		{
 -			group->mVertexBuffer = createVertexBuffer(mVertexDataMask, group->mBufferUsage);
 -			group->mVertexBuffer->allocateBuffer(vertex_count, index_count, true);
 -			stop_glerror();
 -		}
 -		else
 -		{
 -			group->mVertexBuffer->resizeBuffer(vertex_count, index_count);
 -			stop_glerror();
 -		}
 -		
 -		getGeometry(group);
 -	}
 -	else
 -	{
 -		group->mVertexBuffer = NULL;
 -		group->mBufferMap.clear();
 -	}
 -
 -	group->mLastUpdateTime = gFrameTimeSeconds;
 -	group->clearState(LLSpatialGroup::GEOM_DIRTY);
 -}
 -
 -
 -void LLSpatialPartition::rebuildMesh(LLSpatialGroup* group)
 -{
 -
 -}
 -
 -BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector4a& minOut, LLVector4a& maxOut)
 -{	
 -	const OctreeNode* node = mOctreeNode;
 -
 -	if (node->getData().empty())
 -	{	//don't do anything if there are no objects
 -		if (empty && mOctreeNode->getParent())
 -		{	//only root is allowed to be empty
 -			OCT_ERRS << "Empty leaf found in octree." << llendl;
 -		}
 -		return FALSE;
 -	}
 -
 -	LLVector4a& newMin = mObjectExtents[0];
 -	LLVector4a& newMax = mObjectExtents[1];
 -	
 -	if (isState(OBJECT_DIRTY))
 -	{ //calculate new bounding box
 -		clearState(OBJECT_DIRTY);
 -
 -		//initialize bounding box to first element
 -		OctreeNode::const_element_iter i = node->getData().begin();
 -		LLDrawable* drawablep = *i;
 -		const LLVector4a* minMax = drawablep->getSpatialExtents();
 -
 -		newMin = minMax[0];
 -		newMax = minMax[1];
 -
 -		for (++i; i != node->getData().end(); ++i)
 -		{
 -			drawablep = *i;
 -			minMax = drawablep->getSpatialExtents();
 -			
 -			update_min_max(newMin, newMax, minMax[0]);
 -			update_min_max(newMin, newMax, minMax[1]);
 -
 -			//bin up the object
 -			/*for (U32 i = 0; i < 3; i++)
 -			{
 -				if (minMax[0].mV[i] < newMin.mV[i])
 -				{
 -					newMin.mV[i] = minMax[0].mV[i];
 -				}
 -				if (minMax[1].mV[i] > newMax.mV[i])
 -				{
 -					newMax.mV[i] = minMax[1].mV[i];
 -				}
 -			}*/
 -		}
 -		
 -		mObjectBounds[0].setAdd(newMin, newMax);
 -		mObjectBounds[0].mul(0.5f);
 -		mObjectBounds[1].setSub(newMax, newMin);
 -		mObjectBounds[1].mul(0.5f);
 -	}
 -	
 -	if (empty)
 -	{
 -		minOut = newMin;
 -		maxOut = newMax;
 -	}
 -	else
 -	{
 -		minOut.setMin(minOut, newMin);
 -		maxOut.setMax(maxOut, newMax);
 -	}
 -		
 -	return TRUE;
 -}
 -
 -void LLSpatialGroup::unbound()
 -{
 -	if (isState(DIRTY))
 -	{
 -		return;
 -	}
 -
 -	setState(DIRTY);
 -	
 -	//all the parent nodes need to rebound this child
 -	if (mOctreeNode)
 -	{
 -		OctreeNode* parent = (OctreeNode*) mOctreeNode->getParent();
 -		while (parent != NULL)
 -		{
 -			LLSpatialGroup* group = (LLSpatialGroup*) parent->getListener(0);
 -			if (group->isState(DIRTY))
 -			{
 -				return;
 -			}
 -			
 -			group->setState(DIRTY);
 -			parent = (OctreeNode*) parent->getParent();
 -		}
 -	}
 -}
 -
 -LLSpatialGroup* LLSpatialGroup::getParent()
 -{
 -	if (isDead())
 -	{
 -		return NULL;
 -	}
 -
 -	if(!mOctreeNode)
 -	{
 -		return NULL;
 -	}
 -	OctreeNode* parent = mOctreeNode->getOctParent();
 -
 -	if (parent)
 -	{
 -		return (LLSpatialGroup*) parent->getListener(0);
 -	}
 -
 -	return NULL;
 -}
 -
 -BOOL LLSpatialGroup::removeObject(LLDrawable *drawablep, BOOL from_octree)
 -{
 -	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 -	unbound();
 -	if (mOctreeNode && !from_octree)
 -	{
 -		if (!mOctreeNode->remove(drawablep))
 -		{
 -			OCT_ERRS << "Could not remove drawable from spatial group" << llendl;
 -		}
 -	}
 -	else
 -	{
 -		drawablep->setSpatialGroup(NULL);
 -		setState(GEOM_DIRTY);
 -		gPipeline.markRebuild(this, TRUE);
 -
 -		if (drawablep->isSpatialBridge())
 -		{
 -			for (bridge_list_t::iterator i = mBridgeList.begin(); i != mBridgeList.end(); ++i)
 -			{
 -				if (*i == drawablep)
 -				{
 -					mBridgeList.erase(i);
 -					break;
 -				}
 -			}
 -		}
 -
 -		if (getElementCount() == 0)
 -		{ //delete draw map on last element removal since a rebuild might never happen
 -			clearDrawMap();
 -		}
 -	}
 -	return TRUE;
 -}
 -
 -void LLSpatialGroup::shift(const LLVector4a &offset)
 -{
 -	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 -	LLVector4a t = mOctreeNode->getCenter();
 -	t.add(offset);	
 -	mOctreeNode->setCenter(t);
 -	mOctreeNode->updateMinMax();
 -	mBounds[0].add(offset);
 -	mExtents[0].add(offset);
 -	mExtents[1].add(offset);
 -	mObjectBounds[0].add(offset);
 -	mObjectExtents[0].add(offset);
 -	mObjectExtents[1].add(offset);
 -
 -	//if (!mSpatialPartition->mRenderByGroup)
 -	{
 -		setState(GEOM_DIRTY);
 -		gPipeline.markRebuild(this, TRUE);
 -	}
 -
 -	if (mOcclusionVerts.notNull())
 -	{
 -		setState(OCCLUSION_DIRTY);
 -	}
 -}
 -
 -class LLSpatialSetState : public LLSpatialGroup::OctreeTraveler
 -{
 -public:
 -	U32 mState;
 -	LLSpatialSetState(U32 state) : mState(state) { }
 -	virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->setState(mState); }	
 -};
 -
 -class LLSpatialSetStateDiff : public LLSpatialSetState
 -{
 -public:
 -	LLSpatialSetStateDiff(U32 state) : LLSpatialSetState(state) { }
 -
 -	virtual void traverse(const LLSpatialGroup::OctreeNode* n)
 -	{
 -		LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
 -		
 -		if (!group->isState(mState))
 -		{
 -			LLSpatialGroup::OctreeTraveler::traverse(n);
 -		}
 -	}
 -};
 -
 -void LLSpatialGroup::setState(U32 state) 
 -{ 
 -	mState |= state; 
 -	
 -	llassert(state <= LLSpatialGroup::STATE_MASK);
 -}	
 -
 -void LLSpatialGroup::setState(U32 state, S32 mode) 
 -{
 -	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 -
 -	llassert(state <= LLSpatialGroup::STATE_MASK);
 -	
 -	if (mode > STATE_MODE_SINGLE)
 -	{
 -		if (mode == STATE_MODE_DIFF)
 -		{
 -			LLSpatialSetStateDiff setter(state);
 -			setter.traverse(mOctreeNode);
 -		}
 -		else
 -		{
 -			LLSpatialSetState setter(state);
 -			setter.traverse(mOctreeNode);
 -		}
 -	}
 -	else
 -	{
 -		mState |= state;
 -	}
 -}
 -
 -class LLSpatialClearState : public LLSpatialGroup::OctreeTraveler
 -{
 -public:
 -	U32 mState;
 -	LLSpatialClearState(U32 state) : mState(state) { }
 -	virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->clearState(mState); }
 -};
 -
 -class LLSpatialClearStateDiff : public LLSpatialClearState
 -{
 -public:
 -	LLSpatialClearStateDiff(U32 state) : LLSpatialClearState(state) { }
 -
 -	virtual void traverse(const LLSpatialGroup::OctreeNode* n)
 -	{
 -		LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
 -		
 -		if (group->isState(mState))
 -		{
 -			LLSpatialGroup::OctreeTraveler::traverse(n);
 -		}
 -	}
 -};
 -
 -void LLSpatialGroup::clearState(U32 state)
 -{
 -	llassert(state <= LLSpatialGroup::STATE_MASK);
 -
 -	mState &= ~state; 
 -}
 -
 -void LLSpatialGroup::clearState(U32 state, S32 mode)
 -{
 -	llassert(state <= LLSpatialGroup::STATE_MASK);
 -
 -	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 -	
 -	if (mode > STATE_MODE_SINGLE)
 -	{
 -		if (mode == STATE_MODE_DIFF)
 -		{
 -			LLSpatialClearStateDiff clearer(state);
 -			clearer.traverse(mOctreeNode);
 -		}
 -		else
 -		{
 -			LLSpatialClearState clearer(state);
 -			clearer.traverse(mOctreeNode);
 -		}
 -	}
 -	else
 -	{
 -		mState &= ~state;
 -	}
 -}
 -
 -BOOL LLSpatialGroup::isState(U32 state) const
 -{ 
 -	llassert(state <= LLSpatialGroup::STATE_MASK);
 -
 -	return mState & state ? TRUE : FALSE; 
 -}
 -
 -//=====================================
 -//		Occlusion State Set/Clear
 -//=====================================
 -class LLSpatialSetOcclusionState : public LLSpatialGroup::OctreeTraveler
 -{
 -public:
 -	U32 mState;
 -	LLSpatialSetOcclusionState(U32 state) : mState(state) { }
 -	virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->setOcclusionState(mState); }	
 -};
 -
 -class LLSpatialSetOcclusionStateDiff : public LLSpatialSetOcclusionState
 -{
 -public:
 -	LLSpatialSetOcclusionStateDiff(U32 state) : LLSpatialSetOcclusionState(state) { }
 -
 -	virtual void traverse(const LLSpatialGroup::OctreeNode* n)
 -	{
 -		LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
 -		
 -		if (!group->isOcclusionState(mState))
 -		{
 -			LLSpatialGroup::OctreeTraveler::traverse(n);
 -		}
 -	}
 -};
 -
 -
 -void LLSpatialGroup::setOcclusionState(U32 state, S32 mode) 
 -{
 -	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 -	
 -	if (mode > STATE_MODE_SINGLE)
 -	{
 -		if (mode == STATE_MODE_DIFF)
 -		{
 -			LLSpatialSetOcclusionStateDiff setter(state);
 -			setter.traverse(mOctreeNode);
 -		}
 -		else if (mode == STATE_MODE_BRANCH)
 -		{
 -			LLSpatialSetOcclusionState setter(state);
 -			setter.traverse(mOctreeNode);
 -		}
 -		else
 -		{
 -			for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
 -			{
 -				mOcclusionState[i] |= state;
 -
 -				if ((state & DISCARD_QUERY) && mOcclusionQuery[i])
 -				{
 -					sQueryPool.release(mOcclusionQuery[i]);
 -					mOcclusionQuery[i] = 0;
 -				}
 -			}
 -		}
 -	}
 -	else
 -	{
 -		mOcclusionState[LLViewerCamera::sCurCameraID] |= state;
 -		if ((state & DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID])
 -		{
 -			sQueryPool.release(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
 -			mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0;
 -		}
 -	}
 -}
 -
 -class LLSpatialClearOcclusionState : public LLSpatialGroup::OctreeTraveler
 -{
 -public:
 -	U32 mState;
 -	
 -	LLSpatialClearOcclusionState(U32 state) : mState(state) { }
 -	virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->clearOcclusionState(mState); }
 -};
 -
 -class LLSpatialClearOcclusionStateDiff : public LLSpatialClearOcclusionState
 -{
 -public:
 -	LLSpatialClearOcclusionStateDiff(U32 state) : LLSpatialClearOcclusionState(state) { }
 -
 -	virtual void traverse(const LLSpatialGroup::OctreeNode* n)
 -	{
 -		LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
 -		
 -		if (group->isOcclusionState(mState))
 -		{
 -			LLSpatialGroup::OctreeTraveler::traverse(n);
 -		}
 -	}
 -};
 -
 -void LLSpatialGroup::clearOcclusionState(U32 state, S32 mode)
 -{
 -	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 -	
 -	if (mode > STATE_MODE_SINGLE)
 -	{
 -		if (mode == STATE_MODE_DIFF)
 -		{
 -			LLSpatialClearOcclusionStateDiff clearer(state);
 -			clearer.traverse(mOctreeNode);
 -		}
 -		else if (mode == STATE_MODE_BRANCH)
 -		{
 -			LLSpatialClearOcclusionState clearer(state);
 -			clearer.traverse(mOctreeNode);
 -		}
 -		else
 -		{
 -			for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
 -			{
 -				mOcclusionState[i] &= ~state;
 -			}
 -		}
 -	}
 -	else
 -	{
 -		mOcclusionState[LLViewerCamera::sCurCameraID] &= ~state;
 -	}
 -}
 -//======================================
 -//		Octree Listener Implementation
 -//======================================
 -
 -LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) :
 -	mState(0),
 -	mGeometryBytes(0),
 -	mSurfaceArea(0.f),
 -	mBuilt(0.f),
 -	mOctreeNode(node),
 -	mSpatialPartition(part),
 -	mVertexBuffer(NULL), 
 -	mBufferUsage(part->mBufferUsage),
 -	mDistance(0.f),
 -	mDepth(0.f),
 -	mLastUpdateDistance(-1.f), 
 -	mLastUpdateTime(gFrameTimeSeconds),
 -	mAtlasList(4),
 -	mCurUpdatingTime(0),
 -	mCurUpdatingSlotp(NULL),
 -	mCurUpdatingTexture (NULL)
 -{
 -	sNodeCount++;
 -	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 -
 -	mViewAngle.splat(0.f);
 -	mLastUpdateViewAngle.splat(-1.f);
 -	mExtents[0] = mExtents[1] = mObjectBounds[0] = mObjectBounds[0] = mObjectBounds[1] = 
 -		mObjectExtents[0] = mObjectExtents[1] = mViewAngle;
 -
 -	sg_assert(mOctreeNode->getListenerCount() == 0);
 -	mOctreeNode->addListener(this);
 -	setState(SG_INITIAL_STATE_MASK);
 -	gPipeline.markRebuild(this, TRUE);
 -
 -	mBounds[0] = node->getCenter();
 -	mBounds[1] = node->getSize();
 -
 -	part->mLODSeed = (part->mLODSeed+1)%part->mLODPeriod;
 -	mLODHash = part->mLODSeed;
 -
 -	OctreeNode* oct_parent = node->getOctParent();
 -
 -	LLSpatialGroup* parent = oct_parent ? (LLSpatialGroup*) oct_parent->getListener(0) : NULL;
 -
 -	for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
 -	{
 -		mOcclusionQuery[i] = 0;
 -		mOcclusionIssued[i] = 0;
 -		mOcclusionState[i] = parent ? SG_STATE_INHERIT_MASK & parent->mOcclusionState[i] : 0;
 -		mVisible[i] = 0;
 -	}
 -
 -	mOcclusionVerts = NULL;
 -
 -	mRadius = 1;
 -	mPixelArea = 1024.f;
 -}
 -
 -void LLSpatialGroup::updateDistance(LLCamera &camera)
 -{
 -	if (LLViewerCamera::sCurCameraID != LLViewerCamera::CAMERA_WORLD)
 -	{
 -		llwarns << "Attempted to update distance for camera other than world camera!" << llendl;
 -		return;
 -	}
 -
 -#if !LL_RELEASE_FOR_DOWNLOAD
 -	if (isState(LLSpatialGroup::OBJECT_DIRTY))
 -	{
 -		llerrs << "Spatial group dirty on distance update." << llendl;
 -	}
 -#endif
 -	if (!getData().empty())
 -	{
 -		mRadius = mSpatialPartition->mRenderByGroup ? mObjectBounds[1].getLength3().getF32() :
 -						(F32) mOctreeNode->getSize().getLength3().getF32();
 -		mDistance = mSpatialPartition->calcDistance(this, camera);
 -		mPixelArea = mSpatialPartition->calcPixelArea(this, camera);
 -	}
 -}
 -
 -F32 LLSpatialPartition::calcDistance(LLSpatialGroup* group, LLCamera& camera)
 -{
 -	LLVector4a eye;
 -	LLVector4a origin;
 -	origin.load3(camera.getOrigin().mV);
 -
 -	eye.setSub(group->mObjectBounds[0], origin);
 -
 -	F32 dist = 0.f;
 -
 -	if (group->mDrawMap.find(LLRenderPass::PASS_ALPHA) != group->mDrawMap.end())
 -	{
 -		LLVector4a v = eye;
 -
 -		dist = eye.getLength3().getF32();
 -		eye.normalize3fast();
 -
 -		if (!group->isState(LLSpatialGroup::ALPHA_DIRTY))
 -		{
 -			if (!group->mSpatialPartition->isBridge())
 -			{
 -				LLVector4a view_angle = eye;
 -
 -				LLVector4a diff;
 -				diff.setSub(view_angle, group->mLastUpdateViewAngle);
 -
 -				if (diff.getLength3().getF32() > 0.64f)
 -				{
 -					group->mViewAngle = view_angle;
 -					group->mLastUpdateViewAngle = view_angle;
 -					//for occasional alpha sorting within the group
 -					//NOTE: If there is a trivial way to detect that alpha sorting here would not change the render order,
 -					//not setting this node to dirty would be a very good thing
 -					group->setState(LLSpatialGroup::ALPHA_DIRTY);
 -					gPipeline.markRebuild(group, FALSE);
 -				}
 -			}
 -		}
 -
 -		//calculate depth of node for alpha sorting
 -
 -		LLVector3 at = camera.getAtAxis();
 -
 -		LLVector4a ata;
 -		ata.load3(at.mV);
 -
 -		LLVector4a t = ata;
 -		//front of bounding box
 -		t.mul(0.25f);
 -		t.mul(group->mObjectBounds[1]);
 -		v.sub(t);
 -		
 -		group->mDepth = v.dot3(ata).getF32();
 -	}
 -	else
 -	{
 -		dist = eye.getLength3().getF32();
 -	}
 -
 -	if (dist < 16.f)
 -	{
 -		dist /= 16.f;
 -		dist *= dist;
 -		dist *= 16.f;
 -	}
 -
 -	return dist;
 -}
 -
 -F32 LLSpatialPartition::calcPixelArea(LLSpatialGroup* group, LLCamera& camera)
 -{
 -	return LLPipeline::calcPixelArea(group->mObjectBounds[0], group->mObjectBounds[1], camera);
 -}
 -
 -F32 LLSpatialGroup::getUpdateUrgency() const
 -{
 -	if (!isVisible())
 -	{
 -		return 0.f;
 -	}
 -	else
 -	{
 -		F32 time = gFrameTimeSeconds-mLastUpdateTime+4.f;
 -		return time + (mObjectBounds[1].dot3(mObjectBounds[1]).getF32()+1.f)/mDistance;
 -	}
 -}
 -
 -BOOL LLSpatialGroup::needsUpdate()
 -{
 -	return (LLDrawable::getCurrentFrame()%mSpatialPartition->mLODPeriod == mLODHash) ? TRUE : FALSE;
 -}
 -
 -BOOL LLSpatialGroup::changeLOD()
 -{
 -	if (isState(ALPHA_DIRTY | OBJECT_DIRTY))
 -	{ ///a rebuild is going to happen, update distance and LoD
 -		return TRUE;
 -	}
 -
 -	if (mSpatialPartition->mSlopRatio > 0.f)
 -	{
 -		F32 ratio = (mDistance - mLastUpdateDistance)/(llmax(mLastUpdateDistance, mRadius));
 -
 -		if (fabsf(ratio) >= mSpatialPartition->mSlopRatio)
 -		{
 -			return TRUE;
 -		}
 -
 -		if (mDistance > mRadius*2.f)
 -		{
 -			return FALSE;
 -		}
 -	}
 -	
 -	if (needsUpdate())
 -	{
 -		return TRUE;
 -	}
 -	
 -	return FALSE;
 -}
 -
 -void LLSpatialGroup::handleInsertion(const TreeNode* node, LLDrawable* drawablep)
 -{
 -	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 -	addObject(drawablep, FALSE, TRUE);
 -	unbound();
 -	setState(OBJECT_DIRTY);
 -}
 -
 -void LLSpatialGroup::handleRemoval(const TreeNode* node, LLDrawable* drawable)
 -{
 -	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 -	removeObject(drawable, TRUE);
 -	setState(OBJECT_DIRTY);
 -}
 -
 -void LLSpatialGroup::handleDestruction(const TreeNode* node)
 -{
 -	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 -	setState(DEAD);
 -	
 -	for (element_iter i = getData().begin(); i != getData().end(); ++i)
 -	{
 -		LLDrawable* drawable = *i;
 -		if (drawable->getSpatialGroup() == this)
 -		{
 -			drawable->setSpatialGroup(NULL);
 -		}
 -	}
 -	
 -	//clean up avatar attachment stats
 -	LLSpatialBridge* bridge = mSpatialPartition->asBridge();
 -	if (bridge)
 -	{
 -		if (bridge->mAvatar.notNull())
 -		{
 -			bridge->mAvatar->mAttachmentGeometryBytes -= mGeometryBytes;
 -			bridge->mAvatar->mAttachmentSurfaceArea -= mSurfaceArea;
 -		}
 -	}
 -
 -	clearDrawMap();
 -	mVertexBuffer = NULL;
 -	mBufferMap.clear();
 -	sZombieGroups++;
 -	mOctreeNode = NULL;
 -}
 -
 -void LLSpatialGroup::handleStateChange(const TreeNode* node)
 -{
 -	//drop bounding box upon state change
 -	if (mOctreeNode != node)
 -	{
 -		mOctreeNode = (OctreeNode*) node;
 -	}
 -	unbound();
 -}
 -
 -void LLSpatialGroup::handleChildAddition(const OctreeNode* parent, OctreeNode* child) 
 -{
 -	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 -	if (child->getListenerCount() == 0)
 -	{
 -		new LLSpatialGroup(child, mSpatialPartition);
 -	}
 -	else
 -	{
 -		OCT_ERRS << "LLSpatialGroup redundancy detected." << llendl;
 -	}
 -
 -	unbound();
 -
 -	assert_states_valid(this);
 -}
 -
 -void LLSpatialGroup::handleChildRemoval(const OctreeNode* parent, const OctreeNode* child)
 -{
 -	unbound();
 -}
 -
 -void LLSpatialGroup::destroyGL() 
 -{
 -	setState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::IMAGE_DIRTY);
 -	gPipeline.markRebuild(this, TRUE);
 -
 -	mLastUpdateTime = gFrameTimeSeconds;
 -	mVertexBuffer = NULL;
 -	mBufferMap.clear();
 -
 -	clearDrawMap();
 -
 -	for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
 -	{
 -		if (mOcclusionQuery[i])
 -		{
 -			sQueryPool.release(mOcclusionQuery[i]);
 -			mOcclusionQuery[i] = 0;
 -		}
 -	}
 -
 -	mOcclusionVerts = NULL;
 -
 -	for (LLSpatialGroup::element_iter i = getData().begin(); i != getData().end(); ++i)
 -	{
 -		LLDrawable* drawable = *i;
 -		for (S32 j = 0; j < drawable->getNumFaces(); j++)
 -		{
 -			LLFace* facep = drawable->getFace(j);
 -			facep->clearVertexBuffer();
 -		}
 -	}
 -}
 -
 -BOOL LLSpatialGroup::rebound()
 -{
 -	if (!isState(DIRTY))
 -	{	//return TRUE if we're not empty
 -		return TRUE;
 -	}
 -	
 -	if (mOctreeNode->getChildCount() == 1 && mOctreeNode->getElementCount() == 0)
 -	{
 -		LLSpatialGroup* group = (LLSpatialGroup*) mOctreeNode->getChild(0)->getListener(0);
 -		group->rebound();
 -		
 -		//copy single child's bounding box
 -		mBounds[0] = group->mBounds[0];
 -		mBounds[1] = group->mBounds[1];
 -		mExtents[0] = group->mExtents[0];
 -		mExtents[1] = group->mExtents[1];
 -		
 -		group->setState(SKIP_FRUSTUM_CHECK);
 -	}
 -	else if (mOctreeNode->isLeaf())
 -	{ //copy object bounding box if this is a leaf
 -		boundObjects(TRUE, mExtents[0], mExtents[1]);
 -		mBounds[0] = mObjectBounds[0];
 -		mBounds[1] = mObjectBounds[1];
 -	}
 -	else
 -	{
 -		LLVector4a& newMin = mExtents[0];
 -		LLVector4a& newMax = mExtents[1];
 -		LLSpatialGroup* group = (LLSpatialGroup*) mOctreeNode->getChild(0)->getListener(0);
 -		group->clearState(SKIP_FRUSTUM_CHECK);
 -		group->rebound();
 -		//initialize to first child
 -		newMin = group->mExtents[0];
 -		newMax = group->mExtents[1];
 -
 -		//first, rebound children
 -		for (U32 i = 1; i < mOctreeNode->getChildCount(); i++)
 -		{
 -			group = (LLSpatialGroup*) mOctreeNode->getChild(i)->getListener(0);
 -			group->clearState(SKIP_FRUSTUM_CHECK);
 -			group->rebound();
 -			const LLVector4a& max = group->mExtents[1];
 -			const LLVector4a& min = group->mExtents[0];
 -
 -			newMax.setMax(newMax, max);
 -			newMin.setMin(newMin, min);
 -		}
 -
 -		boundObjects(FALSE, newMin, newMax);
 -		
 -		mBounds[0].setAdd(newMin, newMax);
 -		mBounds[0].mul(0.5f);
 -		mBounds[1].setSub(newMax, newMin);
 -		mBounds[1].mul(0.5f);
 -	}
 -	
 -	setState(OCCLUSION_DIRTY);
 -	
 -	clearState(DIRTY);
 -
 -	return TRUE;
 -}
 -
 -static LLFastTimer::DeclareTimer FTM_OCCLUSION_READBACK("Readback Occlusion");
 -static LLFastTimer::DeclareTimer FTM_OCCLUSION_WAIT("Wait");
 -
 -void LLSpatialGroup::checkOcclusion()
 -{
 -	if (LLPipeline::sUseOcclusion > 1)
 -	{
 -		LLFastTimer t(FTM_OCCLUSION_READBACK);
 -		LLSpatialGroup* parent = getParent();
 -		if (parent && parent->isOcclusionState(LLSpatialGroup::OCCLUDED))
 -		{	//if the parent has been marked as occluded, the child is implicitly occluded
 -			clearOcclusionState(QUERY_PENDING | DISCARD_QUERY);
 -		}
 -		else if (isOcclusionState(QUERY_PENDING))
 -		{	//otherwise, if a query is pending, read it back
 -
 -			GLuint available = 0;
 -			if (mOcclusionQuery[LLViewerCamera::sCurCameraID])
 -			{
 -				glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available);
 -
 -				if (mOcclusionIssued[LLViewerCamera::sCurCameraID] < gFrameCount)
 -				{ //query was issued last frame, wait until it's available
 -					S32 max_loop = 1024;
 -					LLFastTimer t(FTM_OCCLUSION_WAIT);
 -					while (!available && max_loop-- > 0)
 -					{
 -						F32 max_time = llmin(gFrameIntervalSeconds*10.f, 1.f);
 -						//do some usefu work while we wait
 -						LLAppViewer::getTextureCache()->update(max_time); // unpauses the texture cache thread
 -						LLAppViewer::getImageDecodeThread()->update(max_time); // unpauses the image thread
 -						LLAppViewer::getTextureFetch()->update(max_time); // unpauses the texture fetch thread
 -						
 -						glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available);
 -					}
 -				}
 -			}
 -			else
 -			{
 -				available = 1;
 -			}
 -
 -			if (available)
 -			{ //result is available, read it back, otherwise wait until next frame
 -				GLuint res = 1;
 -				if (!isOcclusionState(DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID])
 -				{
 -					glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_ARB, &res);	
 -#if LL_TRACK_PENDING_OCCLUSION_QUERIES
 -					sPendingQueries.erase(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
 -#endif
 -				}
 -				else if (mOcclusionQuery[LLViewerCamera::sCurCameraID])
 -				{ //delete the query to avoid holding onto hundreds of pending queries
 -					sQueryPool.release(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
 -					mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0;
 -				}
 -				
 -				if (isOcclusionState(DISCARD_QUERY))
 -				{
 -					res = 2;
 -				}
 -
 -				if (res > 0)
 -				{
 -					assert_states_valid(this);
 -					clearOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
 -					assert_states_valid(this);
 -				}
 -				else
 -				{
 -					assert_states_valid(this);
 -					setOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
 -					assert_states_valid(this);
 -				}
 -
 -				clearOcclusionState(QUERY_PENDING | DISCARD_QUERY);
 -			}
 -		}
 -		else if (mSpatialPartition->isOcclusionEnabled() && isOcclusionState(LLSpatialGroup::OCCLUDED))
 -		{	//check occlusion has been issued for occluded node that has not had a query issued
 -			assert_states_valid(this);
 -			clearOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
 -			assert_states_valid(this);
 -		}
 -	}
 -}
 -
 -static LLFastTimer::DeclareTimer FTM_PUSH_OCCLUSION_VERTS("Push Occlusion");
 -static LLFastTimer::DeclareTimer FTM_SET_OCCLUSION_STATE("Occlusion State");
 -static LLFastTimer::DeclareTimer FTM_OCCLUSION_EARLY_FAIL("Occlusion Early Fail");
 -static LLFastTimer::DeclareTimer FTM_OCCLUSION_ALLOCATE("Allocate");
 -static LLFastTimer::DeclareTimer FTM_OCCLUSION_BUILD("Build");
 -static LLFastTimer::DeclareTimer FTM_OCCLUSION_BEGIN_QUERY("Begin Query");
 -static LLFastTimer::DeclareTimer FTM_OCCLUSION_END_QUERY("End Query");
 -static LLFastTimer::DeclareTimer FTM_OCCLUSION_SET_BUFFER("Set Buffer");
 -static LLFastTimer::DeclareTimer FTM_OCCLUSION_DRAW_WATER("Draw Water");
 -static LLFastTimer::DeclareTimer FTM_OCCLUSION_DRAW("Draw");
 -
 -
 -
 -void LLSpatialGroup::doOcclusion(LLCamera* camera)
 -{
 -	if (mSpatialPartition->isOcclusionEnabled() && LLPipeline::sUseOcclusion > 1)
 -	{
 -		// Don't cull hole/edge water, unless we have the GL_ARB_depth_clamp extension
 -		if (earlyFail(camera, this))
 -		{
 -			LLFastTimer t(FTM_OCCLUSION_EARLY_FAIL);
 -			setOcclusionState(LLSpatialGroup::DISCARD_QUERY);
 -			assert_states_valid(this);
 -			clearOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
 -			assert_states_valid(this);
 -		}
 -		else
 -		{
 -			if (!isOcclusionState(QUERY_PENDING) || isOcclusionState(DISCARD_QUERY))
 -			{
 -				{ //no query pending, or previous query to be discarded
 -					LLFastTimer t(FTM_RENDER_OCCLUSION);
 -
 -					if (!mOcclusionQuery[LLViewerCamera::sCurCameraID])
 -					{
 -						LLFastTimer t(FTM_OCCLUSION_ALLOCATE);
 -						mOcclusionQuery[LLViewerCamera::sCurCameraID] = sQueryPool.allocate();
 -					}
 -
 -					if (mOcclusionVerts.isNull() || isState(LLSpatialGroup::OCCLUSION_DIRTY))
 -					{
 -						LLFastTimer t(FTM_OCCLUSION_BUILD);
 -						buildOcclusion();
 -					}
 -					
 -					// Depth clamp all water to avoid it being culled as a result of being
 -					// behind the far clip plane, and in the case of edge water to avoid
 -					// it being culled while still visible.
 -					bool const use_depth_clamp = gGLManager.mHasDepthClamp &&
 -												(mSpatialPartition->mDrawableType == LLDrawPool::POOL_WATER ||						
 -												mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER);
 -
 -					LLGLEnable clamp(use_depth_clamp ? GL_DEPTH_CLAMP : 0);				
 -						
 -#if !LL_DARWIN					
 -					U32 mode = gGLManager.mHasOcclusionQuery2 ? GL_ANY_SAMPLES_PASSED : GL_SAMPLES_PASSED_ARB;
 -#else
 -					U32 mode = GL_SAMPLES_PASSED_ARB;
 -#endif
 -					
 -#if LL_TRACK_PENDING_OCCLUSION_QUERIES
 -					sPendingQueries.insert(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
 -#endif
 -
 -					{
 -						LLFastTimer t(FTM_PUSH_OCCLUSION_VERTS);
 -						
 -						//store which frame this query was issued on
 -						mOcclusionIssued[LLViewerCamera::sCurCameraID] = gFrameCount;
 -
 -						{
 -							LLFastTimer t(FTM_OCCLUSION_BEGIN_QUERY);
 -							glBeginQueryARB(mode, mOcclusionQuery[LLViewerCamera::sCurCameraID]);					
 -						}
 -					
 -						{
 -							LLFastTimer t(FTM_OCCLUSION_SET_BUFFER);
 -							mOcclusionVerts->setBuffer(LLVertexBuffer::MAP_VERTEX);
 -						}
 -
 -						if (!use_depth_clamp && mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER)
 -						{
 -							LLFastTimer t(FTM_OCCLUSION_DRAW_WATER);
 -
 -							LLGLSquashToFarClip squash(glh_get_current_projection(), 1);
 -							if (camera->getOrigin().isExactlyZero())
 -							{ //origin is invalid, draw entire box
 -								mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0);
 -								mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8);				
 -							}
 -							else
 -							{
 -								mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0]));
 -							}
 -						}
 -						else
 -						{
 -							LLFastTimer t(FTM_OCCLUSION_DRAW);
 -							if (camera->getOrigin().isExactlyZero())
 -							{ //origin is invalid, draw entire box
 -								mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0);
 -								mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8);				
 -							}
 -							else
 -							{
 -								mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0]));
 -							}
 -						}
 -
 -
 -						{
 -							LLFastTimer t(FTM_OCCLUSION_END_QUERY);
 -							glEndQueryARB(mode);
 -						}
 -					}
 -				}
 -
 -				{
 -					LLFastTimer t(FTM_SET_OCCLUSION_STATE);
 -					setOcclusionState(LLSpatialGroup::QUERY_PENDING);
 -					clearOcclusionState(LLSpatialGroup::DISCARD_QUERY);
 -				}
 -			}
 -		}
 -	}
 -}
 -
 -//==============================================
 -
 -LLSpatialPartition::LLSpatialPartition(U32 data_mask, BOOL render_by_group, U32 buffer_usage)
 -: mRenderByGroup(render_by_group), mBridge(NULL)
 -{
 -	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 -	mOcclusionEnabled = TRUE;
 -	mDrawableType = 0;
 -	mPartitionType = LLViewerRegion::PARTITION_NONE;
 -	mLODSeed = 0;
 -	mLODPeriod = 1;
 -	mVertexDataMask = data_mask;
 -	mBufferUsage = buffer_usage;
 -	mDepthMask = FALSE;
 -	mSlopRatio = 0.25f;
 -	mInfiniteFarClip = FALSE;
 -
 -	LLVector4a center, size;
 -	center.splat(0.f);
 -	size.splat(1.f);
 -
 -	mOctree = new LLSpatialGroup::OctreeRoot(center,size,
 -											NULL);
 -	new LLSpatialGroup(mOctree, this);
 -}
 -
 -
 -LLSpatialPartition::~LLSpatialPartition()
 -{
 -	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 -	
 -	delete mOctree;
 -	mOctree = NULL;
 -}
 -
 -
 -LLSpatialGroup *LLSpatialPartition::put(LLDrawable *drawablep, BOOL was_visible)
 -{
 -	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 -		
 -	drawablep->updateSpatialExtents();
 -
 -	//keep drawable from being garbage collected
 -	LLPointer<LLDrawable> ptr = drawablep;
 -		
 -	assert_octree_valid(mOctree);
 -	mOctree->insert(drawablep);
 -	assert_octree_valid(mOctree);
 -	
 -	LLSpatialGroup* group = drawablep->getSpatialGroup();
 -
 -	if (group && was_visible && group->isOcclusionState(LLSpatialGroup::QUERY_PENDING))
 -	{
 -		group->setOcclusionState(LLSpatialGroup::DISCARD_QUERY, LLSpatialGroup::STATE_MODE_ALL_CAMERAS);
 -	}
 -
 -	return group;
 -}
 -
 -BOOL LLSpatialPartition::remove(LLDrawable *drawablep, LLSpatialGroup *curp)
 -{
 -	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 -	
 -	drawablep->setSpatialGroup(NULL);
 -
 -	if (!curp->removeObject(drawablep))
 -	{
 -		OCT_ERRS << "Failed to remove drawable from octree!" << llendl;
 -	}
 -
 -	assert_octree_valid(mOctree);
 -	
 -	return TRUE;
 -}
 -
 -void LLSpatialPartition::move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL immediate)
 -{
 -	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 -		
 -	// sanity check submitted by open source user bushing Spatula
 -	// who was seeing crashing here. (See VWR-424 reported by Bunny Mayne)
 -	if (!drawablep)
 -	{
 -		OCT_ERRS << "LLSpatialPartition::move was passed a bad drawable." << llendl;
 -		return;
 -	}
 -		
 -	BOOL was_visible = curp ? curp->isVisible() : FALSE;
 -
 -	if (curp && curp->mSpatialPartition != this)
 -	{
 -		//keep drawable from being garbage collected
 -		LLPointer<LLDrawable> ptr = drawablep;
 -		if (curp->mSpatialPartition->remove(drawablep, curp))
 -		{
 -			put(drawablep, was_visible);
 -			return;
 -		}
 -		else
 -		{
 -			OCT_ERRS << "Drawable lost between spatial partitions on outbound transition." << llendl;
 -		}
 -	}
 -		
 -	if (curp && curp->updateInGroup(drawablep, immediate))
 -	{
 -		// Already updated, don't need to do anything
 -		assert_octree_valid(mOctree);
 -		return;
 -	}
 -
 -	//keep drawable from being garbage collected
 -	LLPointer<LLDrawable> ptr = drawablep;
 -	if (curp && !remove(drawablep, curp))
 -	{
 -		OCT_ERRS << "Move couldn't find existing spatial group!" << llendl;
 -	}
 -
 -	put(drawablep, was_visible);
 -}
 -
 -class LLSpatialShift : public LLSpatialGroup::OctreeTraveler
 -{
 -public:
 -	const LLVector4a& mOffset;
 -
 -	LLSpatialShift(const LLVector4a& offset) : mOffset(offset) { }
 -	virtual void visit(const LLSpatialGroup::OctreeNode* branch) 
 -	{ 
 -		((LLSpatialGroup*) branch->getListener(0))->shift(mOffset); 
 -	}
 -};
 -
 -void LLSpatialPartition::shift(const LLVector4a &offset)
 -{ //shift octree node bounding boxes by offset
 -	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 -	LLSpatialShift shifter(offset);
 -	shifter.traverse(mOctree);
 -}
 -
 -class LLOctreeCull : public LLSpatialGroup::OctreeTraveler
 -{
 -public:
 -	LLOctreeCull(LLCamera* camera)
 -		: mCamera(camera), mRes(0) { }
 -
 -	virtual bool earlyFail(LLSpatialGroup* group)
 -	{
 -		group->checkOcclusion();
 -
 -		if (group->mOctreeNode->getParent() &&	//never occlusion cull the root node
 -		  	LLPipeline::sUseOcclusion &&			//ignore occlusion if disabled
 -			group->isOcclusionState(LLSpatialGroup::OCCLUDED))
 -		{
 -			gPipeline.markOccluder(group);
 -			return true;
 -		}
 -		
 -		return false;
 -	}
 -	
 -	virtual void traverse(const LLSpatialGroup::OctreeNode* n)
 -	{
 -		LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
 -
 -		if (earlyFail(group))
 -		{
 -			return;
 -		}
 -		
 -		if (mRes == 2 || 
 -			(mRes && group->isState(LLSpatialGroup::SKIP_FRUSTUM_CHECK)))
 -		{	//fully in, just add everything
 -			LLSpatialGroup::OctreeTraveler::traverse(n);
 -		}
 -		else
 -		{
 -			mRes = frustumCheck(group);
 -				
 -			if (mRes)
 -			{ //at least partially in, run on down
 -				LLSpatialGroup::OctreeTraveler::traverse(n);
 -			}
 -
 -			mRes = 0;
 -		}
 -	}
 -	
 -	virtual S32 frustumCheck(const LLSpatialGroup* group)
 -	{
 -		S32 res = mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]);
 -		if (res != 0)
 -		{
 -			res = llmin(res, AABBSphereIntersect(group->mExtents[0], group->mExtents[1], mCamera->getOrigin(), mCamera->mFrustumCornerDist));
 -		}
 -		return res;
 -	}
 -
 -	virtual S32 frustumCheckObjects(const LLSpatialGroup* group)
 -	{
 -		S32 res = mCamera->AABBInFrustumNoFarClip(group->mObjectBounds[0], group->mObjectBounds[1]);
 -		if (res != 0)
 -		{
 -			res = llmin(res, AABBSphereIntersect(group->mObjectExtents[0], group->mObjectExtents[1], mCamera->getOrigin(), mCamera->mFrustumCornerDist));
 -		}
 -		return res;
 -	}
 -
 -	virtual bool checkObjects(const LLSpatialGroup::OctreeNode* branch, const LLSpatialGroup* group)
 -	{
 -		if (branch->getElementCount() == 0) //no elements
 -		{
 -			return false;
 -		}
 -		else if (branch->getChildCount() == 0) //leaf state, already checked tightest bounding box
 -		{
 -			return true;
 -		}
 -		else if (mRes == 1 && !frustumCheckObjects(group)) //no objects in frustum
 -		{
 -			return false;
 -		}
 -		
 -		return true;
 -	}
 -
 -	virtual void preprocess(LLSpatialGroup* group)
 -	{
 -		
 -	}
 -	
 -	virtual void processGroup(LLSpatialGroup* group)
 -	{
 -		if (group->needsUpdate() ||
 -			group->mVisible[LLViewerCamera::sCurCameraID] < LLDrawable::getCurrentFrame() - 1)
 -		{
 -			group->doOcclusion(mCamera);
 -		}
 -		gPipeline.markNotCulled(group, *mCamera);
 -	}
 -	
 -	virtual void visit(const LLSpatialGroup::OctreeNode* branch) 
 -	{	
 -		LLSpatialGroup* group = (LLSpatialGroup*) branch->getListener(0);
 -
 -		preprocess(group);
 -		
 -		if (checkObjects(branch, group))
 -		{
 -			processGroup(group);
 -		}
 -	}
 -
 -	LLCamera *mCamera;
 -	S32 mRes;
 -};
 -
 -class LLOctreeCullNoFarClip : public LLOctreeCull
 -{
 -public: 
 -	LLOctreeCullNoFarClip(LLCamera* camera) 
 -		: LLOctreeCull(camera) { }
 -
 -	virtual S32 frustumCheck(const LLSpatialGroup* group)
 -	{
 -		return mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]);
 -	}
 -
 -	virtual S32 frustumCheckObjects(const LLSpatialGroup* group)
 -	{
 -		S32 res = mCamera->AABBInFrustumNoFarClip(group->mObjectBounds[0], group->mObjectBounds[1]);
 -		return res;
 -	}
 -};
 -
 -class LLOctreeCullShadow : public LLOctreeCull
 -{
 -public:
 -	LLOctreeCullShadow(LLCamera* camera)
 -		: LLOctreeCull(camera) { }
 -
 -	virtual S32 frustumCheck(const LLSpatialGroup* group)
 -	{
 -		return mCamera->AABBInFrustum(group->mBounds[0], group->mBounds[1]);
 -	}
 -
 -	virtual S32 frustumCheckObjects(const LLSpatialGroup* group)
 -	{
 -		return mCamera->AABBInFrustum(group->mObjectBounds[0], group->mObjectBounds[1]);
 -	}
 -};
 -
 -class LLOctreeCullVisExtents: public LLOctreeCullShadow
 -{
 -public:
 -	LLOctreeCullVisExtents(LLCamera* camera, LLVector4a& min, LLVector4a& max)
 -		: LLOctreeCullShadow(camera), mMin(min), mMax(max), mEmpty(TRUE) { }
 -
 -	virtual bool earlyFail(LLSpatialGroup* group)
 -	{
 -		if (group->mOctreeNode->getParent() &&	//never occlusion cull the root node
 -			LLPipeline::sUseOcclusion &&			//ignore occlusion if disabled
 -			group->isOcclusionState(LLSpatialGroup::OCCLUDED))
 -		{
 -			return true;
 -		}
 -		
 -		return false;
 -	}
 -
 -	virtual void traverse(const LLSpatialGroup::OctreeNode* n)
 -	{
 -		LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
 -
 -		if (earlyFail(group))
 -		{
 -			return;
 -		}
 -		
 -		if ((mRes && group->isState(LLSpatialGroup::SKIP_FRUSTUM_CHECK)) ||
 -			mRes == 2)
 -		{	//don't need to do frustum check
 -			LLSpatialGroup::OctreeTraveler::traverse(n);
 -		}
 -		else
 -		{  
 -			mRes = frustumCheck(group);
 -				
 -			if (mRes)
 -			{ //at least partially in, run on down
 -				LLSpatialGroup::OctreeTraveler::traverse(n);
 -			}
 -
 -			mRes = 0;
 -		}
 -	}
 -
 -	virtual void processGroup(LLSpatialGroup* group)
 -	{
 -		llassert(!group->isState(LLSpatialGroup::DIRTY) && !group->getData().empty())
 -		
 -		if (mRes < 2)
 -		{
 -			if (mCamera->AABBInFrustum(group->mObjectBounds[0], group->mObjectBounds[1]) > 0)
 -			{
 -				mEmpty = FALSE;
 -				update_min_max(mMin, mMax, group->mObjectExtents[0]);
 -				update_min_max(mMin, mMax, group->mObjectExtents[1]);
 -			}
 -		}
 -		else
 -		{
 -			mEmpty = FALSE;
 -			update_min_max(mMin, mMax, group->mExtents[0]);
 -			update_min_max(mMin, mMax, group->mExtents[1]);
 -		}
 -	}
 -
 -	BOOL mEmpty;
 -	LLVector4a& mMin;
 -	LLVector4a& mMax;
 -};
 -
 -class LLOctreeCullDetectVisible: public LLOctreeCullShadow
 -{
 -public:
 -	LLOctreeCullDetectVisible(LLCamera* camera)
 -		: LLOctreeCullShadow(camera), mResult(FALSE) { }
 -
 -	virtual bool earlyFail(LLSpatialGroup* group)
 -	{
 -		if (mResult || //already found a node, don't check any more
 -			(group->mOctreeNode->getParent() &&	//never occlusion cull the root node
 -			 LLPipeline::sUseOcclusion &&			//ignore occlusion if disabled
 -			 group->isOcclusionState(LLSpatialGroup::OCCLUDED)))
 -		{
 -			return true;
 -		}
 -		
 -		return false;
 -	}
 -
 -	virtual void processGroup(LLSpatialGroup* group)
 -	{
 -		if (group->isVisible())
 -		{
 -			mResult = TRUE;
 -		}
 -	}
 -
 -	BOOL mResult;
 -};
 -
 -class LLOctreeSelect : public LLOctreeCull
 -{
 -public:
 -	LLOctreeSelect(LLCamera* camera, std::vector<LLDrawable*>* results)
 -		: LLOctreeCull(camera), mResults(results) { }
 -
 -	virtual bool earlyFail(LLSpatialGroup* group) { return false; }
 -	virtual void preprocess(LLSpatialGroup* group) { }
 -
 -	virtual void processGroup(LLSpatialGroup* group)
 -	{
 -		LLSpatialGroup::OctreeNode* branch = group->mOctreeNode;
 -
 -		for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i)
 -		{
 -			LLDrawable* drawable = *i;
 -			
 -			if (!drawable->isDead())
 -			{
 -				if (drawable->isSpatialBridge())
 -				{
 -					drawable->setVisible(*mCamera, mResults, TRUE);
 -				}
 -				else
 -				{
 -					mResults->push_back(drawable);
 -				}
 -			}		
 -		}
 -	}
 -	
 -	std::vector<LLDrawable*>* mResults;
 -};
 -
 -void drawBox(const LLVector3& c, const LLVector3& r)
 -{
 -	LLVertexBuffer::unbind();
 -
 -	gGL.begin(LLRender::TRIANGLE_STRIP);
 -	//left front
 -	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,-1))).mV);
 -	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,1))).mV);
 -	//right front
 -	gGL.vertex3fv((c+r.scaledVec(LLVector3(1,1,-1))).mV);
 -	gGL.vertex3fv((c+r.scaledVec(LLVector3(1,1,1))).mV);
 -	//right back
 - 	gGL.vertex3fv((c+r.scaledVec(LLVector3(1,-1,-1))).mV);
 -	gGL.vertex3fv((c+r.scaledVec(LLVector3(1,-1,1))).mV);
 -	//left back
 -	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,-1,-1))).mV);
 -	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,-1,1))).mV);
 -	//left front
 -	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,-1))).mV);
 -	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,1))).mV);
 -	gGL.end();
 -	
 -	//bottom
 -	gGL.begin(LLRender::TRIANGLE_STRIP);
 -	gGL.vertex3fv((c+r.scaledVec(LLVector3(1,1,-1))).mV);
 -	gGL.vertex3fv((c+r.scaledVec(LLVector3(1,-1,-1))).mV);
 -	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,-1))).mV);
 -	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,-1,-1))).mV);
 -	gGL.end();
 -
 -	//top
 -	gGL.begin(LLRender::TRIANGLE_STRIP);
 -	gGL.vertex3fv((c+r.scaledVec(LLVector3(1,1,1))).mV);
 -	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,1))).mV);
 -	gGL.vertex3fv((c+r.scaledVec(LLVector3(1,-1,1))).mV);
 -	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,-1,1))).mV);
 -	gGL.end();	
 -}
 -
 -void drawBox(const LLVector4a& c, const LLVector4a& r)
 -{
 -	drawBox(reinterpret_cast<const LLVector3&>(c), reinterpret_cast<const LLVector3&>(r));
 -}
 -
 -void drawBoxOutline(const LLVector3& pos, const LLVector3& size)
 -{
 -	LLVector3 v1 = size.scaledVec(LLVector3( 1, 1,1));
 -	LLVector3 v2 = size.scaledVec(LLVector3(-1, 1,1));
 -	LLVector3 v3 = size.scaledVec(LLVector3(-1,-1,1));
 -	LLVector3 v4 = size.scaledVec(LLVector3( 1,-1,1));
 -
 -	gGL.begin(LLRender::LINES); 
 -	
 -	//top
 -	gGL.vertex3fv((pos+v1).mV);
 -	gGL.vertex3fv((pos+v2).mV);
 -	gGL.vertex3fv((pos+v2).mV);
 -	gGL.vertex3fv((pos+v3).mV);
 -	gGL.vertex3fv((pos+v3).mV);
 -	gGL.vertex3fv((pos+v4).mV);
 -	gGL.vertex3fv((pos+v4).mV);
 -	gGL.vertex3fv((pos+v1).mV);
 -	
 -	//bottom
 -	gGL.vertex3fv((pos-v1).mV);
 -	gGL.vertex3fv((pos-v2).mV);
 -	gGL.vertex3fv((pos-v2).mV);
 -	gGL.vertex3fv((pos-v3).mV);
 -	gGL.vertex3fv((pos-v3).mV);
 -	gGL.vertex3fv((pos-v4).mV);
 -	gGL.vertex3fv((pos-v4).mV);
 -	gGL.vertex3fv((pos-v1).mV);
 -	
 -	//right
 -	gGL.vertex3fv((pos+v1).mV);
 -	gGL.vertex3fv((pos-v3).mV);
 -			
 -	gGL.vertex3fv((pos+v4).mV);
 -	gGL.vertex3fv((pos-v2).mV);
 -
 -	//left
 -	gGL.vertex3fv((pos+v2).mV);
 -	gGL.vertex3fv((pos-v4).mV);
 -
 -	gGL.vertex3fv((pos+v3).mV);
 -	gGL.vertex3fv((pos-v1).mV);
 -
 -	gGL.end();
 -}
 -
 -void drawBoxOutline(const LLVector4a& pos, const LLVector4a& size)
 -{
 -	drawBoxOutline(reinterpret_cast<const LLVector3&>(pos), reinterpret_cast<const LLVector3&>(size));
 -}
 -
 -class LLOctreeDirty : public LLOctreeTraveler<LLDrawable>
 -{
 -public:
 -	virtual void visit(const LLOctreeNode<LLDrawable>* state)
 -	{
 -		LLSpatialGroup* group = (LLSpatialGroup*) state->getListener(0);
 -		group->destroyGL();
 -
 -		for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
 -		{
 -			LLDrawable* drawable = *i;
 -			if (drawable->getVObj().notNull() && !group->mSpatialPartition->mRenderByGroup)
 -			{
 -				gPipeline.markRebuild(drawable, LLDrawable::REBUILD_ALL, TRUE);
 -			}
 -		}
 -
 -		for (LLSpatialGroup::bridge_list_t::iterator i = group->mBridgeList.begin(); i != group->mBridgeList.end(); ++i)
 -		{
 -			LLSpatialBridge* bridge = *i;
 -			traverse(bridge->mOctree);
 -		}
 -	}
 -};
 -
 -void LLSpatialPartition::restoreGL()
 -{
 -	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 -}
 -
 -void LLSpatialPartition::resetVertexBuffers()
 -{
 -	LLOctreeDirty dirty;
 -	dirty.traverse(mOctree);
 -}
 -
 -BOOL LLSpatialPartition::isOcclusionEnabled()
 -{
 -	return mOcclusionEnabled || LLPipeline::sUseOcclusion > 2;
 -}
 -
 -BOOL LLSpatialPartition::getVisibleExtents(LLCamera& camera, LLVector3& visMin, LLVector3& visMax)
 -{
 -	LLVector4a visMina, visMaxa;
 -	visMina.load3(visMin.mV);
 -	visMaxa.load3(visMax.mV);
 -
 -	{
 -		LLFastTimer ftm(FTM_CULL_REBOUND);		
 -		LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0);
 -		group->rebound();
 -	}
 -
 -	LLOctreeCullVisExtents vis(&camera, visMina, visMaxa);
 -	vis.traverse(mOctree);
 -
 -	visMin.set(visMina.getF32ptr());
 -	visMax.set(visMaxa.getF32ptr());
 -	return vis.mEmpty;
 -}
 -
 -BOOL LLSpatialPartition::visibleObjectsInFrustum(LLCamera& camera)
 -{
 -	LLOctreeCullDetectVisible vis(&camera);
 -	vis.traverse(mOctree);
 -	return vis.mResult;
 -}
 -
 -S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* results, BOOL for_select)
 -{
 -	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 -#if LL_OCTREE_PARANOIA_CHECK
 -	((LLSpatialGroup*)mOctree->getListener(0))->checkStates();
 -#endif
 -	{
 -		LLFastTimer ftm(FTM_CULL_REBOUND);		
 -		LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0);
 -		group->rebound();
 -	}
 -
 -#if LL_OCTREE_PARANOIA_CHECK
 -	((LLSpatialGroup*)mOctree->getListener(0))->validate();
 -#endif
 -
 -	
 -	if (for_select)
 -	{
 -		LLOctreeSelect selecter(&camera, results);
 -		selecter.traverse(mOctree);
 -	}
 -	else if (LLPipeline::sShadowRender)
 -	{
 -		LLFastTimer ftm(FTM_FRUSTUM_CULL);
 -		LLOctreeCullShadow culler(&camera);
 -		culler.traverse(mOctree);
 -	}
 -	else if (mInfiniteFarClip || !LLPipeline::sUseFarClip)
 -	{
 -		LLFastTimer ftm(FTM_FRUSTUM_CULL);		
 -		LLOctreeCullNoFarClip culler(&camera);
 -		culler.traverse(mOctree);
 -	}
 -	else
 -	{
 -		LLFastTimer ftm(FTM_FRUSTUM_CULL);		
 -		LLOctreeCull culler(&camera);
 -		culler.traverse(mOctree);
 -	}
 -	
 -	return 0;
 -}
 -
 -BOOL earlyFail(LLCamera* camera, LLSpatialGroup* group)
 -{
 -	if (camera->getOrigin().isExactlyZero())
 -	{
 -		return FALSE;
 -	}
 -
 -	const F32 vel = SG_OCCLUSION_FUDGE*2.f;
 -	LLVector4a fudge;
 -	fudge.splat(vel);
 -
 -	const LLVector4a& c = group->mBounds[0];
 -	LLVector4a r;
 -	r.setAdd(group->mBounds[1], fudge);
 -
 -	/*if (r.magVecSquared() > 1024.0*1024.0)
 -	{
 -		return TRUE;
 -	}*/
 -
 -	LLVector4a e;
 -	e.load3(camera->getOrigin().mV);
 -	
 -	LLVector4a min;
 -	min.setSub(c,r);
 -	LLVector4a max;
 -	max.setAdd(c,r);
 -	
 -	S32 lt = e.lessThan(min).getGatheredBits() & 0x7;
 -	if (lt)
 -	{
 -		return FALSE;
 -	}
 -
 -	S32 gt = e.greaterThan(max).getGatheredBits() & 0x7;
 -	if (gt)
 -	{
 -		return FALSE;
 -	}
 -
 -	return TRUE;
 -}
 -
 -
 -void pushVerts(LLDrawInfo* params, U32 mask)
 -{
 -	LLRenderPass::applyModelMatrix(*params);
 -	params->mVertexBuffer->setBuffer(mask);
 -	params->mVertexBuffer->drawRange(params->mParticle ? LLRender::POINTS : LLRender::TRIANGLES,
 -								params->mStart, params->mEnd, params->mCount, params->mOffset);
 -}
 -
 -void pushVerts(LLSpatialGroup* group, U32 mask)
 -{
 -	LLDrawInfo* params = NULL;
 -
 -	for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i)
 -	{
 -		for (LLSpatialGroup::drawmap_elem_t::iterator j = i->second.begin(); j != i->second.end(); ++j) 
 -		{
 -			params = *j;
 -			pushVerts(params, mask);
 -		}
 -	}
 -}
 -
 -void pushVerts(LLFace* face, U32 mask)
 -{
 -	llassert(face->verify());
 -
 -	LLVertexBuffer* buffer = face->getVertexBuffer();
 -
 -	if (buffer && (face->getGeomCount() >= 3))
 -	{
 -		buffer->setBuffer(mask);
 -		U16 start = face->getGeomStart();
 -		U16 end = start + face->getGeomCount()-1;
 -		U32 count = face->getIndicesCount();
 -		U16 offset = face->getIndicesStart();
 -		buffer->drawRange(LLRender::TRIANGLES, start, end, count, offset);
 -	}
 -}
 -
 -void pushVerts(LLDrawable* drawable, U32 mask)
 -{
 -	for (S32 i = 0; i < drawable->getNumFaces(); ++i)
 -	{
 -		pushVerts(drawable->getFace(i), mask);
 -	}
 -}
 -
 -void pushVerts(LLVolume* volume)
 -{
 -	LLVertexBuffer::unbind();
 -	for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
 -	{
 -		const LLVolumeFace& face = volume->getVolumeFace(i);
 -		LLVertexBuffer::drawElements(LLRender::TRIANGLES, face.mPositions, NULL, face.mNumIndices, face.mIndices);
 -	}
 -}
 -
 -void pushBufferVerts(LLVertexBuffer* buffer, U32 mask)
 -{
 -	if (buffer)
 -	{
 -		buffer->setBuffer(mask);
 -		buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
 -	}
 -}
 -
 -void pushBufferVerts(LLSpatialGroup* group, U32 mask)
 -{
 -	if (group->mSpatialPartition->mRenderByGroup)
 -	{
 -		if (!group->mDrawMap.empty())
 -		{
 -			LLDrawInfo* params = *(group->mDrawMap.begin()->second.begin());
 -			LLRenderPass::applyModelMatrix(*params);
 -		
 -			pushBufferVerts(group->mVertexBuffer, mask);
 -
 -			for (LLSpatialGroup::buffer_map_t::iterator i = group->mBufferMap.begin(); i != group->mBufferMap.end(); ++i)
 -			{
 -				for (LLSpatialGroup::buffer_texture_map_t::iterator j = i->second.begin(); j != i->second.end(); ++j)
 -				{
 -					for (LLSpatialGroup::buffer_list_t::iterator k = j->second.begin(); k != j->second.end(); ++k)
 -					{
 -						pushBufferVerts(*k, mask);
 -					}
 -				}
 -			}
 -		}
 -	}
 -	else
 -	{
 -		drawBox(group->mBounds[0], group->mBounds[1]);
 -	}
 -}
 -
 -void pushVertsColorCoded(LLSpatialGroup* group, U32 mask)
 -{
 -	LLDrawInfo* params = NULL;
 -
 -	LLColor4 colors[] = {
 -		LLColor4::green,
 -		LLColor4::green1,
 -		LLColor4::green2,
 -		LLColor4::green3,
 -		LLColor4::green4,
 -		LLColor4::green5,
 -		LLColor4::green6
 -	};
 -		
 -	static const U32 col_count = LL_ARRAY_SIZE(colors);
 -
 -	U32 col = 0;
 -
 -	for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i)
 -	{
 -		for (LLSpatialGroup::drawmap_elem_t::iterator j = i->second.begin(); j != i->second.end(); ++j) 
 -		{
 -			params = *j;
 -			LLRenderPass::applyModelMatrix(*params);
 -			gGL.diffuseColor4f(colors[col].mV[0], colors[col].mV[1], colors[col].mV[2], 0.5f);
 -			params->mVertexBuffer->setBuffer(mask);
 -			params->mVertexBuffer->drawRange(params->mParticle ? LLRender::POINTS : LLRender::TRIANGLES,
 -				params->mStart, params->mEnd, params->mCount, params->mOffset);
 -			col = (col+1)%col_count;
 -		}
 -	}
 -}
 -
 -void renderOctree(LLSpatialGroup* group)
 -{
 -	//render solid object bounding box, color
 -	//coded by buffer usage and activity
 -	gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA);
 -	LLVector4 col;
 -	if (group->mBuilt > 0.f)
 -	{
 -		group->mBuilt -= 2.f * gFrameIntervalSeconds;
 -		if (group->mBufferUsage == GL_STATIC_DRAW_ARB)
 -		{
 -			col.setVec(1.0f, 0, 0, group->mBuilt*0.5f);
 -		}
 -		else 
 -		{
 -			col.setVec(0.1f,0.1f,1,0.1f);
 -			//col.setVec(1.0f, 1.0f, 0, sinf(group->mBuilt*3.14159f)*0.5f);
 -		}
 -
 -		if (group->mBufferUsage != GL_STATIC_DRAW_ARB)
 -		{
 -			LLGLDepthTest gl_depth(FALSE, FALSE);
 -			glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 -
 -			gGL.diffuseColor4f(1,0,0,group->mBuilt);
 -			gGL.flush();
 -			glLineWidth(5.f);
 -			drawBoxOutline(group->mObjectBounds[0], group->mObjectBounds[1]);
 -			gGL.flush();
 -			glLineWidth(1.f);
 -			gGL.flush();
 -			for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
 -			{
 -				LLDrawable* drawable = *i;
 -				if (!group->mSpatialPartition->isBridge())
 -				{
 -					gGL.pushMatrix();
 -					LLVector3 trans = drawable->getRegion()->getOriginAgent();
 -					gGL.translatef(trans.mV[0], trans.mV[1], trans.mV[2]);
 -				}
 -				
 -				for (S32 j = 0; j < drawable->getNumFaces(); j++)
 -				{
 -					LLFace* face = drawable->getFace(j);
 -					if (face->getVertexBuffer())
 -					{
 -						if (gFrameTimeSeconds - face->mLastUpdateTime < 0.5f)
 -						{
 -							gGL.diffuseColor4f(0, 1, 0, group->mBuilt);
 -						}
 -						else if (gFrameTimeSeconds - face->mLastMoveTime < 0.5f)
 -						{
 -							gGL.diffuseColor4f(1, 0, 0, group->mBuilt);
 -						}
 -						else
 -						{
 -							continue;
 -						}
 -
 -						face->getVertexBuffer()->setBuffer(LLVertexBuffer::MAP_VERTEX);
 -						//drawBox((face->mExtents[0] + face->mExtents[1])*0.5f,
 -						//		(face->mExtents[1]-face->mExtents[0])*0.5f);
 -						face->getVertexBuffer()->draw(LLRender::TRIANGLES, face->getIndicesCount(), face->getIndicesStart());
 -					}
 -				}
 -
 -				if (!group->mSpatialPartition->isBridge())
 -				{
 -					gGL.popMatrix();
 -				}
 -			}
 -			glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 -			gGL.diffuseColor4f(1,1,1,1);
 -		}
 -	}
 -	else
 -	{
 -		if (group->mBufferUsage == GL_STATIC_DRAW_ARB && !group->getData().empty() 
 -			&& group->mSpatialPartition->mRenderByGroup)
 -		{
 -			col.setVec(0.8f, 0.4f, 0.1f, 0.1f);
 -		}
 -		else
 -		{
 -			col.setVec(0.1f, 0.1f, 1.f, 0.1f);
 -		}
 -	}
 -
 -	gGL.diffuseColor4fv(col.mV);
 -	LLVector4a fudge;
 -	fudge.splat(0.001f);
 -	LLVector4a size = group->mObjectBounds[1];
 -	size.mul(1.01f);
 -	size.add(fudge);
 -
 -	//{
 -	//	LLGLDepthTest depth(GL_TRUE, GL_FALSE);
 -	//	drawBox(group->mObjectBounds[0], fudge);
 -	//}
 -	
 -	gGL.setSceneBlendType(LLRender::BT_ALPHA);
 -
 -	//if (group->mBuilt <= 0.f)
 -	{
 -		//draw opaque outline
 -		//gGL.diffuseColor4f(col.mV[0], col.mV[1], col.mV[2], 1.f);
 -		//drawBoxOutline(group->mObjectBounds[0], group->mObjectBounds[1]);
 -
 -		gGL.diffuseColor4f(0,1,1,1);
 -		drawBoxOutline(group->mBounds[0],group->mBounds[1]);
 -		
 -		//draw bounding box for draw info
 -		/*if (group->mSpatialPartition->mRenderByGroup)
 -		{
 -			gGL.diffuseColor4f(1.0f, 0.75f, 0.25f, 0.6f);
 -			for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i)
 -			{
 -				for (LLSpatialGroup::drawmap_elem_t::iterator j = i->second.begin(); j != i->second.end(); ++j)
 -				{
 -					LLDrawInfo* draw_info = *j;
 -					LLVector4a center;
 -					center.setAdd(draw_info->mExtents[1], draw_info->mExtents[0]);
 -					center.mul(0.5f);
 -					LLVector4a size;
 -					size.setSub(draw_info->mExtents[1], draw_info->mExtents[0]);
 -					size.mul(0.5f);
 -					drawBoxOutline(center, size);
 -				}
 -			}
 -		}*/
 -	}
 -	
 -//	LLSpatialGroup::OctreeNode* node = group->mOctreeNode;
 -//	gGL.diffuseColor4f(0,1,0,1);
 -//	drawBoxOutline(LLVector3(node->getCenter()), LLVector3(node->getSize()));
 -}
 -
 -void renderVisibility(LLSpatialGroup* group, LLCamera* camera)
 -{
 -	LLGLEnable blend(GL_BLEND);
 -	gGL.setSceneBlendType(LLRender::BT_ALPHA);
 -	LLGLEnable cull(GL_CULL_FACE);
 -	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 -
 -	BOOL render_objects = (!LLPipeline::sUseOcclusion || !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) && group->isVisible() &&
 -							!group->getData().empty();
 -
 -	if (render_objects)
 -	{
 -		LLGLDepthTest depth_under(GL_TRUE, GL_FALSE, GL_GREATER);
 -		gGL.diffuseColor4f(0, 0.5f, 0, 0.5f);
 -		gGL.diffuseColor4f(0, 0.5f, 0, 0.5f);
 -		pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX);
 -	}
 -
 -	{
 -		LLGLDepthTest depth_over(GL_TRUE, GL_FALSE, GL_LEQUAL);
 -
 -		if (render_objects)
 -		{
 -			gGL.diffuseColor4f(0.f, 0.5f, 0.f,1.f);
 -			gGL.diffuseColor4f(0.f, 0.5f, 0.f, 1.f);
 -			pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX);
 -		}
 -
 -		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 -
 -		if (render_objects)
 -		{
 -			gGL.diffuseColor4f(0.f, 0.75f, 0.f,0.5f);
 -			gGL.diffuseColor4f(0.f, 0.75f, 0.f, 0.5f);
 -			pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX);
 -		}
 -		/*else if (camera && group->mOcclusionVerts.notNull())
 -		{
 -			LLVertexBuffer::unbind();
 -			group->mOcclusionVerts->setBuffer(LLVertexBuffer::MAP_VERTEX);
 -			
 -			gGL.diffuseColor4f(1.0f, 0.f, 0.f, 0.5f);
 -			group->mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, group->mBounds[0]));
 -			glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 -			
 -			gGL.diffuseColor4f(1.0f, 1.f, 1.f, 1.0f);
 -			group->mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, group->mBounds[0]));
 -			glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 -		}*/
 -	}
 -}
 -
 -void renderCrossHairs(LLVector3 position, F32 size, LLColor4 color)
 -{
 -	gGL.diffuseColor4fv(color.mV);
 -	gGL.begin(LLRender::LINES);
 -	{
 -		gGL.vertex3fv((position - LLVector3(size, 0.f, 0.f)).mV);
 -		gGL.vertex3fv((position + LLVector3(size, 0.f, 0.f)).mV);
 -		gGL.vertex3fv((position - LLVector3(0.f, size, 0.f)).mV);
 -		gGL.vertex3fv((position + LLVector3(0.f, size, 0.f)).mV);
 -		gGL.vertex3fv((position - LLVector3(0.f, 0.f, size)).mV);
 -		gGL.vertex3fv((position + LLVector3(0.f, 0.f, size)).mV);
 -	}
 -	gGL.end();
 -}
 -
 -void renderUpdateType(LLDrawable* drawablep)
 -{
 -	LLViewerObject* vobj = drawablep->getVObj();
 -	if (!vobj || OUT_UNKNOWN == vobj->getLastUpdateType())
 -	{
 -		return;
 -	}
 -	LLGLEnable blend(GL_BLEND);
 -	switch (vobj->getLastUpdateType())
 -	{
 -	case OUT_FULL:
 -		gGL.diffuseColor4f(0,1,0,0.5f);
 -		break;
 -	case OUT_TERSE_IMPROVED:
 -		gGL.diffuseColor4f(0,1,1,0.5f);
 -		break;
 -	case OUT_FULL_COMPRESSED:
 -		if (vobj->getLastUpdateCached())
 -		{
 -			gGL.diffuseColor4f(1,0,0,0.5f);
 -		}
 -		else
 -		{
 -			gGL.diffuseColor4f(1,1,0,0.5f);
 -		}
 -		break;
 -	case OUT_FULL_CACHED:
 -		gGL.diffuseColor4f(0,0,1,0.5f);
 -		break;
 -	default:
 -		llwarns << "Unknown update_type " << vobj->getLastUpdateType() << llendl;
 -		break;
 -	};
 -	S32 num_faces = drawablep->getNumFaces();
 -	if (num_faces)
 -	{
 -		for (S32 i = 0; i < num_faces; ++i)
 -		{
 -			pushVerts(drawablep->getFace(i), LLVertexBuffer::MAP_VERTEX);
 -		}
 -	}
 -}
 -
 -void renderComplexityDisplay(LLDrawable* drawablep)
 -{
 -	LLViewerObject* vobj = drawablep->getVObj();
 -	if (!vobj)
 -	{
 -		return;
 -	}
 -
 -	LLVOVolume *voVol = dynamic_cast<LLVOVolume*>(vobj);
 -
 -	if (!voVol)
 -	{
 -		return;
 -	}
 -
 -	if (!voVol->isRoot())
 -	{
 -		return;
 -	}
 -
 -	LLVOVolume::texture_cost_t textures;
 -	F32 cost = (F32) voVol->getRenderCost(textures);
 -
 -	// add any child volumes
 -	LLViewerObject::const_child_list_t children = voVol->getChildren();
 -	for (LLViewerObject::const_child_list_t::const_iterator iter = children.begin(); iter != children.end(); ++iter)
 -	{
 -		const LLViewerObject *child = *iter;
 -		const LLVOVolume *child_volume = dynamic_cast<const LLVOVolume*>(child);
 -		if (child_volume)
 -		{
 -			cost += child_volume->getRenderCost(textures);
 -		}
 -	}
 -
 -	// add texture cost
 -	for (LLVOVolume::texture_cost_t::iterator iter = textures.begin(); iter != textures.end(); ++iter)
 -	{
 -		// add the cost of each individual texture in the linkset
 -		cost += iter->second;
 -	}
 -
 -	F32 cost_max = (F32) LLVOVolume::getRenderComplexityMax();
 -
 -
 -
 -	// allow user to set a static color scale
 -	if (gSavedSettings.getS32("RenderComplexityStaticMax") > 0)
 -	{
 -		cost_max = gSavedSettings.getS32("RenderComplexityStaticMax");
 -	}
 -
 -	F32 cost_ratio = cost / cost_max;
 -	
 -	// cap cost ratio at 1.0f in case cost_max is at a low threshold
 -	cost_ratio = cost_ratio > 1.0f ? 1.0f : cost_ratio;
 -	
 -	LLGLEnable blend(GL_BLEND);
 -
 -	LLColor4 color;
 -	const LLColor4 color_min = gSavedSettings.getColor4("RenderComplexityColorMin");
 -	const LLColor4 color_mid = gSavedSettings.getColor4("RenderComplexityColorMid");
 -	const LLColor4 color_max = gSavedSettings.getColor4("RenderComplexityColorMax");
 -
 -	if (cost_ratio < 0.5f)
 -	{
 -		color = color_min * (1 - cost_ratio * 2) + color_mid * (cost_ratio * 2);
 -	}
 -	else
 -	{
 -		color = color_mid * (1 - (cost_ratio - 0.5) * 2) + color_max * ((cost_ratio - 0.5) * 2);
 -	}
 -
 -	LLSD color_val = color.getValue();
 -
 -	// don't highlight objects below the threshold
 -	if (cost > gSavedSettings.getS32("RenderComplexityThreshold"))
 -	{
 -		glColor4f(color[0],color[1],color[2],0.5f);
 -
 -
 -		S32 num_faces = drawablep->getNumFaces();
 -		if (num_faces)
 -		{
 -			for (S32 i = 0; i < num_faces; ++i)
 -			{
 -				pushVerts(drawablep->getFace(i), LLVertexBuffer::MAP_VERTEX);
 -			}
 -		}
 -		LLViewerObject::const_child_list_t children = voVol->getChildren();
 -		for (LLViewerObject::const_child_list_t::const_iterator iter = children.begin(); iter != children.end(); ++iter)
 -		{
 -			const LLViewerObject *child = *iter;
 -			if (child)
 -			{
 -				num_faces = child->getNumFaces();
 -				if (num_faces)
 -				{
 -					for (S32 i = 0; i < num_faces; ++i)
 -					{
 -						pushVerts(child->mDrawable->getFace(i), LLVertexBuffer::MAP_VERTEX);
 -					}
 -				}
 -			}
 -		}
 -	}
 -	
 -	voVol->setDebugText(llformat("%4.0f", cost));	
 -}
 -
 -void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE)
 -{
 -	if (set_color)
 -	{
 -		if (drawable->isSpatialBridge())
 -		{
 -			gGL.diffuseColor4f(1,0.5f,0,1);
 -		}
 -		else if (drawable->getVOVolume())
 -		{
 -			if (drawable->isRoot())
 -			{
 -				gGL.diffuseColor4f(1,1,0,1);
 -			}
 -			else
 -			{
 -				gGL.diffuseColor4f(0,1,0,1);
 -			}
 -		}
 -		else if (drawable->getVObj())
 -		{
 -			switch (drawable->getVObj()->getPCode())
 -			{
 -				case LLViewerObject::LL_VO_SURFACE_PATCH:
 -						gGL.diffuseColor4f(0,1,1,1);
 -						break;
 -				case LLViewerObject::LL_VO_CLOUDS:
 -						// no longer used
 -						break;
 -				case LLViewerObject::LL_VO_PART_GROUP:
 -				case LLViewerObject::LL_VO_HUD_PART_GROUP:
 -						gGL.diffuseColor4f(0,0,1,1);
 -						break;
 -				case LLViewerObject::LL_VO_VOID_WATER:
 -				case LLViewerObject::LL_VO_WATER:
 -						gGL.diffuseColor4f(0,0.5f,1,1);
 -						break;
 -				case LL_PCODE_LEGACY_TREE:
 -						gGL.diffuseColor4f(0,0.5f,0,1);
 -						break;
 -				default:
 -						gGL.diffuseColor4f(1,0,1,1);
 -						break;
 -			}
 -		}
 -		else 
 -		{
 -			gGL.diffuseColor4f(1,0,0,1);
 -		}
 -	}
 -
 -	const LLVector4a* ext;
 -	LLVector4a pos, size;
 -
 -	//render face bounding boxes
 -	for (S32 i = 0; i < drawable->getNumFaces(); i++)
 -	{
 -		LLFace* facep = drawable->getFace(i);
 -
 -		ext = facep->mExtents;
 -
 -		pos.setAdd(ext[0], ext[1]);
 -		pos.mul(0.5f);
 -		size.setSub(ext[1], ext[0]);
 -		size.mul(0.5f);
 -		
 -		drawBoxOutline(pos,size);
 -	}
 -
 -	//render drawable bounding box
 -	ext = drawable->getSpatialExtents();
 -
 -	pos.setAdd(ext[0], ext[1]);
 -	pos.mul(0.5f);
 -	size.setSub(ext[1], ext[0]);
 -	size.mul(0.5f);
 -	
 -	LLViewerObject* vobj = drawable->getVObj();
 -	if (vobj && vobj->onActiveList())
 -	{
 -		gGL.flush();
 -		glLineWidth(llmax(4.f*sinf(gFrameTimeSeconds*2.f)+1.f, 1.f));
 -		//glLineWidth(4.f*(sinf(gFrameTimeSeconds*2.f)*0.25f+0.75f));
 -		stop_glerror();
 -		drawBoxOutline(pos,size);
 -		gGL.flush();
 -		glLineWidth(1.f);
 -	}
 -	else
 -	{
 -		drawBoxOutline(pos,size);
 -	}
 -}
 -
 -void renderNormals(LLDrawable* drawablep)
 -{
 -	LLVertexBuffer::unbind();
 -
 -	LLVOVolume* vol = drawablep->getVOVolume();
 -	if (vol)
 -	{
 -		LLVolume* volume = vol->getVolume();
 -		gGL.pushMatrix();
 -		gGL.multMatrix((F32*) vol->getRelativeXform().mMatrix);
 -		
 -		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 -
 -		LLVector4a scale(gSavedSettings.getF32("RenderDebugNormalScale"));
 -
 -		for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
 -		{
 -			const LLVolumeFace& face = volume->getVolumeFace(i);
 -
 -			for (S32 j = 0; j < face.mNumVertices; ++j)
 -			{
 -				gGL.begin(LLRender::LINES);
 -				LLVector4a n,p;
 -				
 -				n.setMul(face.mNormals[j], scale);
 -				p.setAdd(face.mPositions[j], n);
 -				
 -				gGL.diffuseColor4f(1,1,1,1);
 -				gGL.vertex3fv(face.mPositions[j].getF32ptr());
 -				gGL.vertex3fv(p.getF32ptr());
 -				
 -				if (face.mBinormals)
 -				{
 -					n.setMul(face.mBinormals[j], scale);
 -					p.setAdd(face.mPositions[j], n);
 -				
 -					gGL.diffuseColor4f(0,1,1,1);
 -					gGL.vertex3fv(face.mPositions[j].getF32ptr());
 -					gGL.vertex3fv(p.getF32ptr());
 -				}	
 -				gGL.end();
 -			}
 -		}
 -
 -		gGL.popMatrix();
 -	}
 -}
 -
 -S32 get_physics_detail(const LLVolumeParams& volume_params, const LLVector3& scale)
 -{
 -	const S32 DEFAULT_DETAIL = 1;
 -	const F32 LARGE_THRESHOLD = 5.f;
 -	const F32 MEGA_THRESHOLD = 25.f;
 -
 -	S32 detail = DEFAULT_DETAIL;
 -	F32 avg_scale = (scale[0]+scale[1]+scale[2])/3.f;
 -
 -	if (avg_scale > LARGE_THRESHOLD)
 -	{
 -		detail += 1;
 -		if (avg_scale > MEGA_THRESHOLD)
 -		{
 -			detail += 1;
 -		}
 -	}
 -
 -	return detail;
 -}
 -
 -void renderMeshBaseHull(LLVOVolume* volume, U32 data_mask, LLColor4& color, LLColor4& line_color)
 -{
 -	LLUUID mesh_id = volume->getVolume()->getParams().getSculptID();
 -	LLModel::Decomposition* decomp = gMeshRepo.getDecomposition(mesh_id);
 -
 -	const LLVector3 center(0,0,0);
 -	const LLVector3 size(0.25f,0.25f,0.25f);
 -
 -	if (decomp)
 -	{		
 -		if (!decomp->mBaseHullMesh.empty())
 -		{
 -			gGL.diffuseColor4fv(color.mV);
 -			LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mBaseHullMesh.mPositions, decomp->mBaseHullMesh.mNormals);
 -		}
 -		else
 -		{
 -			gMeshRepo.buildPhysicsMesh(*decomp);
 -			gGL.diffuseColor4f(0,1,1,1);
 -			drawBoxOutline(center, size);
 -		}
 -
 -	}
 -	else
 -	{
 -		gGL.diffuseColor3f(1,0,1);
 -		drawBoxOutline(center, size);
 -	}
 -}
 -
 -void render_hull(LLModel::PhysicsMesh& mesh, const LLColor4& color, const LLColor4& line_color)
 -{
 -	gGL.diffuseColor4fv(color.mV);
 -	LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions, mesh.mNormals);
 -	LLGLEnable offset(GL_POLYGON_OFFSET_LINE);
 -	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 -	glPolygonOffset(3.f, 3.f);
 -	glLineWidth(3.f);
 -	gGL.diffuseColor4fv(line_color.mV);
 -	LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions, mesh.mNormals);
 -	glLineWidth(1.f);
 -	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 -}
 -
 -void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume)
 -{
 -	U8 physics_type = volume->getPhysicsShapeType();
 -
 -	if (physics_type == LLViewerObject::PHYSICS_SHAPE_NONE || volume->isFlexible())
 -	{
 -		return;
 -	}
 -
 -	//not allowed to return at this point without rendering *something*
 -
 -	F32 threshold = gSavedSettings.getF32("ObjectCostHighThreshold");
 -	F32 cost = volume->getObjectCost();
 -
 -	LLColor4 low = gSavedSettings.getColor4("ObjectCostLowColor");
 -	LLColor4 mid = gSavedSettings.getColor4("ObjectCostMidColor");
 -	LLColor4 high = gSavedSettings.getColor4("ObjectCostHighColor");
 -
 -	F32 normalizedCost = 1.f - exp( -(cost / threshold) );
 -
 -	LLColor4 color;
 -	if ( normalizedCost <= 0.5f )
 -	{
 -		color = lerp( low, mid, 2.f * normalizedCost );
 -	}
 -	else
 -	{
 -		color = lerp( mid, high, 2.f * ( normalizedCost - 0.5f ) );
 -	}
 -
 -	LLColor4 line_color = color*0.5f;
 -
 -	U32 data_mask = LLVertexBuffer::MAP_VERTEX;
 -
 -	LLVolumeParams volume_params = volume->getVolume()->getParams();
 -
 -	LLPhysicsVolumeParams physics_params(volume_params, 
 -		physics_type == LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL); 
 -
 -	LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification physics_spec;
 -	LLPhysicsShapeBuilderUtil::determinePhysicsShape(physics_params, volume->getScale(), physics_spec);
 -
 -	U32 type = physics_spec.getType();
 -
 -	LLVector3 center(0,0,0);
 -	LLVector3 size(0.25f,0.25f,0.25f);
 -
 -	gGL.pushMatrix();
 -	gGL.multMatrix((F32*) volume->getRelativeXform().mMatrix);
 -		
 -	if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::USER_MESH)
 -	{
 -		LLUUID mesh_id = volume->getVolume()->getParams().getSculptID();
 -		LLModel::Decomposition* decomp = gMeshRepo.getDecomposition(mesh_id);
 -			
 -		if (decomp)
 -		{ //render a physics based mesh
 -			
 -			gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 -
 -			if (!decomp->mHull.empty())
 -			{ //decomposition exists, use that
 -
 -				if (decomp->mMesh.empty())
 -				{
 -					gMeshRepo.buildPhysicsMesh(*decomp);
 -				}
 -
 -				for (U32 i = 0; i < decomp->mMesh.size(); ++i)
 -				{		
 -					render_hull(decomp->mMesh[i], color, line_color);
 -				}
 -			}
 -			else if (!decomp->mPhysicsShapeMesh.empty())
 -			{ 
 -				//decomp has physics mesh, render that mesh
 -				gGL.diffuseColor4fv(color.mV);
 -				LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions, decomp->mPhysicsShapeMesh.mNormals);
 -								
 -				glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 -				gGL.diffuseColor4fv(line_color.mV);
 -				LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions, decomp->mPhysicsShapeMesh.mNormals);
 -				glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 -			}
 -			else
 -			{ //no mesh or decomposition, render base hull
 -				renderMeshBaseHull(volume, data_mask, color, line_color);
 -
 -				if (decomp->mPhysicsShapeMesh.empty())
 -				{
 -					//attempt to fetch physics shape mesh if available
 -					gMeshRepo.fetchPhysicsShape(mesh_id);
 -				}
 -			}
 -		}
 -		else
 -		{	
 -			gGL.diffuseColor3f(1,1,0);
 -			drawBoxOutline(center, size);
 -		}
 -	}
 -	else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::USER_CONVEX ||
 -		type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::PRIM_CONVEX)
 -	{
 -		if (volume->isMesh())
 -		{
 -			renderMeshBaseHull(volume, data_mask, color, line_color);
 -		}
 -		else
 -		{
 -			LLVolumeParams volume_params = volume->getVolume()->getParams();
 -			S32 detail = get_physics_detail(volume_params, volume->getScale());
 -			LLVolume* phys_volume = LLPrimitive::sVolumeManager->refVolume(volume_params, detail);
 -
 -			if (!phys_volume->mHullPoints)
 -			{ //build convex hull
 -				std::vector<LLVector3> pos;
 -				std::vector<U16> index;
 -
 -				S32 index_offset = 0;
 -
 -				for (S32 i = 0; i < phys_volume->getNumVolumeFaces(); ++i)
 -				{
 -					const LLVolumeFace& face = phys_volume->getVolumeFace(i);
 -					if (index_offset + face.mNumVertices > 65535)
 -					{
 -						continue;
 -					}
 -
 -					for (S32 j = 0; j < face.mNumVertices; ++j)
 -					{
 -						pos.push_back(LLVector3(face.mPositions[j].getF32ptr()));
 -					}
 -
 -					for (S32 j = 0; j < face.mNumIndices; ++j)
 -					{
 -						index.push_back(face.mIndices[j]+index_offset);
 -					}
 -
 -					index_offset += face.mNumVertices;
 -				}
 -
 -				if (!pos.empty() && !index.empty())
 -				{
 -					LLCDMeshData mesh;
 -					mesh.mIndexBase = &index[0];
 -					mesh.mVertexBase = pos[0].mV;
 -					mesh.mNumVertices = pos.size();
 -					mesh.mVertexStrideBytes = 12;
 -					mesh.mIndexStrideBytes = 6;
 -					mesh.mIndexType = LLCDMeshData::INT_16;
 -
 -					mesh.mNumTriangles = index.size()/3;
 -					
 -					LLCDMeshData res;
 -
 -					LLConvexDecomposition::getInstance()->generateSingleHullMeshFromMesh( &mesh, &res );
 -
 -					//copy res into phys_volume
 -					phys_volume->mHullPoints = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*res.mNumVertices);
 -					phys_volume->mNumHullPoints = res.mNumVertices;
 -
 -					S32 idx_size = (res.mNumTriangles*3*2+0xF) & ~0xF;
 -					phys_volume->mHullIndices = (U16*) ll_aligned_malloc_16(idx_size);
 -					phys_volume->mNumHullIndices = res.mNumTriangles*3;
 -
 -					const F32* v = res.mVertexBase;
 -
 -					for (S32 i = 0; i < res.mNumVertices; ++i)
 -					{
 -						F32* p = (F32*) ((U8*)v+i*res.mVertexStrideBytes);
 -						phys_volume->mHullPoints[i].load3(p);
 -					}
 -
 -					if (res.mIndexType == LLCDMeshData::INT_16)
 -					{
 -						for (S32 i = 0; i < res.mNumTriangles; ++i)
 -						{
 -							U16* idx = (U16*) (((U8*)res.mIndexBase)+i*res.mIndexStrideBytes);
 -
 -							phys_volume->mHullIndices[i*3+0] = idx[0];
 -							phys_volume->mHullIndices[i*3+1] = idx[1];
 -							phys_volume->mHullIndices[i*3+2] = idx[2];
 -						}
 -					}
 -					else
 -					{
 -						for (S32 i = 0; i < res.mNumTriangles; ++i)
 -						{
 -							U32* idx = (U32*) (((U8*)res.mIndexBase)+i*res.mIndexStrideBytes);
 -
 -							phys_volume->mHullIndices[i*3+0] = (U16) idx[0];
 -							phys_volume->mHullIndices[i*3+1] = (U16) idx[1];
 -							phys_volume->mHullIndices[i*3+2] = (U16) idx[2];
 -						}
 -					}
 -				}
 -			}
 -
 -			if (phys_volume->mHullPoints)
 -			{
 -				//render hull
 -			
 -				glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 -				
 -				gGL.diffuseColor4fv(line_color.mV);
 -				LLVertexBuffer::unbind();
 -
 -				llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShader != 0);
 -							
 -				LLVertexBuffer::drawElements(LLRender::TRIANGLES, phys_volume->mHullPoints, NULL, phys_volume->mNumHullIndices, phys_volume->mHullIndices);
 -				
 -				gGL.diffuseColor4fv(color.mV);
 -				glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 -				LLVertexBuffer::drawElements(LLRender::TRIANGLES, phys_volume->mHullPoints, NULL, phys_volume->mNumHullIndices, phys_volume->mHullIndices);
 -				
 -			}
 -			else
 -			{
 -				gGL.diffuseColor4f(1,0,1,1);
 -				drawBoxOutline(center, size);
 -			}
 -
 -			LLPrimitive::sVolumeManager->unrefVolume(phys_volume);
 -		}
 -	}
 -	else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::BOX)
 -	{
 -		LLVector3 center = physics_spec.getCenter();
 -		LLVector3 scale = physics_spec.getScale();
 -		LLVector3 vscale = volume->getScale()*2.f;
 -		scale.set(scale[0]/vscale[0], scale[1]/vscale[1], scale[2]/vscale[2]);
 -		
 -		gGL.diffuseColor4fv(color.mV);
 -		drawBox(center, scale);
 -	}
 -	else if	(type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::SPHERE)
 -	{
 -		/*LLVolumeParams volume_params;
 -		volume_params.setType( LL_PCODE_PROFILE_CIRCLE_HALF, LL_PCODE_PATH_CIRCLE );
 -		volume_params.setBeginAndEndS( 0.f, 1.f );
 -		volume_params.setBeginAndEndT( 0.f, 1.f );
 -		volume_params.setRatio	( 1, 1 );
 -		volume_params.setShear	( 0, 0 );
 -		LLVolume* sphere = LLPrimitive::sVolumeManager->refVolume(volume_params, 3);
 -		
 -		gGL.diffuseColor4fv(color.mV);
 -		pushVerts(sphere);
 -		LLPrimitive::sVolumeManager->unrefVolume(sphere);*/
 -	}
 -	else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::CYLINDER)
 -	{
 -		LLVolumeParams volume_params;
 -		volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE );
 -		volume_params.setBeginAndEndS( 0.f, 1.f );
 -		volume_params.setBeginAndEndT( 0.f, 1.f );
 -		volume_params.setRatio	( 1, 1 );
 -		volume_params.setShear	( 0, 0 );
 -		LLVolume* cylinder = LLPrimitive::sVolumeManager->refVolume(volume_params, 3);
 -		
 -		gGL.diffuseColor4fv(color.mV);
 -		pushVerts(cylinder);
 -		LLPrimitive::sVolumeManager->unrefVolume(cylinder);
 -	}
 -	else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::PRIM_MESH)
 -	{
 -		LLVolumeParams volume_params = volume->getVolume()->getParams();
 -		S32 detail = get_physics_detail(volume_params, volume->getScale());
 -
 -		LLVolume* phys_volume = LLPrimitive::sVolumeManager->refVolume(volume_params, detail);
 -		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 -		
 -		gGL.diffuseColor4fv(line_color.mV);
 -		pushVerts(phys_volume);
 -		
 -		gGL.diffuseColor4fv(color.mV);
 -		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 -		pushVerts(phys_volume);
 -		LLPrimitive::sVolumeManager->unrefVolume(phys_volume);
 -	}
 -	else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::PRIM_CONVEX)
 -	{
 -		LLVolumeParams volume_params = volume->getVolume()->getParams();
 -		S32 detail = get_physics_detail(volume_params, volume->getScale());
 -
 -		LLVolume* phys_volume = LLPrimitive::sVolumeManager->refVolume(volume_params, detail);
 -
 -		if (phys_volume->mHullPoints && phys_volume->mHullIndices)
 -		{
 -			glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 -			llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShader != 0);
 -			LLVertexBuffer::unbind();
 -			glVertexPointer(3, GL_FLOAT, 16, phys_volume->mHullPoints);
 -			gGL.diffuseColor4fv(line_color.mV);
 -			gGL.syncMatrices();
 -			glDrawElements(GL_TRIANGLES, phys_volume->mNumHullIndices, GL_UNSIGNED_SHORT, phys_volume->mHullIndices);
 -			
 -			gGL.diffuseColor4fv(color.mV);
 -			glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 -			glDrawElements(GL_TRIANGLES, phys_volume->mNumHullIndices, GL_UNSIGNED_SHORT, phys_volume->mHullIndices);			
 -		}
 -		else
 -		{
 -			gGL.diffuseColor3f(1,0,1);
 -			drawBoxOutline(center, size);
 -			gMeshRepo.buildHull(volume_params, detail);
 -		}
 -		LLPrimitive::sVolumeManager->unrefVolume(phys_volume);
 -	}
 -	else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::SCULPT)
 -	{
 -		//TODO: implement sculpted prim physics display
 -	}
 -	else 
 -	{
 -		llerrs << "Unhandled type" << llendl;
 -	}
 -
 -	gGL.popMatrix();
 -}
 -
 -void renderPhysicsShapes(LLSpatialGroup* group)
 -{
 -	for (LLSpatialGroup::OctreeNode::const_element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
 -	{
 -		LLDrawable* drawable = *i;
 -		LLVOVolume* volume = drawable->getVOVolume();
 -		if (volume && !volume->isAttachment() && volume->getPhysicsShapeType() != LLViewerObject::PHYSICS_SHAPE_NONE )
 -		{
 -			if (!group->mSpatialPartition->isBridge())
 -			{
 -				gGL.pushMatrix();
 -				LLVector3 trans = drawable->getRegion()->getOriginAgent();
 -				gGL.translatef(trans.mV[0], trans.mV[1], trans.mV[2]);
 -				renderPhysicsShape(drawable, volume);
 -				gGL.popMatrix();
 -			}
 -			else
 -			{
 -				renderPhysicsShape(drawable, volume);
 -			}
 -		}
 -		else
 -		{
 -			LLViewerObject* object = drawable->getVObj();
 -			if (object && object->getPCode() == LLViewerObject::LL_VO_SURFACE_PATCH)
 -			{
 -				//push face vertices for terrain
 -				for (S32 i = 0; i < drawable->getNumFaces(); ++i)
 -				{
 -					LLFace* face = drawable->getFace(i);
 -					LLVertexBuffer* buff = face->getVertexBuffer();
 -					if (buff)
 -					{
 -						glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 -
 -						buff->setBuffer(LLVertexBuffer::MAP_VERTEX);
 -						gGL.diffuseColor3f(0.2f, 0.5f, 0.3f);
 -						buff->draw(LLRender::TRIANGLES, buff->getNumIndices(), 0);
 -									
 -						gGL.diffuseColor3f(0.2f, 1.f, 0.3f);
 -						glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 -						buff->draw(LLRender::TRIANGLES, buff->getNumIndices(), 0);
 -					}
 -				}
 -			}
 -		}
 -	}
 -}
 -
 -void renderTexturePriority(LLDrawable* drawable)
 -{
 -	for (int face=0; face<drawable->getNumFaces(); ++face)
 -	{
 -		LLFace *facep = drawable->getFace(face);
 -		
 -		LLVector4 cold(0,0,0.25f);
 -		LLVector4 hot(1,0.25f,0.25f);
 -	
 -		LLVector4 boost_cold(0,0,0,0);
 -		LLVector4 boost_hot(0,1,0,1);
 -		
 -		LLGLDisable blend(GL_BLEND);
 -		
 -		//LLViewerTexture* imagep = facep->getTexture();
 -		//if (imagep)
 -		{
 -				
 -			//F32 vsize = imagep->mMaxVirtualSize;
 -			F32 vsize = facep->getPixelArea();
 -
 -			if (vsize > sCurMaxTexPriority)
 -			{
 -				sCurMaxTexPriority = vsize;
 -			}
 -			
 -			F32 t = vsize/sLastMaxTexPriority;
 -			
 -			LLVector4 col = lerp(cold, hot, t);
 -			gGL.diffuseColor4fv(col.mV);
 -		}
 -		//else
 -		//{
 -		//	gGL.diffuseColor4f(1,0,1,1);
 -		//}
 -		
 -		LLVector4a center;
 -		center.setAdd(facep->mExtents[1],facep->mExtents[0]);
 -		center.mul(0.5f);
 -		LLVector4a size;
 -		size.setSub(facep->mExtents[1],facep->mExtents[0]);
 -		size.mul(0.5f);
 -		size.add(LLVector4a(0.01f));
 -		drawBox(center, size);
 -		
 -		/*S32 boost = imagep->getBoostLevel();
 -		if (boost>LLViewerTexture::BOOST_NONE)
 -		{
 -			F32 t = (F32) boost / (F32) (LLViewerTexture::BOOST_MAX_LEVEL-1);
 -			LLVector4 col = lerp(boost_cold, boost_hot, t);
 -			LLGLEnable blend_on(GL_BLEND);
 -			gGL.blendFunc(GL_SRC_ALPHA, GL_ONE);
 -			gGL.diffuseColor4fv(col.mV);
 -			drawBox(center, size);
 -			gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 -		}*/
 -	}
 -}
 -
 -void renderPoints(LLDrawable* drawablep)
 -{
 -	LLGLDepthTest depth(GL_FALSE, GL_FALSE);
 -	if (drawablep->getNumFaces())
 -	{
 -		gGL.begin(LLRender::POINTS);
 -		gGL.diffuseColor3f(1,1,1);
 -		for (S32 i = 0; i < drawablep->getNumFaces(); i++)
 -		{
 -			gGL.vertex3fv(drawablep->getFace(i)->mCenterLocal.mV);
 -		}
 -		gGL.end();
 -	}
 -}
 -
 -void renderTextureAnim(LLDrawInfo* params)
 -{
 -	if (!params->mTextureMatrix)
 -	{
 -		return;
 -	}
 -	
 -	LLGLEnable blend(GL_BLEND);
 -	gGL.diffuseColor4f(1,1,0,0.5f);
 -	pushVerts(params, LLVertexBuffer::MAP_VERTEX);
 -}
 -
 -void renderBatchSize(LLDrawInfo* params)
 -{
 -	LLGLEnable offset(GL_POLYGON_OFFSET_FILL);
 -	glPolygonOffset(-1.f, 1.f);
 -	gGL.diffuseColor4ubv((GLubyte*) &(params->mDebugColor));
 -	pushVerts(params, LLVertexBuffer::MAP_VERTEX);
 -}
 -
 -void renderShadowFrusta(LLDrawInfo* params)
 -{
 -	LLGLEnable blend(GL_BLEND);
 -	gGL.setSceneBlendType(LLRender::BT_ADD);
 -
 -	LLVector4a center;
 -	center.setAdd(params->mExtents[1], params->mExtents[0]);
 -	center.mul(0.5f);
 -	LLVector4a size;
 -	size.setSub(params->mExtents[1],params->mExtents[0]);
 -	size.mul(0.5f);
 -
 -	if (gPipeline.mShadowCamera[4].AABBInFrustum(center, size))
 -	{
 -		gGL.diffuseColor3f(1,0,0);
 -		pushVerts(params, LLVertexBuffer::MAP_VERTEX);
 -	}
 -	if (gPipeline.mShadowCamera[5].AABBInFrustum(center, size))
 -	{
 -		gGL.diffuseColor3f(0,1,0);
 -		pushVerts(params, LLVertexBuffer::MAP_VERTEX);
 -	}
 -	if (gPipeline.mShadowCamera[6].AABBInFrustum(center, size))
 -	{
 -		gGL.diffuseColor3f(0,0,1);
 -		pushVerts(params, LLVertexBuffer::MAP_VERTEX);
 -	}
 -	if (gPipeline.mShadowCamera[7].AABBInFrustum(center, size))
 -	{
 -		gGL.diffuseColor3f(1,0,1);
 -		pushVerts(params, LLVertexBuffer::MAP_VERTEX);
 -	}
 -
 -	gGL.setSceneBlendType(LLRender::BT_ALPHA);
 -}
 -
 -
 -void renderLights(LLDrawable* drawablep)
 -{
 -	if (!drawablep->isLight())
 -	{
 -		return;
 -	}
 -
 -	if (drawablep->getNumFaces())
 -	{
 -		LLGLEnable blend(GL_BLEND);
 -		gGL.diffuseColor4f(0,1,1,0.5f);
 -
 -		for (S32 i = 0; i < drawablep->getNumFaces(); i++)
 -		{
 -			pushVerts(drawablep->getFace(i), LLVertexBuffer::MAP_VERTEX);
 -		}
 -
 -		const LLVector4a* ext = drawablep->getSpatialExtents();
 -
 -		LLVector4a pos;
 -		pos.setAdd(ext[0], ext[1]);
 -		pos.mul(0.5f);
 -		LLVector4a size;
 -		size.setSub(ext[1], ext[0]);
 -		size.mul(0.5f);
 -
 -		{
 -			LLGLDepthTest depth(GL_FALSE, GL_TRUE);
 -			gGL.diffuseColor4f(1,1,1,1);
 -			drawBoxOutline(pos, size);
 -		}
 -
 -		gGL.diffuseColor4f(1,1,0,1);
 -		F32 rad = drawablep->getVOVolume()->getLightRadius();
 -		drawBoxOutline(pos, LLVector4a(rad));
 -	}
 -}
 -
 -class LLRenderOctreeRaycast : public LLOctreeTriangleRayIntersect
 -{
 -public:
 -	
 -	
 -	LLRenderOctreeRaycast(const LLVector4a& start, const LLVector4a& dir, F32* closest_t)
 -		: LLOctreeTriangleRayIntersect(start, dir, NULL, closest_t, NULL, NULL, NULL, NULL)
 -	{
 -
 -	}
 -
 -	void visit(const LLOctreeNode<LLVolumeTriangle>* branch)
 -	{
 -		LLVolumeOctreeListener* vl = (LLVolumeOctreeListener*) branch->getListener(0);
 -
 -		LLVector3 center, size;
 -		
 -		if (branch->getData().empty())
 -		{
 -			gGL.diffuseColor3f(1.f,0.2f,0.f);
 -			center.set(branch->getCenter().getF32ptr());
 -			size.set(branch->getSize().getF32ptr());
 -		}
 -		else
 -		{
 -			gGL.diffuseColor3f(0.75f, 1.f, 0.f);
 -			center.set(vl->mBounds[0].getF32ptr());
 -			size.set(vl->mBounds[1].getF32ptr());
 -		}
 -
 -		drawBoxOutline(center, size);	
 -		
 -		for (U32 i = 0; i < 2; i++)
 -		{
 -			LLGLDepthTest depth(GL_TRUE, GL_FALSE, i == 1 ? GL_LEQUAL : GL_GREATER);
 -
 -			if (i == 1)
 -			{
 -				gGL.diffuseColor4f(0,1,1,0.5f);
 -			}
 -			else
 -			{
 -				gGL.diffuseColor4f(0,0.5f,0.5f, 0.25f);
 -				drawBoxOutline(center, size);
 -			}
 -			
 -			if (i == 1)
 -			{
 -				gGL.flush();
 -				glLineWidth(3.f);
 -			}
 -
 -			gGL.begin(LLRender::TRIANGLES);
 -			for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter = branch->getData().begin();
 -					iter != branch->getData().end();
 -					++iter)
 -			{
 -				const LLVolumeTriangle* tri = *iter;
 -				
 -				gGL.vertex3fv(tri->mV[0]->getF32ptr());
 -				gGL.vertex3fv(tri->mV[1]->getF32ptr());
 -				gGL.vertex3fv(tri->mV[2]->getF32ptr());
 -			}	
 -			gGL.end();
 -
 -			if (i == 1)
 -			{
 -				gGL.flush();
 -				glLineWidth(1.f);
 -			}
 -		}
 -	}
 -};
 -
 -void renderRaycast(LLDrawable* drawablep)
 -{
 -	if (drawablep->getNumFaces())
 -	{
 -		LLGLEnable blend(GL_BLEND);
 -		gGL.diffuseColor4f(0,1,1,0.5f);
 -
 -		if (drawablep->getVOVolume())
 -		{
 -			//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 -			//pushVerts(drawablep->getFace(gDebugRaycastFaceHit), LLVertexBuffer::MAP_VERTEX);
 -			//glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 -
 -			LLVOVolume* vobj = drawablep->getVOVolume();
 -			LLVolume* volume = vobj->getVolume();
 -
 -			bool transform = true;
 -			if (drawablep->isState(LLDrawable::RIGGED))
 -			{
 -				volume = vobj->getRiggedVolume();
 -				transform = false;
 -			}
 -
 -			if (volume)
 -			{
 -				LLVector3 trans = drawablep->getRegion()->getOriginAgent();
 -				
 -				for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
 -				{
 -					const LLVolumeFace& face = volume->getVolumeFace(i);
 -					
 -					gGL.pushMatrix();
 -					gGL.translatef(trans.mV[0], trans.mV[1], trans.mV[2]);					
 -					gGL.multMatrix((F32*) vobj->getRelativeXform().mMatrix);
 -
 -					LLVector3 start, end;
 -					if (transform)
 -					{
 -						start = vobj->agentPositionToVolume(gDebugRaycastStart);
 -						end = vobj->agentPositionToVolume(gDebugRaycastEnd);
 -					}
 -					else
 -					{
 -						start = gDebugRaycastStart;
 -						end = gDebugRaycastEnd;
 -					}
 -
 -					LLVector4a starta, enda;
 -					starta.load3(start.mV);
 -					enda.load3(end.mV);
 -					LLVector4a dir;
 -					dir.setSub(enda, starta);
 -
 -					gGL.flush();
 -					glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);				
 -
 -					{
 -						//render face positions
 -						LLVertexBuffer::unbind();
 -						gGL.diffuseColor4f(0,1,1,0.5f);
 -						glVertexPointer(3, GL_FLOAT, sizeof(LLVector4a), face.mPositions);
 -						gGL.syncMatrices();
 -						glDrawElements(GL_TRIANGLES, face.mNumIndices, GL_UNSIGNED_SHORT, face.mIndices);
 -					}
 -					
 -					if (!volume->isUnique())
 -					{
 -						F32 t = 1.f;
 -
 -						if (!face.mOctree)
 -						{
 -							((LLVolumeFace*) &face)->createOctree(); 
 -						}
 -
 -						LLRenderOctreeRaycast render(starta, dir, &t);
 -					
 -						render.traverse(face.mOctree);
 -					}
 -
 -					gGL.popMatrix();		
 -					glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 -				}
 -			}
 -		}
 -		else if (drawablep->isAvatar())
 -		{
 -			if (drawablep->getVObj() == gDebugRaycastObject)
 -			{
 -				LLGLDepthTest depth(GL_FALSE);
 -				LLVOAvatar* av = (LLVOAvatar*) drawablep->getVObj().get();
 -				av->renderCollisionVolumes();
 -			}
 -		}
 -
 -		if (drawablep->getVObj() == gDebugRaycastObject)
 -		{
 -			// draw intersection point
 -			gGL.pushMatrix();
 -			gGL.loadMatrix(gGLModelView);
 -			LLVector3 translate = gDebugRaycastIntersection;
 -			gGL.translatef(translate.mV[0], translate.mV[1], translate.mV[2]);
 -			LLCoordFrame orient;
 -			orient.lookDir(gDebugRaycastNormal, gDebugRaycastBinormal);
 -			LLMatrix4 rotation;
 -			orient.getRotMatrixToParent(rotation);
 -			gGL.multMatrix((float*)rotation.mMatrix);
 -			
 -			gGL.diffuseColor4f(1,0,0,0.5f);
 -			drawBox(LLVector3(0, 0, 0), LLVector3(0.1f, 0.022f, 0.022f));
 -			gGL.diffuseColor4f(0,1,0,0.5f);
 -			drawBox(LLVector3(0, 0, 0), LLVector3(0.021f, 0.1f, 0.021f));
 -			gGL.diffuseColor4f(0,0,1,0.5f);
 -			drawBox(LLVector3(0, 0, 0), LLVector3(0.02f, 0.02f, 0.1f));
 -			gGL.popMatrix();
 -
 -			// draw bounding box of prim
 -			const LLVector4a* ext = drawablep->getSpatialExtents();
 -
 -			LLVector4a pos;
 -			pos.setAdd(ext[0], ext[1]);
 -			pos.mul(0.5f);
 -			LLVector4a size;
 -			size.setSub(ext[1], ext[0]);
 -			size.mul(0.5f);
 -
 -			LLGLDepthTest depth(GL_FALSE, GL_TRUE);
 -			gGL.diffuseColor4f(0,0.5f,0.5f,1);
 -			drawBoxOutline(pos, size);		
 -		}
 -	}
 -}
 -
 -
 -void renderAvatarCollisionVolumes(LLVOAvatar* avatar)
 -{
 -	avatar->renderCollisionVolumes();
 -}
 -
 -void renderAgentTarget(LLVOAvatar* avatar)
 -{
 -	// render these for self only (why, i don't know)
 -	if (avatar->isSelf())
 -	{
 -		renderCrossHairs(avatar->getPositionAgent(), 0.2f, LLColor4(1, 0, 0, 0.8f));
 -		renderCrossHairs(avatar->mDrawable->getPositionAgent(), 0.2f, LLColor4(1, 0, 0, 0.8f));
 -		renderCrossHairs(avatar->mRoot.getWorldPosition(), 0.2f, LLColor4(1, 1, 1, 0.8f));
 -		renderCrossHairs(avatar->mPelvisp->getWorldPosition(), 0.2f, LLColor4(0, 0, 1, 0.8f));
 -	}
 -}
 -
 -class LLOctreeRenderNonOccluded : public LLOctreeTraveler<LLDrawable>
 -{
 -public:
 -	LLCamera* mCamera;
 -	LLOctreeRenderNonOccluded(LLCamera* camera): mCamera(camera) {}
 -	
 -	virtual void traverse(const LLSpatialGroup::OctreeNode* node)
 -	{
 -		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
 -		
 -		if (!mCamera || mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]))
 -		{
 -			node->accept(this);
 -			stop_glerror();
 -
 -			for (U32 i = 0; i < node->getChildCount(); i++)
 -			{
 -				traverse(node->getChild(i));
 -				stop_glerror();
 -			}
 -			
 -			//draw tight fit bounding boxes for spatial group
 -			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCTREE))
 -			{	
 -				group->rebuildGeom();
 -				group->rebuildMesh();
 -
 -				renderOctree(group);
 -				stop_glerror();
 -			}
 -
 -			//render visibility wireframe
 -			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION))
 -			{
 -				group->rebuildGeom();
 -				group->rebuildMesh();
 -
 -				gGL.flush();
 -				gGL.pushMatrix();
 -				gGLLastMatrix = NULL;
 -				gGL.loadMatrix(gGLModelView);
 -				renderVisibility(group, mCamera);
 -				stop_glerror();
 -				gGLLastMatrix = NULL;
 -				gGL.popMatrix();
 -				gGL.diffuseColor4f(1,1,1,1);
 -			}
 -		}
 -	}
 -
 -	virtual void visit(const LLSpatialGroup::OctreeNode* branch)
 -	{
 -		LLSpatialGroup* group = (LLSpatialGroup*) branch->getListener(0);
 -
 -		if (group->isState(LLSpatialGroup::GEOM_DIRTY) || (mCamera && !mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1])))
 -		{
 -			return;
 -		}
 -
 -		LLVector4a nodeCenter = group->mBounds[0];
 -		LLVector4a octCenter = group->mOctreeNode->getCenter();
 -
 -		group->rebuildGeom();
 -		group->rebuildMesh();
 -
 -		if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BBOXES))
 -		{
 -			if (!group->getData().empty())
 -			{
 -				gGL.diffuseColor3f(0,0,1);
 -				drawBoxOutline(group->mObjectBounds[0],
 -								group->mObjectBounds[1]);
 -			}
 -		}
 -
 -		for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i)
 -		{
 -			LLDrawable* drawable = *i;
 -					
 -			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BBOXES))
 -			{
 -				renderBoundingBox(drawable);			
 -			}
 -
 -			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_NORMALS))
 -			{
 -				renderNormals(drawable);
 -			}
 -			
 -			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BUILD_QUEUE))
 -			{
 -				if (drawable->isState(LLDrawable::IN_REBUILD_Q2))
 -				{
 -					gGL.diffuseColor4f(0.6f, 0.6f, 0.1f, 1.f);
 -					const LLVector4a* ext = drawable->getSpatialExtents();
 -					LLVector4a center;
 -					center.setAdd(ext[0], ext[1]);
 -					center.mul(0.5f);
 -					LLVector4a size;
 -					size.setSub(ext[1], ext[0]);
 -					size.mul(0.5f);
 -					drawBoxOutline(center, size);
 -				}
 -			}	
 -
 -			if (drawable->getVOVolume() && gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY))
 -			{
 -				renderTexturePriority(drawable);
 -			}
 -
 -			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_POINTS))
 -			{
 -				renderPoints(drawable);
 -			}
 -
 -			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_LIGHTS))
 -			{
 -				renderLights(drawable);
 -			}
 -
 -			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST))
 -			{
 -				renderRaycast(drawable);
 -			}
 -			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_UPDATE_TYPE))
 -			{
 -				renderUpdateType(drawable);
 -			}
 -			if(gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RENDER_COMPLEXITY))
 -			{
 -				renderComplexityDisplay(drawable);
 -			}
 -
 -			LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(drawable->getVObj().get());
 -			
 -			if (avatar && gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_AVATAR_VOLUME))
 -			{
 -				renderAvatarCollisionVolumes(avatar);
 -			}
 -
 -			if (avatar && gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_AGENT_TARGET))
 -			{
 -				renderAgentTarget(avatar);
 -			}
 -			
 -					
 -			if (gDebugGL)
 -			{
 -				for (U32 i = 0; i < drawable->getNumFaces(); ++i)
 -				{
 -					LLFace* facep = drawable->getFace(i);
 -					U8 index = facep->getTextureIndex();
 -					if (facep->mDrawInfo)
 -					{
 -						if (index < 255)
 -						{
 -							if (facep->mDrawInfo->mTextureList.size() <= index)
 -							{
 -								llerrs << "Face texture index out of bounds." << llendl;
 -							}
 -							else if (facep->mDrawInfo->mTextureList[index] != facep->getTexture())
 -							{
 -								llerrs << "Face texture index incorrect." << llendl;
 -							}
 -						}
 -					}
 -				}
 -			}
 -		}
 -		
 -		for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i)
 -		{
 -			LLSpatialGroup::drawmap_elem_t& draw_vec = i->second;	
 -			for (LLSpatialGroup::drawmap_elem_t::iterator j = draw_vec.begin(); j != draw_vec.end(); ++j)	
 -			{
 -				LLDrawInfo* draw_info = *j;
 -				if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_ANIM))
 -				{
 -					renderTextureAnim(draw_info);
 -				}
 -				if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BATCH_SIZE))
 -				{
 -					renderBatchSize(draw_info);
 -				}
 -				if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
 -				{
 -					renderShadowFrusta(draw_info);
 -				}
 -			}
 -		}
 -	}
 -};
 -
 -
 -class LLOctreeRenderPhysicsShapes : public LLOctreeTraveler<LLDrawable>
 -{
 -public:
 -	LLCamera* mCamera;
 -	LLOctreeRenderPhysicsShapes(LLCamera* camera): mCamera(camera) {}
 -	
 -	virtual void traverse(const LLSpatialGroup::OctreeNode* node)
 -	{
 -		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
 -		
 -		if (!mCamera || mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]))
 -		{
 -			node->accept(this);
 -			stop_glerror();
 -
 -			for (U32 i = 0; i < node->getChildCount(); i++)
 -			{
 -				traverse(node->getChild(i));
 -				stop_glerror();
 -			}
 -			
 -			group->rebuildGeom();
 -			group->rebuildMesh();
 -
 -			renderPhysicsShapes(group);
 -		}
 -	}
 -
 -	virtual void visit(const LLSpatialGroup::OctreeNode* branch)
 -	{
 -		
 -	}
 -};
 -
 -class LLOctreePushBBoxVerts : public LLOctreeTraveler<LLDrawable>
 -{
 -public:
 -	LLCamera* mCamera;
 -	LLOctreePushBBoxVerts(LLCamera* camera): mCamera(camera) {}
 -	
 -	virtual void traverse(const LLSpatialGroup::OctreeNode* node)
 -	{
 -		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
 -		
 -		if (!mCamera || mCamera->AABBInFrustum(group->mBounds[0], group->mBounds[1]))
 -		{
 -			node->accept(this);
 -
 -			for (U32 i = 0; i < node->getChildCount(); i++)
 -			{
 -				traverse(node->getChild(i));
 -			}
 -		}
 -	}
 -
 -	virtual void visit(const LLSpatialGroup::OctreeNode* branch)
 -	{
 -		LLSpatialGroup* group = (LLSpatialGroup*) branch->getListener(0);
 -
 -		if (group->isState(LLSpatialGroup::GEOM_DIRTY) || (mCamera && !mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1])))
 -		{
 -			return;
 -		}
 -
 -		for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i)
 -		{
 -			LLDrawable* drawable = *i;
 -						
 -			renderBoundingBox(drawable, FALSE);			
 -		}
 -	}
 -};
 -
 -void LLSpatialPartition::renderIntersectingBBoxes(LLCamera* camera)
 -{
 -	LLOctreePushBBoxVerts pusher(camera);
 -	pusher.traverse(mOctree);
 -}
 -
 -class LLOctreeStateCheck : public LLOctreeTraveler<LLDrawable>
 -{
 -public:
 -	U32 mInheritedMask[LLViewerCamera::NUM_CAMERAS];
 -
 -	LLOctreeStateCheck()
 -	{ 
 -		for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
 -		{
 -			mInheritedMask[i] = 0;
 -		}
 -	}
 -
 -	virtual void traverse(const LLSpatialGroup::OctreeNode* node)
 -	{
 -		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
 -		
 -		node->accept(this);
 -
 -
 -		U32 temp[LLViewerCamera::NUM_CAMERAS];
 -
 -		for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
 -		{
 -			temp[i] = mInheritedMask[i];
 -			mInheritedMask[i] |= group->mOcclusionState[i] & LLSpatialGroup::OCCLUDED; 
 -		}
 -
 -		for (U32 i = 0; i < node->getChildCount(); i++)
 -		{
 -			traverse(node->getChild(i));
 -		}
 -
 -		for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
 -		{
 -			mInheritedMask[i] = temp[i];
 -		}
 -	}
 -	
 -
 -	virtual void visit(const LLOctreeNode<LLDrawable>* state)
 -	{
 -		LLSpatialGroup* group = (LLSpatialGroup*) state->getListener(0);
 -
 -		for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
 -		{
 -			if (mInheritedMask[i] && !(group->mOcclusionState[i] & mInheritedMask[i]))
 -			{
 -				llerrs << "Spatial group failed inherited mask test." << llendl;
 -			}
 -		}
 -
 -		if (group->isState(LLSpatialGroup::DIRTY))
 -		{
 -			assert_parent_state(group, LLSpatialGroup::DIRTY);
 -		}
 -	}
 -
 -	void assert_parent_state(LLSpatialGroup* group, U32 state)
 -	{
 -		LLSpatialGroup* parent = group->getParent();
 -		while (parent)
 -		{
 -			if (!parent->isState(state))
 -			{
 -				llerrs << "Spatial group failed parent state check." << llendl;
 -			}
 -			parent = parent->getParent();
 -		}
 -	}	
 -};
 -
 -
 -void LLSpatialPartition::renderPhysicsShapes()
 -{
 -	LLSpatialBridge* bridge = asBridge();
 -	LLCamera* camera = LLViewerCamera::getInstance();
 -	
 -	if (bridge)
 -	{
 -		camera = NULL;
 -	}
 -
 -	gGL.flush();
 -	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 -	glLineWidth(3.f);
 -	LLOctreeRenderPhysicsShapes render_physics(camera);
 -	render_physics.traverse(mOctree);
 -	gGL.flush();
 -	glLineWidth(1.f);
 -}
 -
 -void LLSpatialPartition::renderDebug()
 -{
 -	if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCTREE |
 -									  LLPipeline::RENDER_DEBUG_OCCLUSION |
 -									  LLPipeline::RENDER_DEBUG_LIGHTS |
 -									  LLPipeline::RENDER_DEBUG_BATCH_SIZE |
 -									  LLPipeline::RENDER_DEBUG_UPDATE_TYPE |
 -									  LLPipeline::RENDER_DEBUG_BBOXES |
 -									  LLPipeline::RENDER_DEBUG_NORMALS |
 -									  LLPipeline::RENDER_DEBUG_POINTS |
 -									  LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY |
 -									  LLPipeline::RENDER_DEBUG_TEXTURE_ANIM |
 -									  LLPipeline::RENDER_DEBUG_RAYCAST |
 -									  LLPipeline::RENDER_DEBUG_AVATAR_VOLUME |
 -									  LLPipeline::RENDER_DEBUG_AGENT_TARGET |
 -									  //LLPipeline::RENDER_DEBUG_BUILD_QUEUE |
 -									  LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA |
 -									  LLPipeline::RENDER_DEBUG_RENDER_COMPLEXITY)) 
 -	{
 -		return;
 -	}
 -	
 -	if (LLGLSLShader::sNoFixedFunction)
 -	{
 -		gDebugProgram.bind();
 -	}
 -
 -	if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY))
 -	{
 -		//sLastMaxTexPriority = lerp(sLastMaxTexPriority, sCurMaxTexPriority, gFrameIntervalSeconds);
 -		sLastMaxTexPriority = (F32) LLViewerCamera::getInstance()->getScreenPixelArea();
 -		sCurMaxTexPriority = 0.f;
 -	}
 -
 -	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 -	
 -	LLGLDisable cullface(GL_CULL_FACE);
 -	LLGLEnable blend(GL_BLEND);
 -	gGL.setSceneBlendType(LLRender::BT_ALPHA);
 -	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 -	gPipeline.disableLights();
 -
 -	LLSpatialBridge* bridge = asBridge();
 -	LLCamera* camera = LLViewerCamera::getInstance();
 -	
 -	if (bridge)
 -	{
 -		camera = NULL;
 -	}
 -
 -	LLOctreeStateCheck checker;
 -	checker.traverse(mOctree);
 -
 -	LLOctreeRenderNonOccluded render_debug(camera);
 -	render_debug.traverse(mOctree);
 -
 -	if (LLGLSLShader::sNoFixedFunction)
 -	{
 -		gDebugProgram.unbind();
 -	}
 -}
 -
 -void LLSpatialGroup::drawObjectBox(LLColor4 col)
 -{
 -	gGL.diffuseColor4fv(col.mV);
 -	LLVector4a size;
 -	size = mObjectBounds[1];
 -	size.mul(1.01f);
 -	size.add(LLVector4a(0.001f));
 -	drawBox(mObjectBounds[0], size);
 -}
 -
 -bool LLSpatialPartition::isHUDPartition() 
 -{ 
 -	return mPartitionType == LLViewerRegion::PARTITION_HUD ;
 -} 
 -
 -BOOL LLSpatialPartition::isVisible(const LLVector3& v)
 -{
 -	if (!LLViewerCamera::getInstance()->sphereInFrustum(v, 4.0f))
 -	{
 -		return FALSE;
 -	}
 -
 -	return TRUE;
 -}
 -
 -class LLOctreeIntersect : public LLSpatialGroup::OctreeTraveler
 -{
 -public:
 -	LLVector3 mStart;
 -	LLVector3 mEnd;
 -	S32       *mFaceHit;
 -	LLVector3 *mIntersection;
 -	LLVector2 *mTexCoord;
 -	LLVector3 *mNormal;
 -	LLVector3 *mBinormal;
 -	LLDrawable* mHit;
 -	BOOL mPickTransparent;
 -
 -	LLOctreeIntersect(LLVector3 start, LLVector3 end, BOOL pick_transparent,
 -					  S32* face_hit, LLVector3* intersection, LLVector2* tex_coord, LLVector3* normal, LLVector3* binormal)
 -		: mStart(start),
 -		  mEnd(end),
 -		  mFaceHit(face_hit),
 -		  mIntersection(intersection),
 -		  mTexCoord(tex_coord),
 -		  mNormal(normal),
 -		  mBinormal(binormal),
 -		  mHit(NULL),
 -		  mPickTransparent(pick_transparent)
 -	{
 -	}
 -	
 -	virtual void visit(const LLSpatialGroup::OctreeNode* branch) 
 -	{	
 -		for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i)
 -		{
 -			check(*i);
 -		}
 -	}
 -
 -	virtual LLDrawable* check(const LLSpatialGroup::OctreeNode* node)
 -	{
 -		node->accept(this);
 -	
 -		for (U32 i = 0; i < node->getChildCount(); i++)
 -		{
 -			const LLSpatialGroup::OctreeNode* child = node->getChild(i);
 -			LLVector3 res;
 -
 -			LLSpatialGroup* group = (LLSpatialGroup*) child->getListener(0);
 -			
 -			LLVector4a size;
 -			LLVector4a center;
 -			
 -			size = group->mBounds[1];
 -			center = group->mBounds[0];
 -			
 -			LLVector3 local_start = mStart;
 -			LLVector3 local_end   = mEnd;
 -
 -			if (group->mSpatialPartition->isBridge())
 -			{
 -				LLMatrix4 local_matrix = group->mSpatialPartition->asBridge()->mDrawable->getRenderMatrix();
 -				local_matrix.invert();
 -				
 -				local_start = mStart * local_matrix;
 -				local_end   = mEnd   * local_matrix;
 -			}
 -
 -			LLVector4a start, end;
 -			start.load3(local_start.mV);
 -			end.load3(local_end.mV);
 -
 -			if (LLLineSegmentBoxIntersect(start, end, center, size))
 -			{
 -				check(child);
 -			}
 -		}	
 -
 -		return mHit;
 -	}
 -
 -	virtual bool check(LLDrawable* drawable)
 -	{	
 -		LLVector3 local_start = mStart;
 -		LLVector3 local_end = mEnd;
 -
 -		if (!drawable || !gPipeline.hasRenderType(drawable->getRenderType()) || !drawable->isVisible())
 -		{
 -			return false;
 -		}
 -
 -		if (drawable->isSpatialBridge())
 -		{
 -			LLSpatialPartition *part = drawable->asPartition();
 -			LLSpatialBridge* bridge = part->asBridge();
 -			if (bridge && gPipeline.hasRenderType(bridge->mDrawableType))
 -			{
 -				check(part->mOctree);
 -			}
 -		}
 -		else
 -		{
 -			LLViewerObject* vobj = drawable->getVObj();
 -
 -			if (vobj)
 -			{
 -				LLVector3 intersection;
 -				bool skip_check = false;
 -				if (vobj->isAvatar())
 -				{
 -					LLVOAvatar* avatar = (LLVOAvatar*) vobj;
 -					if (avatar->isSelf() && LLFloater::isVisible(gFloaterTools))
 -					{
 -						LLViewerObject* hit = avatar->lineSegmentIntersectRiggedAttachments(mStart, mEnd, -1, mPickTransparent, mFaceHit, &intersection, mTexCoord, mNormal, mBinormal);
 -						if (hit)
 -						{
 -							mEnd = intersection;
 -							if (mIntersection)
 -							{
 -								*mIntersection = intersection;
 -							}
 -							
 -							mHit = hit->mDrawable;
 -							skip_check = true;
 -						}
 -
 -					}
 -				}
 -
 -				if (!skip_check && vobj->lineSegmentIntersect(mStart, mEnd, -1, mPickTransparent, mFaceHit, &intersection, mTexCoord, mNormal, mBinormal))
 -				{
 -					mEnd = intersection;  // shorten ray so we only find CLOSER hits
 -					if (mIntersection)
 -					{
 -						*mIntersection = intersection;
 -					}
 -					
 -					mHit = vobj->mDrawable;
 -				}
 -			}
 -		}
 -				
 -		return false;
 -	}
 -};
 -
 -LLDrawable* LLSpatialPartition::lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
 -													 BOOL pick_transparent,													
 -													 S32* face_hit,                   // return the face hit
 -													 LLVector3* intersection,         // return the intersection point
 -													 LLVector2* tex_coord,            // return the texture coordinates of the intersection point
 -													 LLVector3* normal,               // return the surface normal at the intersection point
 -													 LLVector3* bi_normal             // return the surface bi-normal at the intersection point
 -	)
 -
 -{
 -	LLOctreeIntersect intersect(start, end, pick_transparent, face_hit, intersection, tex_coord, normal, bi_normal);
 -	LLDrawable* drawable = intersect.check(mOctree);
 -
 -	return drawable;
 -}
 -
 -LLDrawInfo::LLDrawInfo(U16 start, U16 end, U32 count, U32 offset, 
 -					   LLViewerTexture* texture, LLVertexBuffer* buffer,
 -					   BOOL fullbright, U8 bump, BOOL particle, F32 part_size)
 -:
 -	mVertexBuffer(buffer),
 -	mTexture(texture),
 -	mTextureMatrix(NULL),
 -	mModelMatrix(NULL),
 -	mStart(start),
 -	mEnd(end),
 -	mCount(count),
 -	mOffset(offset), 
 -	mFullbright(fullbright),
 -	mBump(bump),
 -	mParticle(particle),
 -	mPartSize(part_size),
 -	mVSize(0.f),
 -	mGroup(NULL),
 -	mFace(NULL),
 -	mDistance(0.f),
 -	mDrawMode(LLRender::TRIANGLES)
 -{
 -	mVertexBuffer->validateRange(mStart, mEnd, mCount, mOffset);
 -	
 -	mDebugColor = (rand() << 16) + rand();
 -}
 -
 -LLDrawInfo::~LLDrawInfo()	
 -{
 -	/*if (LLSpatialGroup::sNoDelete)
 -	{
 -		llerrs << "LLDrawInfo deleted illegally!" << llendl;
 -	}*/
 -
 -	if (mFace)
 -	{
 -		mFace->setDrawInfo(NULL);
 -	}
 -
 -	if (gDebugGL)
 -	{
 -		gPipeline.checkReferences(this);
 -	}
 -}
 -
 -void LLDrawInfo::validate()
 -{
 -	mVertexBuffer->validateRange(mStart, mEnd, mCount, mOffset);
 -}
 -
 -LLVertexBuffer* LLGeometryManager::createVertexBuffer(U32 type_mask, U32 usage)
 -{
 -	return new LLVertexBuffer(type_mask, usage);
 -}
 -
 -LLCullResult::LLCullResult() 
 -{
 -	clear();
 -}
 -
 -void LLCullResult::clear()
 -{
 -	mVisibleGroupsSize = 0;
 -	mVisibleGroupsEnd = mVisibleGroups.begin();
 -
 -	mAlphaGroupsSize = 0;
 -	mAlphaGroupsEnd = mAlphaGroups.begin();
 -
 -	mOcclusionGroupsSize = 0;
 -	mOcclusionGroupsEnd = mOcclusionGroups.begin();
 -
 -	mDrawableGroupsSize = 0;
 -	mDrawableGroupsEnd = mDrawableGroups.begin();
 -
 -	mVisibleListSize = 0;
 -	mVisibleListEnd = mVisibleList.begin();
 -
 -	mVisibleBridgeSize = 0;
 -	mVisibleBridgeEnd = mVisibleBridge.begin();
 -
 -
 -	for (U32 i = 0; i < LLRenderPass::NUM_RENDER_TYPES; i++)
 -	{
 -		for (U32 j = 0; j < mRenderMapSize[i]; j++)
 -		{
 -			mRenderMap[i][j] = 0;
 -		}
 -		mRenderMapSize[i] = 0;
 -		mRenderMapEnd[i] = mRenderMap[i].begin();
 -	}
 -}
 -
 -LLCullResult::sg_list_t::iterator LLCullResult::beginVisibleGroups()
 -{
 -	return mVisibleGroups.begin();
 -}
 -
 -LLCullResult::sg_list_t::iterator LLCullResult::endVisibleGroups()
 -{
 -	return mVisibleGroupsEnd;
 -}
 -
 -LLCullResult::sg_list_t::iterator LLCullResult::beginAlphaGroups()
 -{
 -	return mAlphaGroups.begin();
 -}
 -
 -LLCullResult::sg_list_t::iterator LLCullResult::endAlphaGroups()
 -{
 -	return mAlphaGroupsEnd;
 -}
 -
 -LLCullResult::sg_list_t::iterator LLCullResult::beginOcclusionGroups()
 -{
 -	return mOcclusionGroups.begin();
 -}
 -
 -LLCullResult::sg_list_t::iterator LLCullResult::endOcclusionGroups()
 -{
 -	return mOcclusionGroupsEnd;
 -}
 -
 -LLCullResult::sg_list_t::iterator LLCullResult::beginDrawableGroups()
 -{
 -	return mDrawableGroups.begin();
 -}
 -
 -LLCullResult::sg_list_t::iterator LLCullResult::endDrawableGroups()
 -{
 -	return mDrawableGroupsEnd;
 -}
 -
 -LLCullResult::drawable_list_t::iterator LLCullResult::beginVisibleList()
 -{
 -	return mVisibleList.begin();
 -}
 -
 -LLCullResult::drawable_list_t::iterator LLCullResult::endVisibleList()
 -{
 -	return mVisibleListEnd;
 -}
 -
 -LLCullResult::bridge_list_t::iterator LLCullResult::beginVisibleBridge()
 -{
 -	return mVisibleBridge.begin();
 -}
 -
 -LLCullResult::bridge_list_t::iterator LLCullResult::endVisibleBridge()
 -{
 -	return mVisibleBridgeEnd;
 -}
 -
 -LLCullResult::drawinfo_list_t::iterator LLCullResult::beginRenderMap(U32 type)
 -{
 -	return mRenderMap[type].begin();
 -}
 -
 -LLCullResult::drawinfo_list_t::iterator LLCullResult::endRenderMap(U32 type)
 -{
 -	return mRenderMapEnd[type];
 -}
 -
 -void LLCullResult::pushVisibleGroup(LLSpatialGroup* group)
 -{
 -	if (mVisibleGroupsSize < mVisibleGroups.size())
 -	{
 -		mVisibleGroups[mVisibleGroupsSize] = group;
 -	}
 -	else
 -	{
 -		mVisibleGroups.push_back(group);
 -	}
 -	++mVisibleGroupsSize;
 -	mVisibleGroupsEnd = mVisibleGroups.begin()+mVisibleGroupsSize;
 -}
 -
 -void LLCullResult::pushAlphaGroup(LLSpatialGroup* group)
 -{
 -	if (mAlphaGroupsSize < mAlphaGroups.size())
 -	{
 -		mAlphaGroups[mAlphaGroupsSize] = group;
 -	}
 -	else
 -	{
 -		mAlphaGroups.push_back(group);
 -	}
 -	++mAlphaGroupsSize;
 -	mAlphaGroupsEnd = mAlphaGroups.begin()+mAlphaGroupsSize;
 -}
 -
 -void LLCullResult::pushOcclusionGroup(LLSpatialGroup* group)
 -{
 -	if (mOcclusionGroupsSize < mOcclusionGroups.size())
 -	{
 -		mOcclusionGroups[mOcclusionGroupsSize] = group;
 -	}
 -	else
 -	{
 -		mOcclusionGroups.push_back(group);
 -	}
 -	++mOcclusionGroupsSize;
 -	mOcclusionGroupsEnd = mOcclusionGroups.begin()+mOcclusionGroupsSize;
 -}
 -
 -void LLCullResult::pushDrawableGroup(LLSpatialGroup* group)
 -{
 -	if (mDrawableGroupsSize < mDrawableGroups.size())
 -	{
 -		mDrawableGroups[mDrawableGroupsSize] = group;
 -	}
 -	else
 -	{
 -		mDrawableGroups.push_back(group);
 -	}
 -	++mDrawableGroupsSize;
 -	mDrawableGroupsEnd = mDrawableGroups.begin()+mDrawableGroupsSize;
 -}
 -
 -void LLCullResult::pushDrawable(LLDrawable* drawable)
 -{
 -	if (mVisibleListSize < mVisibleList.size())
 -	{
 -		mVisibleList[mVisibleListSize] = drawable;
 -	}
 -	else
 -	{
 -		mVisibleList.push_back(drawable);
 -	}
 -	++mVisibleListSize;
 -	mVisibleListEnd = mVisibleList.begin()+mVisibleListSize;
 -}
 -
 -void LLCullResult::pushBridge(LLSpatialBridge* bridge)
 -{
 -	if (mVisibleBridgeSize < mVisibleBridge.size())
 -	{
 -		mVisibleBridge[mVisibleBridgeSize] = bridge;
 -	}
 -	else
 -	{
 -		mVisibleBridge.push_back(bridge);
 -	}
 -	++mVisibleBridgeSize;
 -	mVisibleBridgeEnd = mVisibleBridge.begin()+mVisibleBridgeSize;
 -}
 -
 -void LLCullResult::pushDrawInfo(U32 type, LLDrawInfo* draw_info)
 -{
 -	if (mRenderMapSize[type] < mRenderMap[type].size())
 -	{
 -		mRenderMap[type][mRenderMapSize[type]] = draw_info;
 -	}
 -	else
 -	{
 -		mRenderMap[type].push_back(draw_info);
 -	}
 -	++mRenderMapSize[type];
 -	mRenderMapEnd[type] = mRenderMap[type].begin() + mRenderMapSize[type];
 -}
 -
 -
 -void LLCullResult::assertDrawMapsEmpty()
 -{
 -	for (U32 i = 0; i < LLRenderPass::NUM_RENDER_TYPES; i++)
 -	{
 -		if (mRenderMapSize[i] != 0)
 -		{
 -			llerrs << "Stale LLDrawInfo's in LLCullResult!" << llendl;
 -		}
 -	}
 -}
 -
 -
 -
 +/**  + * @file llspatialpartition.cpp + * @brief LLSpatialGroup class implementation and supporting functions + * + * $LicenseInfo:firstyear=2003&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + *  + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llspatialpartition.h" + +#include "llappviewer.h" +#include "lltexturecache.h" +#include "lltexturefetch.h" +#include "llimageworker.h" +#include "llviewerwindow.h" +#include "llviewerobjectlist.h" +#include "llvovolume.h" +#include "llvolume.h" +#include "llvolumeoctree.h" +#include "llviewercamera.h" +#include "llface.h" +#include "llfloatertools.h" +#include "llviewercontrol.h" +#include "llviewerregion.h" +#include "llcamera.h" +#include "pipeline.h" +#include "llmeshrepository.h" +#include "llrender.h" +#include "lloctree.h" +#include "llphysicsshapebuilderutil.h" +#include "llvoavatar.h" +#include "llvolumemgr.h" +#include "lltextureatlas.h" +#include "llglslshader.h" +#include "llviewershadermgr.h" + +static LLFastTimer::DeclareTimer FTM_FRUSTUM_CULL("Frustum Culling"); +static LLFastTimer::DeclareTimer FTM_CULL_REBOUND("Cull Rebound"); + +const F32 SG_OCCLUSION_FUDGE = 0.25f; +#define SG_DISCARD_TOLERANCE 0.01f + +#if LL_OCTREE_PARANOIA_CHECK +#define assert_octree_valid(x) x->validate() +#define assert_states_valid(x) ((LLSpatialGroup*) x->mSpatialPartition->mOctree->getListener(0))->checkStates() +#else +#define assert_octree_valid(x) +#define assert_states_valid(x) +#endif + + +static U32 sZombieGroups = 0; +U32 LLSpatialGroup::sNodeCount = 0; + +#define LL_TRACK_PENDING_OCCLUSION_QUERIES 0 + +std::set<GLuint> LLSpatialGroup::sPendingQueries; + +U32 gOctreeMaxCapacity; + +BOOL LLSpatialGroup::sNoDelete = FALSE; + +static F32 sLastMaxTexPriority = 1.f; +static F32 sCurMaxTexPriority = 1.f; + +class LLOcclusionQueryPool : public LLGLNamePool +{ +protected: +	virtual GLuint allocateName() +	{ +		GLuint name; +		glGenQueriesARB(1, &name); +		return name; +	} + +	virtual void releaseName(GLuint name) +	{ +#if LL_TRACK_PENDING_OCCLUSION_QUERIES +		LLSpatialGroup::sPendingQueries.erase(name); +#endif +		glDeleteQueriesARB(1, &name); +	} +}; + +static LLOcclusionQueryPool sQueryPool; + +//static counter for frame to switch LOD on + +void sg_assert(BOOL expr) +{ +#if LL_OCTREE_PARANOIA_CHECK +	if (!expr) +	{ +		llerrs << "Octree invalid!" << llendl; +	} +#endif +} + +S32 AABBSphereIntersect(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &rad) +{ +	return AABBSphereIntersectR2(min, max, origin, rad*rad); +} + +S32 AABBSphereIntersectR2(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &r) +{ +	F32 d = 0.f; +	F32 t; +	 +	if ((min-origin).magVecSquared() < r && +		(max-origin).magVecSquared() < r) +	{ +		return 2; +	} + +	for (U32 i = 0; i < 3; i++) +	{ +		if (origin.mV[i] < min.mV[i]) +		{ +			t = min.mV[i] - origin.mV[i]; +			d += t*t; +		} +		else if (origin.mV[i] > max.mV[i]) +		{ +			t = origin.mV[i] - max.mV[i]; +			d += t*t; +		} + +		if (d > r) +		{ +			return 0; +		} +	} + +	return 1; +} + + +S32 AABBSphereIntersect(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &rad) +{ +	return AABBSphereIntersectR2(min, max, origin, rad*rad); +} + +S32 AABBSphereIntersectR2(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &r) +{ +	F32 d = 0.f; +	F32 t; +	 +	LLVector4a origina; +	origina.load3(origin.mV); + +	LLVector4a v; +	v.setSub(min, origina); +	 +	if (v.dot3(v) < r) +	{ +		v.setSub(max, origina); +		if (v.dot3(v) < r) +		{ +			return 2; +		} +	} + + +	for (U32 i = 0; i < 3; i++) +	{ +		if (origin.mV[i] < min[i]) +		{ +			t = min[i] - origin.mV[i]; +			d += t*t; +		} +		else if (origin.mV[i] > max[i]) +		{ +			t = origin.mV[i] - max[i]; +			d += t*t; +		} + +		if (d > r) +		{ +			return 0; +		} +	} + +	return 1; +} + + +typedef enum +{ +	b000 = 0x00, +	b001 = 0x01, +	b010 = 0x02, +	b011 = 0x03, +	b100 = 0x04, +	b101 = 0x05, +	b110 = 0x06, +	b111 = 0x07, +} eLoveTheBits; + +//contact Runitai Linden for a copy of the SL object used to write this table +//basically, you give the table a bitmask of the look-at vector to a node and it +//gives you a triangle fan index array +static U16 sOcclusionIndices[] = +{ +	 //000 +		b111, b110, b010, b011, b001, b101, b100, b110, +	 //001  +		b011, b010, b000, b001, b101, b111, b110, b010, +	 //010 +		b101, b100, b110, b111, b011, b001, b000, b100, +	 //011  +		b001, b000, b100, b101, b111, b011, b010, b000, +	 //100  +		b110, b000, b010, b011, b111, b101, b100, b000, +	 //101  +		b010, b100, b000, b001, b011, b111, b110, b100, +	 //110 +		b100, b010, b110, b111, b101, b001, b000, b010, +	 //111 +		b000, b110, b100, b101, b001, b011, b010, b110, +}; + +U32 get_box_fan_indices(LLCamera* camera, const LLVector4a& center) +{ +	LLVector4a origin; +	origin.load3(camera->getOrigin().mV); + +	S32 cypher = center.greaterThan(origin).getGatheredBits() & 0x7; +	 +	return cypher*8; +} + +U8* get_box_fan_indices_ptr(LLCamera* camera, const LLVector4a& center) +{ +	LLVector4a origin; +	origin.load3(camera->getOrigin().mV); + +	S32 cypher = center.greaterThan(origin).getGatheredBits() & 0x7; +	 +	return (U8*) (sOcclusionIndices+cypher*8); +} + + +static LLFastTimer::DeclareTimer FTM_BUILD_OCCLUSION("Build Occlusion"); + +void LLSpatialGroup::buildOcclusion() +{ +	//if (mOcclusionVerts.isNull()) +	{ +		mOcclusionVerts = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX,  +			LLVertexBuffer::sUseStreamDraw ? mBufferUsage : 0); //if GL has a hard time with VBOs, don't use them for occlusion culling. +		mOcclusionVerts->allocateBuffer(8, 64, true); +	 +		LLStrider<U16> idx; +		mOcclusionVerts->getIndexStrider(idx); +		for (U32 i = 0; i < 64; i++) +		{ +			*idx++ = sOcclusionIndices[i]; +		} +	} + +	LLVector4a fudge; +	fudge.splat(SG_OCCLUSION_FUDGE); + +	LLVector4a r; +	r.setAdd(mBounds[1], fudge); + +	LLStrider<LLVector3> pos; +	 +	{ +		LLFastTimer t(FTM_BUILD_OCCLUSION); +		mOcclusionVerts->getVertexStrider(pos); +	} + +	{ +		LLVector4a* v = (LLVector4a*) pos.get(); + +		const LLVector4a& c = mBounds[0]; +		const LLVector4a& s = r; +		 +		static const LLVector4a octant[] = +		{ +			LLVector4a(-1.f, -1.f, -1.f), +			LLVector4a(-1.f, -1.f, 1.f), +			LLVector4a(-1.f, 1.f, -1.f), +			LLVector4a(-1.f, 1.f, 1.f), + +			LLVector4a(1.f, -1.f, -1.f), +			LLVector4a(1.f, -1.f, 1.f), +			LLVector4a(1.f, 1.f, -1.f), +			LLVector4a(1.f, 1.f, 1.f), +		}; + +		//vertex positions are encoded so the 3 bits of their vertex index  +		//correspond to their axis facing, with bit position 3,2,1 matching +		//axis facing x,y,z, bit set meaning positive facing, bit clear  +		//meaning negative facing +		 +		for (S32 i = 0; i < 8; ++i) +		{ +			LLVector4a p; +			p.setMul(s, octant[i]); +			p.add(c); +			v[i] = p; +		} +	} +	 +	{ +		mOcclusionVerts->flush(); +		LLVertexBuffer::unbind(); +	} + +	clearState(LLSpatialGroup::OCCLUSION_DIRTY); +} + + +BOOL earlyFail(LLCamera* camera, LLSpatialGroup* group); + +//returns: +//	0 if sphere and AABB are not intersecting  +//	1 if they are +//	2 if AABB is entirely inside sphere + +S32 LLSphereAABB(const LLVector3& center, const LLVector3& size, const LLVector3& pos, const F32 &rad) +{ +	S32 ret = 2; + +	LLVector3 min = center - size; +	LLVector3 max = center + size; +	for (U32 i = 0; i < 3; i++) +	{ +		if (min.mV[i] > pos.mV[i] + rad || +			max.mV[i] < pos.mV[i] - rad) +		{	//totally outside +			return 0; +		} +		 +		if (min.mV[i] < pos.mV[i] - rad || +			max.mV[i] > pos.mV[i] + rad) +		{	//intersecting +			ret = 1; +		} +	} + +	return ret; +} + +LLSpatialGroup::~LLSpatialGroup() +{ +	/*if (sNoDelete) +	{ +		llerrs << "Illegal deletion of LLSpatialGroup!" << llendl; +	}*/ + +	if (gDebugGL) +	{ +		gPipeline.checkReferences(this); +	} + +	if (isState(DEAD)) +	{ +		sZombieGroups--; +	} +	 +	sNodeCount--; + +	if (gGLManager.mHasOcclusionQuery) +	{ +		for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; ++i) +		{ +			if (mOcclusionQuery[i]) +			{ +				sQueryPool.release(mOcclusionQuery[i]); +			} +		} +	} + +	mOcclusionVerts = NULL; + +	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); +	clearDrawMap(); +	clearAtlasList() ; +} + +BOOL LLSpatialGroup::hasAtlas(LLTextureAtlas* atlasp) +{ +	S8 type = atlasp->getComponents() - 1 ; +	for(std::list<LLTextureAtlas*>::iterator iter = mAtlasList[type].begin(); iter != mAtlasList[type].end() ; ++iter) +	{ +		if(atlasp == *iter) +		{ +			return TRUE ; +		} +	} +	return FALSE ; +} + +void LLSpatialGroup::addAtlas(LLTextureAtlas* atlasp, S8 recursive_level)  +{		 +	if(!hasAtlas(atlasp)) +	{ +		mAtlasList[atlasp->getComponents() - 1].push_back(atlasp) ; +		atlasp->addSpatialGroup(this) ; +	} +	 +	--recursive_level; +	if(recursive_level)//levels propagating up. +	{ +		LLSpatialGroup* parent = getParent() ; +		if(parent) +		{ +			parent->addAtlas(atlasp, recursive_level) ; +		} +	}	 +} + +void LLSpatialGroup::removeAtlas(LLTextureAtlas* atlasp, BOOL remove_group, S8 recursive_level)  +{ +	mAtlasList[atlasp->getComponents() - 1].remove(atlasp) ; +	if(remove_group) +	{ +		atlasp->removeSpatialGroup(this) ; +	} + +	--recursive_level; +	if(recursive_level)//levels propagating up. +	{ +		LLSpatialGroup* parent = getParent() ; +		if(parent) +		{ +			parent->removeAtlas(atlasp, recursive_level) ; +		} +	}	 +} + +void LLSpatialGroup::clearAtlasList()  +{ +	std::list<LLTextureAtlas*>::iterator iter ; +	for(S8 i = 0 ; i < 4 ; i++) +	{ +		if(mAtlasList[i].size() > 0) +		{ +			for(iter = mAtlasList[i].begin(); iter != mAtlasList[i].end() ; ++iter) +			{ +				((LLTextureAtlas*)*iter)->removeSpatialGroup(this) ;			 +			} +			mAtlasList[i].clear() ; +		} +	} +} + +LLTextureAtlas* LLSpatialGroup::getAtlas(S8 ncomponents, S8 to_be_reserved, S8 recursive_level) +{ +	S8 type = ncomponents - 1 ; +	if(mAtlasList[type].size() > 0) +	{ +		for(std::list<LLTextureAtlas*>::iterator iter = mAtlasList[type].begin(); iter != mAtlasList[type].end() ; ++iter) +		{ +			if(!((LLTextureAtlas*)*iter)->isFull(to_be_reserved)) +			{ +				return *iter ; +			} +		} +	} + +	--recursive_level; +	if(recursive_level) +	{ +		LLSpatialGroup* parent = getParent() ; +		if(parent) +		{ +			return parent->getAtlas(ncomponents, to_be_reserved, recursive_level) ; +		} +	} +	return NULL ; +} + +void LLSpatialGroup::setCurUpdatingSlot(LLTextureAtlasSlot* slotp)  +{  +	mCurUpdatingSlotp = slotp; + +	//if(!hasAtlas(mCurUpdatingSlotp->getAtlas())) +	//{ +	//	addAtlas(mCurUpdatingSlotp->getAtlas()) ; +	//} +} + +LLTextureAtlasSlot* LLSpatialGroup::getCurUpdatingSlot(LLViewerTexture* imagep, S8 recursive_level)  +{  +	if(gFrameCount && mCurUpdatingTime == gFrameCount && mCurUpdatingTexture == imagep) +	{ +		return mCurUpdatingSlotp ; +	} + +	//--recursive_level ; +	//if(recursive_level) +	//{ +	//	LLSpatialGroup* parent = getParent() ; +	//	if(parent) +	//	{ +	//		return parent->getCurUpdatingSlot(imagep, recursive_level) ; +	//	} +	//} +	return NULL ; +} + +void LLSpatialGroup::clearDrawMap() +{ +	mDrawMap.clear(); +} + +BOOL LLSpatialGroup::isHUDGroup()  +{ +	return mSpatialPartition && mSpatialPartition->isHUDPartition() ;  +} + +BOOL LLSpatialGroup::isRecentlyVisible() const +{ +	return (LLDrawable::getCurrentFrame() - mVisible[LLViewerCamera::sCurCameraID]) < LLDrawable::getMinVisFrameRange() ; +} + +BOOL LLSpatialGroup::isVisible() const +{ +	return mVisible[LLViewerCamera::sCurCameraID] >= LLDrawable::getCurrentFrame() ? TRUE : FALSE; +} + +void LLSpatialGroup::setVisible() +{ +	mVisible[LLViewerCamera::sCurCameraID] = LLDrawable::getCurrentFrame(); +} + +void LLSpatialGroup::validate() +{ +#if LL_OCTREE_PARANOIA_CHECK + +	sg_assert(!isState(DIRTY)); +	sg_assert(!isDead()); + +	LLVector4a myMin; +	myMin.setSub(mBounds[0], mBounds[1]); +	LLVector4a myMax; +	myMax.setAdd(mBounds[0], mBounds[1]); + +	validateDrawMap(); + +	for (element_iter i = getData().begin(); i != getData().end(); ++i) +	{ +		LLDrawable* drawable = *i; +		sg_assert(drawable->getSpatialGroup() == this); +		if (drawable->getSpatialBridge()) +		{ +			sg_assert(drawable->getSpatialBridge() == mSpatialPartition->asBridge()); +		} + +		/*if (drawable->isSpatialBridge()) +		{ +			LLSpatialPartition* part = drawable->asPartition(); +			if (!part) +			{ +				llerrs << "Drawable reports it is a spatial bridge but not a partition." << llendl; +			} +			LLSpatialGroup* group = (LLSpatialGroup*) part->mOctree->getListener(0); +			group->validate(); +		}*/ +	} + +	for (U32 i = 0; i < mOctreeNode->getChildCount(); ++i) +	{ +		LLSpatialGroup* group = (LLSpatialGroup*) mOctreeNode->getChild(i)->getListener(0); + +		group->validate(); +		 +		//ensure all children are enclosed in this node +		LLVector4a center = group->mBounds[0]; +		LLVector4a size = group->mBounds[1]; +		 +		LLVector4a min; +		min.setSub(center, size); +		LLVector4a max; +		max.setAdd(center, size); +		 +		for (U32 j = 0; j < 3; j++) +		{ +			sg_assert(min[j] >= myMin[j]-0.02f); +			sg_assert(max[j] <= myMax[j]+0.02f); +		} +	} + +#endif +} + +void LLSpatialGroup::checkStates() +{ +#if LL_OCTREE_PARANOIA_CHECK +	//LLOctreeStateCheck checker; +	//checker.traverse(mOctreeNode); +#endif +} + +void LLSpatialGroup::validateDrawMap() +{ +#if LL_OCTREE_PARANOIA_CHECK +	for (draw_map_t::iterator i = mDrawMap.begin(); i != mDrawMap.end(); ++i) +	{ +		LLSpatialGroup::drawmap_elem_t& draw_vec = i->second; +		for (drawmap_elem_t::iterator j = draw_vec.begin(); j != draw_vec.end(); ++j) +		{ +			LLDrawInfo& params = **j; +		 +			params.validate(); +		} +	} +#endif +} + +BOOL LLSpatialGroup::updateInGroup(LLDrawable *drawablep, BOOL immediate) +{ +	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); +		 +	drawablep->updateSpatialExtents(); + +	OctreeNode* parent = mOctreeNode->getOctParent(); +	 +	if (mOctreeNode->isInside(drawablep->getPositionGroup()) &&  +		(mOctreeNode->contains(drawablep) || +		 (drawablep->getBinRadius() > mOctreeNode->getSize()[0] && +				parent && parent->getElementCount() >= gOctreeMaxCapacity))) +	{ +		unbound(); +		setState(OBJECT_DIRTY); +		//setState(GEOM_DIRTY); +		return TRUE; +	} +		 +	return FALSE; +} + + +BOOL LLSpatialGroup::addObject(LLDrawable *drawablep, BOOL add_all, BOOL from_octree) +{ +	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); +	if (!from_octree) +	{ +		mOctreeNode->insert(drawablep); +	} +	else +	{ +		drawablep->setSpatialGroup(this); +		setState(OBJECT_DIRTY | GEOM_DIRTY); +		setOcclusionState(LLSpatialGroup::DISCARD_QUERY, LLSpatialGroup::STATE_MODE_ALL_CAMERAS); +		gPipeline.markRebuild(this, TRUE); +		if (drawablep->isSpatialBridge()) +		{ +			mBridgeList.push_back((LLSpatialBridge*) drawablep); +		} +		if (drawablep->getRadius() > 1.f) +		{ +			setState(IMAGE_DIRTY); +		} +	} + +	return TRUE; +} + +void LLSpatialGroup::rebuildGeom() +{ +	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); +	if (!isDead()) +	{ +		mSpatialPartition->rebuildGeom(this); +	} +} + +void LLSpatialGroup::rebuildMesh() +{ +	if (!isDead()) +	{ +		mSpatialPartition->rebuildMesh(this); +	} +} + +static LLFastTimer::DeclareTimer FTM_REBUILD_VBO("VBO Rebuilt"); + +void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group) +{ +	if (group->isDead() || !group->isState(LLSpatialGroup::GEOM_DIRTY)) +	{ +		return; +	} + +	if (group->changeLOD()) +	{ +		group->mLastUpdateDistance = group->mDistance; +		group->mLastUpdateViewAngle = group->mViewAngle; +	} +	 +	LLFastTimer ftm(FTM_REBUILD_VBO);	 + +	group->clearDrawMap(); +	 +	//get geometry count +	U32 index_count = 0; +	U32 vertex_count = 0; +	 +	addGeometryCount(group, vertex_count, index_count); + +	if (vertex_count > 0 && index_count > 0) +	{ //create vertex buffer containing volume geometry for this node +		group->mBuilt = 1.f; +		if (group->mVertexBuffer.isNull() || +			!group->mVertexBuffer->isWriteable() || +			(group->mBufferUsage != group->mVertexBuffer->getUsage() && LLVertexBuffer::sEnableVBOs)) +		{ +			group->mVertexBuffer = createVertexBuffer(mVertexDataMask, group->mBufferUsage); +			group->mVertexBuffer->allocateBuffer(vertex_count, index_count, true); +			stop_glerror(); +		} +		else +		{ +			group->mVertexBuffer->resizeBuffer(vertex_count, index_count); +			stop_glerror(); +		} +		 +		getGeometry(group); +	} +	else +	{ +		group->mVertexBuffer = NULL; +		group->mBufferMap.clear(); +	} + +	group->mLastUpdateTime = gFrameTimeSeconds; +	group->clearState(LLSpatialGroup::GEOM_DIRTY); +} + + +void LLSpatialPartition::rebuildMesh(LLSpatialGroup* group) +{ + +} + +BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector4a& minOut, LLVector4a& maxOut) +{	 +	const OctreeNode* node = mOctreeNode; + +	if (node->getData().empty()) +	{	//don't do anything if there are no objects +		if (empty && mOctreeNode->getParent()) +		{	//only root is allowed to be empty +			OCT_ERRS << "Empty leaf found in octree." << llendl; +		} +		return FALSE; +	} + +	LLVector4a& newMin = mObjectExtents[0]; +	LLVector4a& newMax = mObjectExtents[1]; +	 +	if (isState(OBJECT_DIRTY)) +	{ //calculate new bounding box +		clearState(OBJECT_DIRTY); + +		//initialize bounding box to first element +		OctreeNode::const_element_iter i = node->getData().begin(); +		LLDrawable* drawablep = *i; +		const LLVector4a* minMax = drawablep->getSpatialExtents(); + +		newMin = minMax[0]; +		newMax = minMax[1]; + +		for (++i; i != node->getData().end(); ++i) +		{ +			drawablep = *i; +			minMax = drawablep->getSpatialExtents(); +			 +			update_min_max(newMin, newMax, minMax[0]); +			update_min_max(newMin, newMax, minMax[1]); + +			//bin up the object +			/*for (U32 i = 0; i < 3; i++) +			{ +				if (minMax[0].mV[i] < newMin.mV[i]) +				{ +					newMin.mV[i] = minMax[0].mV[i]; +				} +				if (minMax[1].mV[i] > newMax.mV[i]) +				{ +					newMax.mV[i] = minMax[1].mV[i]; +				} +			}*/ +		} +		 +		mObjectBounds[0].setAdd(newMin, newMax); +		mObjectBounds[0].mul(0.5f); +		mObjectBounds[1].setSub(newMax, newMin); +		mObjectBounds[1].mul(0.5f); +	} +	 +	if (empty) +	{ +		minOut = newMin; +		maxOut = newMax; +	} +	else +	{ +		minOut.setMin(minOut, newMin); +		maxOut.setMax(maxOut, newMax); +	} +		 +	return TRUE; +} + +void LLSpatialGroup::unbound() +{ +	if (isState(DIRTY)) +	{ +		return; +	} + +	setState(DIRTY); +	 +	//all the parent nodes need to rebound this child +	if (mOctreeNode) +	{ +		OctreeNode* parent = (OctreeNode*) mOctreeNode->getParent(); +		while (parent != NULL) +		{ +			LLSpatialGroup* group = (LLSpatialGroup*) parent->getListener(0); +			if (group->isState(DIRTY)) +			{ +				return; +			} +			 +			group->setState(DIRTY); +			parent = (OctreeNode*) parent->getParent(); +		} +	} +} + +LLSpatialGroup* LLSpatialGroup::getParent() +{ +	if (isDead()) +	{ +		return NULL; +	} + +	if(!mOctreeNode) +	{ +		return NULL; +	} +	OctreeNode* parent = mOctreeNode->getOctParent(); + +	if (parent) +	{ +		return (LLSpatialGroup*) parent->getListener(0); +	} + +	return NULL; +} + +BOOL LLSpatialGroup::removeObject(LLDrawable *drawablep, BOOL from_octree) +{ +	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); +	unbound(); +	if (mOctreeNode && !from_octree) +	{ +		if (!mOctreeNode->remove(drawablep)) +		{ +			OCT_ERRS << "Could not remove drawable from spatial group" << llendl; +		} +	} +	else +	{ +		drawablep->setSpatialGroup(NULL); +		setState(GEOM_DIRTY); +		gPipeline.markRebuild(this, TRUE); + +		if (drawablep->isSpatialBridge()) +		{ +			for (bridge_list_t::iterator i = mBridgeList.begin(); i != mBridgeList.end(); ++i) +			{ +				if (*i == drawablep) +				{ +					mBridgeList.erase(i); +					break; +				} +			} +		} + +		if (getElementCount() == 0) +		{ //delete draw map on last element removal since a rebuild might never happen +			clearDrawMap(); +		} +	} +	return TRUE; +} + +void LLSpatialGroup::shift(const LLVector4a &offset) +{ +	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); +	LLVector4a t = mOctreeNode->getCenter(); +	t.add(offset);	 +	mOctreeNode->setCenter(t); +	mOctreeNode->updateMinMax(); +	mBounds[0].add(offset); +	mExtents[0].add(offset); +	mExtents[1].add(offset); +	mObjectBounds[0].add(offset); +	mObjectExtents[0].add(offset); +	mObjectExtents[1].add(offset); + +	//if (!mSpatialPartition->mRenderByGroup) +	{ +		setState(GEOM_DIRTY); +		gPipeline.markRebuild(this, TRUE); +	} + +	if (mOcclusionVerts.notNull()) +	{ +		setState(OCCLUSION_DIRTY); +	} +} + +class LLSpatialSetState : public LLSpatialGroup::OctreeTraveler +{ +public: +	U32 mState; +	LLSpatialSetState(U32 state) : mState(state) { } +	virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->setState(mState); }	 +}; + +class LLSpatialSetStateDiff : public LLSpatialSetState +{ +public: +	LLSpatialSetStateDiff(U32 state) : LLSpatialSetState(state) { } + +	virtual void traverse(const LLSpatialGroup::OctreeNode* n) +	{ +		LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0); +		 +		if (!group->isState(mState)) +		{ +			LLSpatialGroup::OctreeTraveler::traverse(n); +		} +	} +}; + +void LLSpatialGroup::setState(U32 state)  +{  +	mState |= state;  +	 +	llassert(state <= LLSpatialGroup::STATE_MASK); +}	 + +void LLSpatialGroup::setState(U32 state, S32 mode)  +{ +	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); + +	llassert(state <= LLSpatialGroup::STATE_MASK); +	 +	if (mode > STATE_MODE_SINGLE) +	{ +		if (mode == STATE_MODE_DIFF) +		{ +			LLSpatialSetStateDiff setter(state); +			setter.traverse(mOctreeNode); +		} +		else +		{ +			LLSpatialSetState setter(state); +			setter.traverse(mOctreeNode); +		} +	} +	else +	{ +		mState |= state; +	} +} + +class LLSpatialClearState : public LLSpatialGroup::OctreeTraveler +{ +public: +	U32 mState; +	LLSpatialClearState(U32 state) : mState(state) { } +	virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->clearState(mState); } +}; + +class LLSpatialClearStateDiff : public LLSpatialClearState +{ +public: +	LLSpatialClearStateDiff(U32 state) : LLSpatialClearState(state) { } + +	virtual void traverse(const LLSpatialGroup::OctreeNode* n) +	{ +		LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0); +		 +		if (group->isState(mState)) +		{ +			LLSpatialGroup::OctreeTraveler::traverse(n); +		} +	} +}; + +void LLSpatialGroup::clearState(U32 state) +{ +	llassert(state <= LLSpatialGroup::STATE_MASK); + +	mState &= ~state;  +} + +void LLSpatialGroup::clearState(U32 state, S32 mode) +{ +	llassert(state <= LLSpatialGroup::STATE_MASK); + +	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); +	 +	if (mode > STATE_MODE_SINGLE) +	{ +		if (mode == STATE_MODE_DIFF) +		{ +			LLSpatialClearStateDiff clearer(state); +			clearer.traverse(mOctreeNode); +		} +		else +		{ +			LLSpatialClearState clearer(state); +			clearer.traverse(mOctreeNode); +		} +	} +	else +	{ +		mState &= ~state; +	} +} + +BOOL LLSpatialGroup::isState(U32 state) const +{  +	llassert(state <= LLSpatialGroup::STATE_MASK); + +	return mState & state ? TRUE : FALSE;  +} + +//===================================== +//		Occlusion State Set/Clear +//===================================== +class LLSpatialSetOcclusionState : public LLSpatialGroup::OctreeTraveler +{ +public: +	U32 mState; +	LLSpatialSetOcclusionState(U32 state) : mState(state) { } +	virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->setOcclusionState(mState); }	 +}; + +class LLSpatialSetOcclusionStateDiff : public LLSpatialSetOcclusionState +{ +public: +	LLSpatialSetOcclusionStateDiff(U32 state) : LLSpatialSetOcclusionState(state) { } + +	virtual void traverse(const LLSpatialGroup::OctreeNode* n) +	{ +		LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0); +		 +		if (!group->isOcclusionState(mState)) +		{ +			LLSpatialGroup::OctreeTraveler::traverse(n); +		} +	} +}; + + +void LLSpatialGroup::setOcclusionState(U32 state, S32 mode)  +{ +	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); +	 +	if (mode > STATE_MODE_SINGLE) +	{ +		if (mode == STATE_MODE_DIFF) +		{ +			LLSpatialSetOcclusionStateDiff setter(state); +			setter.traverse(mOctreeNode); +		} +		else if (mode == STATE_MODE_BRANCH) +		{ +			LLSpatialSetOcclusionState setter(state); +			setter.traverse(mOctreeNode); +		} +		else +		{ +			for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) +			{ +				mOcclusionState[i] |= state; + +				if ((state & DISCARD_QUERY) && mOcclusionQuery[i]) +				{ +					sQueryPool.release(mOcclusionQuery[i]); +					mOcclusionQuery[i] = 0; +				} +			} +		} +	} +	else +	{ +		mOcclusionState[LLViewerCamera::sCurCameraID] |= state; +		if ((state & DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID]) +		{ +			sQueryPool.release(mOcclusionQuery[LLViewerCamera::sCurCameraID]); +			mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0; +		} +	} +} + +class LLSpatialClearOcclusionState : public LLSpatialGroup::OctreeTraveler +{ +public: +	U32 mState; +	 +	LLSpatialClearOcclusionState(U32 state) : mState(state) { } +	virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->clearOcclusionState(mState); } +}; + +class LLSpatialClearOcclusionStateDiff : public LLSpatialClearOcclusionState +{ +public: +	LLSpatialClearOcclusionStateDiff(U32 state) : LLSpatialClearOcclusionState(state) { } + +	virtual void traverse(const LLSpatialGroup::OctreeNode* n) +	{ +		LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0); +		 +		if (group->isOcclusionState(mState)) +		{ +			LLSpatialGroup::OctreeTraveler::traverse(n); +		} +	} +}; + +void LLSpatialGroup::clearOcclusionState(U32 state, S32 mode) +{ +	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); +	 +	if (mode > STATE_MODE_SINGLE) +	{ +		if (mode == STATE_MODE_DIFF) +		{ +			LLSpatialClearOcclusionStateDiff clearer(state); +			clearer.traverse(mOctreeNode); +		} +		else if (mode == STATE_MODE_BRANCH) +		{ +			LLSpatialClearOcclusionState clearer(state); +			clearer.traverse(mOctreeNode); +		} +		else +		{ +			for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) +			{ +				mOcclusionState[i] &= ~state; +			} +		} +	} +	else +	{ +		mOcclusionState[LLViewerCamera::sCurCameraID] &= ~state; +	} +} +//====================================== +//		Octree Listener Implementation +//====================================== + +LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) : +	mState(0), +	mGeometryBytes(0), +	mSurfaceArea(0.f), +	mBuilt(0.f), +	mOctreeNode(node), +	mSpatialPartition(part), +	mVertexBuffer(NULL),  +	mBufferUsage(part->mBufferUsage), +	mDistance(0.f), +	mDepth(0.f), +	mLastUpdateDistance(-1.f),  +	mLastUpdateTime(gFrameTimeSeconds), +	mAtlasList(4), +	mCurUpdatingTime(0), +	mCurUpdatingSlotp(NULL), +	mCurUpdatingTexture (NULL) +{ +	sNodeCount++; +	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); + +	mViewAngle.splat(0.f); +	mLastUpdateViewAngle.splat(-1.f); +	mExtents[0] = mExtents[1] = mObjectBounds[0] = mObjectBounds[0] = mObjectBounds[1] =  +		mObjectExtents[0] = mObjectExtents[1] = mViewAngle; + +	sg_assert(mOctreeNode->getListenerCount() == 0); +	mOctreeNode->addListener(this); +	setState(SG_INITIAL_STATE_MASK); +	gPipeline.markRebuild(this, TRUE); + +	mBounds[0] = node->getCenter(); +	mBounds[1] = node->getSize(); + +	part->mLODSeed = (part->mLODSeed+1)%part->mLODPeriod; +	mLODHash = part->mLODSeed; + +	OctreeNode* oct_parent = node->getOctParent(); + +	LLSpatialGroup* parent = oct_parent ? (LLSpatialGroup*) oct_parent->getListener(0) : NULL; + +	for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) +	{ +		mOcclusionQuery[i] = 0; +		mOcclusionIssued[i] = 0; +		mOcclusionState[i] = parent ? SG_STATE_INHERIT_MASK & parent->mOcclusionState[i] : 0; +		mVisible[i] = 0; +	} + +	mOcclusionVerts = NULL; + +	mRadius = 1; +	mPixelArea = 1024.f; +} + +void LLSpatialGroup::updateDistance(LLCamera &camera) +{ +	if (LLViewerCamera::sCurCameraID != LLViewerCamera::CAMERA_WORLD) +	{ +		llwarns << "Attempted to update distance for camera other than world camera!" << llendl; +		return; +	} + +#if !LL_RELEASE_FOR_DOWNLOAD +	if (isState(LLSpatialGroup::OBJECT_DIRTY)) +	{ +		llerrs << "Spatial group dirty on distance update." << llendl; +	} +#endif +	if (!getData().empty()) +	{ +		mRadius = mSpatialPartition->mRenderByGroup ? mObjectBounds[1].getLength3().getF32() : +						(F32) mOctreeNode->getSize().getLength3().getF32(); +		mDistance = mSpatialPartition->calcDistance(this, camera); +		mPixelArea = mSpatialPartition->calcPixelArea(this, camera); +	} +} + +F32 LLSpatialPartition::calcDistance(LLSpatialGroup* group, LLCamera& camera) +{ +	LLVector4a eye; +	LLVector4a origin; +	origin.load3(camera.getOrigin().mV); + +	eye.setSub(group->mObjectBounds[0], origin); + +	F32 dist = 0.f; + +	if (group->mDrawMap.find(LLRenderPass::PASS_ALPHA) != group->mDrawMap.end()) +	{ +		LLVector4a v = eye; + +		dist = eye.getLength3().getF32(); +		eye.normalize3fast(); + +		if (!group->isState(LLSpatialGroup::ALPHA_DIRTY)) +		{ +			if (!group->mSpatialPartition->isBridge()) +			{ +				LLVector4a view_angle = eye; + +				LLVector4a diff; +				diff.setSub(view_angle, group->mLastUpdateViewAngle); + +				if (diff.getLength3().getF32() > 0.64f) +				{ +					group->mViewAngle = view_angle; +					group->mLastUpdateViewAngle = view_angle; +					//for occasional alpha sorting within the group +					//NOTE: If there is a trivial way to detect that alpha sorting here would not change the render order, +					//not setting this node to dirty would be a very good thing +					group->setState(LLSpatialGroup::ALPHA_DIRTY); +					gPipeline.markRebuild(group, FALSE); +				} +			} +		} + +		//calculate depth of node for alpha sorting + +		LLVector3 at = camera.getAtAxis(); + +		LLVector4a ata; +		ata.load3(at.mV); + +		LLVector4a t = ata; +		//front of bounding box +		t.mul(0.25f); +		t.mul(group->mObjectBounds[1]); +		v.sub(t); +		 +		group->mDepth = v.dot3(ata).getF32(); +	} +	else +	{ +		dist = eye.getLength3().getF32(); +	} + +	if (dist < 16.f) +	{ +		dist /= 16.f; +		dist *= dist; +		dist *= 16.f; +	} + +	return dist; +} + +F32 LLSpatialPartition::calcPixelArea(LLSpatialGroup* group, LLCamera& camera) +{ +	return LLPipeline::calcPixelArea(group->mObjectBounds[0], group->mObjectBounds[1], camera); +} + +F32 LLSpatialGroup::getUpdateUrgency() const +{ +	if (!isVisible()) +	{ +		return 0.f; +	} +	else +	{ +		F32 time = gFrameTimeSeconds-mLastUpdateTime+4.f; +		return time + (mObjectBounds[1].dot3(mObjectBounds[1]).getF32()+1.f)/mDistance; +	} +} + +BOOL LLSpatialGroup::needsUpdate() +{ +	return (LLDrawable::getCurrentFrame()%mSpatialPartition->mLODPeriod == mLODHash) ? TRUE : FALSE; +} + +BOOL LLSpatialGroup::changeLOD() +{ +	if (isState(ALPHA_DIRTY | OBJECT_DIRTY)) +	{ ///a rebuild is going to happen, update distance and LoD +		return TRUE; +	} + +	if (mSpatialPartition->mSlopRatio > 0.f) +	{ +		F32 ratio = (mDistance - mLastUpdateDistance)/(llmax(mLastUpdateDistance, mRadius)); + +		if (fabsf(ratio) >= mSpatialPartition->mSlopRatio) +		{ +			return TRUE; +		} + +		if (mDistance > mRadius*2.f) +		{ +			return FALSE; +		} +	} +	 +	if (needsUpdate()) +	{ +		return TRUE; +	} +	 +	return FALSE; +} + +void LLSpatialGroup::handleInsertion(const TreeNode* node, LLDrawable* drawablep) +{ +	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); +	addObject(drawablep, FALSE, TRUE); +	unbound(); +	setState(OBJECT_DIRTY); +} + +void LLSpatialGroup::handleRemoval(const TreeNode* node, LLDrawable* drawable) +{ +	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); +	removeObject(drawable, TRUE); +	setState(OBJECT_DIRTY); +} + +void LLSpatialGroup::handleDestruction(const TreeNode* node) +{ +	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); +	setState(DEAD); +	 +	for (element_iter i = getData().begin(); i != getData().end(); ++i) +	{ +		LLDrawable* drawable = *i; +		if (drawable->getSpatialGroup() == this) +		{ +			drawable->setSpatialGroup(NULL); +		} +	} +	 +	//clean up avatar attachment stats +	LLSpatialBridge* bridge = mSpatialPartition->asBridge(); +	if (bridge) +	{ +		if (bridge->mAvatar.notNull()) +		{ +			bridge->mAvatar->mAttachmentGeometryBytes -= mGeometryBytes; +			bridge->mAvatar->mAttachmentSurfaceArea -= mSurfaceArea; +		} +	} + +	clearDrawMap(); +	mVertexBuffer = NULL; +	mBufferMap.clear(); +	sZombieGroups++; +	mOctreeNode = NULL; +} + +void LLSpatialGroup::handleStateChange(const TreeNode* node) +{ +	//drop bounding box upon state change +	if (mOctreeNode != node) +	{ +		mOctreeNode = (OctreeNode*) node; +	} +	unbound(); +} + +void LLSpatialGroup::handleChildAddition(const OctreeNode* parent, OctreeNode* child)  +{ +	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); +	if (child->getListenerCount() == 0) +	{ +		new LLSpatialGroup(child, mSpatialPartition); +	} +	else +	{ +		OCT_ERRS << "LLSpatialGroup redundancy detected." << llendl; +	} + +	unbound(); + +	assert_states_valid(this); +} + +void LLSpatialGroup::handleChildRemoval(const OctreeNode* parent, const OctreeNode* child) +{ +	unbound(); +} + +void LLSpatialGroup::destroyGL()  +{ +	setState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::IMAGE_DIRTY); +	gPipeline.markRebuild(this, TRUE); + +	mLastUpdateTime = gFrameTimeSeconds; +	mVertexBuffer = NULL; +	mBufferMap.clear(); + +	clearDrawMap(); + +	for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) +	{ +		if (mOcclusionQuery[i]) +		{ +			sQueryPool.release(mOcclusionQuery[i]); +			mOcclusionQuery[i] = 0; +		} +	} + +	mOcclusionVerts = NULL; + +	for (LLSpatialGroup::element_iter i = getData().begin(); i != getData().end(); ++i) +	{ +		LLDrawable* drawable = *i; +		for (S32 j = 0; j < drawable->getNumFaces(); j++) +		{ +			LLFace* facep = drawable->getFace(j); +			facep->clearVertexBuffer(); +		} +	} +} + +BOOL LLSpatialGroup::rebound() +{ +	if (!isState(DIRTY)) +	{	//return TRUE if we're not empty +		return TRUE; +	} +	 +	if (mOctreeNode->getChildCount() == 1 && mOctreeNode->getElementCount() == 0) +	{ +		LLSpatialGroup* group = (LLSpatialGroup*) mOctreeNode->getChild(0)->getListener(0); +		group->rebound(); +		 +		//copy single child's bounding box +		mBounds[0] = group->mBounds[0]; +		mBounds[1] = group->mBounds[1]; +		mExtents[0] = group->mExtents[0]; +		mExtents[1] = group->mExtents[1]; +		 +		group->setState(SKIP_FRUSTUM_CHECK); +	} +	else if (mOctreeNode->isLeaf()) +	{ //copy object bounding box if this is a leaf +		boundObjects(TRUE, mExtents[0], mExtents[1]); +		mBounds[0] = mObjectBounds[0]; +		mBounds[1] = mObjectBounds[1]; +	} +	else +	{ +		LLVector4a& newMin = mExtents[0]; +		LLVector4a& newMax = mExtents[1]; +		LLSpatialGroup* group = (LLSpatialGroup*) mOctreeNode->getChild(0)->getListener(0); +		group->clearState(SKIP_FRUSTUM_CHECK); +		group->rebound(); +		//initialize to first child +		newMin = group->mExtents[0]; +		newMax = group->mExtents[1]; + +		//first, rebound children +		for (U32 i = 1; i < mOctreeNode->getChildCount(); i++) +		{ +			group = (LLSpatialGroup*) mOctreeNode->getChild(i)->getListener(0); +			group->clearState(SKIP_FRUSTUM_CHECK); +			group->rebound(); +			const LLVector4a& max = group->mExtents[1]; +			const LLVector4a& min = group->mExtents[0]; + +			newMax.setMax(newMax, max); +			newMin.setMin(newMin, min); +		} + +		boundObjects(FALSE, newMin, newMax); +		 +		mBounds[0].setAdd(newMin, newMax); +		mBounds[0].mul(0.5f); +		mBounds[1].setSub(newMax, newMin); +		mBounds[1].mul(0.5f); +	} +	 +	setState(OCCLUSION_DIRTY); +	 +	clearState(DIRTY); + +	return TRUE; +} + +static LLFastTimer::DeclareTimer FTM_OCCLUSION_READBACK("Readback Occlusion"); +static LLFastTimer::DeclareTimer FTM_OCCLUSION_WAIT("Wait"); + +void LLSpatialGroup::checkOcclusion() +{ +	if (LLPipeline::sUseOcclusion > 1) +	{ +		LLFastTimer t(FTM_OCCLUSION_READBACK); +		LLSpatialGroup* parent = getParent(); +		if (parent && parent->isOcclusionState(LLSpatialGroup::OCCLUDED)) +		{	//if the parent has been marked as occluded, the child is implicitly occluded +			clearOcclusionState(QUERY_PENDING | DISCARD_QUERY); +		} +		else if (isOcclusionState(QUERY_PENDING)) +		{	//otherwise, if a query is pending, read it back + +			GLuint available = 0; +			if (mOcclusionQuery[LLViewerCamera::sCurCameraID]) +			{ +				glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available); + +				if (mOcclusionIssued[LLViewerCamera::sCurCameraID] < gFrameCount) +				{ //query was issued last frame, wait until it's available +					S32 max_loop = 1024; +					LLFastTimer t(FTM_OCCLUSION_WAIT); +					while (!available && max_loop-- > 0) +					{ +						F32 max_time = llmin(gFrameIntervalSeconds*10.f, 1.f); +						//do some usefu work while we wait +						LLAppViewer::getTextureCache()->update(max_time); // unpauses the texture cache thread +						LLAppViewer::getImageDecodeThread()->update(max_time); // unpauses the image thread +						LLAppViewer::getTextureFetch()->update(max_time); // unpauses the texture fetch thread +						 +						glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available); +					} +				} +			} +			else +			{ +				available = 1; +			} + +			if (available) +			{ //result is available, read it back, otherwise wait until next frame +				GLuint res = 1; +				if (!isOcclusionState(DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID]) +				{ +					glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_ARB, &res);	 +#if LL_TRACK_PENDING_OCCLUSION_QUERIES +					sPendingQueries.erase(mOcclusionQuery[LLViewerCamera::sCurCameraID]); +#endif +				} +				else if (mOcclusionQuery[LLViewerCamera::sCurCameraID]) +				{ //delete the query to avoid holding onto hundreds of pending queries +					sQueryPool.release(mOcclusionQuery[LLViewerCamera::sCurCameraID]); +					mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0; +				} +				 +				if (isOcclusionState(DISCARD_QUERY)) +				{ +					res = 2; +				} + +				if (res > 0) +				{ +					assert_states_valid(this); +					clearOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF); +					assert_states_valid(this); +				} +				else +				{ +					assert_states_valid(this); +					setOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF); +					assert_states_valid(this); +				} + +				clearOcclusionState(QUERY_PENDING | DISCARD_QUERY); +			} +		} +		else if (mSpatialPartition->isOcclusionEnabled() && isOcclusionState(LLSpatialGroup::OCCLUDED)) +		{	//check occlusion has been issued for occluded node that has not had a query issued +			assert_states_valid(this); +			clearOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF); +			assert_states_valid(this); +		} +	} +} + +static LLFastTimer::DeclareTimer FTM_PUSH_OCCLUSION_VERTS("Push Occlusion"); +static LLFastTimer::DeclareTimer FTM_SET_OCCLUSION_STATE("Occlusion State"); +static LLFastTimer::DeclareTimer FTM_OCCLUSION_EARLY_FAIL("Occlusion Early Fail"); +static LLFastTimer::DeclareTimer FTM_OCCLUSION_ALLOCATE("Allocate"); +static LLFastTimer::DeclareTimer FTM_OCCLUSION_BUILD("Build"); +static LLFastTimer::DeclareTimer FTM_OCCLUSION_BEGIN_QUERY("Begin Query"); +static LLFastTimer::DeclareTimer FTM_OCCLUSION_END_QUERY("End Query"); +static LLFastTimer::DeclareTimer FTM_OCCLUSION_SET_BUFFER("Set Buffer"); +static LLFastTimer::DeclareTimer FTM_OCCLUSION_DRAW_WATER("Draw Water"); +static LLFastTimer::DeclareTimer FTM_OCCLUSION_DRAW("Draw"); + + + +void LLSpatialGroup::doOcclusion(LLCamera* camera) +{ +	if (mSpatialPartition->isOcclusionEnabled() && LLPipeline::sUseOcclusion > 1) +	{ +		// Don't cull hole/edge water, unless we have the GL_ARB_depth_clamp extension +		if (earlyFail(camera, this)) +		{ +			LLFastTimer t(FTM_OCCLUSION_EARLY_FAIL); +			setOcclusionState(LLSpatialGroup::DISCARD_QUERY); +			assert_states_valid(this); +			clearOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF); +			assert_states_valid(this); +		} +		else +		{ +			if (!isOcclusionState(QUERY_PENDING) || isOcclusionState(DISCARD_QUERY)) +			{ +				{ //no query pending, or previous query to be discarded +					LLFastTimer t(FTM_RENDER_OCCLUSION); + +					if (!mOcclusionQuery[LLViewerCamera::sCurCameraID]) +					{ +						LLFastTimer t(FTM_OCCLUSION_ALLOCATE); +						mOcclusionQuery[LLViewerCamera::sCurCameraID] = sQueryPool.allocate(); +					} + +					if (mOcclusionVerts.isNull() || isState(LLSpatialGroup::OCCLUSION_DIRTY)) +					{ +						LLFastTimer t(FTM_OCCLUSION_BUILD); +						buildOcclusion(); +					} +					 +					// Depth clamp all water to avoid it being culled as a result of being +					// behind the far clip plane, and in the case of edge water to avoid +					// it being culled while still visible. +					bool const use_depth_clamp = gGLManager.mHasDepthClamp && +												(mSpatialPartition->mDrawableType == LLDrawPool::POOL_WATER ||						 +												mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER); + +					LLGLEnable clamp(use_depth_clamp ? GL_DEPTH_CLAMP : 0);				 +						 +#if !LL_DARWIN					 +					U32 mode = gGLManager.mHasOcclusionQuery2 ? GL_ANY_SAMPLES_PASSED : GL_SAMPLES_PASSED_ARB; +#else +					U32 mode = GL_SAMPLES_PASSED_ARB; +#endif +					 +#if LL_TRACK_PENDING_OCCLUSION_QUERIES +					sPendingQueries.insert(mOcclusionQuery[LLViewerCamera::sCurCameraID]); +#endif + +					{ +						LLFastTimer t(FTM_PUSH_OCCLUSION_VERTS); +						 +						//store which frame this query was issued on +						mOcclusionIssued[LLViewerCamera::sCurCameraID] = gFrameCount; + +						{ +							LLFastTimer t(FTM_OCCLUSION_BEGIN_QUERY); +							glBeginQueryARB(mode, mOcclusionQuery[LLViewerCamera::sCurCameraID]);					 +						} +					 +						{ +							LLFastTimer t(FTM_OCCLUSION_SET_BUFFER); +							mOcclusionVerts->setBuffer(LLVertexBuffer::MAP_VERTEX); +						} + +						if (!use_depth_clamp && mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER) +						{ +							LLFastTimer t(FTM_OCCLUSION_DRAW_WATER); + +							LLGLSquashToFarClip squash(glh_get_current_projection(), 1); +							if (camera->getOrigin().isExactlyZero()) +							{ //origin is invalid, draw entire box +								mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0); +								mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8);				 +							} +							else +							{ +								mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0])); +							} +						} +						else +						{ +							LLFastTimer t(FTM_OCCLUSION_DRAW); +							if (camera->getOrigin().isExactlyZero()) +							{ //origin is invalid, draw entire box +								mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0); +								mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8);				 +							} +							else +							{ +								mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0])); +							} +						} + + +						{ +							LLFastTimer t(FTM_OCCLUSION_END_QUERY); +							glEndQueryARB(mode); +						} +					} +				} + +				{ +					LLFastTimer t(FTM_SET_OCCLUSION_STATE); +					setOcclusionState(LLSpatialGroup::QUERY_PENDING); +					clearOcclusionState(LLSpatialGroup::DISCARD_QUERY); +				} +			} +		} +	} +} + +//============================================== + +LLSpatialPartition::LLSpatialPartition(U32 data_mask, BOOL render_by_group, U32 buffer_usage) +: mRenderByGroup(render_by_group), mBridge(NULL) +{ +	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); +	mOcclusionEnabled = TRUE; +	mDrawableType = 0; +	mPartitionType = LLViewerRegion::PARTITION_NONE; +	mLODSeed = 0; +	mLODPeriod = 1; +	mVertexDataMask = data_mask; +	mBufferUsage = buffer_usage; +	mDepthMask = FALSE; +	mSlopRatio = 0.25f; +	mInfiniteFarClip = FALSE; + +	LLVector4a center, size; +	center.splat(0.f); +	size.splat(1.f); + +	mOctree = new LLSpatialGroup::OctreeRoot(center,size, +											NULL); +	new LLSpatialGroup(mOctree, this); +} + + +LLSpatialPartition::~LLSpatialPartition() +{ +	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); +	 +	delete mOctree; +	mOctree = NULL; +} + + +LLSpatialGroup *LLSpatialPartition::put(LLDrawable *drawablep, BOOL was_visible) +{ +	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); +		 +	drawablep->updateSpatialExtents(); + +	//keep drawable from being garbage collected +	LLPointer<LLDrawable> ptr = drawablep; +		 +	assert_octree_valid(mOctree); +	mOctree->insert(drawablep); +	assert_octree_valid(mOctree); +	 +	LLSpatialGroup* group = drawablep->getSpatialGroup(); + +	if (group && was_visible && group->isOcclusionState(LLSpatialGroup::QUERY_PENDING)) +	{ +		group->setOcclusionState(LLSpatialGroup::DISCARD_QUERY, LLSpatialGroup::STATE_MODE_ALL_CAMERAS); +	} + +	return group; +} + +BOOL LLSpatialPartition::remove(LLDrawable *drawablep, LLSpatialGroup *curp) +{ +	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); +	 +	drawablep->setSpatialGroup(NULL); + +	if (!curp->removeObject(drawablep)) +	{ +		OCT_ERRS << "Failed to remove drawable from octree!" << llendl; +	} + +	assert_octree_valid(mOctree); +	 +	return TRUE; +} + +void LLSpatialPartition::move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL immediate) +{ +	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); +		 +	// sanity check submitted by open source user bushing Spatula +	// who was seeing crashing here. (See VWR-424 reported by Bunny Mayne) +	if (!drawablep) +	{ +		OCT_ERRS << "LLSpatialPartition::move was passed a bad drawable." << llendl; +		return; +	} +		 +	BOOL was_visible = curp ? curp->isVisible() : FALSE; + +	if (curp && curp->mSpatialPartition != this) +	{ +		//keep drawable from being garbage collected +		LLPointer<LLDrawable> ptr = drawablep; +		if (curp->mSpatialPartition->remove(drawablep, curp)) +		{ +			put(drawablep, was_visible); +			return; +		} +		else +		{ +			OCT_ERRS << "Drawable lost between spatial partitions on outbound transition." << llendl; +		} +	} +		 +	if (curp && curp->updateInGroup(drawablep, immediate)) +	{ +		// Already updated, don't need to do anything +		assert_octree_valid(mOctree); +		return; +	} + +	//keep drawable from being garbage collected +	LLPointer<LLDrawable> ptr = drawablep; +	if (curp && !remove(drawablep, curp)) +	{ +		OCT_ERRS << "Move couldn't find existing spatial group!" << llendl; +	} + +	put(drawablep, was_visible); +} + +class LLSpatialShift : public LLSpatialGroup::OctreeTraveler +{ +public: +	const LLVector4a& mOffset; + +	LLSpatialShift(const LLVector4a& offset) : mOffset(offset) { } +	virtual void visit(const LLSpatialGroup::OctreeNode* branch)  +	{  +		((LLSpatialGroup*) branch->getListener(0))->shift(mOffset);  +	} +}; + +void LLSpatialPartition::shift(const LLVector4a &offset) +{ //shift octree node bounding boxes by offset +	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); +	LLSpatialShift shifter(offset); +	shifter.traverse(mOctree); +} + +class LLOctreeCull : public LLSpatialGroup::OctreeTraveler +{ +public: +	LLOctreeCull(LLCamera* camera) +		: mCamera(camera), mRes(0) { } + +	virtual bool earlyFail(LLSpatialGroup* group) +	{ +		group->checkOcclusion(); + +		if (group->mOctreeNode->getParent() &&	//never occlusion cull the root node +		  	LLPipeline::sUseOcclusion &&			//ignore occlusion if disabled +			group->isOcclusionState(LLSpatialGroup::OCCLUDED)) +		{ +			gPipeline.markOccluder(group); +			return true; +		} +		 +		return false; +	} +	 +	virtual void traverse(const LLSpatialGroup::OctreeNode* n) +	{ +		LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0); + +		if (earlyFail(group)) +		{ +			return; +		} +		 +		if (mRes == 2 ||  +			(mRes && group->isState(LLSpatialGroup::SKIP_FRUSTUM_CHECK))) +		{	//fully in, just add everything +			LLSpatialGroup::OctreeTraveler::traverse(n); +		} +		else +		{ +			mRes = frustumCheck(group); +				 +			if (mRes) +			{ //at least partially in, run on down +				LLSpatialGroup::OctreeTraveler::traverse(n); +			} + +			mRes = 0; +		} +	} +	 +	virtual S32 frustumCheck(const LLSpatialGroup* group) +	{ +		S32 res = mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]); +		if (res != 0) +		{ +			res = llmin(res, AABBSphereIntersect(group->mExtents[0], group->mExtents[1], mCamera->getOrigin(), mCamera->mFrustumCornerDist)); +		} +		return res; +	} + +	virtual S32 frustumCheckObjects(const LLSpatialGroup* group) +	{ +		S32 res = mCamera->AABBInFrustumNoFarClip(group->mObjectBounds[0], group->mObjectBounds[1]); +		if (res != 0) +		{ +			res = llmin(res, AABBSphereIntersect(group->mObjectExtents[0], group->mObjectExtents[1], mCamera->getOrigin(), mCamera->mFrustumCornerDist)); +		} +		return res; +	} + +	virtual bool checkObjects(const LLSpatialGroup::OctreeNode* branch, const LLSpatialGroup* group) +	{ +		if (branch->getElementCount() == 0) //no elements +		{ +			return false; +		} +		else if (branch->getChildCount() == 0) //leaf state, already checked tightest bounding box +		{ +			return true; +		} +		else if (mRes == 1 && !frustumCheckObjects(group)) //no objects in frustum +		{ +			return false; +		} +		 +		return true; +	} + +	virtual void preprocess(LLSpatialGroup* group) +	{ +		 +	} +	 +	virtual void processGroup(LLSpatialGroup* group) +	{ +		if (group->needsUpdate() || +			group->mVisible[LLViewerCamera::sCurCameraID] < LLDrawable::getCurrentFrame() - 1) +		{ +			group->doOcclusion(mCamera); +		} +		gPipeline.markNotCulled(group, *mCamera); +	} +	 +	virtual void visit(const LLSpatialGroup::OctreeNode* branch)  +	{	 +		LLSpatialGroup* group = (LLSpatialGroup*) branch->getListener(0); + +		preprocess(group); +		 +		if (checkObjects(branch, group)) +		{ +			processGroup(group); +		} +	} + +	LLCamera *mCamera; +	S32 mRes; +}; + +class LLOctreeCullNoFarClip : public LLOctreeCull +{ +public:  +	LLOctreeCullNoFarClip(LLCamera* camera)  +		: LLOctreeCull(camera) { } + +	virtual S32 frustumCheck(const LLSpatialGroup* group) +	{ +		return mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]); +	} + +	virtual S32 frustumCheckObjects(const LLSpatialGroup* group) +	{ +		S32 res = mCamera->AABBInFrustumNoFarClip(group->mObjectBounds[0], group->mObjectBounds[1]); +		return res; +	} +}; + +class LLOctreeCullShadow : public LLOctreeCull +{ +public: +	LLOctreeCullShadow(LLCamera* camera) +		: LLOctreeCull(camera) { } + +	virtual S32 frustumCheck(const LLSpatialGroup* group) +	{ +		return mCamera->AABBInFrustum(group->mBounds[0], group->mBounds[1]); +	} + +	virtual S32 frustumCheckObjects(const LLSpatialGroup* group) +	{ +		return mCamera->AABBInFrustum(group->mObjectBounds[0], group->mObjectBounds[1]); +	} +}; + +class LLOctreeCullVisExtents: public LLOctreeCullShadow +{ +public: +	LLOctreeCullVisExtents(LLCamera* camera, LLVector4a& min, LLVector4a& max) +		: LLOctreeCullShadow(camera), mMin(min), mMax(max), mEmpty(TRUE) { } + +	virtual bool earlyFail(LLSpatialGroup* group) +	{ +		if (group->mOctreeNode->getParent() &&	//never occlusion cull the root node +			LLPipeline::sUseOcclusion &&			//ignore occlusion if disabled +			group->isOcclusionState(LLSpatialGroup::OCCLUDED)) +		{ +			return true; +		} +		 +		return false; +	} + +	virtual void traverse(const LLSpatialGroup::OctreeNode* n) +	{ +		LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0); + +		if (earlyFail(group)) +		{ +			return; +		} +		 +		if ((mRes && group->isState(LLSpatialGroup::SKIP_FRUSTUM_CHECK)) || +			mRes == 2) +		{	//don't need to do frustum check +			LLSpatialGroup::OctreeTraveler::traverse(n); +		} +		else +		{   +			mRes = frustumCheck(group); +				 +			if (mRes) +			{ //at least partially in, run on down +				LLSpatialGroup::OctreeTraveler::traverse(n); +			} + +			mRes = 0; +		} +	} + +	virtual void processGroup(LLSpatialGroup* group) +	{ +		llassert(!group->isState(LLSpatialGroup::DIRTY) && !group->getData().empty()) +		 +		if (mRes < 2) +		{ +			if (mCamera->AABBInFrustum(group->mObjectBounds[0], group->mObjectBounds[1]) > 0) +			{ +				mEmpty = FALSE; +				update_min_max(mMin, mMax, group->mObjectExtents[0]); +				update_min_max(mMin, mMax, group->mObjectExtents[1]); +			} +		} +		else +		{ +			mEmpty = FALSE; +			update_min_max(mMin, mMax, group->mExtents[0]); +			update_min_max(mMin, mMax, group->mExtents[1]); +		} +	} + +	BOOL mEmpty; +	LLVector4a& mMin; +	LLVector4a& mMax; +}; + +class LLOctreeCullDetectVisible: public LLOctreeCullShadow +{ +public: +	LLOctreeCullDetectVisible(LLCamera* camera) +		: LLOctreeCullShadow(camera), mResult(FALSE) { } + +	virtual bool earlyFail(LLSpatialGroup* group) +	{ +		if (mResult || //already found a node, don't check any more +			(group->mOctreeNode->getParent() &&	//never occlusion cull the root node +			 LLPipeline::sUseOcclusion &&			//ignore occlusion if disabled +			 group->isOcclusionState(LLSpatialGroup::OCCLUDED))) +		{ +			return true; +		} +		 +		return false; +	} + +	virtual void processGroup(LLSpatialGroup* group) +	{ +		if (group->isVisible()) +		{ +			mResult = TRUE; +		} +	} + +	BOOL mResult; +}; + +class LLOctreeSelect : public LLOctreeCull +{ +public: +	LLOctreeSelect(LLCamera* camera, std::vector<LLDrawable*>* results) +		: LLOctreeCull(camera), mResults(results) { } + +	virtual bool earlyFail(LLSpatialGroup* group) { return false; } +	virtual void preprocess(LLSpatialGroup* group) { } + +	virtual void processGroup(LLSpatialGroup* group) +	{ +		LLSpatialGroup::OctreeNode* branch = group->mOctreeNode; + +		for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i) +		{ +			LLDrawable* drawable = *i; +			 +			if (!drawable->isDead()) +			{ +				if (drawable->isSpatialBridge()) +				{ +					drawable->setVisible(*mCamera, mResults, TRUE); +				} +				else +				{ +					mResults->push_back(drawable); +				} +			}		 +		} +	} +	 +	std::vector<LLDrawable*>* mResults; +}; + +void drawBox(const LLVector3& c, const LLVector3& r) +{ +	LLVertexBuffer::unbind(); + +	gGL.begin(LLRender::TRIANGLE_STRIP); +	//left front +	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,-1))).mV); +	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,1))).mV); +	//right front +	gGL.vertex3fv((c+r.scaledVec(LLVector3(1,1,-1))).mV); +	gGL.vertex3fv((c+r.scaledVec(LLVector3(1,1,1))).mV); +	//right back + 	gGL.vertex3fv((c+r.scaledVec(LLVector3(1,-1,-1))).mV); +	gGL.vertex3fv((c+r.scaledVec(LLVector3(1,-1,1))).mV); +	//left back +	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,-1,-1))).mV); +	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,-1,1))).mV); +	//left front +	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,-1))).mV); +	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,1))).mV); +	gGL.end(); +	 +	//bottom +	gGL.begin(LLRender::TRIANGLE_STRIP); +	gGL.vertex3fv((c+r.scaledVec(LLVector3(1,1,-1))).mV); +	gGL.vertex3fv((c+r.scaledVec(LLVector3(1,-1,-1))).mV); +	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,-1))).mV); +	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,-1,-1))).mV); +	gGL.end(); + +	//top +	gGL.begin(LLRender::TRIANGLE_STRIP); +	gGL.vertex3fv((c+r.scaledVec(LLVector3(1,1,1))).mV); +	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,1))).mV); +	gGL.vertex3fv((c+r.scaledVec(LLVector3(1,-1,1))).mV); +	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,-1,1))).mV); +	gGL.end();	 +} + +void drawBox(const LLVector4a& c, const LLVector4a& r) +{ +	drawBox(reinterpret_cast<const LLVector3&>(c), reinterpret_cast<const LLVector3&>(r)); +} + +void drawBoxOutline(const LLVector3& pos, const LLVector3& size) +{ +	LLVector3 v1 = size.scaledVec(LLVector3( 1, 1,1)); +	LLVector3 v2 = size.scaledVec(LLVector3(-1, 1,1)); +	LLVector3 v3 = size.scaledVec(LLVector3(-1,-1,1)); +	LLVector3 v4 = size.scaledVec(LLVector3( 1,-1,1)); + +	gGL.begin(LLRender::LINES);  +	 +	//top +	gGL.vertex3fv((pos+v1).mV); +	gGL.vertex3fv((pos+v2).mV); +	gGL.vertex3fv((pos+v2).mV); +	gGL.vertex3fv((pos+v3).mV); +	gGL.vertex3fv((pos+v3).mV); +	gGL.vertex3fv((pos+v4).mV); +	gGL.vertex3fv((pos+v4).mV); +	gGL.vertex3fv((pos+v1).mV); +	 +	//bottom +	gGL.vertex3fv((pos-v1).mV); +	gGL.vertex3fv((pos-v2).mV); +	gGL.vertex3fv((pos-v2).mV); +	gGL.vertex3fv((pos-v3).mV); +	gGL.vertex3fv((pos-v3).mV); +	gGL.vertex3fv((pos-v4).mV); +	gGL.vertex3fv((pos-v4).mV); +	gGL.vertex3fv((pos-v1).mV); +	 +	//right +	gGL.vertex3fv((pos+v1).mV); +	gGL.vertex3fv((pos-v3).mV); +			 +	gGL.vertex3fv((pos+v4).mV); +	gGL.vertex3fv((pos-v2).mV); + +	//left +	gGL.vertex3fv((pos+v2).mV); +	gGL.vertex3fv((pos-v4).mV); + +	gGL.vertex3fv((pos+v3).mV); +	gGL.vertex3fv((pos-v1).mV); + +	gGL.end(); +} + +void drawBoxOutline(const LLVector4a& pos, const LLVector4a& size) +{ +	drawBoxOutline(reinterpret_cast<const LLVector3&>(pos), reinterpret_cast<const LLVector3&>(size)); +} + +class LLOctreeDirty : public LLOctreeTraveler<LLDrawable> +{ +public: +	virtual void visit(const LLOctreeNode<LLDrawable>* state) +	{ +		LLSpatialGroup* group = (LLSpatialGroup*) state->getListener(0); +		group->destroyGL(); + +		for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) +		{ +			LLDrawable* drawable = *i; +			if (drawable->getVObj().notNull() && !group->mSpatialPartition->mRenderByGroup) +			{ +				gPipeline.markRebuild(drawable, LLDrawable::REBUILD_ALL, TRUE); +			} +		} + +		for (LLSpatialGroup::bridge_list_t::iterator i = group->mBridgeList.begin(); i != group->mBridgeList.end(); ++i) +		{ +			LLSpatialBridge* bridge = *i; +			traverse(bridge->mOctree); +		} +	} +}; + +void LLSpatialPartition::restoreGL() +{ +	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); +} + +void LLSpatialPartition::resetVertexBuffers() +{ +	LLOctreeDirty dirty; +	dirty.traverse(mOctree); +} + +BOOL LLSpatialPartition::isOcclusionEnabled() +{ +	return mOcclusionEnabled || LLPipeline::sUseOcclusion > 2; +} + +BOOL LLSpatialPartition::getVisibleExtents(LLCamera& camera, LLVector3& visMin, LLVector3& visMax) +{ +	LLVector4a visMina, visMaxa; +	visMina.load3(visMin.mV); +	visMaxa.load3(visMax.mV); + +	{ +		LLFastTimer ftm(FTM_CULL_REBOUND);		 +		LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0); +		group->rebound(); +	} + +	LLOctreeCullVisExtents vis(&camera, visMina, visMaxa); +	vis.traverse(mOctree); + +	visMin.set(visMina.getF32ptr()); +	visMax.set(visMaxa.getF32ptr()); +	return vis.mEmpty; +} + +BOOL LLSpatialPartition::visibleObjectsInFrustum(LLCamera& camera) +{ +	LLOctreeCullDetectVisible vis(&camera); +	vis.traverse(mOctree); +	return vis.mResult; +} + +S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* results, BOOL for_select) +{ +	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); +#if LL_OCTREE_PARANOIA_CHECK +	((LLSpatialGroup*)mOctree->getListener(0))->checkStates(); +#endif +	{ +		LLFastTimer ftm(FTM_CULL_REBOUND);		 +		LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0); +		group->rebound(); +	} + +#if LL_OCTREE_PARANOIA_CHECK +	((LLSpatialGroup*)mOctree->getListener(0))->validate(); +#endif + +	 +	if (for_select) +	{ +		LLOctreeSelect selecter(&camera, results); +		selecter.traverse(mOctree); +	} +	else if (LLPipeline::sShadowRender) +	{ +		LLFastTimer ftm(FTM_FRUSTUM_CULL); +		LLOctreeCullShadow culler(&camera); +		culler.traverse(mOctree); +	} +	else if (mInfiniteFarClip || !LLPipeline::sUseFarClip) +	{ +		LLFastTimer ftm(FTM_FRUSTUM_CULL);		 +		LLOctreeCullNoFarClip culler(&camera); +		culler.traverse(mOctree); +	} +	else +	{ +		LLFastTimer ftm(FTM_FRUSTUM_CULL);		 +		LLOctreeCull culler(&camera); +		culler.traverse(mOctree); +	} +	 +	return 0; +} + +BOOL earlyFail(LLCamera* camera, LLSpatialGroup* group) +{ +	if (camera->getOrigin().isExactlyZero()) +	{ +		return FALSE; +	} + +	const F32 vel = SG_OCCLUSION_FUDGE*2.f; +	LLVector4a fudge; +	fudge.splat(vel); + +	const LLVector4a& c = group->mBounds[0]; +	LLVector4a r; +	r.setAdd(group->mBounds[1], fudge); + +	/*if (r.magVecSquared() > 1024.0*1024.0) +	{ +		return TRUE; +	}*/ + +	LLVector4a e; +	e.load3(camera->getOrigin().mV); +	 +	LLVector4a min; +	min.setSub(c,r); +	LLVector4a max; +	max.setAdd(c,r); +	 +	S32 lt = e.lessThan(min).getGatheredBits() & 0x7; +	if (lt) +	{ +		return FALSE; +	} + +	S32 gt = e.greaterThan(max).getGatheredBits() & 0x7; +	if (gt) +	{ +		return FALSE; +	} + +	return TRUE; +} + + +void pushVerts(LLDrawInfo* params, U32 mask) +{ +	LLRenderPass::applyModelMatrix(*params); +	params->mVertexBuffer->setBuffer(mask); +	params->mVertexBuffer->drawRange(params->mParticle ? LLRender::POINTS : LLRender::TRIANGLES, +								params->mStart, params->mEnd, params->mCount, params->mOffset); +} + +void pushVerts(LLSpatialGroup* group, U32 mask) +{ +	LLDrawInfo* params = NULL; + +	for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i) +	{ +		for (LLSpatialGroup::drawmap_elem_t::iterator j = i->second.begin(); j != i->second.end(); ++j)  +		{ +			params = *j; +			pushVerts(params, mask); +		} +	} +} + +void pushVerts(LLFace* face, U32 mask) +{ +	llassert(face->verify()); + +	LLVertexBuffer* buffer = face->getVertexBuffer(); + +	if (buffer && (face->getGeomCount() >= 3)) +	{ +		buffer->setBuffer(mask); +		U16 start = face->getGeomStart(); +		U16 end = start + face->getGeomCount()-1; +		U32 count = face->getIndicesCount(); +		U16 offset = face->getIndicesStart(); +		buffer->drawRange(LLRender::TRIANGLES, start, end, count, offset); +	} +} + +void pushVerts(LLDrawable* drawable, U32 mask) +{ +	for (S32 i = 0; i < drawable->getNumFaces(); ++i) +	{ +		pushVerts(drawable->getFace(i), mask); +	} +} + +void pushVerts(LLVolume* volume) +{ +	LLVertexBuffer::unbind(); +	for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i) +	{ +		const LLVolumeFace& face = volume->getVolumeFace(i); +		LLVertexBuffer::drawElements(LLRender::TRIANGLES, face.mPositions, NULL, face.mNumIndices, face.mIndices); +	} +} + +void pushBufferVerts(LLVertexBuffer* buffer, U32 mask) +{ +	if (buffer) +	{ +		buffer->setBuffer(mask); +		buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); +	} +} + +void pushBufferVerts(LLSpatialGroup* group, U32 mask) +{ +	if (group->mSpatialPartition->mRenderByGroup) +	{ +		if (!group->mDrawMap.empty()) +		{ +			LLDrawInfo* params = *(group->mDrawMap.begin()->second.begin()); +			LLRenderPass::applyModelMatrix(*params); +		 +			pushBufferVerts(group->mVertexBuffer, mask); + +			for (LLSpatialGroup::buffer_map_t::iterator i = group->mBufferMap.begin(); i != group->mBufferMap.end(); ++i) +			{ +				for (LLSpatialGroup::buffer_texture_map_t::iterator j = i->second.begin(); j != i->second.end(); ++j) +				{ +					for (LLSpatialGroup::buffer_list_t::iterator k = j->second.begin(); k != j->second.end(); ++k) +					{ +						pushBufferVerts(*k, mask); +					} +				} +			} +		} +	} +	else +	{ +		drawBox(group->mBounds[0], group->mBounds[1]); +	} +} + +void pushVertsColorCoded(LLSpatialGroup* group, U32 mask) +{ +	LLDrawInfo* params = NULL; + +	LLColor4 colors[] = { +		LLColor4::green, +		LLColor4::green1, +		LLColor4::green2, +		LLColor4::green3, +		LLColor4::green4, +		LLColor4::green5, +		LLColor4::green6 +	}; +		 +	static const U32 col_count = LL_ARRAY_SIZE(colors); + +	U32 col = 0; + +	for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i) +	{ +		for (LLSpatialGroup::drawmap_elem_t::iterator j = i->second.begin(); j != i->second.end(); ++j)  +		{ +			params = *j; +			LLRenderPass::applyModelMatrix(*params); +			gGL.diffuseColor4f(colors[col].mV[0], colors[col].mV[1], colors[col].mV[2], 0.5f); +			params->mVertexBuffer->setBuffer(mask); +			params->mVertexBuffer->drawRange(params->mParticle ? LLRender::POINTS : LLRender::TRIANGLES, +				params->mStart, params->mEnd, params->mCount, params->mOffset); +			col = (col+1)%col_count; +		} +	} +} + +void renderOctree(LLSpatialGroup* group) +{ +	//render solid object bounding box, color +	//coded by buffer usage and activity +	gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA); +	LLVector4 col; +	if (group->mBuilt > 0.f) +	{ +		group->mBuilt -= 2.f * gFrameIntervalSeconds; +		if (group->mBufferUsage == GL_STATIC_DRAW_ARB) +		{ +			col.setVec(1.0f, 0, 0, group->mBuilt*0.5f); +		} +		else  +		{ +			col.setVec(0.1f,0.1f,1,0.1f); +			//col.setVec(1.0f, 1.0f, 0, sinf(group->mBuilt*3.14159f)*0.5f); +		} + +		if (group->mBufferUsage != GL_STATIC_DRAW_ARB) +		{ +			LLGLDepthTest gl_depth(FALSE, FALSE); +			glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + +			gGL.diffuseColor4f(1,0,0,group->mBuilt); +			gGL.flush(); +			glLineWidth(5.f); +			drawBoxOutline(group->mObjectBounds[0], group->mObjectBounds[1]); +			gGL.flush(); +			glLineWidth(1.f); +			gGL.flush(); +			for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) +			{ +				LLDrawable* drawable = *i; +				if (!group->mSpatialPartition->isBridge()) +				{ +					gGL.pushMatrix(); +					LLVector3 trans = drawable->getRegion()->getOriginAgent(); +					gGL.translatef(trans.mV[0], trans.mV[1], trans.mV[2]); +				} +				 +				for (S32 j = 0; j < drawable->getNumFaces(); j++) +				{ +					LLFace* face = drawable->getFace(j); +					if (face->getVertexBuffer()) +					{ +						if (gFrameTimeSeconds - face->mLastUpdateTime < 0.5f) +						{ +							gGL.diffuseColor4f(0, 1, 0, group->mBuilt); +						} +						else if (gFrameTimeSeconds - face->mLastMoveTime < 0.5f) +						{ +							gGL.diffuseColor4f(1, 0, 0, group->mBuilt); +						} +						else +						{ +							continue; +						} + +						face->getVertexBuffer()->setBuffer(LLVertexBuffer::MAP_VERTEX); +						//drawBox((face->mExtents[0] + face->mExtents[1])*0.5f, +						//		(face->mExtents[1]-face->mExtents[0])*0.5f); +						face->getVertexBuffer()->draw(LLRender::TRIANGLES, face->getIndicesCount(), face->getIndicesStart()); +					} +				} + +				if (!group->mSpatialPartition->isBridge()) +				{ +					gGL.popMatrix(); +				} +			} +			glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); +			gGL.diffuseColor4f(1,1,1,1); +		} +	} +	else +	{ +		if (group->mBufferUsage == GL_STATIC_DRAW_ARB && !group->getData().empty()  +			&& group->mSpatialPartition->mRenderByGroup) +		{ +			col.setVec(0.8f, 0.4f, 0.1f, 0.1f); +		} +		else +		{ +			col.setVec(0.1f, 0.1f, 1.f, 0.1f); +		} +	} + +	gGL.diffuseColor4fv(col.mV); +	LLVector4a fudge; +	fudge.splat(0.001f); +	LLVector4a size = group->mObjectBounds[1]; +	size.mul(1.01f); +	size.add(fudge); + +	//{ +	//	LLGLDepthTest depth(GL_TRUE, GL_FALSE); +	//	drawBox(group->mObjectBounds[0], fudge); +	//} +	 +	gGL.setSceneBlendType(LLRender::BT_ALPHA); + +	//if (group->mBuilt <= 0.f) +	{ +		//draw opaque outline +		//gGL.diffuseColor4f(col.mV[0], col.mV[1], col.mV[2], 1.f); +		//drawBoxOutline(group->mObjectBounds[0], group->mObjectBounds[1]); + +		gGL.diffuseColor4f(0,1,1,1); +		drawBoxOutline(group->mBounds[0],group->mBounds[1]); +		 +		//draw bounding box for draw info +		/*if (group->mSpatialPartition->mRenderByGroup) +		{ +			gGL.diffuseColor4f(1.0f, 0.75f, 0.25f, 0.6f); +			for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i) +			{ +				for (LLSpatialGroup::drawmap_elem_t::iterator j = i->second.begin(); j != i->second.end(); ++j) +				{ +					LLDrawInfo* draw_info = *j; +					LLVector4a center; +					center.setAdd(draw_info->mExtents[1], draw_info->mExtents[0]); +					center.mul(0.5f); +					LLVector4a size; +					size.setSub(draw_info->mExtents[1], draw_info->mExtents[0]); +					size.mul(0.5f); +					drawBoxOutline(center, size); +				} +			} +		}*/ +	} +	 +//	LLSpatialGroup::OctreeNode* node = group->mOctreeNode; +//	gGL.diffuseColor4f(0,1,0,1); +//	drawBoxOutline(LLVector3(node->getCenter()), LLVector3(node->getSize())); +} + +void renderVisibility(LLSpatialGroup* group, LLCamera* camera) +{ +	LLGLEnable blend(GL_BLEND); +	gGL.setSceneBlendType(LLRender::BT_ALPHA); +	LLGLEnable cull(GL_CULL_FACE); +	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + +	BOOL render_objects = (!LLPipeline::sUseOcclusion || !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) && group->isVisible() && +							!group->getData().empty(); + +	if (render_objects) +	{ +		LLGLDepthTest depth_under(GL_TRUE, GL_FALSE, GL_GREATER); +		gGL.diffuseColor4f(0, 0.5f, 0, 0.5f); +		gGL.diffuseColor4f(0, 0.5f, 0, 0.5f); +		pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX); +	} + +	{ +		LLGLDepthTest depth_over(GL_TRUE, GL_FALSE, GL_LEQUAL); + +		if (render_objects) +		{ +			gGL.diffuseColor4f(0.f, 0.5f, 0.f,1.f); +			gGL.diffuseColor4f(0.f, 0.5f, 0.f, 1.f); +			pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX); +		} + +		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + +		if (render_objects) +		{ +			gGL.diffuseColor4f(0.f, 0.75f, 0.f,0.5f); +			gGL.diffuseColor4f(0.f, 0.75f, 0.f, 0.5f); +			pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX); +		} +		/*else if (camera && group->mOcclusionVerts.notNull()) +		{ +			LLVertexBuffer::unbind(); +			group->mOcclusionVerts->setBuffer(LLVertexBuffer::MAP_VERTEX); +			 +			gGL.diffuseColor4f(1.0f, 0.f, 0.f, 0.5f); +			group->mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, group->mBounds[0])); +			glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); +			 +			gGL.diffuseColor4f(1.0f, 1.f, 1.f, 1.0f); +			group->mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, group->mBounds[0])); +			glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); +		}*/ +	} +} + +void renderCrossHairs(LLVector3 position, F32 size, LLColor4 color) +{ +	gGL.diffuseColor4fv(color.mV); +	gGL.begin(LLRender::LINES); +	{ +		gGL.vertex3fv((position - LLVector3(size, 0.f, 0.f)).mV); +		gGL.vertex3fv((position + LLVector3(size, 0.f, 0.f)).mV); +		gGL.vertex3fv((position - LLVector3(0.f, size, 0.f)).mV); +		gGL.vertex3fv((position + LLVector3(0.f, size, 0.f)).mV); +		gGL.vertex3fv((position - LLVector3(0.f, 0.f, size)).mV); +		gGL.vertex3fv((position + LLVector3(0.f, 0.f, size)).mV); +	} +	gGL.end(); +} + +void renderUpdateType(LLDrawable* drawablep) +{ +	LLViewerObject* vobj = drawablep->getVObj(); +	if (!vobj || OUT_UNKNOWN == vobj->getLastUpdateType()) +	{ +		return; +	} +	LLGLEnable blend(GL_BLEND); +	switch (vobj->getLastUpdateType()) +	{ +	case OUT_FULL: +		gGL.diffuseColor4f(0,1,0,0.5f); +		break; +	case OUT_TERSE_IMPROVED: +		gGL.diffuseColor4f(0,1,1,0.5f); +		break; +	case OUT_FULL_COMPRESSED: +		if (vobj->getLastUpdateCached()) +		{ +			gGL.diffuseColor4f(1,0,0,0.5f); +		} +		else +		{ +			gGL.diffuseColor4f(1,1,0,0.5f); +		} +		break; +	case OUT_FULL_CACHED: +		gGL.diffuseColor4f(0,0,1,0.5f); +		break; +	default: +		llwarns << "Unknown update_type " << vobj->getLastUpdateType() << llendl; +		break; +	}; +	S32 num_faces = drawablep->getNumFaces(); +	if (num_faces) +	{ +		for (S32 i = 0; i < num_faces; ++i) +		{ +			pushVerts(drawablep->getFace(i), LLVertexBuffer::MAP_VERTEX); +		} +	} +} + +void renderComplexityDisplay(LLDrawable* drawablep) +{ +	LLViewerObject* vobj = drawablep->getVObj(); +	if (!vobj) +	{ +		return; +	} + +	LLVOVolume *voVol = dynamic_cast<LLVOVolume*>(vobj); + +	if (!voVol) +	{ +		return; +	} + +	if (!voVol->isRoot()) +	{ +		return; +	} + +	LLVOVolume::texture_cost_t textures; +	F32 cost = (F32) voVol->getRenderCost(textures); + +	// add any child volumes +	LLViewerObject::const_child_list_t children = voVol->getChildren(); +	for (LLViewerObject::const_child_list_t::const_iterator iter = children.begin(); iter != children.end(); ++iter) +	{ +		const LLViewerObject *child = *iter; +		const LLVOVolume *child_volume = dynamic_cast<const LLVOVolume*>(child); +		if (child_volume) +		{ +			cost += child_volume->getRenderCost(textures); +		} +	} + +	// add texture cost +	for (LLVOVolume::texture_cost_t::iterator iter = textures.begin(); iter != textures.end(); ++iter) +	{ +		// add the cost of each individual texture in the linkset +		cost += iter->second; +	} + +	F32 cost_max = (F32) LLVOVolume::getRenderComplexityMax(); + + + +	// allow user to set a static color scale +	if (gSavedSettings.getS32("RenderComplexityStaticMax") > 0) +	{ +		cost_max = gSavedSettings.getS32("RenderComplexityStaticMax"); +	} + +	F32 cost_ratio = cost / cost_max; +	 +	// cap cost ratio at 1.0f in case cost_max is at a low threshold +	cost_ratio = cost_ratio > 1.0f ? 1.0f : cost_ratio; +	 +	LLGLEnable blend(GL_BLEND); + +	LLColor4 color; +	const LLColor4 color_min = gSavedSettings.getColor4("RenderComplexityColorMin"); +	const LLColor4 color_mid = gSavedSettings.getColor4("RenderComplexityColorMid"); +	const LLColor4 color_max = gSavedSettings.getColor4("RenderComplexityColorMax"); + +	if (cost_ratio < 0.5f) +	{ +		color = color_min * (1 - cost_ratio * 2) + color_mid * (cost_ratio * 2); +	} +	else +	{ +		color = color_mid * (1 - (cost_ratio - 0.5) * 2) + color_max * ((cost_ratio - 0.5) * 2); +	} + +	LLSD color_val = color.getValue(); + +	// don't highlight objects below the threshold +	if (cost > gSavedSettings.getS32("RenderComplexityThreshold")) +	{ +		glColor4f(color[0],color[1],color[2],0.5f); + + +		S32 num_faces = drawablep->getNumFaces(); +		if (num_faces) +		{ +			for (S32 i = 0; i < num_faces; ++i) +			{ +				pushVerts(drawablep->getFace(i), LLVertexBuffer::MAP_VERTEX); +			} +		} +		LLViewerObject::const_child_list_t children = voVol->getChildren(); +		for (LLViewerObject::const_child_list_t::const_iterator iter = children.begin(); iter != children.end(); ++iter) +		{ +			const LLViewerObject *child = *iter; +			if (child) +			{ +				num_faces = child->getNumFaces(); +				if (num_faces) +				{ +					for (S32 i = 0; i < num_faces; ++i) +					{ +						pushVerts(child->mDrawable->getFace(i), LLVertexBuffer::MAP_VERTEX); +					} +				} +			} +		} +	} +	 +	voVol->setDebugText(llformat("%4.0f", cost));	 +} + +void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE) +{ +	if (set_color) +	{ +		if (drawable->isSpatialBridge()) +		{ +			gGL.diffuseColor4f(1,0.5f,0,1); +		} +		else if (drawable->getVOVolume()) +		{ +			if (drawable->isRoot()) +			{ +				gGL.diffuseColor4f(1,1,0,1); +			} +			else +			{ +				gGL.diffuseColor4f(0,1,0,1); +			} +		} +		else if (drawable->getVObj()) +		{ +			switch (drawable->getVObj()->getPCode()) +			{ +				case LLViewerObject::LL_VO_SURFACE_PATCH: +						gGL.diffuseColor4f(0,1,1,1); +						break; +				case LLViewerObject::LL_VO_CLOUDS: +						// no longer used +						break; +				case LLViewerObject::LL_VO_PART_GROUP: +				case LLViewerObject::LL_VO_HUD_PART_GROUP: +						gGL.diffuseColor4f(0,0,1,1); +						break; +				case LLViewerObject::LL_VO_VOID_WATER: +				case LLViewerObject::LL_VO_WATER: +						gGL.diffuseColor4f(0,0.5f,1,1); +						break; +				case LL_PCODE_LEGACY_TREE: +						gGL.diffuseColor4f(0,0.5f,0,1); +						break; +				default: +						gGL.diffuseColor4f(1,0,1,1); +						break; +			} +		} +		else  +		{ +			gGL.diffuseColor4f(1,0,0,1); +		} +	} + +	const LLVector4a* ext; +	LLVector4a pos, size; + +	//render face bounding boxes +	for (S32 i = 0; i < drawable->getNumFaces(); i++) +	{ +		LLFace* facep = drawable->getFace(i); + +		ext = facep->mExtents; + +		pos.setAdd(ext[0], ext[1]); +		pos.mul(0.5f); +		size.setSub(ext[1], ext[0]); +		size.mul(0.5f); +		 +		drawBoxOutline(pos,size); +	} + +	//render drawable bounding box +	ext = drawable->getSpatialExtents(); + +	pos.setAdd(ext[0], ext[1]); +	pos.mul(0.5f); +	size.setSub(ext[1], ext[0]); +	size.mul(0.5f); +	 +	LLViewerObject* vobj = drawable->getVObj(); +	if (vobj && vobj->onActiveList()) +	{ +		gGL.flush(); +		glLineWidth(llmax(4.f*sinf(gFrameTimeSeconds*2.f)+1.f, 1.f)); +		//glLineWidth(4.f*(sinf(gFrameTimeSeconds*2.f)*0.25f+0.75f)); +		stop_glerror(); +		drawBoxOutline(pos,size); +		gGL.flush(); +		glLineWidth(1.f); +	} +	else +	{ +		drawBoxOutline(pos,size); +	} +} + +void renderNormals(LLDrawable* drawablep) +{ +	LLVertexBuffer::unbind(); + +	LLVOVolume* vol = drawablep->getVOVolume(); +	if (vol) +	{ +		LLVolume* volume = vol->getVolume(); +		gGL.pushMatrix(); +		gGL.multMatrix((F32*) vol->getRelativeXform().mMatrix); +		 +		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + +		LLVector4a scale(gSavedSettings.getF32("RenderDebugNormalScale")); + +		for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i) +		{ +			const LLVolumeFace& face = volume->getVolumeFace(i); + +			for (S32 j = 0; j < face.mNumVertices; ++j) +			{ +				gGL.begin(LLRender::LINES); +				LLVector4a n,p; +				 +				n.setMul(face.mNormals[j], scale); +				p.setAdd(face.mPositions[j], n); +				 +				gGL.diffuseColor4f(1,1,1,1); +				gGL.vertex3fv(face.mPositions[j].getF32ptr()); +				gGL.vertex3fv(p.getF32ptr()); +				 +				if (face.mBinormals) +				{ +					n.setMul(face.mBinormals[j], scale); +					p.setAdd(face.mPositions[j], n); +				 +					gGL.diffuseColor4f(0,1,1,1); +					gGL.vertex3fv(face.mPositions[j].getF32ptr()); +					gGL.vertex3fv(p.getF32ptr()); +				}	 +				gGL.end(); +			} +		} + +		gGL.popMatrix(); +	} +} + +S32 get_physics_detail(const LLVolumeParams& volume_params, const LLVector3& scale) +{ +	const S32 DEFAULT_DETAIL = 1; +	const F32 LARGE_THRESHOLD = 5.f; +	const F32 MEGA_THRESHOLD = 25.f; + +	S32 detail = DEFAULT_DETAIL; +	F32 avg_scale = (scale[0]+scale[1]+scale[2])/3.f; + +	if (avg_scale > LARGE_THRESHOLD) +	{ +		detail += 1; +		if (avg_scale > MEGA_THRESHOLD) +		{ +			detail += 1; +		} +	} + +	return detail; +} + +void renderMeshBaseHull(LLVOVolume* volume, U32 data_mask, LLColor4& color, LLColor4& line_color) +{ +	LLUUID mesh_id = volume->getVolume()->getParams().getSculptID(); +	LLModel::Decomposition* decomp = gMeshRepo.getDecomposition(mesh_id); + +	const LLVector3 center(0,0,0); +	const LLVector3 size(0.25f,0.25f,0.25f); + +	if (decomp) +	{		 +		if (!decomp->mBaseHullMesh.empty()) +		{ +			gGL.diffuseColor4fv(color.mV); +			LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mBaseHullMesh.mPositions, decomp->mBaseHullMesh.mNormals); +		} +		else +		{ +			gMeshRepo.buildPhysicsMesh(*decomp); +			gGL.diffuseColor4f(0,1,1,1); +			drawBoxOutline(center, size); +		} + +	} +	else +	{ +		gGL.diffuseColor3f(1,0,1); +		drawBoxOutline(center, size); +	} +} + +void render_hull(LLModel::PhysicsMesh& mesh, const LLColor4& color, const LLColor4& line_color) +{ +	gGL.diffuseColor4fv(color.mV); +	LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions, mesh.mNormals); +	LLGLEnable offset(GL_POLYGON_OFFSET_LINE); +	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); +	glPolygonOffset(3.f, 3.f); +	glLineWidth(3.f); +	gGL.diffuseColor4fv(line_color.mV); +	LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions, mesh.mNormals); +	glLineWidth(1.f); +	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); +} + +void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume) +{ +	U8 physics_type = volume->getPhysicsShapeType(); + +	if (physics_type == LLViewerObject::PHYSICS_SHAPE_NONE || volume->isFlexible()) +	{ +		return; +	} + +	//not allowed to return at this point without rendering *something* + +	F32 threshold = gSavedSettings.getF32("ObjectCostHighThreshold"); +	F32 cost = volume->getObjectCost(); + +	LLColor4 low = gSavedSettings.getColor4("ObjectCostLowColor"); +	LLColor4 mid = gSavedSettings.getColor4("ObjectCostMidColor"); +	LLColor4 high = gSavedSettings.getColor4("ObjectCostHighColor"); + +	F32 normalizedCost = 1.f - exp( -(cost / threshold) ); + +	LLColor4 color; +	if ( normalizedCost <= 0.5f ) +	{ +		color = lerp( low, mid, 2.f * normalizedCost ); +	} +	else +	{ +		color = lerp( mid, high, 2.f * ( normalizedCost - 0.5f ) ); +	} + +	LLColor4 line_color = color*0.5f; + +	U32 data_mask = LLVertexBuffer::MAP_VERTEX; + +	LLVolumeParams volume_params = volume->getVolume()->getParams(); + +	LLPhysicsVolumeParams physics_params(volume_params,  +		physics_type == LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL);  + +	LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification physics_spec; +	LLPhysicsShapeBuilderUtil::determinePhysicsShape(physics_params, volume->getScale(), physics_spec); + +	U32 type = physics_spec.getType(); + +	LLVector3 center(0,0,0); +	LLVector3 size(0.25f,0.25f,0.25f); + +	gGL.pushMatrix(); +	gGL.multMatrix((F32*) volume->getRelativeXform().mMatrix); +		 +	if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::USER_MESH) +	{ +		LLUUID mesh_id = volume->getVolume()->getParams().getSculptID(); +		LLModel::Decomposition* decomp = gMeshRepo.getDecomposition(mesh_id); +			 +		if (decomp) +		{ //render a physics based mesh +			 +			gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + +			if (!decomp->mHull.empty()) +			{ //decomposition exists, use that + +				if (decomp->mMesh.empty()) +				{ +					gMeshRepo.buildPhysicsMesh(*decomp); +				} + +				for (U32 i = 0; i < decomp->mMesh.size(); ++i) +				{		 +					render_hull(decomp->mMesh[i], color, line_color); +				} +			} +			else if (!decomp->mPhysicsShapeMesh.empty()) +			{  +				//decomp has physics mesh, render that mesh +				gGL.diffuseColor4fv(color.mV); +				LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions, decomp->mPhysicsShapeMesh.mNormals); +								 +				glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); +				gGL.diffuseColor4fv(line_color.mV); +				LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions, decomp->mPhysicsShapeMesh.mNormals); +				glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); +			} +			else +			{ //no mesh or decomposition, render base hull +				renderMeshBaseHull(volume, data_mask, color, line_color); + +				if (decomp->mPhysicsShapeMesh.empty()) +				{ +					//attempt to fetch physics shape mesh if available +					gMeshRepo.fetchPhysicsShape(mesh_id); +				} +			} +		} +		else +		{	 +			gGL.diffuseColor3f(1,1,0); +			drawBoxOutline(center, size); +		} +	} +	else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::USER_CONVEX || +		type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::PRIM_CONVEX) +	{ +		if (volume->isMesh()) +		{ +			renderMeshBaseHull(volume, data_mask, color, line_color); +		} +		else +		{ +			LLVolumeParams volume_params = volume->getVolume()->getParams(); +			S32 detail = get_physics_detail(volume_params, volume->getScale()); +			LLVolume* phys_volume = LLPrimitive::sVolumeManager->refVolume(volume_params, detail); + +			if (!phys_volume->mHullPoints) +			{ //build convex hull +				std::vector<LLVector3> pos; +				std::vector<U16> index; + +				S32 index_offset = 0; + +				for (S32 i = 0; i < phys_volume->getNumVolumeFaces(); ++i) +				{ +					const LLVolumeFace& face = phys_volume->getVolumeFace(i); +					if (index_offset + face.mNumVertices > 65535) +					{ +						continue; +					} + +					for (S32 j = 0; j < face.mNumVertices; ++j) +					{ +						pos.push_back(LLVector3(face.mPositions[j].getF32ptr())); +					} + +					for (S32 j = 0; j < face.mNumIndices; ++j) +					{ +						index.push_back(face.mIndices[j]+index_offset); +					} + +					index_offset += face.mNumVertices; +				} + +				if (!pos.empty() && !index.empty()) +				{ +					LLCDMeshData mesh; +					mesh.mIndexBase = &index[0]; +					mesh.mVertexBase = pos[0].mV; +					mesh.mNumVertices = pos.size(); +					mesh.mVertexStrideBytes = 12; +					mesh.mIndexStrideBytes = 6; +					mesh.mIndexType = LLCDMeshData::INT_16; + +					mesh.mNumTriangles = index.size()/3; +					 +					LLCDMeshData res; + +					LLConvexDecomposition::getInstance()->generateSingleHullMeshFromMesh( &mesh, &res ); + +					//copy res into phys_volume +					phys_volume->mHullPoints = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*res.mNumVertices); +					phys_volume->mNumHullPoints = res.mNumVertices; + +					S32 idx_size = (res.mNumTriangles*3*2+0xF) & ~0xF; +					phys_volume->mHullIndices = (U16*) ll_aligned_malloc_16(idx_size); +					phys_volume->mNumHullIndices = res.mNumTriangles*3; + +					const F32* v = res.mVertexBase; + +					for (S32 i = 0; i < res.mNumVertices; ++i) +					{ +						F32* p = (F32*) ((U8*)v+i*res.mVertexStrideBytes); +						phys_volume->mHullPoints[i].load3(p); +					} + +					if (res.mIndexType == LLCDMeshData::INT_16) +					{ +						for (S32 i = 0; i < res.mNumTriangles; ++i) +						{ +							U16* idx = (U16*) (((U8*)res.mIndexBase)+i*res.mIndexStrideBytes); + +							phys_volume->mHullIndices[i*3+0] = idx[0]; +							phys_volume->mHullIndices[i*3+1] = idx[1]; +							phys_volume->mHullIndices[i*3+2] = idx[2]; +						} +					} +					else +					{ +						for (S32 i = 0; i < res.mNumTriangles; ++i) +						{ +							U32* idx = (U32*) (((U8*)res.mIndexBase)+i*res.mIndexStrideBytes); + +							phys_volume->mHullIndices[i*3+0] = (U16) idx[0]; +							phys_volume->mHullIndices[i*3+1] = (U16) idx[1]; +							phys_volume->mHullIndices[i*3+2] = (U16) idx[2]; +						} +					} +				} +			} + +			if (phys_volume->mHullPoints) +			{ +				//render hull +			 +				glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); +				 +				gGL.diffuseColor4fv(line_color.mV); +				LLVertexBuffer::unbind(); + +				llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShader != 0); +							 +				LLVertexBuffer::drawElements(LLRender::TRIANGLES, phys_volume->mHullPoints, NULL, phys_volume->mNumHullIndices, phys_volume->mHullIndices); +				 +				gGL.diffuseColor4fv(color.mV); +				glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); +				LLVertexBuffer::drawElements(LLRender::TRIANGLES, phys_volume->mHullPoints, NULL, phys_volume->mNumHullIndices, phys_volume->mHullIndices); +				 +			} +			else +			{ +				gGL.diffuseColor4f(1,0,1,1); +				drawBoxOutline(center, size); +			} + +			LLPrimitive::sVolumeManager->unrefVolume(phys_volume); +		} +	} +	else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::BOX) +	{ +		LLVector3 center = physics_spec.getCenter(); +		LLVector3 scale = physics_spec.getScale(); +		LLVector3 vscale = volume->getScale()*2.f; +		scale.set(scale[0]/vscale[0], scale[1]/vscale[1], scale[2]/vscale[2]); +		 +		gGL.diffuseColor4fv(color.mV); +		drawBox(center, scale); +	} +	else if	(type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::SPHERE) +	{ +		/*LLVolumeParams volume_params; +		volume_params.setType( LL_PCODE_PROFILE_CIRCLE_HALF, LL_PCODE_PATH_CIRCLE ); +		volume_params.setBeginAndEndS( 0.f, 1.f ); +		volume_params.setBeginAndEndT( 0.f, 1.f ); +		volume_params.setRatio	( 1, 1 ); +		volume_params.setShear	( 0, 0 ); +		LLVolume* sphere = LLPrimitive::sVolumeManager->refVolume(volume_params, 3); +		 +		gGL.diffuseColor4fv(color.mV); +		pushVerts(sphere); +		LLPrimitive::sVolumeManager->unrefVolume(sphere);*/ +	} +	else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::CYLINDER) +	{ +		LLVolumeParams volume_params; +		volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE ); +		volume_params.setBeginAndEndS( 0.f, 1.f ); +		volume_params.setBeginAndEndT( 0.f, 1.f ); +		volume_params.setRatio	( 1, 1 ); +		volume_params.setShear	( 0, 0 ); +		LLVolume* cylinder = LLPrimitive::sVolumeManager->refVolume(volume_params, 3); +		 +		gGL.diffuseColor4fv(color.mV); +		pushVerts(cylinder); +		LLPrimitive::sVolumeManager->unrefVolume(cylinder); +	} +	else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::PRIM_MESH) +	{ +		LLVolumeParams volume_params = volume->getVolume()->getParams(); +		S32 detail = get_physics_detail(volume_params, volume->getScale()); + +		LLVolume* phys_volume = LLPrimitive::sVolumeManager->refVolume(volume_params, detail); +		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); +		 +		gGL.diffuseColor4fv(line_color.mV); +		pushVerts(phys_volume); +		 +		gGL.diffuseColor4fv(color.mV); +		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); +		pushVerts(phys_volume); +		LLPrimitive::sVolumeManager->unrefVolume(phys_volume); +	} +	else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::PRIM_CONVEX) +	{ +		LLVolumeParams volume_params = volume->getVolume()->getParams(); +		S32 detail = get_physics_detail(volume_params, volume->getScale()); + +		LLVolume* phys_volume = LLPrimitive::sVolumeManager->refVolume(volume_params, detail); + +		if (phys_volume->mHullPoints && phys_volume->mHullIndices) +		{ +			glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); +			llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShader != 0); +			LLVertexBuffer::unbind(); +			glVertexPointer(3, GL_FLOAT, 16, phys_volume->mHullPoints); +			gGL.diffuseColor4fv(line_color.mV); +			gGL.syncMatrices(); +			glDrawElements(GL_TRIANGLES, phys_volume->mNumHullIndices, GL_UNSIGNED_SHORT, phys_volume->mHullIndices); +			 +			gGL.diffuseColor4fv(color.mV); +			glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); +			glDrawElements(GL_TRIANGLES, phys_volume->mNumHullIndices, GL_UNSIGNED_SHORT, phys_volume->mHullIndices);			 +		} +		else +		{ +			gGL.diffuseColor3f(1,0,1); +			drawBoxOutline(center, size); +			gMeshRepo.buildHull(volume_params, detail); +		} +		LLPrimitive::sVolumeManager->unrefVolume(phys_volume); +	} +	else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::SCULPT) +	{ +		//TODO: implement sculpted prim physics display +	} +	else  +	{ +		llerrs << "Unhandled type" << llendl; +	} + +	gGL.popMatrix(); +} + +void renderPhysicsShapes(LLSpatialGroup* group) +{ +	for (LLSpatialGroup::OctreeNode::const_element_iter i = group->getData().begin(); i != group->getData().end(); ++i) +	{ +		LLDrawable* drawable = *i; +		LLVOVolume* volume = drawable->getVOVolume(); +		if (volume && !volume->isAttachment() && volume->getPhysicsShapeType() != LLViewerObject::PHYSICS_SHAPE_NONE ) +		{ +			if (!group->mSpatialPartition->isBridge()) +			{ +				gGL.pushMatrix(); +				LLVector3 trans = drawable->getRegion()->getOriginAgent(); +				gGL.translatef(trans.mV[0], trans.mV[1], trans.mV[2]); +				renderPhysicsShape(drawable, volume); +				gGL.popMatrix(); +			} +			else +			{ +				renderPhysicsShape(drawable, volume); +			} +		} +		else +		{ +			LLViewerObject* object = drawable->getVObj(); +			if (object && object->getPCode() == LLViewerObject::LL_VO_SURFACE_PATCH) +			{ +				//push face vertices for terrain +				for (S32 i = 0; i < drawable->getNumFaces(); ++i) +				{ +					LLFace* face = drawable->getFace(i); +					LLVertexBuffer* buff = face->getVertexBuffer(); +					if (buff) +					{ +						glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + +						buff->setBuffer(LLVertexBuffer::MAP_VERTEX); +						gGL.diffuseColor3f(0.2f, 0.5f, 0.3f); +						buff->draw(LLRender::TRIANGLES, buff->getNumIndices(), 0); +									 +						gGL.diffuseColor3f(0.2f, 1.f, 0.3f); +						glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); +						buff->draw(LLRender::TRIANGLES, buff->getNumIndices(), 0); +					} +				} +			} +		} +	} +} + +void renderTexturePriority(LLDrawable* drawable) +{ +	for (int face=0; face<drawable->getNumFaces(); ++face) +	{ +		LLFace *facep = drawable->getFace(face); +		 +		LLVector4 cold(0,0,0.25f); +		LLVector4 hot(1,0.25f,0.25f); +	 +		LLVector4 boost_cold(0,0,0,0); +		LLVector4 boost_hot(0,1,0,1); +		 +		LLGLDisable blend(GL_BLEND); +		 +		//LLViewerTexture* imagep = facep->getTexture(); +		//if (imagep) +		{ +				 +			//F32 vsize = imagep->mMaxVirtualSize; +			F32 vsize = facep->getPixelArea(); + +			if (vsize > sCurMaxTexPriority) +			{ +				sCurMaxTexPriority = vsize; +			} +			 +			F32 t = vsize/sLastMaxTexPriority; +			 +			LLVector4 col = lerp(cold, hot, t); +			gGL.diffuseColor4fv(col.mV); +		} +		//else +		//{ +		//	gGL.diffuseColor4f(1,0,1,1); +		//} +		 +		LLVector4a center; +		center.setAdd(facep->mExtents[1],facep->mExtents[0]); +		center.mul(0.5f); +		LLVector4a size; +		size.setSub(facep->mExtents[1],facep->mExtents[0]); +		size.mul(0.5f); +		size.add(LLVector4a(0.01f)); +		drawBox(center, size); +		 +		/*S32 boost = imagep->getBoostLevel(); +		if (boost>LLViewerTexture::BOOST_NONE) +		{ +			F32 t = (F32) boost / (F32) (LLViewerTexture::BOOST_MAX_LEVEL-1); +			LLVector4 col = lerp(boost_cold, boost_hot, t); +			LLGLEnable blend_on(GL_BLEND); +			gGL.blendFunc(GL_SRC_ALPHA, GL_ONE); +			gGL.diffuseColor4fv(col.mV); +			drawBox(center, size); +			gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +		}*/ +	} +} + +void renderPoints(LLDrawable* drawablep) +{ +	LLGLDepthTest depth(GL_FALSE, GL_FALSE); +	if (drawablep->getNumFaces()) +	{ +		gGL.begin(LLRender::POINTS); +		gGL.diffuseColor3f(1,1,1); +		for (S32 i = 0; i < drawablep->getNumFaces(); i++) +		{ +			gGL.vertex3fv(drawablep->getFace(i)->mCenterLocal.mV); +		} +		gGL.end(); +	} +} + +void renderTextureAnim(LLDrawInfo* params) +{ +	if (!params->mTextureMatrix) +	{ +		return; +	} +	 +	LLGLEnable blend(GL_BLEND); +	gGL.diffuseColor4f(1,1,0,0.5f); +	pushVerts(params, LLVertexBuffer::MAP_VERTEX); +} + +void renderBatchSize(LLDrawInfo* params) +{ +	LLGLEnable offset(GL_POLYGON_OFFSET_FILL); +	glPolygonOffset(-1.f, 1.f); +	gGL.diffuseColor4ubv((GLubyte*) &(params->mDebugColor)); +	pushVerts(params, LLVertexBuffer::MAP_VERTEX); +} + +void renderShadowFrusta(LLDrawInfo* params) +{ +	LLGLEnable blend(GL_BLEND); +	gGL.setSceneBlendType(LLRender::BT_ADD); + +	LLVector4a center; +	center.setAdd(params->mExtents[1], params->mExtents[0]); +	center.mul(0.5f); +	LLVector4a size; +	size.setSub(params->mExtents[1],params->mExtents[0]); +	size.mul(0.5f); + +	if (gPipeline.mShadowCamera[4].AABBInFrustum(center, size)) +	{ +		gGL.diffuseColor3f(1,0,0); +		pushVerts(params, LLVertexBuffer::MAP_VERTEX); +	} +	if (gPipeline.mShadowCamera[5].AABBInFrustum(center, size)) +	{ +		gGL.diffuseColor3f(0,1,0); +		pushVerts(params, LLVertexBuffer::MAP_VERTEX); +	} +	if (gPipeline.mShadowCamera[6].AABBInFrustum(center, size)) +	{ +		gGL.diffuseColor3f(0,0,1); +		pushVerts(params, LLVertexBuffer::MAP_VERTEX); +	} +	if (gPipeline.mShadowCamera[7].AABBInFrustum(center, size)) +	{ +		gGL.diffuseColor3f(1,0,1); +		pushVerts(params, LLVertexBuffer::MAP_VERTEX); +	} + +	gGL.setSceneBlendType(LLRender::BT_ALPHA); +} + + +void renderLights(LLDrawable* drawablep) +{ +	if (!drawablep->isLight()) +	{ +		return; +	} + +	if (drawablep->getNumFaces()) +	{ +		LLGLEnable blend(GL_BLEND); +		gGL.diffuseColor4f(0,1,1,0.5f); + +		for (S32 i = 0; i < drawablep->getNumFaces(); i++) +		{ +			pushVerts(drawablep->getFace(i), LLVertexBuffer::MAP_VERTEX); +		} + +		const LLVector4a* ext = drawablep->getSpatialExtents(); + +		LLVector4a pos; +		pos.setAdd(ext[0], ext[1]); +		pos.mul(0.5f); +		LLVector4a size; +		size.setSub(ext[1], ext[0]); +		size.mul(0.5f); + +		{ +			LLGLDepthTest depth(GL_FALSE, GL_TRUE); +			gGL.diffuseColor4f(1,1,1,1); +			drawBoxOutline(pos, size); +		} + +		gGL.diffuseColor4f(1,1,0,1); +		F32 rad = drawablep->getVOVolume()->getLightRadius(); +		drawBoxOutline(pos, LLVector4a(rad)); +	} +} + +class LLRenderOctreeRaycast : public LLOctreeTriangleRayIntersect +{ +public: +	 +	 +	LLRenderOctreeRaycast(const LLVector4a& start, const LLVector4a& dir, F32* closest_t) +		: LLOctreeTriangleRayIntersect(start, dir, NULL, closest_t, NULL, NULL, NULL, NULL) +	{ + +	} + +	void visit(const LLOctreeNode<LLVolumeTriangle>* branch) +	{ +		LLVolumeOctreeListener* vl = (LLVolumeOctreeListener*) branch->getListener(0); + +		LLVector3 center, size; +		 +		if (branch->getData().empty()) +		{ +			gGL.diffuseColor3f(1.f,0.2f,0.f); +			center.set(branch->getCenter().getF32ptr()); +			size.set(branch->getSize().getF32ptr()); +		} +		else +		{ +			gGL.diffuseColor3f(0.75f, 1.f, 0.f); +			center.set(vl->mBounds[0].getF32ptr()); +			size.set(vl->mBounds[1].getF32ptr()); +		} + +		drawBoxOutline(center, size);	 +		 +		for (U32 i = 0; i < 2; i++) +		{ +			LLGLDepthTest depth(GL_TRUE, GL_FALSE, i == 1 ? GL_LEQUAL : GL_GREATER); + +			if (i == 1) +			{ +				gGL.diffuseColor4f(0,1,1,0.5f); +			} +			else +			{ +				gGL.diffuseColor4f(0,0.5f,0.5f, 0.25f); +				drawBoxOutline(center, size); +			} +			 +			if (i == 1) +			{ +				gGL.flush(); +				glLineWidth(3.f); +			} + +			gGL.begin(LLRender::TRIANGLES); +			for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter = branch->getData().begin(); +					iter != branch->getData().end(); +					++iter) +			{ +				const LLVolumeTriangle* tri = *iter; +				 +				gGL.vertex3fv(tri->mV[0]->getF32ptr()); +				gGL.vertex3fv(tri->mV[1]->getF32ptr()); +				gGL.vertex3fv(tri->mV[2]->getF32ptr()); +			}	 +			gGL.end(); + +			if (i == 1) +			{ +				gGL.flush(); +				glLineWidth(1.f); +			} +		} +	} +}; + +void renderRaycast(LLDrawable* drawablep) +{ +	if (drawablep->getNumFaces()) +	{ +		LLGLEnable blend(GL_BLEND); +		gGL.diffuseColor4f(0,1,1,0.5f); + +		if (drawablep->getVOVolume()) +		{ +			//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); +			//pushVerts(drawablep->getFace(gDebugRaycastFaceHit), LLVertexBuffer::MAP_VERTEX); +			//glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + +			LLVOVolume* vobj = drawablep->getVOVolume(); +			LLVolume* volume = vobj->getVolume(); + +			bool transform = true; +			if (drawablep->isState(LLDrawable::RIGGED)) +			{ +				volume = vobj->getRiggedVolume(); +				transform = false; +			} + +			if (volume) +			{ +				LLVector3 trans = drawablep->getRegion()->getOriginAgent(); +				 +				for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i) +				{ +					const LLVolumeFace& face = volume->getVolumeFace(i); +					 +					gGL.pushMatrix(); +					gGL.translatef(trans.mV[0], trans.mV[1], trans.mV[2]);					 +					gGL.multMatrix((F32*) vobj->getRelativeXform().mMatrix); + +					LLVector3 start, end; +					if (transform) +					{ +						start = vobj->agentPositionToVolume(gDebugRaycastStart); +						end = vobj->agentPositionToVolume(gDebugRaycastEnd); +					} +					else +					{ +						start = gDebugRaycastStart; +						end = gDebugRaycastEnd; +					} + +					LLVector4a starta, enda; +					starta.load3(start.mV); +					enda.load3(end.mV); +					LLVector4a dir; +					dir.setSub(enda, starta); + +					gGL.flush(); +					glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);				 + +					{ +						//render face positions +						LLVertexBuffer::unbind(); +						gGL.diffuseColor4f(0,1,1,0.5f); +						glVertexPointer(3, GL_FLOAT, sizeof(LLVector4a), face.mPositions); +						gGL.syncMatrices(); +						glDrawElements(GL_TRIANGLES, face.mNumIndices, GL_UNSIGNED_SHORT, face.mIndices); +					} +					 +					if (!volume->isUnique()) +					{ +						F32 t = 1.f; + +						if (!face.mOctree) +						{ +							((LLVolumeFace*) &face)->createOctree();  +						} + +						LLRenderOctreeRaycast render(starta, dir, &t); +					 +						render.traverse(face.mOctree); +					} + +					gGL.popMatrix();		 +					glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); +				} +			} +		} +		else if (drawablep->isAvatar()) +		{ +			if (drawablep->getVObj() == gDebugRaycastObject) +			{ +				LLGLDepthTest depth(GL_FALSE); +				LLVOAvatar* av = (LLVOAvatar*) drawablep->getVObj().get(); +				av->renderCollisionVolumes(); +			} +		} + +		if (drawablep->getVObj() == gDebugRaycastObject) +		{ +			// draw intersection point +			gGL.pushMatrix(); +			gGL.loadMatrix(gGLModelView); +			LLVector3 translate = gDebugRaycastIntersection; +			gGL.translatef(translate.mV[0], translate.mV[1], translate.mV[2]); +			LLCoordFrame orient; +			orient.lookDir(gDebugRaycastNormal, gDebugRaycastBinormal); +			LLMatrix4 rotation; +			orient.getRotMatrixToParent(rotation); +			gGL.multMatrix((float*)rotation.mMatrix); +			 +			gGL.diffuseColor4f(1,0,0,0.5f); +			drawBox(LLVector3(0, 0, 0), LLVector3(0.1f, 0.022f, 0.022f)); +			gGL.diffuseColor4f(0,1,0,0.5f); +			drawBox(LLVector3(0, 0, 0), LLVector3(0.021f, 0.1f, 0.021f)); +			gGL.diffuseColor4f(0,0,1,0.5f); +			drawBox(LLVector3(0, 0, 0), LLVector3(0.02f, 0.02f, 0.1f)); +			gGL.popMatrix(); + +			// draw bounding box of prim +			const LLVector4a* ext = drawablep->getSpatialExtents(); + +			LLVector4a pos; +			pos.setAdd(ext[0], ext[1]); +			pos.mul(0.5f); +			LLVector4a size; +			size.setSub(ext[1], ext[0]); +			size.mul(0.5f); + +			LLGLDepthTest depth(GL_FALSE, GL_TRUE); +			gGL.diffuseColor4f(0,0.5f,0.5f,1); +			drawBoxOutline(pos, size);		 +		} +	} +} + + +void renderAvatarCollisionVolumes(LLVOAvatar* avatar) +{ +	avatar->renderCollisionVolumes(); +} + +void renderAgentTarget(LLVOAvatar* avatar) +{ +	// render these for self only (why, i don't know) +	if (avatar->isSelf()) +	{ +		renderCrossHairs(avatar->getPositionAgent(), 0.2f, LLColor4(1, 0, 0, 0.8f)); +		renderCrossHairs(avatar->mDrawable->getPositionAgent(), 0.2f, LLColor4(1, 0, 0, 0.8f)); +		renderCrossHairs(avatar->mRoot.getWorldPosition(), 0.2f, LLColor4(1, 1, 1, 0.8f)); +		renderCrossHairs(avatar->mPelvisp->getWorldPosition(), 0.2f, LLColor4(0, 0, 1, 0.8f)); +	} +} + +class LLOctreeRenderNonOccluded : public LLOctreeTraveler<LLDrawable> +{ +public: +	LLCamera* mCamera; +	LLOctreeRenderNonOccluded(LLCamera* camera): mCamera(camera) {} +	 +	virtual void traverse(const LLSpatialGroup::OctreeNode* node) +	{ +		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0); +		 +		if (!mCamera || mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1])) +		{ +			node->accept(this); +			stop_glerror(); + +			for (U32 i = 0; i < node->getChildCount(); i++) +			{ +				traverse(node->getChild(i)); +				stop_glerror(); +			} +			 +			//draw tight fit bounding boxes for spatial group +			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCTREE)) +			{	 +				group->rebuildGeom(); +				group->rebuildMesh(); + +				renderOctree(group); +				stop_glerror(); +			} + +			//render visibility wireframe +			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION)) +			{ +				group->rebuildGeom(); +				group->rebuildMesh(); + +				gGL.flush(); +				gGL.pushMatrix(); +				gGLLastMatrix = NULL; +				gGL.loadMatrix(gGLModelView); +				renderVisibility(group, mCamera); +				stop_glerror(); +				gGLLastMatrix = NULL; +				gGL.popMatrix(); +				gGL.diffuseColor4f(1,1,1,1); +			} +		} +	} + +	virtual void visit(const LLSpatialGroup::OctreeNode* branch) +	{ +		LLSpatialGroup* group = (LLSpatialGroup*) branch->getListener(0); + +		if (group->isState(LLSpatialGroup::GEOM_DIRTY) || (mCamera && !mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]))) +		{ +			return; +		} + +		LLVector4a nodeCenter = group->mBounds[0]; +		LLVector4a octCenter = group->mOctreeNode->getCenter(); + +		group->rebuildGeom(); +		group->rebuildMesh(); + +		if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BBOXES)) +		{ +			if (!group->getData().empty()) +			{ +				gGL.diffuseColor3f(0,0,1); +				drawBoxOutline(group->mObjectBounds[0], +								group->mObjectBounds[1]); +			} +		} + +		for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i) +		{ +			LLDrawable* drawable = *i; +					 +			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BBOXES)) +			{ +				renderBoundingBox(drawable);			 +			} + +			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_NORMALS)) +			{ +				renderNormals(drawable); +			} +			 +			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BUILD_QUEUE)) +			{ +				if (drawable->isState(LLDrawable::IN_REBUILD_Q2)) +				{ +					gGL.diffuseColor4f(0.6f, 0.6f, 0.1f, 1.f); +					const LLVector4a* ext = drawable->getSpatialExtents(); +					LLVector4a center; +					center.setAdd(ext[0], ext[1]); +					center.mul(0.5f); +					LLVector4a size; +					size.setSub(ext[1], ext[0]); +					size.mul(0.5f); +					drawBoxOutline(center, size); +				} +			}	 + +			if (drawable->getVOVolume() && gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY)) +			{ +				renderTexturePriority(drawable); +			} + +			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_POINTS)) +			{ +				renderPoints(drawable); +			} + +			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_LIGHTS)) +			{ +				renderLights(drawable); +			} + +			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST)) +			{ +				renderRaycast(drawable); +			} +			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_UPDATE_TYPE)) +			{ +				renderUpdateType(drawable); +			} +			if(gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RENDER_COMPLEXITY)) +			{ +				renderComplexityDisplay(drawable); +			} + +			LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(drawable->getVObj().get()); +			 +			if (avatar && gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_AVATAR_VOLUME)) +			{ +				renderAvatarCollisionVolumes(avatar); +			} + +			if (avatar && gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_AGENT_TARGET)) +			{ +				renderAgentTarget(avatar); +			} +			 +			if (gDebugGL) +			{ +				for (U32 i = 0; i < drawable->getNumFaces(); ++i) +				{ +					LLFace* facep = drawable->getFace(i); +					U8 index = facep->getTextureIndex(); +					if (facep->mDrawInfo) +					{ +						if (index < 255) +						{ +							if (facep->mDrawInfo->mTextureList.size() <= index) +							{ +								llerrs << "Face texture index out of bounds." << llendl; +							} +							else if (facep->mDrawInfo->mTextureList[index] != facep->getTexture()) +							{ +								llerrs << "Face texture index incorrect." << llendl; +							} +						} +					} +				} +			} +		} +		 +		for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i) +		{ +			LLSpatialGroup::drawmap_elem_t& draw_vec = i->second;	 +			for (LLSpatialGroup::drawmap_elem_t::iterator j = draw_vec.begin(); j != draw_vec.end(); ++j)	 +			{ +				LLDrawInfo* draw_info = *j; +				if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_ANIM)) +				{ +					renderTextureAnim(draw_info); +				} +				if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BATCH_SIZE)) +				{ +					renderBatchSize(draw_info); +				} +				if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) +				{ +					renderShadowFrusta(draw_info); +				} +			} +		} +	} +}; + + +class LLOctreeRenderPhysicsShapes : public LLOctreeTraveler<LLDrawable> +{ +public: +	LLCamera* mCamera; +	LLOctreeRenderPhysicsShapes(LLCamera* camera): mCamera(camera) {} +	 +	virtual void traverse(const LLSpatialGroup::OctreeNode* node) +	{ +		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0); +		 +		if (!mCamera || mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1])) +		{ +			node->accept(this); +			stop_glerror(); + +			for (U32 i = 0; i < node->getChildCount(); i++) +			{ +				traverse(node->getChild(i)); +				stop_glerror(); +			} +			 +			group->rebuildGeom(); +			group->rebuildMesh(); + +			renderPhysicsShapes(group); +		} +	} + +	virtual void visit(const LLSpatialGroup::OctreeNode* branch) +	{ +		 +	} +}; + +class LLOctreePushBBoxVerts : public LLOctreeTraveler<LLDrawable> +{ +public: +	LLCamera* mCamera; +	LLOctreePushBBoxVerts(LLCamera* camera): mCamera(camera) {} +	 +	virtual void traverse(const LLSpatialGroup::OctreeNode* node) +	{ +		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0); +		 +		if (!mCamera || mCamera->AABBInFrustum(group->mBounds[0], group->mBounds[1])) +		{ +			node->accept(this); + +			for (U32 i = 0; i < node->getChildCount(); i++) +			{ +				traverse(node->getChild(i)); +			} +		} +	} + +	virtual void visit(const LLSpatialGroup::OctreeNode* branch) +	{ +		LLSpatialGroup* group = (LLSpatialGroup*) branch->getListener(0); + +		if (group->isState(LLSpatialGroup::GEOM_DIRTY) || (mCamera && !mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]))) +		{ +			return; +		} + +		for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i) +		{ +			LLDrawable* drawable = *i; +						 +			renderBoundingBox(drawable, FALSE);			 +		} +	} +}; + +void LLSpatialPartition::renderIntersectingBBoxes(LLCamera* camera) +{ +	LLOctreePushBBoxVerts pusher(camera); +	pusher.traverse(mOctree); +} + +class LLOctreeStateCheck : public LLOctreeTraveler<LLDrawable> +{ +public: +	U32 mInheritedMask[LLViewerCamera::NUM_CAMERAS]; + +	LLOctreeStateCheck() +	{  +		for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) +		{ +			mInheritedMask[i] = 0; +		} +	} + +	virtual void traverse(const LLSpatialGroup::OctreeNode* node) +	{ +		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0); +		 +		node->accept(this); + + +		U32 temp[LLViewerCamera::NUM_CAMERAS]; + +		for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) +		{ +			temp[i] = mInheritedMask[i]; +			mInheritedMask[i] |= group->mOcclusionState[i] & LLSpatialGroup::OCCLUDED;  +		} + +		for (U32 i = 0; i < node->getChildCount(); i++) +		{ +			traverse(node->getChild(i)); +		} + +		for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) +		{ +			mInheritedMask[i] = temp[i]; +		} +	} +	 + +	virtual void visit(const LLOctreeNode<LLDrawable>* state) +	{ +		LLSpatialGroup* group = (LLSpatialGroup*) state->getListener(0); + +		for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) +		{ +			if (mInheritedMask[i] && !(group->mOcclusionState[i] & mInheritedMask[i])) +			{ +				llerrs << "Spatial group failed inherited mask test." << llendl; +			} +		} + +		if (group->isState(LLSpatialGroup::DIRTY)) +		{ +			assert_parent_state(group, LLSpatialGroup::DIRTY); +		} +	} + +	void assert_parent_state(LLSpatialGroup* group, U32 state) +	{ +		LLSpatialGroup* parent = group->getParent(); +		while (parent) +		{ +			if (!parent->isState(state)) +			{ +				llerrs << "Spatial group failed parent state check." << llendl; +			} +			parent = parent->getParent(); +		} +	}	 +}; + + +void LLSpatialPartition::renderPhysicsShapes() +{ +	LLSpatialBridge* bridge = asBridge(); +	LLCamera* camera = LLViewerCamera::getInstance(); +	 +	if (bridge) +	{ +		camera = NULL; +	} + +	gGL.flush(); +	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); +	glLineWidth(3.f); +	LLOctreeRenderPhysicsShapes render_physics(camera); +	render_physics.traverse(mOctree); +	gGL.flush(); +	glLineWidth(1.f); +} + +void LLSpatialPartition::renderDebug() +{ +	if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCTREE | +									  LLPipeline::RENDER_DEBUG_OCCLUSION | +									  LLPipeline::RENDER_DEBUG_LIGHTS | +									  LLPipeline::RENDER_DEBUG_BATCH_SIZE | +									  LLPipeline::RENDER_DEBUG_UPDATE_TYPE | +									  LLPipeline::RENDER_DEBUG_BBOXES | +									  LLPipeline::RENDER_DEBUG_NORMALS | +									  LLPipeline::RENDER_DEBUG_POINTS | +									  LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY | +									  LLPipeline::RENDER_DEBUG_TEXTURE_ANIM | +									  LLPipeline::RENDER_DEBUG_RAYCAST | +									  LLPipeline::RENDER_DEBUG_AVATAR_VOLUME | +									  LLPipeline::RENDER_DEBUG_AGENT_TARGET | +									  //LLPipeline::RENDER_DEBUG_BUILD_QUEUE | +									  LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA | +									  LLPipeline::RENDER_DEBUG_RENDER_COMPLEXITY))  +	{ +		return; +	} +	 +	if (LLGLSLShader::sNoFixedFunction) +	{ +		gDebugProgram.bind(); +	} + +	if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY)) +	{ +		//sLastMaxTexPriority = lerp(sLastMaxTexPriority, sCurMaxTexPriority, gFrameIntervalSeconds); +		sLastMaxTexPriority = (F32) LLViewerCamera::getInstance()->getScreenPixelArea(); +		sCurMaxTexPriority = 0.f; +	} + +	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); +	 +	LLGLDisable cullface(GL_CULL_FACE); +	LLGLEnable blend(GL_BLEND); +	gGL.setSceneBlendType(LLRender::BT_ALPHA); +	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); +	gPipeline.disableLights(); + +	LLSpatialBridge* bridge = asBridge(); +	LLCamera* camera = LLViewerCamera::getInstance(); +	 +	if (bridge) +	{ +		camera = NULL; +	} + +	LLOctreeStateCheck checker; +	checker.traverse(mOctree); + +	LLOctreeRenderNonOccluded render_debug(camera); +	render_debug.traverse(mOctree); + +	if (LLGLSLShader::sNoFixedFunction) +	{ +		gDebugProgram.unbind(); +	} +} + +void LLSpatialGroup::drawObjectBox(LLColor4 col) +{ +	gGL.diffuseColor4fv(col.mV); +	LLVector4a size; +	size = mObjectBounds[1]; +	size.mul(1.01f); +	size.add(LLVector4a(0.001f)); +	drawBox(mObjectBounds[0], size); +} + +bool LLSpatialPartition::isHUDPartition()  +{  +	return mPartitionType == LLViewerRegion::PARTITION_HUD ; +}  + +BOOL LLSpatialPartition::isVisible(const LLVector3& v) +{ +	if (!LLViewerCamera::getInstance()->sphereInFrustum(v, 4.0f)) +	{ +		return FALSE; +	} + +	return TRUE; +} + +class LLOctreeIntersect : public LLSpatialGroup::OctreeTraveler +{ +public: +	LLVector3 mStart; +	LLVector3 mEnd; +	S32       *mFaceHit; +	LLVector3 *mIntersection; +	LLVector2 *mTexCoord; +	LLVector3 *mNormal; +	LLVector3 *mBinormal; +	LLDrawable* mHit; +	BOOL mPickTransparent; + +	LLOctreeIntersect(LLVector3 start, LLVector3 end, BOOL pick_transparent, +					  S32* face_hit, LLVector3* intersection, LLVector2* tex_coord, LLVector3* normal, LLVector3* binormal) +		: mStart(start), +		  mEnd(end), +		  mFaceHit(face_hit), +		  mIntersection(intersection), +		  mTexCoord(tex_coord), +		  mNormal(normal), +		  mBinormal(binormal), +		  mHit(NULL), +		  mPickTransparent(pick_transparent) +	{ +	} +	 +	virtual void visit(const LLSpatialGroup::OctreeNode* branch)  +	{	 +		for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i) +		{ +			check(*i); +		} +	} + +	virtual LLDrawable* check(const LLSpatialGroup::OctreeNode* node) +	{ +		node->accept(this); +	 +		for (U32 i = 0; i < node->getChildCount(); i++) +		{ +			const LLSpatialGroup::OctreeNode* child = node->getChild(i); +			LLVector3 res; + +			LLSpatialGroup* group = (LLSpatialGroup*) child->getListener(0); +			 +			LLVector4a size; +			LLVector4a center; +			 +			size = group->mBounds[1]; +			center = group->mBounds[0]; +			 +			LLVector3 local_start = mStart; +			LLVector3 local_end   = mEnd; + +			if (group->mSpatialPartition->isBridge()) +			{ +				LLMatrix4 local_matrix = group->mSpatialPartition->asBridge()->mDrawable->getRenderMatrix(); +				local_matrix.invert(); +				 +				local_start = mStart * local_matrix; +				local_end   = mEnd   * local_matrix; +			} + +			LLVector4a start, end; +			start.load3(local_start.mV); +			end.load3(local_end.mV); + +			if (LLLineSegmentBoxIntersect(start, end, center, size)) +			{ +				check(child); +			} +		}	 + +		return mHit; +	} + +	virtual bool check(LLDrawable* drawable) +	{	 +		LLVector3 local_start = mStart; +		LLVector3 local_end = mEnd; + +		if (!drawable || !gPipeline.hasRenderType(drawable->getRenderType()) || !drawable->isVisible()) +		{ +			return false; +		} + +		if (drawable->isSpatialBridge()) +		{ +			LLSpatialPartition *part = drawable->asPartition(); +			LLSpatialBridge* bridge = part->asBridge(); +			if (bridge && gPipeline.hasRenderType(bridge->mDrawableType)) +			{ +				check(part->mOctree); +			} +		} +		else +		{ +			LLViewerObject* vobj = drawable->getVObj(); + +			if (vobj) +			{ +				LLVector3 intersection; +				bool skip_check = false; +				if (vobj->isAvatar()) +				{ +					LLVOAvatar* avatar = (LLVOAvatar*) vobj; +					if (avatar->isSelf() && LLFloater::isVisible(gFloaterTools)) +					{ +						LLViewerObject* hit = avatar->lineSegmentIntersectRiggedAttachments(mStart, mEnd, -1, mPickTransparent, mFaceHit, &intersection, mTexCoord, mNormal, mBinormal); +						if (hit) +						{ +							mEnd = intersection; +							if (mIntersection) +							{ +								*mIntersection = intersection; +							} +							 +							mHit = hit->mDrawable; +							skip_check = true; +						} + +					} +				} + +				if (!skip_check && vobj->lineSegmentIntersect(mStart, mEnd, -1, mPickTransparent, mFaceHit, &intersection, mTexCoord, mNormal, mBinormal)) +				{ +					mEnd = intersection;  // shorten ray so we only find CLOSER hits +					if (mIntersection) +					{ +						*mIntersection = intersection; +					} +					 +					mHit = vobj->mDrawable; +				} +			} +		} +				 +		return false; +	} +}; + +LLDrawable* LLSpatialPartition::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, +													 BOOL pick_transparent,													 +													 S32* face_hit,                   // return the face hit +													 LLVector3* intersection,         // return the intersection point +													 LLVector2* tex_coord,            // return the texture coordinates of the intersection point +													 LLVector3* normal,               // return the surface normal at the intersection point +													 LLVector3* bi_normal             // return the surface bi-normal at the intersection point +	) + +{ +	LLOctreeIntersect intersect(start, end, pick_transparent, face_hit, intersection, tex_coord, normal, bi_normal); +	LLDrawable* drawable = intersect.check(mOctree); + +	return drawable; +} + +LLDrawInfo::LLDrawInfo(U16 start, U16 end, U32 count, U32 offset,  +					   LLViewerTexture* texture, LLVertexBuffer* buffer, +					   BOOL fullbright, U8 bump, BOOL particle, F32 part_size) +: +	mVertexBuffer(buffer), +	mTexture(texture), +	mTextureMatrix(NULL), +	mModelMatrix(NULL), +	mStart(start), +	mEnd(end), +	mCount(count), +	mOffset(offset),  +	mFullbright(fullbright), +	mBump(bump), +	mParticle(particle), +	mPartSize(part_size), +	mVSize(0.f), +	mGroup(NULL), +	mFace(NULL), +	mDistance(0.f), +	mDrawMode(LLRender::TRIANGLES) +{ +	mVertexBuffer->validateRange(mStart, mEnd, mCount, mOffset); +	 +	mDebugColor = (rand() << 16) + rand(); +} + +LLDrawInfo::~LLDrawInfo()	 +{ +	/*if (LLSpatialGroup::sNoDelete) +	{ +		llerrs << "LLDrawInfo deleted illegally!" << llendl; +	}*/ + +	if (mFace) +	{ +		mFace->setDrawInfo(NULL); +	} + +	if (gDebugGL) +	{ +		gPipeline.checkReferences(this); +	} +} + +void LLDrawInfo::validate() +{ +	mVertexBuffer->validateRange(mStart, mEnd, mCount, mOffset); +} + +LLVertexBuffer* LLGeometryManager::createVertexBuffer(U32 type_mask, U32 usage) +{ +	return new LLVertexBuffer(type_mask, usage); +} + +LLCullResult::LLCullResult()  +{ +	clear(); +} + +void LLCullResult::clear() +{ +	mVisibleGroupsSize = 0; +	mVisibleGroupsEnd = mVisibleGroups.begin(); + +	mAlphaGroupsSize = 0; +	mAlphaGroupsEnd = mAlphaGroups.begin(); + +	mOcclusionGroupsSize = 0; +	mOcclusionGroupsEnd = mOcclusionGroups.begin(); + +	mDrawableGroupsSize = 0; +	mDrawableGroupsEnd = mDrawableGroups.begin(); + +	mVisibleListSize = 0; +	mVisibleListEnd = mVisibleList.begin(); + +	mVisibleBridgeSize = 0; +	mVisibleBridgeEnd = mVisibleBridge.begin(); + + +	for (U32 i = 0; i < LLRenderPass::NUM_RENDER_TYPES; i++) +	{ +		for (U32 j = 0; j < mRenderMapSize[i]; j++) +		{ +			mRenderMap[i][j] = 0; +		} +		mRenderMapSize[i] = 0; +		mRenderMapEnd[i] = mRenderMap[i].begin(); +	} +} + +LLCullResult::sg_list_t::iterator LLCullResult::beginVisibleGroups() +{ +	return mVisibleGroups.begin(); +} + +LLCullResult::sg_list_t::iterator LLCullResult::endVisibleGroups() +{ +	return mVisibleGroupsEnd; +} + +LLCullResult::sg_list_t::iterator LLCullResult::beginAlphaGroups() +{ +	return mAlphaGroups.begin(); +} + +LLCullResult::sg_list_t::iterator LLCullResult::endAlphaGroups() +{ +	return mAlphaGroupsEnd; +} + +LLCullResult::sg_list_t::iterator LLCullResult::beginOcclusionGroups() +{ +	return mOcclusionGroups.begin(); +} + +LLCullResult::sg_list_t::iterator LLCullResult::endOcclusionGroups() +{ +	return mOcclusionGroupsEnd; +} + +LLCullResult::sg_list_t::iterator LLCullResult::beginDrawableGroups() +{ +	return mDrawableGroups.begin(); +} + +LLCullResult::sg_list_t::iterator LLCullResult::endDrawableGroups() +{ +	return mDrawableGroupsEnd; +} + +LLCullResult::drawable_list_t::iterator LLCullResult::beginVisibleList() +{ +	return mVisibleList.begin(); +} + +LLCullResult::drawable_list_t::iterator LLCullResult::endVisibleList() +{ +	return mVisibleListEnd; +} + +LLCullResult::bridge_list_t::iterator LLCullResult::beginVisibleBridge() +{ +	return mVisibleBridge.begin(); +} + +LLCullResult::bridge_list_t::iterator LLCullResult::endVisibleBridge() +{ +	return mVisibleBridgeEnd; +} + +LLCullResult::drawinfo_list_t::iterator LLCullResult::beginRenderMap(U32 type) +{ +	return mRenderMap[type].begin(); +} + +LLCullResult::drawinfo_list_t::iterator LLCullResult::endRenderMap(U32 type) +{ +	return mRenderMapEnd[type]; +} + +void LLCullResult::pushVisibleGroup(LLSpatialGroup* group) +{ +	if (mVisibleGroupsSize < mVisibleGroups.size()) +	{ +		mVisibleGroups[mVisibleGroupsSize] = group; +	} +	else +	{ +		mVisibleGroups.push_back(group); +	} +	++mVisibleGroupsSize; +	mVisibleGroupsEnd = mVisibleGroups.begin()+mVisibleGroupsSize; +} + +void LLCullResult::pushAlphaGroup(LLSpatialGroup* group) +{ +	if (mAlphaGroupsSize < mAlphaGroups.size()) +	{ +		mAlphaGroups[mAlphaGroupsSize] = group; +	} +	else +	{ +		mAlphaGroups.push_back(group); +	} +	++mAlphaGroupsSize; +	mAlphaGroupsEnd = mAlphaGroups.begin()+mAlphaGroupsSize; +} + +void LLCullResult::pushOcclusionGroup(LLSpatialGroup* group) +{ +	if (mOcclusionGroupsSize < mOcclusionGroups.size()) +	{ +		mOcclusionGroups[mOcclusionGroupsSize] = group; +	} +	else +	{ +		mOcclusionGroups.push_back(group); +	} +	++mOcclusionGroupsSize; +	mOcclusionGroupsEnd = mOcclusionGroups.begin()+mOcclusionGroupsSize; +} + +void LLCullResult::pushDrawableGroup(LLSpatialGroup* group) +{ +	if (mDrawableGroupsSize < mDrawableGroups.size()) +	{ +		mDrawableGroups[mDrawableGroupsSize] = group; +	} +	else +	{ +		mDrawableGroups.push_back(group); +	} +	++mDrawableGroupsSize; +	mDrawableGroupsEnd = mDrawableGroups.begin()+mDrawableGroupsSize; +} + +void LLCullResult::pushDrawable(LLDrawable* drawable) +{ +	if (mVisibleListSize < mVisibleList.size()) +	{ +		mVisibleList[mVisibleListSize] = drawable; +	} +	else +	{ +		mVisibleList.push_back(drawable); +	} +	++mVisibleListSize; +	mVisibleListEnd = mVisibleList.begin()+mVisibleListSize; +} + +void LLCullResult::pushBridge(LLSpatialBridge* bridge) +{ +	if (mVisibleBridgeSize < mVisibleBridge.size()) +	{ +		mVisibleBridge[mVisibleBridgeSize] = bridge; +	} +	else +	{ +		mVisibleBridge.push_back(bridge); +	} +	++mVisibleBridgeSize; +	mVisibleBridgeEnd = mVisibleBridge.begin()+mVisibleBridgeSize; +} + +void LLCullResult::pushDrawInfo(U32 type, LLDrawInfo* draw_info) +{ +	if (mRenderMapSize[type] < mRenderMap[type].size()) +	{ +		mRenderMap[type][mRenderMapSize[type]] = draw_info; +	} +	else +	{ +		mRenderMap[type].push_back(draw_info); +	} +	++mRenderMapSize[type]; +	mRenderMapEnd[type] = mRenderMap[type].begin() + mRenderMapSize[type]; +} + + +void LLCullResult::assertDrawMapsEmpty() +{ +	for (U32 i = 0; i < LLRenderPass::NUM_RENDER_TYPES; i++) +	{ +		if (mRenderMapSize[i] != 0) +		{ +			llerrs << "Stale LLDrawInfo's in LLCullResult!" << llendl; +		} +	} +} + + + diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 42309349b0..0adb187dd2 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -1,1568 +1,1563 @@ -/** 
 - * @file llviewerdisplay.cpp
 - * @brief LLViewerDisplay class implementation
 - *
 - * $LicenseInfo:firstyear=2004&license=viewerlgpl$
 - * Second Life Viewer Source Code
 - * Copyright (C) 2010, Linden Research, Inc.
 - * 
 - * This library is free software; you can redistribute it and/or
 - * modify it under the terms of the GNU Lesser General Public
 - * License as published by the Free Software Foundation;
 - * version 2.1 of the License only.
 - * 
 - * This library is distributed in the hope that it will be useful,
 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 - * Lesser General Public License for more details.
 - * 
 - * You should have received a copy of the GNU Lesser General Public
 - * License along with this library; if not, write to the Free Software
 - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 - * 
 - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 - * $/LicenseInfo$
 - */
 -
 -#include "llviewerprecompiledheaders.h"
 -
 -#include "llviewerdisplay.h"
 -
 -#include "llgl.h"
 -#include "llrender.h"
 -#include "llglheaders.h"
 -#include "llagent.h"
 -#include "llagentcamera.h"
 -#include "llviewercontrol.h"
 -#include "llcoord.h"
 -#include "llcriticaldamp.h"
 -#include "lldir.h"
 -#include "lldynamictexture.h"
 -#include "lldrawpoolalpha.h"
 -#include "llfeaturemanager.h"
 -//#include "llfirstuse.h"
 -#include "llhudmanager.h"
 -#include "llimagebmp.h"
 -#include "llmemory.h"
 -#include "llselectmgr.h"
 -#include "llsky.h"
 -#include "llstartup.h"
 -#include "lltoolfocus.h"
 -#include "lltoolmgr.h"
 -#include "lltooldraganddrop.h"
 -#include "lltoolpie.h"
 -#include "lltracker.h"
 -#include "lltrans.h"
 -#include "llui.h"
 -#include "llviewercamera.h"
 -#include "llviewerobjectlist.h"
 -#include "llviewerparcelmgr.h"
 -#include "llviewerwindow.h"
 -#include "llvoavatarself.h"
 -#include "llvograss.h"
 -#include "llworld.h"
 -#include "pipeline.h"
 -#include "llspatialpartition.h"
 -#include "llappviewer.h"
 -#include "llstartup.h"
 -#include "llviewershadermgr.h"
 -#include "llfasttimer.h"
 -#include "llfloatertools.h"
 -#include "llviewertexturelist.h"
 -#include "llfocusmgr.h"
 -#include "llcubemap.h"
 -#include "llviewerregion.h"
 -#include "lldrawpoolwater.h"
 -#include "lldrawpoolbump.h"
 -#include "llwlparammanager.h"
 -#include "llwaterparammanager.h"
 -#include "llpostprocess.h"
 -#include "LLPathingLib.h"
 -#include "llfloaterpathfindingconsole.h"
 -#include "llfloaterreg.h"
 -
 -extern LLPointer<LLViewerTexture> gStartTexture;
 -
 -LLPointer<LLViewerTexture> gDisconnectedImagep = NULL;
 -
 -// used to toggle renderer back on after teleport
 -const F32 TELEPORT_RENDER_DELAY = 20.f; // Max time a teleport is allowed to take before we raise the curtain
 -const F32 TELEPORT_ARRIVAL_DELAY = 2.f; // Time to preload the world before raising the curtain after we've actually already arrived.
 -const F32 TELEPORT_LOCAL_DELAY = 1.0f;  // Delay to prevent teleports after starting an in-sim teleport.
 -BOOL		 gTeleportDisplay = FALSE;
 -LLFrameTimer gTeleportDisplayTimer;
 -LLFrameTimer gTeleportArrivalTimer;
 -const F32		RESTORE_GL_TIME = 5.f;	// Wait this long while reloading textures before we raise the curtain
 -
 -BOOL gForceRenderLandFence = FALSE;
 -BOOL gDisplaySwapBuffers = FALSE;
 -BOOL gDepthDirty = FALSE;
 -BOOL gResizeScreenTexture = FALSE;
 -BOOL gWindowResized = FALSE;
 -BOOL gSnapshot = FALSE;
 -
 -U32 gRecentFrameCount = 0; // number of 'recent' frames
 -LLFrameTimer gRecentFPSTime;
 -LLFrameTimer gRecentMemoryTime;
 -
 -// Rendering stuff
 -void pre_show_depth_buffer();
 -void post_show_depth_buffer();
 -void render_ui(F32 zoom_factor = 1.f, int subfield = 0);
 -void render_hud_attachments();
 -void render_ui_3d();
 -void render_ui_2d();
 -void render_disconnected_background();
 -
 -void display_startup()
 -{
 -	if (   !gViewerWindow->getActive()
 -		|| !gViewerWindow->getWindow()->getVisible() 
 -		|| gViewerWindow->getWindow()->getMinimized() )
 -	{
 -		return; 
 -	}
 -
 -	gPipeline.updateGL();
 -
 -	// Update images?
 -	//gImageList.updateImages(0.01f);
 -	LLTexUnit::sWhiteTexture = LLViewerFetchedTexture::sWhiteImagep->getTexName();
 -
 -	LLGLSDefault gls_default;
 -
 -	// Required for HTML update in login screen
 -	static S32 frame_count = 0;
 -
 -	LLGLState::checkStates();
 -	LLGLState::checkTextureChannels();
 -
 -	if (frame_count++ > 1) // make sure we have rendered a frame first
 -	{
 -		LLViewerDynamicTexture::updateAllInstances();
 -	}
 -
 -	LLGLState::checkStates();
 -	LLGLState::checkTextureChannels();
 -
 -	glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
 -	LLGLSUIDefault gls_ui;
 -	gPipeline.disableLights();
 -
 -	gViewerWindow->setup2DRender();
 -	gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
 -
 -	gGL.color4f(1,1,1,1);
 -	gViewerWindow->draw();
 -	gGL.flush();
 -
 -	LLVertexBuffer::unbind();
 -
 -	LLGLState::checkStates();
 -	LLGLState::checkTextureChannels();
 -
 -	gViewerWindow->getWindow()->swapBuffers();
 -	glClear(GL_DEPTH_BUFFER_BIT);
 -}
 -
 -void display_update_camera()
 -{
 -	LLMemType mt_uc(LLMemType::MTYPE_DISPLAY_UPDATE_CAMERA);
 -	// TODO: cut draw distance down if customizing avatar?
 -	// TODO: cut draw distance on per-parcel basis?
 -
 -	// Cut draw distance in half when customizing avatar,
 -	// but on the viewer only.
 -	F32 final_far = gAgentCamera.mDrawDistance;
 -	if (CAMERA_MODE_CUSTOMIZE_AVATAR == gAgentCamera.getCameraMode())
 -	{
 -		final_far *= 0.5f;
 -	}
 -	LLViewerCamera::getInstance()->setFar(final_far);
 -	gViewerWindow->setup3DRender();
 -	
 -	// update all the sky/atmospheric/water settings
 -	LLWLParamManager::getInstance()->update(LLViewerCamera::getInstance());
 -	LLWaterParamManager::getInstance()->update(LLViewerCamera::getInstance());
 -
 -	// Update land visibility too
 -	LLWorld::getInstance()->setLandFarClip(final_far);
 -}
 -
 -// Write some stats to llinfos
 -void display_stats()
 -{
 -	F32 fps_log_freq = gSavedSettings.getF32("FPSLogFrequency");
 -	if (fps_log_freq > 0.f && gRecentFPSTime.getElapsedTimeF32() >= fps_log_freq)
 -	{
 -		F32 fps = gRecentFrameCount / fps_log_freq;
 -		llinfos << llformat("FPS: %.02f", fps) << llendl;
 -		gRecentFrameCount = 0;
 -		gRecentFPSTime.reset();
 -	}
 -	F32 mem_log_freq = gSavedSettings.getF32("MemoryLogFrequency");
 -	if (mem_log_freq > 0.f && gRecentMemoryTime.getElapsedTimeF32() >= mem_log_freq)
 -	{
 -		gMemoryAllocated = LLMemory::getCurrentRSS();
 -		U32 memory = (U32)(gMemoryAllocated / (1024*1024));
 -		llinfos << llformat("MEMORY: %d MB", memory) << llendl;
 -		LLMemory::logMemoryInfo(TRUE) ;
 -		gRecentMemoryTime.reset();
 -	}
 -}
 -
 -static LLFastTimer::DeclareTimer FTM_PICK("Picking");
 -static LLFastTimer::DeclareTimer FTM_RENDER("Render", true);
 -static LLFastTimer::DeclareTimer FTM_UPDATE_SKY("Update Sky");
 -static LLFastTimer::DeclareTimer FTM_UPDATE_TEXTURES("Update Textures");
 -static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE("Update Images");
 -static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_CLASS("Class");
 -static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_BUMP("Bump");
 -static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_LIST("List");
 -static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_DELETE("Delete");
 -
 -// Paint the display!
 -void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 -{
 -	LLMemType mt_render(LLMemType::MTYPE_RENDER);
 -	LLFastTimer t(FTM_RENDER);
 -
 -	if (gWindowResized)
 -	{ //skip render on frames where window has been resized
 -		gGL.flush();
 -		glClear(GL_COLOR_BUFFER_BIT);
 -		gViewerWindow->getWindow()->swapBuffers();
 -		LLPipeline::refreshCachedSettings();
 -		gPipeline.resizeScreenTexture();
 -		gResizeScreenTexture = FALSE;
 -		gWindowResized = FALSE;
 -		return;
 -	}
 -
 -	if (LLPipeline::sRenderDeferred)
 -	{ //hack to make sky show up in deferred snapshots
 -		for_snapshot = FALSE;
 -	}
 -
 -	if (LLPipeline::sRenderFrameTest)
 -	{
 -		send_agent_pause();
 -	}
 -
 -	gSnapshot = for_snapshot;
 -
 -	LLGLSDefault gls_default;
 -	LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE, GL_LEQUAL);
 -	
 -	LLVertexBuffer::unbind();
 -
 -	LLGLState::checkStates();
 -	LLGLState::checkTextureChannels();
 -	
 -	stop_glerror();
 -
 -	gPipeline.disableLights();
 -	
 -	//reset vertex buffers if needed
 -	gPipeline.doResetVertexBuffers();
 -
 -	stop_glerror();
 -
 -	// Don't draw if the window is hidden or minimized.
 -	// In fact, must explicitly check the minimized state before drawing.
 -	// Attempting to draw into a minimized window causes a GL error. JC
 -	if (   !gViewerWindow->getActive()
 -		|| !gViewerWindow->getWindow()->getVisible() 
 -		|| gViewerWindow->getWindow()->getMinimized() )
 -	{
 -		// Clean up memory the pools may have allocated
 -		if (rebuild)
 -		{
 -			stop_glerror();
 -			gPipeline.rebuildPools();
 -			stop_glerror();
 -		}
 -
 -		stop_glerror();
 -		gViewerWindow->returnEmptyPicks();
 -		stop_glerror();
 -		return; 
 -	}
 -
 -	gViewerWindow->checkSettings();
 -	
 -	{
 -		LLFastTimer ftm(FTM_PICK);
 -		LLAppViewer::instance()->pingMainloopTimeout("Display:Pick");
 -		gViewerWindow->performPick();
 -	}
 -	
 -	LLAppViewer::instance()->pingMainloopTimeout("Display:CheckStates");
 -	LLGLState::checkStates();
 -	LLGLState::checkTextureChannels();
 -	
 -	//////////////////////////////////////////////////////////
 -	//
 -	// Logic for forcing window updates if we're in drone mode.
 -	//
 -
 -	// *TODO: Investigate running display() during gHeadlessClient.  See if this early exit is needed DK 2011-02-18
 -	if (gHeadlessClient) 
 -	{
 -#if LL_WINDOWS
 -		static F32 last_update_time = 0.f;
 -		if ((gFrameTimeSeconds - last_update_time) > 1.f)
 -		{
 -			InvalidateRect((HWND)gViewerWindow->getPlatformWindow(), NULL, FALSE);
 -			last_update_time = gFrameTimeSeconds;
 -		}
 -#elif LL_DARWIN
 -		// MBW -- Do something clever here.
 -#endif
 -		// Not actually rendering, don't bother.
 -		return;
 -	}
 -
 -
 -	//
 -	// Bail out if we're in the startup state and don't want to try to
 -	// render the world.
 -	//
 -	if (LLStartUp::getStartupState() < STATE_STARTED)
 -	{
 -		LLAppViewer::instance()->pingMainloopTimeout("Display:Startup");
 -		display_startup();
 -		return;
 -	}
 -
 -	//LLGLState::verify(FALSE);
 -
 -	/////////////////////////////////////////////////
 -	//
 -	// Update GL Texture statistics (used for discard logic?)
 -	//
 -
 -	LLAppViewer::instance()->pingMainloopTimeout("Display:TextureStats");
 -	stop_glerror();
 -
 -	LLImageGL::updateStats(gFrameTimeSeconds);
 -	
 -	LLVOAvatar::sRenderName = gSavedSettings.getS32("AvatarNameTagMode");
 -	LLVOAvatar::sRenderGroupTitles = (gSavedSettings.getBOOL("NameTagShowGroupTitles") && gSavedSettings.getS32("AvatarNameTagMode"));
 -	
 -	gPipeline.mBackfaceCull = TRUE;
 -	gFrameCount++;
 -	gRecentFrameCount++;
 -	if (gFocusMgr.getAppHasFocus())
 -	{
 -		gForegroundFrameCount++;
 -	}
 -
 -	//////////////////////////////////////////////////////////
 -	//
 -	// Display start screen if we're teleporting, and skip render
 -	//
 -
 -	if (gTeleportDisplay)
 -	{
 -		LLAppViewer::instance()->pingMainloopTimeout("Display:Teleport");
 -		const F32 TELEPORT_ARRIVAL_DELAY = 2.f; // Time to preload the world before raising the curtain after we've actually already arrived.
 -
 -		S32 attach_count = 0;
 -		if (isAgentAvatarValid())
 -		{
 -			attach_count = gAgentAvatarp->getAttachmentCount();
 -		}
 -		F32 teleport_save_time = TELEPORT_EXPIRY + TELEPORT_EXPIRY_PER_ATTACHMENT * attach_count;
 -		F32 teleport_elapsed = gTeleportDisplayTimer.getElapsedTimeF32();
 -		F32 teleport_percent = teleport_elapsed * (100.f / teleport_save_time);
 -		if( (gAgent.getTeleportState() != LLAgent::TELEPORT_START) && (teleport_percent > 100.f) )
 -		{
 -			// Give up.  Don't keep the UI locked forever.
 -			gAgent.setTeleportState( LLAgent::TELEPORT_NONE );
 -			gAgent.setTeleportMessage(std::string());
 -		}
 -
 -		const std::string& message = gAgent.getTeleportMessage();
 -		switch( gAgent.getTeleportState() )
 -		{
 -		case LLAgent::TELEPORT_START:
 -			// Transition to REQUESTED.  Viewer has sent some kind
 -			// of TeleportRequest to the source simulator
 -			gTeleportDisplayTimer.reset();
 -			gViewerWindow->setShowProgress(TRUE);
 -			gViewerWindow->setProgressPercent(0);
 -			gAgent.setTeleportState( LLAgent::TELEPORT_REQUESTED );
 -			gAgent.setTeleportMessage(
 -				LLAgent::sTeleportProgressMessages["requesting"]);
 -			break;
 -
 -		case LLAgent::TELEPORT_REQUESTED:
 -			// Waiting for source simulator to respond
 -			gViewerWindow->setProgressPercent( llmin(teleport_percent, 37.5f) );
 -			gViewerWindow->setProgressString(message);
 -			break;
 -
 -		case LLAgent::TELEPORT_MOVING:
 -			// Viewer has received destination location from source simulator
 -			gViewerWindow->setProgressPercent( llmin(teleport_percent, 75.f) );
 -			gViewerWindow->setProgressString(message);
 -			break;
 -
 -		case LLAgent::TELEPORT_START_ARRIVAL:
 -			// Transition to ARRIVING.  Viewer has received avatar update, etc., from destination simulator
 -			gTeleportArrivalTimer.reset();
 -				gViewerWindow->setProgressCancelButtonVisible(FALSE, LLTrans::getString("Cancel"));
 -			gViewerWindow->setProgressPercent(75.f);
 -			gAgent.setTeleportState( LLAgent::TELEPORT_ARRIVING );
 -			gAgent.setTeleportMessage(
 -				LLAgent::sTeleportProgressMessages["arriving"]);
 -			gTextureList.mForceResetTextureStats = TRUE;
 -			gAgentCamera.resetView(TRUE, TRUE);
 -			break;
 -
 -		case LLAgent::TELEPORT_ARRIVING:
 -			// Make the user wait while content "pre-caches"
 -			{
 -				F32 arrival_fraction = (gTeleportArrivalTimer.getElapsedTimeF32() / TELEPORT_ARRIVAL_DELAY);
 -				if( arrival_fraction > 1.f )
 -				{
 -					arrival_fraction = 1.f;
 -					//LLFirstUse::useTeleport();
 -					gAgent.setTeleportState( LLAgent::TELEPORT_NONE );
 -				}
 -				gViewerWindow->setProgressCancelButtonVisible(FALSE, LLTrans::getString("Cancel"));
 -				gViewerWindow->setProgressPercent(  arrival_fraction * 25.f + 75.f);
 -				gViewerWindow->setProgressString(message);
 -			}
 -			break;
 -
 -		case LLAgent::TELEPORT_LOCAL:
 -			// Short delay when teleporting in the same sim (progress screen active but not shown - did not
 -			// fall-through from TELEPORT_START)
 -			{
 -				if( gTeleportDisplayTimer.getElapsedTimeF32() > TELEPORT_LOCAL_DELAY )
 -				{
 -					//LLFirstUse::useTeleport();
 -					gAgent.setTeleportState( LLAgent::TELEPORT_NONE );
 -				}
 -			}
 -			break;
 -
 -		case LLAgent::TELEPORT_NONE:
 -			// No teleport in progress
 -			gViewerWindow->setShowProgress(FALSE);
 -			gTeleportDisplay = FALSE;
 -			break;
 -		}
 -	}
 -    else if(LLAppViewer::instance()->logoutRequestSent())
 -	{
 -		LLAppViewer::instance()->pingMainloopTimeout("Display:Logout");
 -		F32 percent_done = gLogoutTimer.getElapsedTimeF32() * 100.f / gLogoutMaxTime;
 -		if (percent_done > 100.f)
 -		{
 -			percent_done = 100.f;
 -		}
 -
 -		if( LLApp::isExiting() )
 -		{
 -			percent_done = 100.f;
 -		}
 -		
 -		gViewerWindow->setProgressPercent( percent_done );
 -	}
 -	else
 -	if (gRestoreGL)
 -	{
 -		LLAppViewer::instance()->pingMainloopTimeout("Display:RestoreGL");
 -		F32 percent_done = gRestoreGLTimer.getElapsedTimeF32() * 100.f / RESTORE_GL_TIME;
 -		if( percent_done > 100.f )
 -		{
 -			gViewerWindow->setShowProgress(FALSE);
 -			gRestoreGL = FALSE;
 -		}
 -		else
 -		{
 -
 -			if( LLApp::isExiting() )
 -			{
 -				percent_done = 100.f;
 -			}
 -			
 -			gViewerWindow->setProgressPercent( percent_done );
 -		}
 -	}
 -
 -	//////////////////////////
 -	//
 -	// Prepare for the next frame
 -	//
 -
 -	/////////////////////////////
 -	//
 -	// Update the camera
 -	//
 -	//
 -
 -	LLAppViewer::instance()->pingMainloopTimeout("Display:Camera");
 -	LLViewerCamera::getInstance()->setZoomParameters(zoom_factor, subfield);
 -	LLViewerCamera::getInstance()->setNear(MIN_NEAR_PLANE);
 -
 -	//////////////////////////
 -	//
 -	// clear the next buffer
 -	// (must follow dynamic texture writing since that uses the frame buffer)
 -	//
 -
 -	if (gDisconnected)
 -	{
 -		LLAppViewer::instance()->pingMainloopTimeout("Display:Disconnected");
 -		render_ui();
 -	}
 -	
 -	//////////////////////////
 -	//
 -	// Set rendering options
 -	//
 -	//
 -	LLAppViewer::instance()->pingMainloopTimeout("Display:RenderSetup");
 -	stop_glerror();
 -
 -	///////////////////////////////////////
 -	//
 -	// Slam lighting parameters back to our defaults.
 -	// Note that these are not the same as GL defaults...
 -
 -	stop_glerror();
 -	gGL.setAmbientLightColor(LLColor4::white);
 -	stop_glerror();
 -			
 -	/////////////////////////////////////
 -	//
 -	// Render
 -	//
 -	// Actually push all of our triangles to the screen.
 -	//
 -
 -	// do render-to-texture stuff here
 -	if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_DYNAMIC_TEXTURES))
 -	{
 -		LLAppViewer::instance()->pingMainloopTimeout("Display:DynamicTextures");
 -		LLFastTimer t(FTM_UPDATE_TEXTURES);
 -		if (LLViewerDynamicTexture::updateAllInstances())
 -		{
 -			gGL.setColorMask(true, true);
 -			glClear(GL_DEPTH_BUFFER_BIT);
 -		}
 -	}
 -
 -	gViewerWindow->setup3DViewport();
 -
 -	gPipeline.resetFrameStats();	// Reset per-frame statistics.
 -	
 -	if (!gDisconnected)
 -	{
 -		LLMemType mt_du(LLMemType::MTYPE_DISPLAY_UPDATE);
 -		LLAppViewer::instance()->pingMainloopTimeout("Display:Update");
 -		if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
 -		{ //don't draw hud objects in this frame
 -			gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
 -		}
 -
 -		if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES))
 -		{ //don't draw hud particles in this frame
 -			gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES);
 -		}
 -
 -		//upkeep gl name pools
 -		LLGLNamePool::upkeepPools();
 -		
 -		stop_glerror();
 -		display_update_camera();
 -		stop_glerror();
 -				
 -		// *TODO: merge these two methods
 -		{
 -			LLMemType mt_uh(LLMemType::MTYPE_DISPLAY_UPDATE_HUD);
 -			LLHUDManager::getInstance()->updateEffects();
 -			LLHUDObject::updateAll();
 -			stop_glerror();
 -		}
 -
 -		{
 -			LLMemType mt_ug(LLMemType::MTYPE_DISPLAY_UPDATE_GEOM);
 -			const F32 max_geom_update_time = 0.005f*10.f*gFrameIntervalSeconds; // 50 ms/second update time
 -			gPipeline.createObjects(max_geom_update_time);
 -			gPipeline.processPartitionQ();
 -			gPipeline.updateGeom(max_geom_update_time);
 -			stop_glerror();
 -		}
 -
 -		gPipeline.updateGL();
 -		stop_glerror();
 -
 -		S32 water_clip = 0;
 -		if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_ENVIRONMENT) > 1) &&
 -			 (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_WATER) || 
 -			  gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_VOIDWATER)))
 -		{
 -			if (LLViewerCamera::getInstance()->cameraUnderWater())
 -			{
 -				water_clip = -1;
 -			}
 -			else
 -			{
 -				water_clip = 1;
 -			}
 -		}
 -		
 -		LLAppViewer::instance()->pingMainloopTimeout("Display:Cull");
 -		
 -		//Increment drawable frame counter
 -		LLDrawable::incrementVisible();
 -
 -		LLSpatialGroup::sNoDelete = TRUE;
 -		LLTexUnit::sWhiteTexture = LLViewerFetchedTexture::sWhiteImagep->getTexName();
 -
 -		/*if (LLPipeline::sUseOcclusion && LLPipeline::sRenderDeferred)
 -		{ //force occlusion on for all render types if doing deferred render (tighter shadow frustum)
 -			LLPipeline::sUseOcclusion = 3;
 -		}*/
 -
 -		S32 occlusion = LLPipeline::sUseOcclusion;
 -		if (gDepthDirty)
 -		{ //depth buffer is invalid, don't overwrite occlusion state
 -			LLPipeline::sUseOcclusion = llmin(occlusion, 1);
 -		}
 -		gDepthDirty = FALSE;
 -
 -		LLGLState::checkStates();
 -		LLGLState::checkTextureChannels();
 -		LLGLState::checkClientArrays();
 -
 -		static LLCullResult result;
 -		LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
 -		gPipeline.updateCull(*LLViewerCamera::getInstance(), result, water_clip);
 -		stop_glerror();
 -
 -		LLGLState::checkStates();
 -		LLGLState::checkTextureChannels();
 -		LLGLState::checkClientArrays();
 -
 -		BOOL to_texture = gPipeline.canUseVertexShaders() &&
 -						LLPipeline::sRenderGlow;
 -
 -		LLAppViewer::instance()->pingMainloopTimeout("Display:Swap");
 -		
 -		{ 
 -			LLMemType mt_ds(LLMemType::MTYPE_DISPLAY_SWAP);
 -
 -			if (gResizeScreenTexture)
 -			{
 -				gResizeScreenTexture = FALSE;
 -				gPipeline.resizeScreenTexture();
 -			}
 -
 -			gGL.setColorMask(true, true);
 -			glClearColor(0,0,0,0);
 -
 -			LLGLState::checkStates();
 -			LLGLState::checkTextureChannels();
 -			LLGLState::checkClientArrays();
 -
 -			if (!for_snapshot)
 -			{
 -				if (gFrameCount > 1)
 -				{ 
 -					//for some reason, ATI 4800 series will error out if you 
 -				    //try to generate a shadow before the first frame is through
 -					gPipeline.generateSunShadow(*LLViewerCamera::getInstance());
 -				}
 -
 -				LLVertexBuffer::unbind();
 -
 -				LLGLState::checkStates();
 -				LLGLState::checkTextureChannels();
 -				LLGLState::checkClientArrays();
 -
 -				glh::matrix4f proj = glh_get_current_projection();
 -				glh::matrix4f mod = glh_get_current_modelview();
 -				glViewport(0,0,512,512);
 -				LLVOAvatar::updateFreezeCounter() ;
 -
 -				if(!LLPipeline::sMemAllocationThrottled)
 -				{		
 -					LLVOAvatar::updateImpostors();
 -				}
 -
 -				glh_set_current_projection(proj);
 -				glh_set_current_modelview(mod);
 -				gGL.matrixMode(LLRender::MM_PROJECTION);
 -				gGL.loadMatrix(proj.m);
 -				gGL.matrixMode(LLRender::MM_MODELVIEW);
 -				gGL.loadMatrix(mod.m);
 -				gViewerWindow->setup3DViewport();
 -
 -				LLGLState::checkStates();
 -				LLGLState::checkTextureChannels();
 -				LLGLState::checkClientArrays();
 -
 -			}
 -			glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
 -		}
 -
 -		LLGLState::checkStates();
 -		LLGLState::checkClientArrays();
 -
 -		//if (!for_snapshot)
 -		{
 -			LLMemType mt_gw(LLMemType::MTYPE_DISPLAY_GEN_REFLECTION);
 -			LLAppViewer::instance()->pingMainloopTimeout("Display:Imagery");
 -			gPipeline.generateWaterReflection(*LLViewerCamera::getInstance());
 -			gPipeline.generateHighlight(*LLViewerCamera::getInstance());
 -			gPipeline.renderPhysicsDisplay();				
 -		}
 -
 -		LLGLState::checkStates();
 -		LLGLState::checkClientArrays();
 -
 -		//////////////////////////////////////
 -		//
 -		// Update images, using the image stats generated during object update/culling
 -		//
 -		// Can put objects onto the retextured list.
 -		//
 -		// Doing this here gives hardware occlusion queries extra time to complete
 -		LLAppViewer::instance()->pingMainloopTimeout("Display:UpdateImages");
 -		
 -		{
 -			LLMemType mt_iu(LLMemType::MTYPE_DISPLAY_IMAGE_UPDATE);
 -			LLFastTimer t(FTM_IMAGE_UPDATE);
 -			
 -			{
 -				LLFastTimer t(FTM_IMAGE_UPDATE_CLASS);
 -				LLViewerTexture::updateClass(LLViewerCamera::getInstance()->getVelocityStat()->getMean(),
 -											LLViewerCamera::getInstance()->getAngularVelocityStat()->getMean());
 -			}
 -
 -			
 -			{
 -				LLFastTimer t(FTM_IMAGE_UPDATE_BUMP);
 -				gBumpImageList.updateImages();  // must be called before gTextureList version so that it's textures are thrown out first.
 -			}
 -
 -			{
 -				LLFastTimer t(FTM_IMAGE_UPDATE_LIST);
 -				F32 max_image_decode_time = 0.050f*gFrameIntervalSeconds; // 50 ms/second decode time
 -				max_image_decode_time = llclamp(max_image_decode_time, 0.002f, 0.005f ); // min 2ms/frame, max 5ms/frame)
 -				gTextureList.updateImages(max_image_decode_time);
 -			}
 -
 -			{
 -				LLFastTimer t(FTM_IMAGE_UPDATE_DELETE);
 -				//remove dead textures from GL
 -				LLImageGL::deleteDeadTextures();
 -				stop_glerror();
 -			}
 -		}
 -
 -		LLGLState::checkStates();
 -		LLGLState::checkClientArrays();
 -
 -		///////////////////////////////////
 -		//
 -		// StateSort
 -		//
 -		// Responsible for taking visible objects, and adding them to the appropriate draw orders.
 -		// In the case of alpha objects, z-sorts them first.
 -		// Also creates special lists for outlines and selected face rendering.
 -		//
 -		LLAppViewer::instance()->pingMainloopTimeout("Display:StateSort");
 -		{
 -			LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
 -			LLMemType mt_ss(LLMemType::MTYPE_DISPLAY_STATE_SORT);
 -			gPipeline.stateSort(*LLViewerCamera::getInstance(), result);
 -			stop_glerror();
 -				
 -			if (rebuild)
 -			{
 -				//////////////////////////////////////
 -				//
 -				// rebuildPools
 -				//
 -				//
 -				gPipeline.rebuildPools();
 -				stop_glerror();
 -			}
 -		}
 -
 -		LLGLState::checkStates();
 -		LLGLState::checkClientArrays();
 -
 -		LLPipeline::sUseOcclusion = occlusion;
 -
 -		{
 -			LLMemType mt_ds(LLMemType::MTYPE_DISPLAY_SKY);
 -			LLAppViewer::instance()->pingMainloopTimeout("Display:Sky");
 -			LLFastTimer t(FTM_UPDATE_SKY);	
 -			gSky.updateSky();
 -		}
 -
 -		if(gUseWireframe)
 -		{
 -			glClearColor(0.5f, 0.5f, 0.5f, 0.f);
 -			glClear(GL_COLOR_BUFFER_BIT);
 -			glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 -		}
 -
 -		LLAppViewer::instance()->pingMainloopTimeout("Display:RenderStart");
 -		
 -		//// render frontmost floater opaque for occlusion culling purposes
 -		//LLFloater* frontmost_floaterp = gFloaterView->getFrontmost();
 -		//// assumes frontmost floater with focus is opaque
 -		//if (frontmost_floaterp && gFocusMgr.childHasKeyboardFocus(frontmost_floaterp))
 -		//{
 -		//	gGL.matrixMode(LLRender::MM_MODELVIEW);
 -		//	gGL.pushMatrix();
 -		//	{
 -		//		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 -
 -		//		glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
 -		//		gGL.loadIdentity();
 -
 -		//		LLRect floater_rect = frontmost_floaterp->calcScreenRect();
 -		//		// deflate by one pixel so rounding errors don't occlude outside of floater extents
 -		//		floater_rect.stretch(-1);
 -		//		LLRectf floater_3d_rect((F32)floater_rect.mLeft / (F32)gViewerWindow->getWindowWidthScaled(), 
 -		//								(F32)floater_rect.mTop / (F32)gViewerWindow->getWindowHeightScaled(),
 -		//								(F32)floater_rect.mRight / (F32)gViewerWindow->getWindowWidthScaled(),
 -		//								(F32)floater_rect.mBottom / (F32)gViewerWindow->getWindowHeightScaled());
 -		//		floater_3d_rect.translate(-0.5f, -0.5f);
 -		//		gGL.translatef(0.f, 0.f, -LLViewerCamera::getInstance()->getNear());
 -		//		gGL.scalef(LLViewerCamera::getInstance()->getNear() * LLViewerCamera::getInstance()->getAspect() / sinf(LLViewerCamera::getInstance()->getView()), LLViewerCamera::getInstance()->getNear() / sinf(LLViewerCamera::getInstance()->getView()), 1.f);
 -		//		gGL.color4fv(LLColor4::white.mV);
 -		//		gGL.begin(LLVertexBuffer::QUADS);
 -		//		{
 -		//			gGL.vertex3f(floater_3d_rect.mLeft, floater_3d_rect.mBottom, 0.f);
 -		//			gGL.vertex3f(floater_3d_rect.mLeft, floater_3d_rect.mTop, 0.f);
 -		//			gGL.vertex3f(floater_3d_rect.mRight, floater_3d_rect.mTop, 0.f);
 -		//			gGL.vertex3f(floater_3d_rect.mRight, floater_3d_rect.mBottom, 0.f);
 -		//		}
 -		//		gGL.end();
 -		//		glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
 -		//	}
 -		//	gGL.popMatrix();
 -		//}
 -
 -		LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater() ? TRUE : FALSE;
 -		
 -		LLGLState::checkStates();
 -		LLGLState::checkClientArrays();
 -
 -		stop_glerror();
 -
 -		
 -		if (to_texture)
 -		{
 -			gGL.setColorMask(true, true);
 -					
 -			if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
 -			{
 -				gPipeline.mDeferredScreen.bindTarget();
 -				glClearColor(1,0,1,1);
 -				gPipeline.mDeferredScreen.clear();
 -			}
 -			else
 -			{
 -				gPipeline.mScreen.bindTarget();
 -				if (LLPipeline::sUnderWaterRender && !gPipeline.canUseWindLightShaders())
 -				{
 -					const LLColor4 &col = LLDrawPoolWater::sWaterFogColor;
 -					glClearColor(col.mV[0], col.mV[1], col.mV[2], 0.f);
 -				}
 -				gPipeline.mScreen.clear();
 -			}
 -			
 -			gGL.setColorMask(true, false);
 -		}
 -		
 -			if (!(LLAppViewer::instance()->logoutRequestSent() && LLAppViewer::instance()->hasSavedFinalSnapshot())
 -				&& !gRestoreGL)
 -		{
 -			LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
 -			LLMemType mt_rg(LLMemType::MTYPE_DISPLAY_RENDER_GEOM);
 -			gGL.setColorMask(true, false);
 -		
 -
 -			if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
 -			{
 -				gPipeline.renderGeomDeferred(*LLViewerCamera::getInstance());
 -			}
 -			else
 -			{
 -				gPipeline.renderGeom(*LLViewerCamera::getInstance(), TRUE);
 -			}
 -			
 -			gGL.setColorMask(true, true);
 -
 -			//store this frame's modelview matrix for use
 -			//when rendering next frame's occlusion queries
 -			for (U32 i = 0; i < 16; i++)
 -			{
 -				gGLLastModelView[i] = gGLModelView[i];
 -				gGLLastProjection[i] = gGLProjection[i];
 -			}
 -			stop_glerror();
 -		}
 -
 -		for (U32 i = 0; i < gGLManager.mNumTextureImageUnits; i++)
 -		{ //dummy cleanup of any currently bound textures
 -			if (gGL.getTexUnit(i)->getCurrType() != LLTexUnit::TT_NONE)
 -			{
 -				gGL.getTexUnit(i)->unbind(gGL.getTexUnit(i)->getCurrType());
 -				gGL.getTexUnit(i)->disable();
 -			}
 -		}
 -		LLAppViewer::instance()->pingMainloopTimeout("Display:RenderFlush");		
 -		
 -		if (to_texture)
 -		{
 -			LLMemType mt_rf(LLMemType::MTYPE_DISPLAY_RENDER_FLUSH);
 -			if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
 -			{
 -				gPipeline.mDeferredScreen.flush();
 -				if(LLRenderTarget::sUseFBO)
 -				{
 -					LLRenderTarget::copyContentsToFramebuffer(gPipeline.mDeferredScreen, 0, 0, gPipeline.mDeferredScreen.getWidth(), 
 -															  gPipeline.mDeferredScreen.getHeight(), 0, 0, 
 -															  gPipeline.mDeferredScreen.getWidth(), 
 -															  gPipeline.mDeferredScreen.getHeight(), 
 -															  GL_DEPTH_BUFFER_BIT, GL_NEAREST);
 -				}
 -			}
 -			else
 -			{
 -				gPipeline.mScreen.flush();
 -				if(LLRenderTarget::sUseFBO)
 -				{				
 -					LLRenderTarget::copyContentsToFramebuffer(gPipeline.mScreen, 0, 0, gPipeline.mScreen.getWidth(), 
 -															  gPipeline.mScreen.getHeight(), 0, 0, 
 -															  gPipeline.mScreen.getWidth(), 
 -															  gPipeline.mScreen.getHeight(), 
 -															  GL_DEPTH_BUFFER_BIT, GL_NEAREST);
 -				}
 -			}
 -		}
 -
 -
 -		if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender )
 -		{
 -			gPipeline.renderDeferredLighting();
 -		}
 -
 -		LLPipeline::sUnderWaterRender = FALSE;
 -
 -		LLAppViewer::instance()->pingMainloopTimeout("Display:RenderUI");
 -		if (!for_snapshot)
 -		{
 -			LLFastTimer t(FTM_RENDER_UI);
 -			render_ui();
 -		}
 -
 -		
 -		LLSpatialGroup::sNoDelete = FALSE;
 -		gPipeline.clearReferences();
 -
 -		gPipeline.rebuildGroups();
 -	}
 -
 -	LLAppViewer::instance()->pingMainloopTimeout("Display:FrameStats");
 -	
 -	stop_glerror();
 -
 -	if (LLPipeline::sRenderFrameTest)
 -	{
 -		send_agent_resume();
 -		LLPipeline::sRenderFrameTest = FALSE;
 -	}
 -
 -	display_stats();
 -				
 -	LLAppViewer::instance()->pingMainloopTimeout("Display:Done");
 -}
 -
 -void render_hud_attachments()
 -{
 -	LLMemType mt_ra(LLMemType::MTYPE_DISPLAY_RENDER_ATTACHMENTS);
 -	gGL.matrixMode(LLRender::MM_PROJECTION);
 -	gGL.pushMatrix();
 -	gGL.matrixMode(LLRender::MM_MODELVIEW);
 -	gGL.pushMatrix();
 -		
 -	glh::matrix4f current_proj = glh_get_current_projection();
 -	glh::matrix4f current_mod = glh_get_current_modelview();
 -
 -	// clamp target zoom level to reasonable values
 -	gAgentCamera.mHUDTargetZoom = llclamp(gAgentCamera.mHUDTargetZoom, 0.1f, 1.f);
 -	// smoothly interpolate current zoom level
 -	gAgentCamera.mHUDCurZoom = lerp(gAgentCamera.mHUDCurZoom, gAgentCamera.mHUDTargetZoom, LLCriticalDamp::getInterpolant(0.03f));
 -
 -	if (LLPipeline::sShowHUDAttachments && !gDisconnected && setup_hud_matrices())
 -	{
 -		LLCamera hud_cam = *LLViewerCamera::getInstance();
 -		LLVector3 origin = hud_cam.getOrigin();
 -		hud_cam.setOrigin(-1.f,0,0);
 -		hud_cam.setAxes(LLVector3(1,0,0), LLVector3(0,1,0), LLVector3(0,0,1));
 -		LLViewerCamera::updateFrustumPlanes(hud_cam, TRUE);
 -
 -		bool render_particles = gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES) && gSavedSettings.getBOOL("RenderHUDParticles");
 -		
 -		//only render hud objects
 -		gPipeline.pushRenderTypeMask();
 -		
 -		// turn off everything
 -		gPipeline.andRenderTypeMask(LLPipeline::END_RENDER_TYPES);
 -		// turn on HUD
 -		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
 -		// turn on HUD particles
 -		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES);
 -
 -		// if particles are off, turn off hud-particles as well
 -		if (!render_particles)
 -		{
 -			// turn back off HUD particles
 -			gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES);
 -		}
 -
 -		bool has_ui = gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI);
 -		if (has_ui)
 -		{
 -			gPipeline.toggleRenderDebugFeature((void*) LLPipeline::RENDER_DEBUG_FEATURE_UI);
 -		}
 -
 -		S32 use_occlusion = LLPipeline::sUseOcclusion;
 -		LLPipeline::sUseOcclusion = 0;
 -				
 -		//cull, sort, and render hud objects
 -		static LLCullResult result;
 -		LLSpatialGroup::sNoDelete = TRUE;
 -
 -		LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
 -		gPipeline.updateCull(hud_cam, result);
 -
 -		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_BUMP);
 -		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_SIMPLE);
 -		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_VOLUME);
 -		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_ALPHA);
 -		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_FULLBRIGHT);
 -		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA);
 -		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK);
 -		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_BUMP);
 -		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT);
 -		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK);
 -		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY);
 -		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_SHINY);
 -		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_INVISIBLE);
 -		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY);
 -		
 -		gPipeline.stateSort(hud_cam, result);
 -
 -		gPipeline.renderGeom(hud_cam);
 -
 -		LLSpatialGroup::sNoDelete = FALSE;
 -		//gPipeline.clearReferences();
 -
 -		render_hud_elements();
 -
 -		//restore type mask
 -		gPipeline.popRenderTypeMask();
 -
 -		if (has_ui)
 -		{
 -			gPipeline.toggleRenderDebugFeature((void*) LLPipeline::RENDER_DEBUG_FEATURE_UI);
 -		}
 -		LLPipeline::sUseOcclusion = use_occlusion;
 -	}
 -	gGL.matrixMode(LLRender::MM_PROJECTION);
 -	gGL.popMatrix();
 -	gGL.matrixMode(LLRender::MM_MODELVIEW);
 -	gGL.popMatrix();
 -	
 -	glh_set_current_projection(current_proj);
 -	glh_set_current_modelview(current_mod);
 -}
 -
 -LLRect get_whole_screen_region()
 -{
 -	LLRect whole_screen = gViewerWindow->getWorldViewRectScaled();
 -	
 -	// apply camera zoom transform (for high res screenshots)
 -	F32 zoom_factor = LLViewerCamera::getInstance()->getZoomFactor();
 -	S16 sub_region = LLViewerCamera::getInstance()->getZoomSubRegion();
 -	if (zoom_factor > 1.f)
 -	{
 -		S32 num_horizontal_tiles = llceil(zoom_factor);
 -		S32 tile_width = llround((F32)gViewerWindow->getWorldViewWidthScaled() / zoom_factor);
 -		S32 tile_height = llround((F32)gViewerWindow->getWorldViewHeightScaled() / zoom_factor);
 -		int tile_y = sub_region / num_horizontal_tiles;
 -		int tile_x = sub_region - (tile_y * num_horizontal_tiles);
 -			
 -		whole_screen.setLeftTopAndSize(tile_x * tile_width, gViewerWindow->getWorldViewHeightScaled() - (tile_y * tile_height), tile_width, tile_height);
 -	}
 -	return whole_screen;
 -}
 -
 -bool get_hud_matrices(const LLRect& screen_region, glh::matrix4f &proj, glh::matrix4f &model)
 -{
 -	if (isAgentAvatarValid() && gAgentAvatarp->hasHUDAttachment())
 -	{
 -		F32 zoom_level = gAgentCamera.mHUDCurZoom;
 -		LLBBox hud_bbox = gAgentAvatarp->getHUDBBox();
 -		
 -		F32 hud_depth = llmax(1.f, hud_bbox.getExtentLocal().mV[VX] * 1.1f);
 -		proj = gl_ortho(-0.5f * LLViewerCamera::getInstance()->getAspect(), 0.5f * LLViewerCamera::getInstance()->getAspect(), -0.5f, 0.5f, 0.f, hud_depth);
 -		proj.element(2,2) = -0.01f;
 -		
 -		F32 aspect_ratio = LLViewerCamera::getInstance()->getAspect();
 -		
 -		glh::matrix4f mat;
 -		F32 scale_x = (F32)gViewerWindow->getWorldViewWidthScaled() / (F32)screen_region.getWidth();
 -		F32 scale_y = (F32)gViewerWindow->getWorldViewHeightScaled() / (F32)screen_region.getHeight();
 -		mat.set_scale(glh::vec3f(scale_x, scale_y, 1.f));
 -		mat.set_translate(
 -			glh::vec3f(clamp_rescale((F32)(screen_region.getCenterX() - screen_region.mLeft), 0.f, (F32)gViewerWindow->getWorldViewWidthScaled(), 0.5f * scale_x * aspect_ratio, -0.5f * scale_x * aspect_ratio),
 -					   clamp_rescale((F32)(screen_region.getCenterY() - screen_region.mBottom), 0.f, (F32)gViewerWindow->getWorldViewHeightScaled(), 0.5f * scale_y, -0.5f * scale_y),
 -					   0.f));
 -		proj *= mat;
 -		
 -		glh::matrix4f tmp_model((GLfloat*) OGL_TO_CFR_ROTATION);
 -		
 -		mat.set_scale(glh::vec3f(zoom_level, zoom_level, zoom_level));
 -		mat.set_translate(glh::vec3f(-hud_bbox.getCenterLocal().mV[VX] + (hud_depth * 0.5f), 0.f, 0.f));
 -		
 -		tmp_model *= mat;
 -		model = tmp_model;		
 -		return TRUE;
 -	}
 -	else
 -	{
 -		return FALSE;
 -	}
 -}
 -
 -bool get_hud_matrices(glh::matrix4f &proj, glh::matrix4f &model)
 -{
 -	LLRect whole_screen = get_whole_screen_region();
 -	return get_hud_matrices(whole_screen, proj, model);
 -}
 -
 -BOOL setup_hud_matrices()
 -{
 -	LLRect whole_screen = get_whole_screen_region();
 -	return setup_hud_matrices(whole_screen);
 -}
 -
 -BOOL setup_hud_matrices(const LLRect& screen_region)
 -{
 -	glh::matrix4f proj, model;
 -	bool result = get_hud_matrices(screen_region, proj, model);
 -	if (!result) return result;
 -	
 -	// set up transform to keep HUD objects in front of camera
 -	gGL.matrixMode(LLRender::MM_PROJECTION);
 -	gGL.loadMatrix(proj.m);
 -	glh_set_current_projection(proj);
 -	
 -	gGL.matrixMode(LLRender::MM_MODELVIEW);
 -	gGL.loadMatrix(model.m);
 -	glh_set_current_modelview(model);
 -	return TRUE;
 -}
 -
 -static LLFastTimer::DeclareTimer FTM_SWAP("Swap");
 -
 -void render_ui(F32 zoom_factor, int subfield)
 -{
 -	LLMemType mt_ru(LLMemType::MTYPE_DISPLAY_RENDER_UI);
 -	LLGLState::checkStates();
 -	
 -	glh::matrix4f saved_view = glh_get_current_modelview();
 -
 -	if (!gSnapshot)
 -	{
 -		gGL.pushMatrix();
 -		gGL.loadMatrix(gGLLastModelView);
 -		glh_set_current_modelview(glh_copy_matrix(gGLLastModelView));
 -	}
 -	
 -	{
 -		BOOL to_texture = gPipeline.canUseVertexShaders() &&
 -							LLPipeline::sRenderGlow;
 -
 -		if (to_texture)
 -		{
 -			gPipeline.renderBloom(gSnapshot, zoom_factor, subfield);
 -		}
 -		
 -		render_hud_elements();
 -		render_hud_attachments();
 -	}
 -
 -	LLGLSDefault gls_default;
 -	LLGLSUIDefault gls_ui;
 -	{
 -		gPipeline.disableLights();
 -	}
 -
 -	{
 -		gGL.color4f(1,1,1,1);
 -		if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
 -		{
 -			LLFastTimer t(FTM_RENDER_UI);
 -
 -			if (!gDisconnected)
 -			{
 -				render_ui_3d();
 -				LLGLState::checkStates();
 -			}
 -			else
 -			{
 -				render_disconnected_background();
 -			}
 -			render_ui_2d();
 -			LLGLState::checkStates();
 -		}
 -		gGL.flush();
 -
 -		{
 -			gViewerWindow->setup2DRender();
 -			gViewerWindow->updateDebugText();
 -			gViewerWindow->drawDebugText();
 -		}
 -
 -		LLVertexBuffer::unbind();
 -	}
 -
 -	if (!gSnapshot)
 -	{
 -		glh_set_current_modelview(saved_view);
 -		gGL.popMatrix();
 -	}
 -
 -	if (gDisplaySwapBuffers)
 -	{
 -		LLFastTimer t(FTM_SWAP);
 -		gViewerWindow->getWindow()->swapBuffers();
 -	}
 -	gDisplaySwapBuffers = TRUE;
 -}
 -
 -void renderCoordinateAxes()
 -{
 -	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 -	gGL.begin(LLRender::LINES);
 -		gGL.color3f(1.0f, 0.0f, 0.0f);   // i direction = X-Axis = red
 -		gGL.vertex3f(0.0f, 0.0f, 0.0f);
 -		gGL.vertex3f(2.0f, 0.0f, 0.0f);
 -		gGL.vertex3f(3.0f, 0.0f, 0.0f);
 -		gGL.vertex3f(5.0f, 0.0f, 0.0f);
 -		gGL.vertex3f(6.0f, 0.0f, 0.0f);
 -		gGL.vertex3f(8.0f, 0.0f, 0.0f);
 -		// Make an X
 -		gGL.vertex3f(11.0f, 1.0f, 1.0f);
 -		gGL.vertex3f(11.0f, -1.0f, -1.0f);
 -		gGL.vertex3f(11.0f, 1.0f, -1.0f);
 -		gGL.vertex3f(11.0f, -1.0f, 1.0f);
 -
 -		gGL.color3f(0.0f, 1.0f, 0.0f);   // j direction = Y-Axis = green
 -		gGL.vertex3f(0.0f, 0.0f, 0.0f);
 -		gGL.vertex3f(0.0f, 2.0f, 0.0f);
 -		gGL.vertex3f(0.0f, 3.0f, 0.0f);
 -		gGL.vertex3f(0.0f, 5.0f, 0.0f);
 -		gGL.vertex3f(0.0f, 6.0f, 0.0f);
 -		gGL.vertex3f(0.0f, 8.0f, 0.0f);
 -		// Make a Y
 -		gGL.vertex3f(1.0f, 11.0f, 1.0f);
 -		gGL.vertex3f(0.0f, 11.0f, 0.0f);
 -		gGL.vertex3f(-1.0f, 11.0f, 1.0f);
 -		gGL.vertex3f(0.0f, 11.0f, 0.0f);
 -		gGL.vertex3f(0.0f, 11.0f, 0.0f);
 -		gGL.vertex3f(0.0f, 11.0f, -1.0f);
 -
 -		gGL.color3f(0.0f, 0.0f, 1.0f);   // Z-Axis = blue
 -		gGL.vertex3f(0.0f, 0.0f, 0.0f);
 -		gGL.vertex3f(0.0f, 0.0f, 2.0f);
 -		gGL.vertex3f(0.0f, 0.0f, 3.0f);
 -		gGL.vertex3f(0.0f, 0.0f, 5.0f);
 -		gGL.vertex3f(0.0f, 0.0f, 6.0f);
 -		gGL.vertex3f(0.0f, 0.0f, 8.0f);
 -		// Make a Z
 -		gGL.vertex3f(-1.0f, 1.0f, 11.0f);
 -		gGL.vertex3f(1.0f, 1.0f, 11.0f);
 -		gGL.vertex3f(1.0f, 1.0f, 11.0f);
 -		gGL.vertex3f(-1.0f, -1.0f, 11.0f);
 -		gGL.vertex3f(-1.0f, -1.0f, 11.0f);
 -		gGL.vertex3f(1.0f, -1.0f, 11.0f);
 -	gGL.end();
 -}
 -
 -
 -void draw_axes() 
 -{
 -	LLGLSUIDefault gls_ui;
 -	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 -	// A vertical white line at origin
 -	LLVector3 v = gAgent.getPositionAgent();
 -	gGL.begin(LLRender::LINES);
 -		gGL.color3f(1.0f, 1.0f, 1.0f); 
 -		gGL.vertex3f(0.0f, 0.0f, 0.0f);
 -		gGL.vertex3f(0.0f, 0.0f, 40.0f);
 -	gGL.end();
 -	// Some coordinate axes
 -	gGL.pushMatrix();
 -		gGL.translatef( v.mV[VX], v.mV[VY], v.mV[VZ] );
 -		renderCoordinateAxes();
 -	gGL.popMatrix();
 -}
 -
 -void render_ui_3d()
 -{
 -	LLGLSPipeline gls_pipeline;
 -
 -	//////////////////////////////////////
 -	//
 -	// Render 3D UI elements
 -	// NOTE: zbuffer is cleared before we get here by LLDrawPoolHUD,
 -	//		 so 3d elements requiring Z buffer are moved to LLDrawPoolHUD
 -	//
 -
 -	/////////////////////////////////////////////////////////////
 -	//
 -	// Render 2.5D elements (2D elements in the world)
 -	// Stuff without z writes
 -	//
 -
 -	// Debugging stuff goes before the UI.
 -
 -	stop_glerror();
 -	
 -	if (LLGLSLShader::sNoFixedFunction)
 -	{
 -		gUIProgram.bind();
 -	}
 -
 -	// Coordinate axes
 -	if (gSavedSettings.getBOOL("ShowAxes"))
 -	{
 -		draw_axes();
 -	}
 -
 -	gViewerWindow->renderSelections(FALSE, FALSE, TRUE); // Non HUD call in render_hud_elements
 -	stop_glerror();
 -}
 -
 -void render_ui_2d()
 -{
 -	LLGLSUIDefault gls_ui;
 -
 -	/////////////////////////////////////////////////////////////
 -	//
 -	// Render 2D UI elements that overlay the world (no z compare)
 -
 -	//  Disable wireframe mode below here, as this is HUD/menus
 -	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 -
 -	//  Menu overlays, HUD, etc
 -	gViewerWindow->setup2DRender();
 -
 -	F32 zoom_factor = LLViewerCamera::getInstance()->getZoomFactor();
 -	S16 sub_region = LLViewerCamera::getInstance()->getZoomSubRegion();
 -
 -	if (zoom_factor > 1.f)
 -	{
 -		//decompose subregion number to x and y values
 -		int pos_y = sub_region / llceil(zoom_factor);
 -		int pos_x = sub_region - (pos_y*llceil(zoom_factor));
 -		// offset for this tile
 -		LLFontGL::sCurOrigin.mX -= llround((F32)gViewerWindow->getWindowWidthScaled() * (F32)pos_x / zoom_factor);
 -		LLFontGL::sCurOrigin.mY -= llround((F32)gViewerWindow->getWindowHeightScaled() * (F32)pos_y / zoom_factor);
 -	}
 -
 -	stop_glerror();
 -	//gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
 -
 -	// render outline for HUD
 -	if (isAgentAvatarValid() && gAgentCamera.mHUDCurZoom < 0.98f)
 -	{
 -		gGL.pushMatrix();
 -		S32 half_width = (gViewerWindow->getWorldViewWidthScaled() / 2);
 -		S32 half_height = (gViewerWindow->getWorldViewHeightScaled() / 2);
 -		gGL.scalef(LLUI::sGLScaleFactor.mV[0], LLUI::sGLScaleFactor.mV[1], 1.f);
 -		gGL.translatef((F32)half_width, (F32)half_height, 0.f);
 -		F32 zoom = gAgentCamera.mHUDCurZoom;
 -		gGL.scalef(zoom,zoom,1.f);
 -		gGL.color4fv(LLColor4::white.mV);
 -		gl_rect_2d(-half_width, half_height, half_width, -half_height, FALSE);
 -		gGL.popMatrix();
 -		stop_glerror();
 -	}
 -	
 -
 -	if (gSavedSettings.getBOOL("RenderUIBuffer"))
 -	{
 -		if (LLUI::sDirty)
 -		{
 -			LLUI::sDirty = FALSE;
 -			LLRect t_rect;
 -
 -			gPipeline.mUIScreen.bindTarget();
 -			gGL.setColorMask(true, true);
 -			{
 -				static const S32 pad = 8;
 -
 -				LLUI::sDirtyRect.mLeft -= pad;
 -				LLUI::sDirtyRect.mRight += pad;
 -				LLUI::sDirtyRect.mBottom -= pad;
 -				LLUI::sDirtyRect.mTop += pad;
 -
 -				LLGLEnable scissor(GL_SCISSOR_TEST);
 -				static LLRect last_rect = LLUI::sDirtyRect;
 -
 -				//union with last rect to avoid mouse poop
 -				last_rect.unionWith(LLUI::sDirtyRect);
 -								
 -				t_rect = LLUI::sDirtyRect;
 -				LLUI::sDirtyRect = last_rect;
 -				last_rect = t_rect;
 -			
 -				last_rect.mLeft = LLRect::tCoordType(last_rect.mLeft / LLUI::sGLScaleFactor.mV[0]);
 -				last_rect.mRight = LLRect::tCoordType(last_rect.mRight / LLUI::sGLScaleFactor.mV[0]);
 -				last_rect.mTop = LLRect::tCoordType(last_rect.mTop / LLUI::sGLScaleFactor.mV[1]);
 -				last_rect.mBottom = LLRect::tCoordType(last_rect.mBottom / LLUI::sGLScaleFactor.mV[1]);
 -
 -				LLRect clip_rect(last_rect);
 -				
 -				glClear(GL_COLOR_BUFFER_BIT);
 -
 -				gViewerWindow->draw();
 -			}
 -
 -			gPipeline.mUIScreen.flush();
 -			gGL.setColorMask(true, false);
 -
 -			LLUI::sDirtyRect = t_rect;
 -		}
 -
 -		LLGLDisable cull(GL_CULL_FACE);
 -		LLGLDisable blend(GL_BLEND);
 -		S32 width = gViewerWindow->getWindowWidthScaled();
 -		S32 height = gViewerWindow->getWindowHeightScaled();
 -		gGL.getTexUnit(0)->bind(&gPipeline.mUIScreen);
 -		gGL.begin(LLRender::TRIANGLE_STRIP);
 -		gGL.color4f(1,1,1,1);
 -		gGL.texCoord2f(0, 0);			gGL.vertex2i(0, 0);
 -		gGL.texCoord2f(width, 0);		gGL.vertex2i(width, 0);
 -		gGL.texCoord2f(0, height);		gGL.vertex2i(0, height);
 -		gGL.texCoord2f(width, height);	gGL.vertex2i(width, height);
 -		gGL.end();
 -	}
 -	else
 -	{
 -		gViewerWindow->draw();
 -	}
 -
 -
 -
 -	// reset current origin for font rendering, in case of tiling render
 -	LLFontGL::sCurOrigin.set(0, 0);
 -}
 -
 -void render_disconnected_background()
 -{
 -	if (LLGLSLShader::sNoFixedFunction)
 -	{
 -		gUIProgram.bind();
 -	}
 -
 -	gGL.color4f(1,1,1,1);
 -	if (!gDisconnectedImagep && gDisconnected)
 -	{
 -		llinfos << "Loading last bitmap..." << llendl;
 -
 -		std::string temp_str;
 -		temp_str = gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter() + SCREEN_LAST_FILENAME;
 -
 -		LLPointer<LLImageBMP> image_bmp = new LLImageBMP;
 -		if( !image_bmp->load(temp_str) )
 -		{
 -			//llinfos << "Bitmap load failed" << llendl;
 -			return;
 -		}
 -		
 -		LLPointer<LLImageRaw> raw = new LLImageRaw;
 -		if (!image_bmp->decode(raw, 0.0f))
 -		{
 -			llinfos << "Bitmap decode failed" << llendl;
 -			gDisconnectedImagep = NULL;
 -			return;
 -		}
 -
 -		U8 *rawp = raw->getData();
 -		S32 npixels = (S32)image_bmp->getWidth()*(S32)image_bmp->getHeight();
 -		for (S32 i = 0; i < npixels; i++)
 -		{
 -			S32 sum = 0;
 -			sum = *rawp + *(rawp+1) + *(rawp+2);
 -			sum /= 3;
 -			*rawp = ((S32)sum*6 + *rawp)/7;
 -			rawp++;
 -			*rawp = ((S32)sum*6 + *rawp)/7;
 -			rawp++;
 -			*rawp = ((S32)sum*6 + *rawp)/7;
 -			rawp++;
 -		}
 -
 -		
 -		raw->expandToPowerOfTwo();
 -		gDisconnectedImagep = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE );
 -		gStartTexture = gDisconnectedImagep;
 -		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 -	}
 -
 -	// Make sure the progress view always fills the entire window.
 -	S32 width = gViewerWindow->getWindowWidthScaled();
 -	S32 height = gViewerWindow->getWindowHeightScaled();
 -
 -	if (gDisconnectedImagep)
 -	{
 -		LLGLSUIDefault gls_ui;
 -		gViewerWindow->setup2DRender();
 -		gGL.pushMatrix();
 -		{
 -			// scale ui to reflect UIScaleFactor
 -			// this can't be done in setup2DRender because it requires a
 -			// pushMatrix/popMatrix pair
 -			const LLVector2& display_scale = gViewerWindow->getDisplayScale();
 -			gGL.scalef(display_scale.mV[VX], display_scale.mV[VY], 1.f);
 -
 -			gGL.getTexUnit(0)->bind(gDisconnectedImagep);
 -			gGL.color4f(1.f, 1.f, 1.f, 1.f);
 -			gl_rect_2d_simple_tex(width, height);
 -			gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 -		}
 -		gGL.popMatrix();
 -	}
 -	gGL.flush();
 -
 -	if (LLGLSLShader::sNoFixedFunction)
 -	{
 -		gUIProgram.unbind();
 -	}
 -
 -}
 -
 -void display_cleanup()
 -{
 -	gDisconnectedImagep = NULL;
 -}
 +/**  + * @file llviewerdisplay.cpp + * @brief LLViewerDisplay class implementation + * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + *  + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llviewerdisplay.h" + +#include "llgl.h" +#include "llrender.h" +#include "llglheaders.h" +#include "llagent.h" +#include "llagentcamera.h" +#include "llviewercontrol.h" +#include "llcoord.h" +#include "llcriticaldamp.h" +#include "lldir.h" +#include "lldynamictexture.h" +#include "lldrawpoolalpha.h" +#include "llfeaturemanager.h" +//#include "llfirstuse.h" +#include "llhudmanager.h" +#include "llimagebmp.h" +#include "llmemory.h" +#include "llselectmgr.h" +#include "llsky.h" +#include "llstartup.h" +#include "lltoolfocus.h" +#include "lltoolmgr.h" +#include "lltooldraganddrop.h" +#include "lltoolpie.h" +#include "lltracker.h" +#include "lltrans.h" +#include "llui.h" +#include "llviewercamera.h" +#include "llviewerobjectlist.h" +#include "llviewerparcelmgr.h" +#include "llviewerwindow.h" +#include "llvoavatarself.h" +#include "llvograss.h" +#include "llworld.h" +#include "pipeline.h" +#include "llspatialpartition.h" +#include "llappviewer.h" +#include "llstartup.h" +#include "llviewershadermgr.h" +#include "llfasttimer.h" +#include "llfloatertools.h" +#include "llviewertexturelist.h" +#include "llfocusmgr.h" +#include "llcubemap.h" +#include "llviewerregion.h" +#include "lldrawpoolwater.h" +#include "lldrawpoolbump.h" +#include "llwlparammanager.h" +#include "llwaterparammanager.h" +#include "llpostprocess.h" + +extern LLPointer<LLViewerTexture> gStartTexture; + +LLPointer<LLViewerTexture> gDisconnectedImagep = NULL; + +// used to toggle renderer back on after teleport +const F32 TELEPORT_RENDER_DELAY = 20.f; // Max time a teleport is allowed to take before we raise the curtain +const F32 TELEPORT_ARRIVAL_DELAY = 2.f; // Time to preload the world before raising the curtain after we've actually already arrived. +const F32 TELEPORT_LOCAL_DELAY = 1.0f;  // Delay to prevent teleports after starting an in-sim teleport. +BOOL		 gTeleportDisplay = FALSE; +LLFrameTimer gTeleportDisplayTimer; +LLFrameTimer gTeleportArrivalTimer; +const F32		RESTORE_GL_TIME = 5.f;	// Wait this long while reloading textures before we raise the curtain + +BOOL gForceRenderLandFence = FALSE; +BOOL gDisplaySwapBuffers = FALSE; +BOOL gDepthDirty = FALSE; +BOOL gResizeScreenTexture = FALSE; +BOOL gWindowResized = FALSE; +BOOL gSnapshot = FALSE; + +U32 gRecentFrameCount = 0; // number of 'recent' frames +LLFrameTimer gRecentFPSTime; +LLFrameTimer gRecentMemoryTime; + +// Rendering stuff +void pre_show_depth_buffer(); +void post_show_depth_buffer(); +void render_ui(F32 zoom_factor = 1.f, int subfield = 0); +void render_hud_attachments(); +void render_ui_3d(); +void render_ui_2d(); +void render_disconnected_background(); + +void display_startup() +{ +	if (   !gViewerWindow->getActive() +		|| !gViewerWindow->getWindow()->getVisible()  +		|| gViewerWindow->getWindow()->getMinimized() ) +	{ +		return;  +	} + +	gPipeline.updateGL(); + +	// Update images? +	//gImageList.updateImages(0.01f); +	LLTexUnit::sWhiteTexture = LLViewerFetchedTexture::sWhiteImagep->getTexName(); + +	LLGLSDefault gls_default; + +	// Required for HTML update in login screen +	static S32 frame_count = 0; + +	LLGLState::checkStates(); +	LLGLState::checkTextureChannels(); + +	if (frame_count++ > 1) // make sure we have rendered a frame first +	{ +		LLViewerDynamicTexture::updateAllInstances(); +	} + +	LLGLState::checkStates(); +	LLGLState::checkTextureChannels(); + +	glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); +	LLGLSUIDefault gls_ui; +	gPipeline.disableLights(); + +	gViewerWindow->setup2DRender(); +	gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); + +	gGL.color4f(1,1,1,1); +	gViewerWindow->draw(); +	gGL.flush(); + +	LLVertexBuffer::unbind(); + +	LLGLState::checkStates(); +	LLGLState::checkTextureChannels(); + +	gViewerWindow->getWindow()->swapBuffers(); +	glClear(GL_DEPTH_BUFFER_BIT); +} + +void display_update_camera() +{ +	LLMemType mt_uc(LLMemType::MTYPE_DISPLAY_UPDATE_CAMERA); +	// TODO: cut draw distance down if customizing avatar? +	// TODO: cut draw distance on per-parcel basis? + +	// Cut draw distance in half when customizing avatar, +	// but on the viewer only. +	F32 final_far = gAgentCamera.mDrawDistance; +	if (CAMERA_MODE_CUSTOMIZE_AVATAR == gAgentCamera.getCameraMode()) +	{ +		final_far *= 0.5f; +	} +	LLViewerCamera::getInstance()->setFar(final_far); +	gViewerWindow->setup3DRender(); +	 +	// update all the sky/atmospheric/water settings +	LLWLParamManager::getInstance()->update(LLViewerCamera::getInstance()); +	LLWaterParamManager::getInstance()->update(LLViewerCamera::getInstance()); + +	// Update land visibility too +	LLWorld::getInstance()->setLandFarClip(final_far); +} + +// Write some stats to llinfos +void display_stats() +{ +	F32 fps_log_freq = gSavedSettings.getF32("FPSLogFrequency"); +	if (fps_log_freq > 0.f && gRecentFPSTime.getElapsedTimeF32() >= fps_log_freq) +	{ +		F32 fps = gRecentFrameCount / fps_log_freq; +		llinfos << llformat("FPS: %.02f", fps) << llendl; +		gRecentFrameCount = 0; +		gRecentFPSTime.reset(); +	} +	F32 mem_log_freq = gSavedSettings.getF32("MemoryLogFrequency"); +	if (mem_log_freq > 0.f && gRecentMemoryTime.getElapsedTimeF32() >= mem_log_freq) +	{ +		gMemoryAllocated = LLMemory::getCurrentRSS(); +		U32 memory = (U32)(gMemoryAllocated / (1024*1024)); +		llinfos << llformat("MEMORY: %d MB", memory) << llendl; +		LLMemory::logMemoryInfo(TRUE) ; +		gRecentMemoryTime.reset(); +	} +} + +static LLFastTimer::DeclareTimer FTM_PICK("Picking"); +static LLFastTimer::DeclareTimer FTM_RENDER("Render", true); +static LLFastTimer::DeclareTimer FTM_UPDATE_SKY("Update Sky"); +static LLFastTimer::DeclareTimer FTM_UPDATE_TEXTURES("Update Textures"); +static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE("Update Images"); +static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_CLASS("Class"); +static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_BUMP("Bump"); +static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_LIST("List"); +static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_DELETE("Delete"); + +// Paint the display! +void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) +{ +	LLMemType mt_render(LLMemType::MTYPE_RENDER); +	LLFastTimer t(FTM_RENDER); + +	if (gWindowResized) +	{ //skip render on frames where window has been resized +		gGL.flush(); +		glClear(GL_COLOR_BUFFER_BIT); +		gViewerWindow->getWindow()->swapBuffers(); +		LLPipeline::refreshCachedSettings(); +		gPipeline.resizeScreenTexture(); +		gResizeScreenTexture = FALSE; +		gWindowResized = FALSE; +		return; +	} + +	if (LLPipeline::sRenderDeferred) +	{ //hack to make sky show up in deferred snapshots +		for_snapshot = FALSE; +	} + +	if (LLPipeline::sRenderFrameTest) +	{ +		send_agent_pause(); +	} + +	gSnapshot = for_snapshot; + +	LLGLSDefault gls_default; +	LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE, GL_LEQUAL); +	 +	LLVertexBuffer::unbind(); + +	LLGLState::checkStates(); +	LLGLState::checkTextureChannels(); +	 +	stop_glerror(); + +	gPipeline.disableLights(); +	 +	//reset vertex buffers if needed +	gPipeline.doResetVertexBuffers(); + +	stop_glerror(); + +	// Don't draw if the window is hidden or minimized. +	// In fact, must explicitly check the minimized state before drawing. +	// Attempting to draw into a minimized window causes a GL error. JC +	if (   !gViewerWindow->getActive() +		|| !gViewerWindow->getWindow()->getVisible()  +		|| gViewerWindow->getWindow()->getMinimized() ) +	{ +		// Clean up memory the pools may have allocated +		if (rebuild) +		{ +			stop_glerror(); +			gPipeline.rebuildPools(); +			stop_glerror(); +		} + +		stop_glerror(); +		gViewerWindow->returnEmptyPicks(); +		stop_glerror(); +		return;  +	} + +	gViewerWindow->checkSettings(); +	 +	{ +		LLFastTimer ftm(FTM_PICK); +		LLAppViewer::instance()->pingMainloopTimeout("Display:Pick"); +		gViewerWindow->performPick(); +	} +	 +	LLAppViewer::instance()->pingMainloopTimeout("Display:CheckStates"); +	LLGLState::checkStates(); +	LLGLState::checkTextureChannels(); +	 +	////////////////////////////////////////////////////////// +	// +	// Logic for forcing window updates if we're in drone mode. +	// + +	// *TODO: Investigate running display() during gHeadlessClient.  See if this early exit is needed DK 2011-02-18 +	if (gHeadlessClient)  +	{ +#if LL_WINDOWS +		static F32 last_update_time = 0.f; +		if ((gFrameTimeSeconds - last_update_time) > 1.f) +		{ +			InvalidateRect((HWND)gViewerWindow->getPlatformWindow(), NULL, FALSE); +			last_update_time = gFrameTimeSeconds; +		} +#elif LL_DARWIN +		// MBW -- Do something clever here. +#endif +		// Not actually rendering, don't bother. +		return; +	} + + +	// +	// Bail out if we're in the startup state and don't want to try to +	// render the world. +	// +	if (LLStartUp::getStartupState() < STATE_STARTED) +	{ +		LLAppViewer::instance()->pingMainloopTimeout("Display:Startup"); +		display_startup(); +		return; +	} + +	//LLGLState::verify(FALSE); + +	///////////////////////////////////////////////// +	// +	// Update GL Texture statistics (used for discard logic?) +	// + +	LLAppViewer::instance()->pingMainloopTimeout("Display:TextureStats"); +	stop_glerror(); + +	LLImageGL::updateStats(gFrameTimeSeconds); +	 +	LLVOAvatar::sRenderName = gSavedSettings.getS32("AvatarNameTagMode"); +	LLVOAvatar::sRenderGroupTitles = (gSavedSettings.getBOOL("NameTagShowGroupTitles") && gSavedSettings.getS32("AvatarNameTagMode")); +	 +	gPipeline.mBackfaceCull = TRUE; +	gFrameCount++; +	gRecentFrameCount++; +	if (gFocusMgr.getAppHasFocus()) +	{ +		gForegroundFrameCount++; +	} + +	////////////////////////////////////////////////////////// +	// +	// Display start screen if we're teleporting, and skip render +	// + +	if (gTeleportDisplay) +	{ +		LLAppViewer::instance()->pingMainloopTimeout("Display:Teleport"); +		const F32 TELEPORT_ARRIVAL_DELAY = 2.f; // Time to preload the world before raising the curtain after we've actually already arrived. + +		S32 attach_count = 0; +		if (isAgentAvatarValid()) +		{ +			attach_count = gAgentAvatarp->getAttachmentCount(); +		} +		F32 teleport_save_time = TELEPORT_EXPIRY + TELEPORT_EXPIRY_PER_ATTACHMENT * attach_count; +		F32 teleport_elapsed = gTeleportDisplayTimer.getElapsedTimeF32(); +		F32 teleport_percent = teleport_elapsed * (100.f / teleport_save_time); +		if( (gAgent.getTeleportState() != LLAgent::TELEPORT_START) && (teleport_percent > 100.f) ) +		{ +			// Give up.  Don't keep the UI locked forever. +			gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); +			gAgent.setTeleportMessage(std::string()); +		} + +		const std::string& message = gAgent.getTeleportMessage(); +		switch( gAgent.getTeleportState() ) +		{ +		case LLAgent::TELEPORT_START: +			// Transition to REQUESTED.  Viewer has sent some kind +			// of TeleportRequest to the source simulator +			gTeleportDisplayTimer.reset(); +			gViewerWindow->setShowProgress(TRUE); +			gViewerWindow->setProgressPercent(0); +			gAgent.setTeleportState( LLAgent::TELEPORT_REQUESTED ); +			gAgent.setTeleportMessage( +				LLAgent::sTeleportProgressMessages["requesting"]); +			break; + +		case LLAgent::TELEPORT_REQUESTED: +			// Waiting for source simulator to respond +			gViewerWindow->setProgressPercent( llmin(teleport_percent, 37.5f) ); +			gViewerWindow->setProgressString(message); +			break; + +		case LLAgent::TELEPORT_MOVING: +			// Viewer has received destination location from source simulator +			gViewerWindow->setProgressPercent( llmin(teleport_percent, 75.f) ); +			gViewerWindow->setProgressString(message); +			break; + +		case LLAgent::TELEPORT_START_ARRIVAL: +			// Transition to ARRIVING.  Viewer has received avatar update, etc., from destination simulator +			gTeleportArrivalTimer.reset(); +				gViewerWindow->setProgressCancelButtonVisible(FALSE, LLTrans::getString("Cancel")); +			gViewerWindow->setProgressPercent(75.f); +			gAgent.setTeleportState( LLAgent::TELEPORT_ARRIVING ); +			gAgent.setTeleportMessage( +				LLAgent::sTeleportProgressMessages["arriving"]); +			gTextureList.mForceResetTextureStats = TRUE; +			gAgentCamera.resetView(TRUE, TRUE); +			break; + +		case LLAgent::TELEPORT_ARRIVING: +			// Make the user wait while content "pre-caches" +			{ +				F32 arrival_fraction = (gTeleportArrivalTimer.getElapsedTimeF32() / TELEPORT_ARRIVAL_DELAY); +				if( arrival_fraction > 1.f ) +				{ +					arrival_fraction = 1.f; +					//LLFirstUse::useTeleport(); +					gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); +				} +				gViewerWindow->setProgressCancelButtonVisible(FALSE, LLTrans::getString("Cancel")); +				gViewerWindow->setProgressPercent(  arrival_fraction * 25.f + 75.f); +				gViewerWindow->setProgressString(message); +			} +			break; + +		case LLAgent::TELEPORT_LOCAL: +			// Short delay when teleporting in the same sim (progress screen active but not shown - did not +			// fall-through from TELEPORT_START) +			{ +				if( gTeleportDisplayTimer.getElapsedTimeF32() > TELEPORT_LOCAL_DELAY ) +				{ +					//LLFirstUse::useTeleport(); +					gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); +				} +			} +			break; + +		case LLAgent::TELEPORT_NONE: +			// No teleport in progress +			gViewerWindow->setShowProgress(FALSE); +			gTeleportDisplay = FALSE; +			break; +		} +	} +    else if(LLAppViewer::instance()->logoutRequestSent()) +	{ +		LLAppViewer::instance()->pingMainloopTimeout("Display:Logout"); +		F32 percent_done = gLogoutTimer.getElapsedTimeF32() * 100.f / gLogoutMaxTime; +		if (percent_done > 100.f) +		{ +			percent_done = 100.f; +		} + +		if( LLApp::isExiting() ) +		{ +			percent_done = 100.f; +		} +		 +		gViewerWindow->setProgressPercent( percent_done ); +	} +	else +	if (gRestoreGL) +	{ +		LLAppViewer::instance()->pingMainloopTimeout("Display:RestoreGL"); +		F32 percent_done = gRestoreGLTimer.getElapsedTimeF32() * 100.f / RESTORE_GL_TIME; +		if( percent_done > 100.f ) +		{ +			gViewerWindow->setShowProgress(FALSE); +			gRestoreGL = FALSE; +		} +		else +		{ + +			if( LLApp::isExiting() ) +			{ +				percent_done = 100.f; +			} +			 +			gViewerWindow->setProgressPercent( percent_done ); +		} +	} + +	////////////////////////// +	// +	// Prepare for the next frame +	// + +	///////////////////////////// +	// +	// Update the camera +	// +	// + +	LLAppViewer::instance()->pingMainloopTimeout("Display:Camera"); +	LLViewerCamera::getInstance()->setZoomParameters(zoom_factor, subfield); +	LLViewerCamera::getInstance()->setNear(MIN_NEAR_PLANE); + +	////////////////////////// +	// +	// clear the next buffer +	// (must follow dynamic texture writing since that uses the frame buffer) +	// + +	if (gDisconnected) +	{ +		LLAppViewer::instance()->pingMainloopTimeout("Display:Disconnected"); +		render_ui(); +	} +	 +	////////////////////////// +	// +	// Set rendering options +	// +	// +	LLAppViewer::instance()->pingMainloopTimeout("Display:RenderSetup"); +	stop_glerror(); + +	/////////////////////////////////////// +	// +	// Slam lighting parameters back to our defaults. +	// Note that these are not the same as GL defaults... + +	stop_glerror(); +	gGL.setAmbientLightColor(LLColor4::white); +	stop_glerror(); +			 +	///////////////////////////////////// +	// +	// Render +	// +	// Actually push all of our triangles to the screen. +	// + +	// do render-to-texture stuff here +	if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_DYNAMIC_TEXTURES)) +	{ +		LLAppViewer::instance()->pingMainloopTimeout("Display:DynamicTextures"); +		LLFastTimer t(FTM_UPDATE_TEXTURES); +		if (LLViewerDynamicTexture::updateAllInstances()) +		{ +			gGL.setColorMask(true, true); +			glClear(GL_DEPTH_BUFFER_BIT); +		} +	} + +	gViewerWindow->setup3DViewport(); + +	gPipeline.resetFrameStats();	// Reset per-frame statistics. +	 +	if (!gDisconnected) +	{ +		LLMemType mt_du(LLMemType::MTYPE_DISPLAY_UPDATE); +		LLAppViewer::instance()->pingMainloopTimeout("Display:Update"); +		if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) +		{ //don't draw hud objects in this frame +			gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD); +		} + +		if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES)) +		{ //don't draw hud particles in this frame +			gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES); +		} + +		//upkeep gl name pools +		LLGLNamePool::upkeepPools(); +		 +		stop_glerror(); +		display_update_camera(); +		stop_glerror(); +				 +		// *TODO: merge these two methods +		{ +			LLMemType mt_uh(LLMemType::MTYPE_DISPLAY_UPDATE_HUD); +			LLHUDManager::getInstance()->updateEffects(); +			LLHUDObject::updateAll(); +			stop_glerror(); +		} + +		{ +			LLMemType mt_ug(LLMemType::MTYPE_DISPLAY_UPDATE_GEOM); +			const F32 max_geom_update_time = 0.005f*10.f*gFrameIntervalSeconds; // 50 ms/second update time +			gPipeline.createObjects(max_geom_update_time); +			gPipeline.processPartitionQ(); +			gPipeline.updateGeom(max_geom_update_time); +			stop_glerror(); +		} + +		gPipeline.updateGL(); +		stop_glerror(); + +		S32 water_clip = 0; +		if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_ENVIRONMENT) > 1) && +			 (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_WATER) ||  +			  gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_VOIDWATER))) +		{ +			if (LLViewerCamera::getInstance()->cameraUnderWater()) +			{ +				water_clip = -1; +			} +			else +			{ +				water_clip = 1; +			} +		} +		 +		LLAppViewer::instance()->pingMainloopTimeout("Display:Cull"); +		 +		//Increment drawable frame counter +		LLDrawable::incrementVisible(); + +		LLSpatialGroup::sNoDelete = TRUE; +		LLTexUnit::sWhiteTexture = LLViewerFetchedTexture::sWhiteImagep->getTexName(); + +		/*if (LLPipeline::sUseOcclusion && LLPipeline::sRenderDeferred) +		{ //force occlusion on for all render types if doing deferred render (tighter shadow frustum) +			LLPipeline::sUseOcclusion = 3; +		}*/ + +		S32 occlusion = LLPipeline::sUseOcclusion; +		if (gDepthDirty) +		{ //depth buffer is invalid, don't overwrite occlusion state +			LLPipeline::sUseOcclusion = llmin(occlusion, 1); +		} +		gDepthDirty = FALSE; + +		LLGLState::checkStates(); +		LLGLState::checkTextureChannels(); +		LLGLState::checkClientArrays(); + +		static LLCullResult result; +		LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; +		gPipeline.updateCull(*LLViewerCamera::getInstance(), result, water_clip); +		stop_glerror(); + +		LLGLState::checkStates(); +		LLGLState::checkTextureChannels(); +		LLGLState::checkClientArrays(); + +		BOOL to_texture = gPipeline.canUseVertexShaders() && +						LLPipeline::sRenderGlow; + +		LLAppViewer::instance()->pingMainloopTimeout("Display:Swap"); +		 +		{  +			LLMemType mt_ds(LLMemType::MTYPE_DISPLAY_SWAP); + +			if (gResizeScreenTexture) +			{ +				gResizeScreenTexture = FALSE; +				gPipeline.resizeScreenTexture(); +			} + +			gGL.setColorMask(true, true); +			glClearColor(0,0,0,0); + +			LLGLState::checkStates(); +			LLGLState::checkTextureChannels(); +			LLGLState::checkClientArrays(); + +			if (!for_snapshot) +			{ +				if (gFrameCount > 1) +				{ //for some reason, ATI 4800 series will error out if you  +				  //try to generate a shadow before the first frame is through +					gPipeline.generateSunShadow(*LLViewerCamera::getInstance()); +				} + +				LLVertexBuffer::unbind(); + +				LLGLState::checkStates(); +				LLGLState::checkTextureChannels(); +				LLGLState::checkClientArrays(); + +				glh::matrix4f proj = glh_get_current_projection(); +				glh::matrix4f mod = glh_get_current_modelview(); +				glViewport(0,0,512,512); +				LLVOAvatar::updateFreezeCounter() ; + +				if(!LLPipeline::sMemAllocationThrottled) +				{		 +					LLVOAvatar::updateImpostors(); +				} + +				glh_set_current_projection(proj); +				glh_set_current_modelview(mod); +				gGL.matrixMode(LLRender::MM_PROJECTION); +				gGL.loadMatrix(proj.m); +				gGL.matrixMode(LLRender::MM_MODELVIEW); +				gGL.loadMatrix(mod.m); +				gViewerWindow->setup3DViewport(); + +				LLGLState::checkStates(); +				LLGLState::checkTextureChannels(); +				LLGLState::checkClientArrays(); + +			} +			glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); +		} + +		LLGLState::checkStates(); +		LLGLState::checkClientArrays(); + +		//if (!for_snapshot) +		{ +			LLMemType mt_gw(LLMemType::MTYPE_DISPLAY_GEN_REFLECTION); +			LLAppViewer::instance()->pingMainloopTimeout("Display:Imagery"); +			gPipeline.generateWaterReflection(*LLViewerCamera::getInstance()); +			gPipeline.generateHighlight(*LLViewerCamera::getInstance()); +			gPipeline.renderPhysicsDisplay(); +		} + +		LLGLState::checkStates(); +		LLGLState::checkClientArrays(); + +		////////////////////////////////////// +		// +		// Update images, using the image stats generated during object update/culling +		// +		// Can put objects onto the retextured list. +		// +		// Doing this here gives hardware occlusion queries extra time to complete +		LLAppViewer::instance()->pingMainloopTimeout("Display:UpdateImages"); +		 +		{ +			LLMemType mt_iu(LLMemType::MTYPE_DISPLAY_IMAGE_UPDATE); +			LLFastTimer t(FTM_IMAGE_UPDATE); +			 +			{ +				LLFastTimer t(FTM_IMAGE_UPDATE_CLASS); +				LLViewerTexture::updateClass(LLViewerCamera::getInstance()->getVelocityStat()->getMean(), +											LLViewerCamera::getInstance()->getAngularVelocityStat()->getMean()); +			} + +			 +			{ +				LLFastTimer t(FTM_IMAGE_UPDATE_BUMP); +				gBumpImageList.updateImages();  // must be called before gTextureList version so that it's textures are thrown out first. +			} + +			{ +				LLFastTimer t(FTM_IMAGE_UPDATE_LIST); +				F32 max_image_decode_time = 0.050f*gFrameIntervalSeconds; // 50 ms/second decode time +				max_image_decode_time = llclamp(max_image_decode_time, 0.002f, 0.005f ); // min 2ms/frame, max 5ms/frame) +				gTextureList.updateImages(max_image_decode_time); +			} + +			{ +				LLFastTimer t(FTM_IMAGE_UPDATE_DELETE); +				//remove dead textures from GL +				LLImageGL::deleteDeadTextures(); +				stop_glerror(); +			} +		} + +		LLGLState::checkStates(); +		LLGLState::checkClientArrays(); + +		/////////////////////////////////// +		// +		// StateSort +		// +		// Responsible for taking visible objects, and adding them to the appropriate draw orders. +		// In the case of alpha objects, z-sorts them first. +		// Also creates special lists for outlines and selected face rendering. +		// +		LLAppViewer::instance()->pingMainloopTimeout("Display:StateSort"); +		{ +			LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; +			LLMemType mt_ss(LLMemType::MTYPE_DISPLAY_STATE_SORT); +			gPipeline.stateSort(*LLViewerCamera::getInstance(), result); +			stop_glerror(); +				 +			if (rebuild) +			{ +				////////////////////////////////////// +				// +				// rebuildPools +				// +				// +				gPipeline.rebuildPools(); +				stop_glerror(); +			} +		} + +		LLGLState::checkStates(); +		LLGLState::checkClientArrays(); + +		LLPipeline::sUseOcclusion = occlusion; + +		{ +			LLMemType mt_ds(LLMemType::MTYPE_DISPLAY_SKY); +			LLAppViewer::instance()->pingMainloopTimeout("Display:Sky"); +			LLFastTimer t(FTM_UPDATE_SKY);	 +			gSky.updateSky(); +		} + +		if(gUseWireframe) +		{ +			glClearColor(0.5f, 0.5f, 0.5f, 0.f); +			glClear(GL_COLOR_BUFFER_BIT); +			glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); +		} + +		LLAppViewer::instance()->pingMainloopTimeout("Display:RenderStart"); +		 +		//// render frontmost floater opaque for occlusion culling purposes +		//LLFloater* frontmost_floaterp = gFloaterView->getFrontmost(); +		//// assumes frontmost floater with focus is opaque +		//if (frontmost_floaterp && gFocusMgr.childHasKeyboardFocus(frontmost_floaterp)) +		//{ +		//	gGL.matrixMode(LLRender::MM_MODELVIEW); +		//	gGL.pushMatrix(); +		//	{ +		//		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + +		//		glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); +		//		gGL.loadIdentity(); + +		//		LLRect floater_rect = frontmost_floaterp->calcScreenRect(); +		//		// deflate by one pixel so rounding errors don't occlude outside of floater extents +		//		floater_rect.stretch(-1); +		//		LLRectf floater_3d_rect((F32)floater_rect.mLeft / (F32)gViewerWindow->getWindowWidthScaled(),  +		//								(F32)floater_rect.mTop / (F32)gViewerWindow->getWindowHeightScaled(), +		//								(F32)floater_rect.mRight / (F32)gViewerWindow->getWindowWidthScaled(), +		//								(F32)floater_rect.mBottom / (F32)gViewerWindow->getWindowHeightScaled()); +		//		floater_3d_rect.translate(-0.5f, -0.5f); +		//		gGL.translatef(0.f, 0.f, -LLViewerCamera::getInstance()->getNear()); +		//		gGL.scalef(LLViewerCamera::getInstance()->getNear() * LLViewerCamera::getInstance()->getAspect() / sinf(LLViewerCamera::getInstance()->getView()), LLViewerCamera::getInstance()->getNear() / sinf(LLViewerCamera::getInstance()->getView()), 1.f); +		//		gGL.color4fv(LLColor4::white.mV); +		//		gGL.begin(LLVertexBuffer::QUADS); +		//		{ +		//			gGL.vertex3f(floater_3d_rect.mLeft, floater_3d_rect.mBottom, 0.f); +		//			gGL.vertex3f(floater_3d_rect.mLeft, floater_3d_rect.mTop, 0.f); +		//			gGL.vertex3f(floater_3d_rect.mRight, floater_3d_rect.mTop, 0.f); +		//			gGL.vertex3f(floater_3d_rect.mRight, floater_3d_rect.mBottom, 0.f); +		//		} +		//		gGL.end(); +		//		glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); +		//	} +		//	gGL.popMatrix(); +		//} + +		LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater() ? TRUE : FALSE; +		 +		LLGLState::checkStates(); +		LLGLState::checkClientArrays(); + +		stop_glerror(); + +		if (to_texture) +		{ +			gGL.setColorMask(true, true); +					 +			if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender) +			{ +				gPipeline.mDeferredScreen.bindTarget(); +				glClearColor(1,0,1,1); +				gPipeline.mDeferredScreen.clear(); +			} +			else +			{ +				gPipeline.mScreen.bindTarget(); +				if (LLPipeline::sUnderWaterRender && !gPipeline.canUseWindLightShaders()) +				{ +					const LLColor4 &col = LLDrawPoolWater::sWaterFogColor; +					glClearColor(col.mV[0], col.mV[1], col.mV[2], 0.f); +				} +				gPipeline.mScreen.clear(); +			} +			 +			gGL.setColorMask(true, false); +		} +		 +		LLAppViewer::instance()->pingMainloopTimeout("Display:RenderGeom"); +		 +		if (!(LLAppViewer::instance()->logoutRequestSent() && LLAppViewer::instance()->hasSavedFinalSnapshot()) +				&& !gRestoreGL) +		{ +			LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; +			LLMemType mt_rg(LLMemType::MTYPE_DISPLAY_RENDER_GEOM); +			gGL.setColorMask(true, false); +			if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender) +			{ +				gPipeline.renderGeomDeferred(*LLViewerCamera::getInstance()); +			} +			else +			{ +				gPipeline.renderGeom(*LLViewerCamera::getInstance(), TRUE); +			} +			 +			gGL.setColorMask(true, true); + +			//store this frame's modelview matrix for use +			//when rendering next frame's occlusion queries +			for (U32 i = 0; i < 16; i++) +			{ +				gGLLastModelView[i] = gGLModelView[i]; +				gGLLastProjection[i] = gGLProjection[i]; +			} +			stop_glerror(); +		} + +		for (U32 i = 0; i < gGLManager.mNumTextureImageUnits; i++) +		{ //dummy cleanup of any currently bound textures +			if (gGL.getTexUnit(i)->getCurrType() != LLTexUnit::TT_NONE) +			{ +				gGL.getTexUnit(i)->unbind(gGL.getTexUnit(i)->getCurrType()); +				gGL.getTexUnit(i)->disable(); +			} +		} +		LLAppViewer::instance()->pingMainloopTimeout("Display:RenderFlush");		 +		 +		if (to_texture) +		{ +			LLMemType mt_rf(LLMemType::MTYPE_DISPLAY_RENDER_FLUSH); +			if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender) +			{ +				gPipeline.mDeferredScreen.flush(); +				if(LLRenderTarget::sUseFBO) +				{ +					LLRenderTarget::copyContentsToFramebuffer(gPipeline.mDeferredScreen, 0, 0, gPipeline.mDeferredScreen.getWidth(),  +															  gPipeline.mDeferredScreen.getHeight(), 0, 0,  +															  gPipeline.mDeferredScreen.getWidth(),  +															  gPipeline.mDeferredScreen.getHeight(),  +															  GL_DEPTH_BUFFER_BIT, GL_NEAREST); +				} +			} +			else +			{ +				gPipeline.mScreen.flush(); +				if(LLRenderTarget::sUseFBO) +				{				 +					LLRenderTarget::copyContentsToFramebuffer(gPipeline.mScreen, 0, 0, gPipeline.mScreen.getWidth(),  +															  gPipeline.mScreen.getHeight(), 0, 0,  +															  gPipeline.mScreen.getWidth(),  +															  gPipeline.mScreen.getHeight(),  +															  GL_DEPTH_BUFFER_BIT, GL_NEAREST); +				} +			} +		} + +		if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender) +		{ +			gPipeline.renderDeferredLighting(); +		} + +		LLPipeline::sUnderWaterRender = FALSE; + +		LLAppViewer::instance()->pingMainloopTimeout("Display:RenderUI"); +		if (!for_snapshot) +		{ +			LLFastTimer t(FTM_RENDER_UI); +			render_ui(); +		} + +		 +		LLSpatialGroup::sNoDelete = FALSE; +		gPipeline.clearReferences(); + +		gPipeline.rebuildGroups(); +	} + +	LLAppViewer::instance()->pingMainloopTimeout("Display:FrameStats"); +	 +	stop_glerror(); + +	if (LLPipeline::sRenderFrameTest) +	{ +		send_agent_resume(); +		LLPipeline::sRenderFrameTest = FALSE; +	} + +	display_stats(); +				 +	LLAppViewer::instance()->pingMainloopTimeout("Display:Done"); +} + +void render_hud_attachments() +{ +	LLMemType mt_ra(LLMemType::MTYPE_DISPLAY_RENDER_ATTACHMENTS); +	gGL.matrixMode(LLRender::MM_PROJECTION); +	gGL.pushMatrix(); +	gGL.matrixMode(LLRender::MM_MODELVIEW); +	gGL.pushMatrix(); +		 +	glh::matrix4f current_proj = glh_get_current_projection(); +	glh::matrix4f current_mod = glh_get_current_modelview(); + +	// clamp target zoom level to reasonable values +	gAgentCamera.mHUDTargetZoom = llclamp(gAgentCamera.mHUDTargetZoom, 0.1f, 1.f); +	// smoothly interpolate current zoom level +	gAgentCamera.mHUDCurZoom = lerp(gAgentCamera.mHUDCurZoom, gAgentCamera.mHUDTargetZoom, LLCriticalDamp::getInterpolant(0.03f)); + +	if (LLPipeline::sShowHUDAttachments && !gDisconnected && setup_hud_matrices()) +	{ +		LLCamera hud_cam = *LLViewerCamera::getInstance(); +		LLVector3 origin = hud_cam.getOrigin(); +		hud_cam.setOrigin(-1.f,0,0); +		hud_cam.setAxes(LLVector3(1,0,0), LLVector3(0,1,0), LLVector3(0,0,1)); +		LLViewerCamera::updateFrustumPlanes(hud_cam, TRUE); + +		bool render_particles = gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES) && gSavedSettings.getBOOL("RenderHUDParticles"); +		 +		//only render hud objects +		gPipeline.pushRenderTypeMask(); +		 +		// turn off everything +		gPipeline.andRenderTypeMask(LLPipeline::END_RENDER_TYPES); +		// turn on HUD +		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD); +		// turn on HUD particles +		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES); + +		// if particles are off, turn off hud-particles as well +		if (!render_particles) +		{ +			// turn back off HUD particles +			gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES); +		} + +		bool has_ui = gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI); +		if (has_ui) +		{ +			gPipeline.toggleRenderDebugFeature((void*) LLPipeline::RENDER_DEBUG_FEATURE_UI); +		} + +		S32 use_occlusion = LLPipeline::sUseOcclusion; +		LLPipeline::sUseOcclusion = 0; +				 +		//cull, sort, and render hud objects +		static LLCullResult result; +		LLSpatialGroup::sNoDelete = TRUE; + +		LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; +		gPipeline.updateCull(hud_cam, result); + +		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_BUMP); +		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_SIMPLE); +		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_VOLUME); +		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_ALPHA); +		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_FULLBRIGHT); +		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA); +		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK); +		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_BUMP); +		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT); +		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK); +		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY); +		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_SHINY); +		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_INVISIBLE); +		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY); +		 +		gPipeline.stateSort(hud_cam, result); + +		gPipeline.renderGeom(hud_cam); + +		LLSpatialGroup::sNoDelete = FALSE; +		//gPipeline.clearReferences(); + +		render_hud_elements(); + +		//restore type mask +		gPipeline.popRenderTypeMask(); + +		if (has_ui) +		{ +			gPipeline.toggleRenderDebugFeature((void*) LLPipeline::RENDER_DEBUG_FEATURE_UI); +		} +		LLPipeline::sUseOcclusion = use_occlusion; +	} +	gGL.matrixMode(LLRender::MM_PROJECTION); +	gGL.popMatrix(); +	gGL.matrixMode(LLRender::MM_MODELVIEW); +	gGL.popMatrix(); +	 +	glh_set_current_projection(current_proj); +	glh_set_current_modelview(current_mod); +} + +LLRect get_whole_screen_region() +{ +	LLRect whole_screen = gViewerWindow->getWorldViewRectScaled(); +	 +	// apply camera zoom transform (for high res screenshots) +	F32 zoom_factor = LLViewerCamera::getInstance()->getZoomFactor(); +	S16 sub_region = LLViewerCamera::getInstance()->getZoomSubRegion(); +	if (zoom_factor > 1.f) +	{ +		S32 num_horizontal_tiles = llceil(zoom_factor); +		S32 tile_width = llround((F32)gViewerWindow->getWorldViewWidthScaled() / zoom_factor); +		S32 tile_height = llround((F32)gViewerWindow->getWorldViewHeightScaled() / zoom_factor); +		int tile_y = sub_region / num_horizontal_tiles; +		int tile_x = sub_region - (tile_y * num_horizontal_tiles); +			 +		whole_screen.setLeftTopAndSize(tile_x * tile_width, gViewerWindow->getWorldViewHeightScaled() - (tile_y * tile_height), tile_width, tile_height); +	} +	return whole_screen; +} + +bool get_hud_matrices(const LLRect& screen_region, glh::matrix4f &proj, glh::matrix4f &model) +{ +	if (isAgentAvatarValid() && gAgentAvatarp->hasHUDAttachment()) +	{ +		F32 zoom_level = gAgentCamera.mHUDCurZoom; +		LLBBox hud_bbox = gAgentAvatarp->getHUDBBox(); +		 +		F32 hud_depth = llmax(1.f, hud_bbox.getExtentLocal().mV[VX] * 1.1f); +		proj = gl_ortho(-0.5f * LLViewerCamera::getInstance()->getAspect(), 0.5f * LLViewerCamera::getInstance()->getAspect(), -0.5f, 0.5f, 0.f, hud_depth); +		proj.element(2,2) = -0.01f; +		 +		F32 aspect_ratio = LLViewerCamera::getInstance()->getAspect(); +		 +		glh::matrix4f mat; +		F32 scale_x = (F32)gViewerWindow->getWorldViewWidthScaled() / (F32)screen_region.getWidth(); +		F32 scale_y = (F32)gViewerWindow->getWorldViewHeightScaled() / (F32)screen_region.getHeight(); +		mat.set_scale(glh::vec3f(scale_x, scale_y, 1.f)); +		mat.set_translate( +			glh::vec3f(clamp_rescale((F32)(screen_region.getCenterX() - screen_region.mLeft), 0.f, (F32)gViewerWindow->getWorldViewWidthScaled(), 0.5f * scale_x * aspect_ratio, -0.5f * scale_x * aspect_ratio), +					   clamp_rescale((F32)(screen_region.getCenterY() - screen_region.mBottom), 0.f, (F32)gViewerWindow->getWorldViewHeightScaled(), 0.5f * scale_y, -0.5f * scale_y), +					   0.f)); +		proj *= mat; +		 +		glh::matrix4f tmp_model((GLfloat*) OGL_TO_CFR_ROTATION); +		 +		mat.set_scale(glh::vec3f(zoom_level, zoom_level, zoom_level)); +		mat.set_translate(glh::vec3f(-hud_bbox.getCenterLocal().mV[VX] + (hud_depth * 0.5f), 0.f, 0.f)); +		 +		tmp_model *= mat; +		model = tmp_model;		 +		return TRUE; +	} +	else +	{ +		return FALSE; +	} +} + +bool get_hud_matrices(glh::matrix4f &proj, glh::matrix4f &model) +{ +	LLRect whole_screen = get_whole_screen_region(); +	return get_hud_matrices(whole_screen, proj, model); +} + +BOOL setup_hud_matrices() +{ +	LLRect whole_screen = get_whole_screen_region(); +	return setup_hud_matrices(whole_screen); +} + +BOOL setup_hud_matrices(const LLRect& screen_region) +{ +	glh::matrix4f proj, model; +	bool result = get_hud_matrices(screen_region, proj, model); +	if (!result) return result; +	 +	// set up transform to keep HUD objects in front of camera +	gGL.matrixMode(LLRender::MM_PROJECTION); +	gGL.loadMatrix(proj.m); +	glh_set_current_projection(proj); +	 +	gGL.matrixMode(LLRender::MM_MODELVIEW); +	gGL.loadMatrix(model.m); +	glh_set_current_modelview(model); +	return TRUE; +} + +static LLFastTimer::DeclareTimer FTM_SWAP("Swap"); + +void render_ui(F32 zoom_factor, int subfield) +{ +	LLMemType mt_ru(LLMemType::MTYPE_DISPLAY_RENDER_UI); +	LLGLState::checkStates(); +	 +	glh::matrix4f saved_view = glh_get_current_modelview(); + +	if (!gSnapshot) +	{ +		gGL.pushMatrix(); +		gGL.loadMatrix(gGLLastModelView); +		glh_set_current_modelview(glh_copy_matrix(gGLLastModelView)); +	} +	 +	{ +		BOOL to_texture = gPipeline.canUseVertexShaders() && +							LLPipeline::sRenderGlow; + +		if (to_texture) +		{ +			gPipeline.renderBloom(gSnapshot, zoom_factor, subfield); +		} +		 +		render_hud_elements(); +		render_hud_attachments(); +	} + +	LLGLSDefault gls_default; +	LLGLSUIDefault gls_ui; +	{ +		gPipeline.disableLights(); +	} + +	{ +		gGL.color4f(1,1,1,1); +		if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) +		{ +			LLFastTimer t(FTM_RENDER_UI); + +			if (!gDisconnected) +			{ +				render_ui_3d(); +				LLGLState::checkStates(); +			} +			else +			{ +				render_disconnected_background(); +			} + +			render_ui_2d(); +			LLGLState::checkStates(); +		} +		gGL.flush(); + +		{ +			gViewerWindow->setup2DRender(); +			gViewerWindow->updateDebugText(); +			gViewerWindow->drawDebugText(); +		} + +		LLVertexBuffer::unbind(); +	} + +	if (!gSnapshot) +	{ +		glh_set_current_modelview(saved_view); +		gGL.popMatrix(); +	} + +	if (gDisplaySwapBuffers) +	{ +		LLFastTimer t(FTM_SWAP); +		gViewerWindow->getWindow()->swapBuffers(); +	} +	gDisplaySwapBuffers = TRUE; +} + +void renderCoordinateAxes() +{ +	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); +	gGL.begin(LLRender::LINES); +		gGL.color3f(1.0f, 0.0f, 0.0f);   // i direction = X-Axis = red +		gGL.vertex3f(0.0f, 0.0f, 0.0f); +		gGL.vertex3f(2.0f, 0.0f, 0.0f); +		gGL.vertex3f(3.0f, 0.0f, 0.0f); +		gGL.vertex3f(5.0f, 0.0f, 0.0f); +		gGL.vertex3f(6.0f, 0.0f, 0.0f); +		gGL.vertex3f(8.0f, 0.0f, 0.0f); +		// Make an X +		gGL.vertex3f(11.0f, 1.0f, 1.0f); +		gGL.vertex3f(11.0f, -1.0f, -1.0f); +		gGL.vertex3f(11.0f, 1.0f, -1.0f); +		gGL.vertex3f(11.0f, -1.0f, 1.0f); + +		gGL.color3f(0.0f, 1.0f, 0.0f);   // j direction = Y-Axis = green +		gGL.vertex3f(0.0f, 0.0f, 0.0f); +		gGL.vertex3f(0.0f, 2.0f, 0.0f); +		gGL.vertex3f(0.0f, 3.0f, 0.0f); +		gGL.vertex3f(0.0f, 5.0f, 0.0f); +		gGL.vertex3f(0.0f, 6.0f, 0.0f); +		gGL.vertex3f(0.0f, 8.0f, 0.0f); +		// Make a Y +		gGL.vertex3f(1.0f, 11.0f, 1.0f); +		gGL.vertex3f(0.0f, 11.0f, 0.0f); +		gGL.vertex3f(-1.0f, 11.0f, 1.0f); +		gGL.vertex3f(0.0f, 11.0f, 0.0f); +		gGL.vertex3f(0.0f, 11.0f, 0.0f); +		gGL.vertex3f(0.0f, 11.0f, -1.0f); + +		gGL.color3f(0.0f, 0.0f, 1.0f);   // Z-Axis = blue +		gGL.vertex3f(0.0f, 0.0f, 0.0f); +		gGL.vertex3f(0.0f, 0.0f, 2.0f); +		gGL.vertex3f(0.0f, 0.0f, 3.0f); +		gGL.vertex3f(0.0f, 0.0f, 5.0f); +		gGL.vertex3f(0.0f, 0.0f, 6.0f); +		gGL.vertex3f(0.0f, 0.0f, 8.0f); +		// Make a Z +		gGL.vertex3f(-1.0f, 1.0f, 11.0f); +		gGL.vertex3f(1.0f, 1.0f, 11.0f); +		gGL.vertex3f(1.0f, 1.0f, 11.0f); +		gGL.vertex3f(-1.0f, -1.0f, 11.0f); +		gGL.vertex3f(-1.0f, -1.0f, 11.0f); +		gGL.vertex3f(1.0f, -1.0f, 11.0f); +	gGL.end(); +} + + +void draw_axes()  +{ +	LLGLSUIDefault gls_ui; +	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); +	// A vertical white line at origin +	LLVector3 v = gAgent.getPositionAgent(); +	gGL.begin(LLRender::LINES); +		gGL.color3f(1.0f, 1.0f, 1.0f);  +		gGL.vertex3f(0.0f, 0.0f, 0.0f); +		gGL.vertex3f(0.0f, 0.0f, 40.0f); +	gGL.end(); +	// Some coordinate axes +	gGL.pushMatrix(); +		gGL.translatef( v.mV[VX], v.mV[VY], v.mV[VZ] ); +		renderCoordinateAxes(); +	gGL.popMatrix(); +} + +void render_ui_3d() +{ +	LLGLSPipeline gls_pipeline; + +	////////////////////////////////////// +	// +	// Render 3D UI elements +	// NOTE: zbuffer is cleared before we get here by LLDrawPoolHUD, +	//		 so 3d elements requiring Z buffer are moved to LLDrawPoolHUD +	// + +	///////////////////////////////////////////////////////////// +	// +	// Render 2.5D elements (2D elements in the world) +	// Stuff without z writes +	// + +	// Debugging stuff goes before the UI. + +	stop_glerror(); +	 +	if (LLGLSLShader::sNoFixedFunction) +	{ +		gUIProgram.bind(); +	} + +	// Coordinate axes +	if (gSavedSettings.getBOOL("ShowAxes")) +	{ +		draw_axes(); +	} + +	gViewerWindow->renderSelections(FALSE, FALSE, TRUE); // Non HUD call in render_hud_elements +	stop_glerror(); +} + +void render_ui_2d() +{ +	LLGLSUIDefault gls_ui; + +	///////////////////////////////////////////////////////////// +	// +	// Render 2D UI elements that overlay the world (no z compare) + +	//  Disable wireframe mode below here, as this is HUD/menus +	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + +	//  Menu overlays, HUD, etc +	gViewerWindow->setup2DRender(); + +	F32 zoom_factor = LLViewerCamera::getInstance()->getZoomFactor(); +	S16 sub_region = LLViewerCamera::getInstance()->getZoomSubRegion(); + +	if (zoom_factor > 1.f) +	{ +		//decompose subregion number to x and y values +		int pos_y = sub_region / llceil(zoom_factor); +		int pos_x = sub_region - (pos_y*llceil(zoom_factor)); +		// offset for this tile +		LLFontGL::sCurOrigin.mX -= llround((F32)gViewerWindow->getWindowWidthScaled() * (F32)pos_x / zoom_factor); +		LLFontGL::sCurOrigin.mY -= llround((F32)gViewerWindow->getWindowHeightScaled() * (F32)pos_y / zoom_factor); +	} + +	stop_glerror(); +	//gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); + +	// render outline for HUD +	if (isAgentAvatarValid() && gAgentCamera.mHUDCurZoom < 0.98f) +	{ +		gGL.pushMatrix(); +		S32 half_width = (gViewerWindow->getWorldViewWidthScaled() / 2); +		S32 half_height = (gViewerWindow->getWorldViewHeightScaled() / 2); +		gGL.scalef(LLUI::sGLScaleFactor.mV[0], LLUI::sGLScaleFactor.mV[1], 1.f); +		gGL.translatef((F32)half_width, (F32)half_height, 0.f); +		F32 zoom = gAgentCamera.mHUDCurZoom; +		gGL.scalef(zoom,zoom,1.f); +		gGL.color4fv(LLColor4::white.mV); +		gl_rect_2d(-half_width, half_height, half_width, -half_height, FALSE); +		gGL.popMatrix(); +		stop_glerror(); +	} +	 + +	if (gSavedSettings.getBOOL("RenderUIBuffer")) +	{ +		if (LLUI::sDirty) +		{ +			LLUI::sDirty = FALSE; +			LLRect t_rect; + +			gPipeline.mUIScreen.bindTarget(); +			gGL.setColorMask(true, true); +			{ +				static const S32 pad = 8; + +				LLUI::sDirtyRect.mLeft -= pad; +				LLUI::sDirtyRect.mRight += pad; +				LLUI::sDirtyRect.mBottom -= pad; +				LLUI::sDirtyRect.mTop += pad; + +				LLGLEnable scissor(GL_SCISSOR_TEST); +				static LLRect last_rect = LLUI::sDirtyRect; + +				//union with last rect to avoid mouse poop +				last_rect.unionWith(LLUI::sDirtyRect); +								 +				t_rect = LLUI::sDirtyRect; +				LLUI::sDirtyRect = last_rect; +				last_rect = t_rect; +			 +				last_rect.mLeft = LLRect::tCoordType(last_rect.mLeft / LLUI::sGLScaleFactor.mV[0]); +				last_rect.mRight = LLRect::tCoordType(last_rect.mRight / LLUI::sGLScaleFactor.mV[0]); +				last_rect.mTop = LLRect::tCoordType(last_rect.mTop / LLUI::sGLScaleFactor.mV[1]); +				last_rect.mBottom = LLRect::tCoordType(last_rect.mBottom / LLUI::sGLScaleFactor.mV[1]); + +				LLRect clip_rect(last_rect); +				 +				glClear(GL_COLOR_BUFFER_BIT); + +				gViewerWindow->draw(); +			} + +			gPipeline.mUIScreen.flush(); +			gGL.setColorMask(true, false); + +			LLUI::sDirtyRect = t_rect; +		} + +		LLGLDisable cull(GL_CULL_FACE); +		LLGLDisable blend(GL_BLEND); +		S32 width = gViewerWindow->getWindowWidthScaled(); +		S32 height = gViewerWindow->getWindowHeightScaled(); +		gGL.getTexUnit(0)->bind(&gPipeline.mUIScreen); +		gGL.begin(LLRender::TRIANGLE_STRIP); +		gGL.color4f(1,1,1,1); +		gGL.texCoord2f(0, 0);			gGL.vertex2i(0, 0); +		gGL.texCoord2f(width, 0);		gGL.vertex2i(width, 0); +		gGL.texCoord2f(0, height);		gGL.vertex2i(0, height); +		gGL.texCoord2f(width, height);	gGL.vertex2i(width, height); +		gGL.end(); +	} +	else +	{ +		gViewerWindow->draw(); +	} + + + +	// reset current origin for font rendering, in case of tiling render +	LLFontGL::sCurOrigin.set(0, 0); +} + +void render_disconnected_background() +{ +	if (LLGLSLShader::sNoFixedFunction) +	{ +		gUIProgram.bind(); +	} + +	gGL.color4f(1,1,1,1); +	if (!gDisconnectedImagep && gDisconnected) +	{ +		llinfos << "Loading last bitmap..." << llendl; + +		std::string temp_str; +		temp_str = gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter() + SCREEN_LAST_FILENAME; + +		LLPointer<LLImageBMP> image_bmp = new LLImageBMP; +		if( !image_bmp->load(temp_str) ) +		{ +			//llinfos << "Bitmap load failed" << llendl; +			return; +		} +		 +		LLPointer<LLImageRaw> raw = new LLImageRaw; +		if (!image_bmp->decode(raw, 0.0f)) +		{ +			llinfos << "Bitmap decode failed" << llendl; +			gDisconnectedImagep = NULL; +			return; +		} + +		U8 *rawp = raw->getData(); +		S32 npixels = (S32)image_bmp->getWidth()*(S32)image_bmp->getHeight(); +		for (S32 i = 0; i < npixels; i++) +		{ +			S32 sum = 0; +			sum = *rawp + *(rawp+1) + *(rawp+2); +			sum /= 3; +			*rawp = ((S32)sum*6 + *rawp)/7; +			rawp++; +			*rawp = ((S32)sum*6 + *rawp)/7; +			rawp++; +			*rawp = ((S32)sum*6 + *rawp)/7; +			rawp++; +		} + +		 +		raw->expandToPowerOfTwo(); +		gDisconnectedImagep = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE ); +		gStartTexture = gDisconnectedImagep; +		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); +	} + +	// Make sure the progress view always fills the entire window. +	S32 width = gViewerWindow->getWindowWidthScaled(); +	S32 height = gViewerWindow->getWindowHeightScaled(); + +	if (gDisconnectedImagep) +	{ +		LLGLSUIDefault gls_ui; +		gViewerWindow->setup2DRender(); +		gGL.pushMatrix(); +		{ +			// scale ui to reflect UIScaleFactor +			// this can't be done in setup2DRender because it requires a +			// pushMatrix/popMatrix pair +			const LLVector2& display_scale = gViewerWindow->getDisplayScale(); +			gGL.scalef(display_scale.mV[VX], display_scale.mV[VY], 1.f); + +			gGL.getTexUnit(0)->bind(gDisconnectedImagep); +			gGL.color4f(1.f, 1.f, 1.f, 1.f); +			gl_rect_2d_simple_tex(width, height); +			gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); +		} +		gGL.popMatrix(); +	} +	gGL.flush(); + +	if (LLGLSLShader::sNoFixedFunction) +	{ +		gUIProgram.unbind(); +	} + +} + +void display_cleanup() +{ +	gDisconnectedImagep = NULL; +} diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index e2f9b1f1a0..dc55247df2 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -1,1298 +1,1298 @@ -/** 
 - * @file llviewermenufile.cpp
 - * @brief "File" menu in the main menu bar.
 - *
 - * $LicenseInfo:firstyear=2002&license=viewerlgpl$
 - * Second Life Viewer Source Code
 - * Copyright (C) 2010, Linden Research, Inc.
 - * 
 - * This library is free software; you can redistribute it and/or
 - * modify it under the terms of the GNU Lesser General Public
 - * License as published by the Free Software Foundation;
 - * version 2.1 of the License only.
 - * 
 - * This library is distributed in the hope that it will be useful,
 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 - * Lesser General Public License for more details.
 - * 
 - * You should have received a copy of the GNU Lesser General Public
 - * License along with this library; if not, write to the Free Software
 - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 - * 
 - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 - * $/LicenseInfo$
 - */
 -
 -#include "llviewerprecompiledheaders.h"
 -
 -#include "llviewermenufile.h"
 -
 -// project includes
 -#include "llagent.h"
 -#include "llagentcamera.h"
 -#include "llfilepicker.h"
 -#include "llfloaterreg.h"
 -#include "llbuycurrencyhtml.h"
 -#include "llfloatermodelpreview.h"
 -#include "llfloatersnapshot.h"
 -#include "llimage.h"
 -#include "llimagebmp.h"
 -#include "llimagepng.h"
 -#include "llimagej2c.h"
 -#include "llimagejpeg.h"
 -#include "llimagetga.h"
 -#include "llinventorymodel.h"	// gInventory
 -#include "llresourcedata.h"
 -#include "llfloaterperms.h"
 -#include "llstatusbar.h"
 -#include "llviewercontrol.h"	// gSavedSettings
 -#include "llviewertexturelist.h"
 -#include "lluictrlfactory.h"
 -#include "llvfile.h"
 -#include "llvfs.h"
 -#include "llviewerinventory.h"
 -#include "llviewermenu.h"	// gMenuHolder
 -#include "llviewerparcelmgr.h"
 -#include "llviewerregion.h"
 -#include "llviewerstats.h"
 -#include "llviewerwindow.h"
 -#include "llappviewer.h"
 -#include "lluploaddialog.h"
 -#include "lltrans.h"
 -#include "llfloaterbuycurrency.h"
 -
 -// linden libraries
 -#include "llassetuploadresponders.h"
 -#include "lleconomy.h"
 -#include "llhttpclient.h"
 -#include "llnotificationsutil.h"
 -#include "llsdserialize.h"
 -#include "llsdutil.h"
 -#include "llstring.h"
 -#include "lltransactiontypes.h"
 -#include "lluuid.h"
 -#include "llvorbisencode.h"
 -#include "message.h"
 -
 -// system libraries
 -#include <boost/tokenizer.hpp>
 -
 -class LLFileEnableUpload : public view_listener_t
 -{
 -	bool handleEvent(const LLSD& userdata)
 -	{
 -		bool new_value = gStatusBar && LLGlobalEconomy::Singleton::getInstance() && (gStatusBar->getBalance() >= LLGlobalEconomy::Singleton::getInstance()->getPriceUpload());
 -		return new_value;
 -	}
 -};
 -
 -class LLFileEnableUploadModel : public view_listener_t
 -{
 -	bool handleEvent(const LLSD& userdata)
 -	{
 -		return true;
 -	}
 -};
 -
 -class LLMeshEnabled : public view_listener_t
 -{
 -	bool handleEvent(const LLSD& userdata)
 -	{
 -		return gSavedSettings.getBOOL("MeshEnabled");
 -	}
 -};
 -
 -class LLMeshUploadVisible : public view_listener_t
 -{
 -	bool handleEvent(const LLSD& userdata)
 -	{
 -		return gMeshRepo.meshUploadEnabled();
 -	}
 -};
 -
 -LLMutex* LLFilePickerThread::sMutex = NULL;
 -std::queue<LLFilePickerThread*> LLFilePickerThread::sDeadQ;
 -
 -void LLFilePickerThread::getFile()
 -{
 -#if LL_WINDOWS
 -	start();
 -#else
 -	run();
 -#endif
 -}
 -
 -//virtual 
 -void LLFilePickerThread::run()
 -{
 -	LLFilePicker picker;
 -#if LL_WINDOWS
 -	if (picker.getOpenFile(mFilter, false))
 -	{
 -		mFile = picker.getFirstFile();
 -	}
 -#else
 -	if (picker.getOpenFile(mFilter, true))
 -	{
 -		mFile = picker.getFirstFile();
 -	}
 -#endif
 -
 -	{
 -		LLMutexLock lock(sMutex);
 -		sDeadQ.push(this);
 -	}
 -
 -}
 -
 -//static
 -void LLFilePickerThread::initClass()
 -{
 -	sMutex = new LLMutex(NULL);
 -}
 -
 -//static
 -void LLFilePickerThread::cleanupClass()
 -{
 -	clearDead();
 -	
 -	delete sMutex;
 -	sMutex = NULL;
 -}
 -
 -//static
 -void LLFilePickerThread::clearDead()
 -{
 -	if (!sDeadQ.empty())
 -	{
 -		LLMutexLock lock(sMutex);
 -		while (!sDeadQ.empty())
 -		{
 -			LLFilePickerThread* thread = sDeadQ.front();
 -			thread->notify(thread->mFile);
 -			delete thread;
 -			sDeadQ.pop();
 -		}
 -	}
 -}
 -
 -
 -//============================================================================
 -
 -#if LL_WINDOWS
 -static std::string SOUND_EXTENSIONS = "wav";
 -static std::string IMAGE_EXTENSIONS = "tga bmp jpg jpeg png";
 -static std::string ANIM_EXTENSIONS =  "bvh anim";
 -#ifdef _CORY_TESTING
 -static std::string GEOMETRY_EXTENSIONS = "slg";
 -#endif
 -static std::string XML_EXTENSIONS = "xml";
 -static std::string SLOBJECT_EXTENSIONS = "slobject";
 -#endif
 -static std::string ALL_FILE_EXTENSIONS = "*.*";
 -static std::string MODEL_EXTENSIONS = "dae";
 -
 -std::string build_extensions_string(LLFilePicker::ELoadFilter filter)
 -{
 -	switch(filter)
 -	{
 -#if LL_WINDOWS
 -	case LLFilePicker::FFLOAD_IMAGE:
 -		return IMAGE_EXTENSIONS;
 -	case LLFilePicker::FFLOAD_WAV:
 -		return SOUND_EXTENSIONS;
 -	case LLFilePicker::FFLOAD_ANIM:
 -		return ANIM_EXTENSIONS;
 -	case LLFilePicker::FFLOAD_SLOBJECT:
 -		return SLOBJECT_EXTENSIONS;
 -	case LLFilePicker::FFLOAD_MODEL:
 -		return MODEL_EXTENSIONS;
 -#ifdef _CORY_TESTING
 -	case LLFilePicker::FFLOAD_GEOMETRY:
 -		return GEOMETRY_EXTENSIONS;
 -#endif
 -	case LLFilePicker::FFLOAD_XML:
 -	    return XML_EXTENSIONS;
 -	case LLFilePicker::FFLOAD_ALL:
 -		return ALL_FILE_EXTENSIONS;
 -#endif
 -    default:
 -	return ALL_FILE_EXTENSIONS;
 -	}
 -}
 -
 -/**
 -   char* upload_pick(void* data)
 -
 -   If applicable, brings up a file chooser in which the user selects a file
 -   to upload for a particular task.  If the file is valid for the given action,
 -   returns the string to the full path filename, else returns NULL.
 -   Data is the load filter for the type of file as defined in LLFilePicker.
 -**/
 -const std::string upload_pick(void* data)
 -{
 - 	if( gAgentCamera.cameraMouselook() )
 -	{
 -		gAgentCamera.changeCameraToDefault();
 -		// This doesn't seem necessary. JC
 -		// display();
 -	}
 -
 -	LLFilePicker::ELoadFilter type;
 -	if(data)
 -	{
 -		type = (LLFilePicker::ELoadFilter)((intptr_t)data);
 -	}
 -	else
 -	{
 -		type = LLFilePicker::FFLOAD_ALL;
 -	}
 -
 -	LLFilePicker& picker = LLFilePicker::instance();
 -	if (!picker.getOpenFile(type))
 -	{
 -		llinfos << "Couldn't import objects from file" << llendl;
 -		return std::string();
 -	}
 -
 -	
 -	const std::string& filename = picker.getFirstFile();
 -	std::string ext = gDirUtilp->getExtension(filename);
 -
 -	//strincmp doesn't like NULL pointers
 -	if (ext.empty())
 -	{
 -		std::string short_name = gDirUtilp->getBaseFileName(filename);
 -		
 -		// No extension
 -		LLSD args;
 -		args["FILE"] = short_name;
 -		LLNotificationsUtil::add("NoFileExtension", args);
 -		return std::string();
 -	}
 -	else
 -	{
 -		//so there is an extension
 -		//loop over the valid extensions and compare to see
 -		//if the extension is valid
 -
 -		//now grab the set of valid file extensions
 -		std::string valid_extensions = build_extensions_string(type);
 -
 -		BOOL ext_valid = FALSE;
 -		
 -		typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
 -		boost::char_separator<char> sep(" ");
 -		tokenizer tokens(valid_extensions, sep);
 -		tokenizer::iterator token_iter;
 -
 -		//now loop over all valid file extensions
 -		//and compare them to the extension of the file
 -		//to be uploaded
 -		for( token_iter = tokens.begin();
 -			 token_iter != tokens.end() && ext_valid != TRUE;
 -			 ++token_iter)
 -		{
 -			const std::string& cur_token = *token_iter;
 -
 -			if (cur_token == ext || cur_token == "*.*")
 -			{
 -				//valid extension
 -				//or the acceptable extension is any
 -				ext_valid = TRUE;
 -			}
 -		}//end for (loop over all tokens)
 -
 -		if (ext_valid == FALSE)
 -		{
 -			//should only get here if the extension exists
 -			//but is invalid
 -			LLSD args;
 -			args["EXTENSION"] = ext;
 -			args["VALIDS"] = valid_extensions;
 -			LLNotificationsUtil::add("InvalidFileExtension", args);
 -			return std::string();
 -		}
 -	}//end else (non-null extension)
 -
 -	//valid file extension
 -	
 -	//now we check to see
 -	//if the file is actually a valid image/sound/etc.
 -	if (type == LLFilePicker::FFLOAD_WAV)
 -	{
 -		// pre-qualify wavs to make sure the format is acceptable
 -		std::string error_msg;
 -		if (check_for_invalid_wav_formats(filename,error_msg))
 -		{
 -			llinfos << error_msg << ": " << filename << llendl;
 -			LLSD args;
 -			args["FILE"] = filename;
 -			LLNotificationsUtil::add( error_msg, args );
 -			return std::string();
 -		}
 -	}//end if a wave/sound file
 -
 -	
 -	return filename;
 -}
 -
 -class LLFileUploadImage : public view_listener_t
 -{
 -	bool handleEvent(const LLSD& userdata)
 -	{
 -		std::string filename = upload_pick((void *)LLFilePicker::FFLOAD_IMAGE);
 -		if (!filename.empty())
 -		{
 -			LLFloaterReg::showInstance("upload_image", LLSD(filename));
 -		}
 -		return TRUE;
 -	}
 -};
 -
 -class LLFileUploadModel : public view_listener_t
 -{
 -	bool handleEvent(const LLSD& userdata)
 -	{
 -		LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) LLFloaterReg::getInstance("upload_model");
 -		if (fmp)
 -		{
 -			fmp->loadModel(3);
 -		}
 -		
 -		return TRUE;
 -	}
 -};
 -	
 -class LLFileUploadSound : public view_listener_t
 -{
 -	bool handleEvent(const LLSD& userdata)
 -	{
 -		std::string filename = upload_pick((void*)LLFilePicker::FFLOAD_WAV);
 -		if (!filename.empty())
 -		{
 -			LLFloaterReg::showInstance("upload_sound", LLSD(filename));
 -		}
 -		return true;
 -	}
 -};
 -
 -class LLFileUploadAnim : public view_listener_t
 -{
 -	bool handleEvent(const LLSD& userdata)
 -	{
 -		const std::string filename = upload_pick((void*)LLFilePicker::FFLOAD_ANIM);
 -		if (!filename.empty())
 -		{
 -			if (filename.rfind(".anim") != std::string::npos)
 -			{
 -				LLFloaterReg::showInstance("upload_anim_anim", LLSD(filename));
 -			}
 -			else
 -			{
 -				LLFloaterReg::showInstance("upload_anim_bvh", LLSD(filename));
 -			}
 -		}
 -		return true;
 -	}
 -};
 -
 -class LLFileUploadBulk : public view_listener_t
 -{
 -	bool handleEvent(const LLSD& userdata)
 -	{
 -		if( gAgentCamera.cameraMouselook() )
 -		{
 -			gAgentCamera.changeCameraToDefault();
 -		}
 -
 -		// TODO:
 -		// Iterate over all files
 -		// Check extensions for uploadability, cost
 -		// Check user balance for entire cost
 -		// Charge user entire cost
 -		// Loop, uploading
 -		// If an upload fails, refund the user for that one
 -		//
 -		// Also fix single upload to charge first, then refund
 -
 -		LLFilePicker& picker = LLFilePicker::instance();
 -		if (picker.getMultipleOpenFiles())
 -		{
 -			const std::string& filename = picker.getFirstFile();
 -			std::string name = gDirUtilp->getBaseFileName(filename, true);
 -			
 -			std::string asset_name = name;
 -			LLStringUtil::replaceNonstandardASCII( asset_name, '?' );
 -			LLStringUtil::replaceChar(asset_name, '|', '?');
 -			LLStringUtil::stripNonprintable(asset_name);
 -			LLStringUtil::trim(asset_name);
 -			
 -			std::string display_name = LLStringUtil::null;
 -			LLAssetStorage::LLStoreAssetCallback callback = NULL;
 -			S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
 -			void *userdata = NULL;
 -
 -			upload_new_resource(
 -				filename,
 -				asset_name,
 -				asset_name,
 -				0,
 -				LLFolderType::FT_NONE,
 -				LLInventoryType::IT_NONE,
 -				LLFloaterPerms::getNextOwnerPerms(),
 -				LLFloaterPerms::getGroupPerms(),
 -				LLFloaterPerms::getEveryonePerms(),
 -				display_name,
 -				callback,
 -				expected_upload_cost,
 -				userdata);
 -
 -			// *NOTE: Ew, we don't iterate over the file list here,
 -			// we handle the next files in upload_done_callback()
 -		}
 -		else
 -		{
 -			llinfos << "Couldn't import objects from file" << llendl;
 -		}
 -		return true;
 -	}
 -};
 -
 -void upload_error(const std::string& error_message, const std::string& label, const std::string& filename, const LLSD& args) 
 -{
 -	llwarns << error_message << llendl;
 -	LLNotificationsUtil::add(label, args);
 -	if(LLFile::remove(filename) == -1)
 -	{
 -		lldebugs << "unable to remove temp file" << llendl;
 -	}
 -	LLFilePicker::instance().reset();						
 -}
 -
 -class LLFileEnableCloseWindow : public view_listener_t
 -{
 -	bool handleEvent(const LLSD& userdata)
 -	{
 -		bool new_value = NULL != LLFloater::getClosableFloaterFromFocus();
 -		return new_value;
 -	}
 -};
 -
 -class LLFileCloseWindow : public view_listener_t
 -{
 -	bool handleEvent(const LLSD& userdata)
 -	{
 -		LLFloater::closeFocusedFloater();
 -
 -		return true;
 -	}
 -};
 -
 -class LLFileEnableCloseAllWindows : public view_listener_t
 -{
 -	bool handleEvent(const LLSD& userdata)
 -	{
 -		bool open_children = gFloaterView->allChildrenClosed();
 -		return !open_children;
 -	}
 -};
 -
 -class LLFileCloseAllWindows : public view_listener_t
 -{
 -	bool handleEvent(const LLSD& userdata)
 -	{
 -		bool app_quitting = false;
 -		gFloaterView->closeAllChildren(app_quitting);
 -
 -		return true;
 -	}
 -};
 -
 -class LLFileTakeSnapshotToDisk : public view_listener_t
 -{
 -	bool handleEvent(const LLSD& userdata)
 -	{
 -		LLPointer<LLImageRaw> raw = new LLImageRaw;
 -
 -		S32 width = gViewerWindow->getWindowWidthRaw();
 -		S32 height = gViewerWindow->getWindowHeightRaw();
 -
 -		if (gSavedSettings.getBOOL("HighResSnapshot"))
 -		{
 -			width *= 2;
 -			height *= 2;
 -		}
 -
 -		if (gViewerWindow->rawSnapshot(raw,
 -									   width,
 -									   height,
 -									   TRUE,
 -									   FALSE,
 -									   gSavedSettings.getBOOL("RenderUIInSnapshot"),
 -									   FALSE))
 -		{
 -			gViewerWindow->playSnapshotAnimAndSound();
 -			LLPointer<LLImageFormatted> formatted;
 -			LLFloaterSnapshot::ESnapshotFormat fmt = (LLFloaterSnapshot::ESnapshotFormat) gSavedSettings.getS32("SnapshotFormat");
 -			switch (fmt)
 -			{
 -			case LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG:
 -				formatted = new LLImageJPEG(gSavedSettings.getS32("SnapshotQuality"));
 -				break;
 -			default:
 -				llwarns << "Unknown local snapshot format: " << fmt << llendl;
 -			case LLFloaterSnapshot::SNAPSHOT_FORMAT_PNG:
 -				formatted = new LLImagePNG;
 -				break;
 -			case LLFloaterSnapshot::SNAPSHOT_FORMAT_BMP:
 -				formatted = new LLImageBMP;
 -				break;
 -			}
 -			formatted->enableOverSize() ;
 -			formatted->encode(raw, 0);
 -			formatted->disableOverSize() ;
 -			gViewerWindow->saveImageNumbered(formatted);
 -		}
 -		return true;
 -	}
 -};
 -
 -class LLFileQuit : public view_listener_t
 -{
 -	bool handleEvent(const LLSD& userdata)
 -	{
 -		LLAppViewer::instance()->userQuit();
 -		return true;
 -	}
 -};
 -
 -
 -void handle_compress_image(void*)
 -{
 -	LLFilePicker& picker = LLFilePicker::instance();
 -	if (picker.getMultipleOpenFiles(LLFilePicker::FFLOAD_IMAGE))
 -	{
 -		std::string infile = picker.getFirstFile();
 -		while (!infile.empty())
 -		{
 -			std::string outfile = infile + ".j2c";
 -
 -			llinfos << "Input:  " << infile << llendl;
 -			llinfos << "Output: " << outfile << llendl;
 -
 -			BOOL success;
 -
 -			success = LLViewerTextureList::createUploadFile(infile, outfile, IMG_CODEC_TGA);
 -
 -			if (success)
 -			{
 -				llinfos << "Compression complete" << llendl;
 -			}
 -			else
 -			{
 -				llinfos << "Compression failed: " << LLImage::getLastError() << llendl;
 -			}
 -
 -			infile = picker.getNextFile();
 -		}
 -	}
 -}
 -
 -LLUUID upload_new_resource(
 -	const std::string& src_filename,
 -	std::string name,
 -	std::string desc,
 -	S32 compression_info,
 -	LLFolderType::EType destination_folder_type,
 -	LLInventoryType::EType inv_type,
 -	U32 next_owner_perms,
 -	U32 group_perms,
 -	U32 everyone_perms,
 -	const std::string& display_name,
 -	LLAssetStorage::LLStoreAssetCallback callback,
 -	S32 expected_upload_cost,
 -	void *userdata)
 -{	
 -	// Generate the temporary UUID.
 -	std::string filename = gDirUtilp->getTempFilename();
 -	LLTransactionID tid;
 -	LLAssetID uuid;
 -	
 -	LLSD args;
 -
 -	std::string exten = gDirUtilp->getExtension(src_filename);
 -	U32 codec = LLImageBase::getCodecFromExtension(exten);
 -	LLAssetType::EType asset_type = LLAssetType::AT_NONE;
 -	std::string error_message;
 -
 -	BOOL error = FALSE;
 -	
 -	if (exten.empty())
 -	{
 -		std::string short_name = gDirUtilp->getBaseFileName(filename);
 -		
 -		// No extension
 -		error_message = llformat(
 -				"No file extension for the file: '%s'\nPlease make sure the file has a correct file extension",
 -				short_name.c_str());
 -		args["FILE"] = short_name;
 - 		upload_error(error_message, "NoFileExtension", filename, args);
 -		return LLUUID();
 -	}
 -	else if (codec != IMG_CODEC_INVALID)
 -	{
 -		// It's an image file, the upload procedure is the same for all
 -		asset_type = LLAssetType::AT_TEXTURE;
 -		if (!LLViewerTextureList::createUploadFile(src_filename, filename, codec ))
 -		{
 -			error_message = llformat( "Problem with file %s:\n\n%s\n",
 -									 src_filename.c_str(), LLImage::getLastError().c_str());
 -			args["FILE"] = src_filename;
 -			args["ERROR"] = LLImage::getLastError();
 -			upload_error(error_message, "ProblemWithFile", filename, args);
 -			return LLUUID();
 -		}
 -	}
 -	else if(exten == "wav")
 -	{
 -		asset_type = LLAssetType::AT_SOUND;  // tag it as audio
 -		S32 encode_result = 0;
 -
 -		llinfos << "Attempting to encode wav as an ogg file" << llendl;
 -
 -		encode_result = encode_vorbis_file(src_filename, filename);
 -		
 -		if (LLVORBISENC_NOERR != encode_result)
 -		{
 -			switch(encode_result)
 -			{
 -				case LLVORBISENC_DEST_OPEN_ERR:
 -				    error_message = llformat( "Couldn't open temporary compressed sound file for writing: %s\n", filename.c_str());
 -					args["FILE"] = filename;
 -					upload_error(error_message, "CannotOpenTemporarySoundFile", filename, args);
 -					break;
 -
 -				default:	
 -				  error_message = llformat("Unknown vorbis encode failure on: %s\n", src_filename.c_str());
 -					args["FILE"] = src_filename;
 -					upload_error(error_message, "UnknownVorbisEncodeFailure", filename, args);
 -					break;	
 -			}	
 -			return LLUUID();
 -		}
 -	}
 -	else if(exten == "tmp")	 	
 -	{	 	
 -		// This is a generic .lin resource file	 	
 -         asset_type = LLAssetType::AT_OBJECT;	 	
 -         LLFILE* in = LLFile::fopen(src_filename, "rb");		/* Flawfinder: ignore */	 	
 -         if (in)	 	
 -         {	 	
 -                 // read in the file header	 	
 -                 char buf[16384];		/* Flawfinder: ignore */ 	
 -                 size_t readbytes;
 -                 S32  version;	 	
 -                 if (fscanf(in, "LindenResource\nversion %d\n", &version))	 	
 -                 {	 	
 -                         if (2 == version)	 	
 -                         {
 -								// *NOTE: This buffer size is hard coded into scanf() below.
 -                                 char label[MAX_STRING];		/* Flawfinder: ignore */	 	
 -                                 char value[MAX_STRING];		/* Flawfinder: ignore */	 	
 -                                 S32  tokens_read;	 	
 -                                 while (fgets(buf, 1024, in))	 	
 -                                 {	 	
 -                                         label[0] = '\0';	 	
 -                                         value[0] = '\0';	 	
 -                                         tokens_read = sscanf(	/* Flawfinder: ignore */
 -											 buf,
 -											 "%254s %254s\n",
 -											 label, value);	 	
 -
 -                                         llinfos << "got: " << label << " = " << value	 	
 -                                                         << llendl;	 	
 -
 -                                         if (EOF == tokens_read)	 	
 -                                         {	 	
 -                                                 fclose(in);	 	
 -                                                 error_message = llformat("corrupt resource file: %s", src_filename.c_str());
 -												 args["FILE"] = src_filename;
 -												 upload_error(error_message, "CorruptResourceFile", filename, args);
 -                                                 return LLUUID();
 -                                         }	 	
 -
 -                                         if (2 == tokens_read)	 	
 -                                         {	 	
 -                                                 if (! strcmp("type", label))	 	
 -                                                 {	 	
 -                                                         asset_type = (LLAssetType::EType)(atoi(value));	 	
 -                                                 }	 	
 -                                         }	 	
 -                                         else	 	
 -                                         {	 	
 -                                                 if (! strcmp("_DATA_", label))	 	
 -                                                 {	 	
 -                                                         // below is the data section	 	
 -                                                         break;	 	
 -                                                 }	 	
 -                                         }	 	
 -                                         // other values are currently discarded	 	
 -                                 }	 	
 -
 -                         }	 	
 -                         else	 	
 -                         {	 	
 -                                 fclose(in);	 	
 -                                 error_message = llformat("unknown linden resource file version in file: %s", src_filename.c_str());
 -								 args["FILE"] = src_filename;
 -								 upload_error(error_message, "UnknownResourceFileVersion", filename, args);
 -                                 return LLUUID();
 -                         }	 	
 -                 }	 	
 -                 else	 	
 -                 {	 	
 -                         // this is an original binary formatted .lin file	 	
 -                         // start over at the beginning of the file	 	
 -                         fseek(in, 0, SEEK_SET);	 	
 -
 -                         const S32 MAX_ASSET_DESCRIPTION_LENGTH = 256;	 	
 -                         const S32 MAX_ASSET_NAME_LENGTH = 64;	 	
 -                         S32 header_size = 34 + MAX_ASSET_DESCRIPTION_LENGTH + MAX_ASSET_NAME_LENGTH;	 	
 -                         S16     type_num;	 	
 -
 -                         // read in and throw out most of the header except for the type	 	
 -                         if (fread(buf, header_size, 1, in) != 1)
 -						 {
 -							 llwarns << "Short read" << llendl;
 -						 }
 -                         memcpy(&type_num, buf + 16, sizeof(S16));		/* Flawfinder: ignore */	 	
 -                         asset_type = (LLAssetType::EType)type_num;	 	
 -                 }	 	
 -
 -                 // copy the file's data segment into another file for uploading	 	
 -                 LLFILE* out = LLFile::fopen(filename, "wb");		/* Flawfinder: ignore */	
 -                 if (out)	 	
 -                 {	 	
 -                         while((readbytes = fread(buf, 1, 16384, in)))		/* Flawfinder: ignore */	 	
 -                         {	 	
 -							 if (fwrite(buf, 1, readbytes, out) != readbytes)
 -							 {
 -								 llwarns << "Short write" << llendl;
 -							 }
 -                         }	 	
 -                         fclose(out);	 	
 -                 }	 	
 -                 else	 	
 -                 {	 	
 -                         fclose(in);	 	
 -                         error_message = llformat( "Unable to create output file: %s", filename.c_str());
 -						 args["FILE"] = filename;
 -						 upload_error(error_message, "UnableToCreateOutputFile", filename, args);
 -                         return LLUUID();
 -                 }	 	
 -
 -                 fclose(in);	 	
 -         }	 	
 -         else	 	
 -         {	 	
 -                 llinfos << "Couldn't open .lin file " << src_filename << llendl;	 	
 -         }	 	
 -	}
 -	else if (exten == "bvh")
 -	{
 -		error_message = llformat("We do not currently support bulk upload of animation files\n");
 -		upload_error(error_message, "DoNotSupportBulkAnimationUpload", filename, args);
 -		return LLUUID();
 -	}
 -	else if (exten == "anim")
 -	{
 -		asset_type = LLAssetType::AT_ANIMATION;
 -		filename = src_filename;
 -	}
 -	else
 -	{
 -		// Unknown extension
 -		error_message = llformat(LLTrans::getString("UnknownFileExtension").c_str(), exten.c_str());
 -		error = TRUE;;
 -	}
 -
 -	// gen a new transaction ID for this asset
 -	tid.generate();
 -
 -	if (!error)
 -	{
 -		uuid = tid.makeAssetID(gAgent.getSecureSessionID());
 -		// copy this file into the vfs for upload
 -		S32 file_size;
 -		LLAPRFile infile ;
 -		infile.open(filename, LL_APR_RB, NULL, &file_size);
 -		if (infile.getFileHandle())
 -		{
 -			LLVFile file(gVFS, uuid, asset_type, LLVFile::WRITE);
 -
 -			file.setMaxSize(file_size);
 -
 -			const S32 buf_size = 65536;
 -			U8 copy_buf[buf_size];
 -			while ((file_size = infile.read(copy_buf, buf_size)))
 -			{
 -				file.write(copy_buf, file_size);
 -			}
 -		}
 -		else
 -		{
 -			error_message = llformat( "Unable to access output file: %s", filename.c_str());
 -			error = TRUE;
 -		}
 -	}
 -
 -	if (!error)
 -	{
 -		std::string t_disp_name = display_name;
 -		if (t_disp_name.empty())
 -		{
 -			t_disp_name = src_filename;
 -		}
 -		upload_new_resource(
 -			tid,
 -			asset_type,
 -			name,
 -			desc,
 -			compression_info, // tid
 -			destination_folder_type,
 -			inv_type,
 -			next_owner_perms,
 -			group_perms,
 -			everyone_perms,
 -			display_name,
 -			callback,
 -			expected_upload_cost,
 -			userdata);
 -	}
 -	else
 -	{
 -		llwarns << error_message << llendl;
 -		LLSD args;
 -		args["ERROR_MESSAGE"] = error_message;
 -		LLNotificationsUtil::add("ErrorMessage", args);
 -		if(LLFile::remove(filename) == -1)
 -		{
 -			lldebugs << "unable to remove temp file" << llendl;
 -		}
 -		LLFilePicker::instance().reset();
 -	}
 -
 -	return uuid;
 -}
 -
 -void upload_done_callback(
 -	const LLUUID& uuid,
 -	void* user_data,
 -	S32 result,
 -	LLExtStat ext_status) // StoreAssetData callback (fixed)
 -{
 -	LLResourceData* data = (LLResourceData*)user_data;
 -	S32 expected_upload_cost = data ? data->mExpectedUploadCost : 0;
 -	//LLAssetType::EType pref_loc = data->mPreferredLocation;
 -	BOOL is_balance_sufficient = TRUE;
 -
 -	if(data)
 -	{
 -		if (result >= 0)
 -		{
 -			LLFolderType::EType dest_loc = (data->mPreferredLocation == LLFolderType::FT_NONE) ? LLFolderType::assetTypeToFolderType(data->mAssetInfo.mType) : data->mPreferredLocation;
 -			
 -			if (LLAssetType::AT_SOUND == data->mAssetInfo.mType ||
 -			    LLAssetType::AT_TEXTURE == data->mAssetInfo.mType ||
 -			    LLAssetType::AT_ANIMATION == data->mAssetInfo.mType)
 -			{
 -				// Charge the user for the upload.
 -				LLViewerRegion* region = gAgent.getRegion();
 -				
 -				if(!(can_afford_transaction(expected_upload_cost)))
 -				{
 -					LLStringUtil::format_map_t args;
 -					args["NAME"] = data->mAssetInfo.getName();
 -					args["AMOUNT"] = llformat("%d", expected_upload_cost);
 -					LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("UploadingCosts", args), expected_upload_cost );
 -					is_balance_sufficient = FALSE;
 -				}
 -				else if(region)
 -				{
 -					// Charge user for upload
 -					gStatusBar->debitBalance(expected_upload_cost);
 -					
 -					LLMessageSystem* msg = gMessageSystem;
 -					msg->newMessageFast(_PREHASH_MoneyTransferRequest);
 -					msg->nextBlockFast(_PREHASH_AgentData);
 -					msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
 -					msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
 -					msg->nextBlockFast(_PREHASH_MoneyData);
 -					msg->addUUIDFast(_PREHASH_SourceID, gAgent.getID());
 -					msg->addUUIDFast(_PREHASH_DestID, LLUUID::null);
 -					msg->addU8("Flags", 0);
 -					// we tell the sim how much we were expecting to pay so it
 -					// can respond to any discrepancy
 -					msg->addS32Fast(_PREHASH_Amount, expected_upload_cost);
 -					msg->addU8Fast(_PREHASH_AggregatePermNextOwner, (U8)LLAggregatePermissions::AP_EMPTY);
 -					msg->addU8Fast(_PREHASH_AggregatePermInventory, (U8)LLAggregatePermissions::AP_EMPTY);
 -					msg->addS32Fast(_PREHASH_TransactionType, TRANS_UPLOAD_CHARGE);
 -					msg->addStringFast(_PREHASH_Description, NULL);
 -					msg->sendReliable(region->getHost());
 -				}
 -			}
 -
 -			if(is_balance_sufficient)
 -			{
 -				// Actually add the upload to inventory
 -				llinfos << "Adding " << uuid << " to inventory." << llendl;
 -				const LLUUID folder_id = gInventory.findCategoryUUIDForType(dest_loc);
 -				if(folder_id.notNull())
 -				{
 -					U32 next_owner_perms = data->mNextOwnerPerm;
 -					if(PERM_NONE == next_owner_perms)
 -					{
 -						next_owner_perms = PERM_MOVE | PERM_TRANSFER;
 -					}
 -					create_inventory_item(gAgent.getID(), gAgent.getSessionID(),
 -							      folder_id, data->mAssetInfo.mTransactionID, data->mAssetInfo.getName(),
 -							      data->mAssetInfo.getDescription(), data->mAssetInfo.mType,
 -							      data->mInventoryType, NOT_WEARABLE, next_owner_perms,
 -							      LLPointer<LLInventoryCallback>(NULL));
 -				}
 -				else
 -				{
 -					llwarns << "Can't find a folder to put it in" << llendl;
 -				}
 -			}
 -		}
 -		else // 	if(result >= 0)
 -		{
 -			LLSD args;
 -			args["FILE"] = LLInventoryType::lookupHumanReadable(data->mInventoryType);
 -			args["REASON"] = std::string(LLAssetStorage::getErrorString(result));
 -			LLNotificationsUtil::add("CannotUploadReason", args);
 -		}
 -	}
 -
 -	LLUploadDialog::modalUploadFinished();
 -	delete data;
 -	data = NULL;
 -
 -	// *NOTE: This is a pretty big hack. What this does is check the
 -	// file picker if there are any more pending uploads. If so,
 -	// upload that file.
 -	const std::string& next_file = LLFilePicker::instance().getNextFile();
 -	if(is_balance_sufficient && !next_file.empty())
 -	{
 -		std::string asset_name = gDirUtilp->getBaseFileName(next_file, true);
 -		LLStringUtil::replaceNonstandardASCII( asset_name, '?' );
 -		LLStringUtil::replaceChar(asset_name, '|', '?');
 -		LLStringUtil::stripNonprintable(asset_name);
 -		LLStringUtil::trim(asset_name);
 -
 -		std::string display_name = LLStringUtil::null;
 -		LLAssetStorage::LLStoreAssetCallback callback = NULL;
 -		void *userdata = NULL;
 -		upload_new_resource(
 -			next_file,
 -			asset_name,
 -			asset_name,	// file
 -			0,
 -			LLFolderType::FT_NONE,
 -			LLInventoryType::IT_NONE,
 -			PERM_NONE,
 -			PERM_NONE,
 -			PERM_NONE,
 -			display_name,
 -			callback,
 -			expected_upload_cost, // assuming next in a group of uploads is of roughly the same type, i.e. same upload cost
 -			userdata);
 -	}
 -}
 -
 -static LLAssetID upload_new_resource_prep(
 -	const LLTransactionID& tid,
 -	LLAssetType::EType asset_type,
 -	LLInventoryType::EType& inventory_type,
 -	std::string& name,
 -	const std::string& display_name,
 -	std::string& description)
 -{
 -	LLAssetID uuid = generate_asset_id_for_new_upload(tid);
 -
 -	increase_new_upload_stats(asset_type);
 -
 -	assign_defaults_and_show_upload_message(
 -		asset_type,
 -		inventory_type,
 -		name,
 -		display_name,
 -		description);
 -
 -	return uuid;
 -}
 -
 -LLSD generate_new_resource_upload_capability_body(
 -	LLAssetType::EType asset_type,
 -	const std::string& name,
 -	const std::string& desc,
 -	LLFolderType::EType destination_folder_type,
 -	LLInventoryType::EType inv_type,
 -	U32 next_owner_perms,
 -	U32 group_perms,
 -	U32 everyone_perms)
 -{
 -	LLSD body;
 -
 -	body["folder_id"] = gInventory.findCategoryUUIDForType(
 -		(destination_folder_type == LLFolderType::FT_NONE) ?
 -		(LLFolderType::EType) asset_type :
 -		destination_folder_type);
 -
 -	body["asset_type"] = LLAssetType::lookup(asset_type);
 -	body["inventory_type"] = LLInventoryType::lookup(inv_type);
 -	body["name"] = name;
 -	body["description"] = desc;
 -	body["next_owner_mask"] = LLSD::Integer(next_owner_perms);
 -	body["group_mask"] = LLSD::Integer(group_perms);
 -	body["everyone_mask"] = LLSD::Integer(everyone_perms);
 -
 -	return body;
 -}
 -
 -void upload_new_resource(
 -	const LLTransactionID &tid,
 -	LLAssetType::EType asset_type,
 -	std::string name,
 -	std::string desc,
 -	S32 compression_info,
 -	LLFolderType::EType destination_folder_type,
 -	LLInventoryType::EType inv_type,
 -	U32 next_owner_perms,
 -	U32 group_perms,
 -	U32 everyone_perms,
 -	const std::string& display_name,
 -	LLAssetStorage::LLStoreAssetCallback callback,
 -	S32 expected_upload_cost,
 -	void *userdata)
 -{
 -	if(gDisconnected)
 -	{
 -		return ;
 -	}
 -	
 -	LLAssetID uuid = 
 -		upload_new_resource_prep(
 -			tid,
 -			asset_type,
 -			inv_type,
 -			name,
 -			display_name,
 -			desc);
 -	
 -	if( LLAssetType::AT_SOUND == asset_type )
 -	{
 -		LLViewerStats::getInstance()->incStat(LLViewerStats::ST_UPLOAD_SOUND_COUNT );
 -	}
 -	else
 -	if( LLAssetType::AT_TEXTURE == asset_type )
 -	{
 -		LLViewerStats::getInstance()->incStat(LLViewerStats::ST_UPLOAD_TEXTURE_COUNT );
 -	}
 -	else
 -	if( LLAssetType::AT_ANIMATION == asset_type)
 -	{
 -		LLViewerStats::getInstance()->incStat(LLViewerStats::ST_UPLOAD_ANIM_COUNT );
 -	}
 -
 -	if(LLInventoryType::IT_NONE == inv_type)
 -	{
 -		inv_type = LLInventoryType::defaultForAssetType(asset_type);
 -	}
 -	LLStringUtil::stripNonprintable(name);
 -	LLStringUtil::stripNonprintable(desc);
 -	if(name.empty())
 -	{
 -		name = "(No Name)";
 -	}
 -	if(desc.empty())
 -	{
 -		desc = "(No Description)";
 -	}
 -	
 -	// At this point, we're ready for the upload.
 -	std::string upload_message = "Uploading...\n\n";
 -	upload_message.append(display_name);
 -	LLUploadDialog::modalUploadDialog(upload_message);
 -
 -	llinfos << "*** Uploading: " << llendl;
 -	llinfos << "Type: " << LLAssetType::lookup(asset_type) << llendl;
 -	llinfos << "UUID: " << uuid << llendl;
 -	llinfos << "Name: " << name << llendl;
 -	llinfos << "Desc: " << desc << llendl;
 -	llinfos << "Expected Upload Cost: " << expected_upload_cost << llendl;
 -	lldebugs << "Folder: " << gInventory.findCategoryUUIDForType((destination_folder_type == LLFolderType::FT_NONE) ? LLFolderType::assetTypeToFolderType(asset_type) : destination_folder_type) << llendl;
 -	lldebugs << "Asset Type: " << LLAssetType::lookup(asset_type) << llendl;
 -
 -	std::string url = gAgent.getRegion()->getCapability(
 -		"NewFileAgentInventory");
 -
 -	if ( !url.empty() )
 -	{
 -		llinfos << "New Agent Inventory via capability" << llendl;
 -
 -		LLSD body;
 -		body = generate_new_resource_upload_capability_body(
 -			asset_type,
 -			name,
 -			desc,
 -			destination_folder_type,
 -			inv_type,
 -			next_owner_perms,
 -			group_perms,
 -			everyone_perms);
 -
 -		LLHTTPClient::post(
 -			url,
 -			body,
 -			new LLNewAgentInventoryResponder(
 -				body,
 -				uuid,
 -				asset_type));
 -	}
 -	else
 -	{
 -		llinfos << "NewAgentInventory capability not found, new agent inventory via asset system." << llendl;
 -		// check for adequate funds
 -		// TODO: do this check on the sim
 -		if (LLAssetType::AT_SOUND == asset_type ||
 -			LLAssetType::AT_TEXTURE == asset_type ||
 -			LLAssetType::AT_ANIMATION == asset_type)
 -		{
 -			S32 balance = gStatusBar->getBalance();
 -			if (balance < expected_upload_cost)
 -			{
 -				// insufficient funds, bail on this upload
 -				LLStringUtil::format_map_t args;
 -				args["NAME"] = name;
 -				args["AMOUNT"] = llformat("%d", expected_upload_cost);
 -				LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("UploadingCosts", args), expected_upload_cost );
 -				return;
 -			}
 -		}
 -
 -		LLResourceData* data = new LLResourceData;
 -		data->mAssetInfo.mTransactionID = tid;
 -		data->mAssetInfo.mUuid = uuid;
 -		data->mAssetInfo.mType = asset_type;
 -		data->mAssetInfo.mCreatorID = gAgentID;
 -		data->mInventoryType = inv_type;
 -		data->mNextOwnerPerm = next_owner_perms;
 -		data->mExpectedUploadCost = expected_upload_cost;
 -		data->mUserData = userdata;
 -		data->mAssetInfo.setName(name);
 -		data->mAssetInfo.setDescription(desc);
 -		data->mPreferredLocation = destination_folder_type;
 -
 -		LLAssetStorage::LLStoreAssetCallback asset_callback = &upload_done_callback;
 -		if (callback)
 -		{
 -			asset_callback = callback;
 -		}
 -		gAssetStorage->storeAssetData(
 -			data->mAssetInfo.mTransactionID,
 -			data->mAssetInfo.mType,
 -			asset_callback,
 -			(void*)data,
 -			FALSE);
 -	}
 -}
 -
 -LLAssetID generate_asset_id_for_new_upload(const LLTransactionID& tid)
 -{
 -	if ( gDisconnected )
 -	{	
 -		LLAssetID rv;
 -
 -		rv.setNull();
 -		return rv;
 -	}
 -
 -	LLAssetID uuid = tid.makeAssetID(gAgent.getSecureSessionID());
 -
 -	return uuid;
 -}
 -
 -void increase_new_upload_stats(LLAssetType::EType asset_type)
 -{
 -	if ( LLAssetType::AT_SOUND == asset_type )
 -	{
 -		LLViewerStats::getInstance()->incStat(
 -			LLViewerStats::ST_UPLOAD_SOUND_COUNT );
 -	}
 -	else if ( LLAssetType::AT_TEXTURE == asset_type )
 -	{
 -		LLViewerStats::getInstance()->incStat(
 -			LLViewerStats::ST_UPLOAD_TEXTURE_COUNT );
 -	}
 -	else if ( LLAssetType::AT_ANIMATION == asset_type )
 -	{
 -		LLViewerStats::getInstance()->incStat(
 -			LLViewerStats::ST_UPLOAD_ANIM_COUNT );
 -	}
 -}
 -
 -void assign_defaults_and_show_upload_message(
 -	LLAssetType::EType asset_type,
 -	LLInventoryType::EType& inventory_type,
 -	std::string& name,
 -	const std::string& display_name,
 -	std::string& description)
 -{
 -	if ( LLInventoryType::IT_NONE == inventory_type )
 -	{
 -		inventory_type = LLInventoryType::defaultForAssetType(asset_type);
 -	}
 -	LLStringUtil::stripNonprintable(name);
 -	LLStringUtil::stripNonprintable(description);
 -
 -	if ( name.empty() )
 -	{
 -		name = "(No Name)";
 -	}
 -	if ( description.empty() )
 -	{
 -		description = "(No Description)";
 -	}
 -
 -	// At this point, we're ready for the upload.
 -	std::string upload_message = "Uploading...\n\n";
 -	upload_message.append(display_name);
 -	LLUploadDialog::modalUploadDialog(upload_message);
 -}
 -
 -
 -void init_menu_file()
 -{
 -	view_listener_t::addCommit(new LLFileUploadImage(), "File.UploadImage");
 -	view_listener_t::addCommit(new LLFileUploadSound(), "File.UploadSound");
 -	view_listener_t::addCommit(new LLFileUploadAnim(), "File.UploadAnim");
 -	view_listener_t::addCommit(new LLFileUploadModel(), "File.UploadModel");
 -	view_listener_t::addCommit(new LLFileUploadBulk(), "File.UploadBulk");
 -	view_listener_t::addCommit(new LLFileCloseWindow(), "File.CloseWindow");
 -	view_listener_t::addCommit(new LLFileCloseAllWindows(), "File.CloseAllWindows");
 -	view_listener_t::addEnable(new LLFileEnableCloseWindow(), "File.EnableCloseWindow");
 -	view_listener_t::addEnable(new LLFileEnableCloseAllWindows(), "File.EnableCloseAllWindows");
 -	view_listener_t::addCommit(new LLFileTakeSnapshotToDisk(), "File.TakeSnapshotToDisk");
 -	view_listener_t::addCommit(new LLFileQuit(), "File.Quit");
 -
 -	view_listener_t::addEnable(new LLFileEnableUpload(), "File.EnableUpload");
 -	view_listener_t::addEnable(new LLFileEnableUploadModel(), "File.EnableUploadModel");
 -	view_listener_t::addMenu(new LLMeshEnabled(), "File.MeshEnabled");
 -	view_listener_t::addMenu(new LLMeshUploadVisible(), "File.VisibleUploadModel");
 -
 -	// "File.SaveTexture" moved to llpanelmaininventory so that it can be properly handled.
 -}
 +/**  + * @file llviewermenufile.cpp + * @brief "File" menu in the main menu bar. + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + *  + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llviewermenufile.h" + +// project includes +#include "llagent.h" +#include "llagentcamera.h" +#include "llfilepicker.h" +#include "llfloaterreg.h" +#include "llbuycurrencyhtml.h" +#include "llfloatermodelpreview.h" +#include "llfloatersnapshot.h" +#include "llimage.h" +#include "llimagebmp.h" +#include "llimagepng.h" +#include "llimagej2c.h" +#include "llimagejpeg.h" +#include "llimagetga.h" +#include "llinventorymodel.h"	// gInventory +#include "llresourcedata.h" +#include "llfloaterperms.h" +#include "llstatusbar.h" +#include "llviewercontrol.h"	// gSavedSettings +#include "llviewertexturelist.h" +#include "lluictrlfactory.h" +#include "llvfile.h" +#include "llvfs.h" +#include "llviewerinventory.h" +#include "llviewermenu.h"	// gMenuHolder +#include "llviewerparcelmgr.h" +#include "llviewerregion.h" +#include "llviewerstats.h" +#include "llviewerwindow.h" +#include "llappviewer.h" +#include "lluploaddialog.h" +#include "lltrans.h" +#include "llfloaterbuycurrency.h" + +// linden libraries +#include "llassetuploadresponders.h" +#include "lleconomy.h" +#include "llhttpclient.h" +#include "llnotificationsutil.h" +#include "llsdserialize.h" +#include "llsdutil.h" +#include "llstring.h" +#include "lltransactiontypes.h" +#include "lluuid.h" +#include "llvorbisencode.h" +#include "message.h" + +// system libraries +#include <boost/tokenizer.hpp> + +class LLFileEnableUpload : public view_listener_t +{ +	bool handleEvent(const LLSD& userdata) +	{ +		bool new_value = gStatusBar && LLGlobalEconomy::Singleton::getInstance() && (gStatusBar->getBalance() >= LLGlobalEconomy::Singleton::getInstance()->getPriceUpload()); +		return new_value; +	} +}; + +class LLFileEnableUploadModel : public view_listener_t +{ +	bool handleEvent(const LLSD& userdata) +	{ +		return true; +	} +}; + +class LLMeshEnabled : public view_listener_t +{ +	bool handleEvent(const LLSD& userdata) +	{ +		return gSavedSettings.getBOOL("MeshEnabled"); +	} +}; + +class LLMeshUploadVisible : public view_listener_t +{ +	bool handleEvent(const LLSD& userdata) +	{ +		return gMeshRepo.meshUploadEnabled(); +	} +}; + +LLMutex* LLFilePickerThread::sMutex = NULL; +std::queue<LLFilePickerThread*> LLFilePickerThread::sDeadQ; + +void LLFilePickerThread::getFile() +{ +#if LL_WINDOWS +	start(); +#else +	run(); +#endif +} + +//virtual  +void LLFilePickerThread::run() +{ +	LLFilePicker picker; +#if LL_WINDOWS +	if (picker.getOpenFile(mFilter, false)) +	{ +		mFile = picker.getFirstFile(); +	} +#else +	if (picker.getOpenFile(mFilter, true)) +	{ +		mFile = picker.getFirstFile(); +	} +#endif + +	{ +		LLMutexLock lock(sMutex); +		sDeadQ.push(this); +	} + +} + +//static +void LLFilePickerThread::initClass() +{ +	sMutex = new LLMutex(NULL); +} + +//static +void LLFilePickerThread::cleanupClass() +{ +	clearDead(); +	 +	delete sMutex; +	sMutex = NULL; +} + +//static +void LLFilePickerThread::clearDead() +{ +	if (!sDeadQ.empty()) +	{ +		LLMutexLock lock(sMutex); +		while (!sDeadQ.empty()) +		{ +			LLFilePickerThread* thread = sDeadQ.front(); +			thread->notify(thread->mFile); +			delete thread; +			sDeadQ.pop(); +		} +	} +} + + +//============================================================================ + +#if LL_WINDOWS +static std::string SOUND_EXTENSIONS = "wav"; +static std::string IMAGE_EXTENSIONS = "tga bmp jpg jpeg png"; +static std::string ANIM_EXTENSIONS =  "bvh anim"; +#ifdef _CORY_TESTING +static std::string GEOMETRY_EXTENSIONS = "slg"; +#endif +static std::string XML_EXTENSIONS = "xml"; +static std::string SLOBJECT_EXTENSIONS = "slobject"; +#endif +static std::string ALL_FILE_EXTENSIONS = "*.*"; +static std::string MODEL_EXTENSIONS = "dae"; + +std::string build_extensions_string(LLFilePicker::ELoadFilter filter) +{ +	switch(filter) +	{ +#if LL_WINDOWS +	case LLFilePicker::FFLOAD_IMAGE: +		return IMAGE_EXTENSIONS; +	case LLFilePicker::FFLOAD_WAV: +		return SOUND_EXTENSIONS; +	case LLFilePicker::FFLOAD_ANIM: +		return ANIM_EXTENSIONS; +	case LLFilePicker::FFLOAD_SLOBJECT: +		return SLOBJECT_EXTENSIONS; +	case LLFilePicker::FFLOAD_MODEL: +		return MODEL_EXTENSIONS; +#ifdef _CORY_TESTING +	case LLFilePicker::FFLOAD_GEOMETRY: +		return GEOMETRY_EXTENSIONS; +#endif +	case LLFilePicker::FFLOAD_XML: +	    return XML_EXTENSIONS; +	case LLFilePicker::FFLOAD_ALL: +		return ALL_FILE_EXTENSIONS; +#endif +    default: +	return ALL_FILE_EXTENSIONS; +	} +} + +/** +   char* upload_pick(void* data) + +   If applicable, brings up a file chooser in which the user selects a file +   to upload for a particular task.  If the file is valid for the given action, +   returns the string to the full path filename, else returns NULL. +   Data is the load filter for the type of file as defined in LLFilePicker. +**/ +const std::string upload_pick(void* data) +{ + 	if( gAgentCamera.cameraMouselook() ) +	{ +		gAgentCamera.changeCameraToDefault(); +		// This doesn't seem necessary. JC +		// display(); +	} + +	LLFilePicker::ELoadFilter type; +	if(data) +	{ +		type = (LLFilePicker::ELoadFilter)((intptr_t)data); +	} +	else +	{ +		type = LLFilePicker::FFLOAD_ALL; +	} + +	LLFilePicker& picker = LLFilePicker::instance(); +	if (!picker.getOpenFile(type)) +	{ +		llinfos << "Couldn't import objects from file" << llendl; +		return std::string(); +	} + +	 +	const std::string& filename = picker.getFirstFile(); +	std::string ext = gDirUtilp->getExtension(filename); + +	//strincmp doesn't like NULL pointers +	if (ext.empty()) +	{ +		std::string short_name = gDirUtilp->getBaseFileName(filename); +		 +		// No extension +		LLSD args; +		args["FILE"] = short_name; +		LLNotificationsUtil::add("NoFileExtension", args); +		return std::string(); +	} +	else +	{ +		//so there is an extension +		//loop over the valid extensions and compare to see +		//if the extension is valid + +		//now grab the set of valid file extensions +		std::string valid_extensions = build_extensions_string(type); + +		BOOL ext_valid = FALSE; +		 +		typedef boost::tokenizer<boost::char_separator<char> > tokenizer; +		boost::char_separator<char> sep(" "); +		tokenizer tokens(valid_extensions, sep); +		tokenizer::iterator token_iter; + +		//now loop over all valid file extensions +		//and compare them to the extension of the file +		//to be uploaded +		for( token_iter = tokens.begin(); +			 token_iter != tokens.end() && ext_valid != TRUE; +			 ++token_iter) +		{ +			const std::string& cur_token = *token_iter; + +			if (cur_token == ext || cur_token == "*.*") +			{ +				//valid extension +				//or the acceptable extension is any +				ext_valid = TRUE; +			} +		}//end for (loop over all tokens) + +		if (ext_valid == FALSE) +		{ +			//should only get here if the extension exists +			//but is invalid +			LLSD args; +			args["EXTENSION"] = ext; +			args["VALIDS"] = valid_extensions; +			LLNotificationsUtil::add("InvalidFileExtension", args); +			return std::string(); +		} +	}//end else (non-null extension) + +	//valid file extension +	 +	//now we check to see +	//if the file is actually a valid image/sound/etc. +	if (type == LLFilePicker::FFLOAD_WAV) +	{ +		// pre-qualify wavs to make sure the format is acceptable +		std::string error_msg; +		if (check_for_invalid_wav_formats(filename,error_msg)) +		{ +			llinfos << error_msg << ": " << filename << llendl; +			LLSD args; +			args["FILE"] = filename; +			LLNotificationsUtil::add( error_msg, args ); +			return std::string(); +		} +	}//end if a wave/sound file + +	 +	return filename; +} + +class LLFileUploadImage : public view_listener_t +{ +	bool handleEvent(const LLSD& userdata) +	{ +		std::string filename = upload_pick((void *)LLFilePicker::FFLOAD_IMAGE); +		if (!filename.empty()) +		{ +			LLFloaterReg::showInstance("upload_image", LLSD(filename)); +		} +		return TRUE; +	} +}; + +class LLFileUploadModel : public view_listener_t +{ +	bool handleEvent(const LLSD& userdata) +	{ +		LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) LLFloaterReg::getInstance("upload_model"); +		if (fmp) +		{ +			fmp->loadModel(3); +		} +		 +		return TRUE; +	} +}; +	 +class LLFileUploadSound : public view_listener_t +{ +	bool handleEvent(const LLSD& userdata) +	{ +		std::string filename = upload_pick((void*)LLFilePicker::FFLOAD_WAV); +		if (!filename.empty()) +		{ +			LLFloaterReg::showInstance("upload_sound", LLSD(filename)); +		} +		return true; +	} +}; + +class LLFileUploadAnim : public view_listener_t +{ +	bool handleEvent(const LLSD& userdata) +	{ +		const std::string filename = upload_pick((void*)LLFilePicker::FFLOAD_ANIM); +		if (!filename.empty()) +		{ +			if (filename.rfind(".anim") != std::string::npos) +			{ +				LLFloaterReg::showInstance("upload_anim_anim", LLSD(filename)); +			} +			else +			{ +				LLFloaterReg::showInstance("upload_anim_bvh", LLSD(filename)); +			} +		} +		return true; +	} +}; + +class LLFileUploadBulk : public view_listener_t +{ +	bool handleEvent(const LLSD& userdata) +	{ +		if( gAgentCamera.cameraMouselook() ) +		{ +			gAgentCamera.changeCameraToDefault(); +		} + +		// TODO: +		// Iterate over all files +		// Check extensions for uploadability, cost +		// Check user balance for entire cost +		// Charge user entire cost +		// Loop, uploading +		// If an upload fails, refund the user for that one +		// +		// Also fix single upload to charge first, then refund + +		LLFilePicker& picker = LLFilePicker::instance(); +		if (picker.getMultipleOpenFiles()) +		{ +			const std::string& filename = picker.getFirstFile(); +			std::string name = gDirUtilp->getBaseFileName(filename, true); +			 +			std::string asset_name = name; +			LLStringUtil::replaceNonstandardASCII( asset_name, '?' ); +			LLStringUtil::replaceChar(asset_name, '|', '?'); +			LLStringUtil::stripNonprintable(asset_name); +			LLStringUtil::trim(asset_name); +			 +			std::string display_name = LLStringUtil::null; +			LLAssetStorage::LLStoreAssetCallback callback = NULL; +			S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); +			void *userdata = NULL; + +			upload_new_resource( +				filename, +				asset_name, +				asset_name, +				0, +				LLFolderType::FT_NONE, +				LLInventoryType::IT_NONE, +				LLFloaterPerms::getNextOwnerPerms(), +				LLFloaterPerms::getGroupPerms(), +				LLFloaterPerms::getEveryonePerms(), +				display_name, +				callback, +				expected_upload_cost, +				userdata); + +			// *NOTE: Ew, we don't iterate over the file list here, +			// we handle the next files in upload_done_callback() +		} +		else +		{ +			llinfos << "Couldn't import objects from file" << llendl; +		} +		return true; +	} +}; + +void upload_error(const std::string& error_message, const std::string& label, const std::string& filename, const LLSD& args)  +{ +	llwarns << error_message << llendl; +	LLNotificationsUtil::add(label, args); +	if(LLFile::remove(filename) == -1) +	{ +		lldebugs << "unable to remove temp file" << llendl; +	} +	LLFilePicker::instance().reset();						 +} + +class LLFileEnableCloseWindow : public view_listener_t +{ +	bool handleEvent(const LLSD& userdata) +	{ +		bool new_value = NULL != LLFloater::getClosableFloaterFromFocus(); +		return new_value; +	} +}; + +class LLFileCloseWindow : public view_listener_t +{ +	bool handleEvent(const LLSD& userdata) +	{ +		LLFloater::closeFocusedFloater(); + +		return true; +	} +}; + +class LLFileEnableCloseAllWindows : public view_listener_t +{ +	bool handleEvent(const LLSD& userdata) +	{ +		bool open_children = gFloaterView->allChildrenClosed(); +		return !open_children; +	} +}; + +class LLFileCloseAllWindows : public view_listener_t +{ +	bool handleEvent(const LLSD& userdata) +	{ +		bool app_quitting = false; +		gFloaterView->closeAllChildren(app_quitting); + +		return true; +	} +}; + +class LLFileTakeSnapshotToDisk : public view_listener_t +{ +	bool handleEvent(const LLSD& userdata) +	{ +		LLPointer<LLImageRaw> raw = new LLImageRaw; + +		S32 width = gViewerWindow->getWindowWidthRaw(); +		S32 height = gViewerWindow->getWindowHeightRaw(); + +		if (gSavedSettings.getBOOL("HighResSnapshot")) +		{ +			width *= 2; +			height *= 2; +		} + +		if (gViewerWindow->rawSnapshot(raw, +									   width, +									   height, +									   TRUE, +									   FALSE, +									   gSavedSettings.getBOOL("RenderUIInSnapshot"), +									   FALSE)) +		{ +			gViewerWindow->playSnapshotAnimAndSound(); +			LLPointer<LLImageFormatted> formatted; +			LLFloaterSnapshot::ESnapshotFormat fmt = (LLFloaterSnapshot::ESnapshotFormat) gSavedSettings.getS32("SnapshotFormat"); +			switch (fmt) +			{ +			case LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG: +				formatted = new LLImageJPEG(gSavedSettings.getS32("SnapshotQuality")); +				break; +			default: +				llwarns << "Unknown local snapshot format: " << fmt << llendl; +			case LLFloaterSnapshot::SNAPSHOT_FORMAT_PNG: +				formatted = new LLImagePNG; +				break; +			case LLFloaterSnapshot::SNAPSHOT_FORMAT_BMP: +				formatted = new LLImageBMP; +				break; +			} +			formatted->enableOverSize() ; +			formatted->encode(raw, 0); +			formatted->disableOverSize() ; +			gViewerWindow->saveImageNumbered(formatted); +		} +		return true; +	} +}; + +class LLFileQuit : public view_listener_t +{ +	bool handleEvent(const LLSD& userdata) +	{ +		LLAppViewer::instance()->userQuit(); +		return true; +	} +}; + + +void handle_compress_image(void*) +{ +	LLFilePicker& picker = LLFilePicker::instance(); +	if (picker.getMultipleOpenFiles(LLFilePicker::FFLOAD_IMAGE)) +	{ +		std::string infile = picker.getFirstFile(); +		while (!infile.empty()) +		{ +			std::string outfile = infile + ".j2c"; + +			llinfos << "Input:  " << infile << llendl; +			llinfos << "Output: " << outfile << llendl; + +			BOOL success; + +			success = LLViewerTextureList::createUploadFile(infile, outfile, IMG_CODEC_TGA); + +			if (success) +			{ +				llinfos << "Compression complete" << llendl; +			} +			else +			{ +				llinfos << "Compression failed: " << LLImage::getLastError() << llendl; +			} + +			infile = picker.getNextFile(); +		} +	} +} + +LLUUID upload_new_resource( +	const std::string& src_filename, +	std::string name, +	std::string desc, +	S32 compression_info, +	LLFolderType::EType destination_folder_type, +	LLInventoryType::EType inv_type, +	U32 next_owner_perms, +	U32 group_perms, +	U32 everyone_perms, +	const std::string& display_name, +	LLAssetStorage::LLStoreAssetCallback callback, +	S32 expected_upload_cost, +	void *userdata) +{	 +	// Generate the temporary UUID. +	std::string filename = gDirUtilp->getTempFilename(); +	LLTransactionID tid; +	LLAssetID uuid; +	 +	LLSD args; + +	std::string exten = gDirUtilp->getExtension(src_filename); +	U32 codec = LLImageBase::getCodecFromExtension(exten); +	LLAssetType::EType asset_type = LLAssetType::AT_NONE; +	std::string error_message; + +	BOOL error = FALSE; +	 +	if (exten.empty()) +	{ +		std::string short_name = gDirUtilp->getBaseFileName(filename); +		 +		// No extension +		error_message = llformat( +				"No file extension for the file: '%s'\nPlease make sure the file has a correct file extension", +				short_name.c_str()); +		args["FILE"] = short_name; + 		upload_error(error_message, "NoFileExtension", filename, args); +		return LLUUID(); +	} +	else if (codec != IMG_CODEC_INVALID) +	{ +		// It's an image file, the upload procedure is the same for all +		asset_type = LLAssetType::AT_TEXTURE; +		if (!LLViewerTextureList::createUploadFile(src_filename, filename, codec )) +		{ +			error_message = llformat( "Problem with file %s:\n\n%s\n", +									 src_filename.c_str(), LLImage::getLastError().c_str()); +			args["FILE"] = src_filename; +			args["ERROR"] = LLImage::getLastError(); +			upload_error(error_message, "ProblemWithFile", filename, args); +			return LLUUID(); +		} +	} +	else if(exten == "wav") +	{ +		asset_type = LLAssetType::AT_SOUND;  // tag it as audio +		S32 encode_result = 0; + +		llinfos << "Attempting to encode wav as an ogg file" << llendl; + +		encode_result = encode_vorbis_file(src_filename, filename); +		 +		if (LLVORBISENC_NOERR != encode_result) +		{ +			switch(encode_result) +			{ +				case LLVORBISENC_DEST_OPEN_ERR: +				    error_message = llformat( "Couldn't open temporary compressed sound file for writing: %s\n", filename.c_str()); +					args["FILE"] = filename; +					upload_error(error_message, "CannotOpenTemporarySoundFile", filename, args); +					break; + +				default:	 +				  error_message = llformat("Unknown vorbis encode failure on: %s\n", src_filename.c_str()); +					args["FILE"] = src_filename; +					upload_error(error_message, "UnknownVorbisEncodeFailure", filename, args); +					break;	 +			}	 +			return LLUUID(); +		} +	} +	else if(exten == "tmp")	 	 +	{	 	 +		// This is a generic .lin resource file	 	 +         asset_type = LLAssetType::AT_OBJECT;	 	 +         LLFILE* in = LLFile::fopen(src_filename, "rb");		/* Flawfinder: ignore */	 	 +         if (in)	 	 +         {	 	 +                 // read in the file header	 	 +                 char buf[16384];		/* Flawfinder: ignore */ 	 +                 size_t readbytes; +                 S32  version;	 	 +                 if (fscanf(in, "LindenResource\nversion %d\n", &version))	 	 +                 {	 	 +                         if (2 == version)	 	 +                         { +								// *NOTE: This buffer size is hard coded into scanf() below. +                                 char label[MAX_STRING];		/* Flawfinder: ignore */	 	 +                                 char value[MAX_STRING];		/* Flawfinder: ignore */	 	 +                                 S32  tokens_read;	 	 +                                 while (fgets(buf, 1024, in))	 	 +                                 {	 	 +                                         label[0] = '\0';	 	 +                                         value[0] = '\0';	 	 +                                         tokens_read = sscanf(	/* Flawfinder: ignore */ +											 buf, +											 "%254s %254s\n", +											 label, value);	 	 + +                                         llinfos << "got: " << label << " = " << value	 	 +                                                         << llendl;	 	 + +                                         if (EOF == tokens_read)	 	 +                                         {	 	 +                                                 fclose(in);	 	 +                                                 error_message = llformat("corrupt resource file: %s", src_filename.c_str()); +												 args["FILE"] = src_filename; +												 upload_error(error_message, "CorruptResourceFile", filename, args); +                                                 return LLUUID(); +                                         }	 	 + +                                         if (2 == tokens_read)	 	 +                                         {	 	 +                                                 if (! strcmp("type", label))	 	 +                                                 {	 	 +                                                         asset_type = (LLAssetType::EType)(atoi(value));	 	 +                                                 }	 	 +                                         }	 	 +                                         else	 	 +                                         {	 	 +                                                 if (! strcmp("_DATA_", label))	 	 +                                                 {	 	 +                                                         // below is the data section	 	 +                                                         break;	 	 +                                                 }	 	 +                                         }	 	 +                                         // other values are currently discarded	 	 +                                 }	 	 + +                         }	 	 +                         else	 	 +                         {	 	 +                                 fclose(in);	 	 +                                 error_message = llformat("unknown linden resource file version in file: %s", src_filename.c_str()); +								 args["FILE"] = src_filename; +								 upload_error(error_message, "UnknownResourceFileVersion", filename, args); +                                 return LLUUID(); +                         }	 	 +                 }	 	 +                 else	 	 +                 {	 	 +                         // this is an original binary formatted .lin file	 	 +                         // start over at the beginning of the file	 	 +                         fseek(in, 0, SEEK_SET);	 	 + +                         const S32 MAX_ASSET_DESCRIPTION_LENGTH = 256;	 	 +                         const S32 MAX_ASSET_NAME_LENGTH = 64;	 	 +                         S32 header_size = 34 + MAX_ASSET_DESCRIPTION_LENGTH + MAX_ASSET_NAME_LENGTH;	 	 +                         S16     type_num;	 	 + +                         // read in and throw out most of the header except for the type	 	 +                         if (fread(buf, header_size, 1, in) != 1) +						 { +							 llwarns << "Short read" << llendl; +						 } +                         memcpy(&type_num, buf + 16, sizeof(S16));		/* Flawfinder: ignore */	 	 +                         asset_type = (LLAssetType::EType)type_num;	 	 +                 }	 	 + +                 // copy the file's data segment into another file for uploading	 	 +                 LLFILE* out = LLFile::fopen(filename, "wb");		/* Flawfinder: ignore */	 +                 if (out)	 	 +                 {	 	 +                         while((readbytes = fread(buf, 1, 16384, in)))		/* Flawfinder: ignore */	 	 +                         {	 	 +							 if (fwrite(buf, 1, readbytes, out) != readbytes) +							 { +								 llwarns << "Short write" << llendl; +							 } +                         }	 	 +                         fclose(out);	 	 +                 }	 	 +                 else	 	 +                 {	 	 +                         fclose(in);	 	 +                         error_message = llformat( "Unable to create output file: %s", filename.c_str()); +						 args["FILE"] = filename; +						 upload_error(error_message, "UnableToCreateOutputFile", filename, args); +                         return LLUUID(); +                 }	 	 + +                 fclose(in);	 	 +         }	 	 +         else	 	 +         {	 	 +                 llinfos << "Couldn't open .lin file " << src_filename << llendl;	 	 +         }	 	 +	} +	else if (exten == "bvh") +	{ +		error_message = llformat("We do not currently support bulk upload of animation files\n"); +		upload_error(error_message, "DoNotSupportBulkAnimationUpload", filename, args); +		return LLUUID(); +	} +	else if (exten == "anim") +	{ +		asset_type = LLAssetType::AT_ANIMATION; +		filename = src_filename; +	} +	else +	{ +		// Unknown extension +		error_message = llformat(LLTrans::getString("UnknownFileExtension").c_str(), exten.c_str()); +		error = TRUE;; +	} + +	// gen a new transaction ID for this asset +	tid.generate(); + +	if (!error) +	{ +		uuid = tid.makeAssetID(gAgent.getSecureSessionID()); +		// copy this file into the vfs for upload +		S32 file_size; +		LLAPRFile infile ; +		infile.open(filename, LL_APR_RB, NULL, &file_size); +		if (infile.getFileHandle()) +		{ +			LLVFile file(gVFS, uuid, asset_type, LLVFile::WRITE); + +			file.setMaxSize(file_size); + +			const S32 buf_size = 65536; +			U8 copy_buf[buf_size]; +			while ((file_size = infile.read(copy_buf, buf_size))) +			{ +				file.write(copy_buf, file_size); +			} +		} +		else +		{ +			error_message = llformat( "Unable to access output file: %s", filename.c_str()); +			error = TRUE; +		} +	} + +	if (!error) +	{ +		std::string t_disp_name = display_name; +		if (t_disp_name.empty()) +		{ +			t_disp_name = src_filename; +		} +		upload_new_resource( +			tid, +			asset_type, +			name, +			desc, +			compression_info, // tid +			destination_folder_type, +			inv_type, +			next_owner_perms, +			group_perms, +			everyone_perms, +			display_name, +			callback, +			expected_upload_cost, +			userdata); +	} +	else +	{ +		llwarns << error_message << llendl; +		LLSD args; +		args["ERROR_MESSAGE"] = error_message; +		LLNotificationsUtil::add("ErrorMessage", args); +		if(LLFile::remove(filename) == -1) +		{ +			lldebugs << "unable to remove temp file" << llendl; +		} +		LLFilePicker::instance().reset(); +	} + +	return uuid; +} + +void upload_done_callback( +	const LLUUID& uuid, +	void* user_data, +	S32 result, +	LLExtStat ext_status) // StoreAssetData callback (fixed) +{ +	LLResourceData* data = (LLResourceData*)user_data; +	S32 expected_upload_cost = data ? data->mExpectedUploadCost : 0; +	//LLAssetType::EType pref_loc = data->mPreferredLocation; +	BOOL is_balance_sufficient = TRUE; + +	if(data) +	{ +		if (result >= 0) +		{ +			LLFolderType::EType dest_loc = (data->mPreferredLocation == LLFolderType::FT_NONE) ? LLFolderType::assetTypeToFolderType(data->mAssetInfo.mType) : data->mPreferredLocation; +			 +			if (LLAssetType::AT_SOUND == data->mAssetInfo.mType || +			    LLAssetType::AT_TEXTURE == data->mAssetInfo.mType || +			    LLAssetType::AT_ANIMATION == data->mAssetInfo.mType) +			{ +				// Charge the user for the upload. +				LLViewerRegion* region = gAgent.getRegion(); +				 +				if(!(can_afford_transaction(expected_upload_cost))) +				{ +					LLStringUtil::format_map_t args; +					args["NAME"] = data->mAssetInfo.getName(); +					args["AMOUNT"] = llformat("%d", expected_upload_cost); +					LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("UploadingCosts", args), expected_upload_cost ); +					is_balance_sufficient = FALSE; +				} +				else if(region) +				{ +					// Charge user for upload +					gStatusBar->debitBalance(expected_upload_cost); +					 +					LLMessageSystem* msg = gMessageSystem; +					msg->newMessageFast(_PREHASH_MoneyTransferRequest); +					msg->nextBlockFast(_PREHASH_AgentData); +					msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); +					msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); +					msg->nextBlockFast(_PREHASH_MoneyData); +					msg->addUUIDFast(_PREHASH_SourceID, gAgent.getID()); +					msg->addUUIDFast(_PREHASH_DestID, LLUUID::null); +					msg->addU8("Flags", 0); +					// we tell the sim how much we were expecting to pay so it +					// can respond to any discrepancy +					msg->addS32Fast(_PREHASH_Amount, expected_upload_cost); +					msg->addU8Fast(_PREHASH_AggregatePermNextOwner, (U8)LLAggregatePermissions::AP_EMPTY); +					msg->addU8Fast(_PREHASH_AggregatePermInventory, (U8)LLAggregatePermissions::AP_EMPTY); +					msg->addS32Fast(_PREHASH_TransactionType, TRANS_UPLOAD_CHARGE); +					msg->addStringFast(_PREHASH_Description, NULL); +					msg->sendReliable(region->getHost()); +				} +			} + +			if(is_balance_sufficient) +			{ +				// Actually add the upload to inventory +				llinfos << "Adding " << uuid << " to inventory." << llendl; +				const LLUUID folder_id = gInventory.findCategoryUUIDForType(dest_loc); +				if(folder_id.notNull()) +				{ +					U32 next_owner_perms = data->mNextOwnerPerm; +					if(PERM_NONE == next_owner_perms) +					{ +						next_owner_perms = PERM_MOVE | PERM_TRANSFER; +					} +					create_inventory_item(gAgent.getID(), gAgent.getSessionID(), +							      folder_id, data->mAssetInfo.mTransactionID, data->mAssetInfo.getName(), +							      data->mAssetInfo.getDescription(), data->mAssetInfo.mType, +							      data->mInventoryType, NOT_WEARABLE, next_owner_perms, +							      LLPointer<LLInventoryCallback>(NULL)); +				} +				else +				{ +					llwarns << "Can't find a folder to put it in" << llendl; +				} +			} +		} +		else // 	if(result >= 0) +		{ +			LLSD args; +			args["FILE"] = LLInventoryType::lookupHumanReadable(data->mInventoryType); +			args["REASON"] = std::string(LLAssetStorage::getErrorString(result)); +			LLNotificationsUtil::add("CannotUploadReason", args); +		} +	} + +	LLUploadDialog::modalUploadFinished(); +	delete data; +	data = NULL; + +	// *NOTE: This is a pretty big hack. What this does is check the +	// file picker if there are any more pending uploads. If so, +	// upload that file. +	const std::string& next_file = LLFilePicker::instance().getNextFile(); +	if(is_balance_sufficient && !next_file.empty()) +	{ +		std::string asset_name = gDirUtilp->getBaseFileName(next_file, true); +		LLStringUtil::replaceNonstandardASCII( asset_name, '?' ); +		LLStringUtil::replaceChar(asset_name, '|', '?'); +		LLStringUtil::stripNonprintable(asset_name); +		LLStringUtil::trim(asset_name); + +		std::string display_name = LLStringUtil::null; +		LLAssetStorage::LLStoreAssetCallback callback = NULL; +		void *userdata = NULL; +		upload_new_resource( +			next_file, +			asset_name, +			asset_name,	// file +			0, +			LLFolderType::FT_NONE, +			LLInventoryType::IT_NONE, +			PERM_NONE, +			PERM_NONE, +			PERM_NONE, +			display_name, +			callback, +			expected_upload_cost, // assuming next in a group of uploads is of roughly the same type, i.e. same upload cost +			userdata); +	} +} + +static LLAssetID upload_new_resource_prep( +	const LLTransactionID& tid, +	LLAssetType::EType asset_type, +	LLInventoryType::EType& inventory_type, +	std::string& name, +	const std::string& display_name, +	std::string& description) +{ +	LLAssetID uuid = generate_asset_id_for_new_upload(tid); + +	increase_new_upload_stats(asset_type); + +	assign_defaults_and_show_upload_message( +		asset_type, +		inventory_type, +		name, +		display_name, +		description); + +	return uuid; +} + +LLSD generate_new_resource_upload_capability_body( +	LLAssetType::EType asset_type, +	const std::string& name, +	const std::string& desc, +	LLFolderType::EType destination_folder_type, +	LLInventoryType::EType inv_type, +	U32 next_owner_perms, +	U32 group_perms, +	U32 everyone_perms) +{ +	LLSD body; + +	body["folder_id"] = gInventory.findCategoryUUIDForType( +		(destination_folder_type == LLFolderType::FT_NONE) ? +		(LLFolderType::EType) asset_type : +		destination_folder_type); + +	body["asset_type"] = LLAssetType::lookup(asset_type); +	body["inventory_type"] = LLInventoryType::lookup(inv_type); +	body["name"] = name; +	body["description"] = desc; +	body["next_owner_mask"] = LLSD::Integer(next_owner_perms); +	body["group_mask"] = LLSD::Integer(group_perms); +	body["everyone_mask"] = LLSD::Integer(everyone_perms); + +	return body; +} + +void upload_new_resource( +	const LLTransactionID &tid, +	LLAssetType::EType asset_type, +	std::string name, +	std::string desc, +	S32 compression_info, +	LLFolderType::EType destination_folder_type, +	LLInventoryType::EType inv_type, +	U32 next_owner_perms, +	U32 group_perms, +	U32 everyone_perms, +	const std::string& display_name, +	LLAssetStorage::LLStoreAssetCallback callback, +	S32 expected_upload_cost, +	void *userdata) +{ +	if(gDisconnected) +	{ +		return ; +	} +	 +	LLAssetID uuid =  +		upload_new_resource_prep( +			tid, +			asset_type, +			inv_type, +			name, +			display_name, +			desc); +	 +	if( LLAssetType::AT_SOUND == asset_type ) +	{ +		LLViewerStats::getInstance()->incStat(LLViewerStats::ST_UPLOAD_SOUND_COUNT ); +	} +	else +	if( LLAssetType::AT_TEXTURE == asset_type ) +	{ +		LLViewerStats::getInstance()->incStat(LLViewerStats::ST_UPLOAD_TEXTURE_COUNT ); +	} +	else +	if( LLAssetType::AT_ANIMATION == asset_type) +	{ +		LLViewerStats::getInstance()->incStat(LLViewerStats::ST_UPLOAD_ANIM_COUNT ); +	} + +	if(LLInventoryType::IT_NONE == inv_type) +	{ +		inv_type = LLInventoryType::defaultForAssetType(asset_type); +	} +	LLStringUtil::stripNonprintable(name); +	LLStringUtil::stripNonprintable(desc); +	if(name.empty()) +	{ +		name = "(No Name)"; +	} +	if(desc.empty()) +	{ +		desc = "(No Description)"; +	} +	 +	// At this point, we're ready for the upload. +	std::string upload_message = "Uploading...\n\n"; +	upload_message.append(display_name); +	LLUploadDialog::modalUploadDialog(upload_message); + +	llinfos << "*** Uploading: " << llendl; +	llinfos << "Type: " << LLAssetType::lookup(asset_type) << llendl; +	llinfos << "UUID: " << uuid << llendl; +	llinfos << "Name: " << name << llendl; +	llinfos << "Desc: " << desc << llendl; +	llinfos << "Expected Upload Cost: " << expected_upload_cost << llendl; +	lldebugs << "Folder: " << gInventory.findCategoryUUIDForType((destination_folder_type == LLFolderType::FT_NONE) ? LLFolderType::assetTypeToFolderType(asset_type) : destination_folder_type) << llendl; +	lldebugs << "Asset Type: " << LLAssetType::lookup(asset_type) << llendl; + +	std::string url = gAgent.getRegion()->getCapability( +		"NewFileAgentInventory"); + +	if ( !url.empty() ) +	{ +		llinfos << "New Agent Inventory via capability" << llendl; + +		LLSD body; +		body = generate_new_resource_upload_capability_body( +			asset_type, +			name, +			desc, +			destination_folder_type, +			inv_type, +			next_owner_perms, +			group_perms, +			everyone_perms); + +		LLHTTPClient::post( +			url, +			body, +			new LLNewAgentInventoryResponder( +				body, +				uuid, +				asset_type)); +	} +	else +	{ +		llinfos << "NewAgentInventory capability not found, new agent inventory via asset system." << llendl; +		// check for adequate funds +		// TODO: do this check on the sim +		if (LLAssetType::AT_SOUND == asset_type || +			LLAssetType::AT_TEXTURE == asset_type || +			LLAssetType::AT_ANIMATION == asset_type) +		{ +			S32 balance = gStatusBar->getBalance(); +			if (balance < expected_upload_cost) +			{ +				// insufficient funds, bail on this upload +				LLStringUtil::format_map_t args; +				args["NAME"] = name; +				args["AMOUNT"] = llformat("%d", expected_upload_cost); +				LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("UploadingCosts", args), expected_upload_cost ); +				return; +			} +		} + +		LLResourceData* data = new LLResourceData; +		data->mAssetInfo.mTransactionID = tid; +		data->mAssetInfo.mUuid = uuid; +		data->mAssetInfo.mType = asset_type; +		data->mAssetInfo.mCreatorID = gAgentID; +		data->mInventoryType = inv_type; +		data->mNextOwnerPerm = next_owner_perms; +		data->mExpectedUploadCost = expected_upload_cost; +		data->mUserData = userdata; +		data->mAssetInfo.setName(name); +		data->mAssetInfo.setDescription(desc); +		data->mPreferredLocation = destination_folder_type; + +		LLAssetStorage::LLStoreAssetCallback asset_callback = &upload_done_callback; +		if (callback) +		{ +			asset_callback = callback; +		} +		gAssetStorage->storeAssetData( +			data->mAssetInfo.mTransactionID, +			data->mAssetInfo.mType, +			asset_callback, +			(void*)data, +			FALSE); +	} +} + +LLAssetID generate_asset_id_for_new_upload(const LLTransactionID& tid) +{ +	if ( gDisconnected ) +	{	 +		LLAssetID rv; + +		rv.setNull(); +		return rv; +	} + +	LLAssetID uuid = tid.makeAssetID(gAgent.getSecureSessionID()); + +	return uuid; +} + +void increase_new_upload_stats(LLAssetType::EType asset_type) +{ +	if ( LLAssetType::AT_SOUND == asset_type ) +	{ +		LLViewerStats::getInstance()->incStat( +			LLViewerStats::ST_UPLOAD_SOUND_COUNT ); +	} +	else if ( LLAssetType::AT_TEXTURE == asset_type ) +	{ +		LLViewerStats::getInstance()->incStat( +			LLViewerStats::ST_UPLOAD_TEXTURE_COUNT ); +	} +	else if ( LLAssetType::AT_ANIMATION == asset_type ) +	{ +		LLViewerStats::getInstance()->incStat( +			LLViewerStats::ST_UPLOAD_ANIM_COUNT ); +	} +} + +void assign_defaults_and_show_upload_message( +	LLAssetType::EType asset_type, +	LLInventoryType::EType& inventory_type, +	std::string& name, +	const std::string& display_name, +	std::string& description) +{ +	if ( LLInventoryType::IT_NONE == inventory_type ) +	{ +		inventory_type = LLInventoryType::defaultForAssetType(asset_type); +	} +	LLStringUtil::stripNonprintable(name); +	LLStringUtil::stripNonprintable(description); + +	if ( name.empty() ) +	{ +		name = "(No Name)"; +	} +	if ( description.empty() ) +	{ +		description = "(No Description)"; +	} + +	// At this point, we're ready for the upload. +	std::string upload_message = "Uploading...\n\n"; +	upload_message.append(display_name); +	LLUploadDialog::modalUploadDialog(upload_message); +} + + +void init_menu_file() +{ +	view_listener_t::addCommit(new LLFileUploadImage(), "File.UploadImage"); +	view_listener_t::addCommit(new LLFileUploadSound(), "File.UploadSound"); +	view_listener_t::addCommit(new LLFileUploadAnim(), "File.UploadAnim"); +	view_listener_t::addCommit(new LLFileUploadModel(), "File.UploadModel"); +	view_listener_t::addCommit(new LLFileUploadBulk(), "File.UploadBulk"); +	view_listener_t::addCommit(new LLFileCloseWindow(), "File.CloseWindow"); +	view_listener_t::addCommit(new LLFileCloseAllWindows(), "File.CloseAllWindows"); +	view_listener_t::addEnable(new LLFileEnableCloseWindow(), "File.EnableCloseWindow"); +	view_listener_t::addEnable(new LLFileEnableCloseAllWindows(), "File.EnableCloseAllWindows"); +	view_listener_t::addCommit(new LLFileTakeSnapshotToDisk(), "File.TakeSnapshotToDisk"); +	view_listener_t::addCommit(new LLFileQuit(), "File.Quit"); + +	view_listener_t::addEnable(new LLFileEnableUpload(), "File.EnableUpload"); +	view_listener_t::addEnable(new LLFileEnableUploadModel(), "File.EnableUploadModel"); +	view_listener_t::addMenu(new LLMeshEnabled(), "File.MeshEnabled"); +	view_listener_t::addMenu(new LLMeshUploadVisible(), "File.VisibleUploadModel"); + +	// "File.SaveTexture" moved to llpanelmaininventory so that it can be properly handled. +} diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 05f1be5de5..92c665d9c1 100755 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -4735,7 +4735,7 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data)  				LLViewerObject* object = gObjectList.findObject(object_id);  				if (object)  				{ -					object->setFlags(FLAGS_ANIM_SOURCE, TRUE); +					object->setFlagsWithoutUpdate(FLAGS_ANIM_SOURCE, TRUE);  					BOOL anim_found = FALSE;  					LLVOAvatar::AnimSourceIterator anim_it = avatarp->mAnimationSources.find(object_id); @@ -4882,7 +4882,7 @@ void process_set_follow_cam_properties(LLMessageSystem *mesgsys, void **user_dat  	LLViewerObject* objectp = gObjectList.findObject(source_id);  	if (objectp)  	{ -		objectp->setFlags(FLAGS_CAMERA_SOURCE, TRUE); +		objectp->setFlagsWithoutUpdate(FLAGS_CAMERA_SOURCE, TRUE);  	}  	S32 num_objects = mesgsys->getNumberOfBlocks("CameraProperty"); diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 48351f4575..a821a7e482 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -5378,6 +5378,19 @@ void LLViewerObject::updateFlags(BOOL physics_changed)  BOOL LLViewerObject::setFlags(U32 flags, BOOL state)  { +	BOOL setit = setFlagsWithoutUpdate(flags, state); + +	// BUG: Sometimes viewer physics and simulator physics get +	// out of sync.  To fix this, always send update to simulator. +// 	if (setit) +	{ +		updateFlags(); +	} +	return setit; +} + +BOOL LLViewerObject::setFlagsWithoutUpdate(U32 flags, BOOL state) +{  	BOOL setit = FALSE;  	if (state)  	{ @@ -5395,13 +5408,6 @@ BOOL LLViewerObject::setFlags(U32 flags, BOOL state)  			setit = TRUE;  		}  	} - -	// BUG: Sometimes viewer physics and simulator physics get -	// out of sync.  To fix this, always send update to simulator. -// 	if (setit) -	{ -		updateFlags(); -	}  	return setit;  } diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index ee1bac28ca..192121c021 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -513,6 +513,7 @@ public:  	void updateFlags(BOOL physics_changed = FALSE);  	BOOL setFlags(U32 flag, BOOL state); +	BOOL setFlagsWithoutUpdate(U32 flag, BOOL state);  	void setPhysicsShapeType(U8 type);  	void setPhysicsGravity(F32 gravity);  	void setPhysicsFriction(F32 friction); diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index fc04546bb8..243231c65a 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -1523,7 +1523,6 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)  	capabilityNames.append("MapLayerGod");  	capabilityNames.append("MeshUploadFlag");	  	capabilityNames.append("NavMeshGenerationStatus"); -	capabilityNames.append("NavMeshUpload");  	capabilityNames.append("NewFileAgentInventory");  	capabilityNames.append("ObjectNavMeshProperties");  	capabilityNames.append("ParcelPropertiesUpdate"); @@ -1562,6 +1561,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)  	capabilityNames.append("ViewerMetrics");  	capabilityNames.append("ViewerStartAuction");  	capabilityNames.append("ViewerStats"); +  	// Please add new capabilities alphabetically to reduce  	// merge conflicts.  } diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index c505936097..c4233dbe8d 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -758,7 +758,7 @@ void LLVOAvatarSelf::stopMotionFromSource(const LLUUID& source_id)  	LLViewerObject* object = gObjectList.findObject(source_id);  	if (object)  	{ -		object->setFlags(FLAGS_ANIM_SOURCE, FALSE); +		object->setFlagsWithoutUpdate(FLAGS_ANIM_SOURCE, FALSE);  	}  } diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index fb1709f28d..7fbc5975f3 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -681,7 +681,6 @@              <menu_item_check.on_enable               function="Build.Enabled" />         </menu_item_check> -	            <menu            create_jump_keys="true"            label="Select Build Tool" @@ -1162,14 +1161,6 @@              <menu_item_call.on_visible              function="File.VisibleUploadModel"/>              </menu_item_call> -          <menu_item_call -            label="BuildNavMeshTest" -            layout="topleft" -            name="BuildNavMesh"> -            <menu_item_call.on_click -             function="File.UploadNavMesh" -             parameter="" /> -          </menu_item_call>  	   <menu_item_call               label="Bulk (L$[COST] per file)..."               layout="topleft"  | 
