diff options
Diffstat (limited to 'indra/llrender')
| -rw-r--r-- | indra/llrender/CMakeLists.txt | 15 | ||||
| -rw-r--r-- | indra/llrender/llglslshader.h | 2 | ||||
| -rw-r--r-- | indra/llrender/llgltexture.cpp | 396 | ||||
| -rw-r--r-- | indra/llrender/llgltexture.h | 196 | ||||
| -rw-r--r-- | indra/llrender/llrender2dutils.cpp | 1621 | ||||
| -rw-r--r-- | indra/llrender/llrender2dutils.h | 164 | ||||
| -rw-r--r-- | indra/llrender/lltexture.h | 7 | ||||
| -rw-r--r-- | indra/llrender/lluiimage.cpp | 199 | ||||
| -rw-r--r-- | indra/llrender/lluiimage.h | 124 | 
9 files changed, 2719 insertions, 5 deletions
| diff --git a/indra/llrender/CMakeLists.txt b/indra/llrender/CMakeLists.txt index 516af93316..d47129a67b 100644 --- a/indra/llrender/CMakeLists.txt +++ b/indra/llrender/CMakeLists.txt @@ -34,12 +34,15 @@ set(llrender_SOURCE_FILES      llfontregistry.cpp      llgldbg.cpp      llglslshader.cpp +    llgltexture.cpp      llimagegl.cpp      llpostprocess.cpp +    llrender2dutils.cpp      llrendernavprim.cpp      llrendersphere.cpp      llshadermgr.cpp      lltexture.cpp +    lluiimage.cpp      llvertexbuffer.cpp      ) @@ -56,14 +59,17 @@ set(llrender_HEADER_FILES      llglheaders.h      llglslshader.h      llglstates.h +    llgltexture.h      llgltypes.h      llimagegl.h      llpostprocess.h      llrender.h +    llrender2dutils.h      llrendernavprim.h      llrendersphere.h      llshadermgr.h      lltexture.h +    lluiimage.h      llvertexbuffer.h      ) @@ -99,6 +105,13 @@ add_library (llrender ${llrender_SOURCE_FILES})  # Libraries on which this library depends, needed for Linux builds  # Sort by high-level to low-level  target_link_libraries(llrender  -    llimage  +    ${LLCOMMON_INCLUDE_DIRS} +    ${LLIMAGE_INCLUDE_DIRS} +    ${LLMATH_INCLUDE_DIRS} +    ${LLRENDER_INCLUDE_DIRS} +    ${LLVFS_INCLUDE_DIRS} +    ${LLXML_INCLUDE_DIRS} +    ${LLVFS_INCLUDE_DIRS} +    ${LLWINDOW_LIBRARIES}      ${FREETYPE_LIBRARIES}      ${OPENGL_LIBRARIES}) diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h index 5c68cb46eb..cf21101e35 100644 --- a/indra/llrender/llglslshader.h +++ b/indra/llrender/llglslshader.h @@ -159,6 +159,8 @@ public:  extern LLGLSLShader			gUIProgram;  //output vec4(color.rgb,color.a*tex0[tc0].a)  extern LLGLSLShader			gSolidColorProgram; +//Alpha mask shader (declared here so llappearance can access properly) +extern LLGLSLShader			gAlphaMaskProgram;  #endif diff --git a/indra/llrender/llgltexture.cpp b/indra/llrender/llgltexture.cpp new file mode 100644 index 0000000000..d06ed5e57b --- /dev/null +++ b/indra/llrender/llgltexture.cpp @@ -0,0 +1,396 @@ +/**  + * @file llgltexture.cpp + * @brief Opengl texture implementation + * + * $LicenseInfo:firstyear=2000&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 "llgltexture.h" + + +// static +S32 LLGLTexture::getTotalNumOfCategories()  +{ +	return MAX_GL_IMAGE_CATEGORY - (BOOST_HIGH - BOOST_SCULPTED) + 2 ; +} + +// static +//index starts from zero. +S32 LLGLTexture::getIndexFromCategory(S32 category)  +{ +	return (category < BOOST_HIGH) ? category : category - (BOOST_HIGH - BOOST_SCULPTED) + 1 ; +} + +//static  +S32 LLGLTexture::getCategoryFromIndex(S32 index) +{ +	return (index < BOOST_HIGH) ? index : index + (BOOST_HIGH - BOOST_SCULPTED) - 1 ; +} + +LLGLTexture::LLGLTexture(BOOL usemipmaps) +{ +	init(); +	mUseMipMaps = usemipmaps; +} + +LLGLTexture::LLGLTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps) +{ +	init(); +	mFullWidth = width ; +	mFullHeight = height ; +	mUseMipMaps = usemipmaps; +	mComponents = components ; +	setTexelsPerImage(); +} + +LLGLTexture::LLGLTexture(const LLImageRaw* raw, BOOL usemipmaps) +{ +	init(); +	mUseMipMaps = usemipmaps ; +	// Create an empty image of the specified size and width +	mGLTexturep = new LLImageGL(raw, usemipmaps) ; +} + +LLGLTexture::~LLGLTexture() +{ +	cleanup(); +} + +void LLGLTexture::init() +{ +	mBoostLevel = LLGLTexture::BOOST_NONE; + +	mFullWidth = 0; +	mFullHeight = 0; +	mTexelsPerImage = 0 ; +	mUseMipMaps = FALSE ; +	mComponents = 0 ; + +	mTextureState = NO_DELETE ; +	mDontDiscard = FALSE; +	mNeedsGLTexture = FALSE ; +} + +void LLGLTexture::cleanup() +{ +	if(mGLTexturep) +	{ +		mGLTexturep->cleanup(); +	} +} + +// virtual +void LLGLTexture::dump() +{ +	if(mGLTexturep) +	{ +		mGLTexturep->dump(); +	} +} + +void LLGLTexture::setBoostLevel(S32 level) +{ +	if(mBoostLevel != level) +	{ +		mBoostLevel = level ; +		if(mBoostLevel != LLGLTexture::BOOST_NONE) +		{ +			setNoDelete() ;		 +		} +	} +} + +void LLGLTexture::forceActive() +{ +	mTextureState = ACTIVE ;  +} + +void LLGLTexture::setActive()  +{  +	if(mTextureState != NO_DELETE) +	{ +		mTextureState = ACTIVE ;  +	} +} + +//set the texture to stay in memory +void LLGLTexture::setNoDelete()  +{  +	mTextureState = NO_DELETE ; +} + +void LLGLTexture::generateGLTexture()  +{	 +	if(mGLTexturep.isNull()) +	{ +		mGLTexturep = new LLImageGL(mFullWidth, mFullHeight, mComponents, mUseMipMaps) ; +	} +} + +LLImageGL* LLGLTexture::getGLTexture() const +{ +	llassert(mGLTexturep.notNull()) ; + +	return mGLTexturep ; +} + +BOOL LLGLTexture::createGLTexture()  +{ +	if(mGLTexturep.isNull()) +	{ +		generateGLTexture() ; +	} + +	return mGLTexturep->createGLTexture() ; +} + +BOOL LLGLTexture::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename, BOOL to_create, S32 category) +{ +	llassert(mGLTexturep.notNull()) ;	 + +	BOOL ret = mGLTexturep->createGLTexture(discard_level, imageraw, usename, to_create, category) ; + +	if(ret) +	{ +		mFullWidth = mGLTexturep->getCurrentWidth() ; +		mFullHeight = mGLTexturep->getCurrentHeight() ;  +		mComponents = mGLTexturep->getComponents() ;	 +		setTexelsPerImage(); +	} + +	return ret ; +} + +void LLGLTexture::setExplicitFormat(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format, BOOL swap_bytes) +{ +	llassert(mGLTexturep.notNull()) ; +	 +	mGLTexturep->setExplicitFormat(internal_format, primary_format, type_format, swap_bytes) ; +} +void LLGLTexture::setAddressMode(LLTexUnit::eTextureAddressMode mode) +{ +	llassert(mGLTexturep.notNull()) ; +	mGLTexturep->setAddressMode(mode) ; +} +void LLGLTexture::setFilteringOption(LLTexUnit::eTextureFilterOptions option) +{ +	llassert(mGLTexturep.notNull()) ; +	mGLTexturep->setFilteringOption(option) ; +} + +//virtual +S32	LLGLTexture::getWidth(S32 discard_level) const +{ +	llassert(mGLTexturep.notNull()) ; +	return mGLTexturep->getWidth(discard_level) ; +} + +//virtual +S32	LLGLTexture::getHeight(S32 discard_level) const +{ +	llassert(mGLTexturep.notNull()) ; +	return mGLTexturep->getHeight(discard_level) ; +} + +S32 LLGLTexture::getMaxDiscardLevel() const +{ +	llassert(mGLTexturep.notNull()) ; +	return mGLTexturep->getMaxDiscardLevel() ; +} +S32 LLGLTexture::getDiscardLevel() const +{ +	llassert(mGLTexturep.notNull()) ; +	return mGLTexturep->getDiscardLevel() ; +} +S8  LLGLTexture::getComponents() const  +{  +	llassert(mGLTexturep.notNull()) ; +	 +	return mGLTexturep->getComponents() ; +} + +LLGLuint LLGLTexture::getTexName() const  +{  +	llassert(mGLTexturep.notNull()) ; + +	return mGLTexturep->getTexName() ;  +} + +BOOL LLGLTexture::hasGLTexture() const  +{ +	if(mGLTexturep.notNull()) +	{ +		return mGLTexturep->getHasGLTexture() ; +	} +	return FALSE ; +} + +BOOL LLGLTexture::getBoundRecently() const +{ +	if(mGLTexturep.notNull()) +	{ +		return mGLTexturep->getBoundRecently() ; +	} +	return FALSE ; +} + +LLTexUnit::eTextureType LLGLTexture::getTarget(void) const +{ +	llassert(mGLTexturep.notNull()) ; +	return mGLTexturep->getTarget() ; +} + +BOOL LLGLTexture::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height) +{ +	llassert(mGLTexturep.notNull()) ; + +	return mGLTexturep->setSubImage(imageraw, x_pos, y_pos, width, height) ; +} + +BOOL LLGLTexture::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height) +{ +	llassert(mGLTexturep.notNull()) ; + +	return mGLTexturep->setSubImage(datap, data_width, data_height, x_pos, y_pos, width, height) ; +} + +void LLGLTexture::setGLTextureCreated (bool initialized) +{ +	llassert(mGLTexturep.notNull()) ; + +	mGLTexturep->setGLTextureCreated (initialized) ; +} + +void  LLGLTexture::setCategory(S32 category)  +{ +	llassert(mGLTexturep.notNull()) ; + +	mGLTexturep->setCategory(category) ; +} + +LLTexUnit::eTextureAddressMode LLGLTexture::getAddressMode(void) const +{ +	llassert(mGLTexturep.notNull()) ; + +	return mGLTexturep->getAddressMode() ; +} + +S32 LLGLTexture::getTextureMemory() const +{ +	llassert(mGLTexturep.notNull()) ; + +	return mGLTexturep->mTextureMemory ; +} + +LLGLenum LLGLTexture::getPrimaryFormat() const +{ +	llassert(mGLTexturep.notNull()) ; + +	return mGLTexturep->getPrimaryFormat() ; +} + +BOOL LLGLTexture::getIsAlphaMask() const +{ +	llassert(mGLTexturep.notNull()) ; + +	return mGLTexturep->getIsAlphaMask() ; +} + +BOOL LLGLTexture::getMask(const LLVector2 &tc) +{ +	llassert(mGLTexturep.notNull()) ; + +	return mGLTexturep->getMask(tc) ; +} + +F32 LLGLTexture::getTimePassedSinceLastBound() +{ +	llassert(mGLTexturep.notNull()) ; + +	return mGLTexturep->getTimePassedSinceLastBound() ; +} +BOOL LLGLTexture::getMissed() const  +{ +	llassert(mGLTexturep.notNull()) ; + +	return mGLTexturep->getMissed() ; +} + +BOOL LLGLTexture::isJustBound() const +{ +	llassert(mGLTexturep.notNull()) ; + +	return mGLTexturep->isJustBound() ; +} + +void LLGLTexture::forceUpdateBindStats(void) const +{ +	llassert(mGLTexturep.notNull()) ; + +	return mGLTexturep->forceUpdateBindStats() ; +} + +U32 LLGLTexture::getTexelsInAtlas() const +{ +	llassert(mGLTexturep.notNull()) ; + +	return mGLTexturep->getTexelsInAtlas() ; +} + +U32 LLGLTexture::getTexelsInGLTexture() const +{ +	llassert(mGLTexturep.notNull()) ; + +	return mGLTexturep->getTexelsInGLTexture() ; +} + +BOOL LLGLTexture::isGLTextureCreated() const +{ +	llassert(mGLTexturep.notNull()) ; + +	return mGLTexturep->isGLTextureCreated() ; +} + +S32  LLGLTexture::getDiscardLevelInAtlas() const +{ +	llassert(mGLTexturep.notNull()) ; + +	return mGLTexturep->getDiscardLevelInAtlas() ; +} + +void LLGLTexture::destroyGLTexture()  +{ +	if(mGLTexturep.notNull() && mGLTexturep->getHasGLTexture()) +	{ +		mGLTexturep->destroyGLTexture() ; +		mTextureState = DELETED ; +	} +} + +void LLGLTexture::setTexelsPerImage() +{ +	S32 fullwidth = llmin(mFullWidth,(S32)MAX_IMAGE_SIZE_DEFAULT); +	S32 fullheight = llmin(mFullHeight,(S32)MAX_IMAGE_SIZE_DEFAULT); +	mTexelsPerImage = (F32)fullwidth * fullheight; +} + + diff --git a/indra/llrender/llgltexture.h b/indra/llrender/llgltexture.h new file mode 100644 index 0000000000..b1efe77519 --- /dev/null +++ b/indra/llrender/llgltexture.h @@ -0,0 +1,196 @@ +/**  + * @file llglviewertexture.h + * @brief Object for managing opengl textures + * + * $LicenseInfo:firstyear=2012&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$ + */ + + +#ifndef LL_GL_TEXTURE_H +#define LL_GL_TEXTURE_H + +#include "lltexture.h" +#include "llgl.h" + +class LLImageRaw; + +// +//this the parent for the class LLViewerTexture +//through the following virtual functions, the class LLViewerTexture can be reached from /llrender. +// +class LLGLTexture : public LLTexture +{ +public: +	enum +	{ +		MAX_IMAGE_SIZE_DEFAULT = 1024, +		INVALID_DISCARD_LEVEL = 0x7fff +	}; + +	enum EBoostLevel +	{ +		BOOST_NONE 			= 0, +		BOOST_AVATAR_BAKED	, +		BOOST_AVATAR		, +		BOOST_CLOUDS		, +		BOOST_SCULPTED      , +		 +		BOOST_HIGH 			= 10, +		BOOST_BUMP          , +		BOOST_TERRAIN		, // has to be high priority for minimap / low detail +		BOOST_SELECTED		,		 +		BOOST_AVATAR_BAKED_SELF	, +		BOOST_AVATAR_SELF	, // needed for baking avatar +		BOOST_SUPER_HIGH    , //textures higher than this need to be downloaded at the required resolution without delay. +		BOOST_HUD			, +		BOOST_ICON			, +		BOOST_UI			, +		BOOST_PREVIEW		, +		BOOST_MAP			, +		BOOST_MAP_VISIBLE	,		 +		BOOST_MAX_LEVEL, + +		//other texture Categories +		LOCAL = BOOST_MAX_LEVEL, +		AVATAR_SCRATCH_TEX, +		DYNAMIC_TEX, +		MEDIA, +		ATLAS, +		OTHER, +		MAX_GL_IMAGE_CATEGORY +	}; + +	static S32 getTotalNumOfCategories() ; +	static S32 getIndexFromCategory(S32 category) ; +	static S32 getCategoryFromIndex(S32 index) ; + +protected: +	virtual ~LLGLTexture(); +	LOG_CLASS(LLGLTexture); + +public: +	LLGLTexture(BOOL usemipmaps = TRUE); +	LLGLTexture(const LLImageRaw* raw, BOOL usemipmaps) ; +	LLGLTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps) ; + +	virtual void dump();	// debug info to llinfos + +	virtual const LLUUID& getID() const = 0; + +	void setBoostLevel(S32 level); +	S32  getBoostLevel() { return mBoostLevel; } + +	S32 getFullWidth() const { return mFullWidth; } +	S32 getFullHeight() const { return mFullHeight; }	 + +	void generateGLTexture() ; +	void destroyGLTexture() ; + +	//--------------------------------------------------------------------------------------------- +	//functions to access LLImageGL +	//--------------------------------------------------------------------------------------------- +	/*virtual*/S32	       getWidth(S32 discard_level = -1) const; +	/*virtual*/S32	       getHeight(S32 discard_level = -1) const; + +	BOOL       hasGLTexture() const ; +	LLGLuint   getTexName() const ;		 +	BOOL       createGLTexture() ; +	BOOL       createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE, S32 category = LLGLTexture::OTHER); + +	void       setFilteringOption(LLTexUnit::eTextureFilterOptions option); +	void       setExplicitFormat(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format = 0, BOOL swap_bytes = FALSE); +	void       setAddressMode(LLTexUnit::eTextureAddressMode mode); +	BOOL       setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height); +	BOOL       setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height); +	void       setGLTextureCreated (bool initialized); +	void       setCategory(S32 category) ; + +	LLTexUnit::eTextureAddressMode getAddressMode(void) const ; +	S32        getMaxDiscardLevel() const; +	S32        getDiscardLevel() const; +	S8         getComponents() const; +	BOOL       getBoundRecently() const; +	S32        getTextureMemory() const ; +	LLGLenum   getPrimaryFormat() const; +	BOOL       getIsAlphaMask() const ; +	LLTexUnit::eTextureType getTarget(void) const ; +	BOOL       getMask(const LLVector2 &tc); +	F32        getTimePassedSinceLastBound(); +	BOOL       getMissed() const ; +	BOOL       isJustBound()const ; +	void       forceUpdateBindStats(void) const; + +	U32        getTexelsInAtlas() const ; +	U32        getTexelsInGLTexture() const ; +	BOOL       isGLTextureCreated() const ; +	S32        getDiscardLevelInAtlas() const ; +	//--------------------------------------------------------------------------------------------- +	//end of functions to access LLImageGL +	//--------------------------------------------------------------------------------------------- + +	//----------------- +	/*virtual*/ void setActive() ; +	void forceActive() ; +	void setNoDelete() ; +	void dontDiscard() { mDontDiscard = 1; mTextureState = NO_DELETE; } +	BOOL getDontDiscard() const { return mDontDiscard; } +	//-----------------	 + +private: +	void cleanup(); +	void init(); + +protected: +	void setTexelsPerImage(); + +	//note: do not make this function public. +	/*virtual*/ LLImageGL* getGLTexture() const ; + +protected: +	S32 mBoostLevel;				// enum describing priority level +	S32 mFullWidth; +	S32 mFullHeight; +	BOOL mUseMipMaps; +	S8  mComponents; +	F32 mTexelsPerImage;			// Texels per image. +	mutable S8  mNeedsGLTexture; + +	//GL texture +	LLPointer<LLImageGL> mGLTexturep ; +	S8 mDontDiscard;			// Keep full res version of this image (for UI, etc) + +protected: +	typedef enum  +	{ +		DELETED = 0,         //removed from memory +		DELETION_CANDIDATE,  //ready to be removed from memory +		INACTIVE,            //not be used for the last certain period (i.e., 30 seconds). +		ACTIVE,              //just being used, can become inactive if not being used for a certain time (10 seconds). +		NO_DELETE = 99       //stay in memory, can not be removed. +	} LLGLTextureState; +	LLGLTextureState  mTextureState ; + + +}; + +#endif // LL_GL_TEXTURE_H + diff --git a/indra/llrender/llrender2dutils.cpp b/indra/llrender/llrender2dutils.cpp new file mode 100644 index 0000000000..b2679176be --- /dev/null +++ b/indra/llrender/llrender2dutils.cpp @@ -0,0 +1,1621 @@ +/**  + * @file llrender2dutils.cpp + * @brief GL function implementations for immediate-mode gl drawing. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + *  + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +// Linden library includes +#include "v2math.h" +#include "m3math.h" +#include "v4color.h" +#include "llfontgl.h" +#include "llrender.h" +#include "llrect.h" +#include "llgl.h" +#include "lltexture.h" + +// Project includes +#include "llrender2dutils.h" +#include "lluiimage.h" + + +// +// Globals +// +const LLColor4 UI_VERTEX_COLOR(1.f, 1.f, 1.f, 1.f); +/*static*/ LLVector2		LLRender2D::sGLScaleFactor(1.f, 1.f); +/*static*/ LLImageProviderInterface* LLRender2D::sImageProvider = NULL; + +// +// Functions +// + +BOOL ui_point_in_rect(S32 x, S32 y, S32 left, S32 top, S32 right, S32 bottom) +{ +	if (x < left || right < x) return FALSE; +	if (y < bottom || top < y) return FALSE; +	return TRUE; +} + + +// Puts GL into 2D drawing mode by turning off lighting, setting to an +// orthographic projection, etc. +void gl_state_for_2d(S32 width, S32 height) +{ +	stop_glerror(); +	F32 window_width = (F32) width;//gViewerWindow->getWindowWidth(); +	F32 window_height = (F32) height;//gViewerWindow->getWindowHeight(); + +	gGL.matrixMode(LLRender::MM_PROJECTION); +	gGL.loadIdentity(); +	gGL.ortho(0.0f, llmax(window_width, 1.f), 0.0f, llmax(window_height,1.f), -1.0f, 1.0f); +	gGL.matrixMode(LLRender::MM_MODELVIEW); +	gGL.loadIdentity(); +	stop_glerror(); +} + + +void gl_draw_x(const LLRect& rect, const LLColor4& color) +{ +	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + +	gGL.color4fv( color.mV ); + +	gGL.begin( LLRender::LINES ); +		gGL.vertex2i( rect.mLeft,		rect.mTop ); +		gGL.vertex2i( rect.mRight,	rect.mBottom ); +		gGL.vertex2i( rect.mLeft,		rect.mBottom ); +		gGL.vertex2i( rect.mRight,	rect.mTop ); +	gGL.end(); +} + + +void gl_rect_2d_offset_local( S32 left, S32 top, S32 right, S32 bottom, const LLColor4 &color, S32 pixel_offset, BOOL filled) +{ +	gGL.color4fv(color.mV); +	gl_rect_2d_offset_local(left, top, right, bottom, pixel_offset, filled); +} + +void gl_rect_2d_offset_local( S32 left, S32 top, S32 right, S32 bottom, S32 pixel_offset, BOOL filled) +{ +	gGL.pushUIMatrix(); +	left += LLFontGL::sCurOrigin.mX; +	right += LLFontGL::sCurOrigin.mX; +	bottom += LLFontGL::sCurOrigin.mY; +	top += LLFontGL::sCurOrigin.mY; + +	gGL.loadUIIdentity(); +	gl_rect_2d(llfloor((F32)left * LLRender2D::sGLScaleFactor.mV[VX]) - pixel_offset, +				llfloor((F32)top * LLRender2D::sGLScaleFactor.mV[VY]) + pixel_offset, +				llfloor((F32)right * LLRender2D::sGLScaleFactor.mV[VX]) + pixel_offset, +				llfloor((F32)bottom * LLRender2D::sGLScaleFactor.mV[VY]) - pixel_offset, +				filled); +	gGL.popUIMatrix(); +} + + +void gl_rect_2d(S32 left, S32 top, S32 right, S32 bottom, BOOL filled ) +{ +	stop_glerror(); +	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + +	// Counterclockwise quad will face the viewer +	if( filled ) +	{  +		gGL.begin( LLRender::QUADS ); +			gGL.vertex2i(left, top); +			gGL.vertex2i(left, bottom); +			gGL.vertex2i(right, bottom); +			gGL.vertex2i(right, top); +		gGL.end(); +	} +	else +	{ +		if( gGLManager.mATIOffsetVerticalLines ) +		{ +			// Work around bug in ATI driver: vertical lines are offset by (-1,-1) +			gGL.begin( LLRender::LINES ); + +				// Verticals  +				gGL.vertex2i(left + 1, top); +				gGL.vertex2i(left + 1, bottom); + +				gGL.vertex2i(right, bottom); +				gGL.vertex2i(right, top); + +				// Horizontals +				top--; +				right--; +				gGL.vertex2i(left, bottom); +				gGL.vertex2i(right, bottom); + +				gGL.vertex2i(left, top); +				gGL.vertex2i(right, top); +			gGL.end(); +		} +		else +		{ +			top--; +			right--; +			gGL.begin( LLRender::LINE_STRIP ); +				gGL.vertex2i(left, top); +				gGL.vertex2i(left, bottom); +				gGL.vertex2i(right, bottom); +				gGL.vertex2i(right, top); +				gGL.vertex2i(left, top); +			gGL.end(); +		} +	} +	stop_glerror(); +} + +void gl_rect_2d(S32 left, S32 top, S32 right, S32 bottom, const LLColor4 &color, BOOL filled ) +{ +	gGL.color4fv( color.mV ); +	gl_rect_2d( left, top, right, bottom, filled ); +} + + +void gl_rect_2d( const LLRect& rect, const LLColor4& color, BOOL filled ) +{ +	gGL.color4fv( color.mV ); +	gl_rect_2d( rect.mLeft, rect.mTop, rect.mRight, rect.mBottom, filled ); +} + +// Given a rectangle on the screen, draws a drop shadow _outside_ +// the right and bottom edges of it.  Along the right it has width "lines" +// and along the bottom it has height "lines". +void gl_drop_shadow(S32 left, S32 top, S32 right, S32 bottom, const LLColor4 &start_color, S32 lines) +{ +	stop_glerror(); +	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); +	 +	// HACK: Overlap with the rectangle by a single pixel. +	right--; +	bottom++; +	lines++; + +	LLColor4 end_color = start_color; +	end_color.mV[VALPHA] = 0.f; + +	gGL.begin(LLRender::QUADS); + +	// Right edge, CCW faces screen +	gGL.color4fv(start_color.mV); +	gGL.vertex2i(right,		top-lines); +	gGL.vertex2i(right,		bottom); +	gGL.color4fv(end_color.mV); +	gGL.vertex2i(right+lines, bottom); +	gGL.vertex2i(right+lines, top-lines); + +	// Bottom edge, CCW faces screen +	gGL.color4fv(start_color.mV); +	gGL.vertex2i(right,		bottom); +	gGL.vertex2i(left+lines,	bottom); +	gGL.color4fv(end_color.mV); +	gGL.vertex2i(left+lines,	bottom-lines); +	gGL.vertex2i(right,		bottom-lines); + +	// bottom left Corner +	gGL.color4fv(start_color.mV); +	gGL.vertex2i(left+lines,	bottom); +	gGL.color4fv(end_color.mV); +	gGL.vertex2i(left,		bottom); +	// make the bottom left corner not sharp +	gGL.vertex2i(left+1,		bottom-lines+1); +	gGL.vertex2i(left+lines,	bottom-lines); + +	// bottom right corner +	gGL.color4fv(start_color.mV); +	gGL.vertex2i(right,		bottom); +	gGL.color4fv(end_color.mV); +	gGL.vertex2i(right,		bottom-lines); +	// make the rightmost corner not sharp +	gGL.vertex2i(right+lines-1,	bottom-lines+1); +	gGL.vertex2i(right+lines,	bottom); + +	// top right corner +	gGL.color4fv(start_color.mV); +	gGL.vertex2i( right,			top-lines ); +	gGL.color4fv(end_color.mV); +	gGL.vertex2i( right+lines,	top-lines ); +	// make the corner not sharp +	gGL.vertex2i( right+lines-1,	top-1 ); +	gGL.vertex2i( right,			top ); + +	gGL.end(); +	stop_glerror(); +} + +void gl_line_2d(S32 x1, S32 y1, S32 x2, S32 y2 ) +{ +	// Work around bug in ATI driver: vertical lines are offset by (-1,-1) +	if( (x1 == x2) && gGLManager.mATIOffsetVerticalLines ) +	{ +		x1++; +		x2++; +		y1++; +		y2++; +	} + +	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); +	 +	gGL.begin(LLRender::LINES); +		gGL.vertex2i(x1, y1); +		gGL.vertex2i(x2, y2); +	gGL.end(); +} + +void gl_line_2d(S32 x1, S32 y1, S32 x2, S32 y2, const LLColor4 &color ) +{ +	// Work around bug in ATI driver: vertical lines are offset by (-1,-1) +	if( (x1 == x2) && gGLManager.mATIOffsetVerticalLines ) +	{ +		x1++; +		x2++; +		y1++; +		y2++; +	} + +	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + +	gGL.color4fv( color.mV ); + +	gGL.begin(LLRender::LINES); +		gGL.vertex2i(x1, y1); +		gGL.vertex2i(x2, y2); +	gGL.end(); +} + +void gl_triangle_2d(S32 x1, S32 y1, S32 x2, S32 y2, S32 x3, S32 y3, const LLColor4& color, BOOL filled) +{ +	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + +	gGL.color4fv(color.mV); + +	if (filled) +	{ +		gGL.begin(LLRender::TRIANGLES); +	} +	else +	{ +		gGL.begin(LLRender::LINE_LOOP); +	} +	gGL.vertex2i(x1, y1); +	gGL.vertex2i(x2, y2); +	gGL.vertex2i(x3, y3); +	gGL.end(); +} + +void gl_corners_2d(S32 left, S32 top, S32 right, S32 bottom, S32 length, F32 max_frac) +{ +	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + +	length = llmin((S32)(max_frac*(right - left)), length); +	length = llmin((S32)(max_frac*(top - bottom)), length); +	gGL.begin(LLRender::LINES); +	gGL.vertex2i(left, top); +	gGL.vertex2i(left + length, top); +	 +	gGL.vertex2i(left, top); +	gGL.vertex2i(left, top - length); + +	gGL.vertex2i(left, bottom); +	gGL.vertex2i(left + length, bottom); +	 +	gGL.vertex2i(left, bottom); +	gGL.vertex2i(left, bottom + length); + +	gGL.vertex2i(right, top); +	gGL.vertex2i(right - length, top); + +	gGL.vertex2i(right, top); +	gGL.vertex2i(right, top - length); + +	gGL.vertex2i(right, bottom); +	gGL.vertex2i(right - length, bottom); + +	gGL.vertex2i(right, bottom); +	gGL.vertex2i(right, bottom + length); +	gGL.end(); +} + + +void gl_draw_image( S32 x, S32 y, LLTexture* image, const LLColor4& color, const LLRectf& uv_rect ) +{ +	if (NULL == image) +	{ +		llwarns << "image == NULL; aborting function" << llendl; +		return; +	} +	gl_draw_scaled_rotated_image( x, y, image->getWidth(0), image->getHeight(0), 0.f, image, color, uv_rect ); +} + +void gl_draw_scaled_image(S32 x, S32 y, S32 width, S32 height, LLTexture* image, const LLColor4& color, const LLRectf& uv_rect) +{ +	if (NULL == image) +	{ +		llwarns << "image == NULL; aborting function" << llendl; +		return; +	} +	gl_draw_scaled_rotated_image( x, y, width, height, 0.f, image, color, uv_rect ); +} + +void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 border_width, S32 border_height, S32 width, S32 height, LLTexture* image, const LLColor4& color, BOOL solid_color, const LLRectf& uv_rect) +{ +	if (NULL == image) +	{ +		llwarns << "image == NULL; aborting function" << llendl; +		return; +	} + +	// scale screen size of borders down +	F32 border_width_fraction = (F32)border_width / (F32)image->getWidth(0); +	F32 border_height_fraction = (F32)border_height / (F32)image->getHeight(0); + +	LLRectf scale_rect(border_width_fraction, 1.f - border_height_fraction, 1.f - border_width_fraction, border_height_fraction); +	gl_draw_scaled_image_with_border(x, y, width, height, image, color, solid_color, uv_rect, scale_rect); +} + +void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTexture* image, const LLColor4& color, BOOL solid_color, const LLRectf& uv_outer_rect, const LLRectf& center_rect) +{ +	stop_glerror(); + +	if (NULL == image) +	{ +		llwarns << "image == NULL; aborting function" << llendl; +		return; +	} + +	// add in offset of current image to current UI translation +	const LLVector3 ui_scale = gGL.getUIScale(); +	const LLVector3 ui_translation = (gGL.getUITranslation() + LLVector3(x, y, 0.f)).scaledVec(ui_scale); + +	F32 uv_width = uv_outer_rect.getWidth(); +	F32 uv_height = uv_outer_rect.getHeight(); + +	// shrink scaling region to be proportional to clipped image region +	LLRectf uv_center_rect( +		uv_outer_rect.mLeft + (center_rect.mLeft * uv_width), +		uv_outer_rect.mBottom + (center_rect.mTop * uv_height), +		uv_outer_rect.mLeft + (center_rect.mRight * uv_width), +		uv_outer_rect.mBottom + (center_rect.mBottom * uv_height)); + +	F32 image_width = image->getWidth(0); +	F32 image_height = image->getHeight(0); + +	S32 image_natural_width = llround(image_width * uv_width); +	S32 image_natural_height = llround(image_height * uv_height); + +	LLRectf draw_center_rect(	uv_center_rect.mLeft * image_width, +								uv_center_rect.mTop * image_height, +								uv_center_rect.mRight * image_width, +								uv_center_rect.mBottom * image_height); + +	{	// scale fixed region of image to drawn region +		draw_center_rect.mRight += width - image_natural_width; +		draw_center_rect.mTop += height - image_natural_height; + +		F32 border_shrink_width = llmax(0.f, draw_center_rect.mLeft - draw_center_rect.mRight); +		F32 border_shrink_height = llmax(0.f, draw_center_rect.mBottom - draw_center_rect.mTop); + +		F32 shrink_width_ratio = center_rect.getWidth() == 1.f ? 0.f : border_shrink_width / ((F32)image_natural_width * (1.f - center_rect.getWidth())); +		F32 shrink_height_ratio = center_rect.getHeight() == 1.f ? 0.f : border_shrink_height / ((F32)image_natural_height * (1.f - center_rect.getHeight())); + +		F32 shrink_scale = 1.f - llmax(shrink_width_ratio, shrink_height_ratio); + +		draw_center_rect.mLeft = llround(ui_translation.mV[VX] + (F32)draw_center_rect.mLeft * shrink_scale * ui_scale.mV[VX]); +		draw_center_rect.mTop = llround(ui_translation.mV[VY] + lerp((F32)height, (F32)draw_center_rect.mTop, shrink_scale) * ui_scale.mV[VY]); +		draw_center_rect.mRight = llround(ui_translation.mV[VX] + lerp((F32)width, (F32)draw_center_rect.mRight, shrink_scale) * ui_scale.mV[VX]); +		draw_center_rect.mBottom = llround(ui_translation.mV[VY] + (F32)draw_center_rect.mBottom * shrink_scale * ui_scale.mV[VY]); +	} + +	LLRectf draw_outer_rect(ui_translation.mV[VX],  +							ui_translation.mV[VY] + height * ui_scale.mV[VY],  +							ui_translation.mV[VX] + width * ui_scale.mV[VX],  +							ui_translation.mV[VY]); + +	LLGLSUIDefault gls_ui; +	 +	if (solid_color) +	{ +		if (LLGLSLShader::sNoFixedFunction) +		{ +			gSolidColorProgram.bind(); +		} +		else +		{ +			gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_COLOR); +			gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_ALPHA, LLTexUnit::TBS_VERT_ALPHA); +		} +	} + +	gGL.getTexUnit(0)->bind(image, true); + +	gGL.color4fv(color.mV); +	 +	const S32 NUM_VERTICES = 9 * 4; // 9 quads +	LLVector2 uv[NUM_VERTICES]; +	LLVector3 pos[NUM_VERTICES]; + +	S32 index = 0; + +	gGL.begin(LLRender::QUADS); +	{ +		// draw bottom left +		uv[index] = LLVector2(uv_outer_rect.mLeft, uv_outer_rect.mBottom); +		pos[index] = LLVector3(draw_outer_rect.mLeft, draw_outer_rect.mBottom, 0.f); +		index++; + +		uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mBottom); +		pos[index] = LLVector3(draw_center_rect.mLeft, draw_outer_rect.mBottom, 0.f); +		index++; + +		uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom); +		pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f); +		index++; + +		uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mBottom); +		pos[index] = LLVector3(draw_outer_rect.mLeft, draw_center_rect.mBottom, 0.f); +		index++; + +		// draw bottom middle +		uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mBottom); +		pos[index] = LLVector3(draw_center_rect.mLeft, draw_outer_rect.mBottom, 0.f); +		index++; + +		uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mBottom); +		pos[index] = LLVector3(draw_center_rect.mRight, draw_outer_rect.mBottom, 0.f); +		index++; + +		uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom); +		pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f); +		index++; + +		uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom); +		pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f); +		index++; + +		// draw bottom right +		uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mBottom); +		pos[index] = LLVector3(draw_center_rect.mRight, draw_outer_rect.mBottom, 0.f); +		index++; + +		uv[index] = LLVector2(uv_outer_rect.mRight, uv_outer_rect.mBottom); +		pos[index] = LLVector3(draw_outer_rect.mRight, draw_outer_rect.mBottom, 0.f); +		index++; + +		uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mBottom); +		pos[index] = LLVector3(draw_outer_rect.mRight, draw_center_rect.mBottom, 0.f); +		index++; + +		uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom); +		pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f); +		index++; + +		// draw left  +		uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mBottom); +		pos[index] = LLVector3(draw_outer_rect.mLeft, draw_center_rect.mBottom, 0.f); +		index++; + +		uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom); +		pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f); +		index++; + +		uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop); +		pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f); +		index++; + +		uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mTop); +		pos[index] = LLVector3(draw_outer_rect.mLeft, draw_center_rect.mTop, 0.f); +		index++; + +		// draw middle +		uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom); +		pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f); +		index++; + +		uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom); +		pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f); +		index++; + +		uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop); +		pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mTop, 0.f); +		index++; + +		uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop); +		pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f); +		index++; + +		// draw right  +		uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom); +		pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f); +		index++; + +		uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mBottom); +		pos[index] = LLVector3(draw_outer_rect.mRight, draw_center_rect.mBottom, 0.f); +		index++; + +		uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mTop); +		pos[index] = LLVector3(draw_outer_rect.mRight, draw_center_rect.mTop, 0.f); +		index++; + +		uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop); +		pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mTop, 0.f); +		index++; + +		// draw top left +		uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mTop); +		pos[index] = LLVector3(draw_outer_rect.mLeft, draw_center_rect.mTop, 0.f); +		index++; + +		uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop); +		pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f); +		index++; + +		uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mTop); +		pos[index] = LLVector3(draw_center_rect.mLeft, draw_outer_rect.mTop, 0.f); +		index++; + +		uv[index] = LLVector2(uv_outer_rect.mLeft, uv_outer_rect.mTop); +		pos[index] = LLVector3(draw_outer_rect.mLeft, draw_outer_rect.mTop, 0.f); +		index++; + +		// draw top middle +		uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop); +		pos[index] = LLVector3(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f); +		index++; + +		uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop); +		pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mTop, 0.f); +		index++; + +		uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mTop); +		pos[index] = LLVector3(draw_center_rect.mRight, draw_outer_rect.mTop, 0.f); +		index++; + +		uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mTop); +		pos[index] = LLVector3(draw_center_rect.mLeft, draw_outer_rect.mTop, 0.f); +		index++; + +		// draw top right +		uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop); +		pos[index] = LLVector3(draw_center_rect.mRight, draw_center_rect.mTop, 0.f); +		index++; + +		uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mTop); +		pos[index] = LLVector3(draw_outer_rect.mRight, draw_center_rect.mTop, 0.f); +		index++; + +		uv[index] = LLVector2(uv_outer_rect.mRight, uv_outer_rect.mTop); +		pos[index] = LLVector3(draw_outer_rect.mRight, draw_outer_rect.mTop, 0.f); +		index++; + +		uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mTop); +		pos[index] = LLVector3(draw_center_rect.mRight, draw_outer_rect.mTop, 0.f); +		index++; + +		gGL.vertexBatchPreTransformed(pos, uv, NUM_VERTICES); +	} +	gGL.end(); + +	if (solid_color) +	{ +		if (LLGLSLShader::sNoFixedFunction) +		{ +			gUIProgram.bind(); +		} +		else +		{ +			gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); +		} +	} +} + +void gl_draw_rotated_image(S32 x, S32 y, F32 degrees, LLTexture* image, const LLColor4& color, const LLRectf& uv_rect) +{ +	gl_draw_scaled_rotated_image( x, y, image->getWidth(0), image->getHeight(0), degrees, image, color, uv_rect ); +} + +void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degrees, LLTexture* image, const LLColor4& color, const LLRectf& uv_rect) +{ +	if (NULL == image) +	{ +		llwarns << "image == NULL; aborting function" << llendl; +		return; +	} + +	LLGLSUIDefault gls_ui; + + +	gGL.getTexUnit(0)->bind(image, true); + +	gGL.color4fv(color.mV); + +	if (degrees == 0.f) +	{ +		const S32 NUM_VERTICES = 4; // 9 quads +		LLVector2 uv[NUM_VERTICES]; +		LLVector3 pos[NUM_VERTICES]; + +		gGL.begin(LLRender::QUADS); +		{ +			LLVector3 ui_scale = gGL.getUIScale(); +			LLVector3 ui_translation = gGL.getUITranslation(); +			ui_translation.mV[VX] += x; +			ui_translation.mV[VY] += y; +			ui_translation.scaleVec(ui_scale); +			S32 index = 0; +			S32 scaled_width = llround(width * ui_scale.mV[VX]); +			S32 scaled_height = llround(height * ui_scale.mV[VY]); + +			uv[index] = LLVector2(uv_rect.mRight, uv_rect.mTop); +			pos[index] = LLVector3(ui_translation.mV[VX] + scaled_width, ui_translation.mV[VY] + scaled_height, 0.f); +			index++; + +			uv[index] = LLVector2(uv_rect.mLeft, uv_rect.mTop); +			pos[index] = LLVector3(ui_translation.mV[VX], ui_translation.mV[VY] + scaled_height, 0.f); +			index++; + +			uv[index] = LLVector2(uv_rect.mLeft, uv_rect.mBottom); +			pos[index] = LLVector3(ui_translation.mV[VX], ui_translation.mV[VY], 0.f); +			index++; + +			uv[index] = LLVector2(uv_rect.mRight, uv_rect.mBottom); +			pos[index] = LLVector3(ui_translation.mV[VX] + scaled_width, ui_translation.mV[VY], 0.f); +			index++; + +			gGL.vertexBatchPreTransformed(pos, uv, NUM_VERTICES); +		} +		gGL.end(); +	} +	else +	{ +		gGL.pushUIMatrix(); +		gGL.translateUI((F32)x, (F32)y, 0.f); +	 +		F32 offset_x = F32(width/2); +		F32 offset_y = F32(height/2); + +		gGL.translateUI(offset_x, offset_y, 0.f); + +		LLMatrix3 quat(0.f, 0.f, degrees*DEG_TO_RAD); +		 +		gGL.getTexUnit(0)->bind(image, true); + +		gGL.color4fv(color.mV); +		 +		gGL.begin(LLRender::QUADS); +		{ +			LLVector3 v; + +			v = LLVector3(offset_x, offset_y, 0.f) * quat; +			gGL.texCoord2f(uv_rect.mRight, uv_rect.mTop); +			gGL.vertex2f(v.mV[0], v.mV[1] ); + +			v = LLVector3(-offset_x, offset_y, 0.f) * quat; +			gGL.texCoord2f(uv_rect.mLeft, uv_rect.mTop); +			gGL.vertex2f(v.mV[0], v.mV[1] ); + +			v = LLVector3(-offset_x, -offset_y, 0.f) * quat; +			gGL.texCoord2f(uv_rect.mLeft, uv_rect.mBottom); +			gGL.vertex2f(v.mV[0], v.mV[1] ); + +			v = LLVector3(offset_x, -offset_y, 0.f) * quat; +			gGL.texCoord2f(uv_rect.mRight, uv_rect.mBottom); +			gGL.vertex2f(v.mV[0], v.mV[1] ); +		} +		gGL.end(); +		gGL.popUIMatrix(); +	} +} + + +void gl_stippled_line_3d( const LLVector3& start, const LLVector3& end, const LLColor4& color, F32 phase ) +{ +	phase = fmod(phase, 1.f); + +	S32 shift = S32(phase * 4.f) % 4; + +	// Stippled line +	LLGLEnable stipple(GL_LINE_STIPPLE); +	 +	gGL.color4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], color.mV[VALPHA]); + +	gGL.flush(); +	glLineWidth(2.5f); + +	if (!LLGLSLShader::sNoFixedFunction) +	{ +		glLineStipple(2, 0x3333 << shift); +	} + +	gGL.begin(LLRender::LINES); +	{ +		gGL.vertex3fv( start.mV ); +		gGL.vertex3fv( end.mV ); +	} +	gGL.end(); + +	LLRender2D::setLineWidth(1.f); +} + +void gl_arc_2d(F32 center_x, F32 center_y, F32 radius, S32 steps, BOOL filled, F32 start_angle, F32 end_angle) +{ +	if (end_angle < start_angle) +	{ +		end_angle += F_TWO_PI; +	} + +	gGL.pushUIMatrix(); +	{ +		gGL.translateUI(center_x, center_y, 0.f); + +		// Inexact, but reasonably fast. +		F32 delta = (end_angle - start_angle) / steps; +		F32 sin_delta = sin( delta ); +		F32 cos_delta = cos( delta ); +		F32 x = cosf(start_angle) * radius; +		F32 y = sinf(start_angle) * radius; + +		if (filled) +		{ +			gGL.begin(LLRender::TRIANGLE_FAN); +			gGL.vertex2f(0.f, 0.f); +			// make sure circle is complete +			steps += 1; +		} +		else +		{ +			gGL.begin(LLRender::LINE_STRIP); +		} + +		while( steps-- ) +		{ +			// Successive rotations +			gGL.vertex2f( x, y ); +			F32 x_new = x * cos_delta - y * sin_delta; +			y = x * sin_delta +  y * cos_delta; +			x = x_new; +		} +		gGL.end(); +	} +	gGL.popUIMatrix(); +} + +void gl_circle_2d(F32 center_x, F32 center_y, F32 radius, S32 steps, BOOL filled) +{ +	gGL.pushUIMatrix(); +	{ +		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); +		gGL.translateUI(center_x, center_y, 0.f); + +		// Inexact, but reasonably fast. +		F32 delta = F_TWO_PI / steps; +		F32 sin_delta = sin( delta ); +		F32 cos_delta = cos( delta ); +		F32 x = radius; +		F32 y = 0.f; + +		if (filled) +		{ +			gGL.begin(LLRender::TRIANGLE_FAN); +			gGL.vertex2f(0.f, 0.f); +			// make sure circle is complete +			steps += 1; +		} +		else +		{ +			gGL.begin(LLRender::LINE_LOOP); +		} + +		while( steps-- ) +		{ +			// Successive rotations +			gGL.vertex2f( x, y ); +			F32 x_new = x * cos_delta - y * sin_delta; +			y = x * sin_delta +  y * cos_delta; +			x = x_new; +		} +		gGL.end(); +	} +	gGL.popUIMatrix(); +} + +// Renders a ring with sides (tube shape) +void gl_deep_circle( F32 radius, F32 depth, S32 steps ) +{ +	F32 x = radius; +	F32 y = 0.f; +	F32 angle_delta = F_TWO_PI / (F32)steps; +	gGL.begin( LLRender::TRIANGLE_STRIP  ); +	{ +		S32 step = steps + 1; // An extra step to close the circle. +		while( step-- ) +		{ +			gGL.vertex3f( x, y, depth ); +			gGL.vertex3f( x, y, 0.f ); + +			F32 x_new = x * cosf(angle_delta) - y * sinf(angle_delta); +			y = x * sinf(angle_delta) +  y * cosf(angle_delta); +			x = x_new; +		} +	} +	gGL.end(); +} + +void gl_ring( F32 radius, F32 width, const LLColor4& center_color, const LLColor4& side_color, S32 steps, BOOL render_center ) +{ +	gGL.pushUIMatrix(); +	{ +		gGL.translateUI(0.f, 0.f, -width / 2); +		if( render_center ) +		{ +			gGL.color4fv(center_color.mV); +			gGL.diffuseColor4fv(center_color.mV); +			gl_deep_circle( radius, width, steps ); +		} +		else +		{ +			gGL.diffuseColor4fv(side_color.mV); +			gl_washer_2d(radius, radius - width, steps, side_color, side_color); +			gGL.translateUI(0.f, 0.f, width); +			gl_washer_2d(radius - width, radius, steps, side_color, side_color); +		} +	} +	gGL.popUIMatrix(); +} + +// Draw gray and white checkerboard with black border +void gl_rect_2d_checkerboard(const LLRect& rect, GLfloat alpha) +{ +	if (!LLGLSLShader::sNoFixedFunction) +	{  +		// Initialize the first time this is called. +		const S32 PIXELS = 32; +		static GLubyte checkerboard[PIXELS * PIXELS]; +		static BOOL first = TRUE; +		if( first ) +		{ +			for( S32 i = 0; i < PIXELS; i++ ) +			{ +				for( S32 j = 0; j < PIXELS; j++ ) +				{ +					checkerboard[i * PIXELS + j] = ((i & 1) ^ (j & 1)) * 0xFF; +				} +			} +			first = FALSE; +		} +	 +		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + +		// ...white squares +		gGL.color4f( 1.f, 1.f, 1.f, alpha ); +		gl_rect_2d(rect); + +		// ...gray squares +		gGL.color4f( .7f, .7f, .7f, alpha ); +		gGL.flush(); + +		glPolygonStipple( checkerboard ); + +		LLGLEnable polygon_stipple(GL_POLYGON_STIPPLE); +		gl_rect_2d(rect); +	} +	else +	{ //polygon stipple is deprecated, use "Checker" texture +		LLPointer<LLUIImage> img = LLRender2D::getUIImage("Checker"); +		gGL.getTexUnit(0)->bind(img->getImage()); +		gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_WRAP); +		gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + +		LLColor4 color(1.f, 1.f, 1.f, alpha); +		LLRectf uv_rect(0, 0, rect.getWidth()/32.f, rect.getHeight()/32.f); + +		gl_draw_scaled_image(rect.mLeft, rect.mBottom, rect.getWidth(), rect.getHeight(), +			img->getImage(), color, uv_rect); +	} +	 +	gGL.flush(); +} + + +// Draws the area between two concentric circles, like +// a doughnut or washer. +void gl_washer_2d(F32 outer_radius, F32 inner_radius, S32 steps, const LLColor4& inner_color, const LLColor4& outer_color) +{ +	const F32 DELTA = F_TWO_PI / steps; +	const F32 SIN_DELTA = sin( DELTA ); +	const F32 COS_DELTA = cos( DELTA ); + +	F32 x1 = outer_radius; +	F32 y1 = 0.f; +	F32 x2 = inner_radius; +	F32 y2 = 0.f; + +	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + +	gGL.begin( LLRender::TRIANGLE_STRIP  ); +	{ +		steps += 1; // An extra step to close the circle. +		while( steps-- ) +		{ +			gGL.color4fv(outer_color.mV); +			gGL.vertex2f( x1, y1 ); +			gGL.color4fv(inner_color.mV); +			gGL.vertex2f( x2, y2 ); + +			F32 x1_new = x1 * COS_DELTA - y1 * SIN_DELTA; +			y1 = x1 * SIN_DELTA +  y1 * COS_DELTA; +			x1 = x1_new; + +			F32 x2_new = x2 * COS_DELTA - y2 * SIN_DELTA; +			y2 = x2 * SIN_DELTA +  y2 * COS_DELTA; +			x2 = x2_new; +		} +	} +	gGL.end(); +} + +// Draws the area between two concentric circles, like +// a doughnut or washer. +void gl_washer_segment_2d(F32 outer_radius, F32 inner_radius, F32 start_radians, F32 end_radians, S32 steps, const LLColor4& inner_color, const LLColor4& outer_color) +{ +	const F32 DELTA = (end_radians - start_radians) / steps; +	const F32 SIN_DELTA = sin( DELTA ); +	const F32 COS_DELTA = cos( DELTA ); + +	F32 x1 = outer_radius * cos( start_radians ); +	F32 y1 = outer_radius * sin( start_radians ); +	F32 x2 = inner_radius * cos( start_radians ); +	F32 y2 = inner_radius * sin( start_radians ); + +	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); +	gGL.begin( LLRender::TRIANGLE_STRIP  ); +	{ +		steps += 1; // An extra step to close the circle. +		while( steps-- ) +		{ +			gGL.color4fv(outer_color.mV); +			gGL.vertex2f( x1, y1 ); +			gGL.color4fv(inner_color.mV); +			gGL.vertex2f( x2, y2 ); + +			F32 x1_new = x1 * COS_DELTA - y1 * SIN_DELTA; +			y1 = x1 * SIN_DELTA +  y1 * COS_DELTA; +			x1 = x1_new; + +			F32 x2_new = x2 * COS_DELTA - y2 * SIN_DELTA; +			y2 = x2 * SIN_DELTA +  y2 * COS_DELTA; +			x2 = x2_new; +		} +	} +	gGL.end(); +} + +void gl_rect_2d_simple_tex( S32 width, S32 height ) +{ +	gGL.begin( LLRender::QUADS ); + +		gGL.texCoord2f(1.f, 1.f); +		gGL.vertex2i(width, height); + +		gGL.texCoord2f(0.f, 1.f); +		gGL.vertex2i(0, height); + +		gGL.texCoord2f(0.f, 0.f); +		gGL.vertex2i(0, 0); + +		gGL.texCoord2f(1.f, 0.f); +		gGL.vertex2i(width, 0); +	 +	gGL.end(); +} + +void gl_rect_2d_simple( S32 width, S32 height ) +{ +	gGL.begin( LLRender::QUADS ); +		gGL.vertex2i(width, height); +		gGL.vertex2i(0, height); +		gGL.vertex2i(0, 0); +		gGL.vertex2i(width, 0); +	gGL.end(); +} + +void gl_segmented_rect_2d_tex(const S32 left,  +							  const S32 top,  +							  const S32 right,  +							  const S32 bottom,  +							  const S32 texture_width,  +							  const S32 texture_height,  +							  const S32 border_size,  +							  const U32 edges) +{ +	S32 width = llabs(right - left); +	S32 height = llabs(top - bottom); + +	gGL.pushUIMatrix(); + +	gGL.translateUI((F32)left, (F32)bottom, 0.f); +	LLVector2 border_uv_scale((F32)border_size / (F32)texture_width, (F32)border_size / (F32)texture_height); + +	if (border_uv_scale.mV[VX] > 0.5f) +	{ +		border_uv_scale *= 0.5f / border_uv_scale.mV[VX]; +	} +	if (border_uv_scale.mV[VY] > 0.5f) +	{ +		border_uv_scale *= 0.5f / border_uv_scale.mV[VY]; +	} + +	F32 border_scale = llmin((F32)border_size, (F32)width * 0.5f, (F32)height * 0.5f); +	LLVector2 border_width_left = ((edges & (~(U32)ROUNDED_RECT_RIGHT)) != 0) ? LLVector2(border_scale, 0.f) : LLVector2::zero; +	LLVector2 border_width_right = ((edges & (~(U32)ROUNDED_RECT_LEFT)) != 0) ? LLVector2(border_scale, 0.f) : LLVector2::zero; +	LLVector2 border_height_bottom = ((edges & (~(U32)ROUNDED_RECT_TOP)) != 0) ? LLVector2(0.f, border_scale) : LLVector2::zero; +	LLVector2 border_height_top = ((edges & (~(U32)ROUNDED_RECT_BOTTOM)) != 0) ? LLVector2(0.f, border_scale) : LLVector2::zero; +	LLVector2 width_vec((F32)width, 0.f); +	LLVector2 height_vec(0.f, (F32)height); + +	gGL.begin(LLRender::QUADS); +	{ +		// draw bottom left +		gGL.texCoord2f(0.f, 0.f); +		gGL.vertex2f(0.f, 0.f); + +		gGL.texCoord2f(border_uv_scale.mV[VX], 0.f); +		gGL.vertex2fv(border_width_left.mV); + +		gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]); +		gGL.vertex2fv((border_width_left + border_height_bottom).mV); + +		gGL.texCoord2f(0.f, border_uv_scale.mV[VY]); +		gGL.vertex2fv(border_height_bottom.mV); + +		// draw bottom middle +		gGL.texCoord2f(border_uv_scale.mV[VX], 0.f); +		gGL.vertex2fv(border_width_left.mV); + +		gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 0.f); +		gGL.vertex2fv((width_vec - border_width_right).mV); + +		gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]); +		gGL.vertex2fv((width_vec - border_width_right + border_height_bottom).mV); + +		gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]); +		gGL.vertex2fv((border_width_left + border_height_bottom).mV); + +		// draw bottom right +		gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 0.f); +		gGL.vertex2fv((width_vec - border_width_right).mV); + +		gGL.texCoord2f(1.f, 0.f); +		gGL.vertex2fv(width_vec.mV); + +		gGL.texCoord2f(1.f, border_uv_scale.mV[VY]); +		gGL.vertex2fv((width_vec + border_height_bottom).mV); + +		gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]); +		gGL.vertex2fv((width_vec - border_width_right + border_height_bottom).mV); + +		// draw left  +		gGL.texCoord2f(0.f, border_uv_scale.mV[VY]); +		gGL.vertex2fv(border_height_bottom.mV); + +		gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]); +		gGL.vertex2fv((border_width_left + border_height_bottom).mV); + +		gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]); +		gGL.vertex2fv((border_width_left + height_vec - border_height_top).mV); + +		gGL.texCoord2f(0.f, 1.f - border_uv_scale.mV[VY]); +		gGL.vertex2fv((height_vec - border_height_top).mV); + +		// draw middle +		gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]); +		gGL.vertex2fv((border_width_left + border_height_bottom).mV); + +		gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]); +		gGL.vertex2fv((width_vec - border_width_right + border_height_bottom).mV); + +		gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]); +		gGL.vertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV); + +		gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]); +		gGL.vertex2fv((border_width_left + height_vec - border_height_top).mV); + +		// draw right  +		gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]); +		gGL.vertex2fv((width_vec - border_width_right + border_height_bottom).mV); + +		gGL.texCoord2f(1.f, border_uv_scale.mV[VY]); +		gGL.vertex2fv((width_vec + border_height_bottom).mV); + +		gGL.texCoord2f(1.f, 1.f - border_uv_scale.mV[VY]); +		gGL.vertex2fv((width_vec + height_vec - border_height_top).mV); + +		gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]); +		gGL.vertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV); + +		// draw top left +		gGL.texCoord2f(0.f, 1.f - border_uv_scale.mV[VY]); +		gGL.vertex2fv((height_vec - border_height_top).mV); + +		gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]); +		gGL.vertex2fv((border_width_left + height_vec - border_height_top).mV); + +		gGL.texCoord2f(border_uv_scale.mV[VX], 1.f); +		gGL.vertex2fv((border_width_left + height_vec).mV); + +		gGL.texCoord2f(0.f, 1.f); +		gGL.vertex2fv((height_vec).mV); + +		// draw top middle +		gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]); +		gGL.vertex2fv((border_width_left + height_vec - border_height_top).mV); + +		gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]); +		gGL.vertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV); + +		gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f); +		gGL.vertex2fv((width_vec - border_width_right + height_vec).mV); + +		gGL.texCoord2f(border_uv_scale.mV[VX], 1.f); +		gGL.vertex2fv((border_width_left + height_vec).mV); + +		// draw top right +		gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]); +		gGL.vertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV); + +		gGL.texCoord2f(1.f, 1.f - border_uv_scale.mV[VY]); +		gGL.vertex2fv((width_vec + height_vec - border_height_top).mV); + +		gGL.texCoord2f(1.f, 1.f); +		gGL.vertex2fv((width_vec + height_vec).mV); + +		gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f); +		gGL.vertex2fv((width_vec - border_width_right + height_vec).mV); +	} +	gGL.end(); + +	gGL.popUIMatrix(); +} + +//FIXME: rewrite to use scissor? +void gl_segmented_rect_2d_fragment_tex(const S32 left,  +									   const S32 top,  +									   const S32 right,  +									   const S32 bottom,  +									   const S32 texture_width,  +									   const S32 texture_height,  +									   const S32 border_size,  +									   const F32 start_fragment,  +									   const F32 end_fragment,  +									   const U32 edges) +{ +	S32 width = llabs(right - left); +	S32 height = llabs(top - bottom); + +	gGL.pushUIMatrix(); + +	gGL.translateUI((F32)left, (F32)bottom, 0.f); +	LLVector2 border_uv_scale((F32)border_size / (F32)texture_width, (F32)border_size / (F32)texture_height); + +	if (border_uv_scale.mV[VX] > 0.5f) +	{ +		border_uv_scale *= 0.5f / border_uv_scale.mV[VX]; +	} +	if (border_uv_scale.mV[VY] > 0.5f) +	{ +		border_uv_scale *= 0.5f / border_uv_scale.mV[VY]; +	} + +	F32 border_scale = llmin((F32)border_size, (F32)width * 0.5f, (F32)height * 0.5f); +	LLVector2 border_width_left = ((edges & (~(U32)ROUNDED_RECT_RIGHT)) != 0) ? LLVector2(border_scale, 0.f) : LLVector2::zero; +	LLVector2 border_width_right = ((edges & (~(U32)ROUNDED_RECT_LEFT)) != 0) ? LLVector2(border_scale, 0.f) : LLVector2::zero; +	LLVector2 border_height_bottom = ((edges & (~(U32)ROUNDED_RECT_TOP)) != 0) ? LLVector2(0.f, border_scale) : LLVector2::zero; +	LLVector2 border_height_top = ((edges & (~(U32)ROUNDED_RECT_BOTTOM)) != 0) ? LLVector2(0.f, border_scale) : LLVector2::zero; +	LLVector2 width_vec((F32)width, 0.f); +	LLVector2 height_vec(0.f, (F32)height); + +	F32 middle_start = border_scale / (F32)width; +	F32 middle_end = 1.f - middle_start; + +	F32 u_min; +	F32 u_max; +	LLVector2 x_min; +	LLVector2 x_max; + +	gGL.begin(LLRender::QUADS); +	{ +		if (start_fragment < middle_start) +		{ +			u_min = (start_fragment / middle_start) * border_uv_scale.mV[VX]; +			u_max = llmin(end_fragment / middle_start, 1.f) * border_uv_scale.mV[VX]; +			x_min = (start_fragment / middle_start) * border_width_left; +			x_max = llmin(end_fragment / middle_start, 1.f) * border_width_left; + +			// draw bottom left +			gGL.texCoord2f(u_min, 0.f); +			gGL.vertex2fv(x_min.mV); + +			gGL.texCoord2f(border_uv_scale.mV[VX], 0.f); +			gGL.vertex2fv(x_max.mV); + +			gGL.texCoord2f(u_max, border_uv_scale.mV[VY]); +			gGL.vertex2fv((x_max + border_height_bottom).mV); + +			gGL.texCoord2f(u_min, border_uv_scale.mV[VY]); +			gGL.vertex2fv((x_min + border_height_bottom).mV); + +			// draw left  +			gGL.texCoord2f(u_min, border_uv_scale.mV[VY]); +			gGL.vertex2fv((x_min + border_height_bottom).mV); + +			gGL.texCoord2f(u_max, border_uv_scale.mV[VY]); +			gGL.vertex2fv((x_max + border_height_bottom).mV); + +			gGL.texCoord2f(u_max, 1.f - border_uv_scale.mV[VY]); +			gGL.vertex2fv((x_max + height_vec - border_height_top).mV); + +			gGL.texCoord2f(u_min, 1.f - border_uv_scale.mV[VY]); +			gGL.vertex2fv((x_min + height_vec - border_height_top).mV); +			 +			// draw top left +			gGL.texCoord2f(u_min, 1.f - border_uv_scale.mV[VY]); +			gGL.vertex2fv((x_min + height_vec - border_height_top).mV); + +			gGL.texCoord2f(u_max, 1.f - border_uv_scale.mV[VY]); +			gGL.vertex2fv((x_max + height_vec - border_height_top).mV); + +			gGL.texCoord2f(u_max, 1.f); +			gGL.vertex2fv((x_max + height_vec).mV); + +			gGL.texCoord2f(u_min, 1.f); +			gGL.vertex2fv((x_min + height_vec).mV); +		} + +		if (end_fragment > middle_start || start_fragment < middle_end) +		{ +			x_min = border_width_left + ((llclamp(start_fragment, middle_start, middle_end) - middle_start)) * width_vec; +			x_max = border_width_left + ((llclamp(end_fragment, middle_start, middle_end) - middle_start)) * width_vec; + +			// draw bottom middle +			gGL.texCoord2f(border_uv_scale.mV[VX], 0.f); +			gGL.vertex2fv(x_min.mV); + +			gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 0.f); +			gGL.vertex2fv((x_max).mV); + +			gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]); +			gGL.vertex2fv((x_max + border_height_bottom).mV); + +			gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]); +			gGL.vertex2fv((x_min + border_height_bottom).mV); + +			// draw middle +			gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]); +			gGL.vertex2fv((x_min + border_height_bottom).mV); + +			gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]); +			gGL.vertex2fv((x_max + border_height_bottom).mV); + +			gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]); +			gGL.vertex2fv((x_max + height_vec - border_height_top).mV); + +			gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]); +			gGL.vertex2fv((x_min + height_vec - border_height_top).mV); + +			// draw top middle +			gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]); +			gGL.vertex2fv((x_min + height_vec - border_height_top).mV); + +			gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]); +			gGL.vertex2fv((x_max + height_vec - border_height_top).mV); + +			gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f); +			gGL.vertex2fv((x_max + height_vec).mV); + +			gGL.texCoord2f(border_uv_scale.mV[VX], 1.f); +			gGL.vertex2fv((x_min + height_vec).mV); +		} + +		if (end_fragment > middle_end) +		{ +			u_min = (1.f - llmax(0.f, ((start_fragment - middle_end) / middle_start))) * border_uv_scale.mV[VX]; +			u_max = (1.f - ((end_fragment - middle_end) / middle_start)) * border_uv_scale.mV[VX]; +			x_min = width_vec - ((1.f - llmax(0.f, ((start_fragment - middle_end) / middle_start))) * border_width_right); +			x_max = width_vec - ((1.f - ((end_fragment - middle_end) / middle_start)) * border_width_right); + +			// draw bottom right +			gGL.texCoord2f(u_min, 0.f); +			gGL.vertex2fv((x_min).mV); + +			gGL.texCoord2f(u_max, 0.f); +			gGL.vertex2fv(x_max.mV); + +			gGL.texCoord2f(u_max, border_uv_scale.mV[VY]); +			gGL.vertex2fv((x_max + border_height_bottom).mV); + +			gGL.texCoord2f(u_min, border_uv_scale.mV[VY]); +			gGL.vertex2fv((x_min + border_height_bottom).mV); + +			// draw right  +			gGL.texCoord2f(u_min, border_uv_scale.mV[VY]); +			gGL.vertex2fv((x_min + border_height_bottom).mV); + +			gGL.texCoord2f(u_max, border_uv_scale.mV[VY]); +			gGL.vertex2fv((x_max + border_height_bottom).mV); + +			gGL.texCoord2f(u_max, 1.f - border_uv_scale.mV[VY]); +			gGL.vertex2fv((x_max + height_vec - border_height_top).mV); + +			gGL.texCoord2f(u_min, 1.f - border_uv_scale.mV[VY]); +			gGL.vertex2fv((x_min + height_vec - border_height_top).mV); + +			// draw top right +			gGL.texCoord2f(u_min, 1.f - border_uv_scale.mV[VY]); +			gGL.vertex2fv((x_min + height_vec - border_height_top).mV); + +			gGL.texCoord2f(u_max, 1.f - border_uv_scale.mV[VY]); +			gGL.vertex2fv((x_max + height_vec - border_height_top).mV); + +			gGL.texCoord2f(u_max, 1.f); +			gGL.vertex2fv((x_max + height_vec).mV); + +			gGL.texCoord2f(u_min, 1.f); +			gGL.vertex2fv((x_min + height_vec).mV); +		} +	} +	gGL.end(); + +	gGL.popUIMatrix(); +} + +void gl_segmented_rect_3d_tex(const LLVector2& border_scale, const LLVector3& border_width,  +							  const LLVector3& border_height, const LLVector3& width_vec, const LLVector3& height_vec, +							  const U32 edges) +{ +	LLVector3 left_border_width = ((edges & (~(U32)ROUNDED_RECT_RIGHT)) != 0) ? border_width : LLVector3::zero; +	LLVector3 right_border_width = ((edges & (~(U32)ROUNDED_RECT_LEFT)) != 0) ? border_width : LLVector3::zero; + +	LLVector3 top_border_height = ((edges & (~(U32)ROUNDED_RECT_BOTTOM)) != 0) ? border_height : LLVector3::zero; +	LLVector3 bottom_border_height = ((edges & (~(U32)ROUNDED_RECT_TOP)) != 0) ? border_height : LLVector3::zero; + + +	gGL.begin(LLRender::QUADS); +	{ +		// draw bottom left +		gGL.texCoord2f(0.f, 0.f); +		gGL.vertex3f(0.f, 0.f, 0.f); + +		gGL.texCoord2f(border_scale.mV[VX], 0.f); +		gGL.vertex3fv(left_border_width.mV); + +		gGL.texCoord2f(border_scale.mV[VX], border_scale.mV[VY]); +		gGL.vertex3fv((left_border_width + bottom_border_height).mV); + +		gGL.texCoord2f(0.f, border_scale.mV[VY]); +		gGL.vertex3fv(bottom_border_height.mV); + +		// draw bottom middle +		gGL.texCoord2f(border_scale.mV[VX], 0.f); +		gGL.vertex3fv(left_border_width.mV); + +		gGL.texCoord2f(1.f - border_scale.mV[VX], 0.f); +		gGL.vertex3fv((width_vec - right_border_width).mV); + +		gGL.texCoord2f(1.f - border_scale.mV[VX], border_scale.mV[VY]); +		gGL.vertex3fv((width_vec - right_border_width + bottom_border_height).mV); + +		gGL.texCoord2f(border_scale.mV[VX], border_scale.mV[VY]); +		gGL.vertex3fv((left_border_width + bottom_border_height).mV); + +		// draw bottom right +		gGL.texCoord2f(1.f - border_scale.mV[VX], 0.f); +		gGL.vertex3fv((width_vec - right_border_width).mV); + +		gGL.texCoord2f(1.f, 0.f); +		gGL.vertex3fv(width_vec.mV); + +		gGL.texCoord2f(1.f, border_scale.mV[VY]); +		gGL.vertex3fv((width_vec + bottom_border_height).mV); + +		gGL.texCoord2f(1.f - border_scale.mV[VX], border_scale.mV[VY]); +		gGL.vertex3fv((width_vec - right_border_width + bottom_border_height).mV); + +		// draw left  +		gGL.texCoord2f(0.f, border_scale.mV[VY]); +		gGL.vertex3fv(bottom_border_height.mV); + +		gGL.texCoord2f(border_scale.mV[VX], border_scale.mV[VY]); +		gGL.vertex3fv((left_border_width + bottom_border_height).mV); + +		gGL.texCoord2f(border_scale.mV[VX], 1.f - border_scale.mV[VY]); +		gGL.vertex3fv((left_border_width + height_vec - top_border_height).mV); + +		gGL.texCoord2f(0.f, 1.f - border_scale.mV[VY]); +		gGL.vertex3fv((height_vec - top_border_height).mV); + +		// draw middle +		gGL.texCoord2f(border_scale.mV[VX], border_scale.mV[VY]); +		gGL.vertex3fv((left_border_width + bottom_border_height).mV); + +		gGL.texCoord2f(1.f - border_scale.mV[VX], border_scale.mV[VY]); +		gGL.vertex3fv((width_vec - right_border_width + bottom_border_height).mV); + +		gGL.texCoord2f(1.f - border_scale.mV[VX], 1.f - border_scale.mV[VY]); +		gGL.vertex3fv((width_vec - right_border_width + height_vec - top_border_height).mV); + +		gGL.texCoord2f(border_scale.mV[VX], 1.f - border_scale.mV[VY]); +		gGL.vertex3fv((left_border_width + height_vec - top_border_height).mV); + +		// draw right  +		gGL.texCoord2f(1.f - border_scale.mV[VX], border_scale.mV[VY]); +		gGL.vertex3fv((width_vec - right_border_width + bottom_border_height).mV); + +		gGL.texCoord2f(1.f, border_scale.mV[VY]); +		gGL.vertex3fv((width_vec + bottom_border_height).mV); + +		gGL.texCoord2f(1.f, 1.f - border_scale.mV[VY]); +		gGL.vertex3fv((width_vec + height_vec - top_border_height).mV); + +		gGL.texCoord2f(1.f - border_scale.mV[VX], 1.f - border_scale.mV[VY]); +		gGL.vertex3fv((width_vec - right_border_width + height_vec - top_border_height).mV); + +		// draw top left +		gGL.texCoord2f(0.f, 1.f - border_scale.mV[VY]); +		gGL.vertex3fv((height_vec - top_border_height).mV); + +		gGL.texCoord2f(border_scale.mV[VX], 1.f - border_scale.mV[VY]); +		gGL.vertex3fv((left_border_width + height_vec - top_border_height).mV); + +		gGL.texCoord2f(border_scale.mV[VX], 1.f); +		gGL.vertex3fv((left_border_width + height_vec).mV); + +		gGL.texCoord2f(0.f, 1.f); +		gGL.vertex3fv((height_vec).mV); + +		// draw top middle +		gGL.texCoord2f(border_scale.mV[VX], 1.f - border_scale.mV[VY]); +		gGL.vertex3fv((left_border_width + height_vec - top_border_height).mV); + +		gGL.texCoord2f(1.f - border_scale.mV[VX], 1.f - border_scale.mV[VY]); +		gGL.vertex3fv((width_vec - right_border_width + height_vec - top_border_height).mV); + +		gGL.texCoord2f(1.f - border_scale.mV[VX], 1.f); +		gGL.vertex3fv((width_vec - right_border_width + height_vec).mV); + +		gGL.texCoord2f(border_scale.mV[VX], 1.f); +		gGL.vertex3fv((left_border_width + height_vec).mV); + +		// draw top right +		gGL.texCoord2f(1.f - border_scale.mV[VX], 1.f - border_scale.mV[VY]); +		gGL.vertex3fv((width_vec - right_border_width + height_vec - top_border_height).mV); + +		gGL.texCoord2f(1.f, 1.f - border_scale.mV[VY]); +		gGL.vertex3fv((width_vec + height_vec - top_border_height).mV); + +		gGL.texCoord2f(1.f, 1.f); +		gGL.vertex3fv((width_vec + height_vec).mV); + +		gGL.texCoord2f(1.f - border_scale.mV[VX], 1.f); +		gGL.vertex3fv((width_vec - right_border_width + height_vec).mV); +	} +	gGL.end(); + +} + +void gl_segmented_rect_3d_tex_top(const LLVector2& border_scale, const LLVector3& border_width, const LLVector3& border_height, const LLVector3& width_vec, const LLVector3& height_vec) +{ +	gl_segmented_rect_3d_tex(border_scale, border_width, border_height, width_vec, height_vec, ROUNDED_RECT_TOP); +} + +// static +void LLRender2D::initClass(LLImageProviderInterface* image_provider, +						   const LLVector2* scale_factor) +{ +	sGLScaleFactor = (scale_factor == NULL) ? LLVector2(1.f, 1.f) : *scale_factor; +	sImageProvider = image_provider; +} + +// static +void LLRender2D::cleanupClass() +{ +	if(sImageProvider) +	{ +		sImageProvider->cleanUp(); +	} +} + + +//static +void LLRender2D::translate(F32 x, F32 y, F32 z) +{ +	gGL.translateUI(x,y,z); +	LLFontGL::sCurOrigin.mX += (S32) x; +	LLFontGL::sCurOrigin.mY += (S32) y; +	LLFontGL::sCurDepth += z; +} + +//static +void LLRender2D::pushMatrix() +{ +	gGL.pushUIMatrix(); +	LLFontGL::sOriginStack.push_back(std::make_pair(LLFontGL::sCurOrigin, LLFontGL::sCurDepth)); +} + +//static +void LLRender2D::popMatrix() +{ +	gGL.popUIMatrix(); +	LLFontGL::sCurOrigin = LLFontGL::sOriginStack.back().first; +	LLFontGL::sCurDepth = LLFontGL::sOriginStack.back().second; +	LLFontGL::sOriginStack.pop_back(); +} + +//static  +void LLRender2D::loadIdentity() +{ +	gGL.loadUIIdentity();  +	LLFontGL::sCurOrigin.mX = 0; +	LLFontGL::sCurOrigin.mY = 0; +	LLFontGL::sCurDepth = 0.f; +} + +//static +void LLRender2D::setScaleFactor(const LLVector2 &scale_factor) +{ +	sGLScaleFactor = scale_factor; +} + +//static +void LLRender2D::setLineWidth(F32 width) +{ +	gGL.flush(); +	glLineWidth(width * lerp(sGLScaleFactor.mV[VX], sGLScaleFactor.mV[VY], 0.5f)); +} + +//static +LLPointer<LLUIImage> LLRender2D::getUIImageByID(const LLUUID& image_id, S32 priority) +{ +	if (sImageProvider) +	{ +		return sImageProvider->getUIImageByID(image_id, priority); +	} +	else +	{ +		return NULL; +	} +} + +//static  +LLPointer<LLUIImage> LLRender2D::getUIImage(const std::string& name, S32 priority) +{ +	if (!name.empty() && sImageProvider) +		return sImageProvider->getUIImage(name, priority); +	else +		return NULL; +} + diff --git a/indra/llrender/llrender2dutils.h b/indra/llrender/llrender2dutils.h new file mode 100644 index 0000000000..4ea2d06d99 --- /dev/null +++ b/indra/llrender/llrender2dutils.h @@ -0,0 +1,164 @@ +/**  + * @file llrender2dutils.h + * @brief GL function declarations for immediate-mode gl drawing. + * + * $LicenseInfo:firstyear=2012&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$ + */ + +// All immediate-mode gl drawing should happen here. + + +#ifndef LL_RENDER2DUTILS_H +#define LL_RENDER2DUTILS_H + +#include "llpointer.h"		// LLPointer<> +#include "llrect.h" +#include "llglslshader.h" + +class LLColor4;  +class LLVector3; +class LLVector2; +class LLUIImage; +class LLUUID; + +extern const LLColor4 UI_VERTEX_COLOR; + +BOOL ui_point_in_rect(S32 x, S32 y, S32 left, S32 top, S32 right, S32 bottom); +void gl_state_for_2d(S32 width, S32 height); + +void gl_line_2d(S32 x1, S32 y1, S32 x2, S32 y2); +void gl_line_2d(S32 x1, S32 y1, S32 x2, S32 y2, const LLColor4 &color ); +void gl_triangle_2d(S32 x1, S32 y1, S32 x2, S32 y2, S32 x3, S32 y3, const LLColor4& color, BOOL filled); +void gl_rect_2d_simple( S32 width, S32 height ); + +void gl_draw_x(const LLRect& rect, const LLColor4& color); + +void gl_rect_2d(S32 left, S32 top, S32 right, S32 bottom, BOOL filled = TRUE ); +void gl_rect_2d(S32 left, S32 top, S32 right, S32 bottom, const LLColor4 &color, BOOL filled = TRUE ); +void gl_rect_2d_offset_local( S32 left, S32 top, S32 right, S32 bottom, const LLColor4 &color, S32 pixel_offset = 0, BOOL filled = TRUE ); +void gl_rect_2d_offset_local( S32 left, S32 top, S32 right, S32 bottom, S32 pixel_offset = 0, BOOL filled = TRUE ); +void gl_rect_2d(const LLRect& rect, BOOL filled = TRUE ); +void gl_rect_2d(const LLRect& rect, const LLColor4& color, BOOL filled = TRUE ); +void gl_rect_2d_checkerboard(const LLRect& rect, GLfloat alpha = 1.0f); + +void gl_drop_shadow(S32 left, S32 top, S32 right, S32 bottom, const LLColor4 &start_color, S32 lines); + +void gl_circle_2d(F32 x, F32 y, F32 radius, S32 steps, BOOL filled); +void gl_arc_2d(F32 center_x, F32 center_y, F32 radius, S32 steps, BOOL filled, F32 start_angle, F32 end_angle); +void gl_deep_circle( F32 radius, F32 depth ); +void gl_ring( F32 radius, F32 width, const LLColor4& center_color, const LLColor4& side_color, S32 steps, BOOL render_center ); +void gl_corners_2d(S32 left, S32 top, S32 right, S32 bottom, S32 length, F32 max_frac); +void gl_washer_2d(F32 outer_radius, F32 inner_radius, S32 steps, const LLColor4& inner_color, const LLColor4& outer_color); +void gl_washer_segment_2d(F32 outer_radius, F32 inner_radius, F32 start_radians, F32 end_radians, S32 steps, const LLColor4& inner_color, const LLColor4& outer_color); + +void gl_draw_image(S32 x, S32 y, LLTexture* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f)); +void gl_draw_scaled_image(S32 x, S32 y, S32 width, S32 height, LLTexture* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f)); +void gl_draw_rotated_image(S32 x, S32 y, F32 degrees, LLTexture* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f)); +void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degrees,LLTexture* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f)); +void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 border_width, S32 border_height, S32 width, S32 height, LLTexture* image, const LLColor4 &color, BOOL solid_color = FALSE, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f)); +void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTexture* image, const LLColor4 &color, BOOL solid_color = FALSE, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f), const LLRectf& scale_rect = LLRectf(0.f, 1.f, 1.f, 0.f)); + +void gl_stippled_line_3d( const LLVector3& start, const LLVector3& end, const LLColor4& color, F32 phase = 0.f );  + +void gl_rect_2d_simple_tex( S32 width, S32 height ); + +// segmented rectangles + +/* +   TL |______TOP_________| TR  +     /|                  |\   +   _/_|__________________|_\_ +   L| |    MIDDLE        | |R +   _|_|__________________|_|_ +    \ |    BOTTOM        | /   +   BL\|__________________|/ BR +      |                  |     +*/ + +typedef enum e_rounded_edge +{ +	ROUNDED_RECT_LEFT	= 0x1,  +	ROUNDED_RECT_TOP	= 0x2,  +	ROUNDED_RECT_RIGHT	= 0x4,  +	ROUNDED_RECT_BOTTOM	= 0x8, +	ROUNDED_RECT_ALL	= 0xf +}ERoundedEdge; + + +void gl_segmented_rect_2d_tex(const S32 left, const S32 top, const S32 right, const S32 bottom, const S32 texture_width, const S32 texture_height, const S32 border_size, const U32 edges = ROUNDED_RECT_ALL); +void gl_segmented_rect_2d_fragment_tex(const S32 left, const S32 top, const S32 right, const S32 bottom, const S32 texture_width, const S32 texture_height, const S32 border_size, const F32 start_fragment, const F32 end_fragment, const U32 edges = ROUNDED_RECT_ALL); +void gl_segmented_rect_3d_tex(const LLVector2& border_scale, const LLVector3& border_width, const LLVector3& border_height, const LLVector3& width_vec, const LLVector3& height_vec, U32 edges = ROUNDED_RECT_ALL); +void gl_segmented_rect_3d_tex_top(const LLVector2& border_scale, const LLVector3& border_width, const LLVector3& border_height, const LLVector3& width_vec, const LLVector3& height_vec); + +inline void gl_rect_2d( const LLRect& rect, BOOL filled ) +{ +	gl_rect_2d( rect.mLeft, rect.mTop, rect.mRight, rect.mBottom, filled ); +} + +inline void gl_rect_2d_offset_local( const LLRect& rect, S32 pixel_offset, BOOL filled) +{ +	gl_rect_2d_offset_local( rect.mLeft, rect.mTop, rect.mRight, rect.mBottom, pixel_offset, filled ); +} + +class LLImageProviderInterface; + +class LLRender2D +{ +	LOG_CLASS(LLRender2D); +public: +	static void initClass(LLImageProviderInterface* image_provider, +						  const LLVector2* scale_factor); +	static void cleanupClass(); + +	static void pushMatrix(); +	static void popMatrix(); +	static void loadIdentity(); +	static void translate(F32 x, F32 y, F32 z = 0.0f); + +	static void setLineWidth(F32 width); +	static void setScaleFactor(const LLVector2& scale_factor); + +	static LLPointer<LLUIImage> getUIImageByID(const LLUUID& image_id, S32 priority = 0); +	static LLPointer<LLUIImage> getUIImage(const std::string& name, S32 priority = 0); + +	static LLVector2		sGLScaleFactor; +private: +	static LLImageProviderInterface* sImageProvider; +}; + +class LLImageProviderInterface +{ +protected: +	LLImageProviderInterface() {}; +	virtual ~LLImageProviderInterface() {}; +public: +	virtual LLPointer<LLUIImage> getUIImage(const std::string& name, S32 priority) = 0; +	virtual LLPointer<LLUIImage> getUIImageByID(const LLUUID& id, S32 priority) = 0; +	virtual void cleanUp() = 0; +}; + + +extern LLGLSLShader gSolidColorProgram; +extern LLGLSLShader gUIProgram; + +#endif // LL_RENDER2DUTILS_H + diff --git a/indra/llrender/lltexture.h b/indra/llrender/lltexture.h index 569a65c2e0..093bac20d1 100644 --- a/indra/llrender/lltexture.h +++ b/indra/llrender/lltexture.h @@ -38,10 +38,9 @@ class LLTexUnit ;  class LLFontGL ;  // -//this is an abstract class as the parent for the class LLViewerTexture -//through the following virtual functions, the class LLViewerTexture can be reached from /llrender. +//this is an abstract class as the parent for the class LLGLTexture  // -class LLTexture : public LLRefCount +class LLTexture : public virtual LLRefCount  {  	friend class LLTexUnit ;  	friend class LLFontGL ; @@ -53,7 +52,7 @@ public:  	LLTexture(){}  	// -	//interfaces to access LLViewerTexture +	//interfaces to access LLGLTexture  	//  	virtual S8         getType() const = 0 ;  	virtual void       setKnownDrawSize(S32 width, S32 height) = 0 ; diff --git a/indra/llrender/lluiimage.cpp b/indra/llrender/lluiimage.cpp new file mode 100644 index 0000000000..a632e7ed2f --- /dev/null +++ b/indra/llrender/lluiimage.cpp @@ -0,0 +1,199 @@ +/**  + * @file lluiimage.cpp + * @brief UI implementation + * + * $LicenseInfo:firstyear=2007&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$ + */ + +// Utilities functions the user interface needs + +//#include "llviewerprecompiledheaders.h" +#include "linden_common.h" + +// Project includes +#include "lluiimage.h" +#include "llrender2dutils.h" + +LLUIImage::LLUIImage(const std::string& name, LLPointer<LLTexture> image) +:	mName(name), +	mImage(image), +	mScaleRegion(0.f, 1.f, 1.f, 0.f), +	mClipRegion(0.f, 1.f, 1.f, 0.f), +	mUniformScaling(TRUE), +	mNoClip(TRUE), +	mImageLoaded(NULL) +{ +} + +LLUIImage::~LLUIImage() +{ +	delete mImageLoaded; +} + +void LLUIImage::setClipRegion(const LLRectf& region)  +{  +	mClipRegion = region;  +	mNoClip = mClipRegion.mLeft == 0.f +				&& mClipRegion.mRight == 1.f +				&& mClipRegion.mBottom == 0.f +				&& mClipRegion.mTop == 1.f; +} + +void LLUIImage::setScaleRegion(const LLRectf& region)  +{  +	mScaleRegion = region;  +	mUniformScaling = mScaleRegion.mLeft == 0.f +					&& mScaleRegion.mRight == 1.f +					&& mScaleRegion.mBottom == 0.f +					&& mScaleRegion.mTop == 1.f; +} + +//TODO: move drawing implementation inside class +void LLUIImage::draw(S32 x, S32 y, const LLColor4& color) const +{ +	gl_draw_scaled_image(x, y, getWidth(), getHeight(), mImage, color, mClipRegion); +} + +void LLUIImage::draw(S32 x, S32 y, S32 width, S32 height, const LLColor4& color) const +{ +	if (mUniformScaling) +	{ +		gl_draw_scaled_image(x, y, width, height, mImage, color, mClipRegion); +	} +	else +	{ +		gl_draw_scaled_image_with_border( +			x, y,  +			width, height,  +			mImage,  +			color, +			FALSE, +			mClipRegion, +			mScaleRegion); +	} +} + +void LLUIImage::drawSolid(S32 x, S32 y, S32 width, S32 height, const LLColor4& color) const +{ +	gl_draw_scaled_image_with_border( +		x, y,  +		width, height,  +		mImage,  +		color,  +		TRUE, +		mClipRegion, +		mScaleRegion); +} + +void LLUIImage::drawBorder(S32 x, S32 y, S32 width, S32 height, const LLColor4& color, S32 border_width) const +{ +	LLRect border_rect; +	border_rect.setOriginAndSize(x, y, width, height); +	border_rect.stretch(border_width, border_width); +	drawSolid(border_rect, color); +} + +S32 LLUIImage::getWidth() const +{  +	// return clipped dimensions of actual image area +	return llround((F32)mImage->getWidth(0) * mClipRegion.getWidth());  +} + +S32 LLUIImage::getHeight() const +{  +	// return clipped dimensions of actual image area +	return llround((F32)mImage->getHeight(0) * mClipRegion.getHeight());  +} + +S32 LLUIImage::getTextureWidth() const +{ +	return mImage->getWidth(0); +} + +S32 LLUIImage::getTextureHeight() const +{ +	return mImage->getHeight(0); +} + +boost::signals2::connection LLUIImage::addLoadedCallback( const image_loaded_signal_t::slot_type& cb )  +{ +	if (!mImageLoaded)  +	{ +		mImageLoaded = new image_loaded_signal_t(); +	} +	return mImageLoaded->connect(cb); +} + + +void LLUIImage::onImageLoaded() +{ +	if (mImageLoaded) +	{ +		(*mImageLoaded)(); +	} +} + + +namespace LLInitParam +{ +	void ParamValue<LLUIImage*, TypeValues<LLUIImage*> >::updateValueFromBlock() +	{ +		// The keyword "none" is specifically requesting a null image +		// do not default to current value. Used to overwrite template images.  +		if (name() == "none") +		{ +			updateValue(NULL); +			return; +		} + +		LLUIImage* imagep =  LLRender2D::getUIImage(name()); +		if (imagep) +		{ +			updateValue(imagep); +		} +	} +	 +	void ParamValue<LLUIImage*, TypeValues<LLUIImage*> >::updateBlockFromValue(bool make_block_authoritative) +	{ +		if (getValue() == NULL) +		{ +			name.set("none", make_block_authoritative); +		} +		else +		{ +			name.set(getValue()->getName(), make_block_authoritative); +		} +	} + +	 +	bool ParamCompare<LLUIImage*, false>::equals( +		LLUIImage* const &a, +		LLUIImage* const &b) +	{ +		// force all LLUIImages for XML UI export to be "non-default" +		if (!a && !b) +			return false; +		else +			return (a == b); +	} +} + diff --git a/indra/llrender/lluiimage.h b/indra/llrender/lluiimage.h new file mode 100644 index 0000000000..f07e8fa746 --- /dev/null +++ b/indra/llrender/lluiimage.h @@ -0,0 +1,124 @@ +/**  + * @file lluiimage.h + * @brief wrapper for images used in the UI that handles smart scaling, etc. + * + * $LicenseInfo:firstyear=2007&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$ + */ + +#ifndef LL_LLUIIMAGE_H +#define LL_LLUIIMAGE_H + +#include "v4color.h" +#include "llpointer.h" +#include "llrefcount.h" +#include "llrefcount.h" +#include "llrect.h" +#include <boost/function.hpp> +#include <boost/signals2.hpp> +#include "llinitparam.h" +#include "lltexture.h" + +extern const LLColor4 UI_VERTEX_COLOR; + +class LLUIImage : public LLRefCount +{ +public: +	typedef boost::signals2::signal<void (void)> image_loaded_signal_t; + +	LLUIImage(const std::string& name, LLPointer<LLTexture> image); +	virtual ~LLUIImage(); + +	void setClipRegion(const LLRectf& region); +	void setScaleRegion(const LLRectf& region); + +	LLPointer<LLTexture> getImage() { return mImage; } +	const LLPointer<LLTexture>& getImage() const { return mImage; } + +	void draw(S32 x, S32 y, S32 width, S32 height, const LLColor4& color = UI_VERTEX_COLOR) const; +	void draw(S32 x, S32 y, const LLColor4& color = UI_VERTEX_COLOR) const; +	void draw(const LLRect& rect, const LLColor4& color = UI_VERTEX_COLOR) const { draw(rect.mLeft, rect.mBottom, rect.getWidth(), rect.getHeight(), color); } +	 +	void drawSolid(S32 x, S32 y, S32 width, S32 height, const LLColor4& color) const; +	void drawSolid(const LLRect& rect, const LLColor4& color) const { drawSolid(rect.mLeft, rect.mBottom, rect.getWidth(), rect.getHeight(), color); } +	void drawSolid(S32 x, S32 y, const LLColor4& color) const { drawSolid(x, y, getWidth(), getHeight(), color); } + +	void drawBorder(S32 x, S32 y, S32 width, S32 height, const LLColor4& color, S32 border_width) const; +	void drawBorder(const LLRect& rect, const LLColor4& color, S32 border_width) const { drawBorder(rect.mLeft, rect.mBottom, rect.getWidth(), rect.getHeight(), color, border_width); } +	void drawBorder(S32 x, S32 y, const LLColor4& color, S32 border_width) const { drawBorder(x, y, getWidth(), getHeight(), color, border_width); } +	 +	const std::string& getName() const { return mName; } + +	virtual S32 getWidth() const; +	virtual S32 getHeight() const; + +	// returns dimensions of underlying textures, which might not be equal to ui image portion +	S32 getTextureWidth() const; +	S32 getTextureHeight() const; + +	boost::signals2::connection addLoadedCallback( const image_loaded_signal_t::slot_type& cb ); + +	void onImageLoaded(); + +protected: +	image_loaded_signal_t* mImageLoaded; + +	std::string			mName; +	LLRectf				mScaleRegion; +	LLRectf				mClipRegion; +	LLPointer<LLTexture> mImage; +	BOOL				mUniformScaling; +	BOOL				mNoClip; +}; + +namespace LLInitParam +{ +	template<> +	class ParamValue<LLUIImage*, TypeValues<LLUIImage*> >  +	:	public CustomParamValue<LLUIImage*> +	{ +		typedef boost::add_reference<boost::add_const<LLUIImage*>::type>::type	T_const_ref; +		typedef CustomParamValue<LLUIImage*> super_t; +	public: +		Optional<std::string> name; + +		ParamValue(LLUIImage* const& image) +		:	super_t(image) +		{ +			updateBlockFromValue(false); +			addSynonym(name, "name"); +		} + +		void updateValueFromBlock(); +		void updateBlockFromValue(bool make_block_authoritative); +	}; + +	// Need custom comparison function for our test app, which only loads +	// LLUIImage* as NULL. +	template<> +	struct ParamCompare<LLUIImage*, false> +	{ +		static bool equals(LLUIImage* const &a, LLUIImage* const &b); +	}; +} + +typedef LLPointer<LLUIImage> LLUIImagePtr; +#endif | 
