diff options
author | Andrey Lihatskiy <alihatskiy@productengine.com> | 2024-05-15 12:46:26 +0300 |
---|---|---|
committer | Andrey Lihatskiy <alihatskiy@productengine.com> | 2024-05-15 12:46:26 +0300 |
commit | bf1235b017b254ba989b156c73c4ce18ba4e6c23 (patch) | |
tree | 8dd5dad68be3aa5cda16938cc3bfaa70f6faad41 /indra/llrender | |
parent | 1e9e5a7b7629276d509c352699fb5891c2dc6587 (diff) | |
parent | e7eced3c87310b15ac20cc3cd470d67686104a14 (diff) |
Merge branch 'marchcat/w-whitespace' into marchcat/x-mf-merge
Diffstat (limited to 'indra/llrender')
41 files changed, 7904 insertions, 7904 deletions
diff --git a/indra/llrender/llatmosphere.cpp b/indra/llrender/llatmosphere.cpp index 8e37ca9b90..eae5623a3c 100644 --- a/indra/llrender/llatmosphere.cpp +++ b/indra/llrender/llatmosphere.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llatmosphere.cpp * @brief LLAtmosphere integration impl * * $LicenseInfo:firstyear=2018&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2018, 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$ */ @@ -175,8 +175,8 @@ bool AtmosphericModelSettings::operator==(const AtmosphericModelSettings& rhs) c void LLAtmosphere::initClass() { if (!gAtmosphere) - { - gAtmosphere = new LLAtmosphere; + { + gAtmosphere = new LLAtmosphere; } } diff --git a/indra/llrender/llatmosphere.h b/indra/llrender/llatmosphere.h index 572365d864..4b8c7d0819 100644 --- a/indra/llrender/llatmosphere.h +++ b/indra/llrender/llatmosphere.h @@ -1,25 +1,25 @@ -/** +/** * @file llatmosphere.h * @brief LLAtmosphere class * * $LicenseInfo:firstyear=2018&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2018, 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$ */ @@ -146,7 +146,7 @@ public: bool configureAtmosphericModel(AtmosphericModelSettings& settings); -protected: +protected: LLAtmosphere(const LLAtmosphere& rhs) { *this = rhs; diff --git a/indra/llrender/llcubemap.cpp b/indra/llrender/llcubemap.cpp index 254288a86e..f16d5b6e53 100644 --- a/indra/llrender/llcubemap.cpp +++ b/indra/llrender/llcubemap.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llcubemap.cpp * @brief LLCubeMap class implementation * * $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$ */ @@ -47,16 +47,16 @@ namespace { bool LLCubeMap::sUseCubeMaps = true; LLCubeMap::LLCubeMap(bool init_as_srgb) - : mTextureStage(0), - mMatrixStage(0), - mIssRGB(init_as_srgb) + : mTextureStage(0), + mMatrixStage(0), + mIssRGB(init_as_srgb) { - mTargets[0] = GL_TEXTURE_CUBE_MAP_NEGATIVE_X; - mTargets[1] = GL_TEXTURE_CUBE_MAP_POSITIVE_X; - mTargets[2] = GL_TEXTURE_CUBE_MAP_NEGATIVE_Y; - mTargets[3] = GL_TEXTURE_CUBE_MAP_POSITIVE_Y; - mTargets[4] = GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; - mTargets[5] = GL_TEXTURE_CUBE_MAP_POSITIVE_Z; + mTargets[0] = GL_TEXTURE_CUBE_MAP_NEGATIVE_X; + mTargets[1] = GL_TEXTURE_CUBE_MAP_POSITIVE_X; + mTargets[2] = GL_TEXTURE_CUBE_MAP_NEGATIVE_Y; + mTargets[3] = GL_TEXTURE_CUBE_MAP_POSITIVE_Y; + mTargets[4] = GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; + mTargets[5] = GL_TEXTURE_CUBE_MAP_POSITIVE_Z; } LLCubeMap::~LLCubeMap() @@ -65,106 +65,106 @@ LLCubeMap::~LLCubeMap() void LLCubeMap::initGL() { - llassert(gGLManager.mInited); - - if (LLCubeMap::sUseCubeMaps) - { - // Not initialized, do stuff. - if (mImages[0].isNull()) - { - U32 texname = 0; - - LLImageGL::generateTextures(1, &texname); - - for (int i = 0; i < 6; i++) - { - mImages[i] = new LLImageGL(RESOLUTION, RESOLUTION, 4, FALSE); + llassert(gGLManager.mInited); + + if (LLCubeMap::sUseCubeMaps) + { + // Not initialized, do stuff. + if (mImages[0].isNull()) + { + U32 texname = 0; + + LLImageGL::generateTextures(1, &texname); + + for (int i = 0; i < 6; i++) + { + mImages[i] = new LLImageGL(RESOLUTION, RESOLUTION, 4, FALSE); #if USE_SRGB_DECODE if (mIssRGB) { mImages[i]->setExplicitFormat(GL_SRGB8_ALPHA8, GL_RGBA); } #endif - mImages[i]->setTarget(mTargets[i], LLTexUnit::TT_CUBE_MAP); - mRawImages[i] = new LLImageRaw(RESOLUTION, RESOLUTION, 4); - mImages[i]->createGLTexture(0, mRawImages[i], texname); - - gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_CUBE_MAP, texname); - mImages[i]->setAddressMode(LLTexUnit::TAM_CLAMP); - stop_glerror(); - } - gGL.getTexUnit(0)->disable(); - } - disable(); - } - else - { - LL_WARNS() << "Using cube map without extension!" << LL_ENDL; - } + mImages[i]->setTarget(mTargets[i], LLTexUnit::TT_CUBE_MAP); + mRawImages[i] = new LLImageRaw(RESOLUTION, RESOLUTION, 4); + mImages[i]->createGLTexture(0, mRawImages[i], texname); + + gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_CUBE_MAP, texname); + mImages[i]->setAddressMode(LLTexUnit::TAM_CLAMP); + stop_glerror(); + } + gGL.getTexUnit(0)->disable(); + } + disable(); + } + else + { + LL_WARNS() << "Using cube map without extension!" << LL_ENDL; + } } void LLCubeMap::initRawData(const std::vector<LLPointer<LLImageRaw> >& rawimages) { - bool flip_x[6] = { false, true, false, false, true, false }; - bool flip_y[6] = { true, true, true, false, true, true }; - bool transpose[6] = { false, false, false, false, true, true }; - - // Yes, I know that this is inefficient! - djs 08/08/02 - for (int i = 0; i < 6; i++) - { - const U8 *sd = rawimages[i]->getData(); - U8 *td = mRawImages[i]->getData(); - - S32 offset = 0; - S32 sx, sy, so; - for (int y = 0; y < 64; y++) - { - for (int x = 0; x < 64; x++) - { - sx = x; - sy = y; - if (flip_y[i]) - { - sy = 63 - y; - } - if (flip_x[i]) - { - sx = 63 - x; - } - if (transpose[i]) - { - S32 temp = sx; - sx = sy; - sy = temp; - } - - so = 64*sy + sx; - so *= 4; - *(td + offset++) = *(sd + so++); - *(td + offset++) = *(sd + so++); - *(td + offset++) = *(sd + so++); - *(td + offset++) = *(sd + so++); - } - } - } + bool flip_x[6] = { false, true, false, false, true, false }; + bool flip_y[6] = { true, true, true, false, true, true }; + bool transpose[6] = { false, false, false, false, true, true }; + + // Yes, I know that this is inefficient! - djs 08/08/02 + for (int i = 0; i < 6; i++) + { + const U8 *sd = rawimages[i]->getData(); + U8 *td = mRawImages[i]->getData(); + + S32 offset = 0; + S32 sx, sy, so; + for (int y = 0; y < 64; y++) + { + for (int x = 0; x < 64; x++) + { + sx = x; + sy = y; + if (flip_y[i]) + { + sy = 63 - y; + } + if (flip_x[i]) + { + sx = 63 - x; + } + if (transpose[i]) + { + S32 temp = sx; + sx = sy; + sy = temp; + } + + so = 64*sy + sx; + so *= 4; + *(td + offset++) = *(sd + so++); + *(td + offset++) = *(sd + so++); + *(td + offset++) = *(sd + so++); + *(td + offset++) = *(sd + so++); + } + } + } } void LLCubeMap::initGLData() { LL_PROFILE_ZONE_SCOPED; - for (int i = 0; i < 6; i++) - { - mImages[i]->setSubImage(mRawImages[i], 0, 0, RESOLUTION, RESOLUTION); - } + for (int i = 0; i < 6; i++) + { + mImages[i]->setSubImage(mRawImages[i], 0, 0, RESOLUTION, RESOLUTION); + } } void LLCubeMap::init(const std::vector<LLPointer<LLImageRaw> >& rawimages) { - if (!gGLManager.mIsDisabled) - { - initGL(); - initRawData(rawimages); - initGLData(); - } + if (!gGLManager.mIsDisabled) + { + initGL(); + initRawData(rawimages); + initGLData(); + } } void LLCubeMap::initReflectionMap(U32 resolution, U32 components) @@ -236,99 +236,99 @@ void LLCubeMap::generateMipMaps() GLuint LLCubeMap::getGLName() { - return mImages[0]->getTexName(); + return mImages[0]->getTexName(); } void LLCubeMap::bind() { - gGL.getTexUnit(mTextureStage)->bind(this); + gGL.getTexUnit(mTextureStage)->bind(this); } void LLCubeMap::enable(S32 stage) { - enableTexture(stage); + enableTexture(stage); } void LLCubeMap::enableTexture(S32 stage) { - mTextureStage = stage; - if (stage >= 0 && LLCubeMap::sUseCubeMaps) - { - gGL.getTexUnit(stage)->enable(LLTexUnit::TT_CUBE_MAP); - } + mTextureStage = stage; + if (stage >= 0 && LLCubeMap::sUseCubeMaps) + { + gGL.getTexUnit(stage)->enable(LLTexUnit::TT_CUBE_MAP); + } } void LLCubeMap::disable(void) { - disableTexture(); + disableTexture(); } void LLCubeMap::disableTexture(void) { - if (mTextureStage >= 0 && LLCubeMap::sUseCubeMaps) - { - gGL.getTexUnit(mTextureStage)->disable(); - if (mTextureStage == 0) - { - gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); - } - } + if (mTextureStage >= 0 && LLCubeMap::sUseCubeMaps) + { + gGL.getTexUnit(mTextureStage)->disable(); + if (mTextureStage == 0) + { + gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); + } + } } void LLCubeMap::setMatrix(S32 stage) { - mMatrixStage = stage; - - if (mMatrixStage < 0) return; - - //if (stage > 0) - { - gGL.getTexUnit(stage)->activate(); - } - - LLVector3 x(gGLModelView+0); - LLVector3 y(gGLModelView+4); - LLVector3 z(gGLModelView+8); - - LLMatrix3 mat3; - mat3.setRows(x,y,z); - LLMatrix4 trans(mat3); - trans.transpose(); - - gGL.matrixMode(LLRender::MM_TEXTURE); - gGL.pushMatrix(); - gGL.loadMatrix((F32 *)trans.mMatrix); - gGL.matrixMode(LLRender::MM_MODELVIEW); - - /*if (stage > 0) - { - gGL.getTexUnit(0)->activate(); - }*/ + mMatrixStage = stage; + + if (mMatrixStage < 0) return; + + //if (stage > 0) + { + gGL.getTexUnit(stage)->activate(); + } + + LLVector3 x(gGLModelView+0); + LLVector3 y(gGLModelView+4); + LLVector3 z(gGLModelView+8); + + LLMatrix3 mat3; + mat3.setRows(x,y,z); + LLMatrix4 trans(mat3); + trans.transpose(); + + gGL.matrixMode(LLRender::MM_TEXTURE); + gGL.pushMatrix(); + gGL.loadMatrix((F32 *)trans.mMatrix); + gGL.matrixMode(LLRender::MM_MODELVIEW); + + /*if (stage > 0) + { + gGL.getTexUnit(0)->activate(); + }*/ } void LLCubeMap::restoreMatrix() { - if (mMatrixStage < 0) return; - - //if (mMatrixStage > 0) - { - gGL.getTexUnit(mMatrixStage)->activate(); - } - gGL.matrixMode(LLRender::MM_TEXTURE); - gGL.popMatrix(); - gGL.matrixMode(LLRender::MM_MODELVIEW); - - /*if (mMatrixStage > 0) - { - gGL.getTexUnit(0)->activate(); - }*/ + if (mMatrixStage < 0) return; + + //if (mMatrixStage > 0) + { + gGL.getTexUnit(mMatrixStage)->activate(); + } + gGL.matrixMode(LLRender::MM_TEXTURE); + gGL.popMatrix(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + + /*if (mMatrixStage > 0) + { + gGL.getTexUnit(0)->activate(); + }*/ } void LLCubeMap::destroyGL() { - for (S32 i = 0; i < 6; i++) - { - mImages[i] = NULL; - } + for (S32 i = 0; i < 6; i++) + { + mImages[i] = NULL; + } } diff --git a/indra/llrender/llcubemap.h b/indra/llrender/llcubemap.h index b9e081cea3..fa5c0ecbf3 100644 --- a/indra/llrender/llcubemap.h +++ b/indra/llrender/llcubemap.h @@ -1,25 +1,25 @@ -/** +/** * @file llcubemap.h * @brief LLCubeMap class definition * * $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$ */ @@ -36,10 +36,10 @@ class LLVector3; // Environment map hack! class LLCubeMap : public LLRefCount { - bool mIssRGB; + bool mIssRGB; public: - LLCubeMap(bool init_as_srgb); - void init(const std::vector<LLPointer<LLImageRaw> >& rawimages); + LLCubeMap(bool init_as_srgb); + void init(const std::vector<LLPointer<LLImageRaw> >& rawimages); // initialize as an undefined cubemap at the given resolution // used for render-to-cubemap operations @@ -51,42 +51,42 @@ public: // respect the resolution of rawimages // Raw images must point to array of six square images that are all the same resolution void initEnvironmentMap(const std::vector<LLPointer<LLImageRaw> >& rawimages); - void initGL(); - void initRawData(const std::vector<LLPointer<LLImageRaw> >& rawimages); - void initGLData(); - - void bind(); - void enable(S32 stage); - - void enableTexture(S32 stage); - S32 getStage(void) { return mTextureStage; } - - void disable(void); - void disableTexture(void); - void setMatrix(S32 stage); - void restoreMatrix(); + void initGL(); + void initRawData(const std::vector<LLPointer<LLImageRaw> >& rawimages); + void initGLData(); + + void bind(); + void enable(S32 stage); + + void enableTexture(S32 stage); + S32 getStage(void) { return mTextureStage; } + + void disable(void); + void disableTexture(void); + void setMatrix(S32 stage); + void restoreMatrix(); U32 getResolution() { return mImages[0].notNull() ? mImages[0]->getWidth(0) : 0; } - + // generate mip maps for this Cube Map using GL // NOTE: Cube Map MUST already be resident in VRAM void generateMipMaps(); - GLuint getGLName(); + GLuint getGLName(); - void destroyGL(); + void destroyGL(); public: - static bool sUseCubeMaps; + static bool sUseCubeMaps; protected: - friend class LLTexUnit; - ~LLCubeMap(); - LLGLenum mTargets[6]; - LLPointer<LLImageGL> mImages[6]; - LLPointer<LLImageRaw> mRawImages[6]; - S32 mTextureStage; - S32 mMatrixStage; + friend class LLTexUnit; + ~LLCubeMap(); + LLGLenum mTargets[6]; + LLPointer<LLImageGL> mImages[6]; + LLPointer<LLImageRaw> mRawImages[6]; + S32 mTextureStage; + S32 mMatrixStage; }; #endif diff --git a/indra/llrender/llcubemaparray.cpp b/indra/llrender/llcubemaparray.cpp index 1debd33953..03fbb90bf6 100644 --- a/indra/llrender/llcubemaparray.cpp +++ b/indra/llrender/llcubemaparray.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llcubemaparray.cpp * @brief LLCubeMap class implementation * * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2022, 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$ */ @@ -63,7 +63,7 @@ LLVector3 LLCubeMapArray::sLookVecs[6] = LLVector3(0, 0, -1) }; -LLVector3 LLCubeMapArray::sUpVecs[6] = +LLVector3 LLCubeMapArray::sUpVecs[6] = { LLVector3(0, -1, 0), LLVector3(0, -1, 0), @@ -77,7 +77,7 @@ LLVector3 LLCubeMapArray::sClipToCubeLookVecs[6] = { LLVector3(0, 0, -1), //GOOD LLVector3(0, 0, 1), //GOOD - + LLVector3(1, 0, 0), // GOOD LLVector3(1, 0, 0), // GOOD @@ -98,9 +98,9 @@ LLVector3 LLCubeMapArray::sClipToCubeUpVecs[6] = }; LLCubeMapArray::LLCubeMapArray() - : mTextureStage(0) + : mTextureStage(0) { - + } LLCubeMapArray::~LLCubeMapArray() @@ -170,7 +170,7 @@ void LLCubeMapArray::unbind() GLuint LLCubeMapArray::getGLName() { - return mImage->getTexName(); + return mImage->getTexName(); } void LLCubeMapArray::destroyGL() diff --git a/indra/llrender/llcubemaparray.h b/indra/llrender/llcubemaparray.h index 6c3f7dc890..9d78c5b0d4 100644 --- a/indra/llrender/llcubemaparray.h +++ b/indra/llrender/llcubemaparray.h @@ -1,25 +1,25 @@ -/** +/** * @file llcubemaparray.h * @brief LLCubeMap class definition * * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2022, 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$ */ @@ -35,10 +35,10 @@ class LLVector3; class LLCubeMapArray : public LLRefCount { public: - LLCubeMapArray(); + LLCubeMapArray(); static GLenum sTargets[6]; - + // look and up vectors for each cube face (agent space) static LLVector3 sLookVecs[6]; static LLVector3 sUpVecs[6]; @@ -47,18 +47,18 @@ public: static LLVector3 sClipToCubeLookVecs[6]; static LLVector3 sClipToCubeUpVecs[6]; - // allocate a cube map array + // allocate a cube map array // res - resolution of each cube face // components - number of components per pixel // count - number of cube maps in the array // use_mips - if TRUE, mipmaps will be allocated for this cube map array and anisotropic filtering will be used void allocate(U32 res, U32 components, U32 count, BOOL use_mips = TRUE); - void bind(S32 stage); + void bind(S32 stage); void unbind(); - - GLuint getGLName(); - void destroyGL(); + GLuint getGLName(); + + void destroyGL(); // get width of cubemaps in array (they're cubes, so this is also the height) U32 getWidth() const { return mWidth; } @@ -67,10 +67,10 @@ public: U32 getCount() const { return mCount; } protected: - friend class LLTexUnit; - ~LLCubeMapArray(); - LLPointer<LLImageGL> mImage; + friend class LLTexUnit; + ~LLCubeMapArray(); + LLPointer<LLImageGL> mImage; U32 mWidth = 0; U32 mCount = 0; - S32 mTextureStage; + S32 mTextureStage; }; diff --git a/indra/llrender/llfontbitmapcache.cpp b/indra/llrender/llfontbitmapcache.cpp index 42b0045cf3..243041945a 100644 --- a/indra/llrender/llfontbitmapcache.cpp +++ b/indra/llrender/llfontbitmapcache.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llfontbitmapcache.cpp * @brief Storage for previously rendered glyphs. * * $LicenseInfo:firstyear=2008&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$ */ @@ -39,60 +39,60 @@ LLFontBitmapCache::~LLFontBitmapCache() } void LLFontBitmapCache::init(S32 max_char_width, - S32 max_char_height) + S32 max_char_height) { - reset(); - - mMaxCharWidth = max_char_width; - mMaxCharHeight = max_char_height; - - S32 image_width = mMaxCharWidth * 20; - S32 pow_iw = 2; - while (pow_iw < image_width) - { - pow_iw <<= 1; - } - image_width = pow_iw; - image_width = llmin(512, image_width); // Don't make bigger than 512x512, ever. - - mBitmapWidth = image_width; - mBitmapHeight = image_width; + reset(); + + mMaxCharWidth = max_char_width; + mMaxCharHeight = max_char_height; + + S32 image_width = mMaxCharWidth * 20; + S32 pow_iw = 2; + while (pow_iw < image_width) + { + pow_iw <<= 1; + } + image_width = pow_iw; + image_width = llmin(512, image_width); // Don't make bigger than 512x512, ever. + + mBitmapWidth = image_width; + mBitmapHeight = image_width; } LLImageRaw *LLFontBitmapCache::getImageRaw(EFontGlyphType bitmap_type, U32 bitmap_num) const { - const U32 bitmap_idx = static_cast<U32>(bitmap_type); - if (bitmap_type >= EFontGlyphType::Count || bitmap_num >= mImageRawVec[bitmap_idx].size()) - return nullptr; + const U32 bitmap_idx = static_cast<U32>(bitmap_type); + if (bitmap_type >= EFontGlyphType::Count || bitmap_num >= mImageRawVec[bitmap_idx].size()) + return nullptr; - return mImageRawVec[bitmap_idx][bitmap_num]; + return mImageRawVec[bitmap_idx][bitmap_num]; } LLImageGL *LLFontBitmapCache::getImageGL(EFontGlyphType bitmap_type, U32 bitmap_num) const { - const U32 bitmap_idx = static_cast<U32>(bitmap_type); - if (bitmap_type >= EFontGlyphType::Count || bitmap_num >= mImageGLVec[bitmap_idx].size()) - return nullptr; + const U32 bitmap_idx = static_cast<U32>(bitmap_type); + if (bitmap_type >= EFontGlyphType::Count || bitmap_num >= mImageGLVec[bitmap_idx].size()) + return nullptr; - return mImageGLVec[bitmap_idx][bitmap_num]; + return mImageGLVec[bitmap_idx][bitmap_num]; } BOOL LLFontBitmapCache::nextOpenPos(S32 width, S32& pos_x, S32& pos_y, EFontGlyphType bitmap_type, U32& bitmap_num) { - if (bitmap_type >= EFontGlyphType::Count) - { - return FALSE; - } - - const U32 bitmap_idx = static_cast<U32>(bitmap_type); - if (mImageRawVec[bitmap_idx].empty() || (mCurrentOffsetX[bitmap_idx] + width + 1) > mBitmapWidth) - { - if ((mImageRawVec[bitmap_idx].empty()) || (mCurrentOffsetY[bitmap_idx] + 2*mMaxCharHeight + 2) > mBitmapHeight) - { - // We're out of space in the current image, or no image - // has been allocated yet. Make a new one. - + if (bitmap_type >= EFontGlyphType::Count) + { + return FALSE; + } + + const U32 bitmap_idx = static_cast<U32>(bitmap_type); + if (mImageRawVec[bitmap_idx].empty() || (mCurrentOffsetX[bitmap_idx] + width + 1) > mBitmapWidth) + { + if ((mImageRawVec[bitmap_idx].empty()) || (mCurrentOffsetY[bitmap_idx] + 2*mMaxCharHeight + 2) > mBitmapHeight) + { + // We're out of space in the current image, or no image + // has been allocated yet. Make a new one. + S32 image_width = mMaxCharWidth * 20; S32 pow_iw = 2; while (pow_iw < image_width) @@ -102,85 +102,85 @@ BOOL LLFontBitmapCache::nextOpenPos(S32 width, S32& pos_x, S32& pos_y, EFontGlyp image_width = pow_iw; image_width = llmin(512, image_width); // Don't make bigger than 512x512, ever. S32 image_height = image_width; - + mBitmapWidth = image_width; mBitmapHeight = image_height; - - S32 num_components = getNumComponents(bitmap_type); - mImageRawVec[bitmap_idx].push_back(new LLImageRaw(mBitmapWidth, mBitmapHeight, num_components)); - bitmap_num = mImageRawVec[bitmap_idx].size() - 1; - - LLImageRaw* image_raw = getImageRaw(bitmap_type, bitmap_num); - if (EFontGlyphType::Grayscale == bitmap_type) - { - image_raw->clear(255, 0); - } - - // Make corresponding GL image. - mImageGLVec[bitmap_idx].push_back(new LLImageGL(image_raw, false)); - LLImageGL* image_gl = getImageGL(bitmap_type, bitmap_num); - - // Start at beginning of the new image. - mCurrentOffsetX[bitmap_idx] = 1; - mCurrentOffsetY[bitmap_idx] = 1; - - // Attach corresponding GL texture. (*TODO: is this needed?) - gGL.getTexUnit(0)->bind(image_gl); - image_gl->setFilteringOption(LLTexUnit::TFO_POINT); // was setMipFilterNearest(TRUE, TRUE); - } - else - { - // Move to next row in current image. - mCurrentOffsetX[bitmap_idx] = 1; - mCurrentOffsetY[bitmap_idx] += mMaxCharHeight + 1; - } - } - - pos_x = mCurrentOffsetX[bitmap_idx]; - pos_y = mCurrentOffsetY[bitmap_idx]; - bitmap_num = getNumBitmaps(bitmap_type) - 1; - - mCurrentOffsetX[bitmap_idx] += width + 1; - - return TRUE; + + S32 num_components = getNumComponents(bitmap_type); + mImageRawVec[bitmap_idx].push_back(new LLImageRaw(mBitmapWidth, mBitmapHeight, num_components)); + bitmap_num = mImageRawVec[bitmap_idx].size() - 1; + + LLImageRaw* image_raw = getImageRaw(bitmap_type, bitmap_num); + if (EFontGlyphType::Grayscale == bitmap_type) + { + image_raw->clear(255, 0); + } + + // Make corresponding GL image. + mImageGLVec[bitmap_idx].push_back(new LLImageGL(image_raw, false)); + LLImageGL* image_gl = getImageGL(bitmap_type, bitmap_num); + + // Start at beginning of the new image. + mCurrentOffsetX[bitmap_idx] = 1; + mCurrentOffsetY[bitmap_idx] = 1; + + // Attach corresponding GL texture. (*TODO: is this needed?) + gGL.getTexUnit(0)->bind(image_gl); + image_gl->setFilteringOption(LLTexUnit::TFO_POINT); // was setMipFilterNearest(TRUE, TRUE); + } + else + { + // Move to next row in current image. + mCurrentOffsetX[bitmap_idx] = 1; + mCurrentOffsetY[bitmap_idx] += mMaxCharHeight + 1; + } + } + + pos_x = mCurrentOffsetX[bitmap_idx]; + pos_y = mCurrentOffsetY[bitmap_idx]; + bitmap_num = getNumBitmaps(bitmap_type) - 1; + + mCurrentOffsetX[bitmap_idx] += width + 1; + + return TRUE; } void LLFontBitmapCache::destroyGL() { - for (U32 idx = 0, cnt = static_cast<U32>(EFontGlyphType::Count); idx < cnt; idx++) - { - for (LLImageGL* image_gl : mImageGLVec[idx]) - { - image_gl->destroyGLTexture(); - } - } + for (U32 idx = 0, cnt = static_cast<U32>(EFontGlyphType::Count); idx < cnt; idx++) + { + for (LLImageGL* image_gl : mImageGLVec[idx]) + { + image_gl->destroyGLTexture(); + } + } } void LLFontBitmapCache::reset() { - for (U32 idx = 0, cnt = static_cast<U32>(EFontGlyphType::Count); idx < cnt; idx++) - { - mImageRawVec[idx].clear(); - mImageGLVec[idx].clear(); - mCurrentOffsetX[idx] = 1; - mCurrentOffsetY[idx] = 1; - } - - mBitmapWidth = 0; - mBitmapHeight = 0; + for (U32 idx = 0, cnt = static_cast<U32>(EFontGlyphType::Count); idx < cnt; idx++) + { + mImageRawVec[idx].clear(); + mImageGLVec[idx].clear(); + mCurrentOffsetX[idx] = 1; + mCurrentOffsetY[idx] = 1; + } + + mBitmapWidth = 0; + mBitmapHeight = 0; } //static U32 LLFontBitmapCache::getNumComponents(EFontGlyphType bitmap_type) { - switch (bitmap_type) - { - case EFontGlyphType::Grayscale: - return 2; - case EFontGlyphType::Color: - return 4; - default: - llassert(false); - return 2; - } + switch (bitmap_type) + { + case EFontGlyphType::Grayscale: + return 2; + case EFontGlyphType::Color: + return 4; + default: + llassert(false); + return 2; + } } diff --git a/indra/llrender/llfontbitmapcache.h b/indra/llrender/llfontbitmapcache.h index c63281ab70..8f704df44f 100644 --- a/indra/llrender/llfontbitmapcache.h +++ b/indra/llrender/llfontbitmapcache.h @@ -1,25 +1,25 @@ -/** +/** * @file llfontbitmapcache.h * @brief Storage for previously rendered glyphs. * * $LicenseInfo:firstyear=2008&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$ */ @@ -32,10 +32,10 @@ enum class EFontGlyphType : U32 { - Grayscale = 0, - Color, - Count, - Unspecified, + Grayscale = 0, + Color, + Count, + Unspecified, }; // Maintain a collection of bitmaps containing rendered glyphs. @@ -43,39 +43,39 @@ enum class EFontGlyphType : U32 class LLFontBitmapCache { public: - LLFontBitmapCache(); - ~LLFontBitmapCache(); + LLFontBitmapCache(); + ~LLFontBitmapCache(); + + // Need to call this once, before caching any glyphs. + void init(S32 max_char_width, + S32 max_char_height); + + void reset(); - // Need to call this once, before caching any glyphs. - void init(S32 max_char_width, - S32 max_char_height); + BOOL nextOpenPos(S32 width, S32& posX, S32& posY, EFontGlyphType bitmapType, U32& bitmapNum); - void reset(); + void destroyGL(); - BOOL nextOpenPos(S32 width, S32& posX, S32& posY, EFontGlyphType bitmapType, U32& bitmapNum); - - void destroyGL(); - - LLImageRaw* getImageRaw(EFontGlyphType bitmapType, U32 bitmapNum) const; - LLImageGL* getImageGL(EFontGlyphType bitmapType, U32 bitmapNum) const; + LLImageRaw* getImageRaw(EFontGlyphType bitmapType, U32 bitmapNum) const; + LLImageGL* getImageGL(EFontGlyphType bitmapType, U32 bitmapNum) const; - S32 getMaxCharWidth() const { return mMaxCharWidth; } - U32 getNumBitmaps(EFontGlyphType bitmapType) const { return (bitmapType < EFontGlyphType::Count) ? mImageRawVec[static_cast<U32>(bitmapType)].size() : 0; } - S32 getBitmapWidth() const { return mBitmapWidth; } - S32 getBitmapHeight() const { return mBitmapHeight; } + S32 getMaxCharWidth() const { return mMaxCharWidth; } + U32 getNumBitmaps(EFontGlyphType bitmapType) const { return (bitmapType < EFontGlyphType::Count) ? mImageRawVec[static_cast<U32>(bitmapType)].size() : 0; } + S32 getBitmapWidth() const { return mBitmapWidth; } + S32 getBitmapHeight() const { return mBitmapHeight; } protected: - static U32 getNumComponents(EFontGlyphType bitmap_type); + static U32 getNumComponents(EFontGlyphType bitmap_type); private: - S32 mBitmapWidth = 0; - S32 mBitmapHeight = 0; - S32 mCurrentOffsetX[static_cast<U32>(EFontGlyphType::Count)] = { 1 }; - S32 mCurrentOffsetY[static_cast<U32>(EFontGlyphType::Count)] = { 1 }; - S32 mMaxCharWidth = 0; - S32 mMaxCharHeight = 0; - std::vector<LLPointer<LLImageRaw>> mImageRawVec[static_cast<U32>(EFontGlyphType::Count)]; - std::vector<LLPointer<LLImageGL>> mImageGLVec[static_cast<U32>(EFontGlyphType::Count)]; + S32 mBitmapWidth = 0; + S32 mBitmapHeight = 0; + S32 mCurrentOffsetX[static_cast<U32>(EFontGlyphType::Count)] = { 1 }; + S32 mCurrentOffsetY[static_cast<U32>(EFontGlyphType::Count)] = { 1 }; + S32 mMaxCharWidth = 0; + S32 mMaxCharHeight = 0; + std::vector<LLPointer<LLImageRaw>> mImageRawVec[static_cast<U32>(EFontGlyphType::Count)]; + std::vector<LLPointer<LLImageGL>> mImageGLVec[static_cast<U32>(EFontGlyphType::Count)]; }; #endif //LL_LLFONTBITMAPCACHE_H diff --git a/indra/llrender/llfontfreetype.cpp b/indra/llrender/llfontfreetype.cpp index d87fb5245c..1e5e441689 100644 --- a/indra/llrender/llfontfreetype.cpp +++ b/indra/llrender/llfontfreetype.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llfontfreetype.cpp * @brief Freetype font library wrapper * * $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$ */ @@ -46,7 +46,7 @@ #include "llimage.h" #include "llimagepng.h" //#include "llimagej2c.h" -#include "llmath.h" // Linden math +#include "llmath.h" // Linden math #include "llstring.h" //#include "imdebug.h" #include "llfontbitmapcache.h" @@ -63,779 +63,779 @@ FT_Library gFTLibrary = NULL; //static void LLFontManager::initClass() { - if (!gFontManagerp) - { - gFontManagerp = new LLFontManager; - } + if (!gFontManagerp) + { + gFontManagerp = new LLFontManager; + } } //static void LLFontManager::cleanupClass() { - delete gFontManagerp; - gFontManagerp = NULL; + delete gFontManagerp; + gFontManagerp = NULL; } LLFontManager::LLFontManager() { - int error; - error = FT_Init_FreeType(&gFTLibrary); - if (error) - { - // Clean up freetype libs. - LL_ERRS() << "Freetype initialization failure!" << LL_ENDL; - FT_Done_FreeType(gFTLibrary); - } + int error; + error = FT_Init_FreeType(&gFTLibrary); + if (error) + { + // Clean up freetype libs. + LL_ERRS() << "Freetype initialization failure!" << LL_ENDL; + FT_Done_FreeType(gFTLibrary); + } #ifdef ENABLE_OT_SVG_SUPPORT - SVG_RendererHooks hooks = { - LLFontFreeTypeSvgRenderer::OnInit, - LLFontFreeTypeSvgRenderer::OnFree, - LLFontFreeTypeSvgRenderer::OnRender, - LLFontFreeTypeSvgRenderer::OnPresetGlypthSlot, - }; - FT_Property_Set(gFTLibrary, "ot-svg", "svg-hooks", &hooks); + SVG_RendererHooks hooks = { + LLFontFreeTypeSvgRenderer::OnInit, + LLFontFreeTypeSvgRenderer::OnFree, + LLFontFreeTypeSvgRenderer::OnRender, + LLFontFreeTypeSvgRenderer::OnPresetGlypthSlot, + }; + FT_Property_Set(gFTLibrary, "ot-svg", "svg-hooks", &hooks); #endif } LLFontManager::~LLFontManager() { - FT_Done_FreeType(gFTLibrary); + FT_Done_FreeType(gFTLibrary); } LLFontGlyphInfo::LLFontGlyphInfo(U32 index, EFontGlyphType glyph_type) -: mGlyphIndex(index), - mGlyphType(glyph_type), - mWidth(0), // In pixels - mHeight(0), // In pixels - mXAdvance(0.f), // In pixels - mYAdvance(0.f), // In pixels - mXBitmapOffset(0), // Offset to the origin in the bitmap - mYBitmapOffset(0), // Offset to the origin in the bitmap - mXBearing(0), // Distance from baseline to left in pixels - mYBearing(0), // Distance from baseline to top in pixels - mBitmapEntry(std::make_pair(EFontGlyphType::Unspecified, -1)) // Which bitmap in the bitmap cache contains this glyph +: mGlyphIndex(index), + mGlyphType(glyph_type), + mWidth(0), // In pixels + mHeight(0), // In pixels + mXAdvance(0.f), // In pixels + mYAdvance(0.f), // In pixels + mXBitmapOffset(0), // Offset to the origin in the bitmap + mYBitmapOffset(0), // Offset to the origin in the bitmap + mXBearing(0), // Distance from baseline to left in pixels + mYBearing(0), // Distance from baseline to top in pixels + mBitmapEntry(std::make_pair(EFontGlyphType::Unspecified, -1)) // Which bitmap in the bitmap cache contains this glyph { } LLFontGlyphInfo::LLFontGlyphInfo(const LLFontGlyphInfo& fgi) - : mGlyphIndex(fgi.mGlyphIndex) - , mGlyphType(fgi.mGlyphType) - , mWidth(fgi.mWidth) - , mHeight(fgi.mHeight) - , mXAdvance(fgi.mXAdvance) - , mYAdvance(fgi.mYAdvance) - , mXBitmapOffset(fgi.mXBitmapOffset) - , mYBitmapOffset(fgi.mYBitmapOffset) - , mXBearing(fgi.mXBearing) - , mYBearing(fgi.mYBearing) + : mGlyphIndex(fgi.mGlyphIndex) + , mGlyphType(fgi.mGlyphType) + , mWidth(fgi.mWidth) + , mHeight(fgi.mHeight) + , mXAdvance(fgi.mXAdvance) + , mYAdvance(fgi.mYAdvance) + , mXBitmapOffset(fgi.mXBitmapOffset) + , mYBitmapOffset(fgi.mYBitmapOffset) + , mXBearing(fgi.mXBearing) + , mYBearing(fgi.mYBearing) { - mBitmapEntry = fgi.mBitmapEntry; + mBitmapEntry = fgi.mBitmapEntry; } LLFontFreetype::LLFontFreetype() -: mFontBitmapCachep(new LLFontBitmapCache), - mAscender(0.f), - mDescender(0.f), - mLineHeight(0.f), +: mFontBitmapCachep(new LLFontBitmapCache), + mAscender(0.f), + mDescender(0.f), + mLineHeight(0.f), #ifdef LL_WINDOWS - pFileStream(NULL), - pFtStream(NULL), + pFileStream(NULL), + pFtStream(NULL), #endif - mIsFallback(FALSE), - mFTFace(NULL), - mRenderGlyphCount(0), - mAddGlyphCount(0), - mStyle(0), - mPointSize(0) + mIsFallback(FALSE), + mFTFace(NULL), + mRenderGlyphCount(0), + mAddGlyphCount(0), + mStyle(0), + mPointSize(0) { } LLFontFreetype::~LLFontFreetype() { - // Clean up freetype libs. - if (mFTFace) - FT_Done_Face(mFTFace); - mFTFace = NULL; + // Clean up freetype libs. + if (mFTFace) + FT_Done_Face(mFTFace); + mFTFace = NULL; - // Delete glyph info - std::for_each(mCharGlyphInfoMap.begin(), mCharGlyphInfoMap.end(), DeletePairedPointer()); - mCharGlyphInfoMap.clear(); + // Delete glyph info + std::for_each(mCharGlyphInfoMap.begin(), mCharGlyphInfoMap.end(), DeletePairedPointer()); + mCharGlyphInfoMap.clear(); #ifdef LL_WINDOWS - delete pFileStream; // closed by FT_Done_Face - delete pFtStream; + delete pFileStream; // closed by FT_Done_Face + delete pFtStream; #endif - delete mFontBitmapCachep; - // mFallbackFonts cleaned up by LLPointer destructor + delete mFontBitmapCachep; + // mFallbackFonts cleaned up by LLPointer destructor } #ifdef LL_WINDOWS unsigned long ft_read_cb(FT_Stream stream, unsigned long offset, unsigned char *buffer, unsigned long count) { - if (count <= 0) return count; - llifstream *file_stream = static_cast<llifstream *>(stream->descriptor.pointer); - file_stream->seekg(offset, std::ios::beg); - file_stream->read((char*)buffer, count); - return file_stream->gcount(); + if (count <= 0) return count; + llifstream *file_stream = static_cast<llifstream *>(stream->descriptor.pointer); + file_stream->seekg(offset, std::ios::beg); + file_stream->read((char*)buffer, count); + return file_stream->gcount(); } void ft_close_cb(FT_Stream stream) { - llifstream *file_stream = static_cast<llifstream *>(stream->descriptor.pointer); - file_stream->close(); + llifstream *file_stream = static_cast<llifstream *>(stream->descriptor.pointer); + file_stream->close(); } #endif BOOL LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, bool is_fallback, S32 face_n) { - // Don't leak face objects. This is also needed to deal with - // changed font file names. - if (mFTFace) - { - FT_Done_Face(mFTFace); - mFTFace = NULL; - } - - int error; + // Don't leak face objects. This is also needed to deal with + // changed font file names. + if (mFTFace) + { + FT_Done_Face(mFTFace); + mFTFace = NULL; + } + + int error; #ifdef LL_WINDOWS - error = ftOpenFace(filename, face_n); + error = ftOpenFace(filename, face_n); #else - error = FT_New_Face( gFTLibrary, - filename.c_str(), - 0, - &mFTFace); + error = FT_New_Face( gFTLibrary, + filename.c_str(), + 0, + &mFTFace); #endif - if (error) - { + if (error) + { #ifdef LL_WINDOWS - clearFontStreams(); + clearFontStreams(); #endif - return FALSE; - } - - mIsFallback = is_fallback; - F32 pixels_per_em = (point_size / 72.f)*vert_dpi; // Size in inches * dpi - - error = FT_Set_Char_Size(mFTFace, /* handle to face object */ - 0, /* char_width in 1/64th of points */ - (S32)(point_size*64), /* char_height in 1/64th of points */ - (U32)horz_dpi, /* horizontal device resolution */ - (U32)vert_dpi); /* vertical device resolution */ - - if (error) - { - // Clean up freetype libs. - FT_Done_Face(mFTFace); + return FALSE; + } + + mIsFallback = is_fallback; + F32 pixels_per_em = (point_size / 72.f)*vert_dpi; // Size in inches * dpi + + error = FT_Set_Char_Size(mFTFace, /* handle to face object */ + 0, /* char_width in 1/64th of points */ + (S32)(point_size*64), /* char_height in 1/64th of points */ + (U32)horz_dpi, /* horizontal device resolution */ + (U32)vert_dpi); /* vertical device resolution */ + + if (error) + { + // Clean up freetype libs. + FT_Done_Face(mFTFace); #ifdef LL_WINDOWS - clearFontStreams(); + clearFontStreams(); #endif - mFTFace = NULL; - return FALSE; - } + mFTFace = NULL; + return FALSE; + } - F32 y_max, y_min, x_max, x_min; - F32 ems_per_unit = 1.f/ mFTFace->units_per_EM; - F32 pixels_per_unit = pixels_per_em * ems_per_unit; + F32 y_max, y_min, x_max, x_min; + F32 ems_per_unit = 1.f/ mFTFace->units_per_EM; + F32 pixels_per_unit = pixels_per_em * ems_per_unit; - // Get size of bbox in pixels - y_max = mFTFace->bbox.yMax * pixels_per_unit; - y_min = mFTFace->bbox.yMin * pixels_per_unit; - x_max = mFTFace->bbox.xMax * pixels_per_unit; - x_min = mFTFace->bbox.xMin * pixels_per_unit; - mAscender = mFTFace->ascender * pixels_per_unit; - mDescender = -mFTFace->descender * pixels_per_unit; - mLineHeight = mFTFace->height * pixels_per_unit; + // Get size of bbox in pixels + y_max = mFTFace->bbox.yMax * pixels_per_unit; + y_min = mFTFace->bbox.yMin * pixels_per_unit; + x_max = mFTFace->bbox.xMax * pixels_per_unit; + x_min = mFTFace->bbox.xMin * pixels_per_unit; + mAscender = mFTFace->ascender * pixels_per_unit; + mDescender = -mFTFace->descender * pixels_per_unit; + mLineHeight = mFTFace->height * pixels_per_unit; - S32 max_char_width = ll_round(0.5f + (x_max - x_min)); - S32 max_char_height = ll_round(0.5f + (y_max - y_min)); + S32 max_char_width = ll_round(0.5f + (x_max - x_min)); + S32 max_char_height = ll_round(0.5f + (y_max - y_min)); - mFontBitmapCachep->init(max_char_width, max_char_height); + mFontBitmapCachep->init(max_char_width, max_char_height); - if (!mFTFace->charmap) - { - //LL_INFOS() << " no unicode encoding, set whatever encoding there is..." << LL_ENDL; - FT_Set_Charmap(mFTFace, mFTFace->charmaps[0]); - } + if (!mFTFace->charmap) + { + //LL_INFOS() << " no unicode encoding, set whatever encoding there is..." << LL_ENDL; + FT_Set_Charmap(mFTFace, mFTFace->charmaps[0]); + } - if (!mIsFallback) - { - // Add the default glyph - addGlyphFromFont(this, 0, 0, EFontGlyphType::Grayscale); - } + if (!mIsFallback) + { + // Add the default glyph + addGlyphFromFont(this, 0, 0, EFontGlyphType::Grayscale); + } - mName = filename; - mPointSize = point_size; + mName = filename; + mPointSize = point_size; - mStyle = LLFontGL::NORMAL; - if(mFTFace->style_flags & FT_STYLE_FLAG_BOLD) - { - mStyle |= LLFontGL::BOLD; - } + mStyle = LLFontGL::NORMAL; + if(mFTFace->style_flags & FT_STYLE_FLAG_BOLD) + { + mStyle |= LLFontGL::BOLD; + } - if(mFTFace->style_flags & FT_STYLE_FLAG_ITALIC) - { - mStyle |= LLFontGL::ITALIC; - } + if(mFTFace->style_flags & FT_STYLE_FLAG_ITALIC) + { + mStyle |= LLFontGL::ITALIC; + } - return TRUE; + return TRUE; } S32 LLFontFreetype::getNumFaces(const std::string& filename) { - if (mFTFace) - { - FT_Done_Face(mFTFace); - mFTFace = NULL; - } + if (mFTFace) + { + FT_Done_Face(mFTFace); + mFTFace = NULL; + } - S32 num_faces = 1; + S32 num_faces = 1; #ifdef LL_WINDOWS - int error = ftOpenFace(filename, 0); - - if (error) - { - return 0; - } - else - { - num_faces = mFTFace->num_faces; - } - - FT_Done_Face(mFTFace); - clearFontStreams(); - mFTFace = NULL; + int error = ftOpenFace(filename, 0); + + if (error) + { + return 0; + } + else + { + num_faces = mFTFace->num_faces; + } + + FT_Done_Face(mFTFace); + clearFontStreams(); + mFTFace = NULL; #endif - return num_faces; + return num_faces; } #ifdef LL_WINDOWS S32 LLFontFreetype::ftOpenFace(const std::string& filename, S32 face_n) { - S32 error = -1; - pFileStream = new llifstream(filename, std::ios::binary); - if (pFileStream->is_open()) - { - std::streampos beg = pFileStream->tellg(); - pFileStream->seekg(0, std::ios::end); - std::streampos end = pFileStream->tellg(); - std::size_t file_size = end - beg; - pFileStream->seekg(0, std::ios::beg); - - pFtStream = new LLFT_Stream(); - pFtStream->base = 0; - pFtStream->pos = 0; - pFtStream->size = file_size; - pFtStream->descriptor.pointer = pFileStream; - pFtStream->read = ft_read_cb; - pFtStream->close = ft_close_cb; - - FT_Open_Args args; - args.flags = FT_OPEN_STREAM; - args.stream = (FT_StreamRec*)pFtStream; - error = FT_Open_Face(gFTLibrary, &args, face_n, &mFTFace); - } - return error; + S32 error = -1; + pFileStream = new llifstream(filename, std::ios::binary); + if (pFileStream->is_open()) + { + std::streampos beg = pFileStream->tellg(); + pFileStream->seekg(0, std::ios::end); + std::streampos end = pFileStream->tellg(); + std::size_t file_size = end - beg; + pFileStream->seekg(0, std::ios::beg); + + pFtStream = new LLFT_Stream(); + pFtStream->base = 0; + pFtStream->pos = 0; + pFtStream->size = file_size; + pFtStream->descriptor.pointer = pFileStream; + pFtStream->read = ft_read_cb; + pFtStream->close = ft_close_cb; + + FT_Open_Args args; + args.flags = FT_OPEN_STREAM; + args.stream = (FT_StreamRec*)pFtStream; + error = FT_Open_Face(gFTLibrary, &args, face_n, &mFTFace); + } + return error; } void LLFontFreetype::clearFontStreams() { - if (pFileStream) - { - pFileStream->close(); - } - delete pFileStream; - delete pFtStream; - pFileStream = NULL; - pFtStream = NULL; + if (pFileStream) + { + pFileStream->close(); + } + delete pFileStream; + delete pFtStream; + pFileStream = NULL; + pFtStream = NULL; } #endif void LLFontFreetype::addFallbackFont(const LLPointer<LLFontFreetype>& fallback_font, const char_functor_t& functor) { - // Insert functor fallbacks before generic fallbacks - mFallbackFonts.insert((functor) ? std::find_if(mFallbackFonts.begin(), mFallbackFonts.end(), [](const fallback_font_t& fe) { return !fe.second; }) : mFallbackFonts.end(), - std::make_pair(fallback_font, functor)); + // Insert functor fallbacks before generic fallbacks + mFallbackFonts.insert((functor) ? std::find_if(mFallbackFonts.begin(), mFallbackFonts.end(), [](const fallback_font_t& fe) { return !fe.second; }) : mFallbackFonts.end(), + std::make_pair(fallback_font, functor)); } F32 LLFontFreetype::getLineHeight() const { - return mLineHeight; + return mLineHeight; } F32 LLFontFreetype::getAscenderHeight() const { - return mAscender; + return mAscender; } F32 LLFontFreetype::getDescenderHeight() const { - return mDescender; + return mDescender; } F32 LLFontFreetype::getXAdvance(llwchar wch) const { - if (mFTFace == NULL) - return 0.0; + if (mFTFace == NULL) + return 0.0; - // Return existing info only if it is current - LLFontGlyphInfo* gi = getGlyphInfo(wch, EFontGlyphType::Unspecified); - if (gi) - { - return gi->mXAdvance; - } - else - { - char_glyph_info_map_t::iterator found_it = mCharGlyphInfoMap.find((llwchar)0); - if (found_it != mCharGlyphInfoMap.end()) - { - return found_it->second->mXAdvance; - } - } + // Return existing info only if it is current + LLFontGlyphInfo* gi = getGlyphInfo(wch, EFontGlyphType::Unspecified); + if (gi) + { + return gi->mXAdvance; + } + else + { + char_glyph_info_map_t::iterator found_it = mCharGlyphInfoMap.find((llwchar)0); + if (found_it != mCharGlyphInfoMap.end()) + { + return found_it->second->mXAdvance; + } + } - // Last ditch fallback - no glyphs defined at all. - return (F32)mFontBitmapCachep->getMaxCharWidth(); + // Last ditch fallback - no glyphs defined at all. + return (F32)mFontBitmapCachep->getMaxCharWidth(); } F32 LLFontFreetype::getXAdvance(const LLFontGlyphInfo* glyph) const { - if (mFTFace == NULL) - return 0.0; + if (mFTFace == NULL) + return 0.0; - return glyph->mXAdvance; + return glyph->mXAdvance; } F32 LLFontFreetype::getXKerning(llwchar char_left, llwchar char_right) const { - if (mFTFace == NULL) - return 0.0; + if (mFTFace == NULL) + return 0.0; - //llassert(!mIsFallback); - LLFontGlyphInfo* left_glyph_info = getGlyphInfo(char_left, EFontGlyphType::Unspecified);; - U32 left_glyph = left_glyph_info ? left_glyph_info->mGlyphIndex : 0; - // Kern this puppy. - LLFontGlyphInfo* right_glyph_info = getGlyphInfo(char_right, EFontGlyphType::Unspecified); - U32 right_glyph = right_glyph_info ? right_glyph_info->mGlyphIndex : 0; + //llassert(!mIsFallback); + LLFontGlyphInfo* left_glyph_info = getGlyphInfo(char_left, EFontGlyphType::Unspecified);; + U32 left_glyph = left_glyph_info ? left_glyph_info->mGlyphIndex : 0; + // Kern this puppy. + LLFontGlyphInfo* right_glyph_info = getGlyphInfo(char_right, EFontGlyphType::Unspecified); + U32 right_glyph = right_glyph_info ? right_glyph_info->mGlyphIndex : 0; - FT_Vector delta; + FT_Vector delta; - llverify(!FT_Get_Kerning(mFTFace, left_glyph, right_glyph, ft_kerning_unfitted, &delta)); + llverify(!FT_Get_Kerning(mFTFace, left_glyph, right_glyph, ft_kerning_unfitted, &delta)); - return delta.x*(1.f/64.f); + return delta.x*(1.f/64.f); } F32 LLFontFreetype::getXKerning(const LLFontGlyphInfo* left_glyph_info, const LLFontGlyphInfo* right_glyph_info) const { - if (mFTFace == NULL) - return 0.0; + if (mFTFace == NULL) + return 0.0; - U32 left_glyph = left_glyph_info ? left_glyph_info->mGlyphIndex : 0; - U32 right_glyph = right_glyph_info ? right_glyph_info->mGlyphIndex : 0; + U32 left_glyph = left_glyph_info ? left_glyph_info->mGlyphIndex : 0; + U32 right_glyph = right_glyph_info ? right_glyph_info->mGlyphIndex : 0; - FT_Vector delta; + FT_Vector delta; - llverify(!FT_Get_Kerning(mFTFace, left_glyph, right_glyph, ft_kerning_unfitted, &delta)); + llverify(!FT_Get_Kerning(mFTFace, left_glyph, right_glyph, ft_kerning_unfitted, &delta)); - return delta.x*(1.f/64.f); + return delta.x*(1.f/64.f); } BOOL LLFontFreetype::hasGlyph(llwchar wch) const { - llassert(!mIsFallback); - return(mCharGlyphInfoMap.find(wch) != mCharGlyphInfoMap.end()); + llassert(!mIsFallback); + return(mCharGlyphInfoMap.find(wch) != mCharGlyphInfoMap.end()); } LLFontGlyphInfo* LLFontFreetype::addGlyph(llwchar wch, EFontGlyphType glyph_type) const { - if (mFTFace == NULL) - return FALSE; - - llassert(!mIsFallback); - llassert(glyph_type < EFontGlyphType::Count); - //LL_DEBUGS() << "Adding new glyph for " << wch << " to font" << LL_ENDL; - - FT_UInt glyph_index; - - // Fallback fonts with a functor have precedence over everything else - fallback_font_vector_t::const_iterator it_fallback = mFallbackFonts.cbegin(); - /* This leads to a bug SL-19831 "Check marks in the menu are less visible." - ** Also, LLFontRegistry::createFont() says: "Fallback fonts don't render" - for (; it_fallback != mFallbackFonts.cend() && it_fallback->second; ++it_fallback) - { - if (it_fallback->second(wch)) - { - glyph_index = FT_Get_Char_Index(it_fallback->first->mFTFace, wch); - if (glyph_index) - { - return addGlyphFromFont(it_fallback->first, wch, glyph_index, glyph_type); - } - } - } - */ - - // Initialize char to glyph map - glyph_index = FT_Get_Char_Index(mFTFace, wch); - if (glyph_index == 0) - { - //LL_INFOS() << "Trying to add glyph from fallback font!" << LL_ENDL; - for (; it_fallback != mFallbackFonts.cend(); ++it_fallback) - { - glyph_index = FT_Get_Char_Index(it_fallback->first->mFTFace, wch); - if (glyph_index) - { - return addGlyphFromFont(it_fallback->first, wch, glyph_index, glyph_type); - } - } - } - - std::pair<char_glyph_info_map_t::iterator, char_glyph_info_map_t::iterator> range_it = mCharGlyphInfoMap.equal_range(wch); - char_glyph_info_map_t::iterator iter = - std::find_if(range_it.first, range_it.second, [&glyph_type](const char_glyph_info_map_t::value_type& entry) { return entry.second->mGlyphType == glyph_type; }); - if (iter == range_it.second) - { - return addGlyphFromFont(this, wch, glyph_index, glyph_type); - } - return NULL; + if (mFTFace == NULL) + return FALSE; + + llassert(!mIsFallback); + llassert(glyph_type < EFontGlyphType::Count); + //LL_DEBUGS() << "Adding new glyph for " << wch << " to font" << LL_ENDL; + + FT_UInt glyph_index; + + // Fallback fonts with a functor have precedence over everything else + fallback_font_vector_t::const_iterator it_fallback = mFallbackFonts.cbegin(); + /* This leads to a bug SL-19831 "Check marks in the menu are less visible." + ** Also, LLFontRegistry::createFont() says: "Fallback fonts don't render" + for (; it_fallback != mFallbackFonts.cend() && it_fallback->second; ++it_fallback) + { + if (it_fallback->second(wch)) + { + glyph_index = FT_Get_Char_Index(it_fallback->first->mFTFace, wch); + if (glyph_index) + { + return addGlyphFromFont(it_fallback->first, wch, glyph_index, glyph_type); + } + } + } + */ + + // Initialize char to glyph map + glyph_index = FT_Get_Char_Index(mFTFace, wch); + if (glyph_index == 0) + { + //LL_INFOS() << "Trying to add glyph from fallback font!" << LL_ENDL; + for (; it_fallback != mFallbackFonts.cend(); ++it_fallback) + { + glyph_index = FT_Get_Char_Index(it_fallback->first->mFTFace, wch); + if (glyph_index) + { + return addGlyphFromFont(it_fallback->first, wch, glyph_index, glyph_type); + } + } + } + + std::pair<char_glyph_info_map_t::iterator, char_glyph_info_map_t::iterator> range_it = mCharGlyphInfoMap.equal_range(wch); + char_glyph_info_map_t::iterator iter = + std::find_if(range_it.first, range_it.second, [&glyph_type](const char_glyph_info_map_t::value_type& entry) { return entry.second->mGlyphType == glyph_type; }); + if (iter == range_it.second) + { + return addGlyphFromFont(this, wch, glyph_index, glyph_type); + } + return NULL; } LLFontGlyphInfo* LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, llwchar wch, U32 glyph_index, EFontGlyphType requested_glyph_type) const { LL_PROFILE_ZONE_SCOPED; - if (mFTFace == NULL) - return NULL; - - llassert(!mIsFallback); - fontp->renderGlyph(requested_glyph_type, glyph_index); - - EFontGlyphType bitmap_glyph_type = EFontGlyphType::Unspecified; - switch (fontp->mFTFace->glyph->bitmap.pixel_mode) - { - case FT_PIXEL_MODE_MONO: - case FT_PIXEL_MODE_GRAY: - bitmap_glyph_type = EFontGlyphType::Grayscale; - break; - case FT_PIXEL_MODE_BGRA: - bitmap_glyph_type = EFontGlyphType::Color; - break; - default: - llassert_always(true); - break; - } - S32 width = fontp->mFTFace->glyph->bitmap.width; - S32 height = fontp->mFTFace->glyph->bitmap.rows; - - S32 pos_x, pos_y; - U32 bitmap_num; - mFontBitmapCachep->nextOpenPos(width, pos_x, pos_y, bitmap_glyph_type, bitmap_num); - mAddGlyphCount++; - - LLFontGlyphInfo* gi = new LLFontGlyphInfo(glyph_index, requested_glyph_type); - gi->mXBitmapOffset = pos_x; - gi->mYBitmapOffset = pos_y; - gi->mBitmapEntry = std::make_pair(bitmap_glyph_type, bitmap_num); - gi->mWidth = width; - gi->mHeight = height; - gi->mXBearing = fontp->mFTFace->glyph->bitmap_left; - gi->mYBearing = fontp->mFTFace->glyph->bitmap_top; - // Convert these from 26.6 units to float pixels. - gi->mXAdvance = fontp->mFTFace->glyph->advance.x / 64.f; - gi->mYAdvance = fontp->mFTFace->glyph->advance.y / 64.f; - - insertGlyphInfo(wch, gi); - - if (requested_glyph_type != bitmap_glyph_type) - { - LLFontGlyphInfo* gi_temp = new LLFontGlyphInfo(*gi); - gi_temp->mGlyphType = bitmap_glyph_type; - insertGlyphInfo(wch, gi_temp); - } - - if (fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO - || fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY) - { - U8 *buffer_data = fontp->mFTFace->glyph->bitmap.buffer; - S32 buffer_row_stride = fontp->mFTFace->glyph->bitmap.pitch; - U8 *tmp_graydata = NULL; - - if (fontp->mFTFace->glyph->bitmap.pixel_mode - == FT_PIXEL_MODE_MONO) - { - // need to expand 1-bit bitmap to 8-bit graymap. - tmp_graydata = new U8[width * height]; - S32 xpos, ypos; - for (ypos = 0; ypos < height; ++ypos) - { - S32 bm_row_offset = buffer_row_stride * ypos; - for (xpos = 0; xpos < width; ++xpos) - { - U32 bm_col_offsetbyte = xpos / 8; - U32 bm_col_offsetbit = 7 - (xpos % 8); - U32 bit = - !!(buffer_data[bm_row_offset - + bm_col_offsetbyte - ] & (1 << bm_col_offsetbit) ); - tmp_graydata[width*ypos + xpos] = - 255 * bit; - } - } - // use newly-built graymap. - buffer_data = tmp_graydata; - buffer_row_stride = width; - } - - setSubImageLuminanceAlpha(pos_x, - pos_y, - bitmap_num, - width, - height, - buffer_data, - buffer_row_stride); - - if (tmp_graydata) - delete[] tmp_graydata; - } - else if (fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) - { - setSubImageBGRA(pos_x, - pos_y, - bitmap_num, - fontp->mFTFace->glyph->bitmap.width, - fontp->mFTFace->glyph->bitmap.rows, - fontp->mFTFace->glyph->bitmap.buffer, - llabs(fontp->mFTFace->glyph->bitmap.pitch)); - } else { - llassert(false); - } - - LLImageGL *image_gl = mFontBitmapCachep->getImageGL(bitmap_glyph_type, bitmap_num); - LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(bitmap_glyph_type, bitmap_num); - image_gl->setSubImage(image_raw, 0, 0, image_gl->getWidth(), image_gl->getHeight()); - - return gi; + if (mFTFace == NULL) + return NULL; + + llassert(!mIsFallback); + fontp->renderGlyph(requested_glyph_type, glyph_index); + + EFontGlyphType bitmap_glyph_type = EFontGlyphType::Unspecified; + switch (fontp->mFTFace->glyph->bitmap.pixel_mode) + { + case FT_PIXEL_MODE_MONO: + case FT_PIXEL_MODE_GRAY: + bitmap_glyph_type = EFontGlyphType::Grayscale; + break; + case FT_PIXEL_MODE_BGRA: + bitmap_glyph_type = EFontGlyphType::Color; + break; + default: + llassert_always(true); + break; + } + S32 width = fontp->mFTFace->glyph->bitmap.width; + S32 height = fontp->mFTFace->glyph->bitmap.rows; + + S32 pos_x, pos_y; + U32 bitmap_num; + mFontBitmapCachep->nextOpenPos(width, pos_x, pos_y, bitmap_glyph_type, bitmap_num); + mAddGlyphCount++; + + LLFontGlyphInfo* gi = new LLFontGlyphInfo(glyph_index, requested_glyph_type); + gi->mXBitmapOffset = pos_x; + gi->mYBitmapOffset = pos_y; + gi->mBitmapEntry = std::make_pair(bitmap_glyph_type, bitmap_num); + gi->mWidth = width; + gi->mHeight = height; + gi->mXBearing = fontp->mFTFace->glyph->bitmap_left; + gi->mYBearing = fontp->mFTFace->glyph->bitmap_top; + // Convert these from 26.6 units to float pixels. + gi->mXAdvance = fontp->mFTFace->glyph->advance.x / 64.f; + gi->mYAdvance = fontp->mFTFace->glyph->advance.y / 64.f; + + insertGlyphInfo(wch, gi); + + if (requested_glyph_type != bitmap_glyph_type) + { + LLFontGlyphInfo* gi_temp = new LLFontGlyphInfo(*gi); + gi_temp->mGlyphType = bitmap_glyph_type; + insertGlyphInfo(wch, gi_temp); + } + + if (fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO + || fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY) + { + U8 *buffer_data = fontp->mFTFace->glyph->bitmap.buffer; + S32 buffer_row_stride = fontp->mFTFace->glyph->bitmap.pitch; + U8 *tmp_graydata = NULL; + + if (fontp->mFTFace->glyph->bitmap.pixel_mode + == FT_PIXEL_MODE_MONO) + { + // need to expand 1-bit bitmap to 8-bit graymap. + tmp_graydata = new U8[width * height]; + S32 xpos, ypos; + for (ypos = 0; ypos < height; ++ypos) + { + S32 bm_row_offset = buffer_row_stride * ypos; + for (xpos = 0; xpos < width; ++xpos) + { + U32 bm_col_offsetbyte = xpos / 8; + U32 bm_col_offsetbit = 7 - (xpos % 8); + U32 bit = + !!(buffer_data[bm_row_offset + + bm_col_offsetbyte + ] & (1 << bm_col_offsetbit) ); + tmp_graydata[width*ypos + xpos] = + 255 * bit; + } + } + // use newly-built graymap. + buffer_data = tmp_graydata; + buffer_row_stride = width; + } + + setSubImageLuminanceAlpha(pos_x, + pos_y, + bitmap_num, + width, + height, + buffer_data, + buffer_row_stride); + + if (tmp_graydata) + delete[] tmp_graydata; + } + else if (fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) + { + setSubImageBGRA(pos_x, + pos_y, + bitmap_num, + fontp->mFTFace->glyph->bitmap.width, + fontp->mFTFace->glyph->bitmap.rows, + fontp->mFTFace->glyph->bitmap.buffer, + llabs(fontp->mFTFace->glyph->bitmap.pitch)); + } else { + llassert(false); + } + + LLImageGL *image_gl = mFontBitmapCachep->getImageGL(bitmap_glyph_type, bitmap_num); + LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(bitmap_glyph_type, bitmap_num); + image_gl->setSubImage(image_raw, 0, 0, image_gl->getWidth(), image_gl->getHeight()); + + return gi; } LLFontGlyphInfo* LLFontFreetype::getGlyphInfo(llwchar wch, EFontGlyphType glyph_type) const { - std::pair<char_glyph_info_map_t::iterator, char_glyph_info_map_t::iterator> range_it = mCharGlyphInfoMap.equal_range(wch); + std::pair<char_glyph_info_map_t::iterator, char_glyph_info_map_t::iterator> range_it = mCharGlyphInfoMap.equal_range(wch); - char_glyph_info_map_t::iterator iter = (EFontGlyphType::Unspecified != glyph_type) - ? std::find_if(range_it.first, range_it.second, [&glyph_type](const char_glyph_info_map_t::value_type& entry) { return entry.second->mGlyphType == glyph_type; }) - : range_it.first; - if (iter != range_it.second) - { - return iter->second; - } - else - { - // this glyph doesn't yet exist, so render it and return the result - return addGlyph(wch, (EFontGlyphType::Unspecified != glyph_type) ? glyph_type : EFontGlyphType::Grayscale); - } + char_glyph_info_map_t::iterator iter = (EFontGlyphType::Unspecified != glyph_type) + ? std::find_if(range_it.first, range_it.second, [&glyph_type](const char_glyph_info_map_t::value_type& entry) { return entry.second->mGlyphType == glyph_type; }) + : range_it.first; + if (iter != range_it.second) + { + return iter->second; + } + else + { + // this glyph doesn't yet exist, so render it and return the result + return addGlyph(wch, (EFontGlyphType::Unspecified != glyph_type) ? glyph_type : EFontGlyphType::Grayscale); + } } void LLFontFreetype::insertGlyphInfo(llwchar wch, LLFontGlyphInfo* gi) const { - llassert(gi->mGlyphType < EFontGlyphType::Count); - std::pair<char_glyph_info_map_t::iterator, char_glyph_info_map_t::iterator> range_it = mCharGlyphInfoMap.equal_range(wch); + llassert(gi->mGlyphType < EFontGlyphType::Count); + std::pair<char_glyph_info_map_t::iterator, char_glyph_info_map_t::iterator> range_it = mCharGlyphInfoMap.equal_range(wch); - char_glyph_info_map_t::iterator iter = - std::find_if(range_it.first, range_it.second, [&gi](const char_glyph_info_map_t::value_type& entry) { return entry.second->mGlyphType == gi->mGlyphType; }); - if (iter != range_it.second) - { - delete iter->second; - iter->second = gi; - } - else - { - mCharGlyphInfoMap.insert(std::make_pair(wch, gi)); - } + char_glyph_info_map_t::iterator iter = + std::find_if(range_it.first, range_it.second, [&gi](const char_glyph_info_map_t::value_type& entry) { return entry.second->mGlyphType == gi->mGlyphType; }); + if (iter != range_it.second) + { + delete iter->second; + iter->second = gi; + } + else + { + mCharGlyphInfoMap.insert(std::make_pair(wch, gi)); + } } void LLFontFreetype::renderGlyph(EFontGlyphType bitmap_type, U32 glyph_index) const { - if (mFTFace == NULL) - return; + if (mFTFace == NULL) + return; - FT_Int32 load_flags = FT_LOAD_FORCE_AUTOHINT; - if (EFontGlyphType::Color == bitmap_type) - { - // We may not actually get a color render so our caller should always examine mFTFace->glyph->bitmap.pixel_mode - load_flags |= FT_LOAD_COLOR; - } + FT_Int32 load_flags = FT_LOAD_FORCE_AUTOHINT; + if (EFontGlyphType::Color == bitmap_type) + { + // We may not actually get a color render so our caller should always examine mFTFace->glyph->bitmap.pixel_mode + load_flags |= FT_LOAD_COLOR; + } - FT_Error error = FT_Load_Glyph(mFTFace, glyph_index, load_flags); - if (FT_Err_Ok != error) - { - std::string message = llformat( - "Error %d (%s) loading glyph %u: bitmap_type=%u, load_flags=%d", - error, FT_Error_String(error), glyph_index, bitmap_type, load_flags); - LL_WARNS_ONCE() << message << LL_ENDL; - error = FT_Load_Glyph(mFTFace, glyph_index, load_flags ^ FT_LOAD_COLOR); - llassert_always_msg(FT_Err_Ok == error, message.c_str()); - } + FT_Error error = FT_Load_Glyph(mFTFace, glyph_index, load_flags); + if (FT_Err_Ok != error) + { + std::string message = llformat( + "Error %d (%s) loading glyph %u: bitmap_type=%u, load_flags=%d", + error, FT_Error_String(error), glyph_index, bitmap_type, load_flags); + LL_WARNS_ONCE() << message << LL_ENDL; + error = FT_Load_Glyph(mFTFace, glyph_index, load_flags ^ FT_LOAD_COLOR); + llassert_always_msg(FT_Err_Ok == error, message.c_str()); + } - llassert_always(! FT_Render_Glyph(mFTFace->glyph, gFontRenderMode) ); + llassert_always(! FT_Render_Glyph(mFTFace->glyph, gFontRenderMode) ); - mRenderGlyphCount++; + mRenderGlyphCount++; } void LLFontFreetype::reset(F32 vert_dpi, F32 horz_dpi) { - resetBitmapCache(); - loadFace(mName, mPointSize, vert_dpi ,horz_dpi, mIsFallback, 0); - if (!mIsFallback) - { - // This is the head of the list - need to rebuild ourself and all fallbacks. - if (mFallbackFonts.empty()) - { - LL_WARNS() << "LLFontGL::reset(), no fallback fonts present" << LL_ENDL; - } - else - { - for (fallback_font_vector_t::iterator it = mFallbackFonts.begin(); it != mFallbackFonts.end(); ++it) - { - it->first->reset(vert_dpi, horz_dpi); - } - } - } + resetBitmapCache(); + loadFace(mName, mPointSize, vert_dpi ,horz_dpi, mIsFallback, 0); + if (!mIsFallback) + { + // This is the head of the list - need to rebuild ourself and all fallbacks. + if (mFallbackFonts.empty()) + { + LL_WARNS() << "LLFontGL::reset(), no fallback fonts present" << LL_ENDL; + } + else + { + for (fallback_font_vector_t::iterator it = mFallbackFonts.begin(); it != mFallbackFonts.end(); ++it) + { + it->first->reset(vert_dpi, horz_dpi); + } + } + } } void LLFontFreetype::resetBitmapCache() { - for (char_glyph_info_map_t::iterator it = mCharGlyphInfoMap.begin(), end_it = mCharGlyphInfoMap.end(); - it != end_it; - ++it) - { - delete it->second; - } - mCharGlyphInfoMap.clear(); - mFontBitmapCachep->reset(); + for (char_glyph_info_map_t::iterator it = mCharGlyphInfoMap.begin(), end_it = mCharGlyphInfoMap.end(); + it != end_it; + ++it) + { + delete it->second; + } + mCharGlyphInfoMap.clear(); + mFontBitmapCachep->reset(); - // Adding default glyph is skipped for fallback fonts here as well as in loadFace(). - // This if was added as fix for EXT-4971. - if(!mIsFallback) - { - // Add the empty glyph - addGlyphFromFont(this, 0, 0, EFontGlyphType::Grayscale); - } + // Adding default glyph is skipped for fallback fonts here as well as in loadFace(). + // This if was added as fix for EXT-4971. + if(!mIsFallback) + { + // Add the empty glyph + addGlyphFromFont(this, 0, 0, EFontGlyphType::Grayscale); + } } void LLFontFreetype::destroyGL() { - mFontBitmapCachep->destroyGL(); + mFontBitmapCachep->destroyGL(); } const std::string &LLFontFreetype::getName() const { - return mName; + return mName; } static void dumpFontBitmap(const LLImageRaw* image_raw, const std::string& file_name) { - LLPointer<LLImagePNG> tmpImage = new LLImagePNG(); - if ( (tmpImage->encode(image_raw, 0.0f)) && (tmpImage->save(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, file_name))) ) - { - LL_INFOS("Font") << "Successfully saved " << file_name << LL_ENDL; - } - else - { - LL_WARNS("Font") << "Failed to save " << file_name << LL_ENDL; - } + LLPointer<LLImagePNG> tmpImage = new LLImagePNG(); + if ( (tmpImage->encode(image_raw, 0.0f)) && (tmpImage->save(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, file_name))) ) + { + LL_INFOS("Font") << "Successfully saved " << file_name << LL_ENDL; + } + else + { + LL_WARNS("Font") << "Failed to save " << file_name << LL_ENDL; + } } void LLFontFreetype::dumpFontBitmaps() const { - // Dump all the regular bitmaps (if any) - for (int idx = 0, cnt = mFontBitmapCachep->getNumBitmaps(EFontGlyphType::Grayscale); idx < cnt; idx++) - { - dumpFontBitmap(mFontBitmapCachep->getImageRaw(EFontGlyphType::Grayscale, idx), llformat("%s_%d_%d_%d.png", mFTFace->family_name, (int)(mPointSize * 10), mStyle, idx)); - } + // Dump all the regular bitmaps (if any) + for (int idx = 0, cnt = mFontBitmapCachep->getNumBitmaps(EFontGlyphType::Grayscale); idx < cnt; idx++) + { + dumpFontBitmap(mFontBitmapCachep->getImageRaw(EFontGlyphType::Grayscale, idx), llformat("%s_%d_%d_%d.png", mFTFace->family_name, (int)(mPointSize * 10), mStyle, idx)); + } - // Dump all the color bitmaps (if any) - for (int idx = 0, cnt = mFontBitmapCachep->getNumBitmaps(EFontGlyphType::Color); idx < cnt; idx++) - { - dumpFontBitmap(mFontBitmapCachep->getImageRaw(EFontGlyphType::Color, idx), llformat("%s_%d_%d_%d_clr.png", mFTFace->family_name, (int)(mPointSize * 10), mStyle, idx)); - } + // Dump all the color bitmaps (if any) + for (int idx = 0, cnt = mFontBitmapCachep->getNumBitmaps(EFontGlyphType::Color); idx < cnt; idx++) + { + dumpFontBitmap(mFontBitmapCachep->getImageRaw(EFontGlyphType::Color, idx), llformat("%s_%d_%d_%d_clr.png", mFTFace->family_name, (int)(mPointSize * 10), mStyle, idx)); + } } const LLFontBitmapCache* LLFontFreetype::getFontBitmapCache() const { - return mFontBitmapCachep; + return mFontBitmapCachep; } void LLFontFreetype::setStyle(U8 style) { - mStyle = style; + mStyle = style; } U8 LLFontFreetype::getStyle() const { - return mStyle; + return mStyle; } bool LLFontFreetype::setSubImageBGRA(U32 x, U32 y, U32 bitmap_num, U16 width, U16 height, const U8* data, U32 stride) const { - LLImageRaw* image_raw = mFontBitmapCachep->getImageRaw(EFontGlyphType::Color, bitmap_num); - llassert(!mIsFallback); - llassert(image_raw && (image_raw->getComponents() == 4)); + LLImageRaw* image_raw = mFontBitmapCachep->getImageRaw(EFontGlyphType::Color, bitmap_num); + llassert(!mIsFallback); + llassert(image_raw && (image_raw->getComponents() == 4)); - // NOTE: inspired by LLImageRaw::setSubImage() - U32* image_data = (U32*)image_raw->getData(); - if (!image_data) - { - return false; - } + // NOTE: inspired by LLImageRaw::setSubImage() + U32* image_data = (U32*)image_raw->getData(); + if (!image_data) + { + return false; + } - for (U32 idxRow = 0; idxRow < height; idxRow++) - { - const U32 nSrcRow = height - 1 - idxRow; - const U32 nSrcOffset = nSrcRow * width * image_raw->getComponents(); - const U32 nDstOffset = (y + idxRow) * image_raw->getWidth() + x; + for (U32 idxRow = 0; idxRow < height; idxRow++) + { + const U32 nSrcRow = height - 1 - idxRow; + const U32 nSrcOffset = nSrcRow * width * image_raw->getComponents(); + const U32 nDstOffset = (y + idxRow) * image_raw->getWidth() + x; - for (U32 idxCol = 0; idxCol < width; idxCol++) - { - U32 nTemp = nSrcOffset + idxCol * 4; - image_data[nDstOffset + idxCol] = data[nTemp + 3] << 24 | data[nTemp] << 16 | data[nTemp + 1] << 8 | data[nTemp + 2]; - } - } + for (U32 idxCol = 0; idxCol < width; idxCol++) + { + U32 nTemp = nSrcOffset + idxCol * 4; + image_data[nDstOffset + idxCol] = data[nTemp + 3] << 24 | data[nTemp] << 16 | data[nTemp + 1] << 8 | data[nTemp + 2]; + } + } - return true; + return true; } void LLFontFreetype::setSubImageLuminanceAlpha(U32 x, U32 y, U32 bitmap_num, U32 width, U32 height, U8 *data, S32 stride) const { - LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(EFontGlyphType::Grayscale, bitmap_num); + LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(EFontGlyphType::Grayscale, bitmap_num); + + llassert(!mIsFallback); + llassert(image_raw && (image_raw->getComponents() == 2)); - llassert(!mIsFallback); - llassert(image_raw && (image_raw->getComponents() == 2)); - - U8 *target = image_raw->getData(); + U8 *target = image_raw->getData(); llassert(target); - if (!data || !target) - { - return; - } - - if (0 == stride) - stride = width; - - U32 i, j; - U32 to_offset; - U32 from_offset; - U32 target_width = image_raw->getWidth(); - for (i = 0; i < height; i++) - { - to_offset = (y + i)*target_width + x; - from_offset = (height - 1 - i)*stride; - for (j = 0; j < width; j++) - { - *(target + to_offset*2 + 1) = *(data + from_offset); - to_offset++; - from_offset++; - } - } + if (!data || !target) + { + return; + } + + if (0 == stride) + stride = width; + + U32 i, j; + U32 to_offset; + U32 from_offset; + U32 target_width = image_raw->getWidth(); + for (i = 0; i < height; i++) + { + to_offset = (y + i)*target_width + x; + from_offset = (height - 1 - i)*stride; + for (j = 0; j < width; j++) + { + *(target + to_offset*2 + 1) = *(data + from_offset); + to_offset++; + from_offset++; + } + } } diff --git a/indra/llrender/llfontfreetype.h b/indra/llrender/llfontfreetype.h index b036d337ba..19112830a4 100644 --- a/indra/llrender/llfontfreetype.h +++ b/indra/llrender/llfontfreetype.h @@ -1,25 +1,25 @@ -/** +/** * @file llfontfreetype.h * @brief Font library wrapper * * $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$ */ @@ -35,8 +35,8 @@ #include "llfontbitmapcache.h" // Hack. FT_Face is just a typedef for a pointer to a struct, -// but there's no simple forward declarations file for FreeType, -// and the main include file is 200K. +// but there's no simple forward declarations file for FreeType, +// and the main include file is 200K. // We'll forward declare the struct here. JC struct FT_FaceRec_; typedef struct FT_FaceRec_* LLFT_Face; @@ -46,34 +46,34 @@ typedef struct FT_StreamRec_ LLFT_Stream; class LLFontManager { public: - static void initClass(); - static void cleanupClass(); + static void initClass(); + static void cleanupClass(); private: - LLFontManager(); - ~LLFontManager(); + LLFontManager(); + ~LLFontManager(); }; struct LLFontGlyphInfo { - LLFontGlyphInfo(U32 index, EFontGlyphType glyph_type); - LLFontGlyphInfo(const LLFontGlyphInfo& fgi); - - U32 mGlyphIndex; - EFontGlyphType mGlyphType; - - // Metrics - S32 mWidth; // In pixels - S32 mHeight; // In pixels - F32 mXAdvance; // In pixels - F32 mYAdvance; // In pixels - - // Information for actually rendering - S32 mXBitmapOffset; // Offset to the origin in the bitmap - S32 mYBitmapOffset; // Offset to the origin in the bitmap - S32 mXBearing; // Distance from baseline to left in pixels - S32 mYBearing; // Distance from baseline to top in pixels - std::pair<EFontGlyphType, S32> mBitmapEntry; // Which bitmap in the bitmap cache contains this glyph + LLFontGlyphInfo(U32 index, EFontGlyphType glyph_type); + LLFontGlyphInfo(const LLFontGlyphInfo& fgi); + + U32 mGlyphIndex; + EFontGlyphType mGlyphType; + + // Metrics + S32 mWidth; // In pixels + S32 mHeight; // In pixels + F32 mXAdvance; // In pixels + F32 mYAdvance; // In pixels + + // Information for actually rendering + S32 mXBitmapOffset; // Offset to the origin in the bitmap + S32 mYBitmapOffset; // Offset to the origin in the bitmap + S32 mXBearing; // Distance from baseline to left in pixels + S32 mYBearing; // Distance from baseline to top in pixels + std::pair<EFontGlyphType, S32> mBitmapEntry; // Which bitmap in the bitmap cache contains this glyph }; extern LLFontManager *gFontManagerp; @@ -81,113 +81,113 @@ extern LLFontManager *gFontManagerp; class LLFontFreetype : public LLRefCount { public: - LLFontFreetype(); - ~LLFontFreetype(); + LLFontFreetype(); + ~LLFontFreetype(); - // is_fallback should be true for fallback fonts that aren't used - // to render directly (Unicode backup, primarily) - BOOL loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, bool is_fallback, S32 face_n); + // is_fallback should be true for fallback fonts that aren't used + // to render directly (Unicode backup, primarily) + BOOL loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, bool is_fallback, S32 face_n); - S32 getNumFaces(const std::string& filename); + S32 getNumFaces(const std::string& filename); #ifdef LL_WINDOWS - S32 ftOpenFace(const std::string& filename, S32 face_n); - void clearFontStreams(); + S32 ftOpenFace(const std::string& filename, S32 face_n); + void clearFontStreams(); #endif - typedef std::function<bool(llwchar)> char_functor_t; - void addFallbackFont(const LLPointer<LLFontFreetype>& fallback_font, const char_functor_t& functor = nullptr); + typedef std::function<bool(llwchar)> char_functor_t; + void addFallbackFont(const LLPointer<LLFontFreetype>& fallback_font, const char_functor_t& functor = nullptr); - // Global font metrics - in units of pixels - F32 getLineHeight() const; - F32 getAscenderHeight() const; - F32 getDescenderHeight() const; + // Global font metrics - in units of pixels + F32 getLineHeight() const; + F32 getAscenderHeight() const; + F32 getDescenderHeight() const; // For a lowercase "g": // -// ------------------------------ -// ^ ^ -// | | -// xxx x |Ascender -// x x v | -// --------- xxxx-------------- Baseline -// ^ x | +// ------------------------------ +// ^ ^ +// | | +// xxx x |Ascender +// x x v | +// --------- xxxx-------------- Baseline +// ^ x | // | Descender x | -// v xxxx |LineHeight +// v xxxx |LineHeight // ----------------------- | // v -// ------------------------------ +// ------------------------------ - enum - { - FIRST_CHAR = 32, - NUM_CHARS = 127 - 32, - LAST_CHAR_BASIC = 127, + enum + { + FIRST_CHAR = 32, + NUM_CHARS = 127 - 32, + LAST_CHAR_BASIC = 127, - // Need full 8-bit ascii range for spanish - NUM_CHARS_FULL = 255 - 32, - LAST_CHAR_FULL = 255 - }; + // Need full 8-bit ascii range for spanish + NUM_CHARS_FULL = 255 - 32, + LAST_CHAR_FULL = 255 + }; - F32 getXAdvance(llwchar wc) const; - F32 getXAdvance(const LLFontGlyphInfo* glyph) const; - F32 getXKerning(llwchar char_left, llwchar char_right) const; // Get the kerning between the two characters - F32 getXKerning(const LLFontGlyphInfo* left_glyph_info, const LLFontGlyphInfo* right_glyph_info) const; // Get the kerning between the two characters + F32 getXAdvance(llwchar wc) const; + F32 getXAdvance(const LLFontGlyphInfo* glyph) const; + F32 getXKerning(llwchar char_left, llwchar char_right) const; // Get the kerning between the two characters + F32 getXKerning(const LLFontGlyphInfo* left_glyph_info, const LLFontGlyphInfo* right_glyph_info) const; // Get the kerning between the two characters - LLFontGlyphInfo* getGlyphInfo(llwchar wch, EFontGlyphType glyph_type) const; + LLFontGlyphInfo* getGlyphInfo(llwchar wch, EFontGlyphType glyph_type) const; - void reset(F32 vert_dpi, F32 horz_dpi); + void reset(F32 vert_dpi, F32 horz_dpi); - void destroyGL(); + void destroyGL(); - const std::string& getName() const; + const std::string& getName() const; - void dumpFontBitmaps() const; - const LLFontBitmapCache* getFontBitmapCache() const; + void dumpFontBitmaps() const; + const LLFontBitmapCache* getFontBitmapCache() const; - void setStyle(U8 style); - U8 getStyle() const; + void setStyle(U8 style); + U8 getStyle() const; private: - void resetBitmapCache(); - void setSubImageLuminanceAlpha(U32 x, U32 y, U32 bitmap_num, U32 width, U32 height, U8 *data, S32 stride = 0) const; - bool setSubImageBGRA(U32 x, U32 y, U32 bitmap_num, U16 width, U16 height, const U8* data, U32 stride) const; - BOOL hasGlyph(llwchar wch) const; // Has a glyph for this character - LLFontGlyphInfo* addGlyph(llwchar wch, EFontGlyphType glyph_type) const; // Add a new character to the font if necessary - LLFontGlyphInfo* addGlyphFromFont(const LLFontFreetype *fontp, llwchar wch, U32 glyph_index, EFontGlyphType bitmap_type) const; // Add a glyph from this font to the other (returns the glyph_index, 0 if not found) - void renderGlyph(EFontGlyphType bitmap_type, U32 glyph_index) const; - void insertGlyphInfo(llwchar wch, LLFontGlyphInfo* gi) const; + void resetBitmapCache(); + void setSubImageLuminanceAlpha(U32 x, U32 y, U32 bitmap_num, U32 width, U32 height, U8 *data, S32 stride = 0) const; + bool setSubImageBGRA(U32 x, U32 y, U32 bitmap_num, U16 width, U16 height, const U8* data, U32 stride) const; + BOOL hasGlyph(llwchar wch) const; // Has a glyph for this character + LLFontGlyphInfo* addGlyph(llwchar wch, EFontGlyphType glyph_type) const; // Add a new character to the font if necessary + LLFontGlyphInfo* addGlyphFromFont(const LLFontFreetype *fontp, llwchar wch, U32 glyph_index, EFontGlyphType bitmap_type) const; // Add a glyph from this font to the other (returns the glyph_index, 0 if not found) + void renderGlyph(EFontGlyphType bitmap_type, U32 glyph_index) const; + void insertGlyphInfo(llwchar wch, LLFontGlyphInfo* gi) const; - std::string mName; + std::string mName; - U8 mStyle; + U8 mStyle; - F32 mPointSize; - F32 mAscender; - F32 mDescender; - F32 mLineHeight; + F32 mPointSize; + F32 mAscender; + F32 mDescender; + F32 mLineHeight; - LLFT_Face mFTFace; + LLFT_Face mFTFace; #ifdef LL_WINDOWS - llifstream *pFileStream; - LLFT_Stream *pFtStream; + llifstream *pFileStream; + LLFT_Stream *pFtStream; #endif - BOOL mIsFallback; - typedef std::pair<LLPointer<LLFontFreetype>, char_functor_t> fallback_font_t; - typedef std::vector<fallback_font_t> fallback_font_vector_t; - fallback_font_vector_t mFallbackFonts; // A list of fallback fonts to look for glyphs in (for Unicode chars) + BOOL mIsFallback; + typedef std::pair<LLPointer<LLFontFreetype>, char_functor_t> fallback_font_t; + typedef std::vector<fallback_font_t> fallback_font_vector_t; + fallback_font_vector_t mFallbackFonts; // A list of fallback fonts to look for glyphs in (for Unicode chars) - // *NOTE: the same glyph can be present with multiple representations (but the pointer is always unique) - typedef boost::unordered_multimap<llwchar, LLFontGlyphInfo*> char_glyph_info_map_t; - mutable char_glyph_info_map_t mCharGlyphInfoMap; // Information about glyph location in bitmap + // *NOTE: the same glyph can be present with multiple representations (but the pointer is always unique) + typedef boost::unordered_multimap<llwchar, LLFontGlyphInfo*> char_glyph_info_map_t; + mutable char_glyph_info_map_t mCharGlyphInfoMap; // Information about glyph location in bitmap - mutable LLFontBitmapCache* mFontBitmapCachep; + mutable LLFontBitmapCache* mFontBitmapCachep; - mutable S32 mRenderGlyphCount; - mutable S32 mAddGlyphCount; + mutable S32 mRenderGlyphCount; + mutable S32 mAddGlyphCount; }; #endif // LL_FONTFREETYPE_H diff --git a/indra/llrender/llfontfreetypesvg.cpp b/indra/llrender/llfontfreetypesvg.cpp index 19d327a4c9..355e8432aa 100644 --- a/indra/llrender/llfontfreetypesvg.cpp +++ b/indra/llrender/llfontfreetypesvg.cpp @@ -44,21 +44,21 @@ struct LLSvgRenderData { - FT_UInt GlyphIndex = 0; - FT_Error Error = FT_Err_Ok; // FreeType currently (@2.12.1) ignores the error value returned by the preset glyph slot callback so we return it at render time - // (See https://github.com/freetype/freetype/blob/5faa1df8b93ebecf0f8fd5fe8fda7b9082eddced/src/base/ftobjs.c#L1170) - NSVGimage* pNSvgImage = nullptr; - float Scale = 0.f; + FT_UInt GlyphIndex = 0; + FT_Error Error = FT_Err_Ok; // FreeType currently (@2.12.1) ignores the error value returned by the preset glyph slot callback so we return it at render time + // (See https://github.com/freetype/freetype/blob/5faa1df8b93ebecf0f8fd5fe8fda7b9082eddced/src/base/ftobjs.c#L1170) + NSVGimage* pNSvgImage = nullptr; + float Scale = 0.f; }; // static FT_Error LLFontFreeTypeSvgRenderer::OnInit(FT_Pointer* state) { - // The SVG driver hook state is shared across all callback invocations; since our state is lightweight - // we store it in the glyph instead. - *state = nullptr; + // The SVG driver hook state is shared across all callback invocations; since our state is lightweight + // we store it in the glyph instead. + *state = nullptr; - return FT_Err_Ok; + return FT_Err_Ok; } // static @@ -69,137 +69,137 @@ void LLFontFreeTypeSvgRenderer::OnFree(FT_Pointer* state) // static void LLFontFreeTypeSvgRenderer::OnDataFinalizer(void* objectp) { - FT_GlyphSlot glyph_slot = static_cast<FT_GlyphSlot>(objectp); + FT_GlyphSlot glyph_slot = static_cast<FT_GlyphSlot>(objectp); - LLSvgRenderData* pData = static_cast<LLSvgRenderData*>(glyph_slot->generic.data); - glyph_slot->generic.data = nullptr; - glyph_slot->generic.finalizer = nullptr; - delete(pData); + LLSvgRenderData* pData = static_cast<LLSvgRenderData*>(glyph_slot->generic.data); + glyph_slot->generic.data = nullptr; + glyph_slot->generic.finalizer = nullptr; + delete(pData); } //static FT_Error LLFontFreeTypeSvgRenderer::OnPresetGlypthSlot(FT_GlyphSlot glyph_slot, FT_Bool cache, FT_Pointer*) { - FT_SVG_Document document = static_cast<FT_SVG_Document>(glyph_slot->other); - - llassert(!glyph_slot->generic.data || !cache || glyph_slot->glyph_index == ((LLSvgRenderData*)glyph_slot->generic.data)->GlyphIndex); - if (!glyph_slot->generic.data) - { - glyph_slot->generic.data = new LLSvgRenderData(); - glyph_slot->generic.finalizer = LLFontFreeTypeSvgRenderer::OnDataFinalizer; - } - LLSvgRenderData* datap = static_cast<LLSvgRenderData*>(glyph_slot->generic.data); - if (!cache) - { - datap->GlyphIndex = glyph_slot->glyph_index; - datap->Error = FT_Err_Ok; - } - - // NOTE: nsvgParse modifies the input string so we need a temporary copy - llassert(!datap->pNSvgImage || cache); - if (!datap->pNSvgImage) - { - char* document_buffer = new char[document->svg_document_length + 1]; - memcpy(document_buffer, document->svg_document, document->svg_document_length); - document_buffer[document->svg_document_length] = '\0'; - - datap->pNSvgImage = nsvgParse(document_buffer, "px", 0.); - - delete[] document_buffer; - } - - if (!datap->pNSvgImage) - { - datap->Error = FT_Err_Invalid_SVG_Document; - return FT_Err_Invalid_SVG_Document; - } - - // We don't (currently) support transformations so test for an identity rotation matrix + zero translation - if (document->transform.xx != 1 << 16 || document->transform.yx != 0 || - document->transform.xy != 0 || document->transform.yy != 1 << 16 || - document->delta.x > 0 || document->delta.y > 0) - { - datap->Error = FT_Err_Unimplemented_Feature; - return FT_Err_Unimplemented_Feature; - } - - float svg_width = datap->pNSvgImage->width; - float svg_height = datap->pNSvgImage->height; - if (svg_width == 0.f || svg_height == 0.f) - { - svg_width = document->units_per_EM; - svg_height = document->units_per_EM; - } - - float svg_x_scale = (float)document->metrics.x_ppem / floorf(svg_width); - float svg_y_scale = (float)document->metrics.y_ppem / floorf(svg_height); - float svg_scale = llmin(svg_x_scale, svg_y_scale); - datap->Scale = svg_scale; - - glyph_slot->bitmap.width = floorf(svg_width) * svg_scale; - glyph_slot->bitmap.rows = floorf(svg_height) * svg_scale; - glyph_slot->bitmap_left = (document->metrics.x_ppem - glyph_slot->bitmap.width) / 2; - glyph_slot->bitmap_top = glyph_slot->face->size->metrics.ascender / 64.f; - glyph_slot->bitmap.pitch = glyph_slot->bitmap.width * 4; - glyph_slot->bitmap.pixel_mode = FT_PIXEL_MODE_BGRA; - - /* Copied as-is from fcft (MIT license) */ - - // Compute all the bearings and set them correctly. The outline is scaled already, we just need to use the bounding box. - float horiBearingX = 0.; - float horiBearingY = -glyph_slot->bitmap_top; - - // XXX parentheses correct? - float vertBearingX = glyph_slot->metrics.horiBearingX / 64.0f - glyph_slot->metrics.horiAdvance / 64.0f / 2; - float vertBearingY = (glyph_slot->metrics.vertAdvance / 64.0f - glyph_slot->metrics.height / 64.0f) / 2; - - // Do conversion in two steps to avoid 'bad function cast' warning - glyph_slot->metrics.width = glyph_slot->bitmap.width * 64; - glyph_slot->metrics.height = glyph_slot->bitmap.rows * 64; - glyph_slot->metrics.horiBearingX = horiBearingX * 64; - glyph_slot->metrics.horiBearingY = horiBearingY * 64; - glyph_slot->metrics.vertBearingX = vertBearingX * 64; - glyph_slot->metrics.vertBearingY = vertBearingY * 64; - if (glyph_slot->metrics.vertAdvance == 0) - { - glyph_slot->metrics.vertAdvance = glyph_slot->bitmap.rows * 1.2f * 64; - } - - return FT_Err_Ok; + FT_SVG_Document document = static_cast<FT_SVG_Document>(glyph_slot->other); + + llassert(!glyph_slot->generic.data || !cache || glyph_slot->glyph_index == ((LLSvgRenderData*)glyph_slot->generic.data)->GlyphIndex); + if (!glyph_slot->generic.data) + { + glyph_slot->generic.data = new LLSvgRenderData(); + glyph_slot->generic.finalizer = LLFontFreeTypeSvgRenderer::OnDataFinalizer; + } + LLSvgRenderData* datap = static_cast<LLSvgRenderData*>(glyph_slot->generic.data); + if (!cache) + { + datap->GlyphIndex = glyph_slot->glyph_index; + datap->Error = FT_Err_Ok; + } + + // NOTE: nsvgParse modifies the input string so we need a temporary copy + llassert(!datap->pNSvgImage || cache); + if (!datap->pNSvgImage) + { + char* document_buffer = new char[document->svg_document_length + 1]; + memcpy(document_buffer, document->svg_document, document->svg_document_length); + document_buffer[document->svg_document_length] = '\0'; + + datap->pNSvgImage = nsvgParse(document_buffer, "px", 0.); + + delete[] document_buffer; + } + + if (!datap->pNSvgImage) + { + datap->Error = FT_Err_Invalid_SVG_Document; + return FT_Err_Invalid_SVG_Document; + } + + // We don't (currently) support transformations so test for an identity rotation matrix + zero translation + if (document->transform.xx != 1 << 16 || document->transform.yx != 0 || + document->transform.xy != 0 || document->transform.yy != 1 << 16 || + document->delta.x > 0 || document->delta.y > 0) + { + datap->Error = FT_Err_Unimplemented_Feature; + return FT_Err_Unimplemented_Feature; + } + + float svg_width = datap->pNSvgImage->width; + float svg_height = datap->pNSvgImage->height; + if (svg_width == 0.f || svg_height == 0.f) + { + svg_width = document->units_per_EM; + svg_height = document->units_per_EM; + } + + float svg_x_scale = (float)document->metrics.x_ppem / floorf(svg_width); + float svg_y_scale = (float)document->metrics.y_ppem / floorf(svg_height); + float svg_scale = llmin(svg_x_scale, svg_y_scale); + datap->Scale = svg_scale; + + glyph_slot->bitmap.width = floorf(svg_width) * svg_scale; + glyph_slot->bitmap.rows = floorf(svg_height) * svg_scale; + glyph_slot->bitmap_left = (document->metrics.x_ppem - glyph_slot->bitmap.width) / 2; + glyph_slot->bitmap_top = glyph_slot->face->size->metrics.ascender / 64.f; + glyph_slot->bitmap.pitch = glyph_slot->bitmap.width * 4; + glyph_slot->bitmap.pixel_mode = FT_PIXEL_MODE_BGRA; + + /* Copied as-is from fcft (MIT license) */ + + // Compute all the bearings and set them correctly. The outline is scaled already, we just need to use the bounding box. + float horiBearingX = 0.; + float horiBearingY = -glyph_slot->bitmap_top; + + // XXX parentheses correct? + float vertBearingX = glyph_slot->metrics.horiBearingX / 64.0f - glyph_slot->metrics.horiAdvance / 64.0f / 2; + float vertBearingY = (glyph_slot->metrics.vertAdvance / 64.0f - glyph_slot->metrics.height / 64.0f) / 2; + + // Do conversion in two steps to avoid 'bad function cast' warning + glyph_slot->metrics.width = glyph_slot->bitmap.width * 64; + glyph_slot->metrics.height = glyph_slot->bitmap.rows * 64; + glyph_slot->metrics.horiBearingX = horiBearingX * 64; + glyph_slot->metrics.horiBearingY = horiBearingY * 64; + glyph_slot->metrics.vertBearingX = vertBearingX * 64; + glyph_slot->metrics.vertBearingY = vertBearingY * 64; + if (glyph_slot->metrics.vertAdvance == 0) + { + glyph_slot->metrics.vertAdvance = glyph_slot->bitmap.rows * 1.2f * 64; + } + + return FT_Err_Ok; } // static FT_Error LLFontFreeTypeSvgRenderer::OnRender(FT_GlyphSlot glyph_slot, FT_Pointer*) { - LLSvgRenderData* datap = static_cast<LLSvgRenderData*>(glyph_slot->generic.data); - llassert(FT_Err_Ok == datap->Error); - if (FT_Err_Ok != datap->Error) - { - return datap->Error; - } - - // Render to glyph bitmap - NSVGrasterizer* nsvgRasterizer = nsvgCreateRasterizer(); - nsvgRasterize(nsvgRasterizer, datap->pNSvgImage, 0, 0, datap->Scale, glyph_slot->bitmap.buffer, glyph_slot->bitmap.width, glyph_slot->bitmap.rows, glyph_slot->bitmap.pitch); - nsvgDeleteRasterizer(nsvgRasterizer); - nsvgDelete(datap->pNSvgImage); - datap->pNSvgImage = nullptr; - - // Convert from RGBA to BGRA - U32* pixel_buffer = (U32*)glyph_slot->bitmap.buffer; U8* byte_buffer = glyph_slot->bitmap.buffer; - for (size_t y = 0, h = glyph_slot->bitmap.rows; y < h; y++) - { - for (size_t x = 0, w = glyph_slot->bitmap.pitch / 4; x < w; x++) - { - size_t pixel_idx = y * w + x; - size_t byte_idx = pixel_idx * 4; - U8 alpha = byte_buffer[byte_idx + 3]; - // Store as ARGB (*TODO - do we still have to care about endianness?) - pixel_buffer[y * w + x] = alpha << 24 | (byte_buffer[byte_idx] * alpha / 0xFF) << 16 | (byte_buffer[byte_idx + 1] * alpha / 0xFF) << 8 | (byte_buffer[byte_idx + 2] * alpha / 0xFF); - } - } - - glyph_slot->format = FT_GLYPH_FORMAT_BITMAP; - glyph_slot->bitmap.pixel_mode = FT_PIXEL_MODE_BGRA; - return FT_Err_Ok; + LLSvgRenderData* datap = static_cast<LLSvgRenderData*>(glyph_slot->generic.data); + llassert(FT_Err_Ok == datap->Error); + if (FT_Err_Ok != datap->Error) + { + return datap->Error; + } + + // Render to glyph bitmap + NSVGrasterizer* nsvgRasterizer = nsvgCreateRasterizer(); + nsvgRasterize(nsvgRasterizer, datap->pNSvgImage, 0, 0, datap->Scale, glyph_slot->bitmap.buffer, glyph_slot->bitmap.width, glyph_slot->bitmap.rows, glyph_slot->bitmap.pitch); + nsvgDeleteRasterizer(nsvgRasterizer); + nsvgDelete(datap->pNSvgImage); + datap->pNSvgImage = nullptr; + + // Convert from RGBA to BGRA + U32* pixel_buffer = (U32*)glyph_slot->bitmap.buffer; U8* byte_buffer = glyph_slot->bitmap.buffer; + for (size_t y = 0, h = glyph_slot->bitmap.rows; y < h; y++) + { + for (size_t x = 0, w = glyph_slot->bitmap.pitch / 4; x < w; x++) + { + size_t pixel_idx = y * w + x; + size_t byte_idx = pixel_idx * 4; + U8 alpha = byte_buffer[byte_idx + 3]; + // Store as ARGB (*TODO - do we still have to care about endianness?) + pixel_buffer[y * w + x] = alpha << 24 | (byte_buffer[byte_idx] * alpha / 0xFF) << 16 | (byte_buffer[byte_idx + 1] * alpha / 0xFF) << 8 | (byte_buffer[byte_idx + 2] * alpha / 0xFF); + } + } + + glyph_slot->format = FT_GLYPH_FORMAT_BITMAP; + glyph_slot->bitmap.pixel_mode = FT_PIXEL_MODE_BGRA; + return FT_Err_Ok; } diff --git a/indra/llrender/llfontfreetypesvg.h b/indra/llrender/llfontfreetypesvg.h index b5f541991a..72ac5293ce 100644 --- a/indra/llrender/llfontfreetypesvg.h +++ b/indra/llrender/llfontfreetypesvg.h @@ -35,20 +35,20 @@ class LLFontFreeTypeSvgRenderer { public: - // Called when the very first OT-SVG glyph is rendered (across the entire lifetime of our FT_Library object) - static FT_Error OnInit(FT_Pointer* state); + // Called when the very first OT-SVG glyph is rendered (across the entire lifetime of our FT_Library object) + static FT_Error OnInit(FT_Pointer* state); - // Called when the ot-svg module is being freed (but only called if the init hook was called previously) - static void OnFree(FT_Pointer* state); + // Called when the ot-svg module is being freed (but only called if the init hook was called previously) + static void OnFree(FT_Pointer* state); - // Called to preset the glyph slot, twice per glyph: - // - when FT_Load_Glyph needs to preset the glyph slot (with cache == false) - // - right before the svg module calls the render callback hook. (with cache == true) - static FT_Error OnPresetGlypthSlot(FT_GlyphSlot glyph_slot, FT_Bool cache, FT_Pointer* state); + // Called to preset the glyph slot, twice per glyph: + // - when FT_Load_Glyph needs to preset the glyph slot (with cache == false) + // - right before the svg module calls the render callback hook. (with cache == true) + static FT_Error OnPresetGlypthSlot(FT_GlyphSlot glyph_slot, FT_Bool cache, FT_Pointer* state); - // Called to render an OT-SVG glyph (right after the preset hook OnPresetGlypthSlot was called with cache set to TRUE) - static FT_Error OnRender(FT_GlyphSlot glyph_slot, FT_Pointer* state); + // Called to render an OT-SVG glyph (right after the preset hook OnPresetGlypthSlot was called with cache set to TRUE) + static FT_Error OnRender(FT_GlyphSlot glyph_slot, FT_Pointer* state); - // Called to deallocate our per glyph slot data - static void OnDataFinalizer(void* objectp); + // Called to deallocate our per glyph slot data + static void OnDataFinalizer(void* objectp); }; diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp index 53661b6a63..8d0fed7829 100644 --- a/indra/llrender/llfontgl.cpp +++ b/indra/llrender/llfontgl.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llfontgl.cpp * @brief Wrapper around FreeType * * $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$ */ @@ -81,32 +81,32 @@ LLFontGL::~LLFontGL() void LLFontGL::reset() { - mFontFreetype->reset(sVertDPI, sHorizDPI); + mFontFreetype->reset(sVertDPI, sHorizDPI); } void LLFontGL::destroyGL() { - mFontFreetype->destroyGL(); + mFontFreetype->destroyGL(); } BOOL LLFontGL::loadFace(const std::string& filename, F32 point_size, const F32 vert_dpi, const F32 horz_dpi, bool is_fallback, S32 face_n) { - if(mFontFreetype == reinterpret_cast<LLFontFreetype*>(NULL)) - { - mFontFreetype = new LLFontFreetype; - } + if(mFontFreetype == reinterpret_cast<LLFontFreetype*>(NULL)) + { + mFontFreetype = new LLFontFreetype; + } - return mFontFreetype->loadFace(filename, point_size, vert_dpi, horz_dpi, is_fallback, face_n); + return mFontFreetype->loadFace(filename, point_size, vert_dpi, horz_dpi, is_fallback, face_n); } S32 LLFontGL::getNumFaces(const std::string& filename) { - if (mFontFreetype == reinterpret_cast<LLFontFreetype*>(NULL)) - { - mFontFreetype = new LLFontFreetype; - } + if (mFontFreetype == reinterpret_cast<LLFontFreetype*>(NULL)) + { + mFontFreetype = new LLFontFreetype; + } - return mFontFreetype->getNumFaces(filename); + return mFontFreetype->getNumFaces(filename); } S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, const LLRect& rect, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, @@ -116,439 +116,439 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, const LLRect& rect return render(wstr, begin_offset, rect_float, color, halign, valign, style, shadow, max_chars, right_x, use_ellipses, use_color); } -S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, const LLRectf& rect, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, - ShadowType shadow, S32 max_chars, F32* right_x, BOOL use_ellipses, BOOL use_color) const +S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, const LLRectf& rect, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, + ShadowType shadow, S32 max_chars, F32* right_x, BOOL use_ellipses, BOOL use_color) const { - F32 x = rect.mLeft; - F32 y = 0.f; + F32 x = rect.mLeft; + F32 y = 0.f; - switch(valign) - { - case TOP: - y = rect.mTop; - break; - case VCENTER: - y = rect.getCenterY(); - break; - case BASELINE: - case BOTTOM: - y = rect.mBottom; - break; - default: - y = rect.mBottom; - break; - } - return render(wstr, begin_offset, x, y, color, halign, valign, style, shadow, max_chars, rect.getWidth(), right_x, use_ellipses, use_color); + switch(valign) + { + case TOP: + y = rect.mTop; + break; + case VCENTER: + y = rect.getCenterY(); + break; + case BASELINE: + case BOTTOM: + y = rect.mBottom; + break; + default: + y = rect.mBottom; + break; + } + return render(wstr, begin_offset, x, y, color, halign, valign, style, shadow, max_chars, rect.getWidth(), right_x, use_ellipses, use_color); } -S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, - ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_ellipses, BOOL use_color) const +S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, + ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_ellipses, BOOL use_color) const { LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; - if(!sDisplayFont) //do not display texts - { - return wstr.length() ; - } - - if (wstr.empty()) - { - return 0; - } - - gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); - - S32 scaled_max_pixels = max_pixels == S32_MAX ? S32_MAX : llceil((F32)max_pixels * sScaleX); - - // determine which style flags need to be added programmatically by stripping off the - // style bits that are drawn by the underlying Freetype font - U8 style_to_add = (style | mFontDescriptor.getStyle()) & ~mFontFreetype->getStyle(); - - F32 drop_shadow_strength = 0.f; - if (shadow != NO_SHADOW) - { - F32 luminance; - color.calcHSL(NULL, NULL, &luminance); - drop_shadow_strength = clamp_rescale(luminance, 0.35f, 0.6f, 0.f, 1.f); - if (luminance < 0.35f) - { - shadow = NO_SHADOW; - } - } - - gGL.pushUIMatrix(); - - gGL.loadUIIdentity(); - - LLVector2 origin(floorf(sCurOrigin.mX*sScaleX), floorf(sCurOrigin.mY*sScaleY)); - - // Depth translation, so that floating text appears 'in-world' - // and is correctly occluded. - gGL.translatef(0.f,0.f,sCurDepth); - - S32 chars_drawn = 0; - S32 i; - S32 length; - - if (-1 == max_chars) - { - max_chars = length = (S32)wstr.length() - begin_offset; - } - else - { - length = llmin((S32)wstr.length() - begin_offset, max_chars ); - } - - F32 cur_x, cur_y, cur_render_x, cur_render_y; - - // Not guaranteed to be set correctly - gGL.setSceneBlendType(LLRender::BT_ALPHA); - - cur_x = ((F32)x * sScaleX) + origin.mV[VX]; - cur_y = ((F32)y * sScaleY) + origin.mV[VY]; - - // Offset y by vertical alignment. - // use unscaled font metrics here - switch (valign) - { - case TOP: - cur_y -= llceil(mFontFreetype->getAscenderHeight()); - break; - case BOTTOM: - cur_y += llceil(mFontFreetype->getDescenderHeight()); - break; - case VCENTER: - cur_y -= llceil((llceil(mFontFreetype->getAscenderHeight()) - llceil(mFontFreetype->getDescenderHeight())) / 2.f); - break; - case BASELINE: - // Baseline, do nothing. - break; - default: - break; - } - - switch (halign) - { - case LEFT: - break; - case RIGHT: - cur_x -= llmin(scaled_max_pixels, ll_round(getWidthF32(wstr.c_str(), begin_offset, length) * sScaleX)); - break; - case HCENTER: - cur_x -= llmin(scaled_max_pixels, ll_round(getWidthF32(wstr.c_str(), begin_offset, length) * sScaleX)) / 2; - break; - default: - break; - } - - cur_render_y = cur_y; - cur_render_x = cur_x; - - F32 start_x = (F32)ll_round(cur_x); - - const LLFontBitmapCache* font_bitmap_cache = mFontFreetype->getFontBitmapCache(); - - F32 inv_width = 1.f / font_bitmap_cache->getBitmapWidth(); - F32 inv_height = 1.f / font_bitmap_cache->getBitmapHeight(); - - const S32 LAST_CHARACTER = LLFontFreetype::LAST_CHAR_FULL; - - BOOL draw_ellipses = FALSE; - if (use_ellipses) - { - // check for too long of a string - S32 string_width = ll_round(getWidthF32(wstr.c_str(), begin_offset, max_chars) * sScaleX); - if (string_width > scaled_max_pixels) - { - // use four dots for ellipsis width to generate padding - const LLWString dots(utf8str_to_wstring(std::string("...."))); - scaled_max_pixels = llmax(0, scaled_max_pixels - ll_round(getWidthF32(dots.c_str()))); - draw_ellipses = TRUE; - } - } - - const LLFontGlyphInfo* next_glyph = NULL; - - const S32 GLYPH_BATCH_SIZE = 30; - LLVector3 vertices[GLYPH_BATCH_SIZE * 4]; - LLVector2 uvs[GLYPH_BATCH_SIZE * 4]; - LLColor4U colors[GLYPH_BATCH_SIZE * 4]; - - LLColor4U text_color(color); - - std::pair<EFontGlyphType, S32> bitmap_entry = std::make_pair(EFontGlyphType::Grayscale, -1); - S32 glyph_count = 0; - for (i = begin_offset; i < begin_offset + length; i++) - { - llwchar wch = wstr[i]; - - const LLFontGlyphInfo* fgi = next_glyph; - next_glyph = NULL; - if(!fgi) - { - fgi = mFontFreetype->getGlyphInfo(wch, (!use_color) ? EFontGlyphType::Grayscale : EFontGlyphType::Color); - } - if (!fgi) - { - LL_ERRS() << "Missing Glyph Info" << LL_ENDL; - break; - } - // Per-glyph bitmap texture. - std::pair<EFontGlyphType, S32> next_bitmap_entry = fgi->mBitmapEntry; - if (next_bitmap_entry != bitmap_entry) - { - // Actually draw the queued glyphs before switching their texture; - // otherwise the queued glyphs will be taken from wrong textures. - if (glyph_count > 0) - { - gGL.begin(LLRender::QUADS); - { - gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4); - } - gGL.end(); - glyph_count = 0; - } - - bitmap_entry = next_bitmap_entry; - LLImageGL* font_image = font_bitmap_cache->getImageGL(bitmap_entry.first, bitmap_entry.second); - gGL.getTexUnit(0)->bind(font_image); - } - - if ((start_x + scaled_max_pixels) < (cur_x + fgi->mXBearing + fgi->mWidth)) - { - // Not enough room for this character. - break; - } - - // Draw the text at the appropriate location - //Specify vertices and texture coordinates - LLRectf uv_rect((fgi->mXBitmapOffset) * inv_width, - (fgi->mYBitmapOffset + fgi->mHeight + PAD_UVY) * inv_height, - (fgi->mXBitmapOffset + fgi->mWidth) * inv_width, - (fgi->mYBitmapOffset - PAD_UVY) * inv_height); - // snap glyph origin to whole screen pixel - LLRectf screen_rect((F32)ll_round(cur_render_x + (F32)fgi->mXBearing), - (F32)ll_round(cur_render_y + (F32)fgi->mYBearing), - (F32)ll_round(cur_render_x + (F32)fgi->mXBearing) + (F32)fgi->mWidth, - (F32)ll_round(cur_render_y + (F32)fgi->mYBearing) - (F32)fgi->mHeight); - - if (glyph_count >= GLYPH_BATCH_SIZE) - { - gGL.begin(LLRender::QUADS); - { - gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4); - } - gGL.end(); - - glyph_count = 0; - } - - drawGlyph(glyph_count, vertices, uvs, colors, screen_rect, uv_rect, (bitmap_entry.first == EFontGlyphType::Grayscale) ? text_color : LLColor4U::white, style_to_add, shadow, drop_shadow_strength); - - chars_drawn++; - cur_x += fgi->mXAdvance; - cur_y += fgi->mYAdvance; - - llwchar next_char = wstr[i+1]; - if (next_char && (next_char < LAST_CHARACTER)) - { - // Kern this puppy. - next_glyph = mFontFreetype->getGlyphInfo(next_char, (!use_color) ? EFontGlyphType::Grayscale : EFontGlyphType::Color); - cur_x += mFontFreetype->getXKerning(fgi, next_glyph); - } - - // Round after kerning. - // Must do this to cur_x, not just to cur_render_x, otherwise you - // will squish sub-pixel kerned characters too close together. - // For example, "CCCCC" looks bad. - cur_x = (F32)ll_round(cur_x); - //cur_y = (F32)ll_round(cur_y); - - cur_render_x = cur_x; - cur_render_y = cur_y; - } - - gGL.begin(LLRender::QUADS); - { - gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4); - } - gGL.end(); - - - if (right_x) - { - *right_x = (cur_x - origin.mV[VX]) / sScaleX; - } - - //FIXME: add underline as glyph? - if (style_to_add & UNDERLINE) - { - F32 descender = (F32)llfloor(mFontFreetype->getDescenderHeight()); - - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.begin(LLRender::LINES); - gGL.vertex2f(start_x, cur_y - descender); - gGL.vertex2f(cur_x, cur_y - descender); - gGL.end(); - } - - if (draw_ellipses) - { - - // recursively render ellipses at end of string - // we've already reserved enough room - gGL.pushUIMatrix(); - renderUTF8(std::string("..."), - 0, - (cur_x - origin.mV[VX]) / sScaleX, (F32)y, - color, - LEFT, valign, - style_to_add, - shadow, - S32_MAX, max_pixels, - right_x, - FALSE, - use_color); - gGL.popUIMatrix(); - } - - gGL.popUIMatrix(); - - return chars_drawn; + if(!sDisplayFont) //do not display texts + { + return wstr.length() ; + } + + if (wstr.empty()) + { + return 0; + } + + gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); + + S32 scaled_max_pixels = max_pixels == S32_MAX ? S32_MAX : llceil((F32)max_pixels * sScaleX); + + // determine which style flags need to be added programmatically by stripping off the + // style bits that are drawn by the underlying Freetype font + U8 style_to_add = (style | mFontDescriptor.getStyle()) & ~mFontFreetype->getStyle(); + + F32 drop_shadow_strength = 0.f; + if (shadow != NO_SHADOW) + { + F32 luminance; + color.calcHSL(NULL, NULL, &luminance); + drop_shadow_strength = clamp_rescale(luminance, 0.35f, 0.6f, 0.f, 1.f); + if (luminance < 0.35f) + { + shadow = NO_SHADOW; + } + } + + gGL.pushUIMatrix(); + + gGL.loadUIIdentity(); + + LLVector2 origin(floorf(sCurOrigin.mX*sScaleX), floorf(sCurOrigin.mY*sScaleY)); + + // Depth translation, so that floating text appears 'in-world' + // and is correctly occluded. + gGL.translatef(0.f,0.f,sCurDepth); + + S32 chars_drawn = 0; + S32 i; + S32 length; + + if (-1 == max_chars) + { + max_chars = length = (S32)wstr.length() - begin_offset; + } + else + { + length = llmin((S32)wstr.length() - begin_offset, max_chars ); + } + + F32 cur_x, cur_y, cur_render_x, cur_render_y; + + // Not guaranteed to be set correctly + gGL.setSceneBlendType(LLRender::BT_ALPHA); + + cur_x = ((F32)x * sScaleX) + origin.mV[VX]; + cur_y = ((F32)y * sScaleY) + origin.mV[VY]; + + // Offset y by vertical alignment. + // use unscaled font metrics here + switch (valign) + { + case TOP: + cur_y -= llceil(mFontFreetype->getAscenderHeight()); + break; + case BOTTOM: + cur_y += llceil(mFontFreetype->getDescenderHeight()); + break; + case VCENTER: + cur_y -= llceil((llceil(mFontFreetype->getAscenderHeight()) - llceil(mFontFreetype->getDescenderHeight())) / 2.f); + break; + case BASELINE: + // Baseline, do nothing. + break; + default: + break; + } + + switch (halign) + { + case LEFT: + break; + case RIGHT: + cur_x -= llmin(scaled_max_pixels, ll_round(getWidthF32(wstr.c_str(), begin_offset, length) * sScaleX)); + break; + case HCENTER: + cur_x -= llmin(scaled_max_pixels, ll_round(getWidthF32(wstr.c_str(), begin_offset, length) * sScaleX)) / 2; + break; + default: + break; + } + + cur_render_y = cur_y; + cur_render_x = cur_x; + + F32 start_x = (F32)ll_round(cur_x); + + const LLFontBitmapCache* font_bitmap_cache = mFontFreetype->getFontBitmapCache(); + + F32 inv_width = 1.f / font_bitmap_cache->getBitmapWidth(); + F32 inv_height = 1.f / font_bitmap_cache->getBitmapHeight(); + + const S32 LAST_CHARACTER = LLFontFreetype::LAST_CHAR_FULL; + + BOOL draw_ellipses = FALSE; + if (use_ellipses) + { + // check for too long of a string + S32 string_width = ll_round(getWidthF32(wstr.c_str(), begin_offset, max_chars) * sScaleX); + if (string_width > scaled_max_pixels) + { + // use four dots for ellipsis width to generate padding + const LLWString dots(utf8str_to_wstring(std::string("...."))); + scaled_max_pixels = llmax(0, scaled_max_pixels - ll_round(getWidthF32(dots.c_str()))); + draw_ellipses = TRUE; + } + } + + const LLFontGlyphInfo* next_glyph = NULL; + + const S32 GLYPH_BATCH_SIZE = 30; + LLVector3 vertices[GLYPH_BATCH_SIZE * 4]; + LLVector2 uvs[GLYPH_BATCH_SIZE * 4]; + LLColor4U colors[GLYPH_BATCH_SIZE * 4]; + + LLColor4U text_color(color); + + std::pair<EFontGlyphType, S32> bitmap_entry = std::make_pair(EFontGlyphType::Grayscale, -1); + S32 glyph_count = 0; + for (i = begin_offset; i < begin_offset + length; i++) + { + llwchar wch = wstr[i]; + + const LLFontGlyphInfo* fgi = next_glyph; + next_glyph = NULL; + if(!fgi) + { + fgi = mFontFreetype->getGlyphInfo(wch, (!use_color) ? EFontGlyphType::Grayscale : EFontGlyphType::Color); + } + if (!fgi) + { + LL_ERRS() << "Missing Glyph Info" << LL_ENDL; + break; + } + // Per-glyph bitmap texture. + std::pair<EFontGlyphType, S32> next_bitmap_entry = fgi->mBitmapEntry; + if (next_bitmap_entry != bitmap_entry) + { + // Actually draw the queued glyphs before switching their texture; + // otherwise the queued glyphs will be taken from wrong textures. + if (glyph_count > 0) + { + gGL.begin(LLRender::QUADS); + { + gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4); + } + gGL.end(); + glyph_count = 0; + } + + bitmap_entry = next_bitmap_entry; + LLImageGL* font_image = font_bitmap_cache->getImageGL(bitmap_entry.first, bitmap_entry.second); + gGL.getTexUnit(0)->bind(font_image); + } + + if ((start_x + scaled_max_pixels) < (cur_x + fgi->mXBearing + fgi->mWidth)) + { + // Not enough room for this character. + break; + } + + // Draw the text at the appropriate location + //Specify vertices and texture coordinates + LLRectf uv_rect((fgi->mXBitmapOffset) * inv_width, + (fgi->mYBitmapOffset + fgi->mHeight + PAD_UVY) * inv_height, + (fgi->mXBitmapOffset + fgi->mWidth) * inv_width, + (fgi->mYBitmapOffset - PAD_UVY) * inv_height); + // snap glyph origin to whole screen pixel + LLRectf screen_rect((F32)ll_round(cur_render_x + (F32)fgi->mXBearing), + (F32)ll_round(cur_render_y + (F32)fgi->mYBearing), + (F32)ll_round(cur_render_x + (F32)fgi->mXBearing) + (F32)fgi->mWidth, + (F32)ll_round(cur_render_y + (F32)fgi->mYBearing) - (F32)fgi->mHeight); + + if (glyph_count >= GLYPH_BATCH_SIZE) + { + gGL.begin(LLRender::QUADS); + { + gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4); + } + gGL.end(); + + glyph_count = 0; + } + + drawGlyph(glyph_count, vertices, uvs, colors, screen_rect, uv_rect, (bitmap_entry.first == EFontGlyphType::Grayscale) ? text_color : LLColor4U::white, style_to_add, shadow, drop_shadow_strength); + + chars_drawn++; + cur_x += fgi->mXAdvance; + cur_y += fgi->mYAdvance; + + llwchar next_char = wstr[i+1]; + if (next_char && (next_char < LAST_CHARACTER)) + { + // Kern this puppy. + next_glyph = mFontFreetype->getGlyphInfo(next_char, (!use_color) ? EFontGlyphType::Grayscale : EFontGlyphType::Color); + cur_x += mFontFreetype->getXKerning(fgi, next_glyph); + } + + // Round after kerning. + // Must do this to cur_x, not just to cur_render_x, otherwise you + // will squish sub-pixel kerned characters too close together. + // For example, "CCCCC" looks bad. + cur_x = (F32)ll_round(cur_x); + //cur_y = (F32)ll_round(cur_y); + + cur_render_x = cur_x; + cur_render_y = cur_y; + } + + gGL.begin(LLRender::QUADS); + { + gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4); + } + gGL.end(); + + + if (right_x) + { + *right_x = (cur_x - origin.mV[VX]) / sScaleX; + } + + //FIXME: add underline as glyph? + if (style_to_add & UNDERLINE) + { + F32 descender = (F32)llfloor(mFontFreetype->getDescenderHeight()); + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.begin(LLRender::LINES); + gGL.vertex2f(start_x, cur_y - descender); + gGL.vertex2f(cur_x, cur_y - descender); + gGL.end(); + } + + if (draw_ellipses) + { + + // recursively render ellipses at end of string + // we've already reserved enough room + gGL.pushUIMatrix(); + renderUTF8(std::string("..."), + 0, + (cur_x - origin.mV[VX]) / sScaleX, (F32)y, + color, + LEFT, valign, + style_to_add, + shadow, + S32_MAX, max_pixels, + right_x, + FALSE, + use_color); + gGL.popUIMatrix(); + } + + gGL.popUIMatrix(); + + return chars_drawn; } S32 LLFontGL::render(const LLWString &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color) const { - return render(text, begin_offset, x, y, color, LEFT, BASELINE, NORMAL, NO_SHADOW); + return render(text, begin_offset, x, y, color, LEFT, BASELINE, NORMAL, NO_SHADOW); } S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_ellipses, BOOL use_color) const { - return render(utf8str_to_wstring(text), begin_offset, x, y, color, halign, valign, style, shadow, max_chars, max_pixels, right_x, use_ellipses, use_color); + return render(utf8str_to_wstring(text), begin_offset, x, y, color, halign, valign, style, shadow, max_chars, max_pixels, right_x, use_ellipses, use_color); } S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color) const { - return renderUTF8(text, begin_offset, (F32)x, (F32)y, color, LEFT, BASELINE, NORMAL, NO_SHADOW); + return renderUTF8(text, begin_offset, (F32)x, (F32)y, color, LEFT, BASELINE, NORMAL, NO_SHADOW); } S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, ShadowType shadow) const { - return renderUTF8(text, begin_offset, (F32)x, (F32)y, color, halign, valign, style, shadow); + return renderUTF8(text, begin_offset, (F32)x, (F32)y, color, halign, valign, style, shadow); } // font metrics - override for LLFontFreetype that returns units of virtual pixels F32 LLFontGL::getAscenderHeight() const -{ - return mFontFreetype->getAscenderHeight() / sScaleY; +{ + return mFontFreetype->getAscenderHeight() / sScaleY; } F32 LLFontGL::getDescenderHeight() const -{ - return mFontFreetype->getDescenderHeight() / sScaleY; +{ + return mFontFreetype->getDescenderHeight() / sScaleY; } S32 LLFontGL::getLineHeight() const -{ - return llceil(mFontFreetype->getAscenderHeight() / sScaleY) + llceil(mFontFreetype->getDescenderHeight() / sScaleY); +{ + return llceil(mFontFreetype->getAscenderHeight() / sScaleY) + llceil(mFontFreetype->getDescenderHeight() / sScaleY); } S32 LLFontGL::getWidth(const std::string& utf8text) const { - LLWString wtext = utf8str_to_wstring(utf8text); - return getWidth(wtext.c_str(), 0, S32_MAX); + LLWString wtext = utf8str_to_wstring(utf8text); + return getWidth(wtext.c_str(), 0, S32_MAX); } S32 LLFontGL::getWidth(const llwchar* wchars) const { - return getWidth(wchars, 0, S32_MAX); + return getWidth(wchars, 0, S32_MAX); } S32 LLFontGL::getWidth(const std::string& utf8text, S32 begin_offset, S32 max_chars) const { - LLWString wtext = utf8str_to_wstring(utf8text); - return getWidth(wtext.c_str(), begin_offset, max_chars); + LLWString wtext = utf8str_to_wstring(utf8text); + return getWidth(wtext.c_str(), begin_offset, max_chars); } S32 LLFontGL::getWidth(const llwchar* wchars, S32 begin_offset, S32 max_chars) const { - F32 width = getWidthF32(wchars, begin_offset, max_chars); - return ll_round(width); + F32 width = getWidthF32(wchars, begin_offset, max_chars); + return ll_round(width); } F32 LLFontGL::getWidthF32(const std::string& utf8text) const { - LLWString wtext = utf8str_to_wstring(utf8text); - return getWidthF32(wtext.c_str(), 0, S32_MAX); + LLWString wtext = utf8str_to_wstring(utf8text); + return getWidthF32(wtext.c_str(), 0, S32_MAX); } F32 LLFontGL::getWidthF32(const llwchar* wchars) const { - return getWidthF32(wchars, 0, S32_MAX); + return getWidthF32(wchars, 0, S32_MAX); } F32 LLFontGL::getWidthF32(const std::string& utf8text, S32 begin_offset, S32 max_chars) const { - LLWString wtext = utf8str_to_wstring(utf8text); - return getWidthF32(wtext.c_str(), begin_offset, max_chars); + LLWString wtext = utf8str_to_wstring(utf8text); + return getWidthF32(wtext.c_str(), begin_offset, max_chars); } F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars, bool no_padding) const { - const S32 LAST_CHARACTER = LLFontFreetype::LAST_CHAR_FULL; - - F32 cur_x = 0; - const S32 max_index = begin_offset + max_chars; - - const LLFontGlyphInfo* next_glyph = NULL; - - F32 width_padding = 0.f; - for (S32 i = begin_offset; i < max_index && wchars[i] != 0; i++) - { - llwchar wch = wchars[i]; - - const LLFontGlyphInfo* fgi = next_glyph; - next_glyph = NULL; - if(!fgi) - { - fgi = mFontFreetype->getGlyphInfo(wch, EFontGlyphType::Unspecified); - } - - F32 advance = mFontFreetype->getXAdvance(fgi); - - if (!no_padding) - { - // for the last character we want to measure the greater of its width and xadvance values - // so keep track of the difference between these values for the each character we measure - // so we can fix things up at the end - width_padding = llmax(0.f, // always use positive padding amount - width_padding - advance, // previous padding left over after advance of current character - (F32)(fgi->mWidth + fgi->mXBearing) - advance); // difference between width of this character and advance to next character - } - - cur_x += advance; - llwchar next_char = wchars[i+1]; - - if (((i + 1) < begin_offset + max_chars) - && next_char - && (next_char < LAST_CHARACTER)) - { - // Kern this puppy. - next_glyph = mFontFreetype->getGlyphInfo(next_char, EFontGlyphType::Unspecified); - cur_x += mFontFreetype->getXKerning(fgi, next_glyph); - } - // Round after kerning. - cur_x = (F32)ll_round(cur_x); - } - - if (!no_padding) - { - // add in extra pixels for last character's width past its xadvance - cur_x += width_padding; - } - - return cur_x / sScaleX; + const S32 LAST_CHARACTER = LLFontFreetype::LAST_CHAR_FULL; + + F32 cur_x = 0; + const S32 max_index = begin_offset + max_chars; + + const LLFontGlyphInfo* next_glyph = NULL; + + F32 width_padding = 0.f; + for (S32 i = begin_offset; i < max_index && wchars[i] != 0; i++) + { + llwchar wch = wchars[i]; + + const LLFontGlyphInfo* fgi = next_glyph; + next_glyph = NULL; + if(!fgi) + { + fgi = mFontFreetype->getGlyphInfo(wch, EFontGlyphType::Unspecified); + } + + F32 advance = mFontFreetype->getXAdvance(fgi); + + if (!no_padding) + { + // for the last character we want to measure the greater of its width and xadvance values + // so keep track of the difference between these values for the each character we measure + // so we can fix things up at the end + width_padding = llmax(0.f, // always use positive padding amount + width_padding - advance, // previous padding left over after advance of current character + (F32)(fgi->mWidth + fgi->mXBearing) - advance); // difference between width of this character and advance to next character + } + + cur_x += advance; + llwchar next_char = wchars[i+1]; + + if (((i + 1) < begin_offset + max_chars) + && next_char + && (next_char < LAST_CHARACTER)) + { + // Kern this puppy. + next_glyph = mFontFreetype->getGlyphInfo(next_char, EFontGlyphType::Unspecified); + cur_x += mFontFreetype->getXKerning(fgi, next_glyph); + } + // Round after kerning. + cur_x = (F32)ll_round(cur_x); + } + + if (!no_padding) + { + // add in extra pixels for last character's width past its xadvance + cur_x += width_padding; + } + + return cur_x / sScaleX; } void LLFontGL::generateASCIIglyphs() @@ -563,308 +563,308 @@ void LLFontGL::generateASCIIglyphs() // Returns the max number of complete characters from text (up to max_chars) that can be drawn in max_pixels S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_chars, EWordWrapStyle end_on_word_boundary) const { - LL_PROFILE_ZONE_SCOPED_CATEGORY_UI - if (!wchars || !wchars[0] || max_chars == 0) - { - return 0; - } - - llassert(max_pixels >= 0.f); - llassert(max_chars >= 0); - - BOOL clip = FALSE; - F32 cur_x = 0; - - S32 start_of_last_word = 0; - BOOL in_word = FALSE; - - // avoid S32 overflow when max_pixels == S32_MAX by staying in floating point - F32 scaled_max_pixels = max_pixels * sScaleX; - F32 width_padding = 0.f; - - LLFontGlyphInfo* next_glyph = NULL; - - S32 i; - for (i=0; (i < max_chars); i++) - { - llwchar wch = wchars[i]; - - if(wch == 0) - { - // Null terminator. We're done. - break; - } - - if (in_word) - { - if (iswspace(wch)) - { - if(wch !=(0x00A0)) - { - in_word = FALSE; - } - } - if (iswindividual(wch)) - { - if (iswpunct(wchars[i+1])) - { - in_word=TRUE; - } - else - { - in_word=FALSE; - start_of_last_word = i; - } - } - } - else - { - start_of_last_word = i; - if (!iswspace(wch)||!iswindividual(wch)) - { - in_word = TRUE; - } - } - - LLFontGlyphInfo* fgi = next_glyph; - next_glyph = NULL; - if(!fgi) - { - fgi = mFontFreetype->getGlyphInfo(wch, EFontGlyphType::Unspecified); - - if (NULL == fgi) - { - return 0; - } - } - - // account for glyphs that run beyond the starting point for the next glyphs - width_padding = llmax( 0.f, // always use positive padding amount - width_padding - fgi->mXAdvance, // previous padding left over after advance of current character - (F32)(fgi->mWidth + fgi->mXBearing) - fgi->mXAdvance); // difference between width of this character and advance to next character - - cur_x += fgi->mXAdvance; - - // clip if current character runs past scaled_max_pixels (using width_padding) - if (scaled_max_pixels < cur_x + width_padding) - { - clip = TRUE; - break; - } - - if (((i+1) < max_chars) && wchars[i+1]) - { - // Kern this puppy. - next_glyph = mFontFreetype->getGlyphInfo(wchars[i+1], EFontGlyphType::Unspecified); - cur_x += mFontFreetype->getXKerning(fgi, next_glyph); - } - - // Round after kerning. - cur_x = (F32)ll_round(cur_x); - } - - if( clip ) - { - switch (end_on_word_boundary) - { - case ONLY_WORD_BOUNDARIES: - i = start_of_last_word; - break; - case WORD_BOUNDARY_IF_POSSIBLE: - if (start_of_last_word != 0) - { - i = start_of_last_word; - } - break; - default: - case ANYWHERE: - // do nothing - break; - } - } - return i; -} - -S32 LLFontGL::firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_len, S32 start_pos, S32 max_chars) const -{ - if (!wchars || !wchars[0] || max_chars == 0) - { - return 0; - } - - F32 total_width = 0.0; - S32 drawable_chars = 0; - - F32 scaled_max_pixels = max_pixels * sScaleX; - - S32 start = llmin(start_pos, text_len - 1); - for (S32 i = start; i >= 0; i--) - { - llwchar wch = wchars[i]; - - const LLFontGlyphInfo* fgi= mFontFreetype->getGlyphInfo(wch, EFontGlyphType::Unspecified); - - // last character uses character width, since the whole character needs to be visible - // other characters just use advance - F32 width = (i == start) - ? (F32)(fgi->mWidth + fgi->mXBearing) // use actual width for last character - : fgi->mXAdvance; // use advance for all other characters - - if( scaled_max_pixels < (total_width + width) ) - { - break; - } - - total_width += width; - drawable_chars++; - - if( max_chars >= 0 && drawable_chars >= max_chars ) - { - break; - } - - if ( i > 0 ) - { - // kerning - total_width += mFontFreetype->getXKerning(wchars[i-1], wch); - } - - // Round after kerning. - total_width = (F32)ll_round(total_width); - } - - if (drawable_chars == 0) - { - return start_pos; // just draw last character - } - else - { - // if only 1 character is drawable, we want to return start_pos as the first character to draw - // if 2 are drawable, return start_pos and character before start_pos, etc. - return start_pos + 1 - drawable_chars; - } - + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI + if (!wchars || !wchars[0] || max_chars == 0) + { + return 0; + } + + llassert(max_pixels >= 0.f); + llassert(max_chars >= 0); + + BOOL clip = FALSE; + F32 cur_x = 0; + + S32 start_of_last_word = 0; + BOOL in_word = FALSE; + + // avoid S32 overflow when max_pixels == S32_MAX by staying in floating point + F32 scaled_max_pixels = max_pixels * sScaleX; + F32 width_padding = 0.f; + + LLFontGlyphInfo* next_glyph = NULL; + + S32 i; + for (i=0; (i < max_chars); i++) + { + llwchar wch = wchars[i]; + + if(wch == 0) + { + // Null terminator. We're done. + break; + } + + if (in_word) + { + if (iswspace(wch)) + { + if(wch !=(0x00A0)) + { + in_word = FALSE; + } + } + if (iswindividual(wch)) + { + if (iswpunct(wchars[i+1])) + { + in_word=TRUE; + } + else + { + in_word=FALSE; + start_of_last_word = i; + } + } + } + else + { + start_of_last_word = i; + if (!iswspace(wch)||!iswindividual(wch)) + { + in_word = TRUE; + } + } + + LLFontGlyphInfo* fgi = next_glyph; + next_glyph = NULL; + if(!fgi) + { + fgi = mFontFreetype->getGlyphInfo(wch, EFontGlyphType::Unspecified); + + if (NULL == fgi) + { + return 0; + } + } + + // account for glyphs that run beyond the starting point for the next glyphs + width_padding = llmax( 0.f, // always use positive padding amount + width_padding - fgi->mXAdvance, // previous padding left over after advance of current character + (F32)(fgi->mWidth + fgi->mXBearing) - fgi->mXAdvance); // difference between width of this character and advance to next character + + cur_x += fgi->mXAdvance; + + // clip if current character runs past scaled_max_pixels (using width_padding) + if (scaled_max_pixels < cur_x + width_padding) + { + clip = TRUE; + break; + } + + if (((i+1) < max_chars) && wchars[i+1]) + { + // Kern this puppy. + next_glyph = mFontFreetype->getGlyphInfo(wchars[i+1], EFontGlyphType::Unspecified); + cur_x += mFontFreetype->getXKerning(fgi, next_glyph); + } + + // Round after kerning. + cur_x = (F32)ll_round(cur_x); + } + + if( clip ) + { + switch (end_on_word_boundary) + { + case ONLY_WORD_BOUNDARIES: + i = start_of_last_word; + break; + case WORD_BOUNDARY_IF_POSSIBLE: + if (start_of_last_word != 0) + { + i = start_of_last_word; + } + break; + default: + case ANYWHERE: + // do nothing + break; + } + } + return i; +} + +S32 LLFontGL::firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_len, S32 start_pos, S32 max_chars) const +{ + if (!wchars || !wchars[0] || max_chars == 0) + { + return 0; + } + + F32 total_width = 0.0; + S32 drawable_chars = 0; + + F32 scaled_max_pixels = max_pixels * sScaleX; + + S32 start = llmin(start_pos, text_len - 1); + for (S32 i = start; i >= 0; i--) + { + llwchar wch = wchars[i]; + + const LLFontGlyphInfo* fgi= mFontFreetype->getGlyphInfo(wch, EFontGlyphType::Unspecified); + + // last character uses character width, since the whole character needs to be visible + // other characters just use advance + F32 width = (i == start) + ? (F32)(fgi->mWidth + fgi->mXBearing) // use actual width for last character + : fgi->mXAdvance; // use advance for all other characters + + if( scaled_max_pixels < (total_width + width) ) + { + break; + } + + total_width += width; + drawable_chars++; + + if( max_chars >= 0 && drawable_chars >= max_chars ) + { + break; + } + + if ( i > 0 ) + { + // kerning + total_width += mFontFreetype->getXKerning(wchars[i-1], wch); + } + + // Round after kerning. + total_width = (F32)ll_round(total_width); + } + + if (drawable_chars == 0) + { + return start_pos; // just draw last character + } + else + { + // if only 1 character is drawable, we want to return start_pos as the first character to draw + // if 2 are drawable, return start_pos and character before start_pos, etc. + return start_pos + 1 - drawable_chars; + } + } S32 LLFontGL::charFromPixelOffset(const llwchar* wchars, S32 begin_offset, F32 target_x, F32 max_pixels, S32 max_chars, BOOL round) const { - if (!wchars || !wchars[0] || max_chars == 0) - { - return 0; - } - - F32 cur_x = 0; - - target_x *= sScaleX; - - // max_chars is S32_MAX by default, so make sure we don't get overflow - const S32 max_index = begin_offset + llmin(S32_MAX - begin_offset, max_chars - 1); - - F32 scaled_max_pixels = max_pixels * sScaleX; - - const LLFontGlyphInfo* next_glyph = NULL; - - S32 pos; - for (pos = begin_offset; pos < max_index; pos++) - { - llwchar wch = wchars[pos]; - if (!wch) - { - break; // done - } - - const LLFontGlyphInfo* glyph = next_glyph; - next_glyph = NULL; - if(!glyph) - { - glyph = mFontFreetype->getGlyphInfo(wch, EFontGlyphType::Unspecified); - } - - F32 char_width = mFontFreetype->getXAdvance(glyph); - - if (round) - { - // Note: if the mouse is on the left half of the character, the pick is to the character's left - // If it's on the right half, the pick is to the right. - if (target_x < cur_x + char_width*0.5f) - { - break; - } - } - else if (target_x < cur_x + char_width) - { - break; - } - - if (scaled_max_pixels < cur_x + char_width) - { - break; - } - - cur_x += char_width; - - if (((pos + 1) < max_index) - && (wchars[(pos + 1)])) - { - // Kern this puppy. - next_glyph = mFontFreetype->getGlyphInfo(wchars[pos + 1], EFontGlyphType::Unspecified); - cur_x += mFontFreetype->getXKerning(glyph, next_glyph); - } - - - // Round after kerning. - cur_x = (F32)ll_round(cur_x); - } - - return llmin(max_chars, pos - begin_offset); + if (!wchars || !wchars[0] || max_chars == 0) + { + return 0; + } + + F32 cur_x = 0; + + target_x *= sScaleX; + + // max_chars is S32_MAX by default, so make sure we don't get overflow + const S32 max_index = begin_offset + llmin(S32_MAX - begin_offset, max_chars - 1); + + F32 scaled_max_pixels = max_pixels * sScaleX; + + const LLFontGlyphInfo* next_glyph = NULL; + + S32 pos; + for (pos = begin_offset; pos < max_index; pos++) + { + llwchar wch = wchars[pos]; + if (!wch) + { + break; // done + } + + const LLFontGlyphInfo* glyph = next_glyph; + next_glyph = NULL; + if(!glyph) + { + glyph = mFontFreetype->getGlyphInfo(wch, EFontGlyphType::Unspecified); + } + + F32 char_width = mFontFreetype->getXAdvance(glyph); + + if (round) + { + // Note: if the mouse is on the left half of the character, the pick is to the character's left + // If it's on the right half, the pick is to the right. + if (target_x < cur_x + char_width*0.5f) + { + break; + } + } + else if (target_x < cur_x + char_width) + { + break; + } + + if (scaled_max_pixels < cur_x + char_width) + { + break; + } + + cur_x += char_width; + + if (((pos + 1) < max_index) + && (wchars[(pos + 1)])) + { + // Kern this puppy. + next_glyph = mFontFreetype->getGlyphInfo(wchars[pos + 1], EFontGlyphType::Unspecified); + cur_x += mFontFreetype->getXKerning(glyph, next_glyph); + } + + + // Round after kerning. + cur_x = (F32)ll_round(cur_x); + } + + return llmin(max_chars, pos - begin_offset); } const LLFontDescriptor& LLFontGL::getFontDesc() const { - return mFontDescriptor; + return mFontDescriptor; } // static void LLFontGL::initClass(F32 screen_dpi, F32 x_scale, F32 y_scale, const std::string& app_dir, bool create_gl_textures) { - sVertDPI = (F32)llfloor(screen_dpi * y_scale); - sHorizDPI = (F32)llfloor(screen_dpi * x_scale); - sScaleX = x_scale; - sScaleY = y_scale; - sAppDir = app_dir; - - // Font registry init - if (!sFontRegistry) - { - sFontRegistry = new LLFontRegistry(create_gl_textures); - sFontRegistry->parseFontInfo("fonts.xml"); - } - else - { - sFontRegistry->reset(); - } + sVertDPI = (F32)llfloor(screen_dpi * y_scale); + sHorizDPI = (F32)llfloor(screen_dpi * x_scale); + sScaleX = x_scale; + sScaleY = y_scale; + sAppDir = app_dir; + + // Font registry init + if (!sFontRegistry) + { + sFontRegistry = new LLFontRegistry(create_gl_textures); + sFontRegistry->parseFontInfo("fonts.xml"); + } + else + { + sFontRegistry->reset(); + } - LLFontGL::loadDefaultFonts(); + LLFontGL::loadDefaultFonts(); } void LLFontGL::dumpTextures() { - if (mFontFreetype.notNull()) - { - mFontFreetype->dumpFontBitmaps(); - } + if (mFontFreetype.notNull()) + { + mFontFreetype->dumpFontBitmaps(); + } } // static void LLFontGL::dumpFonts() { - sFontRegistry->dump(); + sFontRegistry->dump(); } // static void LLFontGL::dumpFontTextures() { - sFontRegistry->dumpTextures(); + sFontRegistry->dumpTextures(); } // Force standard fonts to get generated up front. @@ -874,15 +874,15 @@ void LLFontGL::dumpFontTextures() // static bool LLFontGL::loadDefaultFonts() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_UI - bool succ = true; - succ &= (NULL != getFontSansSerifSmall()); - succ &= (NULL != getFontSansSerif()); - succ &= (NULL != getFontSansSerifBig()); - succ &= (NULL != getFontSansSerifHuge()); - succ &= (NULL != getFontSansSerifBold()); - succ &= (NULL != getFontMonospace()); - return succ; + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI + bool succ = true; + succ &= (NULL != getFontSansSerifSmall()); + succ &= (NULL != getFontSansSerif()); + succ &= (NULL != getFontSansSerifBig()); + succ &= (NULL != getFontSansSerifHuge()); + succ &= (NULL != getFontSansSerifBold()); + succ &= (NULL != getFontMonospace()); + return succ; } void LLFontGL::loadCommonFonts() @@ -897,164 +897,164 @@ void LLFontGL::loadCommonFonts() // static void LLFontGL::destroyDefaultFonts() { - // Remove the actual fonts. - delete sFontRegistry; - sFontRegistry = NULL; + // Remove the actual fonts. + delete sFontRegistry; + sFontRegistry = NULL; } -//static +//static void LLFontGL::destroyAllGL() { - if (sFontRegistry) - { - sFontRegistry->destroyGL(); - } + if (sFontRegistry) + { + sFontRegistry->destroyGL(); + } } // static U8 LLFontGL::getStyleFromString(const std::string &style) { - S32 ret = 0; - if (style.find("BOLD") != style.npos) - { - ret |= BOLD; - } - if (style.find("ITALIC") != style.npos) - { - ret |= ITALIC; - } - if (style.find("UNDERLINE") != style.npos) - { - ret |= UNDERLINE; - } - return ret; + S32 ret = 0; + if (style.find("BOLD") != style.npos) + { + ret |= BOLD; + } + if (style.find("ITALIC") != style.npos) + { + ret |= ITALIC; + } + if (style.find("UNDERLINE") != style.npos) + { + ret |= UNDERLINE; + } + return ret; } // static std::string LLFontGL::getStringFromStyle(U8 style) { - std::string style_string; - if (style == NORMAL) - { - style_string += "|NORMAL"; - } - if (style & BOLD) - { - style_string += "|BOLD"; - } - if (style & ITALIC) - { - style_string += "|ITALIC"; - } - if (style & UNDERLINE) - { - style_string += "|UNDERLINE"; - } - return style_string; + std::string style_string; + if (style == NORMAL) + { + style_string += "|NORMAL"; + } + if (style & BOLD) + { + style_string += "|BOLD"; + } + if (style & ITALIC) + { + style_string += "|ITALIC"; + } + if (style & UNDERLINE) + { + style_string += "|UNDERLINE"; + } + return style_string; } // static std::string LLFontGL::nameFromFont(const LLFontGL* fontp) { - return fontp->mFontDescriptor.getName(); + return fontp->mFontDescriptor.getName(); } // static std::string LLFontGL::sizeFromFont(const LLFontGL* fontp) { - return fontp->mFontDescriptor.getSize(); + return fontp->mFontDescriptor.getSize(); } // static std::string LLFontGL::nameFromHAlign(LLFontGL::HAlign align) { - if (align == LEFT) return std::string("left"); - else if (align == RIGHT) return std::string("right"); - else if (align == HCENTER) return std::string("center"); - else return std::string(); + if (align == LEFT) return std::string("left"); + else if (align == RIGHT) return std::string("right"); + else if (align == HCENTER) return std::string("center"); + else return std::string(); } // static LLFontGL::HAlign LLFontGL::hAlignFromName(const std::string& name) { - LLFontGL::HAlign gl_hfont_align = LLFontGL::LEFT; - if (name == "left") - { - gl_hfont_align = LLFontGL::LEFT; - } - else if (name == "right") - { - gl_hfont_align = LLFontGL::RIGHT; - } - else if (name == "center") - { - gl_hfont_align = LLFontGL::HCENTER; - } - //else leave left - return gl_hfont_align; + LLFontGL::HAlign gl_hfont_align = LLFontGL::LEFT; + if (name == "left") + { + gl_hfont_align = LLFontGL::LEFT; + } + else if (name == "right") + { + gl_hfont_align = LLFontGL::RIGHT; + } + else if (name == "center") + { + gl_hfont_align = LLFontGL::HCENTER; + } + //else leave left + return gl_hfont_align; } // static std::string LLFontGL::nameFromVAlign(LLFontGL::VAlign align) { - if (align == TOP) return std::string("top"); - else if (align == VCENTER) return std::string("center"); - else if (align == BASELINE) return std::string("baseline"); - else if (align == BOTTOM) return std::string("bottom"); - else return std::string(); + if (align == TOP) return std::string("top"); + else if (align == VCENTER) return std::string("center"); + else if (align == BASELINE) return std::string("baseline"); + else if (align == BOTTOM) return std::string("bottom"); + else return std::string(); } // static LLFontGL::VAlign LLFontGL::vAlignFromName(const std::string& name) { - LLFontGL::VAlign gl_vfont_align = LLFontGL::BASELINE; - if (name == "top") - { - gl_vfont_align = LLFontGL::TOP; - } - else if (name == "center") - { - gl_vfont_align = LLFontGL::VCENTER; - } - else if (name == "baseline") - { - gl_vfont_align = LLFontGL::BASELINE; - } - else if (name == "bottom") - { - gl_vfont_align = LLFontGL::BOTTOM; - } - //else leave baseline - return gl_vfont_align; + LLFontGL::VAlign gl_vfont_align = LLFontGL::BASELINE; + if (name == "top") + { + gl_vfont_align = LLFontGL::TOP; + } + else if (name == "center") + { + gl_vfont_align = LLFontGL::VCENTER; + } + else if (name == "baseline") + { + gl_vfont_align = LLFontGL::BASELINE; + } + else if (name == "bottom") + { + gl_vfont_align = LLFontGL::BOTTOM; + } + //else leave baseline + return gl_vfont_align; } //static LLFontGL* LLFontGL::getFontEmoji() { - static LLFontGL* fontp = getFont(LLFontDescriptor("Emoji", "Large", 0)); - return fontp;; + static LLFontGL* fontp = getFont(LLFontDescriptor("Emoji", "Large", 0)); + return fontp;; } //static LLFontGL* LLFontGL::getFontEmojiHuge() { - static LLFontGL* fontp = getFont(LLFontDescriptor("Emoji", "Huge", 0)); - return fontp;; + static LLFontGL* fontp = getFont(LLFontDescriptor("Emoji", "Huge", 0)); + return fontp;; } //static LLFontGL* LLFontGL::getFontMonospace() { - static LLFontGL* fontp = getFont(LLFontDescriptor("Monospace","Monospace",0)); - return fontp; + static LLFontGL* fontp = getFont(LLFontDescriptor("Monospace","Monospace",0)); + return fontp; } //static LLFontGL* LLFontGL::getFontSansSerifSmall() { - static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Small",0)); - return fontp; + static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Small",0)); + return fontp; } //static @@ -1074,73 +1074,73 @@ LLFontGL* LLFontGL::getFontSansSerifSmallItalic() //static LLFontGL* LLFontGL::getFontSansSerif() { - static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Medium",0)); - return fontp; + static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Medium",0)); + return fontp; } //static LLFontGL* LLFontGL::getFontSansSerifBig() { - static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Large",0)); - return fontp; + static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Large",0)); + return fontp; } -//static +//static LLFontGL* LLFontGL::getFontSansSerifHuge() { - static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Huge",0)); - return fontp; + static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Huge",0)); + return fontp; } -//static +//static LLFontGL* LLFontGL::getFontSansSerifBold() { - static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Medium",BOLD)); - return fontp; + static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Medium",BOLD)); + return fontp; } -//static +//static LLFontGL* LLFontGL::getFont(const LLFontDescriptor& desc) { - return sFontRegistry->getFont(desc); + return sFontRegistry->getFont(desc); } //static LLFontGL* LLFontGL::getFontByName(const std::string& name) { - // check for most common fonts first - if (name == "SANSSERIF") - { - return getFontSansSerif(); - } - else if (name == "SANSSERIF_SMALL") - { - return getFontSansSerifSmall(); - } - else if (name == "SANSSERIF_BIG") - { - return getFontSansSerifBig(); - } - else if (name == "SMALL" || name == "OCRA") - { - // *BUG: Should this be "MONOSPACE"? Do we use "OCRA" anymore? - // Does "SMALL" mean "SERIF"? - return getFontMonospace(); - } - else - { - return NULL; - } + // check for most common fonts first + if (name == "SANSSERIF") + { + return getFontSansSerif(); + } + else if (name == "SANSSERIF_SMALL") + { + return getFontSansSerifSmall(); + } + else if (name == "SANSSERIF_BIG") + { + return getFontSansSerifBig(); + } + else if (name == "SMALL" || name == "OCRA") + { + // *BUG: Should this be "MONOSPACE"? Do we use "OCRA" anymore? + // Does "SMALL" mean "SERIF"? + return getFontMonospace(); + } + else + { + return NULL; + } } //static LLFontGL* LLFontGL::getFontDefault() { - return getFontSansSerif(); // Fallback to sans serif as default font + return getFontSansSerif(); // Fallback to sans serif as default font } -// static +// static std::string LLFontGL::getFontPathSystem() { #if LL_DARWIN @@ -1173,127 +1173,127 @@ std::string LLFontGL::getFontPathSystem() } -// static +// static std::string LLFontGL::getFontPathLocal() { - std::string local_path; + std::string local_path; - // Backup files if we can't load from system fonts directory. - // We could store this in an end-user writable directory to allow - // end users to switch fonts. - if (LLFontGL::sAppDir.length()) - { - // use specified application dir to look for fonts - local_path = LLFontGL::sAppDir + "/fonts/"; - } - else - { - // assume working directory is executable directory - local_path = "./fonts/"; - } - return local_path; + // Backup files if we can't load from system fonts directory. + // We could store this in an end-user writable directory to allow + // end users to switch fonts. + if (LLFontGL::sAppDir.length()) + { + // use specified application dir to look for fonts + local_path = LLFontGL::sAppDir + "/fonts/"; + } + else + { + // assume working directory is executable directory + local_path = "./fonts/"; + } + return local_path; } LLFontGL::LLFontGL(const LLFontGL &source) { - LL_ERRS() << "Not implemented!" << LL_ENDL; + LL_ERRS() << "Not implemented!" << LL_ENDL; } LLFontGL &LLFontGL::operator=(const LLFontGL &source) { - LL_ERRS() << "Not implemented" << LL_ENDL; - return *this; + LL_ERRS() << "Not implemented" << LL_ENDL; + return *this; } void LLFontGL::renderQuad(LLVector3* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, F32 slant_amt) const { - S32 index = 0; + S32 index = 0; - vertex_out[index] = LLVector3(screen_rect.mRight, screen_rect.mTop, 0.f); - uv_out[index] = LLVector2(uv_rect.mRight, uv_rect.mTop); - colors_out[index] = color; - index++; + vertex_out[index] = LLVector3(screen_rect.mRight, screen_rect.mTop, 0.f); + uv_out[index] = LLVector2(uv_rect.mRight, uv_rect.mTop); + colors_out[index] = color; + index++; - vertex_out[index] = LLVector3(screen_rect.mLeft, screen_rect.mTop, 0.f); - uv_out[index] = LLVector2(uv_rect.mLeft, uv_rect.mTop); - colors_out[index] = color; - index++; + vertex_out[index] = LLVector3(screen_rect.mLeft, screen_rect.mTop, 0.f); + uv_out[index] = LLVector2(uv_rect.mLeft, uv_rect.mTop); + colors_out[index] = color; + index++; - vertex_out[index] = LLVector3(screen_rect.mLeft, screen_rect.mBottom, 0.f); - uv_out[index] = LLVector2(uv_rect.mLeft, uv_rect.mBottom); - colors_out[index] = color; - index++; + vertex_out[index] = LLVector3(screen_rect.mLeft, screen_rect.mBottom, 0.f); + uv_out[index] = LLVector2(uv_rect.mLeft, uv_rect.mBottom); + colors_out[index] = color; + index++; - vertex_out[index] = LLVector3(screen_rect.mRight, screen_rect.mBottom, 0.f); - uv_out[index] = LLVector2(uv_rect.mRight, uv_rect.mBottom); - colors_out[index] = color; + vertex_out[index] = LLVector3(screen_rect.mRight, screen_rect.mBottom, 0.f); + uv_out[index] = LLVector2(uv_rect.mRight, uv_rect.mBottom); + colors_out[index] = color; } void LLFontGL::drawGlyph(S32& glyph_count, LLVector3* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, U8 style, ShadowType shadow, F32 drop_shadow_strength) const { - F32 slant_offset; - slant_offset = ((style & ITALIC) ? ( -mFontFreetype->getAscenderHeight() * 0.2f) : 0.f); - - //FIXME: bold and drop shadow are mutually exclusive only for convenience - //Allow both when we need them. - if (style & BOLD) - { - for (S32 pass = 0; pass < 2; pass++) - { - LLRectf screen_rect_offset = screen_rect; - - screen_rect_offset.translate((F32)(pass * BOLD_OFFSET), 0.f); - renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect_offset, uv_rect, color, slant_offset); - glyph_count++; - } - } - else if (shadow == DROP_SHADOW_SOFT) - { - LLColor4U shadow_color = LLFontGL::sShadowColor; - shadow_color.mV[VALPHA] = U8(color.mV[VALPHA] * drop_shadow_strength * DROP_SHADOW_SOFT_STRENGTH); - for (S32 pass = 0; pass < 5; pass++) - { - LLRectf screen_rect_offset = screen_rect; - - switch(pass) - { - case 0: - screen_rect_offset.translate(-1.f, -1.f); - break; - case 1: - screen_rect_offset.translate(1.f, -1.f); - break; - case 2: - screen_rect_offset.translate(1.f, 1.f); - break; - case 3: - screen_rect_offset.translate(-1.f, 1.f); - break; - case 4: - screen_rect_offset.translate(0, -2.f); - break; - } - - renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect_offset, uv_rect, shadow_color, slant_offset); - glyph_count++; - } - renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect, uv_rect, color, slant_offset); - glyph_count++; - } - else if (shadow == DROP_SHADOW) - { - LLColor4U shadow_color = LLFontGL::sShadowColor; - shadow_color.mV[VALPHA] = U8(color.mV[VALPHA] * drop_shadow_strength); - LLRectf screen_rect_shadow = screen_rect; - screen_rect_shadow.translate(1.f, -1.f); - renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect_shadow, uv_rect, shadow_color, slant_offset); - glyph_count++; - renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect, uv_rect, color, slant_offset); - glyph_count++; - } - else // normal rendering - { - renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect, uv_rect, color, slant_offset); - glyph_count++; - } + F32 slant_offset; + slant_offset = ((style & ITALIC) ? ( -mFontFreetype->getAscenderHeight() * 0.2f) : 0.f); + + //FIXME: bold and drop shadow are mutually exclusive only for convenience + //Allow both when we need them. + if (style & BOLD) + { + for (S32 pass = 0; pass < 2; pass++) + { + LLRectf screen_rect_offset = screen_rect; + + screen_rect_offset.translate((F32)(pass * BOLD_OFFSET), 0.f); + renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect_offset, uv_rect, color, slant_offset); + glyph_count++; + } + } + else if (shadow == DROP_SHADOW_SOFT) + { + LLColor4U shadow_color = LLFontGL::sShadowColor; + shadow_color.mV[VALPHA] = U8(color.mV[VALPHA] * drop_shadow_strength * DROP_SHADOW_SOFT_STRENGTH); + for (S32 pass = 0; pass < 5; pass++) + { + LLRectf screen_rect_offset = screen_rect; + + switch(pass) + { + case 0: + screen_rect_offset.translate(-1.f, -1.f); + break; + case 1: + screen_rect_offset.translate(1.f, -1.f); + break; + case 2: + screen_rect_offset.translate(1.f, 1.f); + break; + case 3: + screen_rect_offset.translate(-1.f, 1.f); + break; + case 4: + screen_rect_offset.translate(0, -2.f); + break; + } + + renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect_offset, uv_rect, shadow_color, slant_offset); + glyph_count++; + } + renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect, uv_rect, color, slant_offset); + glyph_count++; + } + else if (shadow == DROP_SHADOW) + { + LLColor4U shadow_color = LLFontGL::sShadowColor; + shadow_color.mV[VALPHA] = U8(color.mV[VALPHA] * drop_shadow_strength); + LLRectf screen_rect_shadow = screen_rect; + screen_rect_shadow.translate(1.f, -1.f); + renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect_shadow, uv_rect, shadow_color, slant_offset); + glyph_count++; + renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect, uv_rect, color, slant_offset); + glyph_count++; + } + else // normal rendering + { + renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect, uv_rect, color, slant_offset); + glyph_count++; + } } diff --git a/indra/llrender/llfontgl.h b/indra/llrender/llfontgl.h index f6ec416c8b..2e1d04a2b9 100644 --- a/indra/llrender/llfontgl.h +++ b/indra/llrender/llfontgl.h @@ -1,4 +1,4 @@ -/** +/** * @file llfontgl.h * @author Doug Soo * @brief Wrapper around FreeType @@ -6,21 +6,21 @@ * $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$ */ @@ -46,201 +46,201 @@ class LLFontRegistry; class LLFontGL { public: - enum HAlign - { - // Horizontal location of x,y coord to render. - LEFT = 0, // Left align - RIGHT = 1, // Right align - HCENTER = 2, // Center - }; - - enum VAlign - { - // Vertical location of x,y coord to render. - TOP = 3, // Top align - VCENTER = 4, // Center - BASELINE = 5, // Baseline - BOTTOM = 6 // Bottom - }; - - enum StyleFlags - { - // text style to render. May be combined (these are bit flags) - NORMAL = 0x00, - BOLD = 0x01, - ITALIC = 0x02, - UNDERLINE = 0x04 - }; - - enum ShadowType - { - NO_SHADOW, - DROP_SHADOW, - DROP_SHADOW_SOFT - }; - - LLFontGL(); - ~LLFontGL(); - - - void reset(); // Reset a font after GL cleanup. ONLY works on an already loaded font. - - void destroyGL(); - - BOOL loadFace(const std::string& filename, F32 point_size, const F32 vert_dpi, const F32 horz_dpi, bool is_fallback, S32 face_n); - - S32 getNumFaces(const std::string& filename); - - S32 render(const LLWString &text, S32 begin_offset, - const LLRect& rect, - const LLColor4 &color, - HAlign halign = LEFT, VAlign valign = BASELINE, - U8 style = NORMAL, ShadowType shadow = NO_SHADOW, - S32 max_chars = S32_MAX, - F32* right_x=NULL, - BOOL use_ellipses = FALSE, - BOOL use_color = TRUE) const; - - S32 render(const LLWString &text, S32 begin_offset, - const LLRectf& rect, - const LLColor4 &color, - HAlign halign = LEFT, VAlign valign = BASELINE, - U8 style = NORMAL, ShadowType shadow = NO_SHADOW, - S32 max_chars = S32_MAX, - F32* right_x=NULL, - BOOL use_ellipses = FALSE, - BOOL use_color = TRUE) const; - - S32 render(const LLWString &text, S32 begin_offset, - F32 x, F32 y, - const LLColor4 &color, - HAlign halign = LEFT, VAlign valign = BASELINE, - U8 style = NORMAL, ShadowType shadow = NO_SHADOW, - S32 max_chars = S32_MAX, S32 max_pixels = S32_MAX, - F32* right_x=NULL, - BOOL use_ellipses = FALSE, - BOOL use_color = TRUE) const; - - S32 render(const LLWString &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color) const; - - // renderUTF8 does a conversion, so is slower! - S32 renderUTF8(const std::string &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, ShadowType shadow, S32 max_chars = S32_MAX, S32 max_pixels = S32_MAX, F32* right_x = NULL, BOOL use_ellipses = FALSE, BOOL use_color = TRUE) const; - S32 renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color) const; - S32 renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style = NORMAL, ShadowType shadow = NO_SHADOW) const; - - // font metrics - override for LLFontFreetype that returns units of virtual pixels - F32 getAscenderHeight() const; - F32 getDescenderHeight() const; - S32 getLineHeight() const; - - S32 getWidth(const std::string& utf8text) const; - S32 getWidth(const llwchar* wchars) const; - S32 getWidth(const std::string& utf8text, S32 offset, S32 max_chars) const; - S32 getWidth(const llwchar* wchars, S32 offset, S32 max_chars) const; - - F32 getWidthF32(const std::string& utf8text) const; - F32 getWidthF32(const llwchar* wchars) const; - F32 getWidthF32(const std::string& text, S32 offset, S32 max_chars) const; - F32 getWidthF32(const llwchar* wchars, S32 offset, S32 max_chars, bool no_padding = false) const; - - // The following are called often, frequently with large buffers, so do not use a string interface - - // Returns the max number of complete characters from text (up to max_chars) that can be drawn in max_pixels - typedef enum e_word_wrap_style - { - ONLY_WORD_BOUNDARIES, - WORD_BOUNDARY_IF_POSSIBLE, - ANYWHERE - } EWordWrapStyle ; - S32 maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_chars = S32_MAX, EWordWrapStyle end_on_word_boundary = ANYWHERE) const; - - // Returns the index of the first complete characters from text that can be drawn in max_pixels - // given that the character at start_pos should be the last character (or as close to last as possible). - S32 firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_len, S32 start_pos=S32_MAX, S32 max_chars = S32_MAX) const; - - // Returns the index of the character closest to pixel position x (ignoring text to the right of max_pixels and max_chars) - S32 charFromPixelOffset(const llwchar* wchars, S32 char_offset, F32 x, F32 max_pixels=F32_MAX, S32 max_chars = S32_MAX, BOOL round = TRUE) const; - - const LLFontDescriptor& getFontDesc() const; - - void generateASCIIglyphs(); - - - static void initClass(F32 screen_dpi, F32 x_scale, F32 y_scale, const std::string& app_dir, bool create_gl_textures = true); - - void dumpTextures(); - static void dumpFonts(); - static void dumpFontTextures(); - - // Load sans-serif, sans-serif-small, etc. - // Slow, requires multiple seconds to load fonts. - static bool loadDefaultFonts(); + enum HAlign + { + // Horizontal location of x,y coord to render. + LEFT = 0, // Left align + RIGHT = 1, // Right align + HCENTER = 2, // Center + }; + + enum VAlign + { + // Vertical location of x,y coord to render. + TOP = 3, // Top align + VCENTER = 4, // Center + BASELINE = 5, // Baseline + BOTTOM = 6 // Bottom + }; + + enum StyleFlags + { + // text style to render. May be combined (these are bit flags) + NORMAL = 0x00, + BOLD = 0x01, + ITALIC = 0x02, + UNDERLINE = 0x04 + }; + + enum ShadowType + { + NO_SHADOW, + DROP_SHADOW, + DROP_SHADOW_SOFT + }; + + LLFontGL(); + ~LLFontGL(); + + + void reset(); // Reset a font after GL cleanup. ONLY works on an already loaded font. + + void destroyGL(); + + BOOL loadFace(const std::string& filename, F32 point_size, const F32 vert_dpi, const F32 horz_dpi, bool is_fallback, S32 face_n); + + S32 getNumFaces(const std::string& filename); + + S32 render(const LLWString &text, S32 begin_offset, + const LLRect& rect, + const LLColor4 &color, + HAlign halign = LEFT, VAlign valign = BASELINE, + U8 style = NORMAL, ShadowType shadow = NO_SHADOW, + S32 max_chars = S32_MAX, + F32* right_x=NULL, + BOOL use_ellipses = FALSE, + BOOL use_color = TRUE) const; + + S32 render(const LLWString &text, S32 begin_offset, + const LLRectf& rect, + const LLColor4 &color, + HAlign halign = LEFT, VAlign valign = BASELINE, + U8 style = NORMAL, ShadowType shadow = NO_SHADOW, + S32 max_chars = S32_MAX, + F32* right_x=NULL, + BOOL use_ellipses = FALSE, + BOOL use_color = TRUE) const; + + S32 render(const LLWString &text, S32 begin_offset, + F32 x, F32 y, + const LLColor4 &color, + HAlign halign = LEFT, VAlign valign = BASELINE, + U8 style = NORMAL, ShadowType shadow = NO_SHADOW, + S32 max_chars = S32_MAX, S32 max_pixels = S32_MAX, + F32* right_x=NULL, + BOOL use_ellipses = FALSE, + BOOL use_color = TRUE) const; + + S32 render(const LLWString &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color) const; + + // renderUTF8 does a conversion, so is slower! + S32 renderUTF8(const std::string &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, ShadowType shadow, S32 max_chars = S32_MAX, S32 max_pixels = S32_MAX, F32* right_x = NULL, BOOL use_ellipses = FALSE, BOOL use_color = TRUE) const; + S32 renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color) const; + S32 renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style = NORMAL, ShadowType shadow = NO_SHADOW) const; + + // font metrics - override for LLFontFreetype that returns units of virtual pixels + F32 getAscenderHeight() const; + F32 getDescenderHeight() const; + S32 getLineHeight() const; + + S32 getWidth(const std::string& utf8text) const; + S32 getWidth(const llwchar* wchars) const; + S32 getWidth(const std::string& utf8text, S32 offset, S32 max_chars) const; + S32 getWidth(const llwchar* wchars, S32 offset, S32 max_chars) const; + + F32 getWidthF32(const std::string& utf8text) const; + F32 getWidthF32(const llwchar* wchars) const; + F32 getWidthF32(const std::string& text, S32 offset, S32 max_chars) const; + F32 getWidthF32(const llwchar* wchars, S32 offset, S32 max_chars, bool no_padding = false) const; + + // The following are called often, frequently with large buffers, so do not use a string interface + + // Returns the max number of complete characters from text (up to max_chars) that can be drawn in max_pixels + typedef enum e_word_wrap_style + { + ONLY_WORD_BOUNDARIES, + WORD_BOUNDARY_IF_POSSIBLE, + ANYWHERE + } EWordWrapStyle ; + S32 maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_chars = S32_MAX, EWordWrapStyle end_on_word_boundary = ANYWHERE) const; + + // Returns the index of the first complete characters from text that can be drawn in max_pixels + // given that the character at start_pos should be the last character (or as close to last as possible). + S32 firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_len, S32 start_pos=S32_MAX, S32 max_chars = S32_MAX) const; + + // Returns the index of the character closest to pixel position x (ignoring text to the right of max_pixels and max_chars) + S32 charFromPixelOffset(const llwchar* wchars, S32 char_offset, F32 x, F32 max_pixels=F32_MAX, S32 max_chars = S32_MAX, BOOL round = TRUE) const; + + const LLFontDescriptor& getFontDesc() const; + + void generateASCIIglyphs(); + + + static void initClass(F32 screen_dpi, F32 x_scale, F32 y_scale, const std::string& app_dir, bool create_gl_textures = true); + + void dumpTextures(); + static void dumpFonts(); + static void dumpFontTextures(); + + // Load sans-serif, sans-serif-small, etc. + // Slow, requires multiple seconds to load fonts. + static bool loadDefaultFonts(); static void loadCommonFonts(); - static void destroyDefaultFonts(); - static void destroyAllGL(); + static void destroyDefaultFonts(); + static void destroyAllGL(); + + // Takes a string with potentially several flags, i.e. "NORMAL|BOLD|ITALIC" + static U8 getStyleFromString(const std::string &style); + static std::string getStringFromStyle(U8 style); - // Takes a string with potentially several flags, i.e. "NORMAL|BOLD|ITALIC" - static U8 getStyleFromString(const std::string &style); - static std::string getStringFromStyle(U8 style); + static std::string nameFromFont(const LLFontGL* fontp); + static std::string sizeFromFont(const LLFontGL* fontp); - static std::string nameFromFont(const LLFontGL* fontp); - static std::string sizeFromFont(const LLFontGL* fontp); + static std::string nameFromHAlign(LLFontGL::HAlign align); + static LLFontGL::HAlign hAlignFromName(const std::string& name); - static std::string nameFromHAlign(LLFontGL::HAlign align); - static LLFontGL::HAlign hAlignFromName(const std::string& name); + static std::string nameFromVAlign(LLFontGL::VAlign align); + static LLFontGL::VAlign vAlignFromName(const std::string& name); - static std::string nameFromVAlign(LLFontGL::VAlign align); - static LLFontGL::VAlign vAlignFromName(const std::string& name); + static void setFontDisplay(BOOL flag) { sDisplayFont = flag; } - static void setFontDisplay(BOOL flag) { sDisplayFont = flag; } - - static LLFontGL* getFontEmoji(); - static LLFontGL* getFontEmojiHuge(); - static LLFontGL* getFontMonospace(); - static LLFontGL* getFontSansSerifSmall(); + static LLFontGL* getFontEmoji(); + static LLFontGL* getFontEmojiHuge(); + static LLFontGL* getFontMonospace(); + static LLFontGL* getFontSansSerifSmall(); static LLFontGL* getFontSansSerifSmallBold(); static LLFontGL* getFontSansSerifSmallItalic(); - static LLFontGL* getFontSansSerif(); - static LLFontGL* getFontSansSerifBig(); - static LLFontGL* getFontSansSerifHuge(); - static LLFontGL* getFontSansSerifBold(); - static LLFontGL* getFont(const LLFontDescriptor& desc); - // Use with legacy names like "SANSSERIF_SMALL" or "OCRA" - static LLFontGL* getFontByName(const std::string& name); - static LLFontGL* getFontDefault(); // default fallback font - - static std::string getFontPathLocal(); - static std::string getFontPathSystem(); - - static LLCoordGL sCurOrigin; - static F32 sCurDepth; - static std::vector<std::pair<LLCoordGL, F32> > sOriginStack; - - static LLColor4 sShadowColor; - - static F32 sVertDPI; - static F32 sHorizDPI; - static F32 sScaleX; - static F32 sScaleY; - static BOOL sDisplayFont ; - static std::string sAppDir; // For loading fonts + static LLFontGL* getFontSansSerif(); + static LLFontGL* getFontSansSerifBig(); + static LLFontGL* getFontSansSerifHuge(); + static LLFontGL* getFontSansSerifBold(); + static LLFontGL* getFont(const LLFontDescriptor& desc); + // Use with legacy names like "SANSSERIF_SMALL" or "OCRA" + static LLFontGL* getFontByName(const std::string& name); + static LLFontGL* getFontDefault(); // default fallback font + + static std::string getFontPathLocal(); + static std::string getFontPathSystem(); + + static LLCoordGL sCurOrigin; + static F32 sCurDepth; + static std::vector<std::pair<LLCoordGL, F32> > sOriginStack; + + static LLColor4 sShadowColor; + + static F32 sVertDPI; + static F32 sHorizDPI; + static F32 sScaleX; + static F32 sScaleY; + static BOOL sDisplayFont ; + static std::string sAppDir; // For loading fonts private: - friend class LLFontRegistry; - friend class LLTextBillboard; - friend class LLHUDText; + friend class LLFontRegistry; + friend class LLTextBillboard; + friend class LLHUDText; - LLFontGL(const LLFontGL &source); - LLFontGL &operator=(const LLFontGL &source); + LLFontGL(const LLFontGL &source); + LLFontGL &operator=(const LLFontGL &source); - LLFontDescriptor mFontDescriptor; - LLPointer<LLFontFreetype> mFontFreetype; + LLFontDescriptor mFontDescriptor; + LLPointer<LLFontFreetype> mFontFreetype; - void renderQuad(LLVector3* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, F32 slant_amt) const; - void drawGlyph(S32& glyph_count, LLVector3* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, U8 style, ShadowType shadow, F32 drop_shadow_fade) const; + void renderQuad(LLVector3* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, F32 slant_amt) const; + void drawGlyph(S32& glyph_count, LLVector3* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, U8 style, ShadowType shadow, F32 drop_shadow_fade) const; - // Registry holds all instantiated fonts. - static LLFontRegistry* sFontRegistry; + // Registry holds all instantiated fonts. + static LLFontRegistry* sFontRegistry; }; #endif diff --git a/indra/llrender/llfontregistry.cpp b/indra/llrender/llfontregistry.cpp index d2c7e466e6..546211aac8 100644 --- a/indra/llrender/llfontregistry.cpp +++ b/indra/llrender/llfontregistry.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llfontregistry.cpp * @author Brad Payne * @brief Storage for fonts. @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2008&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$ */ @@ -48,90 +48,90 @@ const std::string MACOSX_FONT_PATH_LIBRARY = "/Library/Fonts/"; const std::string MACOSX_FONT_SUPPLEMENTAL = "Supplemental/"; LLFontDescriptor::char_functor_map_t LLFontDescriptor::mCharFunctors({ - { "is_emoji", LLStringOps::isEmoji } + { "is_emoji", LLStringOps::isEmoji } }); LLFontDescriptor::LLFontDescriptor(): - mStyle(0) + mStyle(0) { } LLFontDescriptor::LLFontDescriptor(const std::string& name, - const std::string& size, - const U8 style, - const font_file_info_vec_t& font_files): - mName(name), - mSize(size), - mStyle(style), - mFontFiles(font_files) + const std::string& size, + const U8 style, + const font_file_info_vec_t& font_files): + mName(name), + mSize(size), + mStyle(style), + mFontFiles(font_files) { } LLFontDescriptor::LLFontDescriptor(const std::string& name, - const std::string& size, - const U8 style, - const font_file_info_vec_t& font_list, - const font_file_info_vec_t& font_collection_files) : - LLFontDescriptor(name, size, style, font_list) + const std::string& size, + const U8 style, + const font_file_info_vec_t& font_list, + const font_file_info_vec_t& font_collection_files) : + LLFontDescriptor(name, size, style, font_list) { - mFontCollectionFiles = font_collection_files; + mFontCollectionFiles = font_collection_files; } LLFontDescriptor::LLFontDescriptor(const std::string& name, - const std::string& size, - const U8 style): - mName(name), - mSize(size), - mStyle(style) + const std::string& size, + const U8 style): + mName(name), + mSize(size), + mStyle(style) { } bool LLFontDescriptor::operator<(const LLFontDescriptor& b) const { - if (mName < b.mName) - return true; - else if (mName > b.mName) - return false; - - if (mStyle < b.mStyle) - return true; - else if (mStyle > b.mStyle) - return false; - - if (mSize < b.mSize) - return true; - else - return false; + if (mName < b.mName) + return true; + else if (mName > b.mName) + return false; + + if (mStyle < b.mStyle) + return true; + else if (mStyle > b.mStyle) + return false; + + if (mSize < b.mSize) + return true; + else + return false; } static const std::string s_template_string("TEMPLATE"); bool LLFontDescriptor::isTemplate() const { - return getSize() == s_template_string; + return getSize() == s_template_string; } // Look for substring match and remove substring if matched. bool removeSubString(std::string& str, const std::string& substr) { - size_t pos = str.find(substr); - if (pos != string::npos) - { - str.erase(pos, substr.size()); - return true; - } - return false; + size_t pos = str.find(substr); + if (pos != string::npos) + { + str.erase(pos, substr.size()); + return true; + } + return false; } // Check for substring match without modifying the source string. bool findSubString(std::string& str, const std::string& substr) { - size_t pos = str.find(substr); - if (pos != string::npos) - { - return true; - } - return false; + size_t pos = str.find(substr); + if (pos != string::npos) + { + return true; + } + return false; } @@ -145,618 +145,618 @@ bool findSubString(std::string& str, const std::string& substr) // - "SansSerifBold" would normalize to { "SansSerifBold", "Medium", BOLD } LLFontDescriptor LLFontDescriptor::normalize() const { - std::string new_name(mName); - std::string new_size(mSize); - U8 new_style(mStyle); - - // Only care about style to extent it can be picked up by font. - new_style &= (LLFontGL::BOLD | LLFontGL::ITALIC); - - // All these transformations are to support old-style font specifications. - if (removeSubString(new_name,"Small")) - new_size = "Small"; - if (removeSubString(new_name,"Big")) - new_size = "Large"; - if (removeSubString(new_name,"Medium")) - new_size = "Medium"; - if (removeSubString(new_name,"Large")) - new_size = "Large"; - if (removeSubString(new_name,"Huge")) - new_size = "Huge"; - - // HACK - Monospace is the only one we don't remove, so - // name "Monospace" doesn't get taken down to "" - // For other fonts, there's no ambiguity between font name and size specifier. - if (new_size != s_template_string && new_size.empty() && findSubString(new_name,"Monospace")) - new_size = "Monospace"; - if (new_size.empty()) - new_size = "Medium"; - - if (removeSubString(new_name,"Bold")) - new_style |= LLFontGL::BOLD; - - if (removeSubString(new_name,"Italic")) - new_style |= LLFontGL::ITALIC; - - return LLFontDescriptor(new_name,new_size,new_style, getFontFiles(), getFontCollectionFiles()); + std::string new_name(mName); + std::string new_size(mSize); + U8 new_style(mStyle); + + // Only care about style to extent it can be picked up by font. + new_style &= (LLFontGL::BOLD | LLFontGL::ITALIC); + + // All these transformations are to support old-style font specifications. + if (removeSubString(new_name,"Small")) + new_size = "Small"; + if (removeSubString(new_name,"Big")) + new_size = "Large"; + if (removeSubString(new_name,"Medium")) + new_size = "Medium"; + if (removeSubString(new_name,"Large")) + new_size = "Large"; + if (removeSubString(new_name,"Huge")) + new_size = "Huge"; + + // HACK - Monospace is the only one we don't remove, so + // name "Monospace" doesn't get taken down to "" + // For other fonts, there's no ambiguity between font name and size specifier. + if (new_size != s_template_string && new_size.empty() && findSubString(new_name,"Monospace")) + new_size = "Monospace"; + if (new_size.empty()) + new_size = "Medium"; + + if (removeSubString(new_name,"Bold")) + new_style |= LLFontGL::BOLD; + + if (removeSubString(new_name,"Italic")) + new_style |= LLFontGL::ITALIC; + + return LLFontDescriptor(new_name,new_size,new_style, getFontFiles(), getFontCollectionFiles()); } void LLFontDescriptor::addFontFile(const std::string& file_name, const std::string& char_functor) { - char_functor_map_t::const_iterator it = mCharFunctors.find(char_functor); - mFontFiles.push_back(LLFontFileInfo(file_name, (mCharFunctors.end() != it) ? it->second : nullptr)); + char_functor_map_t::const_iterator it = mCharFunctors.find(char_functor); + mFontFiles.push_back(LLFontFileInfo(file_name, (mCharFunctors.end() != it) ? it->second : nullptr)); } void LLFontDescriptor::addFontCollectionFile(const std::string& file_name, const std::string& char_functor) { - char_functor_map_t::const_iterator it = mCharFunctors.find(char_functor); - mFontCollectionFiles.push_back(LLFontFileInfo(file_name, (mCharFunctors.end() != it) ? it->second : nullptr)); + char_functor_map_t::const_iterator it = mCharFunctors.find(char_functor); + mFontCollectionFiles.push_back(LLFontFileInfo(file_name, (mCharFunctors.end() != it) ? it->second : nullptr)); } LLFontRegistry::LLFontRegistry(bool create_gl_textures) -: mCreateGLTextures(create_gl_textures) +: mCreateGLTextures(create_gl_textures) { - // This is potentially a slow directory traversal, so we want to - // cache the result. - mUltimateFallbackList = LLWindow::getDynamicFallbackFontList(); + // This is potentially a slow directory traversal, so we want to + // cache the result. + mUltimateFallbackList = LLWindow::getDynamicFallbackFontList(); } LLFontRegistry::~LLFontRegistry() { - clear(); + clear(); } bool LLFontRegistry::parseFontInfo(const std::string& xml_filename) { - bool success = false; // Succeed if we find and read at least one XUI file - const string_vec_t xml_paths = gDirUtilp->findSkinnedFilenames(LLDir::XUI, xml_filename); - if (xml_paths.empty()) - { - // We didn't even find one single XUI file - return false; - } - - for (string_vec_t::const_iterator path_it = xml_paths.begin(); - path_it != xml_paths.end(); - ++path_it) - { - LLXMLNodePtr root; - bool parsed_file = LLXMLNode::parseFile(*path_it, root, NULL); - - if (!parsed_file) - continue; - - if ( root.isNull() || ! root->hasName( "fonts" ) ) - { - LL_WARNS() << "Bad font info file: " << *path_it << LL_ENDL; - continue; - } - - std::string root_name; - root->getAttributeString("name",root_name); - if (root->hasName("fonts")) - { - // Expect a collection of children consisting of "font" or "font_size" entries - bool init_succ = init_from_xml(this, root); - success = success || init_succ; - } - } - - //if (success) - // dump(); - - return success; + bool success = false; // Succeed if we find and read at least one XUI file + const string_vec_t xml_paths = gDirUtilp->findSkinnedFilenames(LLDir::XUI, xml_filename); + if (xml_paths.empty()) + { + // We didn't even find one single XUI file + return false; + } + + for (string_vec_t::const_iterator path_it = xml_paths.begin(); + path_it != xml_paths.end(); + ++path_it) + { + LLXMLNodePtr root; + bool parsed_file = LLXMLNode::parseFile(*path_it, root, NULL); + + if (!parsed_file) + continue; + + if ( root.isNull() || ! root->hasName( "fonts" ) ) + { + LL_WARNS() << "Bad font info file: " << *path_it << LL_ENDL; + continue; + } + + std::string root_name; + root->getAttributeString("name",root_name); + if (root->hasName("fonts")) + { + // Expect a collection of children consisting of "font" or "font_size" entries + bool init_succ = init_from_xml(this, root); + success = success || init_succ; + } + } + + //if (success) + // dump(); + + return success; } std::string currentOsName() { #if LL_WINDOWS - return "Windows"; + return "Windows"; #elif LL_DARWIN - return "Mac"; + return "Mac"; #elif LL_LINUX - return "Linux"; + return "Linux"; #else - return ""; + return ""; #endif } bool font_desc_init_from_xml(LLXMLNodePtr node, LLFontDescriptor& desc) { - if (node->hasName("font")) - { - std::string attr_name; - if (node->getAttributeString("name",attr_name)) - { - desc.setName(attr_name); - } - - std::string attr_style; - if (node->getAttributeString("font_style",attr_style)) - { - desc.setStyle(LLFontGL::getStyleFromString(attr_style)); - } - - desc.setSize(s_template_string); - } - - LLXMLNodePtr child; - for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) - { - std::string child_name; - child->getAttributeString("name",child_name); - if (child->hasName("file")) - { - std::string font_file_name = child->getTextContents(); - std::string char_functor; - - if (child->hasAttribute("functor")) - { - child->getAttributeString("functor", char_functor); - } - - if (child->hasAttribute("load_collection")) - { - BOOL col = FALSE; - child->getAttributeBOOL("load_collection", col); - if (col) - { - desc.addFontCollectionFile(font_file_name, char_functor); - } - } - - desc.addFontFile(font_file_name, char_functor); - } - else if (child->hasName("os")) - { - if (child_name == currentOsName()) - { - font_desc_init_from_xml(child, desc); - } - } - } - return true; + if (node->hasName("font")) + { + std::string attr_name; + if (node->getAttributeString("name",attr_name)) + { + desc.setName(attr_name); + } + + std::string attr_style; + if (node->getAttributeString("font_style",attr_style)) + { + desc.setStyle(LLFontGL::getStyleFromString(attr_style)); + } + + desc.setSize(s_template_string); + } + + LLXMLNodePtr child; + for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) + { + std::string child_name; + child->getAttributeString("name",child_name); + if (child->hasName("file")) + { + std::string font_file_name = child->getTextContents(); + std::string char_functor; + + if (child->hasAttribute("functor")) + { + child->getAttributeString("functor", char_functor); + } + + if (child->hasAttribute("load_collection")) + { + BOOL col = FALSE; + child->getAttributeBOOL("load_collection", col); + if (col) + { + desc.addFontCollectionFile(font_file_name, char_functor); + } + } + + desc.addFontFile(font_file_name, char_functor); + } + else if (child->hasName("os")) + { + if (child_name == currentOsName()) + { + font_desc_init_from_xml(child, desc); + } + } + } + return true; } bool init_from_xml(LLFontRegistry* registry, LLXMLNodePtr node) { - LLXMLNodePtr child; - - for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) - { - std::string child_name; - child->getAttributeString("name",child_name); - if (child->hasName("font")) - { - LLFontDescriptor desc; - bool font_succ = font_desc_init_from_xml(child, desc); - LLFontDescriptor norm_desc = desc.normalize(); - if (font_succ) - { - // if this is the first time we've seen this font name, - // create a new template map entry for it. - const LLFontDescriptor *match_desc = registry->getMatchingFontDesc(desc); - if (match_desc == NULL) - { - // Create a new entry (with no corresponding font). - registry->mFontMap[norm_desc] = NULL; - } - // otherwise, find the existing entry and combine data. - else - { - // Prepend files from desc. - // A little roundabout because the map key is const, - // so we have to fetch it, make a new map key, and - // replace the old entry. - font_file_info_vec_t font_files = match_desc->getFontFiles(); - font_files.insert(font_files.begin(), - desc.getFontFiles().begin(), - desc.getFontFiles().end()); - - font_file_info_vec_t font_collection_files = match_desc->getFontCollectionFiles(); - font_collection_files.insert(font_collection_files.begin(), - desc.getFontCollectionFiles().begin(), - desc.getFontCollectionFiles().end()); - - LLFontDescriptor new_desc = *match_desc; - new_desc.setFontFiles(font_files); - new_desc.setFontCollectionFiles(font_collection_files); - registry->mFontMap.erase(*match_desc); - registry->mFontMap[new_desc] = NULL; - } - } - } - else if (child->hasName("font_size")) - { - std::string size_name; - F32 size_value; - if (child->getAttributeString("name",size_name) && - child->getAttributeF32("size",size_value)) - { - registry->mFontSizes[size_name] = size_value; - } - - } - } - return true; + LLXMLNodePtr child; + + for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) + { + std::string child_name; + child->getAttributeString("name",child_name); + if (child->hasName("font")) + { + LLFontDescriptor desc; + bool font_succ = font_desc_init_from_xml(child, desc); + LLFontDescriptor norm_desc = desc.normalize(); + if (font_succ) + { + // if this is the first time we've seen this font name, + // create a new template map entry for it. + const LLFontDescriptor *match_desc = registry->getMatchingFontDesc(desc); + if (match_desc == NULL) + { + // Create a new entry (with no corresponding font). + registry->mFontMap[norm_desc] = NULL; + } + // otherwise, find the existing entry and combine data. + else + { + // Prepend files from desc. + // A little roundabout because the map key is const, + // so we have to fetch it, make a new map key, and + // replace the old entry. + font_file_info_vec_t font_files = match_desc->getFontFiles(); + font_files.insert(font_files.begin(), + desc.getFontFiles().begin(), + desc.getFontFiles().end()); + + font_file_info_vec_t font_collection_files = match_desc->getFontCollectionFiles(); + font_collection_files.insert(font_collection_files.begin(), + desc.getFontCollectionFiles().begin(), + desc.getFontCollectionFiles().end()); + + LLFontDescriptor new_desc = *match_desc; + new_desc.setFontFiles(font_files); + new_desc.setFontCollectionFiles(font_collection_files); + registry->mFontMap.erase(*match_desc); + registry->mFontMap[new_desc] = NULL; + } + } + } + else if (child->hasName("font_size")) + { + std::string size_name; + F32 size_value; + if (child->getAttributeString("name",size_name) && + child->getAttributeF32("size",size_value)) + { + registry->mFontSizes[size_name] = size_value; + } + + } + } + return true; } bool LLFontRegistry::nameToSize(const std::string& size_name, F32& size) { - font_size_map_t::iterator it = mFontSizes.find(size_name); - if (it != mFontSizes.end()) - { - size = it->second; - return true; - } - return false; + font_size_map_t::iterator it = mFontSizes.find(size_name); + if (it != mFontSizes.end()) + { + size = it->second; + return true; + } + return false; } LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc) { - // Name should hold a font name recognized as a setting; the value - // of the setting should be a list of font files. - // Size should be a recognized string value - // Style should be a set of flags including any implied by the font name. - - // First decipher the requested size. - LLFontDescriptor norm_desc = desc.normalize(); - F32 point_size; - bool found_size = nameToSize(norm_desc.getSize(),point_size); - if (!found_size) - { - LL_WARNS() << "createFont unrecognized size " << norm_desc.getSize() << LL_ENDL; - return NULL; - } - LL_INFOS() << "createFont " << norm_desc.getName() << " size " << norm_desc.getSize() << " style " << ((S32) norm_desc.getStyle()) << LL_ENDL; - F32 fallback_scale = 1.0; - - // Find corresponding font template (based on same descriptor with no size specified) - LLFontDescriptor template_desc(norm_desc); - template_desc.setSize(s_template_string); - const LLFontDescriptor *match_desc = getClosestFontTemplate(template_desc); - if (!match_desc) - { - LL_WARNS() << "createFont failed, no template found for " - << norm_desc.getName() << " style [" << ((S32)norm_desc.getStyle()) << "]" << LL_ENDL; - return NULL; - } - - // See whether this best-match font has already been instantiated in the requested size. - LLFontDescriptor nearest_exact_desc = *match_desc; - nearest_exact_desc.setSize(norm_desc.getSize()); - font_reg_map_t::iterator it = mFontMap.find(nearest_exact_desc); - // If we fail to find a font in the fonts directory, it->second might be NULL. - // We shouldn't construcnt a font with a NULL mFontFreetype. - // This may not be the best solution, but it at least prevents a crash. - if (it != mFontMap.end() && it->second != NULL) - { - LL_INFOS() << "-- matching font exists: " << nearest_exact_desc.getName() << " size " << nearest_exact_desc.getSize() << " style " << ((S32) nearest_exact_desc.getStyle()) << LL_ENDL; - - // copying underlying Freetype font, and storing in LLFontGL with requested font descriptor - LLFontGL *font = new LLFontGL; - font->mFontDescriptor = desc; - font->mFontFreetype = it->second->mFontFreetype; - mFontMap[desc] = font; - - return font; - } - - // Build list of font names to look for. - // Files specified for this font come first, followed by those from the default descriptor. - font_file_info_vec_t font_files = match_desc->getFontFiles(); - font_file_info_vec_t font_collection_files = match_desc->getFontCollectionFiles(); - LLFontDescriptor default_desc("default",s_template_string,0); - const LLFontDescriptor *match_default_desc = getMatchingFontDesc(default_desc); - if (match_default_desc) - { - font_files.insert(font_files.end(), - match_default_desc->getFontFiles().begin(), - match_default_desc->getFontFiles().end()); - font_collection_files.insert(font_collection_files.end(), - match_default_desc->getFontCollectionFiles().begin(), - match_default_desc->getFontCollectionFiles().end()); - } - - // Add ultimate fallback list - generated dynamically on linux, - // null elsewhere. - std::transform(getUltimateFallbackList().begin(), getUltimateFallbackList().end(), std::back_inserter(font_files), - [](const std::string& file_name) { return LLFontFileInfo(file_name); }); - - // Load fonts based on names. - if (font_files.empty()) - { - LL_WARNS() << "createFont failed, no file names specified" << LL_ENDL; - return NULL; - } - - LLFontGL *result = NULL; - - // The first font will get pulled will be the "head" font, set to non-fallback. - // Rest will consitute the fallback list. - BOOL is_first_found = TRUE; - - string_vec_t font_search_paths; - font_search_paths.push_back(LLFontGL::getFontPathLocal()); - font_search_paths.push_back(LLFontGL::getFontPathSystem()); + // Name should hold a font name recognized as a setting; the value + // of the setting should be a list of font files. + // Size should be a recognized string value + // Style should be a set of flags including any implied by the font name. + + // First decipher the requested size. + LLFontDescriptor norm_desc = desc.normalize(); + F32 point_size; + bool found_size = nameToSize(norm_desc.getSize(),point_size); + if (!found_size) + { + LL_WARNS() << "createFont unrecognized size " << norm_desc.getSize() << LL_ENDL; + return NULL; + } + LL_INFOS() << "createFont " << norm_desc.getName() << " size " << norm_desc.getSize() << " style " << ((S32) norm_desc.getStyle()) << LL_ENDL; + F32 fallback_scale = 1.0; + + // Find corresponding font template (based on same descriptor with no size specified) + LLFontDescriptor template_desc(norm_desc); + template_desc.setSize(s_template_string); + const LLFontDescriptor *match_desc = getClosestFontTemplate(template_desc); + if (!match_desc) + { + LL_WARNS() << "createFont failed, no template found for " + << norm_desc.getName() << " style [" << ((S32)norm_desc.getStyle()) << "]" << LL_ENDL; + return NULL; + } + + // See whether this best-match font has already been instantiated in the requested size. + LLFontDescriptor nearest_exact_desc = *match_desc; + nearest_exact_desc.setSize(norm_desc.getSize()); + font_reg_map_t::iterator it = mFontMap.find(nearest_exact_desc); + // If we fail to find a font in the fonts directory, it->second might be NULL. + // We shouldn't construcnt a font with a NULL mFontFreetype. + // This may not be the best solution, but it at least prevents a crash. + if (it != mFontMap.end() && it->second != NULL) + { + LL_INFOS() << "-- matching font exists: " << nearest_exact_desc.getName() << " size " << nearest_exact_desc.getSize() << " style " << ((S32) nearest_exact_desc.getStyle()) << LL_ENDL; + + // copying underlying Freetype font, and storing in LLFontGL with requested font descriptor + LLFontGL *font = new LLFontGL; + font->mFontDescriptor = desc; + font->mFontFreetype = it->second->mFontFreetype; + mFontMap[desc] = font; + + return font; + } + + // Build list of font names to look for. + // Files specified for this font come first, followed by those from the default descriptor. + font_file_info_vec_t font_files = match_desc->getFontFiles(); + font_file_info_vec_t font_collection_files = match_desc->getFontCollectionFiles(); + LLFontDescriptor default_desc("default",s_template_string,0); + const LLFontDescriptor *match_default_desc = getMatchingFontDesc(default_desc); + if (match_default_desc) + { + font_files.insert(font_files.end(), + match_default_desc->getFontFiles().begin(), + match_default_desc->getFontFiles().end()); + font_collection_files.insert(font_collection_files.end(), + match_default_desc->getFontCollectionFiles().begin(), + match_default_desc->getFontCollectionFiles().end()); + } + + // Add ultimate fallback list - generated dynamically on linux, + // null elsewhere. + std::transform(getUltimateFallbackList().begin(), getUltimateFallbackList().end(), std::back_inserter(font_files), + [](const std::string& file_name) { return LLFontFileInfo(file_name); }); + + // Load fonts based on names. + if (font_files.empty()) + { + LL_WARNS() << "createFont failed, no file names specified" << LL_ENDL; + return NULL; + } + + LLFontGL *result = NULL; + + // The first font will get pulled will be the "head" font, set to non-fallback. + // Rest will consitute the fallback list. + BOOL is_first_found = TRUE; + + string_vec_t font_search_paths; + font_search_paths.push_back(LLFontGL::getFontPathLocal()); + font_search_paths.push_back(LLFontGL::getFontPathSystem()); #if LL_DARWIN - font_search_paths.push_back(MACOSX_FONT_PATH_LIBRARY); - font_search_paths.push_back(MACOSX_FONT_PATH_LIBRARY + MACOSX_FONT_SUPPLEMENTAL); - font_search_paths.push_back(LLFontGL::getFontPathSystem() + MACOSX_FONT_SUPPLEMENTAL); + font_search_paths.push_back(MACOSX_FONT_PATH_LIBRARY); + font_search_paths.push_back(MACOSX_FONT_PATH_LIBRARY + MACOSX_FONT_SUPPLEMENTAL); + font_search_paths.push_back(LLFontGL::getFontPathSystem() + MACOSX_FONT_SUPPLEMENTAL); #endif - // The fontname string may contain multiple font file names separated by semicolons. - // Break it apart and try loading each one, in order. - for(font_file_info_vec_t::iterator font_file_it = font_files.begin(); - font_file_it != font_files.end(); - ++font_file_it) - { - LLFontGL *fontp = NULL; - - bool is_ft_collection = (std::find_if(font_collection_files.begin(), font_collection_files.end(), - [&font_file_it](const LLFontFileInfo& ffi) { return font_file_it->FileName == ffi.FileName; }) != font_collection_files.end()); - - // *HACK: Fallback fonts don't render, so we can use that to suppress - // creation of OpenGL textures for test apps. JC - BOOL is_fallback = !is_first_found || !mCreateGLTextures; - F32 extra_scale = (is_fallback)?fallback_scale:1.0; - F32 point_size_scale = extra_scale * point_size; - bool is_font_loaded = false; - for(string_vec_t::iterator font_search_path_it = font_search_paths.begin(); - font_search_path_it != font_search_paths.end(); - ++font_search_path_it) - { - const std::string font_path = *font_search_path_it + font_file_it->FileName; - - fontp = new LLFontGL; - S32 num_faces = is_ft_collection ? fontp->getNumFaces(font_path) : 1; - for (S32 i = 0; i < num_faces; i++) - { - if (fontp == NULL) - { - fontp = new LLFontGL; - } - if (fontp->loadFace(font_path, point_size_scale, - LLFontGL::sVertDPI, LLFontGL::sHorizDPI, is_fallback, i)) - { - is_font_loaded = true; - if (is_first_found) - { - result = fontp; - is_first_found = false; - } - else - { - result->mFontFreetype->addFallbackFont(fontp->mFontFreetype, font_file_it->CharFunctor); - - delete fontp; - fontp = NULL; - } - } - else - { - delete fontp; - fontp = NULL; - } - } - if (is_font_loaded) break; - } - if(!is_font_loaded) - { - LL_INFOS_ONCE("LLFontRegistry") << "Couldn't load font " << font_file_it->FileName << LL_ENDL; - delete fontp; - fontp = NULL; - } - } - - if (result) - { - result->mFontDescriptor = desc; - } - else - { - LL_WARNS() << "createFont failed in some way" << LL_ENDL; - } - - mFontMap[desc] = result; - return result; + // The fontname string may contain multiple font file names separated by semicolons. + // Break it apart and try loading each one, in order. + for(font_file_info_vec_t::iterator font_file_it = font_files.begin(); + font_file_it != font_files.end(); + ++font_file_it) + { + LLFontGL *fontp = NULL; + + bool is_ft_collection = (std::find_if(font_collection_files.begin(), font_collection_files.end(), + [&font_file_it](const LLFontFileInfo& ffi) { return font_file_it->FileName == ffi.FileName; }) != font_collection_files.end()); + + // *HACK: Fallback fonts don't render, so we can use that to suppress + // creation of OpenGL textures for test apps. JC + BOOL is_fallback = !is_first_found || !mCreateGLTextures; + F32 extra_scale = (is_fallback)?fallback_scale:1.0; + F32 point_size_scale = extra_scale * point_size; + bool is_font_loaded = false; + for(string_vec_t::iterator font_search_path_it = font_search_paths.begin(); + font_search_path_it != font_search_paths.end(); + ++font_search_path_it) + { + const std::string font_path = *font_search_path_it + font_file_it->FileName; + + fontp = new LLFontGL; + S32 num_faces = is_ft_collection ? fontp->getNumFaces(font_path) : 1; + for (S32 i = 0; i < num_faces; i++) + { + if (fontp == NULL) + { + fontp = new LLFontGL; + } + if (fontp->loadFace(font_path, point_size_scale, + LLFontGL::sVertDPI, LLFontGL::sHorizDPI, is_fallback, i)) + { + is_font_loaded = true; + if (is_first_found) + { + result = fontp; + is_first_found = false; + } + else + { + result->mFontFreetype->addFallbackFont(fontp->mFontFreetype, font_file_it->CharFunctor); + + delete fontp; + fontp = NULL; + } + } + else + { + delete fontp; + fontp = NULL; + } + } + if (is_font_loaded) break; + } + if(!is_font_loaded) + { + LL_INFOS_ONCE("LLFontRegistry") << "Couldn't load font " << font_file_it->FileName << LL_ENDL; + delete fontp; + fontp = NULL; + } + } + + if (result) + { + result->mFontDescriptor = desc; + } + else + { + LL_WARNS() << "createFont failed in some way" << LL_ENDL; + } + + mFontMap[desc] = result; + return result; } void LLFontRegistry::reset() { - for (font_reg_map_t::iterator it = mFontMap.begin(); - it != mFontMap.end(); - ++it) - { - // Reset the corresponding font but preserve the entry. - if (it->second) - it->second->reset(); - } + for (font_reg_map_t::iterator it = mFontMap.begin(); + it != mFontMap.end(); + ++it) + { + // Reset the corresponding font but preserve the entry. + if (it->second) + it->second->reset(); + } } void LLFontRegistry::clear() { - for (font_reg_map_t::iterator it = mFontMap.begin(); - it != mFontMap.end(); - ++it) - { - LLFontGL *fontp = it->second; - delete fontp; - } - mFontMap.clear(); + for (font_reg_map_t::iterator it = mFontMap.begin(); + it != mFontMap.end(); + ++it) + { + LLFontGL *fontp = it->second; + delete fontp; + } + mFontMap.clear(); } void LLFontRegistry::destroyGL() { - for (font_reg_map_t::iterator it = mFontMap.begin(); - it != mFontMap.end(); - ++it) - { - // Reset the corresponding font but preserve the entry. - if (it->second) - it->second->destroyGL(); - } + for (font_reg_map_t::iterator it = mFontMap.begin(); + it != mFontMap.end(); + ++it) + { + // Reset the corresponding font but preserve the entry. + if (it->second) + it->second->destroyGL(); + } } LLFontGL *LLFontRegistry::getFont(const LLFontDescriptor& desc) { - font_reg_map_t::iterator it = mFontMap.find(desc); - if (it != mFontMap.end()) - return it->second; - else - { - LLFontGL *fontp = createFont(desc); - if (!fontp) - { - LL_WARNS() << "getFont failed, name " << desc.getName() - <<" style=[" << ((S32) desc.getStyle()) << "]" - << " size=[" << desc.getSize() << "]" << LL_ENDL; - } - else - { - //generate glyphs for ASCII chars to avoid stalls later - fontp->generateASCIIglyphs(); - } - return fontp; - } + font_reg_map_t::iterator it = mFontMap.find(desc); + if (it != mFontMap.end()) + return it->second; + else + { + LLFontGL *fontp = createFont(desc); + if (!fontp) + { + LL_WARNS() << "getFont failed, name " << desc.getName() + <<" style=[" << ((S32) desc.getStyle()) << "]" + << " size=[" << desc.getSize() << "]" << LL_ENDL; + } + else + { + //generate glyphs for ASCII chars to avoid stalls later + fontp->generateASCIIglyphs(); + } + return fontp; + } } const LLFontDescriptor *LLFontRegistry::getMatchingFontDesc(const LLFontDescriptor& desc) { - LLFontDescriptor norm_desc = desc.normalize(); + LLFontDescriptor norm_desc = desc.normalize(); - font_reg_map_t::iterator it = mFontMap.find(norm_desc); - if (it != mFontMap.end()) - return &(it->first); - else - return NULL; + font_reg_map_t::iterator it = mFontMap.find(norm_desc); + if (it != mFontMap.end()) + return &(it->first); + else + return NULL; } static U32 bitCount(U8 c) { - U32 count = 0; - if (c & 1) - count++; - if (c & 2) - count++; - if (c & 4) - count++; - if (c & 8) - count++; - if (c & 16) - count++; - if (c & 32) - count++; - if (c & 64) - count++; - if (c & 128) - count++; - return count; + U32 count = 0; + if (c & 1) + count++; + if (c & 2) + count++; + if (c & 4) + count++; + if (c & 8) + count++; + if (c & 16) + count++; + if (c & 32) + count++; + if (c & 64) + count++; + if (c & 128) + count++; + return count; } // Find nearest match for the requested descriptor. const LLFontDescriptor *LLFontRegistry::getClosestFontTemplate(const LLFontDescriptor& desc) { - const LLFontDescriptor *exact_match_desc = getMatchingFontDesc(desc); - if (exact_match_desc) - { - return exact_match_desc; - } - - LLFontDescriptor norm_desc = desc.normalize(); - - const LLFontDescriptor *best_match_desc = NULL; - for (font_reg_map_t::iterator it = mFontMap.begin(); - it != mFontMap.end(); - ++it) - { - const LLFontDescriptor* curr_desc = &(it->first); - - // Ignore if not a template. - if (!curr_desc->isTemplate()) - continue; - - // Ignore if font name is wrong. - if (curr_desc->getName() != norm_desc.getName()) - continue; - - // Reject font if it matches any bits we don't want - if (curr_desc->getStyle() & ~norm_desc.getStyle()) - { - continue; - } - - // Take if it's the first plausible candidate we've found. - if (!best_match_desc) - { - best_match_desc = curr_desc; - continue; - } - - // Take if it matches more bits than anything before. - U8 best_style_match_bits = - norm_desc.getStyle() & best_match_desc->getStyle(); - U8 curr_style_match_bits = - norm_desc.getStyle() & curr_desc->getStyle(); - if (bitCount(curr_style_match_bits) > bitCount(best_style_match_bits)) - { - best_match_desc = curr_desc; - continue; - } - - // Tie-breaker: take if it matches bold. - if (curr_style_match_bits & LLFontGL::BOLD) // Bold is requested and this descriptor matches it. - { - best_match_desc = curr_desc; - continue; - } - } - - // Nothing matched. - return best_match_desc; + const LLFontDescriptor *exact_match_desc = getMatchingFontDesc(desc); + if (exact_match_desc) + { + return exact_match_desc; + } + + LLFontDescriptor norm_desc = desc.normalize(); + + const LLFontDescriptor *best_match_desc = NULL; + for (font_reg_map_t::iterator it = mFontMap.begin(); + it != mFontMap.end(); + ++it) + { + const LLFontDescriptor* curr_desc = &(it->first); + + // Ignore if not a template. + if (!curr_desc->isTemplate()) + continue; + + // Ignore if font name is wrong. + if (curr_desc->getName() != norm_desc.getName()) + continue; + + // Reject font if it matches any bits we don't want + if (curr_desc->getStyle() & ~norm_desc.getStyle()) + { + continue; + } + + // Take if it's the first plausible candidate we've found. + if (!best_match_desc) + { + best_match_desc = curr_desc; + continue; + } + + // Take if it matches more bits than anything before. + U8 best_style_match_bits = + norm_desc.getStyle() & best_match_desc->getStyle(); + U8 curr_style_match_bits = + norm_desc.getStyle() & curr_desc->getStyle(); + if (bitCount(curr_style_match_bits) > bitCount(best_style_match_bits)) + { + best_match_desc = curr_desc; + continue; + } + + // Tie-breaker: take if it matches bold. + if (curr_style_match_bits & LLFontGL::BOLD) // Bold is requested and this descriptor matches it. + { + best_match_desc = curr_desc; + continue; + } + } + + // Nothing matched. + return best_match_desc; } void LLFontRegistry::dump() { - LL_INFOS() << "LLFontRegistry dump: " << LL_ENDL; - for (font_size_map_t::iterator size_it = mFontSizes.begin(); - size_it != mFontSizes.end(); - ++size_it) - { - LL_INFOS() << "Size: " << size_it->first << " => " << size_it->second << LL_ENDL; - } - for (font_reg_map_t::iterator font_it = mFontMap.begin(); - font_it != mFontMap.end(); - ++font_it) - { - const LLFontDescriptor& desc = font_it->first; - LL_INFOS() << "Font: name=" << desc.getName() - << " style=[" << ((S32)desc.getStyle()) << "]" - << " size=[" << desc.getSize() << "]" - << " fileNames=" - << LL_ENDL; - for (font_file_info_vec_t::const_iterator file_it=desc.getFontFiles().begin(); - file_it != desc.getFontFiles().end(); - ++file_it) - { - LL_INFOS() << " file: " << file_it->FileName << LL_ENDL; - } - } + LL_INFOS() << "LLFontRegistry dump: " << LL_ENDL; + for (font_size_map_t::iterator size_it = mFontSizes.begin(); + size_it != mFontSizes.end(); + ++size_it) + { + LL_INFOS() << "Size: " << size_it->first << " => " << size_it->second << LL_ENDL; + } + for (font_reg_map_t::iterator font_it = mFontMap.begin(); + font_it != mFontMap.end(); + ++font_it) + { + const LLFontDescriptor& desc = font_it->first; + LL_INFOS() << "Font: name=" << desc.getName() + << " style=[" << ((S32)desc.getStyle()) << "]" + << " size=[" << desc.getSize() << "]" + << " fileNames=" + << LL_ENDL; + for (font_file_info_vec_t::const_iterator file_it=desc.getFontFiles().begin(); + file_it != desc.getFontFiles().end(); + ++file_it) + { + LL_INFOS() << " file: " << file_it->FileName << LL_ENDL; + } + } } void LLFontRegistry::dumpTextures() { - for (const auto& fontEntry : mFontMap) - { - if (fontEntry.second) - { - fontEntry.second->dumpTextures(); - } - } + for (const auto& fontEntry : mFontMap) + { + if (fontEntry.second) + { + fontEntry.second->dumpTextures(); + } + } } -const string_vec_t& LLFontRegistry::getUltimateFallbackList() const -{ - return mUltimateFallbackList; +const string_vec_t& LLFontRegistry::getUltimateFallbackList() const +{ + return mUltimateFallbackList; } diff --git a/indra/llrender/llfontregistry.h b/indra/llrender/llfontregistry.h index b0ef72c5de..8bbf5aa30c 100644 --- a/indra/llrender/llfontregistry.h +++ b/indra/llrender/llfontregistry.h @@ -1,4 +1,4 @@ -/** +/** * @file llfontregistry.h * @author Brad Payne * @brief Storage for fonts. @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2008&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$ */ @@ -36,107 +36,107 @@ typedef std::vector<std::string> string_vec_t; struct LLFontFileInfo { - LLFontFileInfo(const std::string& file_name, const std::function<bool(llwchar)>& char_functor = nullptr) - : FileName(file_name) - , CharFunctor(char_functor) - { - } - - LLFontFileInfo(const LLFontFileInfo& ffi) - : FileName(ffi.FileName) - , CharFunctor(ffi.CharFunctor) - { - } - - std::string FileName; - std::function<bool(llwchar)> CharFunctor; + LLFontFileInfo(const std::string& file_name, const std::function<bool(llwchar)>& char_functor = nullptr) + : FileName(file_name) + , CharFunctor(char_functor) + { + } + + LLFontFileInfo(const LLFontFileInfo& ffi) + : FileName(ffi.FileName) + , CharFunctor(ffi.CharFunctor) + { + } + + std::string FileName; + std::function<bool(llwchar)> CharFunctor; }; typedef std::vector<LLFontFileInfo> font_file_info_vec_t; class LLFontDescriptor { public: - LLFontDescriptor(); - LLFontDescriptor(const std::string& name, const std::string& size, const U8 style); - LLFontDescriptor(const std::string& name, const std::string& size, const U8 style, const font_file_info_vec_t& font_list); - LLFontDescriptor(const std::string& name, const std::string& size, const U8 style, const font_file_info_vec_t& font_list, const font_file_info_vec_t& font_collection_list); - LLFontDescriptor normalize() const; - - bool operator<(const LLFontDescriptor& b) const; - - bool isTemplate() const; - - const std::string& getName() const { return mName; } - void setName(const std::string& name) { mName = name; } - const std::string& getSize() const { return mSize; } - void setSize(const std::string& size) { mSize = size; } - - void addFontFile(const std::string& file_name, const std::string& char_functor = LLStringUtil::null); - const font_file_info_vec_t & getFontFiles() const { return mFontFiles; } - void setFontFiles(const font_file_info_vec_t& font_files) { mFontFiles = font_files; } - void addFontCollectionFile(const std::string& file_name, const std::string& char_functor = LLStringUtil::null); - const font_file_info_vec_t& getFontCollectionFiles() const { return mFontCollectionFiles; } - void setFontCollectionFiles(const font_file_info_vec_t& font_collection_files) { mFontCollectionFiles = font_collection_files; } - - const U8 getStyle() const { return mStyle; } - void setStyle(U8 style) { mStyle = style; } + LLFontDescriptor(); + LLFontDescriptor(const std::string& name, const std::string& size, const U8 style); + LLFontDescriptor(const std::string& name, const std::string& size, const U8 style, const font_file_info_vec_t& font_list); + LLFontDescriptor(const std::string& name, const std::string& size, const U8 style, const font_file_info_vec_t& font_list, const font_file_info_vec_t& font_collection_list); + LLFontDescriptor normalize() const; + + bool operator<(const LLFontDescriptor& b) const; + + bool isTemplate() const; + + const std::string& getName() const { return mName; } + void setName(const std::string& name) { mName = name; } + const std::string& getSize() const { return mSize; } + void setSize(const std::string& size) { mSize = size; } + + void addFontFile(const std::string& file_name, const std::string& char_functor = LLStringUtil::null); + const font_file_info_vec_t & getFontFiles() const { return mFontFiles; } + void setFontFiles(const font_file_info_vec_t& font_files) { mFontFiles = font_files; } + void addFontCollectionFile(const std::string& file_name, const std::string& char_functor = LLStringUtil::null); + const font_file_info_vec_t& getFontCollectionFiles() const { return mFontCollectionFiles; } + void setFontCollectionFiles(const font_file_info_vec_t& font_collection_files) { mFontCollectionFiles = font_collection_files; } + + const U8 getStyle() const { return mStyle; } + void setStyle(U8 style) { mStyle = style; } private: - std::string mName; - std::string mSize; - font_file_info_vec_t mFontFiles; - font_file_info_vec_t mFontCollectionFiles; - U8 mStyle; - - typedef std::map<std::string, std::function<bool(llwchar)>> char_functor_map_t; - static char_functor_map_t mCharFunctors; + std::string mName; + std::string mSize; + font_file_info_vec_t mFontFiles; + font_file_info_vec_t mFontCollectionFiles; + U8 mStyle; + + typedef std::map<std::string, std::function<bool(llwchar)>> char_functor_map_t; + static char_functor_map_t mCharFunctors; }; class LLFontRegistry { public: - friend bool init_from_xml(LLFontRegistry*, LLPointer<class LLXMLNode>); - // create_gl_textures - set to false for test apps with no OpenGL window, - // such as llui_libtest - LLFontRegistry(bool create_gl_textures); - ~LLFontRegistry(); + friend bool init_from_xml(LLFontRegistry*, LLPointer<class LLXMLNode>); + // create_gl_textures - set to false for test apps with no OpenGL window, + // such as llui_libtest + LLFontRegistry(bool create_gl_textures); + ~LLFontRegistry(); + + // Load standard font info from XML file(s). + bool parseFontInfo(const std::string& xml_filename); + + // Clear cached glyphs for all fonts. + void reset(); - // Load standard font info from XML file(s). - bool parseFontInfo(const std::string& xml_filename); + // Destroy all fonts. + void clear(); - // Clear cached glyphs for all fonts. - void reset(); + // GL cleanup + void destroyGL(); - // Destroy all fonts. - void clear(); + LLFontGL *getFont(const LLFontDescriptor& desc); + const LLFontDescriptor *getMatchingFontDesc(const LLFontDescriptor& desc); + const LLFontDescriptor *getClosestFontTemplate(const LLFontDescriptor& desc); - // GL cleanup - void destroyGL(); - - LLFontGL *getFont(const LLFontDescriptor& desc); - const LLFontDescriptor *getMatchingFontDesc(const LLFontDescriptor& desc); - const LLFontDescriptor *getClosestFontTemplate(const LLFontDescriptor& desc); + bool nameToSize(const std::string& size_name, F32& size); - bool nameToSize(const std::string& size_name, F32& size); + void dump(); + void dumpTextures(); - void dump(); - void dumpTextures(); - - const string_vec_t& getUltimateFallbackList() const; + const string_vec_t& getUltimateFallbackList() const; private: - LLFontRegistry(const LLFontRegistry& other); // no-copy - LLFontGL *createFont(const LLFontDescriptor& desc); - typedef std::map<LLFontDescriptor,LLFontGL*> font_reg_map_t; - typedef std::map<std::string,F32> font_size_map_t; - - // Given a descriptor, look up specific font instantiation. - font_reg_map_t mFontMap; - // Given a size name, look up the point size. - font_size_map_t mFontSizes; - - string_vec_t mUltimateFallbackList; - bool mCreateGLTextures; + LLFontRegistry(const LLFontRegistry& other); // no-copy + LLFontGL *createFont(const LLFontDescriptor& desc); + typedef std::map<LLFontDescriptor,LLFontGL*> font_reg_map_t; + typedef std::map<std::string,F32> font_size_map_t; + + // Given a descriptor, look up specific font instantiation. + font_reg_map_t mFontMap; + // Given a size name, look up the point size. + font_size_map_t mFontSizes; + + string_vec_t mUltimateFallbackList; + bool mCreateGLTextures; }; #endif // LL_LLFONTREGISTRY_H diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index a4a56af981..1b5566a3f7 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -1,30 +1,30 @@ -/** +/** * @file llgl.cpp * @brief LLGL implementation * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ -// This file sets some global GL parameters, and implements some +// This file sets some global GL parameters, and implements some // useful functions for GL operations. #define GLH_EXT_SINGLE_FILE @@ -172,37 +172,37 @@ void parse_glsl_version(S32& major, S32& minor); void ll_init_fail_log(std::string filename) { - gFailLog.open(filename.c_str()); + gFailLog.open(filename.c_str()); } void ll_fail(std::string msg) { - - if (gDebugSession) - { - std::vector<std::string> lines; - gFailLog << LLError::utcTime() << " " << msg << std::endl; + if (gDebugSession) + { + std::vector<std::string> lines; - gFailLog << "Stack Trace:" << std::endl; + gFailLog << LLError::utcTime() << " " << msg << std::endl; - ll_get_stack_trace(lines); - - for(size_t i = 0; i < lines.size(); ++i) - { - gFailLog << lines[i] << std::endl; - } + gFailLog << "Stack Trace:" << std::endl; + + ll_get_stack_trace(lines); + + for(size_t i = 0; i < lines.size(); ++i) + { + gFailLog << lines[i] << std::endl; + } - gFailLog << "End of Stack Trace." << std::endl << std::endl; + gFailLog << "End of Stack Trace." << std::endl << std::endl; - gFailLog.flush(); - } + gFailLog.flush(); + } }; void ll_close_fail_log() { - gFailLog.close(); + gFailLog.close(); } LLMatrix4 gGLObliqueProjectionInverse; @@ -983,30 +983,30 @@ PFNGLPOLYGONOFFSETCLAMPPROC glPolygonOffsetClamp = nullptr; LLGLManager gGLManager; LLGLManager::LLGLManager() : - mInited(FALSE), - mIsDisabled(FALSE), - mMaxSamples(0), - mNumTextureImageUnits(1), - mMaxSampleMaskWords(0), - mMaxColorTextureSamples(0), - mMaxDepthTextureSamples(0), - mMaxIntegerSamples(0), - mIsAMD(FALSE), - mIsNVIDIA(FALSE), - mIsIntel(FALSE), + mInited(FALSE), + mIsDisabled(FALSE), + mMaxSamples(0), + mNumTextureImageUnits(1), + mMaxSampleMaskWords(0), + mMaxColorTextureSamples(0), + mMaxDepthTextureSamples(0), + mMaxIntegerSamples(0), + mIsAMD(FALSE), + mIsNVIDIA(FALSE), + mIsIntel(FALSE), #if LL_DARWIN - mIsMobileGF(FALSE), + mIsMobileGF(FALSE), #endif - mHasRequirements(TRUE), - mDriverVersionMajor(1), - mDriverVersionMinor(0), - mDriverVersionRelease(0), - mGLVersion(1.0f), - mGLSLVersionMajor(0), - mGLSLVersionMinor(0), - mVRAM(0), - mGLMaxVertexRange(0), - mGLMaxIndexRange(0) + mHasRequirements(TRUE), + mDriverVersionMajor(1), + mDriverVersionMinor(0), + mDriverVersionRelease(0), + mGLVersion(1.0f), + mGLSLVersionMajor(0), + mGLSLVersionMinor(0), + mVRAM(0), + mGLMaxVertexRange(0), + mGLMaxIndexRange(0) { } @@ -1016,227 +1016,227 @@ LLGLManager::LLGLManager() : void LLGLManager::initWGL() { #if LL_WINDOWS && !LL_MESA_HEADLESS - if (!glh_init_extensions("WGL_ARB_pixel_format")) - { - LL_WARNS("RenderInit") << "No ARB pixel format extensions" << LL_ENDL; - } - - if (ExtensionExists("WGL_ARB_create_context",gGLHExts.mSysExts)) - { - GLH_EXT_NAME(wglCreateContextAttribsARB) = (PFNWGLCREATECONTEXTATTRIBSARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglCreateContextAttribsARB"); - } - else - { - LL_WARNS("RenderInit") << "No ARB create context extensions" << LL_ENDL; - } - - // For retreiving information per AMD adapter, - // because we can't trust curently selected/default one when there are multiple - mHasAMDAssociations = ExtensionExists("WGL_AMD_gpu_association", gGLHExts.mSysExts); - if (mHasAMDAssociations) - { - GLH_EXT_NAME(wglGetGPUIDsAMD) = (PFNWGLGETGPUIDSAMDPROC)GLH_EXT_GET_PROC_ADDRESS("wglGetGPUIDsAMD"); - GLH_EXT_NAME(wglGetGPUInfoAMD) = (PFNWGLGETGPUINFOAMDPROC)GLH_EXT_GET_PROC_ADDRESS("wglGetGPUInfoAMD"); - } - - if (ExtensionExists("WGL_EXT_swap_control", gGLHExts.mSysExts)) - { + if (!glh_init_extensions("WGL_ARB_pixel_format")) + { + LL_WARNS("RenderInit") << "No ARB pixel format extensions" << LL_ENDL; + } + + if (ExtensionExists("WGL_ARB_create_context",gGLHExts.mSysExts)) + { + GLH_EXT_NAME(wglCreateContextAttribsARB) = (PFNWGLCREATECONTEXTATTRIBSARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglCreateContextAttribsARB"); + } + else + { + LL_WARNS("RenderInit") << "No ARB create context extensions" << LL_ENDL; + } + + // For retreiving information per AMD adapter, + // because we can't trust curently selected/default one when there are multiple + mHasAMDAssociations = ExtensionExists("WGL_AMD_gpu_association", gGLHExts.mSysExts); + if (mHasAMDAssociations) + { + GLH_EXT_NAME(wglGetGPUIDsAMD) = (PFNWGLGETGPUIDSAMDPROC)GLH_EXT_GET_PROC_ADDRESS("wglGetGPUIDsAMD"); + GLH_EXT_NAME(wglGetGPUInfoAMD) = (PFNWGLGETGPUINFOAMDPROC)GLH_EXT_GET_PROC_ADDRESS("wglGetGPUInfoAMD"); + } + + if (ExtensionExists("WGL_EXT_swap_control", gGLHExts.mSysExts)) + { GLH_EXT_NAME(wglSwapIntervalEXT) = (PFNWGLSWAPINTERVALEXTPROC)GLH_EXT_GET_PROC_ADDRESS("wglSwapIntervalEXT"); - } + } - if( !glh_init_extensions("WGL_ARB_pbuffer") ) - { - LL_WARNS("RenderInit") << "No ARB WGL PBuffer extensions" << LL_ENDL; - } + if( !glh_init_extensions("WGL_ARB_pbuffer") ) + { + LL_WARNS("RenderInit") << "No ARB WGL PBuffer extensions" << LL_ENDL; + } - if( !glh_init_extensions("WGL_ARB_render_texture") ) - { - LL_WARNS("RenderInit") << "No ARB WGL render texture extensions" << LL_ENDL; - } + if( !glh_init_extensions("WGL_ARB_render_texture") ) + { + LL_WARNS("RenderInit") << "No ARB WGL render texture extensions" << LL_ENDL; + } #endif } // return false if unable (or unwilling due to old drivers) to init GL bool LLGLManager::initGL() { - if (mInited) - { - LL_ERRS("RenderInit") << "Calling init on LLGLManager after already initialized!" << LL_ENDL; - } + if (mInited) + { + LL_ERRS("RenderInit") << "Calling init on LLGLManager after already initialized!" << LL_ENDL; + } #if 0 && LL_WINDOWS - if (!glGetStringi) - { - glGetStringi = (PFNGLGETSTRINGIPROC) GLH_EXT_GET_PROC_ADDRESS("glGetStringi"); - } - - //reload extensions string (may have changed after using wglCreateContextAttrib) - if (glGetStringi) - { - std::stringstream str; - - GLint count = 0; - glGetIntegerv(GL_NUM_EXTENSIONS, &count); - for (GLint i = 0; i < count; ++i) - { - std::string ext = ll_safe_string((const char*) glGetStringi(GL_EXTENSIONS, i)); - str << ext << " "; - LL_DEBUGS("GLExtensions") << ext << LL_ENDL; - } - - { - PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = 0; - wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB"); - if(wglGetExtensionsStringARB) - { - str << (const char*) wglGetExtensionsStringARB(wglGetCurrentDC()); - } - } - - free(gGLHExts.mSysExts); - std::string extensions = str.str(); - gGLHExts.mSysExts = strdup(extensions.c_str()); - } + if (!glGetStringi) + { + glGetStringi = (PFNGLGETSTRINGIPROC) GLH_EXT_GET_PROC_ADDRESS("glGetStringi"); + } + + //reload extensions string (may have changed after using wglCreateContextAttrib) + if (glGetStringi) + { + std::stringstream str; + + GLint count = 0; + glGetIntegerv(GL_NUM_EXTENSIONS, &count); + for (GLint i = 0; i < count; ++i) + { + std::string ext = ll_safe_string((const char*) glGetStringi(GL_EXTENSIONS, i)); + str << ext << " "; + LL_DEBUGS("GLExtensions") << ext << LL_ENDL; + } + + { + PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = 0; + wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB"); + if(wglGetExtensionsStringARB) + { + str << (const char*) wglGetExtensionsStringARB(wglGetCurrentDC()); + } + } + + free(gGLHExts.mSysExts); + std::string extensions = str.str(); + gGLHExts.mSysExts = strdup(extensions.c_str()); + } #endif - - // Extract video card strings and convert to upper case to - // work around driver-to-driver variation in capitalization. - mGLVendor = ll_safe_string((const char *)glGetString(GL_VENDOR)); - LLStringUtil::toUpper(mGLVendor); - mGLRenderer = ll_safe_string((const char *)glGetString(GL_RENDERER)); - LLStringUtil::toUpper(mGLRenderer); + // Extract video card strings and convert to upper case to + // work around driver-to-driver variation in capitalization. + mGLVendor = ll_safe_string((const char *)glGetString(GL_VENDOR)); + LLStringUtil::toUpper(mGLVendor); - parse_gl_version( &mDriverVersionMajor, - &mDriverVersionMinor, - &mDriverVersionRelease, - &mDriverVersionVendorString, - &mGLVersionString); + mGLRenderer = ll_safe_string((const char *)glGetString(GL_RENDERER)); + LLStringUtil::toUpper(mGLRenderer); - mGLVersion = mDriverVersionMajor + mDriverVersionMinor * .1f; + parse_gl_version( &mDriverVersionMajor, + &mDriverVersionMinor, + &mDriverVersionRelease, + &mDriverVersionVendorString, + &mGLVersionString); - if (mGLVersion >= 2.f) - { - parse_glsl_version(mGLSLVersionMajor, mGLSLVersionMinor); + mGLVersion = mDriverVersionMajor + mDriverVersionMinor * .1f; + + if (mGLVersion >= 2.f) + { + parse_glsl_version(mGLSLVersionMajor, mGLSLVersionMinor); #if 0 && LL_DARWIN - // TODO maybe switch to using a core profile for GL 3.2? - // https://stackoverflow.com/a/19868861 - //never use GLSL greater than 1.20 on OSX - if (mGLSLVersionMajor > 1 || mGLSLVersionMinor > 30) - { - mGLSLVersionMajor = 1; - mGLSLVersionMinor = 30; - } + // TODO maybe switch to using a core profile for GL 3.2? + // https://stackoverflow.com/a/19868861 + //never use GLSL greater than 1.20 on OSX + if (mGLSLVersionMajor > 1 || mGLSLVersionMinor > 30) + { + mGLSLVersionMajor = 1; + mGLSLVersionMinor = 30; + } #endif - } - - if (mGLVersion >= 2.1f && LLImageGL::sCompressTextures) - { //use texture compression - glHint(GL_TEXTURE_COMPRESSION_HINT, GL_NICEST); - } - else - { //GL version is < 3.0, always disable texture compression - LLImageGL::sCompressTextures = false; - } - - // Trailing space necessary to keep "nVidia Corpor_ati_on" cards - // from being recognized as ATI. + } + + if (mGLVersion >= 2.1f && LLImageGL::sCompressTextures) + { //use texture compression + glHint(GL_TEXTURE_COMPRESSION_HINT, GL_NICEST); + } + else + { //GL version is < 3.0, always disable texture compression + LLImageGL::sCompressTextures = false; + } + + // Trailing space necessary to keep "nVidia Corpor_ati_on" cards + // from being recognized as ATI. // NOTE: AMD has been pretty good about not breaking this check, do not rename without good reason - if (mGLVendor.substr(0,4) == "ATI ") - { - mGLVendorShort = "AMD"; - // *TODO: Fix this? - mIsAMD = TRUE; - } - else if (mGLVendor.find("NVIDIA ") != std::string::npos) - { - mGLVendorShort = "NVIDIA"; - mIsNVIDIA = TRUE; - } - else if (mGLVendor.find("INTEL") != std::string::npos + if (mGLVendor.substr(0,4) == "ATI ") + { + mGLVendorShort = "AMD"; + // *TODO: Fix this? + mIsAMD = TRUE; + } + else if (mGLVendor.find("NVIDIA ") != std::string::npos) + { + mGLVendorShort = "NVIDIA"; + mIsNVIDIA = TRUE; + } + else if (mGLVendor.find("INTEL") != std::string::npos #if LL_LINUX - // The Mesa-based drivers put this in the Renderer string, - // not the Vendor string. - || mGLRenderer.find("INTEL") != std::string::npos + // The Mesa-based drivers put this in the Renderer string, + // not the Vendor string. + || mGLRenderer.find("INTEL") != std::string::npos #endif //LL_LINUX - ) - { - mGLVendorShort = "INTEL"; - mIsIntel = TRUE; - } - else - { - mGLVendorShort = "MISC"; - } - - // This is called here because it depends on the setting of mIsGF2or4MX, and sets up mHasMultitexture. - initExtensions(); - - S32 old_vram = mVRAM; - mVRAM = 0; + ) + { + mGLVendorShort = "INTEL"; + mIsIntel = TRUE; + } + else + { + mGLVendorShort = "MISC"; + } + + // This is called here because it depends on the setting of mIsGF2or4MX, and sets up mHasMultitexture. + initExtensions(); + + S32 old_vram = mVRAM; + mVRAM = 0; #if LL_WINDOWS - if (mHasAMDAssociations) - { - GLuint gl_gpus_count = wglGetGPUIDsAMD(0, 0); - if (gl_gpus_count > 0) - { - GLuint* ids = new GLuint[gl_gpus_count]; - wglGetGPUIDsAMD(gl_gpus_count, ids); - - GLuint mem_mb = 0; - for (U32 i = 0; i < gl_gpus_count; i++) - { - wglGetGPUInfoAMD(ids[i], - WGL_GPU_RAM_AMD, - GL_UNSIGNED_INT, - sizeof(GLuint), - &mem_mb); - if (mVRAM < mem_mb) - { - // basically pick the best AMD and trust driver/OS to know to switch - mVRAM = mem_mb; - } - } - } - if (mVRAM != 0) - { - LL_WARNS("RenderInit") << "VRAM Detected (AMDAssociations):" << mVRAM << LL_ENDL; - } - } + if (mHasAMDAssociations) + { + GLuint gl_gpus_count = wglGetGPUIDsAMD(0, 0); + if (gl_gpus_count > 0) + { + GLuint* ids = new GLuint[gl_gpus_count]; + wglGetGPUIDsAMD(gl_gpus_count, ids); + + GLuint mem_mb = 0; + for (U32 i = 0; i < gl_gpus_count; i++) + { + wglGetGPUInfoAMD(ids[i], + WGL_GPU_RAM_AMD, + GL_UNSIGNED_INT, + sizeof(GLuint), + &mem_mb); + if (mVRAM < mem_mb) + { + // basically pick the best AMD and trust driver/OS to know to switch + mVRAM = mem_mb; + } + } + } + if (mVRAM != 0) + { + LL_WARNS("RenderInit") << "VRAM Detected (AMDAssociations):" << mVRAM << LL_ENDL; + } + } #endif #if LL_WINDOWS - if (mVRAM < 256) - { - // Something likely went wrong using the above extensions - // try WMI first and fall back to old method (from dxdiag) if all else fails - // Function will check all GPUs WMI knows of and will pick up the one with most - // memory. We need to check all GPUs because system can switch active GPU to - // weaker one, to preserve power when not under load. - S32 mem = LLDXHardware::getMBVideoMemoryViaWMI(); - if (mem != 0) - { - mVRAM = mem; - LL_WARNS("RenderInit") << "VRAM Detected (WMI):" << mVRAM<< LL_ENDL; - } - } + if (mVRAM < 256) + { + // Something likely went wrong using the above extensions + // try WMI first and fall back to old method (from dxdiag) if all else fails + // Function will check all GPUs WMI knows of and will pick up the one with most + // memory. We need to check all GPUs because system can switch active GPU to + // weaker one, to preserve power when not under load. + S32 mem = LLDXHardware::getMBVideoMemoryViaWMI(); + if (mem != 0) + { + mVRAM = mem; + LL_WARNS("RenderInit") << "VRAM Detected (WMI):" << mVRAM<< LL_ENDL; + } + } #endif - if (mVRAM < 256 && old_vram > 0) - { - // fall back to old method - // Note: on Windows value will be from LLDXHardware. - // Either received via dxdiag or via WMI by id from dxdiag. - mVRAM = old_vram; - } - - glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &mNumTextureImageUnits); - glGetIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &mMaxColorTextureSamples); - glGetIntegerv(GL_MAX_DEPTH_TEXTURE_SAMPLES, &mMaxDepthTextureSamples); - glGetIntegerv(GL_MAX_INTEGER_SAMPLES, &mMaxIntegerSamples); - glGetIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &mMaxSampleMaskWords); + if (mVRAM < 256 && old_vram > 0) + { + // fall back to old method + // Note: on Windows value will be from LLDXHardware. + // Either received via dxdiag or via WMI by id from dxdiag. + mVRAM = old_vram; + } + + glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &mNumTextureImageUnits); + glGetIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &mMaxColorTextureSamples); + glGetIntegerv(GL_MAX_DEPTH_TEXTURE_SAMPLES, &mMaxDepthTextureSamples); + glGetIntegerv(GL_MAX_INTEGER_SAMPLES, &mMaxIntegerSamples); + glGetIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &mMaxSampleMaskWords); glGetIntegerv(GL_MAX_SAMPLES, &mMaxSamples); if (mGLVersion >= 4.59f) @@ -1244,136 +1244,136 @@ bool LLGLManager::initGL() glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY, &mMaxAnisotropy); } - initGLStates(); + initGLStates(); - return true; + return true; } void LLGLManager::getGLInfo(LLSD& info) { - if (gHeadlessClient) - { - info["GLInfo"]["GLVendor"] = HEADLESS_VENDOR_STRING; - info["GLInfo"]["GLRenderer"] = HEADLESS_RENDERER_STRING; - info["GLInfo"]["GLVersion"] = HEADLESS_VERSION_STRING; - return; - } - else - { - info["GLInfo"]["GLVendor"] = ll_safe_string((const char *)glGetString(GL_VENDOR)); - info["GLInfo"]["GLRenderer"] = ll_safe_string((const char *)glGetString(GL_RENDERER)); - info["GLInfo"]["GLVersion"] = ll_safe_string((const char *)glGetString(GL_VERSION)); - } + if (gHeadlessClient) + { + info["GLInfo"]["GLVendor"] = HEADLESS_VENDOR_STRING; + info["GLInfo"]["GLRenderer"] = HEADLESS_RENDERER_STRING; + info["GLInfo"]["GLVersion"] = HEADLESS_VERSION_STRING; + return; + } + else + { + info["GLInfo"]["GLVendor"] = ll_safe_string((const char *)glGetString(GL_VENDOR)); + info["GLInfo"]["GLRenderer"] = ll_safe_string((const char *)glGetString(GL_RENDERER)); + info["GLInfo"]["GLVersion"] = ll_safe_string((const char *)glGetString(GL_VERSION)); + } #if !LL_MESA_HEADLESS - std::string all_exts = ll_safe_string((const char *)gGLHExts.mSysExts); - boost::char_separator<char> sep(" "); - boost::tokenizer<boost::char_separator<char> > tok(all_exts, sep); - for(boost::tokenizer<boost::char_separator<char> >::iterator i = tok.begin(); i != tok.end(); ++i) - { - info["GLInfo"]["GLExtensions"].append(*i); - } + std::string all_exts = ll_safe_string((const char *)gGLHExts.mSysExts); + boost::char_separator<char> sep(" "); + boost::tokenizer<boost::char_separator<char> > tok(all_exts, sep); + for(boost::tokenizer<boost::char_separator<char> >::iterator i = tok.begin(); i != tok.end(); ++i) + { + info["GLInfo"]["GLExtensions"].append(*i); + } #endif } std::string LLGLManager::getGLInfoString() { - std::string info_str; - - if (gHeadlessClient) - { - info_str += std::string("GL_VENDOR ") + HEADLESS_VENDOR_STRING + std::string("\n"); - info_str += std::string("GL_RENDERER ") + HEADLESS_RENDERER_STRING + std::string("\n"); - info_str += std::string("GL_VERSION ") + HEADLESS_VERSION_STRING + std::string("\n"); - } - else - { - info_str += std::string("GL_VENDOR ") + ll_safe_string((const char *)glGetString(GL_VENDOR)) + std::string("\n"); - info_str += std::string("GL_RENDERER ") + ll_safe_string((const char *)glGetString(GL_RENDERER)) + std::string("\n"); - info_str += std::string("GL_VERSION ") + ll_safe_string((const char *)glGetString(GL_VERSION)) + std::string("\n"); - } - -#if !LL_MESA_HEADLESS - std::string all_exts= ll_safe_string(((const char *)gGLHExts.mSysExts)); - LLStringUtil::replaceChar(all_exts, ' ', '\n'); - info_str += std::string("GL_EXTENSIONS:\n") + all_exts + std::string("\n"); + std::string info_str; + + if (gHeadlessClient) + { + info_str += std::string("GL_VENDOR ") + HEADLESS_VENDOR_STRING + std::string("\n"); + info_str += std::string("GL_RENDERER ") + HEADLESS_RENDERER_STRING + std::string("\n"); + info_str += std::string("GL_VERSION ") + HEADLESS_VERSION_STRING + std::string("\n"); + } + else + { + info_str += std::string("GL_VENDOR ") + ll_safe_string((const char *)glGetString(GL_VENDOR)) + std::string("\n"); + info_str += std::string("GL_RENDERER ") + ll_safe_string((const char *)glGetString(GL_RENDERER)) + std::string("\n"); + info_str += std::string("GL_VERSION ") + ll_safe_string((const char *)glGetString(GL_VERSION)) + std::string("\n"); + } + +#if !LL_MESA_HEADLESS + std::string all_exts= ll_safe_string(((const char *)gGLHExts.mSysExts)); + LLStringUtil::replaceChar(all_exts, ' ', '\n'); + info_str += std::string("GL_EXTENSIONS:\n") + all_exts + std::string("\n"); #endif - - return info_str; + + return info_str; } void LLGLManager::printGLInfoString() { - if (gHeadlessClient) - { - LL_INFOS("RenderInit") << "GL_VENDOR: " << HEADLESS_VENDOR_STRING << LL_ENDL; - LL_INFOS("RenderInit") << "GL_RENDERER: " << HEADLESS_RENDERER_STRING << LL_ENDL; - LL_INFOS("RenderInit") << "GL_VERSION: " << HEADLESS_VERSION_STRING << LL_ENDL; - } - else - { - LL_INFOS("RenderInit") << "GL_VENDOR: " << ll_safe_string((const char *)glGetString(GL_VENDOR)) << LL_ENDL; - LL_INFOS("RenderInit") << "GL_RENDERER: " << ll_safe_string((const char *)glGetString(GL_RENDERER)) << LL_ENDL; - LL_INFOS("RenderInit") << "GL_VERSION: " << ll_safe_string((const char *)glGetString(GL_VERSION)) << LL_ENDL; - } + if (gHeadlessClient) + { + LL_INFOS("RenderInit") << "GL_VENDOR: " << HEADLESS_VENDOR_STRING << LL_ENDL; + LL_INFOS("RenderInit") << "GL_RENDERER: " << HEADLESS_RENDERER_STRING << LL_ENDL; + LL_INFOS("RenderInit") << "GL_VERSION: " << HEADLESS_VERSION_STRING << LL_ENDL; + } + else + { + LL_INFOS("RenderInit") << "GL_VENDOR: " << ll_safe_string((const char *)glGetString(GL_VENDOR)) << LL_ENDL; + LL_INFOS("RenderInit") << "GL_RENDERER: " << ll_safe_string((const char *)glGetString(GL_RENDERER)) << LL_ENDL; + LL_INFOS("RenderInit") << "GL_VERSION: " << ll_safe_string((const char *)glGetString(GL_VERSION)) << LL_ENDL; + } #if !LL_MESA_HEADLESS - std::string all_exts= ll_safe_string(((const char *)gGLHExts.mSysExts)); - LLStringUtil::replaceChar(all_exts, ' ', '\n'); - LL_DEBUGS("RenderInit") << "GL_EXTENSIONS:\n" << all_exts << LL_ENDL; + std::string all_exts= ll_safe_string(((const char *)gGLHExts.mSysExts)); + LLStringUtil::replaceChar(all_exts, ' ', '\n'); + LL_DEBUGS("RenderInit") << "GL_EXTENSIONS:\n" << all_exts << LL_ENDL; #endif } std::string LLGLManager::getRawGLString() { - std::string gl_string; - if (gHeadlessClient) - { - gl_string = HEADLESS_VENDOR_STRING + " " + HEADLESS_RENDERER_STRING; - } - else - { - gl_string = ll_safe_string((char*)glGetString(GL_VENDOR)) + " " + ll_safe_string((char*)glGetString(GL_RENDERER)); - } - return gl_string; + std::string gl_string; + if (gHeadlessClient) + { + gl_string = HEADLESS_VENDOR_STRING + " " + HEADLESS_RENDERER_STRING; + } + else + { + gl_string = ll_safe_string((char*)glGetString(GL_VENDOR)) + " " + ll_safe_string((char*)glGetString(GL_RENDERER)); + } + return gl_string; } void LLGLManager::asLLSD(LLSD& info) { - // Currently these are duplicates of fields in "system". - info["gpu_vendor"] = mGLVendorShort; - info["gpu_version"] = mDriverVersionVendorString; - info["opengl_version"] = mGLVersionString; - - info["vram"] = mVRAM; - - // OpenGL limits - info["max_samples"] = mMaxSamples; - info["num_texture_image_units"] = mNumTextureImageUnits; - info["max_sample_mask_words"] = mMaxSampleMaskWords; - info["max_color_texture_samples"] = mMaxColorTextureSamples; - info["max_depth_texture_samples"] = mMaxDepthTextureSamples; - info["max_integer_samples"] = mMaxIntegerSamples; + // Currently these are duplicates of fields in "system". + info["gpu_vendor"] = mGLVendorShort; + info["gpu_version"] = mDriverVersionVendorString; + info["opengl_version"] = mGLVersionString; + + info["vram"] = mVRAM; + + // OpenGL limits + info["max_samples"] = mMaxSamples; + info["num_texture_image_units"] = mNumTextureImageUnits; + info["max_sample_mask_words"] = mMaxSampleMaskWords; + info["max_color_texture_samples"] = mMaxColorTextureSamples; + info["max_depth_texture_samples"] = mMaxDepthTextureSamples; + info["max_integer_samples"] = mMaxIntegerSamples; info["max_vertex_range"] = mGLMaxVertexRange; info["max_index_range"] = mGLMaxIndexRange; info["max_texture_size"] = mGLMaxTextureSize; - // Which vendor - info["is_ati"] = mIsAMD; // note, do not rename is_ati to is_amd without coordinating with DW - info["is_nvidia"] = mIsNVIDIA; - info["is_intel"] = mIsIntel; + // Which vendor + info["is_ati"] = mIsAMD; // note, do not rename is_ati to is_amd without coordinating with DW + info["is_nvidia"] = mIsNVIDIA; + info["is_intel"] = mIsIntel; - info["gl_renderer"] = mGLRenderer; + info["gl_renderer"] = mGLRenderer; } void LLGLManager::shutdownGL() { - if (mInited) - { - glFinish(); - stop_glerror(); - mInited = FALSE; - } + if (mInited) + { + glFinish(); + stop_glerror(); + mInited = FALSE; + } } // these are used to turn software blending on. They appear in the Debug/Avatar menu @@ -1398,22 +1398,22 @@ void LLGLManager::initExtensions() #endif // NOTE: version checks against mGLVersion should bias down by 0.01 because of F32 errors - + // OpenGL 4.x capabilities - mHasCubeMapArray = mGLVersion >= 3.99f; + mHasCubeMapArray = mGLVersion >= 3.99f; mHasTransformFeedback = mGLVersion >= 3.99f; mHasDebugOutput = mGLVersion >= 4.29f; // Misc - glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, (GLint*) &mGLMaxVertexRange); - glGetIntegerv(GL_MAX_ELEMENTS_INDICES, (GLint*) &mGLMaxIndexRange); - glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint*) &mGLMaxTextureSize); + glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, (GLint*) &mGLMaxVertexRange); + glGetIntegerv(GL_MAX_ELEMENTS_INDICES, (GLint*) &mGLMaxIndexRange); + glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint*) &mGLMaxTextureSize); mInited = TRUE; #if (LL_WINDOWS || LL_LINUX) && !LL_MESA_HEADLESS - LL_DEBUGS("RenderInit") << "GL Probe: Getting symbols" << LL_ENDL; - + LL_DEBUGS("RenderInit") << "GL Probe: Getting symbols" << LL_ENDL; + #if LL_WINDOWS // WGL_AMD_gpu_association wglGetGPUIDsAMD = (PFNWGLGETGPUIDSAMDPROC)GLH_EXT_GET_PROC_ADDRESS("wglGetGPUIDsAMD"); @@ -2249,123 +2249,123 @@ void LLGLManager::initExtensions() glMultiDrawArraysIndirectCount = (PFNGLMULTIDRAWARRAYSINDIRECTCOUNTPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiDrawArraysIndirectCount"); glMultiDrawElementsIndirectCount = (PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiDrawElementsIndirectCount"); glPolygonOffsetClamp = (PFNGLPOLYGONOFFSETCLAMPPROC)GLH_EXT_GET_PROC_ADDRESS("glPolygonOffsetClamp"); - + #endif } void rotate_quat(LLQuaternion& rotation) { - F32 angle_radians, x, y, z; - rotation.getAngleAxis(&angle_radians, &x, &y, &z); - gGL.rotatef(angle_radians * RAD_TO_DEG, x, y, z); + F32 angle_radians, x, y, z; + rotation.getAngleAxis(&angle_radians, &x, &y, &z); + gGL.rotatef(angle_radians * RAD_TO_DEG, x, y, z); } void flush_glerror() { - glGetError(); + glGetError(); } //this function outputs gl error to the log file, does not crash the code. void log_glerror() { - if (LL_UNLIKELY(!gGLManager.mInited)) - { - return ; - } - // Create or update texture to be used with this data - GLenum error; - error = glGetError(); - while (LL_UNLIKELY(error)) - { - GLubyte const * gl_error_msg = gluErrorString(error); - if (NULL != gl_error_msg) - { - LL_WARNS() << "GL Error: " << error << " GL Error String: " << gl_error_msg << LL_ENDL ; - } - else - { - // gluErrorString returns NULL for some extensions' error codes. - // you'll probably have to grep for the number in glext.h. - LL_WARNS() << "GL Error: UNKNOWN 0x" << std::hex << error << std::dec << LL_ENDL; - } - error = glGetError(); - } + if (LL_UNLIKELY(!gGLManager.mInited)) + { + return ; + } + // Create or update texture to be used with this data + GLenum error; + error = glGetError(); + while (LL_UNLIKELY(error)) + { + GLubyte const * gl_error_msg = gluErrorString(error); + if (NULL != gl_error_msg) + { + LL_WARNS() << "GL Error: " << error << " GL Error String: " << gl_error_msg << LL_ENDL ; + } + else + { + // gluErrorString returns NULL for some extensions' error codes. + // you'll probably have to grep for the number in glext.h. + LL_WARNS() << "GL Error: UNKNOWN 0x" << std::hex << error << std::dec << LL_ENDL; + } + error = glGetError(); + } } void do_assert_glerror() { - // Create or update texture to be used with this data - GLenum error; - error = glGetError(); - BOOL quit = FALSE; - if (LL_UNLIKELY(error)) - { - quit = TRUE; - GLubyte const * gl_error_msg = gluErrorString(error); - if (NULL != gl_error_msg) - { - LL_WARNS("RenderState") << "GL Error:" << error<< LL_ENDL; - LL_WARNS("RenderState") << "GL Error String:" << gl_error_msg << LL_ENDL; - - if (gDebugSession) - { - gFailLog << "GL Error:" << gl_error_msg << std::endl; - } - } - else - { - // gluErrorString returns NULL for some extensions' error codes. - // you'll probably have to grep for the number in glext.h. - LL_WARNS("RenderState") << "GL Error: UNKNOWN 0x" << std::hex << error << std::dec << LL_ENDL; - - if (gDebugSession) - { - gFailLog << "GL Error: UNKNOWN 0x" << std::hex << error << std::dec << std::endl; - } - } - } - - if (quit) - { - if (gDebugSession) - { - ll_fail("assert_glerror failed"); - } - else - { - LL_ERRS() << "One or more unhandled GL errors." << LL_ENDL; - } - } + // Create or update texture to be used with this data + GLenum error; + error = glGetError(); + BOOL quit = FALSE; + if (LL_UNLIKELY(error)) + { + quit = TRUE; + GLubyte const * gl_error_msg = gluErrorString(error); + if (NULL != gl_error_msg) + { + LL_WARNS("RenderState") << "GL Error:" << error<< LL_ENDL; + LL_WARNS("RenderState") << "GL Error String:" << gl_error_msg << LL_ENDL; + + if (gDebugSession) + { + gFailLog << "GL Error:" << gl_error_msg << std::endl; + } + } + else + { + // gluErrorString returns NULL for some extensions' error codes. + // you'll probably have to grep for the number in glext.h. + LL_WARNS("RenderState") << "GL Error: UNKNOWN 0x" << std::hex << error << std::dec << LL_ENDL; + + if (gDebugSession) + { + gFailLog << "GL Error: UNKNOWN 0x" << std::hex << error << std::dec << std::endl; + } + } + } + + if (quit) + { + if (gDebugSession) + { + ll_fail("assert_glerror failed"); + } + else + { + LL_ERRS() << "One or more unhandled GL errors." << LL_ENDL; + } + } } void assert_glerror() { -/* if (!gGLActive) - { - //LL_WARNS() << "GL used while not active!" << LL_ENDL; - - if (gDebugSession) - { - //ll_fail("GL used while not active"); - } - } +/* if (!gGLActive) + { + //LL_WARNS() << "GL used while not active!" << LL_ENDL; + + if (gDebugSession) + { + //ll_fail("GL used while not active"); + } + } */ - if (!gDebugGL) - { - //funny looking if for branch prediction -- gDebugGL is almost always false and assert_glerror is called often - } - else - { - do_assert_glerror(); - } + if (!gDebugGL) + { + //funny looking if for branch prediction -- gDebugGL is almost always false and assert_glerror is called often + } + else + { + do_assert_glerror(); + } } - + void clear_glerror() { - glGetError(); - glGetError(); + glGetError(); + glGetError(); } /////////////////////////////////////////////////////////////// @@ -2381,333 +2381,333 @@ GLenum LLGLDepthTest::sDepthFunc = GL_LESS; // OpenGL default GLboolean LLGLDepthTest::sWriteEnabled = GL_TRUE; // OpenGL default //static -void LLGLState::initClass() +void LLGLState::initClass() { - sStateMap[GL_DITHER] = GL_TRUE; - // sStateMap[GL_TEXTURE_2D] = GL_TRUE; - - //make sure multisample defaults to disabled - sStateMap[GL_MULTISAMPLE] = GL_FALSE; - glDisable(GL_MULTISAMPLE); + sStateMap[GL_DITHER] = GL_TRUE; + // sStateMap[GL_TEXTURE_2D] = GL_TRUE; + + //make sure multisample defaults to disabled + sStateMap[GL_MULTISAMPLE] = GL_FALSE; + glDisable(GL_MULTISAMPLE); } //static void LLGLState::restoreGL() { - sStateMap.clear(); - initClass(); + sStateMap.clear(); + initClass(); } //static // Really shouldn't be needed, but seems we sometimes do. void LLGLState::resetTextureStates() { - gGL.flush(); - GLint maxTextureUnits; - - glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &maxTextureUnits); - for (S32 j = maxTextureUnits-1; j >=0; j--) - { - gGL.getTexUnit(j)->activate(); - glClientActiveTexture(GL_TEXTURE0+j); - j == 0 ? gGL.getTexUnit(j)->enable(LLTexUnit::TT_TEXTURE) : gGL.getTexUnit(j)->disable(); - } + gGL.flush(); + GLint maxTextureUnits; + + glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &maxTextureUnits); + for (S32 j = maxTextureUnits-1; j >=0; j--) + { + gGL.getTexUnit(j)->activate(); + glClientActiveTexture(GL_TEXTURE0+j); + j == 0 ? gGL.getTexUnit(j)->enable(LLTexUnit::TT_TEXTURE) : gGL.getTexUnit(j)->disable(); + } } -void LLGLState::dumpStates() +void LLGLState::dumpStates() { - LL_INFOS("RenderState") << "GL States:" << LL_ENDL; - for (boost::unordered_map<LLGLenum, LLGLboolean>::iterator iter = sStateMap.begin(); - iter != sStateMap.end(); ++iter) - { - LL_INFOS("RenderState") << llformat(" 0x%04x : %s",(S32)iter->first,iter->second?"TRUE":"FALSE") << LL_ENDL; - } + LL_INFOS("RenderState") << "GL States:" << LL_ENDL; + for (boost::unordered_map<LLGLenum, LLGLboolean>::iterator iter = sStateMap.begin(); + iter != sStateMap.end(); ++iter) + { + LL_INFOS("RenderState") << llformat(" 0x%04x : %s",(S32)iter->first,iter->second?"TRUE":"FALSE") << LL_ENDL; + } } void LLGLState::checkStates(GLboolean writeAlpha) { - if (!gDebugGL) - { - return; - } - - GLint src; - GLint dst; - glGetIntegerv(GL_BLEND_SRC, &src); - glGetIntegerv(GL_BLEND_DST, &dst); + if (!gDebugGL) + { + return; + } + + GLint src; + GLint dst; + glGetIntegerv(GL_BLEND_SRC, &src); + glGetIntegerv(GL_BLEND_DST, &dst); llassert_always(src == GL_SRC_ALPHA); llassert_always(dst == GL_ONE_MINUS_SRC_ALPHA); - + // disable for now until usage is consistent //GLboolean colorMask[4]; //glGetBooleanv(GL_COLOR_WRITEMASK, colorMask); //llassert_always(colorMask[0]); //llassert_always(colorMask[1]); //llassert_always(colorMask[2]); - // llassert_always(colorMask[3] == writeAlpha); - - for (boost::unordered_map<LLGLenum, LLGLboolean>::iterator iter = sStateMap.begin(); - iter != sStateMap.end(); ++iter) - { - LLGLenum state = iter->first; - LLGLboolean cur_state = iter->second; - LLGLboolean gl_state = glIsEnabled(state); - if(cur_state != gl_state) - { - dumpStates(); - LL_GL_ERRS << llformat("LLGLState error. State: 0x%04x",state) << LL_ENDL; - } - } + // llassert_always(colorMask[3] == writeAlpha); + + for (boost::unordered_map<LLGLenum, LLGLboolean>::iterator iter = sStateMap.begin(); + iter != sStateMap.end(); ++iter) + { + LLGLenum state = iter->first; + LLGLboolean cur_state = iter->second; + LLGLboolean gl_state = glIsEnabled(state); + if(cur_state != gl_state) + { + dumpStates(); + LL_GL_ERRS << llformat("LLGLState error. State: 0x%04x",state) << LL_ENDL; + } + } } /////////////////////////////////////////////////////////////////////// LLGLState::LLGLState(LLGLenum state, S32 enabled) : - mState(state), mWasEnabled(FALSE), mIsEnabled(FALSE) + mState(state), mWasEnabled(FALSE), mIsEnabled(FALSE) { LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; - if (mState) - { - mWasEnabled = sStateMap[state]; - setEnabled(enabled); - } + if (mState) + { + mWasEnabled = sStateMap[state]; + setEnabled(enabled); + } } void LLGLState::setEnabled(S32 enabled) { - if (!mState) - { - return; - } - if (enabled == CURRENT_STATE) - { - enabled = sStateMap[mState] == GL_TRUE ? TRUE : FALSE; - } - else if (enabled == TRUE && sStateMap[mState] != GL_TRUE) - { - gGL.flush(); - glEnable(mState); - sStateMap[mState] = GL_TRUE; - } - else if (enabled == FALSE && sStateMap[mState] != GL_FALSE) - { - gGL.flush(); - glDisable(mState); - sStateMap[mState] = GL_FALSE; - } - mIsEnabled = enabled; + if (!mState) + { + return; + } + if (enabled == CURRENT_STATE) + { + enabled = sStateMap[mState] == GL_TRUE ? TRUE : FALSE; + } + else if (enabled == TRUE && sStateMap[mState] != GL_TRUE) + { + gGL.flush(); + glEnable(mState); + sStateMap[mState] = GL_TRUE; + } + else if (enabled == FALSE && sStateMap[mState] != GL_FALSE) + { + gGL.flush(); + glDisable(mState); + sStateMap[mState] = GL_FALSE; + } + mIsEnabled = enabled; } -LLGLState::~LLGLState() +LLGLState::~LLGLState() { LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; - if (mState) - { - if (gDebugGL) - { - if (!gDebugSession) - { - llassert_always(sStateMap[mState] == glIsEnabled(mState)); - } - else - { - if (sStateMap[mState] != glIsEnabled(mState)) - { - ll_fail("GL enabled state does not match expected"); - } - } - } - - if (mIsEnabled != mWasEnabled) - { - gGL.flush(); - if (mWasEnabled) - { - glEnable(mState); - sStateMap[mState] = GL_TRUE; - } - else - { - glDisable(mState); - sStateMap[mState] = GL_FALSE; - } - } - } + if (mState) + { + if (gDebugGL) + { + if (!gDebugSession) + { + llassert_always(sStateMap[mState] == glIsEnabled(mState)); + } + else + { + if (sStateMap[mState] != glIsEnabled(mState)) + { + ll_fail("GL enabled state does not match expected"); + } + } + } + + if (mIsEnabled != mWasEnabled) + { + gGL.flush(); + if (mWasEnabled) + { + glEnable(mState); + sStateMap[mState] = GL_TRUE; + } + else + { + glDisable(mState); + sStateMap[mState] = GL_FALSE; + } + } + } } //////////////////////////////////////////////////////////////////////////////// void LLGLManager::initGLStates() { - //gl states moved to classes in llglstates.h - LLGLState::initClass(); + //gl states moved to classes in llglstates.h + LLGLState::initClass(); } //////////////////////////////////////////////////////////////////////////////// void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific, std::string* version_string ) { - // GL_VERSION returns a null-terminated string with the format: - // <major>.<minor>[.<release>] [<vendor specific>] - - const char* version = (const char*) glGetString(GL_VERSION); - *major = 0; - *minor = 0; - *release = 0; - vendor_specific->assign(""); - - if( !version ) - { - return; - } - - version_string->assign(version); - - std::string ver_copy( version ); - S32 len = (S32)strlen( version ); /* Flawfinder: ignore */ - S32 i = 0; - S32 start; - // Find the major version - start = i; - for( ; i < len; i++ ) - { - if( '.' == version[i] ) - { - break; - } - } - std::string major_str = ver_copy.substr(start,i-start); - LLStringUtil::convertToS32(major_str, *major); - - if( '.' == version[i] ) - { - i++; - } - - // Find the minor version - start = i; - for( ; i < len; i++ ) - { - if( ('.' == version[i]) || isspace(version[i]) ) - { - break; - } - } - std::string minor_str = ver_copy.substr(start,i-start); - LLStringUtil::convertToS32(minor_str, *minor); - - // Find the release number (optional) - if( '.' == version[i] ) - { - i++; - - start = i; - for( ; i < len; i++ ) - { - if( isspace(version[i]) ) - { - break; - } - } - - std::string release_str = ver_copy.substr(start,i-start); - LLStringUtil::convertToS32(release_str, *release); - } - - // Skip over any white space - while( version[i] && isspace( version[i] ) ) - { - i++; - } - - // Copy the vendor-specific string (optional) - if( version[i] ) - { - vendor_specific->assign( version + i ); - } + // GL_VERSION returns a null-terminated string with the format: + // <major>.<minor>[.<release>] [<vendor specific>] + + const char* version = (const char*) glGetString(GL_VERSION); + *major = 0; + *minor = 0; + *release = 0; + vendor_specific->assign(""); + + if( !version ) + { + return; + } + + version_string->assign(version); + + std::string ver_copy( version ); + S32 len = (S32)strlen( version ); /* Flawfinder: ignore */ + S32 i = 0; + S32 start; + // Find the major version + start = i; + for( ; i < len; i++ ) + { + if( '.' == version[i] ) + { + break; + } + } + std::string major_str = ver_copy.substr(start,i-start); + LLStringUtil::convertToS32(major_str, *major); + + if( '.' == version[i] ) + { + i++; + } + + // Find the minor version + start = i; + for( ; i < len; i++ ) + { + if( ('.' == version[i]) || isspace(version[i]) ) + { + break; + } + } + std::string minor_str = ver_copy.substr(start,i-start); + LLStringUtil::convertToS32(minor_str, *minor); + + // Find the release number (optional) + if( '.' == version[i] ) + { + i++; + + start = i; + for( ; i < len; i++ ) + { + if( isspace(version[i]) ) + { + break; + } + } + + std::string release_str = ver_copy.substr(start,i-start); + LLStringUtil::convertToS32(release_str, *release); + } + + // Skip over any white space + while( version[i] && isspace( version[i] ) ) + { + i++; + } + + // Copy the vendor-specific string (optional) + if( version[i] ) + { + vendor_specific->assign( version + i ); + } } void parse_glsl_version(S32& major, S32& minor) { - // GL_SHADING_LANGUAGE_VERSION returns a null-terminated string with the format: - // <major>.<minor>[.<release>] [<vendor specific>] - - const char* version = (const char*) glGetString(GL_SHADING_LANGUAGE_VERSION); - major = 0; - minor = 0; - - if( !version ) - { - return; - } - - std::string ver_copy( version ); - S32 len = (S32)strlen( version ); /* Flawfinder: ignore */ - S32 i = 0; - S32 start; - // Find the major version - start = i; - for( ; i < len; i++ ) - { - if( '.' == version[i] ) - { - break; - } - } - std::string major_str = ver_copy.substr(start,i-start); - LLStringUtil::convertToS32(major_str, major); - - if( '.' == version[i] ) - { - i++; - } - - // Find the minor version - start = i; - for( ; i < len; i++ ) - { - if( ('.' == version[i]) || isspace(version[i]) ) - { - break; - } - } - std::string minor_str = ver_copy.substr(start,i-start); - LLStringUtil::convertToS32(minor_str, minor); + // GL_SHADING_LANGUAGE_VERSION returns a null-terminated string with the format: + // <major>.<minor>[.<release>] [<vendor specific>] + + const char* version = (const char*) glGetString(GL_SHADING_LANGUAGE_VERSION); + major = 0; + minor = 0; + + if( !version ) + { + return; + } + + std::string ver_copy( version ); + S32 len = (S32)strlen( version ); /* Flawfinder: ignore */ + S32 i = 0; + S32 start; + // Find the major version + start = i; + for( ; i < len; i++ ) + { + if( '.' == version[i] ) + { + break; + } + } + std::string major_str = ver_copy.substr(start,i-start); + LLStringUtil::convertToS32(major_str, major); + + if( '.' == version[i] ) + { + i++; + } + + // Find the minor version + start = i; + for( ; i < len; i++ ) + { + if( ('.' == version[i]) || isspace(version[i]) ) + { + break; + } + } + std::string minor_str = ver_copy.substr(start,i-start); + LLStringUtil::convertToS32(minor_str, minor); } LLGLUserClipPlane::LLGLUserClipPlane(const LLPlane& p, const glh::matrix4f& modelview, const glh::matrix4f& projection, bool apply) { - mApply = apply; + mApply = apply; - if (mApply) - { - mModelview = modelview; - mProjection = projection; + if (mApply) + { + mModelview = modelview; + mProjection = projection; //flip incoming LLPlane to get consistent behavior compared to frustum culling - setPlane(-p[0], -p[1], -p[2], -p[3]); - } + setPlane(-p[0], -p[1], -p[2], -p[3]); + } } void LLGLUserClipPlane::disable() { if (mApply) - { - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.popMatrix(); - gGL.matrixMode(LLRender::MM_MODELVIEW); - } + { + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.popMatrix(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + } mApply = false; } void LLGLUserClipPlane::setPlane(F32 a, F32 b, F32 c, F32 d) { - glh::matrix4f& P = mProjection; - glh::matrix4f& M = mModelview; - - glh::matrix4f invtrans_MVP = (P * M).inverse().transpose(); + glh::matrix4f& P = mProjection; + glh::matrix4f& M = mModelview; + + glh::matrix4f invtrans_MVP = (P * M).inverse().transpose(); glh::vec4f oplane(a,b,c,d); glh::vec4f cplane; invtrans_MVP.mult_matrix_vec(oplane, cplane); @@ -2722,100 +2722,100 @@ void LLGLUserClipPlane::setPlane(F32 a, F32 b, F32 c, F32 d) suffix.set_row(2, cplane); glh::matrix4f newP = suffix * P; gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.pushMatrix(); + gGL.pushMatrix(); gGL.loadMatrix(newP.m); - gGLObliqueProjectionInverse = LLMatrix4(newP.inverse().transpose().m); + gGLObliqueProjectionInverse = LLMatrix4(newP.inverse().transpose().m); gGL.matrixMode(LLRender::MM_MODELVIEW); } LLGLUserClipPlane::~LLGLUserClipPlane() { - disable(); + disable(); } LLGLDepthTest::LLGLDepthTest(GLboolean depth_enabled, GLboolean write_enabled, GLenum depth_func) : mPrevDepthEnabled(sDepthEnabled), mPrevDepthFunc(sDepthFunc), mPrevWriteEnabled(sWriteEnabled) { - stop_glerror(); - - checkState(); - - if (!depth_enabled) - { // always disable depth writes if depth testing is disabled - // GL spec defines this as a requirement, but some implementations allow depth writes with testing disabled - // The proper way to write to depth buffer with testing disabled is to enable testing and use a depth_func of GL_ALWAYS - write_enabled = FALSE; - } - - if (depth_enabled != sDepthEnabled) - { - gGL.flush(); - if (depth_enabled) glEnable(GL_DEPTH_TEST); - else glDisable(GL_DEPTH_TEST); - sDepthEnabled = depth_enabled; - } - if (depth_func != sDepthFunc) - { - gGL.flush(); - glDepthFunc(depth_func); - sDepthFunc = depth_func; - } - if (write_enabled != sWriteEnabled) - { - gGL.flush(); - glDepthMask(write_enabled); - sWriteEnabled = write_enabled; - } + stop_glerror(); + + checkState(); + + if (!depth_enabled) + { // always disable depth writes if depth testing is disabled + // GL spec defines this as a requirement, but some implementations allow depth writes with testing disabled + // The proper way to write to depth buffer with testing disabled is to enable testing and use a depth_func of GL_ALWAYS + write_enabled = FALSE; + } + + if (depth_enabled != sDepthEnabled) + { + gGL.flush(); + if (depth_enabled) glEnable(GL_DEPTH_TEST); + else glDisable(GL_DEPTH_TEST); + sDepthEnabled = depth_enabled; + } + if (depth_func != sDepthFunc) + { + gGL.flush(); + glDepthFunc(depth_func); + sDepthFunc = depth_func; + } + if (write_enabled != sWriteEnabled) + { + gGL.flush(); + glDepthMask(write_enabled); + sWriteEnabled = write_enabled; + } } LLGLDepthTest::~LLGLDepthTest() { - checkState(); - if (sDepthEnabled != mPrevDepthEnabled ) - { - gGL.flush(); - if (mPrevDepthEnabled) glEnable(GL_DEPTH_TEST); - else glDisable(GL_DEPTH_TEST); - sDepthEnabled = mPrevDepthEnabled; - } - if (sDepthFunc != mPrevDepthFunc) - { - gGL.flush(); - glDepthFunc(mPrevDepthFunc); - sDepthFunc = mPrevDepthFunc; - } - if (sWriteEnabled != mPrevWriteEnabled ) - { - gGL.flush(); - glDepthMask(mPrevWriteEnabled); - sWriteEnabled = mPrevWriteEnabled; - } + checkState(); + if (sDepthEnabled != mPrevDepthEnabled ) + { + gGL.flush(); + if (mPrevDepthEnabled) glEnable(GL_DEPTH_TEST); + else glDisable(GL_DEPTH_TEST); + sDepthEnabled = mPrevDepthEnabled; + } + if (sDepthFunc != mPrevDepthFunc) + { + gGL.flush(); + glDepthFunc(mPrevDepthFunc); + sDepthFunc = mPrevDepthFunc; + } + if (sWriteEnabled != mPrevWriteEnabled ) + { + gGL.flush(); + glDepthMask(mPrevWriteEnabled); + sWriteEnabled = mPrevWriteEnabled; + } } void LLGLDepthTest::checkState() { - if (gDebugGL) - { - GLint func = 0; - GLboolean mask = FALSE; - - glGetIntegerv(GL_DEPTH_FUNC, &func); - glGetBooleanv(GL_DEPTH_WRITEMASK, &mask); - - if (glIsEnabled(GL_DEPTH_TEST) != sDepthEnabled || - sWriteEnabled != mask || - sDepthFunc != func) - { - if (gDebugSession) - { - gFailLog << "Unexpected depth testing state." << std::endl; - } - else - { - LL_GL_ERRS << "Unexpected depth testing state." << LL_ENDL; - } - } - } + if (gDebugGL) + { + GLint func = 0; + GLboolean mask = FALSE; + + glGetIntegerv(GL_DEPTH_FUNC, &func); + glGetBooleanv(GL_DEPTH_WRITEMASK, &mask); + + if (glIsEnabled(GL_DEPTH_TEST) != sDepthEnabled || + sWriteEnabled != mask || + sDepthFunc != func) + { + if (gDebugSession) + { + gFailLog << "Unexpected depth testing state." << std::endl; + } + else + { + LL_GL_ERRS << "Unexpected depth testing state." << LL_ENDL; + } + } + } } LLGLSquashToFarClip::LLGLSquashToFarClip() @@ -2833,84 +2833,84 @@ LLGLSquashToFarClip::LLGLSquashToFarClip(glh::matrix4f& P, U32 layer) void LLGLSquashToFarClip::setProjectionMatrix(glh::matrix4f& projection, U32 layer) { - F32 depth = 0.99999f - 0.0001f * layer; + F32 depth = 0.99999f - 0.0001f * layer; - for (U32 i = 0; i < 4; i++) - { - projection.element(2, i) = projection.element(3, i) * depth; - } + for (U32 i = 0; i < 4; i++) + { + projection.element(2, i) = projection.element(3, i) * depth; + } LLRender::eMatrixMode last_matrix_mode = gGL.getMatrixMode(); - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.pushMatrix(); - gGL.loadMatrix(projection.m); + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.pushMatrix(); + gGL.loadMatrix(projection.m); - gGL.matrixMode(last_matrix_mode); + gGL.matrixMode(last_matrix_mode); } LLGLSquashToFarClip::~LLGLSquashToFarClip() { LLRender::eMatrixMode last_matrix_mode = gGL.getMatrixMode(); - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.popMatrix(); + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.popMatrix(); - gGL.matrixMode(last_matrix_mode); + gGL.matrixMode(last_matrix_mode); } - + LLGLSyncFence::LLGLSyncFence() { - mSync = 0; + mSync = 0; } LLGLSyncFence::~LLGLSyncFence() { - if (mSync) - { - glDeleteSync(mSync); - } + if (mSync) + { + glDeleteSync(mSync); + } } void LLGLSyncFence::placeFence() { - if (mSync) - { - glDeleteSync(mSync); - } - mSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + if (mSync) + { + glDeleteSync(mSync); + } + mSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); } bool LLGLSyncFence::isCompleted() { - bool ret = true; - if (mSync) - { - GLenum status = glClientWaitSync(mSync, 0, 1); - if (status == GL_TIMEOUT_EXPIRED) - { - ret = false; - } - } - return ret; + bool ret = true; + if (mSync) + { + GLenum status = glClientWaitSync(mSync, 0, 1); + if (status == GL_TIMEOUT_EXPIRED) + { + ret = false; + } + } + return ret; } void LLGLSyncFence::wait() { - if (mSync) - { - while (glClientWaitSync(mSync, 0, FENCE_WAIT_TIME_NANOSECONDS) == GL_TIMEOUT_EXPIRED) - { //track the number of times we've waited here - } - } + if (mSync) + { + while (glClientWaitSync(mSync, 0, FENCE_WAIT_TIME_NANOSECONDS) == GL_TIMEOUT_EXPIRED) + { //track the number of times we've waited here + } + } } LLGLSPipelineSkyBox::LLGLSPipelineSkyBox() : mCullFace(GL_CULL_FACE) , mSquashClip() -{ +{ } LLGLSPipelineSkyBox::~LLGLSPipelineSkyBox() @@ -2925,17 +2925,17 @@ LLGLSPipelineDepthTestSkyBox::LLGLSPipelineDepthTestSkyBox(bool depth_test, bool } LLGLSPipelineBlendSkyBox::LLGLSPipelineBlendSkyBox(bool depth_test, bool depth_write) -: LLGLSPipelineDepthTestSkyBox(depth_test, depth_write) +: LLGLSPipelineDepthTestSkyBox(depth_test, depth_write) , mBlend(GL_BLEND) -{ +{ gGL.setSceneBlendType(LLRender::BT_ALPHA); } #if LL_WINDOWS // Expose desired use of high-performance graphics processor to Optimus driver and to AMD driver // https://docs.nvidia.com/gameworks/content/technologies/desktop/optimus.htm -extern "C" -{ +extern "C" +{ __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; } diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h index 4b0fbc0466..5a7ad943df 100644 --- a/indra/llrender/llgl.h +++ b/indra/llrender/llgl.h @@ -1,25 +1,25 @@ -/** +/** * @file llgl.h * @brief LLGL definition * * $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$ */ @@ -64,81 +64,81 @@ class LLSD; class LLGLManager { public: - LLGLManager(); + LLGLManager(); - bool initGL(); - void shutdownGL(); + bool initGL(); + void shutdownGL(); - void initWGL(); // Initializes stupid WGL extensions + void initWGL(); // Initializes stupid WGL extensions - std::string getRawGLString(); // For sending to simulator + std::string getRawGLString(); // For sending to simulator - BOOL mInited; - BOOL mIsDisabled; + BOOL mInited; + BOOL mIsDisabled; - // OpenGL limits - S32 mMaxSamples; - S32 mNumTextureImageUnits; - S32 mMaxSampleMaskWords; - S32 mMaxColorTextureSamples; - S32 mMaxDepthTextureSamples; - S32 mMaxIntegerSamples; + // OpenGL limits + S32 mMaxSamples; + S32 mNumTextureImageUnits; + S32 mMaxSampleMaskWords; + S32 mMaxColorTextureSamples; + S32 mMaxDepthTextureSamples; + S32 mMaxIntegerSamples; S32 mGLMaxVertexRange; S32 mGLMaxIndexRange; S32 mGLMaxTextureSize; F32 mMaxAnisotropy = 0.f; - // GL 4.x capabilities - bool mHasCubeMapArray = false; - bool mHasDebugOutput = false; + // GL 4.x capabilities + bool mHasCubeMapArray = false; + bool mHasDebugOutput = false; bool mHasTransformFeedback = false; bool mHasAnisotropic = false; - - // Vendor-specific extensions + + // Vendor-specific extensions bool mHasAMDAssociations = false; - BOOL mIsAMD; - BOOL mIsNVIDIA; - BOOL mIsIntel; + BOOL mIsAMD; + BOOL mIsNVIDIA; + BOOL mIsIntel; #if LL_DARWIN - // Needed to distinguish problem cards on older Macs that break with Materials - BOOL mIsMobileGF; + // Needed to distinguish problem cards on older Macs that break with Materials + BOOL mIsMobileGF; #endif - - // Whether this version of GL is good enough for SL to use - BOOL mHasRequirements; - S32 mDriverVersionMajor; - S32 mDriverVersionMinor; - S32 mDriverVersionRelease; - F32 mGLVersion; // e.g = 1.4 - S32 mGLSLVersionMajor; - S32 mGLSLVersionMinor; - std::string mDriverVersionVendorString; - std::string mGLVersionString; + // Whether this version of GL is good enough for SL to use + BOOL mHasRequirements; + + S32 mDriverVersionMajor; + S32 mDriverVersionMinor; + S32 mDriverVersionRelease; + F32 mGLVersion; // e.g = 1.4 + S32 mGLSLVersionMajor; + S32 mGLSLVersionMinor; + std::string mDriverVersionVendorString; + std::string mGLVersionString; - S32 mVRAM; // VRAM in MB - - void getPixelFormat(); // Get the best pixel format + S32 mVRAM; // VRAM in MB - std::string getGLInfoString(); - void printGLInfoString(); - void getGLInfo(LLSD& info); + void getPixelFormat(); // Get the best pixel format - void asLLSD(LLSD& info); + std::string getGLInfoString(); + void printGLInfoString(); + void getGLInfo(LLSD& info); - // In ALL CAPS - std::string mGLVendor; - std::string mGLVendorShort; + void asLLSD(LLSD& info); - // In ALL CAPS - std::string mGLRenderer; + // In ALL CAPS + std::string mGLVendor; + std::string mGLVendorShort; + + // In ALL CAPS + std::string mGLRenderer; private: - void initExtensions(); - void initGLStates(); - void initGLImages(); + void initExtensions(); + void initGLStates(); + void initGLImages(); }; extern LLGLManager gGLManager; @@ -173,51 +173,51 @@ void clear_glerror(); // This is a class for GL state management /* - GL STATE MANAGEMENT DESCRIPTION + GL STATE MANAGEMENT DESCRIPTION - LLGLState and its two subclasses, LLGLEnable and LLGLDisable, manage the current - enable/disable states of the GL to prevent redundant setting of state within a - render path or the accidental corruption of what state the next path expects. + LLGLState and its two subclasses, LLGLEnable and LLGLDisable, manage the current + enable/disable states of the GL to prevent redundant setting of state within a + render path or the accidental corruption of what state the next path expects. - Essentially, wherever you would call glEnable set a state and then - subsequently reset it by calling glDisable (or vice versa), make an instance of - LLGLEnable with the state you want to set, and assume it will be restored to its - original state when that instance of LLGLEnable is destroyed. It is good practice - to exploit stack frame controls for optimal setting/unsetting and readability of - code. In llglstates.h, there are a collection of helper classes that define groups - of enables/disables that can cause multiple states to be set with the creation of - one instance. + Essentially, wherever you would call glEnable set a state and then + subsequently reset it by calling glDisable (or vice versa), make an instance of + LLGLEnable with the state you want to set, and assume it will be restored to its + original state when that instance of LLGLEnable is destroyed. It is good practice + to exploit stack frame controls for optimal setting/unsetting and readability of + code. In llglstates.h, there are a collection of helper classes that define groups + of enables/disables that can cause multiple states to be set with the creation of + one instance. - Sample usage: + Sample usage: - //disable lighting for rendering hud objects - //INCORRECT USAGE - LLGLEnable blend(GL_BLEND); - renderHUD(); - LLGLDisable blend(GL_BLEND); + //disable lighting for rendering hud objects + //INCORRECT USAGE + LLGLEnable blend(GL_BLEND); + renderHUD(); + LLGLDisable blend(GL_BLEND); - //CORRECT USAGE - { - LLGLEnable blend(GL_BLEND); - renderHUD(); - } + //CORRECT USAGE + { + LLGLEnable blend(GL_BLEND); + renderHUD(); + } - If a state is to be set on a conditional, the following mechanism - is useful: + If a state is to be set on a conditional, the following mechanism + is useful: - { - LLGLEnable blend(blend_hud ? GL_GL_BLEND: 0); - renderHUD(); - } + { + LLGLEnable blend(blend_hud ? GL_GL_BLEND: 0); + renderHUD(); + } - A LLGLState initialized with a parameter of 0 does nothing. + A LLGLState initialized with a parameter of 0 does nothing. - LLGLState works by maintaining a map of the current GL states, and ignoring redundant - enables/disables. If a redundant call is attempted, it becomes a noop, otherwise, - it is set in the constructor and reset in the destructor. + LLGLState works by maintaining a map of the current GL states, and ignoring redundant + enables/disables. If a redundant call is attempted, it becomes a noop, otherwise, + it is set in the constructor and reset in the destructor. - For debugging GL state corruption, running with debug enabled will trigger asserts - if the existing GL state does not match the expected GL state. + For debugging GL state corruption, running with debug enabled will trigger asserts + if the existing GL state does not match the expected GL state. */ @@ -226,79 +226,79 @@ void clear_glerror(); class LLGLState { public: - static void initClass(); - static void restoreGL(); + static void initClass(); + static void restoreGL(); - static void resetTextureStates(); - static void dumpStates(); + static void resetTextureStates(); + static void dumpStates(); // make sure GL blend function, GL states, and GL color mask match - // what we expect + // what we expect // writeAlpha - whether or not writing to alpha channel is expected - static void checkStates(GLboolean writeAlpha = GL_TRUE); + static void checkStates(GLboolean writeAlpha = GL_TRUE); protected: - static boost::unordered_map<LLGLenum, LLGLboolean> sStateMap; - + static boost::unordered_map<LLGLenum, LLGLboolean> sStateMap; + public: - enum { CURRENT_STATE = -2 }; - LLGLState(LLGLenum state, S32 enabled = CURRENT_STATE); - ~LLGLState(); - void setEnabled(S32 enabled); - void enable() { setEnabled(TRUE); } - void disable() { setEnabled(FALSE); } + enum { CURRENT_STATE = -2 }; + LLGLState(LLGLenum state, S32 enabled = CURRENT_STATE); + ~LLGLState(); + void setEnabled(S32 enabled); + void enable() { setEnabled(TRUE); } + void disable() { setEnabled(FALSE); } protected: - LLGLenum mState; - BOOL mWasEnabled; - BOOL mIsEnabled; + LLGLenum mState; + BOOL mWasEnabled; + BOOL mIsEnabled; }; // New LLGLState class wrappers that don't depend on actual GL flags. class LLGLEnableBlending : public LLGLState { public: - LLGLEnableBlending(bool enable); + LLGLEnableBlending(bool enable); }; class LLGLEnableAlphaReject : public LLGLState { public: - LLGLEnableAlphaReject(bool enable); + LLGLEnableAlphaReject(bool enable); }; // Enable with functor class LLGLEnableFunc : LLGLState { public: - LLGLEnableFunc(LLGLenum state, bool enable, boost::function<void()> func) - : LLGLState(state, enable) - { - if (enable) - { - func(); - } - } + LLGLEnableFunc(LLGLenum state, bool enable, boost::function<void()> func) + : LLGLState(state, enable) + { + if (enable) + { + func(); + } + } }; /// TODO: Being deprecated. class LLGLEnable : public LLGLState { public: - LLGLEnable(LLGLenum state) : LLGLState(state, TRUE) {} + LLGLEnable(LLGLenum state) : LLGLState(state, TRUE) {} }; /// TODO: Being deprecated. class LLGLDisable : public LLGLState { public: - LLGLDisable(LLGLenum state) : LLGLState(state, FALSE) {} + LLGLDisable(LLGLenum state) : LLGLState(state, FALSE) {} }; /* Store and modify projection matrix to create an oblique projection that clips to the specified plane. Oblique projections alter values in the depth buffer, so this - class should not be used mid-renderpass. + class should not be used mid-renderpass. Restores projection matrix on destruction. GL_MODELVIEW_MATRIX is active whenever program execution @@ -306,21 +306,21 @@ public: Does not stack. Caches inverse of projection matrix used in gGLObliqueProjectionInverse */ -class LLGLUserClipPlane +class LLGLUserClipPlane { public: - - LLGLUserClipPlane(const LLPlane& plane, const glh::matrix4f& modelview, const glh::matrix4f& projection, bool apply = true); - ~LLGLUserClipPlane(); - void setPlane(F32 a, F32 b, F32 c, F32 d); + LLGLUserClipPlane(const LLPlane& plane, const glh::matrix4f& modelview, const glh::matrix4f& projection, bool apply = true); + ~LLGLUserClipPlane(); + + void setPlane(F32 a, F32 b, F32 c, F32 d); void disable(); private: - bool mApply; + bool mApply; - glh::matrix4f mProjection; - glh::matrix4f mModelview; + glh::matrix4f mProjection; + glh::matrix4f mModelview; }; /* @@ -334,40 +334,40 @@ class LLGLSquashToFarClip { public: LLGLSquashToFarClip(); - LLGLSquashToFarClip(glh::matrix4f& projection, U32 layer = 0); + LLGLSquashToFarClip(glh::matrix4f& projection, U32 layer = 0); void setProjectionMatrix(glh::matrix4f& projection, U32 layer); - ~LLGLSquashToFarClip(); + ~LLGLSquashToFarClip(); }; /* - Interface for objects that need periodic GL updates applied to them. - Used to synchronize GL updates with GL thread. + Interface for objects that need periodic GL updates applied to them. + Used to synchronize GL updates with GL thread. */ class LLGLUpdate { public: - static std::list<LLGLUpdate*> sGLQ; - - BOOL mInQ; - LLGLUpdate() - : mInQ(FALSE) - { - } - virtual ~LLGLUpdate() - { - if (mInQ) - { - std::list<LLGLUpdate*>::iterator iter = std::find(sGLQ.begin(), sGLQ.end(), this); - if (iter != sGLQ.end()) - { - sGLQ.erase(iter); - } - } - } - virtual void updateGL() = 0; + static std::list<LLGLUpdate*> sGLQ; + + BOOL mInQ; + LLGLUpdate() + : mInQ(FALSE) + { + } + virtual ~LLGLUpdate() + { + if (mInQ) + { + std::list<LLGLUpdate*>::iterator iter = std::find(sGLQ.begin(), sGLQ.end(), this); + if (iter != sGLQ.end()) + { + sGLQ.erase(iter); + } + } + } + virtual void updateGL() = 0; }; const U32 FENCE_WAIT_TIME_NANOSECONDS = 1000; //1 ms @@ -375,26 +375,26 @@ const U32 FENCE_WAIT_TIME_NANOSECONDS = 1000; //1 ms class LLGLFence { public: - virtual ~LLGLFence() - { - } + virtual ~LLGLFence() + { + } - virtual void placeFence() = 0; - virtual bool isCompleted() = 0; - virtual void wait() = 0; + virtual void placeFence() = 0; + virtual bool isCompleted() = 0; + virtual void wait() = 0; }; class LLGLSyncFence : public LLGLFence { public: - GLsync mSync; - - LLGLSyncFence(); - virtual ~LLGLSyncFence(); - - void placeFence(); - bool isCompleted(); - void wait(); + GLsync mSync; + + LLGLSyncFence(); + virtual ~LLGLSyncFence(); + + void placeFence(); + bool isCompleted(); + void wait(); }; extern LLMatrix4 gGLObliqueProjectionInverse; @@ -471,6 +471,6 @@ extern BOOL gGLActive; #ifndef GL_DEPTH24_STENCIL8 #define GL_DEPTH24_STENCIL8 GL_DEPTH24_STENCIL8_EXT -#endif +#endif #endif // LL_LLGL_H diff --git a/indra/llrender/llglcommonfunc.cpp b/indra/llrender/llglcommonfunc.cpp index 04d29b9430..13b08de7cc 100644 --- a/indra/llrender/llglcommonfunc.cpp +++ b/indra/llrender/llglcommonfunc.cpp @@ -27,12 +27,12 @@ #include "llglheaders.h" #include "llglcommonfunc.h" -namespace LLGLCommonFunc +namespace LLGLCommonFunc { - void selected_stencil_test() - { + void selected_stencil_test() + { // deprecated - //glStencilFunc(GL_ALWAYS, 2, 0xffff); - //glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); - } + //glStencilFunc(GL_ALWAYS, 2, 0xffff); + //glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + } } diff --git a/indra/llrender/llglcommonfunc.h b/indra/llrender/llglcommonfunc.h index e6d3755755..bb995fc199 100644 --- a/indra/llrender/llglcommonfunc.h +++ b/indra/llrender/llglcommonfunc.h @@ -26,5 +26,5 @@ namespace LLGLCommonFunc { - void selected_stencil_test(); + void selected_stencil_test(); } diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h index b80680a3d2..c5e1ff3e23 100644 --- a/indra/llrender/llglheaders.h +++ b/indra/llrender/llglheaders.h @@ -855,7 +855,7 @@ extern void glGenerateMipmapEXT(GLenum target) AVAILABLE_MAC_OS_X_VERSION_10_4_A #ifndef GL_ARB_framebuffer_object #define glGenerateMipmap glGenerateMipmapEXT -#define GL_MAX_SAMPLES 0x8D57 +#define GL_MAX_SAMPLES 0x8D57 #endif #ifdef __cplusplus @@ -937,7 +937,7 @@ extern "C" { #define GL_DYNAMIC_READ_ARB 0x88E9 #define GL_DYNAMIC_COPY_ARB 0x88EA #endif - + #ifndef GL_ARB_vertex_buffer_object @@ -957,7 +957,7 @@ typedef GLboolean (* glIsBufferARBProcPtr) (GLuint buffer); typedef void (* glBufferDataARBProcPtr) (GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage); typedef void (* glBufferSubDataARBProcPtr) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data); typedef void (* glGetBufferSubDataARBProcPtr) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid *data); -typedef GLvoid* (* glMapBufferARBProcPtr) (GLenum target, GLenum access); /* Flawfinder: ignore */ +typedef GLvoid* (* glMapBufferARBProcPtr) (GLenum target, GLenum access); /* Flawfinder: ignore */ typedef GLboolean (* glUnmapBufferARBProcPtr) (GLenum target); typedef void (* glGetBufferParameterivARBProcPtr) (GLenum target, GLenum pname, GLint *params); typedef void (* glGetBufferPointervARBProcPtr) (GLenum target, GLenum pname, GLvoid* *params); @@ -1045,11 +1045,11 @@ extern void glGetBufferPointervARB (GLenum, GLenum, GLvoid* *); //GL_NVX_gpu_memory_info constants #ifndef GL_NVX_gpu_memory_info #define GL_NVX_gpu_memory_info -#define GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX 0x9047 -#define GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX 0x9048 -#define GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX 0x9049 -#define GL_GPU_MEMORY_INFO_EVICTION_COUNT_NVX 0x904A -#define GL_GPU_MEMORY_INFO_EVICTED_MEMORY_NVX 0x904B +#define GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX 0x9047 +#define GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX 0x9048 +#define GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX 0x9049 +#define GL_GPU_MEMORY_INFO_EVICTION_COUNT_NVX 0x904A +#define GL_GPU_MEMORY_INFO_EVICTED_MEMORY_NVX 0x904B #endif //GL_ATI_meminfo constants @@ -1063,6 +1063,6 @@ extern void glGetBufferPointervARB (GLenum, GLenum, GLvoid* *); #if defined(TRACY_ENABLE) && LL_PROFILER_ENABLE_TRACY_OPENGL #include <tracy/TracyOpenGL.hpp> #endif - + #endif // LL_LLGLHEADERS_H diff --git a/indra/llrender/llglstates.h b/indra/llrender/llglstates.h index 930c5e3ed7..9bb980d7ad 100644 --- a/indra/llrender/llglstates.h +++ b/indra/llrender/llglstates.h @@ -1,25 +1,25 @@ -/** +/** * @file llglstates.h * @brief LLGL states definitions * * $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$ */ @@ -34,21 +34,21 @@ class LLGLDepthTest { - // Enabled by default + // Enabled by default public: - LLGLDepthTest(GLboolean depth_enabled, GLboolean write_enabled = GL_TRUE, GLenum depth_func = GL_LEQUAL); - - ~LLGLDepthTest(); - - void checkState(); - - GLboolean mPrevDepthEnabled; - GLenum mPrevDepthFunc; - GLboolean mPrevWriteEnabled; + LLGLDepthTest(GLboolean depth_enabled, GLboolean write_enabled = GL_TRUE, GLenum depth_func = GL_LEQUAL); + + ~LLGLDepthTest(); + + void checkState(); + + GLboolean mPrevDepthEnabled; + GLenum mPrevDepthFunc; + GLboolean mPrevWriteEnabled; private: - static GLboolean sDepthEnabled; // defaults to GL_FALSE - static GLenum sDepthFunc; // defaults to GL_LESS - static GLboolean sWriteEnabled; // defaults to GL_TRUE + static GLboolean sDepthEnabled; // defaults to GL_FALSE + static GLenum sDepthFunc; // defaults to GL_LESS + static GLboolean sWriteEnabled; // defaults to GL_TRUE }; //---------------------------------------------------------------------------- @@ -58,110 +58,110 @@ class LLGLSDefault protected: LLGLDisable mBlend, mCullFace; public: - LLGLSDefault() - : - // Disable - mBlend(GL_BLEND), - mCullFace(GL_CULL_FACE) - { } + LLGLSDefault() + : + // Disable + mBlend(GL_BLEND), + mCullFace(GL_CULL_FACE) + { } }; class LLGLSObjectSelect -{ +{ protected: - LLGLDisable mBlend; - LLGLEnable mCullFace; + LLGLDisable mBlend; + LLGLEnable mCullFace; public: - LLGLSObjectSelect() - : mBlend(GL_BLEND), - mCullFace(GL_CULL_FACE) - { } + LLGLSObjectSelect() + : mBlend(GL_BLEND), + mCullFace(GL_CULL_FACE) + { } }; //---------------------------------------------------------------------------- class LLGLSUIDefault -{ +{ protected: - LLGLEnable mBlend; - LLGLDisable mCullFace; - LLGLDepthTest mDepthTest; + LLGLEnable mBlend; + LLGLDisable mCullFace; + LLGLDepthTest mDepthTest; public: - LLGLSUIDefault() - : mBlend(GL_BLEND), - mCullFace(GL_CULL_FACE), - mDepthTest(GL_FALSE, GL_TRUE, GL_LEQUAL) - {} + LLGLSUIDefault() + : mBlend(GL_BLEND), + mCullFace(GL_CULL_FACE), + mDepthTest(GL_FALSE, GL_TRUE, GL_LEQUAL) + {} }; //---------------------------------------------------------------------------- class LLGLSPipeline -{ +{ protected: - LLGLEnable mCullFace; - LLGLDepthTest mDepthTest; + LLGLEnable mCullFace; + LLGLDepthTest mDepthTest; public: - LLGLSPipeline() - : mCullFace(GL_CULL_FACE), - mDepthTest(GL_TRUE, GL_TRUE, GL_LEQUAL) - { } + LLGLSPipeline() + : mCullFace(GL_CULL_FACE), + mDepthTest(GL_TRUE, GL_TRUE, GL_LEQUAL) + { } }; class LLGLSPipelineAlpha // : public LLGLSPipeline -{ +{ protected: - LLGLEnable mBlend; + LLGLEnable mBlend; public: - LLGLSPipelineAlpha() - : mBlend(GL_BLEND) - { } + LLGLSPipelineAlpha() + : mBlend(GL_BLEND) + { } }; class LLGLSPipelineSelection -{ +{ protected: - LLGLDisable mCullFace; + LLGLDisable mCullFace; public: - LLGLSPipelineSelection() - : mCullFace(GL_CULL_FACE) - {} + LLGLSPipelineSelection() + : mCullFace(GL_CULL_FACE) + {} }; class LLGLSPipelineSkyBox -{ +{ protected: LLGLDisable mCullFace; LLGLSquashToFarClip mSquashClip; public: - LLGLSPipelineSkyBox(); + LLGLSPipelineSkyBox(); ~LLGLSPipelineSkyBox(); }; class LLGLSPipelineDepthTestSkyBox : public LLGLSPipelineSkyBox -{ +{ public: - LLGLSPipelineDepthTestSkyBox(bool depth_test, bool depth_write); + LLGLSPipelineDepthTestSkyBox(bool depth_test, bool depth_write); LLGLDepthTest mDepth; }; -class LLGLSPipelineBlendSkyBox : public LLGLSPipelineDepthTestSkyBox -{ +class LLGLSPipelineBlendSkyBox : public LLGLSPipelineDepthTestSkyBox +{ public: - LLGLSPipelineBlendSkyBox(bool depth_test, bool depth_write); - LLGLEnable mBlend; + LLGLSPipelineBlendSkyBox(bool depth_test, bool depth_write); + LLGLEnable mBlend; }; class LLGLSTracker { protected: - LLGLEnable mCullFace, mBlend; + LLGLEnable mCullFace, mBlend; public: - LLGLSTracker() : - mCullFace(GL_CULL_FACE), - mBlend(GL_BLEND) - { } + LLGLSTracker() : + mCullFace(GL_CULL_FACE), + mBlend(GL_BLEND) + { } }; //---------------------------------------------------------------------------- @@ -169,26 +169,26 @@ public: class LLGLSSpecular { public: - F32 mShininess; - LLGLSSpecular(const LLColor4& color, F32 shininess) - { - mShininess = shininess; - if (mShininess > 0.0f) - { - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, color.mV); - S32 shiny = (S32)(shininess*128.f); - shiny = llclamp(shiny,0,128); - glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, shiny); - } - } - ~LLGLSSpecular() - { - if (mShininess > 0.f) - { - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, LLColor4(0.f,0.f,0.f,0.f).mV); - glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 0); - } - } + F32 mShininess; + LLGLSSpecular(const LLColor4& color, F32 shininess) + { + mShininess = shininess; + if (mShininess > 0.0f) + { + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, color.mV); + S32 shiny = (S32)(shininess*128.f); + shiny = llclamp(shiny,0,128); + glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, shiny); + } + } + ~LLGLSSpecular() + { + if (mShininess > 0.f) + { + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, LLColor4(0.f,0.f,0.f,0.f).mV); + glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 0); + } + } }; //---------------------------------------------------------------------------- diff --git a/indra/llrender/llgltypes.h b/indra/llrender/llgltypes.h index 6c217ef727..b593a0532f 100644 --- a/indra/llrender/llgltypes.h +++ b/indra/llrender/llgltypes.h @@ -1,25 +1,25 @@ -/** +/** * @file llgltypes.h * @brief LLGL definition * * $LicenseInfo:firstyear=2006&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$ */ diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 56a12b07b1..1609afb7ef 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llimagegl.cpp * @brief Generic GL image handler * * $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$ */ @@ -114,7 +114,7 @@ static void free_cur_tex_image() free_tex_image(texName); } -// static +// static U64 LLImageGL::getTextureBytesAllocated() { return sTextureBytes; @@ -122,12 +122,12 @@ U64 LLImageGL::getTextureBytesAllocated() //statics -U32 LLImageGL::sUniqueCount = 0; -U32 LLImageGL::sBindCount = 0; -S32 LLImageGL::sCount = 0; +U32 LLImageGL::sUniqueCount = 0; +U32 LLImageGL::sBindCount = 0; +S32 LLImageGL::sCount = 0; -BOOL LLImageGL::sGlobalUseAnisotropic = FALSE; -F32 LLImageGL::sLastFrameTime = 0.f; +BOOL LLImageGL::sGlobalUseAnisotropic = FALSE; +F32 LLImageGL::sLastFrameTime = 0.f; BOOL LLImageGL::sAllowReadBackRaw = FALSE ; LLImageGL* LLImageGL::sDefaultGLTexture = NULL ; bool LLImageGL::sCompressTextures = false; @@ -159,78 +159,78 @@ BOOL LLImageGL::sSkipAnalyzeAlpha; //do not delete them even though they are not currently being used. void check_all_images() { - for (std::set<LLImageGL*>::iterator iter = LLImageGL::sImageList.begin(); - iter != LLImageGL::sImageList.end(); iter++) - { - LLImageGL* glimage = *iter; - if (glimage->getTexName() && glimage->isGLTextureCreated()) - { - gGL.getTexUnit(0)->bind(glimage) ; - glimage->checkTexSize() ; - gGL.getTexUnit(0)->unbind(glimage->getTarget()) ; - } - } + for (std::set<LLImageGL*>::iterator iter = LLImageGL::sImageList.begin(); + iter != LLImageGL::sImageList.end(); iter++) + { + LLImageGL* glimage = *iter; + if (glimage->getTexName() && glimage->isGLTextureCreated()) + { + gGL.getTexUnit(0)->bind(glimage) ; + glimage->checkTexSize() ; + gGL.getTexUnit(0)->unbind(glimage->getTarget()) ; + } + } } void LLImageGL::checkTexSize(bool forced) const { - if ((forced || gDebugGL) && mTarget == GL_TEXTURE_2D) - { - { - //check viewport - GLint vp[4] ; - glGetIntegerv(GL_VIEWPORT, vp) ; - llcallstacks << "viewport: " << vp[0] << " : " << vp[1] << " : " << vp[2] << " : " << vp[3] << llcallstacksendl ; - } - - GLint texname; - glGetIntegerv(GL_TEXTURE_BINDING_2D, &texname); - BOOL error = FALSE; - if (texname != mTexName) - { - LL_INFOS() << "Bound: " << texname << " Should bind: " << mTexName << " Default: " << LLImageGL::sDefaultGLTexture->getTexName() << LL_ENDL; - - error = TRUE; - if (gDebugSession) - { - gFailLog << "Invalid texture bound!" << std::endl; - } - else - { - LL_ERRS() << "Invalid texture bound!" << LL_ENDL; - } - } - stop_glerror() ; - LLGLint x = 0, y = 0 ; - glGetTexLevelParameteriv(mTarget, 0, GL_TEXTURE_WIDTH, (GLint*)&x); - glGetTexLevelParameteriv(mTarget, 0, GL_TEXTURE_HEIGHT, (GLint*)&y) ; - stop_glerror() ; - llcallstacks << "w: " << x << " h: " << y << llcallstacksendl ; - - if(!x || !y) - { - return ; - } - if(x != (mWidth >> mCurrentDiscardLevel) || y != (mHeight >> mCurrentDiscardLevel)) - { - error = TRUE; - if (gDebugSession) - { - gFailLog << "wrong texture size and discard level!" << - mWidth << " Height: " << mHeight << " Current Level: " << (S32)mCurrentDiscardLevel << std::endl; - } - else - { - LL_ERRS() << "wrong texture size and discard level: width: " << - mWidth << " Height: " << mHeight << " Current Level: " << (S32)mCurrentDiscardLevel << LL_ENDL ; - } - } - - if (error) - { - ll_fail("LLImageGL::checkTexSize failed."); - } - } + if ((forced || gDebugGL) && mTarget == GL_TEXTURE_2D) + { + { + //check viewport + GLint vp[4] ; + glGetIntegerv(GL_VIEWPORT, vp) ; + llcallstacks << "viewport: " << vp[0] << " : " << vp[1] << " : " << vp[2] << " : " << vp[3] << llcallstacksendl ; + } + + GLint texname; + glGetIntegerv(GL_TEXTURE_BINDING_2D, &texname); + BOOL error = FALSE; + if (texname != mTexName) + { + LL_INFOS() << "Bound: " << texname << " Should bind: " << mTexName << " Default: " << LLImageGL::sDefaultGLTexture->getTexName() << LL_ENDL; + + error = TRUE; + if (gDebugSession) + { + gFailLog << "Invalid texture bound!" << std::endl; + } + else + { + LL_ERRS() << "Invalid texture bound!" << LL_ENDL; + } + } + stop_glerror() ; + LLGLint x = 0, y = 0 ; + glGetTexLevelParameteriv(mTarget, 0, GL_TEXTURE_WIDTH, (GLint*)&x); + glGetTexLevelParameteriv(mTarget, 0, GL_TEXTURE_HEIGHT, (GLint*)&y) ; + stop_glerror() ; + llcallstacks << "w: " << x << " h: " << y << llcallstacksendl ; + + if(!x || !y) + { + return ; + } + if(x != (mWidth >> mCurrentDiscardLevel) || y != (mHeight >> mCurrentDiscardLevel)) + { + error = TRUE; + if (gDebugSession) + { + gFailLog << "wrong texture size and discard level!" << + mWidth << " Height: " << mHeight << " Current Level: " << (S32)mCurrentDiscardLevel << std::endl; + } + else + { + LL_ERRS() << "wrong texture size and discard level: width: " << + mWidth << " Height: " << mHeight << " Current Level: " << (S32)mCurrentDiscardLevel << LL_ENDL ; + } + } + + if (error) + { + ll_fail("LLImageGL::checkTexSize failed."); + } + } } //end of debug functions //************************************************************************************** @@ -238,17 +238,17 @@ void LLImageGL::checkTexSize(bool forced) const //---------------------------------------------------------------------------- BOOL is_little_endian() { - S32 a = 0x12345678; + S32 a = 0x12345678; U8 *c = (U8*)(&a); - - return (*c == 0x78) ; + + return (*c == 0x78) ; } -//static +//static void LLImageGL::initClass(LLWindow* window, S32 num_catagories, BOOL skip_analyze_alpha /* = false */, bool thread_texture_loads /* = false */, bool thread_media_updates /* = false */) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - sSkipAnalyzeAlpha = skip_analyze_alpha; + sSkipAnalyzeAlpha = skip_analyze_alpha; if (thread_texture_loads || thread_media_updates) { @@ -258,8 +258,8 @@ void LLImageGL::initClass(LLWindow* window, S32 num_catagories, BOOL skip_analyz } } -//static -void LLImageGL::cleanupClass() +//static +void LLImageGL::cleanupClass() { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; LLImageGLThread::deleteSingleton(); @@ -271,23 +271,23 @@ S32 LLImageGL::dataFormatBits(S32 dataformat) { switch (dataformat) { - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return 4; + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return 4; case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: return 4; - case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: return 8; + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: return 8; case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: return 8; - case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: return 8; + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: return 8; case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: return 8; - case GL_LUMINANCE: return 8; - case GL_ALPHA: return 8; + case GL_LUMINANCE: return 8; + case GL_ALPHA: return 8; case GL_RED: return 8; - case GL_COLOR_INDEX: return 8; - case GL_LUMINANCE_ALPHA: return 16; - case GL_RGB: return 24; - case GL_SRGB: return 24; - case GL_RGB8: return 24; - case GL_RGBA: return 32; - case GL_SRGB_ALPHA: return 32; - case GL_BGRA: return 32; // Used for QuickTime media textures on the Mac + case GL_COLOR_INDEX: return 8; + case GL_LUMINANCE_ALPHA: return 16; + case GL_RGB: return 24; + case GL_SRGB: return 24; + case GL_RGB8: return 24; + case GL_RGBA: return 32; + case GL_SRGB_ALPHA: return 32; + case GL_BGRA: return 32; // Used for QuickTime media textures on the Mac case GL_DEPTH_COMPONENT: return 24; default: LL_ERRS() << "LLImageGL::Unknown format: " << dataformat << LL_ENDL; @@ -312,36 +312,36 @@ S64 LLImageGL::dataFormatBytes(S32 dataformat, S32 width, S32 height) default: break; } - S64 bytes (((S64)width * (S64)height * (S64)dataFormatBits(dataformat)+7)>>3); - S64 aligned = (bytes+3)&~3; - return aligned; + S64 bytes (((S64)width * (S64)height * (S64)dataFormatBits(dataformat)+7)>>3); + S64 aligned = (bytes+3)&~3; + return aligned; } //static S32 LLImageGL::dataFormatComponents(S32 dataformat) { - switch (dataformat) - { - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return 3; - case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: return 3; - case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: return 4; - case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: return 4; - case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: return 4; - case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: return 4; - case GL_LUMINANCE: return 1; - case GL_ALPHA: return 1; + switch (dataformat) + { + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return 3; + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: return 3; + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: return 4; + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: return 4; + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: return 4; + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: return 4; + case GL_LUMINANCE: return 1; + case GL_ALPHA: return 1; case GL_RED: return 1; - case GL_COLOR_INDEX: return 1; - case GL_LUMINANCE_ALPHA: return 2; - case GL_RGB: return 3; - case GL_SRGB: return 3; - case GL_RGBA: return 4; - case GL_SRGB_ALPHA: return 4; - case GL_BGRA: return 4; // Used for QuickTime media textures on the Mac - default: - LL_ERRS() << "LLImageGL::Unknown format: " << dataformat << LL_ENDL; - return 0; - } + case GL_COLOR_INDEX: return 1; + case GL_LUMINANCE_ALPHA: return 2; + case GL_RGB: return 3; + case GL_SRGB: return 3; + case GL_RGBA: return 4; + case GL_SRGB_ALPHA: return 4; + case GL_BGRA: return 4; // Used for QuickTime media textures on the Mac + default: + LL_ERRS() << "LLImageGL::Unknown format: " << dataformat << LL_ENDL; + return 0; + } } //---------------------------------------------------------------------------- @@ -350,131 +350,131 @@ S32 LLImageGL::dataFormatComponents(S32 dataformat) void LLImageGL::updateStats(F32 current_time) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - sLastFrameTime = current_time; + sLastFrameTime = current_time; } //---------------------------------------------------------------------------- -//static +//static void LLImageGL::destroyGL(BOOL save_state) { - for (S32 stage = 0; stage < gGLManager.mNumTextureImageUnits; stage++) - { - gGL.getTexUnit(stage)->unbind(LLTexUnit::TT_TEXTURE); - } - - sAllowReadBackRaw = true ; - for (std::set<LLImageGL*>::iterator iter = sImageList.begin(); - iter != sImageList.end(); iter++) - { - LLImageGL* glimage = *iter; - if (glimage->mTexName) - { - if (save_state && glimage->isGLTextureCreated() && glimage->mComponents) - { - glimage->mSaveData = new LLImageRaw; - if(!glimage->readBackRaw(glimage->mCurrentDiscardLevel, glimage->mSaveData, false)) //necessary, keep it. - { - glimage->mSaveData = NULL ; - } - } - - glimage->destroyGLTexture(); - stop_glerror(); - } - } - sAllowReadBackRaw = false ; -} - -//static + for (S32 stage = 0; stage < gGLManager.mNumTextureImageUnits; stage++) + { + gGL.getTexUnit(stage)->unbind(LLTexUnit::TT_TEXTURE); + } + + sAllowReadBackRaw = true ; + for (std::set<LLImageGL*>::iterator iter = sImageList.begin(); + iter != sImageList.end(); iter++) + { + LLImageGL* glimage = *iter; + if (glimage->mTexName) + { + if (save_state && glimage->isGLTextureCreated() && glimage->mComponents) + { + glimage->mSaveData = new LLImageRaw; + if(!glimage->readBackRaw(glimage->mCurrentDiscardLevel, glimage->mSaveData, false)) //necessary, keep it. + { + glimage->mSaveData = NULL ; + } + } + + glimage->destroyGLTexture(); + stop_glerror(); + } + } + sAllowReadBackRaw = false ; +} + +//static void LLImageGL::restoreGL() { - for (std::set<LLImageGL*>::iterator iter = sImageList.begin(); - iter != sImageList.end(); iter++) - { - LLImageGL* glimage = *iter; - if(glimage->getTexName()) - { - LL_ERRS() << "tex name is not 0." << LL_ENDL ; - } - if (glimage->mSaveData.notNull()) - { - if (glimage->getComponents() && glimage->mSaveData->getComponents()) - { - glimage->createGLTexture(glimage->mCurrentDiscardLevel, glimage->mSaveData, 0, TRUE, glimage->getCategory()); - stop_glerror(); - } - glimage->mSaveData = NULL; // deletes data - } - } -} - -//static + for (std::set<LLImageGL*>::iterator iter = sImageList.begin(); + iter != sImageList.end(); iter++) + { + LLImageGL* glimage = *iter; + if(glimage->getTexName()) + { + LL_ERRS() << "tex name is not 0." << LL_ENDL ; + } + if (glimage->mSaveData.notNull()) + { + if (glimage->getComponents() && glimage->mSaveData->getComponents()) + { + glimage->createGLTexture(glimage->mCurrentDiscardLevel, glimage->mSaveData, 0, TRUE, glimage->getCategory()); + stop_glerror(); + } + glimage->mSaveData = NULL; // deletes data + } + } +} + +//static void LLImageGL::dirtyTexOptions() { - for (std::set<LLImageGL*>::iterator iter = sImageList.begin(); - iter != sImageList.end(); iter++) - { - LLImageGL* glimage = *iter; - glimage->mTexOptionsDirty = true; - stop_glerror(); - } - + for (std::set<LLImageGL*>::iterator iter = sImageList.begin(); + iter != sImageList.end(); iter++) + { + LLImageGL* glimage = *iter; + glimage->mTexOptionsDirty = true; + stop_glerror(); + } + } //---------------------------------------------------------------------------- //for server side use only. -//static +//static BOOL LLImageGL::create(LLPointer<LLImageGL>& dest, BOOL usemipmaps) { - dest = new LLImageGL(usemipmaps); - return TRUE; + dest = new LLImageGL(usemipmaps); + return TRUE; } //for server side use only. BOOL LLImageGL::create(LLPointer<LLImageGL>& dest, U32 width, U32 height, U8 components, BOOL usemipmaps) { - dest = new LLImageGL(width, height, components, usemipmaps); - return TRUE; + dest = new LLImageGL(width, height, components, usemipmaps); + return TRUE; } //for server side use only. BOOL LLImageGL::create(LLPointer<LLImageGL>& dest, const LLImageRaw* imageraw, BOOL usemipmaps) { - dest = new LLImageGL(imageraw, usemipmaps); - return TRUE; + dest = new LLImageGL(imageraw, usemipmaps); + return TRUE; } //---------------------------------------------------------------------------- LLImageGL::LLImageGL(BOOL usemipmaps) -: mSaveData(0), mExternalTexture(FALSE) +: mSaveData(0), mExternalTexture(FALSE) { - init(usemipmaps); - setSize(0, 0, 0); - sImageList.insert(this); - sCount++; + init(usemipmaps); + setSize(0, 0, 0); + sImageList.insert(this); + sCount++; } LLImageGL::LLImageGL(U32 width, U32 height, U8 components, BOOL usemipmaps) -: mSaveData(0), mExternalTexture(FALSE) +: mSaveData(0), mExternalTexture(FALSE) { - llassert( components <= 4 ); - init(usemipmaps); - setSize(width, height, components); - sImageList.insert(this); - sCount++; + llassert( components <= 4 ); + init(usemipmaps); + setSize(width, height, components); + sImageList.insert(this); + sCount++; } LLImageGL::LLImageGL(const LLImageRaw* imageraw, BOOL usemipmaps) -: mSaveData(0), mExternalTexture(FALSE) +: mSaveData(0), mExternalTexture(FALSE) { - init(usemipmaps); - setSize(0, 0, 0); - sImageList.insert(this); - sCount++; + init(usemipmaps); + setSize(0, 0, 0); + sImageList.insert(this); + sCount++; - createGLTexture(0, imageraw); + createGLTexture(0, imageraw); } LLImageGL::LLImageGL( @@ -501,10 +501,10 @@ LLImageGL::~LLImageGL() { if (!mExternalTexture && gGLManager.mInited) { - LLImageGL::cleanup(); - sImageList.erase(this); - freePickMask(); - sCount--; + LLImageGL::cleanup(); + sImageList.erase(this); + freePickMask(); + sCount--; } } @@ -514,74 +514,74 @@ void LLImageGL::init(BOOL usemipmaps) mActiveThread = LLThread::currentID(); #endif - // keep these members in the same order as declared in llimagehl.h - // so that it is obvious by visual inspection if we forgot to - // init a field. - - mTextureMemory = S64Bytes(0); - mLastBindTime = 0.f; - - mPickMask = NULL; - mPickMaskWidth = 0; - mPickMaskHeight = 0; - mUseMipMaps = usemipmaps; - mHasExplicitFormat = FALSE; - - mIsMask = FALSE; - mNeedsAlphaAndPickMask = TRUE ; - mAlphaStride = 0 ; - mAlphaOffset = 0 ; - - mGLTextureCreated = FALSE ; - mTexName = 0; - mWidth = 0; - mHeight = 0; - mCurrentDiscardLevel = -1; - - mDiscardLevelInAtlas = -1 ; - mTexelsInAtlas = 0 ; - mTexelsInGLTexture = 0 ; - - mAllowCompression = true; - - mTarget = GL_TEXTURE_2D; - mBindTarget = LLTexUnit::TT_TEXTURE; - mHasMipMaps = false; - mMipLevels = -1; - - mIsResident = 0; - - mComponents = 0; - mMaxDiscardLevel = MAX_DISCARD_LEVEL; - - mTexOptionsDirty = true; - mAddressMode = LLTexUnit::TAM_WRAP; - mFilterOption = LLTexUnit::TFO_ANISOTROPIC; - - mFormatInternal = -1; - mFormatPrimary = (LLGLenum) 0; - mFormatType = GL_UNSIGNED_BYTE; - mFormatSwapBytes = FALSE; + // keep these members in the same order as declared in llimagehl.h + // so that it is obvious by visual inspection if we forgot to + // init a field. + + mTextureMemory = S64Bytes(0); + mLastBindTime = 0.f; + + mPickMask = NULL; + mPickMaskWidth = 0; + mPickMaskHeight = 0; + mUseMipMaps = usemipmaps; + mHasExplicitFormat = FALSE; + + mIsMask = FALSE; + mNeedsAlphaAndPickMask = TRUE ; + mAlphaStride = 0 ; + mAlphaOffset = 0 ; + + mGLTextureCreated = FALSE ; + mTexName = 0; + mWidth = 0; + mHeight = 0; + mCurrentDiscardLevel = -1; + + mDiscardLevelInAtlas = -1 ; + mTexelsInAtlas = 0 ; + mTexelsInGLTexture = 0 ; + + mAllowCompression = true; + + mTarget = GL_TEXTURE_2D; + mBindTarget = LLTexUnit::TT_TEXTURE; + mHasMipMaps = false; + mMipLevels = -1; + + mIsResident = 0; + + mComponents = 0; + mMaxDiscardLevel = MAX_DISCARD_LEVEL; + + mTexOptionsDirty = true; + mAddressMode = LLTexUnit::TAM_WRAP; + mFilterOption = LLTexUnit::TFO_ANISOTROPIC; + + mFormatInternal = -1; + mFormatPrimary = (LLGLenum) 0; + mFormatType = GL_UNSIGNED_BYTE; + mFormatSwapBytes = FALSE; #ifdef DEBUG_MISS - mMissed = FALSE; + mMissed = FALSE; #endif - mCategory = -1; + mCategory = -1; - // Sometimes we have to post work for the main thread. - mMainQueue = LL::WorkQueue::getInstance("mainloop"); + // Sometimes we have to post work for the main thread. + mMainQueue = LL::WorkQueue::getInstance("mainloop"); } void LLImageGL::cleanup() { - if (!gGLManager.mIsDisabled) - { - destroyGLTexture(); - } - freePickMask(); + if (!gGLManager.mIsDisabled) + { + destroyGLTexture(); + } + freePickMask(); - mSaveData = NULL; // deletes data + mSaveData = NULL; // deletes data } //---------------------------------------------------------------------------- @@ -590,62 +590,62 @@ void LLImageGL::cleanup() //so dim should be a positive number static bool check_power_of_two(S32 dim) { - if(dim < 0) - { - return false ; - } - if(!dim)//0 is a power-of-two number - { - return true ; - } - return !(dim & (dim - 1)) ; + if(dim < 0) + { + return false ; + } + if(!dim)//0 is a power-of-two number + { + return true ; + } + return !(dim & (dim - 1)) ; } //static bool LLImageGL::checkSize(S32 width, S32 height) { - return check_power_of_two(width) && check_power_of_two(height); + return check_power_of_two(width) && check_power_of_two(height); } bool LLImageGL::setSize(S32 width, S32 height, S32 ncomponents, S32 discard_level) { - if (width != mWidth || height != mHeight || ncomponents != mComponents) - { - // Check if dimensions are a power of two! - if (!checkSize(width, height)) - { - LL_WARNS() << llformat("Texture has non power of two dimension: %dx%d",width,height) << LL_ENDL; - return false; - } - - // pickmask validity depends on old image size, delete it - freePickMask(); - - mWidth = width; - mHeight = height; - mComponents = ncomponents; - if (ncomponents > 0) - { - mMaxDiscardLevel = 0; - while (width > 1 && height > 1 && mMaxDiscardLevel < MAX_DISCARD_LEVEL) - { - mMaxDiscardLevel++; - width >>= 1; - height >>= 1; - } - - if(discard_level > 0) - { - mMaxDiscardLevel = llmax(mMaxDiscardLevel, (S8)discard_level); - } - } - else - { - mMaxDiscardLevel = MAX_DISCARD_LEVEL; - } - } - - return true; + if (width != mWidth || height != mHeight || ncomponents != mComponents) + { + // Check if dimensions are a power of two! + if (!checkSize(width, height)) + { + LL_WARNS() << llformat("Texture has non power of two dimension: %dx%d",width,height) << LL_ENDL; + return false; + } + + // pickmask validity depends on old image size, delete it + freePickMask(); + + mWidth = width; + mHeight = height; + mComponents = ncomponents; + if (ncomponents > 0) + { + mMaxDiscardLevel = 0; + while (width > 1 && height > 1 && mMaxDiscardLevel < MAX_DISCARD_LEVEL) + { + mMaxDiscardLevel++; + width >>= 1; + height >>= 1; + } + + if(discard_level > 0) + { + mMaxDiscardLevel = llmax(mMaxDiscardLevel, (S8)discard_level); + } + } + else + { + mMaxDiscardLevel = MAX_DISCARD_LEVEL; + } + } + + return true; } //---------------------------------------------------------------------------- @@ -653,74 +653,74 @@ bool LLImageGL::setSize(S32 width, S32 height, S32 ncomponents, S32 discard_leve // virtual void LLImageGL::dump() { - LL_INFOS() << "mMaxDiscardLevel " << S32(mMaxDiscardLevel) - << " mLastBindTime " << mLastBindTime - << " mTarget " << S32(mTarget) - << " mBindTarget " << S32(mBindTarget) - << " mUseMipMaps " << S32(mUseMipMaps) - << " mHasMipMaps " << S32(mHasMipMaps) - << " mCurrentDiscardLevel " << S32(mCurrentDiscardLevel) - << " mFormatInternal " << S32(mFormatInternal) - << " mFormatPrimary " << S32(mFormatPrimary) - << " mFormatType " << S32(mFormatType) - << " mFormatSwapBytes " << S32(mFormatSwapBytes) - << " mHasExplicitFormat " << S32(mHasExplicitFormat) + LL_INFOS() << "mMaxDiscardLevel " << S32(mMaxDiscardLevel) + << " mLastBindTime " << mLastBindTime + << " mTarget " << S32(mTarget) + << " mBindTarget " << S32(mBindTarget) + << " mUseMipMaps " << S32(mUseMipMaps) + << " mHasMipMaps " << S32(mHasMipMaps) + << " mCurrentDiscardLevel " << S32(mCurrentDiscardLevel) + << " mFormatInternal " << S32(mFormatInternal) + << " mFormatPrimary " << S32(mFormatPrimary) + << " mFormatType " << S32(mFormatType) + << " mFormatSwapBytes " << S32(mFormatSwapBytes) + << " mHasExplicitFormat " << S32(mHasExplicitFormat) #if DEBUG_MISS - << " mMissed " << mMissed + << " mMissed " << mMissed #endif - << LL_ENDL; + << LL_ENDL; - LL_INFOS() << " mTextureMemory " << mTextureMemory - << " mTexNames " << mTexName - << " mIsResident " << S32(mIsResident) - << LL_ENDL; + LL_INFOS() << " mTextureMemory " << mTextureMemory + << " mTexNames " << mTexName + << " mIsResident " << S32(mIsResident) + << LL_ENDL; } //---------------------------------------------------------------------------- void LLImageGL::forceUpdateBindStats(void) const { - mLastBindTime = sLastFrameTime; + mLastBindTime = sLastFrameTime; } BOOL LLImageGL::updateBindStats() const -{ - if (mTexName != 0) - { +{ + if (mTexName != 0) + { #ifdef DEBUG_MISS - mMissed = ! getIsResident(TRUE); + mMissed = ! getIsResident(TRUE); #endif - sBindCount++; - if (mLastBindTime != sLastFrameTime) - { - // we haven't accounted for this texture yet this frame - sUniqueCount++; - mLastBindTime = sLastFrameTime; + sBindCount++; + if (mLastBindTime != sLastFrameTime) + { + // we haven't accounted for this texture yet this frame + sUniqueCount++; + mLastBindTime = sLastFrameTime; - return TRUE ; - } - } - return FALSE ; + return TRUE ; + } + } + return FALSE ; } F32 LLImageGL::getTimePassedSinceLastBound() { - return sLastFrameTime - mLastBindTime ; + return sLastFrameTime - mLastBindTime ; } void LLImageGL::setExplicitFormat( LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format, BOOL swap_bytes ) { - // Note: must be called before createTexture() - // Note: it's up to the caller to ensure that the format matches the number of components. - mHasExplicitFormat = TRUE; - mFormatInternal = internal_format; - mFormatPrimary = primary_format; - if(type_format == 0) - mFormatType = GL_UNSIGNED_BYTE; - else - mFormatType = type_format; - mFormatSwapBytes = swap_bytes; + // Note: must be called before createTexture() + // Note: it's up to the caller to ensure that the format matches the number of components. + mHasExplicitFormat = TRUE; + mFormatInternal = internal_format; + mFormatPrimary = primary_format; + if(type_format == 0) + mFormatType = GL_UNSIGNED_BYTE; + else + mFormatType = type_format; + mFormatSwapBytes = swap_bytes; - calcAlphaChannelOffsetAndStride() ; + calcAlphaChannelOffsetAndStride() ; } //---------------------------------------------------------------------------- @@ -728,33 +728,33 @@ void LLImageGL::setExplicitFormat( LLGLint internal_format, LLGLenum primary_for void LLImageGL::setImage(const LLImageRaw* imageraw) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - llassert((imageraw->getWidth() == getWidth(mCurrentDiscardLevel)) && - (imageraw->getHeight() == getHeight(mCurrentDiscardLevel)) && - (imageraw->getComponents() == getComponents())); - const U8* rawdata = imageraw->getData(); - setImage(rawdata, FALSE); + llassert((imageraw->getWidth() == getWidth(mCurrentDiscardLevel)) && + (imageraw->getHeight() == getHeight(mCurrentDiscardLevel)) && + (imageraw->getComponents() == getComponents())); + const U8* rawdata = imageraw->getData(); + setImage(rawdata, FALSE); } BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips /* = FALSE */, S32 usename /* = 0 */) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - const bool is_compressed = isCompressed(); - - if (mUseMipMaps) - { - //set has mip maps to true before binding image so tex parameters get set properly + const bool is_compressed = isCompressed(); + + if (mUseMipMaps) + { + //set has mip maps to true before binding image so tex parameters get set properly gGL.getTexUnit(0)->unbind(mBindTarget); - - mHasMipMaps = true; - mTexOptionsDirty = true; - setFilteringOption(LLTexUnit::TFO_ANISOTROPIC); - } - else - { - mHasMipMaps = false; - } - + + mHasMipMaps = true; + mTexOptionsDirty = true; + setFilteringOption(LLTexUnit::TFO_ANISOTROPIC); + } + else + { + mHasMipMaps = false; + } + gGL.getTexUnit(0)->bind(this, false, false, usename); if (data_in == nullptr) @@ -765,291 +765,291 @@ BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips /* = FALSE */, S32 mFormatPrimary, mFormatType, (GLvoid*)data_in, mAllowCompression); } else if (mUseMipMaps) - { - if (data_hasmips) - { - // NOTE: data_in points to largest image; smaller images - // are stored BEFORE the largest image - for (S32 d=mCurrentDiscardLevel; d<=mMaxDiscardLevel; d++) - { - - S32 w = getWidth(d); - S32 h = getHeight(d); - S32 gl_level = d-mCurrentDiscardLevel; - - mMipLevels = llmax(mMipLevels, gl_level); - - if (d > mCurrentDiscardLevel) - { - data_in -= dataFormatBytes(mFormatPrimary, w, h); // see above comment - } - if (is_compressed) - { - S32 tex_size = dataFormatBytes(mFormatPrimary, w, h); - glCompressedTexImage2D(mTarget, gl_level, mFormatPrimary, w, h, 0, tex_size, (GLvoid *)data_in); - stop_glerror(); - } - else - { - if(mFormatSwapBytes) - { - glPixelStorei(GL_UNPACK_SWAP_BYTES, 1); - stop_glerror(); - } - - LLImageGL::setManualImage(mTarget, gl_level, mFormatInternal, w, h, mFormatPrimary, GL_UNSIGNED_BYTE, (GLvoid*)data_in, mAllowCompression); - if (gl_level == 0) - { - analyzeAlpha(data_in, w, h); - } - updatePickMask(w, h, data_in); - - if(mFormatSwapBytes) - { - glPixelStorei(GL_UNPACK_SWAP_BYTES, 0); - stop_glerror(); - } - - stop_glerror(); - } - stop_glerror(); - } - } - else if (!is_compressed) - { - if (mAutoGenMips) - { - stop_glerror(); - { - if(mFormatSwapBytes) - { - glPixelStorei(GL_UNPACK_SWAP_BYTES, 1); - stop_glerror(); - } - - S32 w = getWidth(mCurrentDiscardLevel); - S32 h = getHeight(mCurrentDiscardLevel); - - mMipLevels = wpo2(llmax(w, h)); - - //use legacy mipmap generation mode (note: making this condional can cause rendering issues) - // -- but making it not conditional triggers deprecation warnings when core profile is enabled - // (some rendering issues while core profile is enabled are acceptable at this point in time) - if (!LLRender::sGLCoreProfile) - { - glTexParameteri(mTarget, GL_GENERATE_MIPMAP, GL_TRUE); - } + { + if (data_hasmips) + { + // NOTE: data_in points to largest image; smaller images + // are stored BEFORE the largest image + for (S32 d=mCurrentDiscardLevel; d<=mMaxDiscardLevel; d++) + { + + S32 w = getWidth(d); + S32 h = getHeight(d); + S32 gl_level = d-mCurrentDiscardLevel; + + mMipLevels = llmax(mMipLevels, gl_level); + + if (d > mCurrentDiscardLevel) + { + data_in -= dataFormatBytes(mFormatPrimary, w, h); // see above comment + } + if (is_compressed) + { + S32 tex_size = dataFormatBytes(mFormatPrimary, w, h); + glCompressedTexImage2D(mTarget, gl_level, mFormatPrimary, w, h, 0, tex_size, (GLvoid *)data_in); + stop_glerror(); + } + else + { + if(mFormatSwapBytes) + { + glPixelStorei(GL_UNPACK_SWAP_BYTES, 1); + stop_glerror(); + } + + LLImageGL::setManualImage(mTarget, gl_level, mFormatInternal, w, h, mFormatPrimary, GL_UNSIGNED_BYTE, (GLvoid*)data_in, mAllowCompression); + if (gl_level == 0) + { + analyzeAlpha(data_in, w, h); + } + updatePickMask(w, h, data_in); + + if(mFormatSwapBytes) + { + glPixelStorei(GL_UNPACK_SWAP_BYTES, 0); + stop_glerror(); + } + + stop_glerror(); + } + stop_glerror(); + } + } + else if (!is_compressed) + { + if (mAutoGenMips) + { + stop_glerror(); + { + if(mFormatSwapBytes) + { + glPixelStorei(GL_UNPACK_SWAP_BYTES, 1); + stop_glerror(); + } + + S32 w = getWidth(mCurrentDiscardLevel); + S32 h = getHeight(mCurrentDiscardLevel); + + mMipLevels = wpo2(llmax(w, h)); + + //use legacy mipmap generation mode (note: making this condional can cause rendering issues) + // -- but making it not conditional triggers deprecation warnings when core profile is enabled + // (some rendering issues while core profile is enabled are acceptable at this point in time) + if (!LLRender::sGLCoreProfile) + { + glTexParameteri(mTarget, GL_GENERATE_MIPMAP, GL_TRUE); + } LLImageGL::setManualImage(mTarget, 0, mFormatInternal, - w, h, - mFormatPrimary, mFormatType, - data_in, mAllowCompression); - analyzeAlpha(data_in, w, h); - stop_glerror(); - - updatePickMask(w, h, data_in); - - if(mFormatSwapBytes) - { - glPixelStorei(GL_UNPACK_SWAP_BYTES, 0); - stop_glerror(); - } - - if (LLRender::sGLCoreProfile) - { + w, h, + mFormatPrimary, mFormatType, + data_in, mAllowCompression); + analyzeAlpha(data_in, w, h); + stop_glerror(); + + updatePickMask(w, h, data_in); + + if(mFormatSwapBytes) + { + glPixelStorei(GL_UNPACK_SWAP_BYTES, 0); + stop_glerror(); + } + + if (LLRender::sGLCoreProfile) + { LL_PROFILE_GPU_ZONE("generate mip map"); - glGenerateMipmap(mTarget); - } - stop_glerror(); - } - } - else - { - // Create mips by hand - // ~4x faster than gluBuild2DMipmaps - S32 width = getWidth(mCurrentDiscardLevel); - S32 height = getHeight(mCurrentDiscardLevel); - S32 nummips = mMaxDiscardLevel - mCurrentDiscardLevel + 1; - S32 w = width, h = height; - - - const U8* new_data = 0; - (void)new_data; - - const U8* prev_mip_data = 0; - const U8* cur_mip_data = 0; + glGenerateMipmap(mTarget); + } + stop_glerror(); + } + } + else + { + // Create mips by hand + // ~4x faster than gluBuild2DMipmaps + S32 width = getWidth(mCurrentDiscardLevel); + S32 height = getHeight(mCurrentDiscardLevel); + S32 nummips = mMaxDiscardLevel - mCurrentDiscardLevel + 1; + S32 w = width, h = height; + + + const U8* new_data = 0; + (void)new_data; + + const U8* prev_mip_data = 0; + const U8* cur_mip_data = 0; #ifdef SHOW_ASSERT - S32 cur_mip_size = 0; + S32 cur_mip_size = 0; #endif - mMipLevels = nummips; + mMipLevels = nummips; - for (int m=0; m<nummips; m++) - { - if (m==0) - { - cur_mip_data = data_in; + for (int m=0; m<nummips; m++) + { + if (m==0) + { + cur_mip_data = data_in; #ifdef SHOW_ASSERT - cur_mip_size = width * height * mComponents; + cur_mip_size = width * height * mComponents; #endif - } - else - { - S32 bytes = w * h * mComponents; + } + else + { + S32 bytes = w * h * mComponents; #ifdef SHOW_ASSERT - llassert(prev_mip_data); - llassert(cur_mip_size == bytes*4); + llassert(prev_mip_data); + llassert(cur_mip_size == bytes*4); #endif - U8* new_data = new(std::nothrow) U8[bytes]; - if (!new_data) - { - stop_glerror(); - - if (prev_mip_data) - { - if (prev_mip_data != cur_mip_data) - delete[] prev_mip_data; - prev_mip_data = nullptr; - } - if (cur_mip_data) - { - delete[] cur_mip_data; - cur_mip_data = nullptr; - } - - mGLTextureCreated = false; - return FALSE; - } - else - { + U8* new_data = new(std::nothrow) U8[bytes]; + if (!new_data) + { + stop_glerror(); + + if (prev_mip_data) + { + if (prev_mip_data != cur_mip_data) + delete[] prev_mip_data; + prev_mip_data = nullptr; + } + if (cur_mip_data) + { + delete[] cur_mip_data; + cur_mip_data = nullptr; + } + + mGLTextureCreated = false; + return FALSE; + } + else + { #ifdef SHOW_ASSERT - llassert(prev_mip_data); - llassert(cur_mip_size == bytes * 4); + llassert(prev_mip_data); + llassert(cur_mip_size == bytes * 4); #endif - LLImageBase::generateMip(prev_mip_data, new_data, w, h, mComponents); - cur_mip_data = new_data; + LLImageBase::generateMip(prev_mip_data, new_data, w, h, mComponents); + cur_mip_data = new_data; #ifdef SHOW_ASSERT - cur_mip_size = bytes; + cur_mip_size = bytes; #endif - } - - } - llassert(w > 0 && h > 0 && cur_mip_data); - (void)cur_mip_data; - { - if(mFormatSwapBytes) - { - glPixelStorei(GL_UNPACK_SWAP_BYTES, 1); - stop_glerror(); - } + } + + } + llassert(w > 0 && h > 0 && cur_mip_data); + (void)cur_mip_data; + { + if(mFormatSwapBytes) + { + glPixelStorei(GL_UNPACK_SWAP_BYTES, 1); + stop_glerror(); + } LLImageGL::setManualImage(mTarget, m, mFormatInternal, w, h, mFormatPrimary, mFormatType, cur_mip_data, mAllowCompression); - if (m == 0) - { - analyzeAlpha(data_in, w, h); - } - stop_glerror(); - if (m == 0) - { - updatePickMask(w, h, cur_mip_data); - } - - if(mFormatSwapBytes) - { - glPixelStorei(GL_UNPACK_SWAP_BYTES, 0); - stop_glerror(); - } - } - if (prev_mip_data && prev_mip_data != data_in) - { - delete[] prev_mip_data; - } - prev_mip_data = cur_mip_data; - w >>= 1; - h >>= 1; - } - if (prev_mip_data && prev_mip_data != data_in) - { - delete[] prev_mip_data; - prev_mip_data = NULL; - } - } - } - else - { - LL_ERRS() << "Compressed Image has mipmaps but data does not (can not auto generate compressed mips)" << LL_ENDL; - } - } - else - { - mMipLevels = 0; - S32 w = getWidth(); - S32 h = getHeight(); - if (is_compressed) - { - S32 tex_size = dataFormatBytes(mFormatPrimary, w, h); - glCompressedTexImage2D(mTarget, 0, mFormatPrimary, w, h, 0, tex_size, (GLvoid *)data_in); - stop_glerror(); - } - else - { - if(mFormatSwapBytes) - { - glPixelStorei(GL_UNPACK_SWAP_BYTES, 1); - stop_glerror(); - } - - LLImageGL::setManualImage(mTarget, 0, mFormatInternal, w, h, - mFormatPrimary, mFormatType, (GLvoid *)data_in, mAllowCompression); - analyzeAlpha(data_in, w, h); - - updatePickMask(w, h, data_in); - - stop_glerror(); - - if(mFormatSwapBytes) - { - glPixelStorei(GL_UNPACK_SWAP_BYTES, 0); - stop_glerror(); - } - - } - } - stop_glerror(); - mGLTextureCreated = true; - return TRUE; + if (m == 0) + { + analyzeAlpha(data_in, w, h); + } + stop_glerror(); + if (m == 0) + { + updatePickMask(w, h, cur_mip_data); + } + + if(mFormatSwapBytes) + { + glPixelStorei(GL_UNPACK_SWAP_BYTES, 0); + stop_glerror(); + } + } + if (prev_mip_data && prev_mip_data != data_in) + { + delete[] prev_mip_data; + } + prev_mip_data = cur_mip_data; + w >>= 1; + h >>= 1; + } + if (prev_mip_data && prev_mip_data != data_in) + { + delete[] prev_mip_data; + prev_mip_data = NULL; + } + } + } + else + { + LL_ERRS() << "Compressed Image has mipmaps but data does not (can not auto generate compressed mips)" << LL_ENDL; + } + } + else + { + mMipLevels = 0; + S32 w = getWidth(); + S32 h = getHeight(); + if (is_compressed) + { + S32 tex_size = dataFormatBytes(mFormatPrimary, w, h); + glCompressedTexImage2D(mTarget, 0, mFormatPrimary, w, h, 0, tex_size, (GLvoid *)data_in); + stop_glerror(); + } + else + { + if(mFormatSwapBytes) + { + glPixelStorei(GL_UNPACK_SWAP_BYTES, 1); + stop_glerror(); + } + + LLImageGL::setManualImage(mTarget, 0, mFormatInternal, w, h, + mFormatPrimary, mFormatType, (GLvoid *)data_in, mAllowCompression); + analyzeAlpha(data_in, w, h); + + updatePickMask(w, h, data_in); + + stop_glerror(); + + if(mFormatSwapBytes) + { + glPixelStorei(GL_UNPACK_SWAP_BYTES, 0); + stop_glerror(); + } + + } + } + stop_glerror(); + mGLTextureCreated = true; + return TRUE; } BOOL LLImageGL::preAddToAtlas(S32 discard_level, const LLImageRaw* raw_image) { - //not compatible with core GL profile - llassert(!LLRender::sGLCoreProfile); - - if (gGLManager.mIsDisabled) - { - LL_WARNS() << "Trying to create a texture while GL is disabled!" << LL_ENDL; - return FALSE; - } - llassert(gGLManager.mInited); - stop_glerror(); - - if (discard_level < 0) - { - llassert(mCurrentDiscardLevel >= 0); - discard_level = mCurrentDiscardLevel; - } - - // Actual image width/height = raw image width/height * 2^discard_level - S32 w = raw_image->getWidth() << discard_level; - S32 h = raw_image->getHeight() << discard_level; - - // setSize may call destroyGLTexture if the size does not match - if (!setSize(w, h, raw_image->getComponents(), discard_level)) - { - LL_WARNS() << "Trying to create a texture with incorrect dimensions!" << LL_ENDL; - return FALSE; - } + //not compatible with core GL profile + llassert(!LLRender::sGLCoreProfile); + + if (gGLManager.mIsDisabled) + { + LL_WARNS() << "Trying to create a texture while GL is disabled!" << LL_ENDL; + return FALSE; + } + llassert(gGLManager.mInited); + stop_glerror(); + + if (discard_level < 0) + { + llassert(mCurrentDiscardLevel >= 0); + discard_level = mCurrentDiscardLevel; + } + + // Actual image width/height = raw image width/height * 2^discard_level + S32 w = raw_image->getWidth() << discard_level; + S32 h = raw_image->getHeight() << discard_level; + + // setSize may call destroyGLTexture if the size does not match + if (!setSize(w, h, raw_image->getComponents(), discard_level)) + { + LL_WARNS() << "Trying to create a texture with incorrect dimensions!" << LL_ENDL; + return FALSE; + } if (!mHasExplicitFormat) { @@ -1082,35 +1082,35 @@ BOOL LLImageGL::preAddToAtlas(S32 discard_level, const LLImageRaw* raw_image) } } - mCurrentDiscardLevel = discard_level; - mDiscardLevelInAtlas = discard_level; - mTexelsInAtlas = raw_image->getWidth() * raw_image->getHeight() ; - mLastBindTime = sLastFrameTime; - mGLTextureCreated = false ; - - glPixelStorei(GL_UNPACK_ROW_LENGTH, raw_image->getWidth()); - stop_glerror(); + mCurrentDiscardLevel = discard_level; + mDiscardLevelInAtlas = discard_level; + mTexelsInAtlas = raw_image->getWidth() * raw_image->getHeight() ; + mLastBindTime = sLastFrameTime; + mGLTextureCreated = false ; + + glPixelStorei(GL_UNPACK_ROW_LENGTH, raw_image->getWidth()); + stop_glerror(); - if(mFormatSwapBytes) - { - glPixelStorei(GL_UNPACK_SWAP_BYTES, 1); - stop_glerror(); - } + if(mFormatSwapBytes) + { + glPixelStorei(GL_UNPACK_SWAP_BYTES, 1); + stop_glerror(); + } - return TRUE ; + return TRUE ; } void LLImageGL::postAddToAtlas() { - if(mFormatSwapBytes) - { - glPixelStorei(GL_UNPACK_SWAP_BYTES, 0); - stop_glerror(); - } + if(mFormatSwapBytes) + { + glPixelStorei(GL_UNPACK_SWAP_BYTES, 0); + stop_glerror(); + } - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - gGL.getTexUnit(0)->setTextureFilteringOption(mFilterOption); - stop_glerror(); + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + gGL.getTexUnit(0)->setTextureFilteringOption(mFilterOption); + stop_glerror(); } U32 type_width_from_pixtype(U32 pixtype) @@ -1170,82 +1170,82 @@ void sub_image_lines(U32 target, S32 miplevel, S32 x_offset, S32 y_offset, S32 w BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update /* = FALSE */, LLGLuint use_name) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - if (!width || !height) - { - return TRUE; - } + if (!width || !height) + { + return TRUE; + } LLGLuint tex_name = use_name != 0 ? use_name : mTexName; - if (0 == tex_name) - { - // *TODO: Re-enable warning? Ran into thread locking issues? DK 2011-02-18 - //LL_WARNS() << "Setting subimage on image without GL texture" << LL_ENDL; - return FALSE; - } - if (datap == NULL) - { - // *TODO: Re-enable warning? Ran into thread locking issues? DK 2011-02-18 - //LL_WARNS() << "Setting subimage on image with NULL datap" << LL_ENDL; - return FALSE; - } - - // HACK: allow the caller to explicitly force the fast path (i.e. using glTexSubImage2D here instead of calling setImage) even when updating the full texture. - if (!force_fast_update && x_pos == 0 && y_pos == 0 && width == getWidth() && height == getHeight() && data_width == width && data_height == height) - { - setImage(datap, FALSE, tex_name); - } - else - { - if (mUseMipMaps) - { - dump(); - LL_ERRS() << "setSubImage called with mipmapped image (not supported)" << LL_ENDL; - } - llassert_always(mCurrentDiscardLevel == 0); - llassert_always(x_pos >= 0 && y_pos >= 0); - - if (((x_pos + width) > getWidth()) || - (y_pos + height) > getHeight()) - { - dump(); - LL_ERRS() << "Subimage not wholly in target image!" - << " x_pos " << x_pos - << " y_pos " << y_pos - << " width " << width - << " height " << height - << " getWidth() " << getWidth() - << " getHeight() " << getHeight() - << LL_ENDL; - } - - if ((x_pos + width) > data_width || - (y_pos + height) > data_height) - { - dump(); - LL_ERRS() << "Subimage not wholly in source image!" - << " x_pos " << x_pos - << " y_pos " << y_pos - << " width " << width - << " height " << height - << " source_width " << data_width - << " source_height " << data_height - << LL_ENDL; - } - - - glPixelStorei(GL_UNPACK_ROW_LENGTH, data_width); - stop_glerror(); - - if(mFormatSwapBytes) - { - glPixelStorei(GL_UNPACK_SWAP_BYTES, 1); - stop_glerror(); - } - - const U8* sub_datap = datap + (y_pos * data_width + x_pos) * getComponents(); - // Update the GL texture - BOOL res = gGL.getTexUnit(0)->bindManual(mBindTarget, tex_name); - if (!res) LL_ERRS() << "LLImageGL::setSubImage(): bindTexture failed" << LL_ENDL; - stop_glerror(); + if (0 == tex_name) + { + // *TODO: Re-enable warning? Ran into thread locking issues? DK 2011-02-18 + //LL_WARNS() << "Setting subimage on image without GL texture" << LL_ENDL; + return FALSE; + } + if (datap == NULL) + { + // *TODO: Re-enable warning? Ran into thread locking issues? DK 2011-02-18 + //LL_WARNS() << "Setting subimage on image with NULL datap" << LL_ENDL; + return FALSE; + } + + // HACK: allow the caller to explicitly force the fast path (i.e. using glTexSubImage2D here instead of calling setImage) even when updating the full texture. + if (!force_fast_update && x_pos == 0 && y_pos == 0 && width == getWidth() && height == getHeight() && data_width == width && data_height == height) + { + setImage(datap, FALSE, tex_name); + } + else + { + if (mUseMipMaps) + { + dump(); + LL_ERRS() << "setSubImage called with mipmapped image (not supported)" << LL_ENDL; + } + llassert_always(mCurrentDiscardLevel == 0); + llassert_always(x_pos >= 0 && y_pos >= 0); + + if (((x_pos + width) > getWidth()) || + (y_pos + height) > getHeight()) + { + dump(); + LL_ERRS() << "Subimage not wholly in target image!" + << " x_pos " << x_pos + << " y_pos " << y_pos + << " width " << width + << " height " << height + << " getWidth() " << getWidth() + << " getHeight() " << getHeight() + << LL_ENDL; + } + + if ((x_pos + width) > data_width || + (y_pos + height) > data_height) + { + dump(); + LL_ERRS() << "Subimage not wholly in source image!" + << " x_pos " << x_pos + << " y_pos " << y_pos + << " width " << width + << " height " << height + << " source_width " << data_width + << " source_height " << data_height + << LL_ENDL; + } + + + glPixelStorei(GL_UNPACK_ROW_LENGTH, data_width); + stop_glerror(); + + if(mFormatSwapBytes) + { + glPixelStorei(GL_UNPACK_SWAP_BYTES, 1); + stop_glerror(); + } + + const U8* sub_datap = datap + (y_pos * data_width + x_pos) * getComponents(); + // Update the GL texture + BOOL res = gGL.getTexUnit(0)->bindManual(mBindTarget, tex_name); + if (!res) LL_ERRS() << "LLImageGL::setSubImage(): bindTexture failed" << LL_ENDL; + stop_glerror(); const bool use_sub_image = should_stagger_image_set(isCompressed()); if (!use_sub_image) @@ -1260,42 +1260,42 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3 { sub_image_lines(mTarget, 0, x_pos, y_pos, width, height, mFormatPrimary, mFormatType, sub_datap, data_width); } - gGL.getTexUnit(0)->disable(); - stop_glerror(); + gGL.getTexUnit(0)->disable(); + stop_glerror(); - if(mFormatSwapBytes) - { - glPixelStorei(GL_UNPACK_SWAP_BYTES, 0); - stop_glerror(); - } + if(mFormatSwapBytes) + { + glPixelStorei(GL_UNPACK_SWAP_BYTES, 0); + stop_glerror(); + } - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - stop_glerror(); - mGLTextureCreated = true; - } - return TRUE; + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + stop_glerror(); + mGLTextureCreated = true; + } + return TRUE; } BOOL LLImageGL::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update /* = FALSE */, LLGLuint use_name) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - return setSubImage(imageraw->getData(), imageraw->getWidth(), imageraw->getHeight(), x_pos, y_pos, width, height, force_fast_update, use_name); + return setSubImage(imageraw->getData(), imageraw->getWidth(), imageraw->getHeight(), x_pos, y_pos, width, height, force_fast_update, use_name); } // Copy sub image from frame buffer BOOL LLImageGL::setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_pos, S32 width, S32 height) { - if (gGL.getTexUnit(0)->bind(this, false, true)) - { - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, fb_x, fb_y, x_pos, y_pos, width, height); - mGLTextureCreated = true; - stop_glerror(); - return TRUE; - } - else - { - return FALSE; - } + if (gGL.getTexUnit(0)->bind(this, false, true)) + { + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, fb_x, fb_y, x_pos, y_pos, width, height); + mGLTextureCreated = true; + stop_glerror(); + return TRUE; + } + else + { + return FALSE; + } } // static @@ -1330,11 +1330,11 @@ void LLImageGL::generateTextures(S32 numTextures, U32 *textures) // static void LLImageGL::deleteTextures(S32 numTextures, const U32 *textures) { - if (gGLManager.mInited) - { + if (gGLManager.mInited) + { free_tex_images(numTextures, textures); - glDeleteTextures(numTextures, textures); - } + glDeleteTextures(numTextures, textures); + } } // static @@ -1516,33 +1516,33 @@ BOOL LLImageGL::createGLTexture() LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; checkActiveThread(); - if (gGLManager.mIsDisabled) - { - LL_WARNS() << "Trying to create a texture while GL is disabled!" << LL_ENDL; - return FALSE; - } - - mGLTextureCreated = false ; //do not save this texture when gl is destroyed. + if (gGLManager.mIsDisabled) + { + LL_WARNS() << "Trying to create a texture while GL is disabled!" << LL_ENDL; + return FALSE; + } + + mGLTextureCreated = false ; //do not save this texture when gl is destroyed. - llassert(gGLManager.mInited); - stop_glerror(); + llassert(gGLManager.mInited); + stop_glerror(); - if(mTexName) - { - LLImageGL::deleteTextures(1, (reinterpret_cast<GLuint*>(&mTexName))) ; + if(mTexName) + { + LLImageGL::deleteTextures(1, (reinterpret_cast<GLuint*>(&mTexName))) ; mTexName = 0; - } - + } - LLImageGL::generateTextures(1, &mTexName); - stop_glerror(); - if (!mTexName) - { - LL_WARNS() << "LLImageGL::createGLTexture failed to make an empty texture" << LL_ENDL; - return FALSE; - } - return TRUE ; + LLImageGL::generateTextures(1, &mTexName); + stop_glerror(); + if (!mTexName) + { + LL_WARNS() << "LLImageGL::createGLTexture failed to make an empty texture" << LL_ENDL; + return FALSE; + } + + return TRUE ; } BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/, BOOL to_create, S32 category, bool defer_copy, LLGLuint* tex_name) @@ -1550,54 +1550,54 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; checkActiveThread(); - if (gGLManager.mIsDisabled) - { - LL_WARNS() << "Trying to create a texture while GL is disabled!" << LL_ENDL; - return FALSE; - } + if (gGLManager.mIsDisabled) + { + LL_WARNS() << "Trying to create a texture while GL is disabled!" << LL_ENDL; + return FALSE; + } - llassert(gGLManager.mInited); - stop_glerror(); + llassert(gGLManager.mInited); + stop_glerror(); - if (!imageraw || imageraw->isBufferInvalid()) - { - LL_WARNS() << "Trying to create a texture from invalid image data" << LL_ENDL; + if (!imageraw || imageraw->isBufferInvalid()) + { + LL_WARNS() << "Trying to create a texture from invalid image data" << LL_ENDL; mGLTextureCreated = false; - return FALSE; - } - - if (discard_level < 0) - { - llassert(mCurrentDiscardLevel >= 0); - discard_level = mCurrentDiscardLevel; - } - - // Actual image width/height = raw image width/height * 2^discard_level - S32 raw_w = imageraw->getWidth() ; - S32 raw_h = imageraw->getHeight() ; - - S32 w = raw_w << discard_level; - S32 h = raw_h << discard_level; - - // setSize may call destroyGLTexture if the size does not match - if (!setSize(w, h, imageraw->getComponents(), discard_level)) - { - LL_WARNS() << "Trying to create a texture with incorrect dimensions!" << LL_ENDL; + return FALSE; + } + + if (discard_level < 0) + { + llassert(mCurrentDiscardLevel >= 0); + discard_level = mCurrentDiscardLevel; + } + + // Actual image width/height = raw image width/height * 2^discard_level + S32 raw_w = imageraw->getWidth() ; + S32 raw_h = imageraw->getHeight() ; + + S32 w = raw_w << discard_level; + S32 h = raw_h << discard_level; + + // setSize may call destroyGLTexture if the size does not match + if (!setSize(w, h, imageraw->getComponents(), discard_level)) + { + LL_WARNS() << "Trying to create a texture with incorrect dimensions!" << LL_ENDL; mGLTextureCreated = false; - return FALSE; - } + return FALSE; + } - if (mHasExplicitFormat && - ((mFormatPrimary == GL_RGBA && mComponents < 4) || - (mFormatPrimary == GL_RGB && mComponents < 3))) + if (mHasExplicitFormat && + ((mFormatPrimary == GL_RGBA && mComponents < 4) || + (mFormatPrimary == GL_RGB && mComponents < 3))) - { - LL_WARNS() << "Incorrect format: " << std::hex << mFormatPrimary << " components: " << (U32)mComponents << LL_ENDL; - mHasExplicitFormat = FALSE; - } + { + LL_WARNS() << "Incorrect format: " << std::hex << mFormatPrimary << " components: " << (U32)mComponents << LL_ENDL; + mHasExplicitFormat = FALSE; + } - if( !mHasExplicitFormat ) - { + if( !mHasExplicitFormat ) + { switch (mComponents) { case 1: @@ -1626,21 +1626,21 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S LL_ERRS() << "Bad number of components for texture: " << (U32)getComponents() << LL_ENDL; } - calcAlphaChannelOffsetAndStride() ; - } + calcAlphaChannelOffsetAndStride() ; + } - if(!to_create) //not create a gl texture - { - destroyGLTexture(); - mCurrentDiscardLevel = discard_level; - mLastBindTime = sLastFrameTime; + if(!to_create) //not create a gl texture + { + destroyGLTexture(); + mCurrentDiscardLevel = discard_level; + mLastBindTime = sLastFrameTime; mGLTextureCreated = false; - return TRUE ; - } + return TRUE ; + } - setCategory(category); - const U8* rawdata = imageraw->getData(); - return createGLTexture(discard_level, rawdata, FALSE, usename, defer_copy, tex_name); + setCategory(category); + const U8* rawdata = imageraw->getData(); + return createGLTexture(discard_level, rawdata, FALSE, usename, defer_copy, tex_name); } BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips, S32 usename, bool defer_copy, LLGLuint* tex_name) @@ -1746,7 +1746,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_ } } - + mTextureMemory = (S64Bytes)getMipBytes(mCurrentDiscardLevel); mTexelsInGLTexture = getWidth() * getHeight(); @@ -1826,302 +1826,302 @@ void LLImageGL::syncTexName(LLGLuint texname) BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const { - llassert_always(sAllowReadBackRaw) ; - //LL_ERRS() << "should not call this function!" << LL_ENDL ; - - if (discard_level < 0) - { - discard_level = mCurrentDiscardLevel; - } - - if (mTexName == 0 || discard_level < mCurrentDiscardLevel || discard_level > mMaxDiscardLevel ) - { - return FALSE; - } - - S32 gl_discard = discard_level - mCurrentDiscardLevel; - - //explicitly unbind texture - gGL.getTexUnit(0)->unbind(mBindTarget); - llverify(gGL.getTexUnit(0)->bindManual(mBindTarget, mTexName)); - - //debug code, leave it there commented. - //checkTexSize() ; - - LLGLint glwidth = 0; - glGetTexLevelParameteriv(mTarget, gl_discard, GL_TEXTURE_WIDTH, (GLint*)&glwidth); - if (glwidth == 0) - { - // No mip data smaller than current discard level - return FALSE; - } - - S32 width = getWidth(discard_level); - S32 height = getHeight(discard_level); - S32 ncomponents = getComponents(); - if (ncomponents == 0) - { - return FALSE; - } - if(width < glwidth) - { - LL_WARNS() << "texture size is smaller than it should be." << LL_ENDL ; - LL_WARNS() << "width: " << width << " glwidth: " << glwidth << " mWidth: " << mWidth << - " mCurrentDiscardLevel: " << (S32)mCurrentDiscardLevel << " discard_level: " << (S32)discard_level << LL_ENDL ; - return FALSE ; - } - - if (width <= 0 || width > 2048 || height <= 0 || height > 2048 || ncomponents < 1 || ncomponents > 4) - { - LL_ERRS() << llformat("LLImageGL::readBackRaw: bogus params: %d x %d x %d",width,height,ncomponents) << LL_ENDL; - } - - LLGLint is_compressed = 0; - if (compressed_ok) - { - glGetTexLevelParameteriv(mTarget, is_compressed, GL_TEXTURE_COMPRESSED, (GLint*)&is_compressed); - } - - //----------------------------------------------------------------------------------------------- - GLenum error ; - while((error = glGetError()) != GL_NO_ERROR) - { - LL_WARNS() << "GL Error happens before reading back texture. Error code: " << error << LL_ENDL ; - } - //----------------------------------------------------------------------------------------------- - - if (is_compressed) - { - LLGLint glbytes; - glGetTexLevelParameteriv(mTarget, gl_discard, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, (GLint*)&glbytes); - if(!imageraw->allocateDataSize(width, height, ncomponents, glbytes)) - { - LL_WARNS() << "Memory allocation failed for reading back texture. Size is: " << glbytes << LL_ENDL ; - LL_WARNS() << "width: " << width << "height: " << height << "components: " << ncomponents << LL_ENDL ; - return FALSE ; - } - - glGetCompressedTexImage(mTarget, gl_discard, (GLvoid*)(imageraw->getData())); - //stop_glerror(); - } - else - { - if(!imageraw->allocateDataSize(width, height, ncomponents)) - { - LL_WARNS() << "Memory allocation failed for reading back texture." << LL_ENDL ; - LL_WARNS() << "width: " << width << "height: " << height << "components: " << ncomponents << LL_ENDL ; - return FALSE ; - } - - glGetTexImage(GL_TEXTURE_2D, gl_discard, mFormatPrimary, mFormatType, (GLvoid*)(imageraw->getData())); - //stop_glerror(); - } - - //----------------------------------------------------------------------------------------------- - if((error = glGetError()) != GL_NO_ERROR) - { - LL_WARNS() << "GL Error happens after reading back texture. Error code: " << error << LL_ENDL ; - imageraw->deleteData() ; - - while((error = glGetError()) != GL_NO_ERROR) - { - LL_WARNS() << "GL Error happens after reading back texture. Error code: " << error << LL_ENDL ; - } - - return FALSE ; - } - //----------------------------------------------------------------------------------------------- - - return TRUE ; + llassert_always(sAllowReadBackRaw) ; + //LL_ERRS() << "should not call this function!" << LL_ENDL ; + + if (discard_level < 0) + { + discard_level = mCurrentDiscardLevel; + } + + if (mTexName == 0 || discard_level < mCurrentDiscardLevel || discard_level > mMaxDiscardLevel ) + { + return FALSE; + } + + S32 gl_discard = discard_level - mCurrentDiscardLevel; + + //explicitly unbind texture + gGL.getTexUnit(0)->unbind(mBindTarget); + llverify(gGL.getTexUnit(0)->bindManual(mBindTarget, mTexName)); + + //debug code, leave it there commented. + //checkTexSize() ; + + LLGLint glwidth = 0; + glGetTexLevelParameteriv(mTarget, gl_discard, GL_TEXTURE_WIDTH, (GLint*)&glwidth); + if (glwidth == 0) + { + // No mip data smaller than current discard level + return FALSE; + } + + S32 width = getWidth(discard_level); + S32 height = getHeight(discard_level); + S32 ncomponents = getComponents(); + if (ncomponents == 0) + { + return FALSE; + } + if(width < glwidth) + { + LL_WARNS() << "texture size is smaller than it should be." << LL_ENDL ; + LL_WARNS() << "width: " << width << " glwidth: " << glwidth << " mWidth: " << mWidth << + " mCurrentDiscardLevel: " << (S32)mCurrentDiscardLevel << " discard_level: " << (S32)discard_level << LL_ENDL ; + return FALSE ; + } + + if (width <= 0 || width > 2048 || height <= 0 || height > 2048 || ncomponents < 1 || ncomponents > 4) + { + LL_ERRS() << llformat("LLImageGL::readBackRaw: bogus params: %d x %d x %d",width,height,ncomponents) << LL_ENDL; + } + + LLGLint is_compressed = 0; + if (compressed_ok) + { + glGetTexLevelParameteriv(mTarget, is_compressed, GL_TEXTURE_COMPRESSED, (GLint*)&is_compressed); + } + + //----------------------------------------------------------------------------------------------- + GLenum error ; + while((error = glGetError()) != GL_NO_ERROR) + { + LL_WARNS() << "GL Error happens before reading back texture. Error code: " << error << LL_ENDL ; + } + //----------------------------------------------------------------------------------------------- + + if (is_compressed) + { + LLGLint glbytes; + glGetTexLevelParameteriv(mTarget, gl_discard, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, (GLint*)&glbytes); + if(!imageraw->allocateDataSize(width, height, ncomponents, glbytes)) + { + LL_WARNS() << "Memory allocation failed for reading back texture. Size is: " << glbytes << LL_ENDL ; + LL_WARNS() << "width: " << width << "height: " << height << "components: " << ncomponents << LL_ENDL ; + return FALSE ; + } + + glGetCompressedTexImage(mTarget, gl_discard, (GLvoid*)(imageraw->getData())); + //stop_glerror(); + } + else + { + if(!imageraw->allocateDataSize(width, height, ncomponents)) + { + LL_WARNS() << "Memory allocation failed for reading back texture." << LL_ENDL ; + LL_WARNS() << "width: " << width << "height: " << height << "components: " << ncomponents << LL_ENDL ; + return FALSE ; + } + + glGetTexImage(GL_TEXTURE_2D, gl_discard, mFormatPrimary, mFormatType, (GLvoid*)(imageraw->getData())); + //stop_glerror(); + } + + //----------------------------------------------------------------------------------------------- + if((error = glGetError()) != GL_NO_ERROR) + { + LL_WARNS() << "GL Error happens after reading back texture. Error code: " << error << LL_ENDL ; + imageraw->deleteData() ; + + while((error = glGetError()) != GL_NO_ERROR) + { + LL_WARNS() << "GL Error happens after reading back texture. Error code: " << error << LL_ENDL ; + } + + return FALSE ; + } + //----------------------------------------------------------------------------------------------- + + return TRUE ; } void LLImageGL::destroyGLTexture() { checkActiveThread(); - if (mTexName != 0) - { - if(mTextureMemory != S64Bytes(0)) - { - mTextureMemory = (S64Bytes)0; - } - - LLImageGL::deleteTextures(1, &mTexName); - mCurrentDiscardLevel = -1 ; //invalidate mCurrentDiscardLevel. - mTexName = 0; - mGLTextureCreated = FALSE ; - } + if (mTexName != 0) + { + if(mTextureMemory != S64Bytes(0)) + { + mTextureMemory = (S64Bytes)0; + } + + LLImageGL::deleteTextures(1, &mTexName); + mCurrentDiscardLevel = -1 ; //invalidate mCurrentDiscardLevel. + mTexName = 0; + mGLTextureCreated = FALSE ; + } } //force to invalidate the gl texture, most likely a sculpty texture void LLImageGL::forceToInvalidateGLTexture() { checkActiveThread(); - if (mTexName != 0) - { - destroyGLTexture(); - } - else - { - mCurrentDiscardLevel = -1 ; //invalidate mCurrentDiscardLevel. - } + if (mTexName != 0) + { + destroyGLTexture(); + } + else + { + mCurrentDiscardLevel = -1 ; //invalidate mCurrentDiscardLevel. + } } //---------------------------------------------------------------------------- void LLImageGL::setAddressMode(LLTexUnit::eTextureAddressMode mode) { - if (mAddressMode != mode) - { - mTexOptionsDirty = true; - mAddressMode = mode; - } + if (mAddressMode != mode) + { + mTexOptionsDirty = true; + mAddressMode = mode; + } - if (gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->getCurrTexture() == mTexName) - { - gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->setTextureAddressMode(mode); - mTexOptionsDirty = false; - } + if (gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->getCurrTexture() == mTexName) + { + gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->setTextureAddressMode(mode); + mTexOptionsDirty = false; + } } void LLImageGL::setFilteringOption(LLTexUnit::eTextureFilterOptions option) { - if (mFilterOption != option) - { - mTexOptionsDirty = true; - mFilterOption = option; - } + if (mFilterOption != option) + { + mTexOptionsDirty = true; + mFilterOption = option; + } - if (mTexName != 0 && gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->getCurrTexture() == mTexName) - { - gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->setTextureFilteringOption(option); - mTexOptionsDirty = false; - stop_glerror(); - } + if (mTexName != 0 && gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->getCurrTexture() == mTexName) + { + gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->setTextureFilteringOption(option); + mTexOptionsDirty = false; + stop_glerror(); + } } BOOL LLImageGL::getIsResident(BOOL test_now) { - if (test_now) - { - if (mTexName != 0) - { - glAreTexturesResident(1, (GLuint*)&mTexName, &mIsResident); - } - else - { - mIsResident = FALSE; - } - } + if (test_now) + { + if (mTexName != 0) + { + glAreTexturesResident(1, (GLuint*)&mTexName, &mIsResident); + } + else + { + mIsResident = FALSE; + } + } - return mIsResident; + return mIsResident; } S32 LLImageGL::getHeight(S32 discard_level) const { - if (discard_level < 0) - { - discard_level = mCurrentDiscardLevel; - } - S32 height = mHeight >> discard_level; - if (height < 1) height = 1; - return height; + if (discard_level < 0) + { + discard_level = mCurrentDiscardLevel; + } + S32 height = mHeight >> discard_level; + if (height < 1) height = 1; + return height; } S32 LLImageGL::getWidth(S32 discard_level) const { - if (discard_level < 0) - { - discard_level = mCurrentDiscardLevel; - } - S32 width = mWidth >> discard_level; - if (width < 1) width = 1; - return width; + if (discard_level < 0) + { + discard_level = mCurrentDiscardLevel; + } + S32 width = mWidth >> discard_level; + if (width < 1) width = 1; + return width; } S64 LLImageGL::getBytes(S32 discard_level) const { - if (discard_level < 0) - { - discard_level = mCurrentDiscardLevel; - } - S32 w = mWidth>>discard_level; - S32 h = mHeight>>discard_level; - if (w == 0) w = 1; - if (h == 0) h = 1; - return dataFormatBytes(mFormatPrimary, w, h); + if (discard_level < 0) + { + discard_level = mCurrentDiscardLevel; + } + S32 w = mWidth>>discard_level; + S32 h = mHeight>>discard_level; + if (w == 0) w = 1; + if (h == 0) h = 1; + return dataFormatBytes(mFormatPrimary, w, h); } S64 LLImageGL::getMipBytes(S32 discard_level) const { - if (discard_level < 0) - { - discard_level = mCurrentDiscardLevel; - } - S32 w = mWidth>>discard_level; - S32 h = mHeight>>discard_level; - S64 res = dataFormatBytes(mFormatPrimary, w, h); - if (mUseMipMaps) - { - while (w > 1 && h > 1) - { - w >>= 1; if (w == 0) w = 1; - h >>= 1; if (h == 0) h = 1; - res += dataFormatBytes(mFormatPrimary, w, h); - } - } - return res; + if (discard_level < 0) + { + discard_level = mCurrentDiscardLevel; + } + S32 w = mWidth>>discard_level; + S32 h = mHeight>>discard_level; + S64 res = dataFormatBytes(mFormatPrimary, w, h); + if (mUseMipMaps) + { + while (w > 1 && h > 1) + { + w >>= 1; if (w == 0) w = 1; + h >>= 1; if (h == 0) h = 1; + res += dataFormatBytes(mFormatPrimary, w, h); + } + } + return res; } BOOL LLImageGL::isJustBound() const { - return (BOOL)(sLastFrameTime - mLastBindTime < 0.5f); + return (BOOL)(sLastFrameTime - mLastBindTime < 0.5f); } BOOL LLImageGL::getBoundRecently() const { - return (BOOL)(sLastFrameTime - mLastBindTime < MIN_TEXTURE_LIFETIME); + return (BOOL)(sLastFrameTime - mLastBindTime < MIN_TEXTURE_LIFETIME); } BOOL LLImageGL::getIsAlphaMask() const { - llassert_always(!sSkipAnalyzeAlpha); - return mIsMask; + llassert_always(!sSkipAnalyzeAlpha); + return mIsMask; } void LLImageGL::setTarget(const LLGLenum target, const LLTexUnit::eTextureType bind_target) { - mTarget = target; - mBindTarget = bind_target; + mTarget = target; + mBindTarget = bind_target; } const S8 INVALID_OFFSET = -99 ; -void LLImageGL::setNeedsAlphaAndPickMask(BOOL need_mask) +void LLImageGL::setNeedsAlphaAndPickMask(BOOL need_mask) { - if(mNeedsAlphaAndPickMask != need_mask) - { - mNeedsAlphaAndPickMask = need_mask; + if(mNeedsAlphaAndPickMask != need_mask) + { + mNeedsAlphaAndPickMask = need_mask; - if(mNeedsAlphaAndPickMask) - { - mAlphaOffset = 0 ; - } - else //do not need alpha mask - { - mAlphaOffset = INVALID_OFFSET ; - mIsMask = FALSE; - } - } + if(mNeedsAlphaAndPickMask) + { + mAlphaOffset = 0 ; + } + else //do not need alpha mask + { + mAlphaOffset = INVALID_OFFSET ; + mIsMask = FALSE; + } + } } void LLImageGL::calcAlphaChannelOffsetAndStride() { - if(mAlphaOffset == INVALID_OFFSET)//do not need alpha mask - { - return ; - } + if(mAlphaOffset == INVALID_OFFSET)//do not need alpha mask + { + return ; + } - mAlphaStride = -1 ; + mAlphaStride = -1 ; switch (mFormatPrimary) { case GL_LUMINANCE: @@ -2148,173 +2148,173 @@ void LLImageGL::calcAlphaChannelOffsetAndStride() break; } - mAlphaOffset = -1 ; - if (mFormatType == GL_UNSIGNED_BYTE) - { - mAlphaOffset = mAlphaStride - 1 ; - } - else if(is_little_endian()) - { - if (mFormatType == GL_UNSIGNED_INT_8_8_8_8) - { - mAlphaOffset = 0 ; - } - else if (mFormatType == GL_UNSIGNED_INT_8_8_8_8_REV) - { - mAlphaOffset = 3 ; - } - } - else //big endian - { - if (mFormatType == GL_UNSIGNED_INT_8_8_8_8) - { - mAlphaOffset = 3 ; - } - else if (mFormatType == GL_UNSIGNED_INT_8_8_8_8_REV) - { - mAlphaOffset = 0 ; - } - } - - if( mAlphaStride < 1 || //unsupported format - mAlphaOffset < 0 || //unsupported type - (mFormatPrimary == GL_BGRA_EXT && mFormatType != GL_UNSIGNED_BYTE)) //unknown situation - { - LL_WARNS() << "Cannot analyze alpha for image with format type " << std::hex << mFormatType << std::dec << LL_ENDL; - - mNeedsAlphaAndPickMask = FALSE ; - mIsMask = FALSE; - } + mAlphaOffset = -1 ; + if (mFormatType == GL_UNSIGNED_BYTE) + { + mAlphaOffset = mAlphaStride - 1 ; + } + else if(is_little_endian()) + { + if (mFormatType == GL_UNSIGNED_INT_8_8_8_8) + { + mAlphaOffset = 0 ; + } + else if (mFormatType == GL_UNSIGNED_INT_8_8_8_8_REV) + { + mAlphaOffset = 3 ; + } + } + else //big endian + { + if (mFormatType == GL_UNSIGNED_INT_8_8_8_8) + { + mAlphaOffset = 3 ; + } + else if (mFormatType == GL_UNSIGNED_INT_8_8_8_8_REV) + { + mAlphaOffset = 0 ; + } + } + + if( mAlphaStride < 1 || //unsupported format + mAlphaOffset < 0 || //unsupported type + (mFormatPrimary == GL_BGRA_EXT && mFormatType != GL_UNSIGNED_BYTE)) //unknown situation + { + LL_WARNS() << "Cannot analyze alpha for image with format type " << std::hex << mFormatType << std::dec << LL_ENDL; + + mNeedsAlphaAndPickMask = FALSE ; + mIsMask = FALSE; + } } void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h) { - if(sSkipAnalyzeAlpha || !mNeedsAlphaAndPickMask) - { - return ; - } - - U32 length = w * h; - U32 alphatotal = 0; - - U32 sample[16]; - memset(sample, 0, sizeof(U32)*16); - - // generate histogram of quantized alpha. - // also add-in the histogram of a 2x2 box-sampled version. The idea is - // this will mid-skew the data (and thus increase the chances of not - // being used as a mask) from high-frequency alpha maps which - // suffer the worst from aliasing when used as alpha masks. - if (w >= 2 && h >= 2) - { - llassert(w%2 == 0); - llassert(h%2 == 0); - const GLubyte* rowstart = ((const GLubyte*) data_in) + mAlphaOffset; - for (U32 y = 0; y < h; y+=2) - { - const GLubyte* current = rowstart; - for (U32 x = 0; x < w; x+=2) - { - const U32 s1 = current[0]; - alphatotal += s1; - const U32 s2 = current[w * mAlphaStride]; - alphatotal += s2; - current += mAlphaStride; - const U32 s3 = current[0]; - alphatotal += s3; - const U32 s4 = current[w * mAlphaStride]; - alphatotal += s4; - current += mAlphaStride; - - ++sample[s1/16]; - ++sample[s2/16]; - ++sample[s3/16]; - ++sample[s4/16]; - - const U32 asum = (s1+s2+s3+s4); - alphatotal += asum; - sample[asum/(16*4)] += 4; - } - - - rowstart += 2 * w * mAlphaStride; - } - length *= 2; // we sampled everything twice, essentially - } - else - { - const GLubyte* current = ((const GLubyte*) data_in) + mAlphaOffset; - for (U32 i = 0; i < length; i++) - { - const U32 s1 = *current; - alphatotal += s1; - ++sample[s1/16]; - current += mAlphaStride; - } - } - - // if more than 1/16th of alpha samples are mid-range, this - // shouldn't be treated as a 1-bit mask - - // also, if all of the alpha samples are clumped on one half - // of the range (but not at an absolute extreme), then consider - // this to be an intentional effect and don't treat as a mask. - - U32 midrangetotal = 0; - for (U32 i = 2; i < 13; i++) - { - midrangetotal += sample[i]; - } - U32 lowerhalftotal = 0; - for (U32 i = 0; i < 8; i++) - { - lowerhalftotal += sample[i]; - } - U32 upperhalftotal = 0; - for (U32 i = 8; i < 16; i++) - { - upperhalftotal += sample[i]; - } - - if (midrangetotal > length/48 || // lots of midrange, or - (lowerhalftotal == length && alphatotal != 0) || // all close to transparent but not all totally transparent, or - (upperhalftotal == length && alphatotal != 255*length)) // all close to opaque but not all totally opaque - { - mIsMask = FALSE; // not suitable for masking - } - else - { - mIsMask = TRUE; - } + if(sSkipAnalyzeAlpha || !mNeedsAlphaAndPickMask) + { + return ; + } + + U32 length = w * h; + U32 alphatotal = 0; + + U32 sample[16]; + memset(sample, 0, sizeof(U32)*16); + + // generate histogram of quantized alpha. + // also add-in the histogram of a 2x2 box-sampled version. The idea is + // this will mid-skew the data (and thus increase the chances of not + // being used as a mask) from high-frequency alpha maps which + // suffer the worst from aliasing when used as alpha masks. + if (w >= 2 && h >= 2) + { + llassert(w%2 == 0); + llassert(h%2 == 0); + const GLubyte* rowstart = ((const GLubyte*) data_in) + mAlphaOffset; + for (U32 y = 0; y < h; y+=2) + { + const GLubyte* current = rowstart; + for (U32 x = 0; x < w; x+=2) + { + const U32 s1 = current[0]; + alphatotal += s1; + const U32 s2 = current[w * mAlphaStride]; + alphatotal += s2; + current += mAlphaStride; + const U32 s3 = current[0]; + alphatotal += s3; + const U32 s4 = current[w * mAlphaStride]; + alphatotal += s4; + current += mAlphaStride; + + ++sample[s1/16]; + ++sample[s2/16]; + ++sample[s3/16]; + ++sample[s4/16]; + + const U32 asum = (s1+s2+s3+s4); + alphatotal += asum; + sample[asum/(16*4)] += 4; + } + + + rowstart += 2 * w * mAlphaStride; + } + length *= 2; // we sampled everything twice, essentially + } + else + { + const GLubyte* current = ((const GLubyte*) data_in) + mAlphaOffset; + for (U32 i = 0; i < length; i++) + { + const U32 s1 = *current; + alphatotal += s1; + ++sample[s1/16]; + current += mAlphaStride; + } + } + + // if more than 1/16th of alpha samples are mid-range, this + // shouldn't be treated as a 1-bit mask + + // also, if all of the alpha samples are clumped on one half + // of the range (but not at an absolute extreme), then consider + // this to be an intentional effect and don't treat as a mask. + + U32 midrangetotal = 0; + for (U32 i = 2; i < 13; i++) + { + midrangetotal += sample[i]; + } + U32 lowerhalftotal = 0; + for (U32 i = 0; i < 8; i++) + { + lowerhalftotal += sample[i]; + } + U32 upperhalftotal = 0; + for (U32 i = 8; i < 16; i++) + { + upperhalftotal += sample[i]; + } + + if (midrangetotal > length/48 || // lots of midrange, or + (lowerhalftotal == length && alphatotal != 0) || // all close to transparent but not all totally transparent, or + (upperhalftotal == length && alphatotal != 255*length)) // all close to opaque but not all totally opaque + { + mIsMask = FALSE; // not suitable for masking + } + else + { + mIsMask = TRUE; + } } //---------------------------------------------------------------------------- U32 LLImageGL::createPickMask(S32 pWidth, S32 pHeight) { - U32 pick_width = pWidth/2 + 1; - U32 pick_height = pHeight/2 + 1; + U32 pick_width = pWidth/2 + 1; + U32 pick_height = pHeight/2 + 1; - U32 size = pick_width * pick_height; - size = (size + 7) / 8; // pixelcount-to-bits - mPickMask = new U8[size]; - mPickMaskWidth = pick_width - 1; - mPickMaskHeight = pick_height - 1; + U32 size = pick_width * pick_height; + size = (size + 7) / 8; // pixelcount-to-bits + mPickMask = new U8[size]; + mPickMaskWidth = pick_width - 1; + mPickMaskHeight = pick_height - 1; - memset(mPickMask, 0, sizeof(U8) * size); + memset(mPickMask, 0, sizeof(U8) * size); - return size; + return size; } //---------------------------------------------------------------------------- void LLImageGL::freePickMask() { - // pickmask validity depends on old image size, delete it - if (mPickMask != NULL) - { - delete [] mPickMask; - } - mPickMask = NULL; - mPickMaskWidth = mPickMaskHeight = 0; + // pickmask validity depends on old image size, delete it + if (mPickMask != NULL) + { + delete [] mPickMask; + } + mPickMask = NULL; + mPickMaskWidth = mPickMaskHeight = 0; } bool LLImageGL::isCompressed() @@ -2341,12 +2341,12 @@ bool LLImageGL::isCompressed() //---------------------------------------------------------------------------- void LLImageGL::updatePickMask(S32 width, S32 height, const U8* data_in) { - if(!mNeedsAlphaAndPickMask) - { - return ; - } + if(!mNeedsAlphaAndPickMask) + { + return ; + } - freePickMask(); + freePickMask(); if (mFormatType != GL_UNSIGNED_BYTE || ((mFormatPrimary != GL_RGBA) @@ -2357,102 +2357,102 @@ void LLImageGL::updatePickMask(S32 width, S32 height, const U8* data_in) } #ifdef SHOW_ASSERT - const U32 pickSize = createPickMask(width, height); + const U32 pickSize = createPickMask(width, height); #else // SHOW_ASSERT - createPickMask(width, height); + createPickMask(width, height); #endif // SHOW_ASSERT - U32 pick_bit = 0; - - for (S32 y = 0; y < height; y += 2) - { - for (S32 x = 0; x < width; x += 2) - { - U8 alpha = data_in[(y*width+x)*4+3]; + U32 pick_bit = 0; - if (alpha > 32) - { - U32 pick_idx = pick_bit/8; - U32 pick_offset = pick_bit%8; - llassert(pick_idx < pickSize); + for (S32 y = 0; y < height; y += 2) + { + for (S32 x = 0; x < width; x += 2) + { + U8 alpha = data_in[(y*width+x)*4+3]; + + if (alpha > 32) + { + U32 pick_idx = pick_bit/8; + U32 pick_offset = pick_bit%8; + llassert(pick_idx < pickSize); - mPickMask[pick_idx] |= 1 << pick_offset; - } - - ++pick_bit; - } - } + mPickMask[pick_idx] |= 1 << pick_offset; + } + + ++pick_bit; + } + } } BOOL LLImageGL::getMask(const LLVector2 &tc) { - BOOL res = TRUE; - - if (mPickMask) - { - F32 u,v; - if (LL_LIKELY(tc.isFinite())) - { - u = tc.mV[0] - floorf(tc.mV[0]); - v = tc.mV[1] - floorf(tc.mV[1]); - } - else - { - LL_WARNS_ONCE("render") << "Ugh, non-finite u/v in mask pick" << LL_ENDL; - u = v = 0.f; - // removing assert per EXT-4388 - // llassert(false); - } - - if (LL_UNLIKELY(u < 0.f || u > 1.f || - v < 0.f || v > 1.f)) - { - LL_WARNS_ONCE("render") << "Ugh, u/v out of range in image mask pick" << LL_ENDL; - u = v = 0.f; - // removing assert per EXT-4388 - // llassert(false); - } - - S32 x = llfloor(u * mPickMaskWidth); - S32 y = llfloor(v * mPickMaskHeight); - - if (LL_UNLIKELY(x > mPickMaskWidth)) - { - LL_WARNS_ONCE("render") << "Ooh, width overrun on pick mask read, that coulda been bad." << LL_ENDL; - x = llmax((U16)0, mPickMaskWidth); - } - if (LL_UNLIKELY(y > mPickMaskHeight)) - { - LL_WARNS_ONCE("render") << "Ooh, height overrun on pick mask read, that woulda been bad." << LL_ENDL; - y = llmax((U16)0, mPickMaskHeight); - } - - S32 idx = y*mPickMaskWidth+x; - S32 offset = idx%8; - - res = mPickMask[idx/8] & (1 << offset) ? TRUE : FALSE; - } - - return res; + BOOL res = TRUE; + + if (mPickMask) + { + F32 u,v; + if (LL_LIKELY(tc.isFinite())) + { + u = tc.mV[0] - floorf(tc.mV[0]); + v = tc.mV[1] - floorf(tc.mV[1]); + } + else + { + LL_WARNS_ONCE("render") << "Ugh, non-finite u/v in mask pick" << LL_ENDL; + u = v = 0.f; + // removing assert per EXT-4388 + // llassert(false); + } + + if (LL_UNLIKELY(u < 0.f || u > 1.f || + v < 0.f || v > 1.f)) + { + LL_WARNS_ONCE("render") << "Ugh, u/v out of range in image mask pick" << LL_ENDL; + u = v = 0.f; + // removing assert per EXT-4388 + // llassert(false); + } + + S32 x = llfloor(u * mPickMaskWidth); + S32 y = llfloor(v * mPickMaskHeight); + + if (LL_UNLIKELY(x > mPickMaskWidth)) + { + LL_WARNS_ONCE("render") << "Ooh, width overrun on pick mask read, that coulda been bad." << LL_ENDL; + x = llmax((U16)0, mPickMaskWidth); + } + if (LL_UNLIKELY(y > mPickMaskHeight)) + { + LL_WARNS_ONCE("render") << "Ooh, height overrun on pick mask read, that woulda been bad." << LL_ENDL; + y = llmax((U16)0, mPickMaskHeight); + } + + S32 idx = y*mPickMaskWidth+x; + S32 offset = idx%8; + + res = mPickMask[idx/8] & (1 << offset) ? TRUE : FALSE; + } + + return res; } void LLImageGL::setCurTexSizebar(S32 index, BOOL set_pick_size) { - sCurTexSizeBar = index ; + sCurTexSizeBar = index ; - if(set_pick_size) - { - sCurTexPickSize = (1 << index) ; - } - else - { - sCurTexPickSize = -1 ; - } + if(set_pick_size) + { + sCurTexPickSize = (1 << index) ; + } + else + { + sCurTexPickSize = -1 ; + } } void LLImageGL::resetCurTexSizebar() { - sCurTexSizeBar = -1 ; - sCurTexPickSize = -1 ; + sCurTexSizeBar = -1 ; + sCurTexPickSize = -1 ; } //---------------------------------------------------------------------------- #if LL_IMAGEGL_THREAD_CHECK @@ -2467,53 +2467,53 @@ void LLImageGL::checkActiveThread() // Manual Mip Generation /* - S32 width = getWidth(discard_level); - S32 height = getHeight(discard_level); - S32 w = width, h = height; - S32 nummips = 1; - while (w > 4 && h > 4) - { - w >>= 1; h >>= 1; - nummips++; - } - stop_glerror(); - w = width, h = height; - const U8* prev_mip_data = 0; - const U8* cur_mip_data = 0; - for (int m=0; m<nummips; m++) - { - if (m==0) - { - cur_mip_data = rawdata; - } - else - { - S32 bytes = w * h * mComponents; - U8* new_data = new U8[bytes]; - LLImageBase::generateMip(prev_mip_data, new_data, w, h, mComponents); - cur_mip_data = new_data; - } - llassert(w > 0 && h > 0 && cur_mip_data); - U8 test = cur_mip_data[w*h*mComponents-1]; - { - LLImageGL::setManualImage(mTarget, m, mFormatInternal, w, h, mFormatPrimary, mFormatType, cur_mip_data); - stop_glerror(); - } - if (prev_mip_data && prev_mip_data != rawdata) - { - delete prev_mip_data; - } - prev_mip_data = cur_mip_data; - w >>= 1; - h >>= 1; - } - if (prev_mip_data && prev_mip_data != rawdata) - { - delete prev_mip_data; - } - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, nummips); -*/ + S32 width = getWidth(discard_level); + S32 height = getHeight(discard_level); + S32 w = width, h = height; + S32 nummips = 1; + while (w > 4 && h > 4) + { + w >>= 1; h >>= 1; + nummips++; + } + stop_glerror(); + w = width, h = height; + const U8* prev_mip_data = 0; + const U8* cur_mip_data = 0; + for (int m=0; m<nummips; m++) + { + if (m==0) + { + cur_mip_data = rawdata; + } + else + { + S32 bytes = w * h * mComponents; + U8* new_data = new U8[bytes]; + LLImageBase::generateMip(prev_mip_data, new_data, w, h, mComponents); + cur_mip_data = new_data; + } + llassert(w > 0 && h > 0 && cur_mip_data); + U8 test = cur_mip_data[w*h*mComponents-1]; + { + LLImageGL::setManualImage(mTarget, m, mFormatInternal, w, h, mFormatPrimary, mFormatType, cur_mip_data); + stop_glerror(); + } + if (prev_mip_data && prev_mip_data != rawdata) + { + delete prev_mip_data; + } + prev_mip_data = cur_mip_data; + w >>= 1; + h >>= 1; + } + if (prev_mip_data && prev_mip_data != rawdata) + { + delete prev_mip_data; + } + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, nummips); +*/ LLImageGLThread::LLImageGLThread(LLWindow* window) // We want exactly one thread. diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h index a9a6b93cb3..89e35d2226 100644 --- a/indra/llrender/llimagegl.h +++ b/indra/llrender/llimagegl.h @@ -1,25 +1,25 @@ -/** +/** * @file llimagegl.h * @brief Object for managing images and their textures * * $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$ */ @@ -50,7 +50,7 @@ class LLWindow; //============================================================================ class LLImageGL : public LLRefCount { - friend class LLTexUnit; + friend class LLTexUnit; public: // Get an estimate of how many bytes have been allocated in vram for textures. @@ -59,146 +59,146 @@ public: // video memory usage based on testing in lagland against an NVIDIA GPU. static U64 getTextureBytesAllocated(); - // These 2 functions replace glGenTextures() and glDeleteTextures() - static void generateTextures(S32 numTextures, U32 *textures); - static void deleteTextures(S32 numTextures, const U32 *textures); + // These 2 functions replace glGenTextures() and glDeleteTextures() + static void generateTextures(S32 numTextures, U32 *textures); + static void deleteTextures(S32 numTextures, const U32 *textures); + + // Size calculation + static S32 dataFormatBits(S32 dataformat); + static S64 dataFormatBytes(S32 dataformat, S32 width, S32 height); + static S32 dataFormatComponents(S32 dataformat); - // Size calculation - static S32 dataFormatBits(S32 dataformat); - static S64 dataFormatBytes(S32 dataformat, S32 width, S32 height); - static S32 dataFormatComponents(S32 dataformat); + BOOL updateBindStats() const ; + F32 getTimePassedSinceLastBound(); + void forceUpdateBindStats(void) const; - BOOL updateBindStats() const ; - F32 getTimePassedSinceLastBound(); - void forceUpdateBindStats(void) const; + // needs to be called every frame + static void updateStats(F32 current_time); - // needs to be called every frame - static void updateStats(F32 current_time); + // Save off / restore GL textures + static void destroyGL(BOOL save_state = TRUE); + static void restoreGL(); + static void dirtyTexOptions(); - // Save off / restore GL textures - static void destroyGL(BOOL save_state = TRUE); - static void restoreGL(); - static void dirtyTexOptions(); + static bool checkSize(S32 width, S32 height); - static bool checkSize(S32 width, S32 height); + //for server side use only. + // Not currently necessary for LLImageGL, but required in some derived classes, + // so include for compatability + static BOOL create(LLPointer<LLImageGL>& dest, BOOL usemipmaps = TRUE); + static BOOL create(LLPointer<LLImageGL>& dest, U32 width, U32 height, U8 components, BOOL usemipmaps = TRUE); + static BOOL create(LLPointer<LLImageGL>& dest, const LLImageRaw* imageraw, BOOL usemipmaps = TRUE); - //for server side use only. - // Not currently necessary for LLImageGL, but required in some derived classes, - // so include for compatability - static BOOL create(LLPointer<LLImageGL>& dest, BOOL usemipmaps = TRUE); - static BOOL create(LLPointer<LLImageGL>& dest, U32 width, U32 height, U8 components, BOOL usemipmaps = TRUE); - static BOOL create(LLPointer<LLImageGL>& dest, const LLImageRaw* imageraw, BOOL usemipmaps = TRUE); - public: - LLImageGL(BOOL usemipmaps = TRUE); - LLImageGL(U32 width, U32 height, U8 components, BOOL usemipmaps = TRUE); - LLImageGL(const LLImageRaw* imageraw, BOOL usemipmaps = TRUE); + LLImageGL(BOOL usemipmaps = TRUE); + LLImageGL(U32 width, U32 height, U8 components, BOOL usemipmaps = TRUE); + LLImageGL(const LLImageRaw* imageraw, BOOL usemipmaps = TRUE); // For wrapping textures created via GL elsewhere with our API only. Use with caution. LLImageGL(LLGLuint mTexName, U32 components, LLGLenum target, LLGLint formatInternal, LLGLenum formatPrimary, LLGLenum formatType, LLTexUnit::eTextureAddressMode addressMode); protected: - virtual ~LLImageGL(); + virtual ~LLImageGL(); - void analyzeAlpha(const void* data_in, U32 w, U32 h); - void calcAlphaChannelOffsetAndStride(); + void analyzeAlpha(const void* data_in, U32 w, U32 h); + void calcAlphaChannelOffsetAndStride(); public: - virtual void dump(); // debugging info to LL_INFOS() - - bool setSize(S32 width, S32 height, S32 ncomponents, S32 discard_level = -1); - void setComponents(S32 ncomponents) { mComponents = (S8)ncomponents ;} - void setAllowCompression(bool allow) { mAllowCompression = allow; } - - static void setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels, bool allow_compression = true); - - BOOL createGLTexture() ; - BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE, - S32 category = sMaxCategories-1, bool defer_copy = false, LLGLuint* tex_name = nullptr); - BOOL createGLTexture(S32 discard_level, const U8* data, BOOL data_hasmips = FALSE, S32 usename = 0, bool defer_copy = false, LLGLuint* tex_name = nullptr); - void setImage(const LLImageRaw* imageraw); - BOOL setImage(const U8* data_in, BOOL data_hasmips = FALSE, S32 usename = 0); + virtual void dump(); // debugging info to LL_INFOS() + + bool setSize(S32 width, S32 height, S32 ncomponents, S32 discard_level = -1); + void setComponents(S32 ncomponents) { mComponents = (S8)ncomponents ;} + void setAllowCompression(bool allow) { mAllowCompression = allow; } + + static void setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels, bool allow_compression = true); + + BOOL createGLTexture() ; + BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE, + S32 category = sMaxCategories-1, bool defer_copy = false, LLGLuint* tex_name = nullptr); + BOOL createGLTexture(S32 discard_level, const U8* data, BOOL data_hasmips = FALSE, S32 usename = 0, bool defer_copy = false, LLGLuint* tex_name = nullptr); + void setImage(const LLImageRaw* imageraw); + BOOL setImage(const U8* data_in, BOOL data_hasmips = FALSE, S32 usename = 0); // *TODO: This function may not work if the textures is compressed (i.e. // RenderCompressTextures is 0). Partial image updates do not work on // compressed textures. - BOOL setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update = FALSE, LLGLuint use_name = 0); - BOOL setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update = FALSE, LLGLuint use_name = 0); - BOOL setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_pos, S32 width, S32 height); + BOOL setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update = FALSE, LLGLuint use_name = 0); + BOOL setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update = FALSE, LLGLuint use_name = 0); + BOOL setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_pos, S32 width, S32 height); // wait for gl commands to finish on current thread and push // a lambda to main thread to swap mNewTexName and mTexName void syncToMainThread(LLGLuint new_tex_name); - // Read back a raw image for this discard level, if it exists - BOOL readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const; - void destroyGLTexture(); - void forceToInvalidateGLTexture(); + // Read back a raw image for this discard level, if it exists + BOOL readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const; + void destroyGLTexture(); + void forceToInvalidateGLTexture(); - void setExplicitFormat(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format = 0, BOOL swap_bytes = FALSE); - void setComponents(S8 ncomponents) { mComponents = ncomponents; } + void setExplicitFormat(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format = 0, BOOL swap_bytes = FALSE); + void setComponents(S8 ncomponents) { mComponents = ncomponents; } - S32 getDiscardLevel() const { return mCurrentDiscardLevel; } - S32 getMaxDiscardLevel() const { return mMaxDiscardLevel; } + S32 getDiscardLevel() const { return mCurrentDiscardLevel; } + S32 getMaxDiscardLevel() const { return mMaxDiscardLevel; } - S32 getCurrentWidth() const { return mWidth ;} - S32 getCurrentHeight() const { return mHeight ;} - S32 getWidth(S32 discard_level = -1) const; - S32 getHeight(S32 discard_level = -1) const; - U8 getComponents() const { return mComponents; } - S64 getBytes(S32 discard_level = -1) const; - S64 getMipBytes(S32 discard_level = -1) const; - BOOL getBoundRecently() const; - BOOL isJustBound() const; - BOOL getHasExplicitFormat() const { return mHasExplicitFormat; } - LLGLenum getPrimaryFormat() const { return mFormatPrimary; } - LLGLenum getFormatType() const { return mFormatType; } + S32 getCurrentWidth() const { return mWidth ;} + S32 getCurrentHeight() const { return mHeight ;} + S32 getWidth(S32 discard_level = -1) const; + S32 getHeight(S32 discard_level = -1) const; + U8 getComponents() const { return mComponents; } + S64 getBytes(S32 discard_level = -1) const; + S64 getMipBytes(S32 discard_level = -1) const; + BOOL getBoundRecently() const; + BOOL isJustBound() const; + BOOL getHasExplicitFormat() const { return mHasExplicitFormat; } + LLGLenum getPrimaryFormat() const { return mFormatPrimary; } + LLGLenum getFormatType() const { return mFormatType; } - BOOL getHasGLTexture() const { return mTexName != 0; } - LLGLuint getTexName() const { return mTexName; } + BOOL getHasGLTexture() const { return mTexName != 0; } + LLGLuint getTexName() const { return mTexName; } - BOOL getIsAlphaMask() const; + BOOL getIsAlphaMask() const; - BOOL getIsResident(BOOL test_now = FALSE); // not const + BOOL getIsResident(BOOL test_now = FALSE); // not const - void setTarget(const LLGLenum target, const LLTexUnit::eTextureType bind_target); + void setTarget(const LLGLenum target, const LLTexUnit::eTextureType bind_target); - LLTexUnit::eTextureType getTarget(void) const { return mBindTarget; } - bool isGLTextureCreated(void) const { return mGLTextureCreated ; } - void setGLTextureCreated (bool initialized) { mGLTextureCreated = initialized; } + LLTexUnit::eTextureType getTarget(void) const { return mBindTarget; } + bool isGLTextureCreated(void) const { return mGLTextureCreated ; } + void setGLTextureCreated (bool initialized) { mGLTextureCreated = initialized; } - BOOL getUseMipMaps() const { return mUseMipMaps; } - void setUseMipMaps(BOOL usemips) { mUseMipMaps = usemips; } + BOOL getUseMipMaps() const { return mUseMipMaps; } + void setUseMipMaps(BOOL usemips) { mUseMipMaps = usemips; } void setHasMipMaps(BOOL hasmips) { mHasMipMaps = hasmips; } - void updatePickMask(S32 width, S32 height, const U8* data_in); - BOOL getMask(const LLVector2 &tc); + void updatePickMask(S32 width, S32 height, const U8* data_in); + BOOL getMask(const LLVector2 &tc); void checkTexSize(bool forced = false) const ; - - // Sets the addressing mode used to sample the texture - // (such as wrapping, mirrored wrapping, and clamp) - // Note: this actually gets set the next time the texture is bound. - void setAddressMode(LLTexUnit::eTextureAddressMode mode); - LLTexUnit::eTextureAddressMode getAddressMode(void) const { return mAddressMode; } - // Sets the filtering options used to sample the texture - // (such as point sampling, bilinear interpolation, mipmapping, and anisotropic filtering) - // Note: this actually gets set the next time the texture is bound. - void setFilteringOption(LLTexUnit::eTextureFilterOptions option); - LLTexUnit::eTextureFilterOptions getFilteringOption(void) const { return mFilterOption; } + // Sets the addressing mode used to sample the texture + // (such as wrapping, mirrored wrapping, and clamp) + // Note: this actually gets set the next time the texture is bound. + void setAddressMode(LLTexUnit::eTextureAddressMode mode); + LLTexUnit::eTextureAddressMode getAddressMode(void) const { return mAddressMode; } + + // Sets the filtering options used to sample the texture + // (such as point sampling, bilinear interpolation, mipmapping, and anisotropic filtering) + // Note: this actually gets set the next time the texture is bound. + void setFilteringOption(LLTexUnit::eTextureFilterOptions option); + LLTexUnit::eTextureFilterOptions getFilteringOption(void) const { return mFilterOption; } - LLGLenum getTexTarget()const { return mTarget ;} - S8 getDiscardLevelInAtlas()const {return mDiscardLevelInAtlas;} - U32 getTexelsInAtlas()const { return mTexelsInAtlas ;} - U32 getTexelsInGLTexture()const {return mTexelsInGLTexture;} + LLGLenum getTexTarget()const { return mTarget ;} + S8 getDiscardLevelInAtlas()const {return mDiscardLevelInAtlas;} + U32 getTexelsInAtlas()const { return mTexelsInAtlas ;} + U32 getTexelsInGLTexture()const {return mTexelsInGLTexture;} - - void init(BOOL usemipmaps); - virtual void cleanup(); // Clean up the LLImageGL so it can be reinitialized. Be careful when using this in derived class destructors - void setNeedsAlphaAndPickMask(BOOL need_mask); + void init(BOOL usemipmaps); + virtual void cleanup(); // Clean up the LLImageGL so it can be reinitialized. Be careful when using this in derived class destructors - BOOL preAddToAtlas(S32 discard_level, const LLImageRaw* raw_image); - void postAddToAtlas() ; + void setNeedsAlphaAndPickMask(BOOL need_mask); + + BOOL preAddToAtlas(S32 discard_level, const LLImageRaw* raw_image); + void postAddToAtlas() ; #if LL_IMAGEGL_THREAD_CHECK // thread debugging @@ -207,118 +207,118 @@ public: #endif public: - // Various GL/Rendering options - S64Bytes mTextureMemory; - mutable F32 mLastBindTime; // last time this was bound, by discard level - + // Various GL/Rendering options + S64Bytes mTextureMemory; + mutable F32 mLastBindTime; // last time this was bound, by discard level + private: - U32 createPickMask(S32 pWidth, S32 pHeight); - void freePickMask(); + U32 createPickMask(S32 pWidth, S32 pHeight); + void freePickMask(); bool isCompressed(); - LLPointer<LLImageRaw> mSaveData; // used for destroyGL/restoreGL - LL::WorkQueue::weak_t mMainQueue; - U8* mPickMask; //downsampled bitmap approximation of alpha channel. NULL if no alpha channel - U16 mPickMaskWidth; - U16 mPickMaskHeight; - S8 mUseMipMaps; - BOOL mHasExplicitFormat; // If false (default), GL format is f(mComponents) - bool mAutoGenMips = false; - - BOOL mIsMask; - BOOL mNeedsAlphaAndPickMask; - S8 mAlphaStride ; - S8 mAlphaOffset ; - - bool mGLTextureCreated ; - LLGLuint mTexName; + LLPointer<LLImageRaw> mSaveData; // used for destroyGL/restoreGL + LL::WorkQueue::weak_t mMainQueue; + U8* mPickMask; //downsampled bitmap approximation of alpha channel. NULL if no alpha channel + U16 mPickMaskWidth; + U16 mPickMaskHeight; + S8 mUseMipMaps; + BOOL mHasExplicitFormat; // If false (default), GL format is f(mComponents) + bool mAutoGenMips = false; + + BOOL mIsMask; + BOOL mNeedsAlphaAndPickMask; + S8 mAlphaStride ; + S8 mAlphaOffset ; + + bool mGLTextureCreated ; + LLGLuint mTexName; //LLGLuint mNewTexName = 0; // tex name set by background thread to be applied in main thread - U16 mWidth; - U16 mHeight; - S8 mCurrentDiscardLevel; - - S8 mDiscardLevelInAtlas; - U32 mTexelsInAtlas ; - U32 mTexelsInGLTexture; + U16 mWidth; + U16 mHeight; + S8 mCurrentDiscardLevel; - bool mAllowCompression; + S8 mDiscardLevelInAtlas; + U32 mTexelsInAtlas ; + U32 mTexelsInGLTexture; + + bool mAllowCompression; protected: - LLGLenum mTarget; // Normally GL_TEXTURE2D, sometimes something else (ex. cube maps) - LLTexUnit::eTextureType mBindTarget; // Normally TT_TEXTURE, sometimes something else (ex. cube maps) - bool mHasMipMaps; - S32 mMipLevels; - - LLGLboolean mIsResident; - - S8 mComponents; - S8 mMaxDiscardLevel; - - bool mTexOptionsDirty; - LLTexUnit::eTextureAddressMode mAddressMode; // Defaults to TAM_WRAP - LLTexUnit::eTextureFilterOptions mFilterOption; // Defaults to TFO_ANISOTROPIC - - LLGLint mFormatInternal; // = GL internalformat - LLGLenum mFormatPrimary; // = GL format (pixel data format) - LLGLenum mFormatType; - BOOL mFormatSwapBytes;// if true, use glPixelStorei(GL_UNPACK_SWAP_BYTES, 1) - + LLGLenum mTarget; // Normally GL_TEXTURE2D, sometimes something else (ex. cube maps) + LLTexUnit::eTextureType mBindTarget; // Normally TT_TEXTURE, sometimes something else (ex. cube maps) + bool mHasMipMaps; + S32 mMipLevels; + + LLGLboolean mIsResident; + + S8 mComponents; + S8 mMaxDiscardLevel; + + bool mTexOptionsDirty; + LLTexUnit::eTextureAddressMode mAddressMode; // Defaults to TAM_WRAP + LLTexUnit::eTextureFilterOptions mFilterOption; // Defaults to TFO_ANISOTROPIC + + LLGLint mFormatInternal; // = GL internalformat + LLGLenum mFormatPrimary; // = GL format (pixel data format) + LLGLenum mFormatType; + BOOL mFormatSwapBytes;// if true, use glPixelStorei(GL_UNPACK_SWAP_BYTES, 1) + BOOL mExternalTexture; - // STATICS -public: - static std::set<LLImageGL*> sImageList; - static S32 sCount; - - static F32 sLastFrameTime; - - // Global memory statistics - static U32 sBindCount; // Tracks number of texture binds for current frame - static U32 sUniqueCount; // Tracks number of unique texture binds for current frame - static BOOL sGlobalUseAnisotropic; - static LLImageGL* sDefaultGLTexture ; - static BOOL sAutomatedTest; - static bool sCompressTextures; //use GL texture compression + // STATICS +public: + static std::set<LLImageGL*> sImageList; + static S32 sCount; + + static F32 sLastFrameTime; + + // Global memory statistics + static U32 sBindCount; // Tracks number of texture binds for current frame + static U32 sUniqueCount; // Tracks number of unique texture binds for current frame + static BOOL sGlobalUseAnisotropic; + static LLImageGL* sDefaultGLTexture ; + static BOOL sAutomatedTest; + static bool sCompressTextures; //use GL texture compression #if DEBUG_MISS - BOOL mMissed; // Missed on last bind? - BOOL getMissed() const { return mMissed; }; + BOOL mMissed; // Missed on last bind? + BOOL getMissed() const { return mMissed; }; #else - BOOL getMissed() const { return FALSE; }; + BOOL getMissed() const { return FALSE; }; #endif public: - static void initClass(LLWindow* window, S32 num_catagories, BOOL skip_analyze_alpha = false, bool thread_texture_loads = false, bool thread_media_updates = false); - static void cleanupClass() ; + static void initClass(LLWindow* window, S32 num_catagories, BOOL skip_analyze_alpha = false, bool thread_texture_loads = false, bool thread_media_updates = false); + static void cleanupClass() ; private: - static S32 sMaxCategories; - static BOOL sSkipAnalyzeAlpha; - - //the flag to allow to call readBackRaw(...). - //can be removed if we do not use that function at all. - static BOOL sAllowReadBackRaw ; + static S32 sMaxCategories; + static BOOL sSkipAnalyzeAlpha; + + //the flag to allow to call readBackRaw(...). + //can be removed if we do not use that function at all. + static BOOL sAllowReadBackRaw ; // //**************************************************************************************************** //The below for texture auditing use only //**************************************************************************************************** private: - S32 mCategory ; + S32 mCategory ; public: - void setCategory(S32 category) {mCategory = category;} - S32 getCategory()const {return mCategory;} - + void setCategory(S32 category) {mCategory = category;} + S32 getCategory()const {return mCategory;} + void setTexName(GLuint texName) { mTexName = texName; } //similar to setTexName, but will call deleteTextures on mTexName if mTexName is not 0 or texname void syncTexName(LLGLuint texname); - //for debug use: show texture size distribution - //---------------------------------------- - static S32 sCurTexSizeBar ; - static S32 sCurTexPickSize ; + //for debug use: show texture size distribution + //---------------------------------------- + static S32 sCurTexSizeBar ; + static S32 sCurTexPickSize ; - static void setCurTexSizebar(S32 index, BOOL set_pick_size = TRUE) ; - static void resetCurTexSizebar(); + static void setCurTexSizebar(S32 index, BOOL set_pick_size = TRUE) ; + static void resetCurTexSizebar(); //**************************************************************************************************** //End of definitions for texture auditing use only @@ -333,7 +333,7 @@ public: static bool sEnabledTextures; // follows gSavedSettings "RenderGLMultiThreadedMedia" static bool sEnabledMedia; - + LLImageGLThread(LLWindow* window); // post a function to be executed on the LLImageGL background thread diff --git a/indra/llrender/llpostprocess.cpp b/indra/llrender/llpostprocess.cpp index 0f8655132b..4242e330f4 100644 --- a/indra/llrender/llpostprocess.cpp +++ b/indra/llrender/llpostprocess.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llpostprocess.cpp * @brief LLPostProcess class 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$ */ @@ -51,214 +51,214 @@ LLPostProcess * gPostProcess = NULL; static const unsigned int NOISE_SIZE = 512; -LLPostProcess::LLPostProcess(void) : - initialized(false), - mAllEffects(LLSD::emptyMap()), - screenW(1), screenH(1) +LLPostProcess::LLPostProcess(void) : + initialized(false), + mAllEffects(LLSD::emptyMap()), + screenW(1), screenH(1) { - mSceneRenderTexture = NULL ; - mNoiseTexture = NULL ; - mTempBloomTexture = NULL ; - - noiseTextureScale = 1.0f; - - /* Do nothing. Needs to be updated to use our current shader system, and to work with the move into llrender. - std::string pathName(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight", XML_FILENAME)); - LL_DEBUGS("AppInit", "Shaders") << "Loading PostProcess Effects settings from " << pathName << LL_ENDL; - - llifstream effectsXML(pathName); - - if (effectsXML) - { - LLPointer<LLSDParser> parser = new LLSDXMLParser(); - - parser->parse(effectsXML, mAllEffects, LLSDSerialize::SIZE_UNLIMITED); - } - - if (!mAllEffects.has("default")) - { - LLSD & defaultEffect = (mAllEffects["default"] = LLSD::emptyMap()); - - defaultEffect["enable_night_vision"] = LLSD::Boolean(false); - defaultEffect["enable_bloom"] = LLSD::Boolean(false); - defaultEffect["enable_color_filter"] = LLSD::Boolean(false); - - /// NVG Defaults - defaultEffect["brightness_multiplier"] = 3.0; - defaultEffect["noise_size"] = 25.0; - defaultEffect["noise_strength"] = 0.4; - - // TODO BTest potentially add this to tweaks? - noiseTextureScale = 1.0f; - - /// Bloom Defaults - defaultEffect["extract_low"] = 0.95; - defaultEffect["extract_high"] = 1.0; - defaultEffect["bloom_width"] = 2.25; - defaultEffect["bloom_strength"] = 1.5; - - /// Color Filter Defaults - defaultEffect["brightness"] = 1.0; - defaultEffect["contrast"] = 1.0; - defaultEffect["saturation"] = 1.0; - - LLSD& contrastBase = (defaultEffect["contrast_base"] = LLSD::emptyArray()); - contrastBase.append(1.0); - contrastBase.append(1.0); - contrastBase.append(1.0); - contrastBase.append(0.5); - } - - setSelectedEffect("default"); - */ + mSceneRenderTexture = NULL ; + mNoiseTexture = NULL ; + mTempBloomTexture = NULL ; + + noiseTextureScale = 1.0f; + + /* Do nothing. Needs to be updated to use our current shader system, and to work with the move into llrender. + std::string pathName(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight", XML_FILENAME)); + LL_DEBUGS("AppInit", "Shaders") << "Loading PostProcess Effects settings from " << pathName << LL_ENDL; + + llifstream effectsXML(pathName); + + if (effectsXML) + { + LLPointer<LLSDParser> parser = new LLSDXMLParser(); + + parser->parse(effectsXML, mAllEffects, LLSDSerialize::SIZE_UNLIMITED); + } + + if (!mAllEffects.has("default")) + { + LLSD & defaultEffect = (mAllEffects["default"] = LLSD::emptyMap()); + + defaultEffect["enable_night_vision"] = LLSD::Boolean(false); + defaultEffect["enable_bloom"] = LLSD::Boolean(false); + defaultEffect["enable_color_filter"] = LLSD::Boolean(false); + + /// NVG Defaults + defaultEffect["brightness_multiplier"] = 3.0; + defaultEffect["noise_size"] = 25.0; + defaultEffect["noise_strength"] = 0.4; + + // TODO BTest potentially add this to tweaks? + noiseTextureScale = 1.0f; + + /// Bloom Defaults + defaultEffect["extract_low"] = 0.95; + defaultEffect["extract_high"] = 1.0; + defaultEffect["bloom_width"] = 2.25; + defaultEffect["bloom_strength"] = 1.5; + + /// Color Filter Defaults + defaultEffect["brightness"] = 1.0; + defaultEffect["contrast"] = 1.0; + defaultEffect["saturation"] = 1.0; + + LLSD& contrastBase = (defaultEffect["contrast_base"] = LLSD::emptyArray()); + contrastBase.append(1.0); + contrastBase.append(1.0); + contrastBase.append(1.0); + contrastBase.append(0.5); + } + + setSelectedEffect("default"); + */ } LLPostProcess::~LLPostProcess(void) { - invalidate() ; + invalidate() ; } // static void LLPostProcess::initClass(void) { - //this will cause system to crash at second time login - //if first time login fails due to network connection --- bao - //***llassert_always(gPostProcess == NULL); - //replaced by the following line: - if(gPostProcess) - return ; - - - gPostProcess = new LLPostProcess(); + //this will cause system to crash at second time login + //if first time login fails due to network connection --- bao + //***llassert_always(gPostProcess == NULL); + //replaced by the following line: + if(gPostProcess) + return ; + + + gPostProcess = new LLPostProcess(); } // static void LLPostProcess::cleanupClass() { - delete gPostProcess; - gPostProcess = NULL; + delete gPostProcess; + gPostProcess = NULL; } void LLPostProcess::setSelectedEffect(std::string const & effectName) { - mSelectedEffectName = effectName; - static_cast<LLSD &>(tweaks) = mAllEffects[effectName]; + mSelectedEffectName = effectName; + static_cast<LLSD &>(tweaks) = mAllEffects[effectName]; } void LLPostProcess::saveEffect(std::string const & effectName) { - /* Do nothing. Needs to be updated to use our current shader system, and to work with the move into llrender. - mAllEffects[effectName] = tweaks; + /* Do nothing. Needs to be updated to use our current shader system, and to work with the move into llrender. + mAllEffects[effectName] = tweaks; - std::string pathName(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight", XML_FILENAME)); - //LL_INFOS() << "Saving PostProcess Effects settings to " << pathName << LL_ENDL; + std::string pathName(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight", XML_FILENAME)); + //LL_INFOS() << "Saving PostProcess Effects settings to " << pathName << LL_ENDL; - llofstream effectsXML(pathName); + llofstream effectsXML(pathName); - LLPointer<LLSDFormatter> formatter = new LLSDXMLFormatter(); + LLPointer<LLSDFormatter> formatter = new LLSDXMLFormatter(); - formatter->format(mAllEffects, effectsXML); - */ + formatter->format(mAllEffects, effectsXML); + */ } void LLPostProcess::invalidate() { - mSceneRenderTexture = NULL ; - mNoiseTexture = NULL ; - mTempBloomTexture = NULL ; - initialized = FALSE ; + mSceneRenderTexture = NULL ; + mNoiseTexture = NULL ; + mTempBloomTexture = NULL ; + initialized = FALSE ; } void LLPostProcess::apply(unsigned int width, unsigned int height) { - if (!initialized || width != screenW || height != screenH){ - initialize(width, height); - } - if (shadersEnabled()){ - doEffects(); - } + if (!initialized || width != screenW || height != screenH){ + initialize(width, height); + } + if (shadersEnabled()){ + doEffects(); + } } void LLPostProcess::initialize(unsigned int width, unsigned int height) { - screenW = width; - screenH = height; - createTexture(mSceneRenderTexture, screenW, screenH); - initialized = true; - - checkError(); - createNightVisionShader(); - createBloomShader(); - createColorFilterShader(); - checkError(); + screenW = width; + screenH = height; + createTexture(mSceneRenderTexture, screenW, screenH); + initialized = true; + + checkError(); + createNightVisionShader(); + createBloomShader(); + createColorFilterShader(); + checkError(); } inline bool LLPostProcess::shadersEnabled(void) { - return (tweaks.useColorFilter().asBoolean() || - tweaks.useNightVisionShader().asBoolean() || - tweaks.useBloomShader().asBoolean() ); + return (tweaks.useColorFilter().asBoolean() || + tweaks.useNightVisionShader().asBoolean() || + tweaks.useBloomShader().asBoolean() ); } void LLPostProcess::applyShaders(void) { - if (tweaks.useColorFilter()){ - applyColorFilterShader(); - checkError(); - } - if (tweaks.useNightVisionShader()){ - /// If any of the above shaders have been called update the frame buffer; - if (tweaks.useColorFilter()) - { - U32 tex = mSceneRenderTexture->getTexName() ; - copyFrameBuffer(tex, screenW, screenH); - } - applyNightVisionShader(); - checkError(); - } - if (tweaks.useBloomShader()){ - /// If any of the above shaders have been called update the frame buffer; - if (tweaks.useColorFilter().asBoolean() || tweaks.useNightVisionShader().asBoolean()) - { - U32 tex = mSceneRenderTexture->getTexName() ; - copyFrameBuffer(tex, screenW, screenH); - } - applyBloomShader(); - checkError(); - } + if (tweaks.useColorFilter()){ + applyColorFilterShader(); + checkError(); + } + if (tweaks.useNightVisionShader()){ + /// If any of the above shaders have been called update the frame buffer; + if (tweaks.useColorFilter()) + { + U32 tex = mSceneRenderTexture->getTexName() ; + copyFrameBuffer(tex, screenW, screenH); + } + applyNightVisionShader(); + checkError(); + } + if (tweaks.useBloomShader()){ + /// If any of the above shaders have been called update the frame buffer; + if (tweaks.useColorFilter().asBoolean() || tweaks.useNightVisionShader().asBoolean()) + { + U32 tex = mSceneRenderTexture->getTexName() ; + copyFrameBuffer(tex, screenW, screenH); + } + applyBloomShader(); + checkError(); + } } void LLPostProcess::applyColorFilterShader(void) -{ - +{ + } void LLPostProcess::createColorFilterShader(void) { - /// Define uniform names - colorFilterUniforms[sRenderTexture] = 0; - colorFilterUniforms[sBrightness] = 0; - colorFilterUniforms[sContrast] = 0; - colorFilterUniforms[sContrastBase] = 0; - colorFilterUniforms[sSaturation] = 0; - colorFilterUniforms[sLumWeights] = 0; + /// Define uniform names + colorFilterUniforms[sRenderTexture] = 0; + colorFilterUniforms[sBrightness] = 0; + colorFilterUniforms[sContrast] = 0; + colorFilterUniforms[sContrastBase] = 0; + colorFilterUniforms[sSaturation] = 0; + colorFilterUniforms[sLumWeights] = 0; } void LLPostProcess::applyNightVisionShader(void) -{ - +{ + } void LLPostProcess::createNightVisionShader(void) { - /// Define uniform names - nightVisionUniforms[sRenderTexture] = 0; - nightVisionUniforms[sNoiseTexture] = 0; - nightVisionUniforms[sBrightMult] = 0; - nightVisionUniforms[sNoiseStrength] = 0; - nightVisionUniforms[sLumWeights] = 0; - - createNoiseTexture(mNoiseTexture); + /// Define uniform names + nightVisionUniforms[sRenderTexture] = 0; + nightVisionUniforms[sNoiseTexture] = 0; + nightVisionUniforms[sBrightMult] = 0; + nightVisionUniforms[sNoiseStrength] = 0; + nightVisionUniforms[sLumWeights] = 0; + + createNoiseTexture(mNoiseTexture); } void LLPostProcess::applyBloomShader(void) @@ -268,69 +268,69 @@ void LLPostProcess::applyBloomShader(void) void LLPostProcess::createBloomShader(void) { - createTexture(mTempBloomTexture, unsigned(screenW * 0.5), unsigned(screenH * 0.5)); - - /// Create Bloom Extract Shader - bloomExtractUniforms[sRenderTexture] = 0; - bloomExtractUniforms[sExtractLow] = 0; - bloomExtractUniforms[sExtractHigh] = 0; - bloomExtractUniforms[sLumWeights] = 0; - - /// Create Bloom Blur Shader - bloomBlurUniforms[sRenderTexture] = 0; - bloomBlurUniforms[sBloomStrength] = 0; - bloomBlurUniforms[sTexelSize] = 0; - bloomBlurUniforms[sBlurDirection] = 0; - bloomBlurUniforms[sBlurWidth] = 0; + createTexture(mTempBloomTexture, unsigned(screenW * 0.5), unsigned(screenH * 0.5)); + + /// Create Bloom Extract Shader + bloomExtractUniforms[sRenderTexture] = 0; + bloomExtractUniforms[sExtractLow] = 0; + bloomExtractUniforms[sExtractHigh] = 0; + bloomExtractUniforms[sLumWeights] = 0; + + /// Create Bloom Blur Shader + bloomBlurUniforms[sRenderTexture] = 0; + bloomBlurUniforms[sBloomStrength] = 0; + bloomBlurUniforms[sTexelSize] = 0; + bloomBlurUniforms[sBlurDirection] = 0; + bloomBlurUniforms[sBlurWidth] = 0; } void LLPostProcess::getShaderUniforms(glslUniforms & uniforms, GLuint & prog) { - /// Find uniform locations and insert into map - glslUniforms::iterator i; - for (i = uniforms.begin(); i != uniforms.end(); ++i){ - i->second = glGetUniformLocation(prog, i->first.String().c_str()); - } + /// Find uniform locations and insert into map + glslUniforms::iterator i; + for (i = uniforms.begin(); i != uniforms.end(); ++i){ + i->second = glGetUniformLocation(prog, i->first.String().c_str()); + } } void LLPostProcess::doEffects(void) { - /// Save GL State - glPushAttrib(GL_ALL_ATTRIB_BITS); - glPushClientAttrib(GL_ALL_ATTRIB_BITS); - - /// Copy the screen buffer to the render texture - { - U32 tex = mSceneRenderTexture->getTexName() ; - copyFrameBuffer(tex, screenW, screenH); - } - - /// Clear the frame buffer. - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); - - /// Change to an orthogonal view - viewOrthogonal(screenW, screenH); - - checkError(); - applyShaders(); - - LLGLSLShader::unbind(); - checkError(); - - /// Change to a perspective view - viewPerspective(); - - /// Reset GL State - glPopClientAttrib(); - glPopAttrib(); - checkError(); + /// Save GL State + glPushAttrib(GL_ALL_ATTRIB_BITS); + glPushClientAttrib(GL_ALL_ATTRIB_BITS); + + /// Copy the screen buffer to the render texture + { + U32 tex = mSceneRenderTexture->getTexName() ; + copyFrameBuffer(tex, screenW, screenH); + } + + /// Clear the frame buffer. + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + + /// Change to an orthogonal view + viewOrthogonal(screenW, screenH); + + checkError(); + applyShaders(); + + LLGLSLShader::unbind(); + checkError(); + + /// Change to a perspective view + viewPerspective(); + + /// Reset GL State + glPopClientAttrib(); + glPopAttrib(); + checkError(); } void LLPostProcess::copyFrameBuffer(U32 & texture, unsigned int width, unsigned int height) { - gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, texture); - glCopyTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_RGBA, 0, 0, width, height, 0); + gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, texture); + glCopyTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_RGBA, 0, 0, width, height, 0); } void LLPostProcess::drawOrthoQuad(unsigned int width, unsigned int height, QuadType type) @@ -340,84 +340,84 @@ void LLPostProcess::drawOrthoQuad(unsigned int width, unsigned int height, QuadT void LLPostProcess::viewOrthogonal(unsigned int width, unsigned int height) { - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.pushMatrix(); - gGL.loadIdentity(); - gGL.ortho( 0.f, (GLdouble) width , (GLdouble) height , 0.f, -1.f, 1.f ); - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.pushMatrix(); - gGL.loadIdentity(); + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.pushMatrix(); + gGL.loadIdentity(); + gGL.ortho( 0.f, (GLdouble) width , (GLdouble) height , 0.f, -1.f, 1.f ); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.pushMatrix(); + gGL.loadIdentity(); } void LLPostProcess::viewPerspective(void) { - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.popMatrix(); - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.popMatrix(); + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.popMatrix(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.popMatrix(); } void LLPostProcess::changeOrthogonal(unsigned int width, unsigned int height) { - viewPerspective(); - viewOrthogonal(width, height); + viewPerspective(); + viewOrthogonal(width, height); } void LLPostProcess::createTexture(LLPointer<LLImageGL>& texture, unsigned int width, unsigned int height) { - std::vector<GLubyte> data(width * height * 4, 0) ; - - texture = new LLImageGL(FALSE) ; - if(texture->createGLTexture()) - { - gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, texture->getTexName()); - glTexImage2D(GL_TEXTURE_RECTANGLE, 0, 4, width, height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, &data[0]); - gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); - gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); - } + std::vector<GLubyte> data(width * height * 4, 0) ; + + texture = new LLImageGL(FALSE) ; + if(texture->createGLTexture()) + { + gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, texture->getTexName()); + glTexImage2D(GL_TEXTURE_RECTANGLE, 0, 4, width, height, 0, + GL_RGBA, GL_UNSIGNED_BYTE, &data[0]); + gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); + } } void LLPostProcess::createNoiseTexture(LLPointer<LLImageGL>& texture) -{ - std::vector<GLubyte> buffer(NOISE_SIZE * NOISE_SIZE); - for (unsigned int i = 0; i < NOISE_SIZE; i++){ - for (unsigned int k = 0; k < NOISE_SIZE; k++){ - buffer[(i * NOISE_SIZE) + k] = (GLubyte)((double) rand() / ((double) RAND_MAX + 1.f) * 255.f); - } - } - - texture = new LLImageGL(FALSE) ; - if(texture->createGLTexture()) - { - gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, texture->getTexName()); - LLImageGL::setManualImage(GL_TEXTURE_2D, 0, GL_LUMINANCE, NOISE_SIZE, NOISE_SIZE, GL_LUMINANCE, GL_UNSIGNED_BYTE, &buffer[0]); - gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); - gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_WRAP); - } +{ + std::vector<GLubyte> buffer(NOISE_SIZE * NOISE_SIZE); + for (unsigned int i = 0; i < NOISE_SIZE; i++){ + for (unsigned int k = 0; k < NOISE_SIZE; k++){ + buffer[(i * NOISE_SIZE) + k] = (GLubyte)((double) rand() / ((double) RAND_MAX + 1.f) * 255.f); + } + } + + texture = new LLImageGL(FALSE) ; + if(texture->createGLTexture()) + { + gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, texture->getTexName()); + LLImageGL::setManualImage(GL_TEXTURE_2D, 0, GL_LUMINANCE, NOISE_SIZE, NOISE_SIZE, GL_LUMINANCE, GL_UNSIGNED_BYTE, &buffer[0]); + gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_WRAP); + } } bool LLPostProcess::checkError(void) { - GLenum glErr; + GLenum glErr; bool retCode = false; glErr = glGetError(); while (glErr != GL_NO_ERROR) { - // shaderErrorLog << (const char *) gluErrorString(glErr) << std::endl; - char const * err_str_raw = (const char *) gluErrorString(glErr); - - if(err_str_raw == NULL) - { - std::ostringstream err_builder; - err_builder << "unknown error number " << glErr; - mShaderErrorString = err_builder.str(); - } - else - { - mShaderErrorString = err_str_raw; - } + // shaderErrorLog << (const char *) gluErrorString(glErr) << std::endl; + char const * err_str_raw = (const char *) gluErrorString(glErr); + + if(err_str_raw == NULL) + { + std::ostringstream err_builder; + err_builder << "unknown error number " << glErr; + mShaderErrorString = err_builder.str(); + } + else + { + mShaderErrorString = err_str_raw; + } retCode = true; glErr = glGetError(); @@ -446,8 +446,8 @@ void LLPostProcess::checkShaderError(GLuint shader) return; } glGetProgramInfoLog(shader, infologLength, &charsWritten, infoLog); - // shaderErrorLog << (char *) infoLog << std::endl; - mShaderErrorString = (char *) infoLog; + // shaderErrorLog << (char *) infoLog << std::endl; + mShaderErrorString = (char *) infoLog; free(infoLog); } checkError(); // Check for OpenGL errors diff --git a/indra/llrender/llpostprocess.h b/indra/llrender/llpostprocess.h index bdfc632831..b5b7549efb 100644 --- a/indra/llrender/llpostprocess.h +++ b/indra/llrender/llpostprocess.h @@ -1,25 +1,25 @@ -/** +/** * @file llpostprocess.h * @brief LLPostProcess class definition * * $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$ */ @@ -33,232 +33,232 @@ #include "llglheaders.h" #include "llstaticstringtable.h" -class LLPostProcess +class LLPostProcess { public: - typedef enum _QuadType { - QUAD_NORMAL, - QUAD_NOISE, - QUAD_BLOOM_EXTRACT, - QUAD_BLOOM_COMBINE - } QuadType; + typedef enum _QuadType { + QUAD_NORMAL, + QUAD_NOISE, + QUAD_BLOOM_EXTRACT, + QUAD_BLOOM_COMBINE + } QuadType; + + /// GLSL Shader Encapsulation Struct + typedef LLStaticStringTable<GLuint> glslUniforms; - /// GLSL Shader Encapsulation Struct - typedef LLStaticStringTable<GLuint> glslUniforms; + struct PostProcessTweaks : public LLSD { + inline PostProcessTweaks() : LLSD(LLSD::emptyMap()) + { + } - struct PostProcessTweaks : public LLSD { - inline PostProcessTweaks() : LLSD(LLSD::emptyMap()) - { - } + inline LLSD & brightMult() { + return (*this)["brightness_multiplier"]; + } - inline LLSD & brightMult() { - return (*this)["brightness_multiplier"]; - } + inline LLSD & noiseStrength() { + return (*this)["noise_strength"]; + } - inline LLSD & noiseStrength() { - return (*this)["noise_strength"]; - } + inline LLSD & noiseSize() { + return (*this)["noise_size"]; + } - inline LLSD & noiseSize() { - return (*this)["noise_size"]; - } + inline LLSD & extractLow() { + return (*this)["extract_low"]; + } - inline LLSD & extractLow() { - return (*this)["extract_low"]; - } + inline LLSD & extractHigh() { + return (*this)["extract_high"]; + } - inline LLSD & extractHigh() { - return (*this)["extract_high"]; - } + inline LLSD & bloomWidth() { + return (*this)["bloom_width"]; + } - inline LLSD & bloomWidth() { - return (*this)["bloom_width"]; - } + inline LLSD & bloomStrength() { + return (*this)["bloom_strength"]; + } - inline LLSD & bloomStrength() { - return (*this)["bloom_strength"]; - } + inline LLSD & brightness() { + return (*this)["brightness"]; + } - inline LLSD & brightness() { - return (*this)["brightness"]; - } + inline LLSD & contrast() { + return (*this)["contrast"]; + } - inline LLSD & contrast() { - return (*this)["contrast"]; - } + inline LLSD & contrastBaseR() { + return (*this)["contrast_base"][0]; + } - inline LLSD & contrastBaseR() { - return (*this)["contrast_base"][0]; - } + inline LLSD & contrastBaseG() { + return (*this)["contrast_base"][1]; + } - inline LLSD & contrastBaseG() { - return (*this)["contrast_base"][1]; - } + inline LLSD & contrastBaseB() { + return (*this)["contrast_base"][2]; + } - inline LLSD & contrastBaseB() { - return (*this)["contrast_base"][2]; - } + inline LLSD & contrastBaseIntensity() { + return (*this)["contrast_base"][3]; + } - inline LLSD & contrastBaseIntensity() { - return (*this)["contrast_base"][3]; - } + inline LLSD & saturation() { + return (*this)["saturation"]; + } - inline LLSD & saturation() { - return (*this)["saturation"]; - } + inline LLSD & useNightVisionShader() { + return (*this)["enable_night_vision"]; + } - inline LLSD & useNightVisionShader() { - return (*this)["enable_night_vision"]; - } + inline LLSD & useBloomShader() { + return (*this)["enable_bloom"]; + } - inline LLSD & useBloomShader() { - return (*this)["enable_bloom"]; - } + inline LLSD & useColorFilter() { + return (*this)["enable_color_filter"]; + } - inline LLSD & useColorFilter() { - return (*this)["enable_color_filter"]; - } + inline F32 getBrightMult() const { + return F32((*this)["brightness_multiplier"].asReal()); + } - inline F32 getBrightMult() const { - return F32((*this)["brightness_multiplier"].asReal()); - } + inline F32 getNoiseStrength() const { + return F32((*this)["noise_strength"].asReal()); + } - inline F32 getNoiseStrength() const { - return F32((*this)["noise_strength"].asReal()); - } + inline F32 getNoiseSize() const { + return F32((*this)["noise_size"].asReal()); + } - inline F32 getNoiseSize() const { - return F32((*this)["noise_size"].asReal()); - } + inline F32 getExtractLow() const { + return F32((*this)["extract_low"].asReal()); + } - inline F32 getExtractLow() const { - return F32((*this)["extract_low"].asReal()); - } + inline F32 getExtractHigh() const { + return F32((*this)["extract_high"].asReal()); + } - inline F32 getExtractHigh() const { - return F32((*this)["extract_high"].asReal()); - } + inline F32 getBloomWidth() const { + return F32((*this)["bloom_width"].asReal()); + } - inline F32 getBloomWidth() const { - return F32((*this)["bloom_width"].asReal()); - } + inline F32 getBloomStrength() const { + return F32((*this)["bloom_strength"].asReal()); + } - inline F32 getBloomStrength() const { - return F32((*this)["bloom_strength"].asReal()); - } + inline F32 getBrightness() const { + return F32((*this)["brightness"].asReal()); + } - inline F32 getBrightness() const { - return F32((*this)["brightness"].asReal()); - } + inline F32 getContrast() const { + return F32((*this)["contrast"].asReal()); + } - inline F32 getContrast() const { - return F32((*this)["contrast"].asReal()); - } + inline F32 getContrastBaseR() const { + return F32((*this)["contrast_base"][0].asReal()); + } - inline F32 getContrastBaseR() const { - return F32((*this)["contrast_base"][0].asReal()); - } + inline F32 getContrastBaseG() const { + return F32((*this)["contrast_base"][1].asReal()); + } - inline F32 getContrastBaseG() const { - return F32((*this)["contrast_base"][1].asReal()); - } + inline F32 getContrastBaseB() const { + return F32((*this)["contrast_base"][2].asReal()); + } - inline F32 getContrastBaseB() const { - return F32((*this)["contrast_base"][2].asReal()); - } + inline F32 getContrastBaseIntensity() const { + return F32((*this)["contrast_base"][3].asReal()); + } - inline F32 getContrastBaseIntensity() const { - return F32((*this)["contrast_base"][3].asReal()); - } + inline F32 getSaturation() const { + return F32((*this)["saturation"].asReal()); + } - inline F32 getSaturation() const { - return F32((*this)["saturation"].asReal()); - } + }; - }; - - bool initialized; - PostProcessTweaks tweaks; + bool initialized; + PostProcessTweaks tweaks; - // the map of all availible effects - LLSD mAllEffects; + // the map of all availible effects + LLSD mAllEffects; private: - LLPointer<LLImageGL> mSceneRenderTexture ; - LLPointer<LLImageGL> mNoiseTexture ; - LLPointer<LLImageGL> mTempBloomTexture ; + LLPointer<LLImageGL> mSceneRenderTexture ; + LLPointer<LLImageGL> mNoiseTexture ; + LLPointer<LLImageGL> mTempBloomTexture ; public: - LLPostProcess(void); + LLPostProcess(void); - ~LLPostProcess(void); + ~LLPostProcess(void); - void apply(unsigned int width, unsigned int height); - void invalidate() ; + void apply(unsigned int width, unsigned int height); + void invalidate() ; - /// Perform global initialization for this class. - static void initClass(void); + /// Perform global initialization for this class. + static void initClass(void); - // Cleanup of global data that's only inited once per class. - static void cleanupClass(); + // Cleanup of global data that's only inited once per class. + static void cleanupClass(); - void setSelectedEffect(std::string const & effectName); + void setSelectedEffect(std::string const & effectName); - inline std::string const & getSelectedEffect(void) const { - return mSelectedEffectName; - } + inline std::string const & getSelectedEffect(void) const { + return mSelectedEffectName; + } - void saveEffect(std::string const & effectName); + void saveEffect(std::string const & effectName); private: - /// read in from file - std::string mShaderErrorString; - unsigned int screenW; - unsigned int screenH; - - float noiseTextureScale; - - /// Shader Uniforms - glslUniforms nightVisionUniforms; - glslUniforms bloomExtractUniforms; - glslUniforms bloomBlurUniforms; - glslUniforms colorFilterUniforms; - - // the name of currently selected effect in mAllEffects - // invariant: tweaks == mAllEffects[mSelectedEffectName] - std::string mSelectedEffectName; - - /// General functions - void initialize(unsigned int width, unsigned int height); - void doEffects(void); - void applyShaders(void); - bool shadersEnabled(void); - - /// Night Vision Functions - void createNightVisionShader(void); - void applyNightVisionShader(void); - - /// Bloom Functions - void createBloomShader(void); - void applyBloomShader(void); - - /// Color Filter Functions - void createColorFilterShader(void); - void applyColorFilterShader(void); - - /// OpenGL Helper Functions - void getShaderUniforms(glslUniforms & uniforms, GLuint & prog); - void createTexture(LLPointer<LLImageGL>& texture, unsigned int width, unsigned int height); - void copyFrameBuffer(U32 & texture, unsigned int width, unsigned int height); - void createNoiseTexture(LLPointer<LLImageGL>& texture); - bool checkError(void); - void checkShaderError(GLuint shader); - void drawOrthoQuad(unsigned int width, unsigned int height, QuadType type); - void viewOrthogonal(unsigned int width, unsigned int height); - void changeOrthogonal(unsigned int width, unsigned int height); - void viewPerspective(void); + /// read in from file + std::string mShaderErrorString; + unsigned int screenW; + unsigned int screenH; + + float noiseTextureScale; + + /// Shader Uniforms + glslUniforms nightVisionUniforms; + glslUniforms bloomExtractUniforms; + glslUniforms bloomBlurUniforms; + glslUniforms colorFilterUniforms; + + // the name of currently selected effect in mAllEffects + // invariant: tweaks == mAllEffects[mSelectedEffectName] + std::string mSelectedEffectName; + + /// General functions + void initialize(unsigned int width, unsigned int height); + void doEffects(void); + void applyShaders(void); + bool shadersEnabled(void); + + /// Night Vision Functions + void createNightVisionShader(void); + void applyNightVisionShader(void); + + /// Bloom Functions + void createBloomShader(void); + void applyBloomShader(void); + + /// Color Filter Functions + void createColorFilterShader(void); + void applyColorFilterShader(void); + + /// OpenGL Helper Functions + void getShaderUniforms(glslUniforms & uniforms, GLuint & prog); + void createTexture(LLPointer<LLImageGL>& texture, unsigned int width, unsigned int height); + void copyFrameBuffer(U32 & texture, unsigned int width, unsigned int height); + void createNoiseTexture(LLPointer<LLImageGL>& texture); + bool checkError(void); + void checkShaderError(GLuint shader); + void drawOrthoQuad(unsigned int width, unsigned int height, QuadType type); + void viewOrthogonal(unsigned int width, unsigned int height); + void changeOrthogonal(unsigned int width, unsigned int height); + void viewPerspective(void); }; extern LLPostProcess * gPostProcess; diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h index 716b52354d..ebdc9e751d 100644 --- a/indra/llrender/llrender.h +++ b/indra/llrender/llrender.h @@ -1,30 +1,30 @@ -/** +/** * @file llrender.h * @brief LLRender definition * - * This class acts as a wrapper for OpenGL calls. - * The goal of this class is to minimize the number of api calls due to legacy rendering - * code, to define an interface for a multiple rendering API abstraction of the UI - * rendering, and to abstract out direct rendering calls in a way that is cleaner and easier to maintain. + * This class acts as a wrapper for OpenGL calls. + * The goal of this class is to minimize the number of api calls due to legacy rendering + * code, to define an interface for a multiple rendering API abstraction of the UI + * rendering, and to abstract out direct rendering calls in a way that is cleaner and easier to maintain. * * $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$ */ @@ -57,89 +57,89 @@ class LLTexture ; constexpr U32 LL_NUM_TEXTURE_LAYERS = 32; constexpr U32 LL_NUM_LIGHT_UNITS = 8; -class LLTexUnit +class LLTexUnit { - friend class LLRender; + friend class LLRender; public: - static U32 sWhiteTexture; - - typedef enum - { - TT_TEXTURE = 0, // Standard 2D Texture - TT_RECT_TEXTURE, // Non power of 2 texture - TT_CUBE_MAP, // 6-sided cube map texture - TT_CUBE_MAP_ARRAY, // Array of cube maps - TT_MULTISAMPLE_TEXTURE, // see GL_ARB_texture_multisample + static U32 sWhiteTexture; + + typedef enum + { + TT_TEXTURE = 0, // Standard 2D Texture + TT_RECT_TEXTURE, // Non power of 2 texture + TT_CUBE_MAP, // 6-sided cube map texture + TT_CUBE_MAP_ARRAY, // Array of cube maps + TT_MULTISAMPLE_TEXTURE, // see GL_ARB_texture_multisample TT_TEXTURE_3D, // standard 3D Texture - TT_NONE, // No texture type is currently enabled - } eTextureType; - - typedef enum - { - TAM_WRAP = 0, // Standard 2D Texture - TAM_MIRROR, // Non power of 2 texture - TAM_CLAMP // No texture type is currently enabled - } eTextureAddressMode; - - typedef enum - { // Note: If mipmapping or anisotropic are not enabled or supported it should fall back gracefully - TFO_POINT = 0, // Equal to: min=point, mag=point, mip=none. - TFO_BILINEAR, // Equal to: min=linear, mag=linear, mip=point. - TFO_TRILINEAR, // Equal to: min=linear, mag=linear, mip=linear. - TFO_ANISOTROPIC // Equal to: min=anisotropic, max=anisotropic, mip=linear. - } eTextureFilterOptions; - - typedef enum - { - TMG_NONE = 0, // Mipmaps are not automatically generated for this texture. - TMG_AUTO, // Mipmaps are automatically generated for this texture. - TMG_MANUAL // Mipmaps are manually generated for this texture. - } eTextureMipGeneration; - - typedef enum - { - TB_REPLACE = 0, - TB_ADD, - TB_MULT, - TB_MULT_X2, - TB_ALPHA_BLEND, - TB_COMBINE // Doesn't need to be set directly, setTexture___Blend() set TB_COMBINE automatically - } eTextureBlendType; - - typedef enum - { - TBO_REPLACE = 0, // Use Source 1 - TBO_MULT, // Multiply: ( Source1 * Source2 ) - TBO_MULT_X2, // Multiply then scale by 2: ( 2.0 * ( Source1 * Source2 ) ) - TBO_MULT_X4, // Multiply then scale by 4: ( 4.0 * ( Source1 * Source2 ) ) - TBO_ADD, // Add: ( Source1 + Source2 ) - TBO_ADD_SIGNED, // Add then subtract 0.5: ( ( Source1 + Source2 ) - 0.5 ) - TBO_SUBTRACT, // Subtract Source2 from Source1: ( Source1 - Source2 ) - TBO_LERP_VERT_ALPHA, // Interpolate based on Vertex Alpha (VA): ( Source1 * VA + Source2 * (1-VA) ) - TBO_LERP_TEX_ALPHA, // Interpolate based on Texture Alpha (TA): ( Source1 * TA + Source2 * (1-TA) ) - TBO_LERP_PREV_ALPHA, // Interpolate based on Previous Alpha (PA): ( Source1 * PA + Source2 * (1-PA) ) - TBO_LERP_CONST_ALPHA // Interpolate based on Const Alpha (CA): ( Source1 * CA + Source2 * (1-CA) ) - } eTextureBlendOp; - - typedef enum - { - TBS_PREV_COLOR = 0, // Color from the previous texture stage - TBS_PREV_ALPHA, - TBS_ONE_MINUS_PREV_COLOR, - TBS_ONE_MINUS_PREV_ALPHA, - TBS_TEX_COLOR, // Color from the texture bound to this stage - TBS_TEX_ALPHA, - TBS_ONE_MINUS_TEX_COLOR, - TBS_ONE_MINUS_TEX_ALPHA, - TBS_VERT_COLOR, // The vertex color currently set - TBS_VERT_ALPHA, - TBS_ONE_MINUS_VERT_COLOR, - TBS_ONE_MINUS_VERT_ALPHA, - TBS_CONST_COLOR, // The constant color value currently set - TBS_CONST_ALPHA, - TBS_ONE_MINUS_CONST_COLOR, - TBS_ONE_MINUS_CONST_ALPHA - } eTextureBlendSrc; + TT_NONE, // No texture type is currently enabled + } eTextureType; + + typedef enum + { + TAM_WRAP = 0, // Standard 2D Texture + TAM_MIRROR, // Non power of 2 texture + TAM_CLAMP // No texture type is currently enabled + } eTextureAddressMode; + + typedef enum + { // Note: If mipmapping or anisotropic are not enabled or supported it should fall back gracefully + TFO_POINT = 0, // Equal to: min=point, mag=point, mip=none. + TFO_BILINEAR, // Equal to: min=linear, mag=linear, mip=point. + TFO_TRILINEAR, // Equal to: min=linear, mag=linear, mip=linear. + TFO_ANISOTROPIC // Equal to: min=anisotropic, max=anisotropic, mip=linear. + } eTextureFilterOptions; + + typedef enum + { + TMG_NONE = 0, // Mipmaps are not automatically generated for this texture. + TMG_AUTO, // Mipmaps are automatically generated for this texture. + TMG_MANUAL // Mipmaps are manually generated for this texture. + } eTextureMipGeneration; + + typedef enum + { + TB_REPLACE = 0, + TB_ADD, + TB_MULT, + TB_MULT_X2, + TB_ALPHA_BLEND, + TB_COMBINE // Doesn't need to be set directly, setTexture___Blend() set TB_COMBINE automatically + } eTextureBlendType; + + typedef enum + { + TBO_REPLACE = 0, // Use Source 1 + TBO_MULT, // Multiply: ( Source1 * Source2 ) + TBO_MULT_X2, // Multiply then scale by 2: ( 2.0 * ( Source1 * Source2 ) ) + TBO_MULT_X4, // Multiply then scale by 4: ( 4.0 * ( Source1 * Source2 ) ) + TBO_ADD, // Add: ( Source1 + Source2 ) + TBO_ADD_SIGNED, // Add then subtract 0.5: ( ( Source1 + Source2 ) - 0.5 ) + TBO_SUBTRACT, // Subtract Source2 from Source1: ( Source1 - Source2 ) + TBO_LERP_VERT_ALPHA, // Interpolate based on Vertex Alpha (VA): ( Source1 * VA + Source2 * (1-VA) ) + TBO_LERP_TEX_ALPHA, // Interpolate based on Texture Alpha (TA): ( Source1 * TA + Source2 * (1-TA) ) + TBO_LERP_PREV_ALPHA, // Interpolate based on Previous Alpha (PA): ( Source1 * PA + Source2 * (1-PA) ) + TBO_LERP_CONST_ALPHA // Interpolate based on Const Alpha (CA): ( Source1 * CA + Source2 * (1-CA) ) + } eTextureBlendOp; + + typedef enum + { + TBS_PREV_COLOR = 0, // Color from the previous texture stage + TBS_PREV_ALPHA, + TBS_ONE_MINUS_PREV_COLOR, + TBS_ONE_MINUS_PREV_ALPHA, + TBS_TEX_COLOR, // Color from the texture bound to this stage + TBS_TEX_ALPHA, + TBS_ONE_MINUS_TEX_COLOR, + TBS_ONE_MINUS_TEX_ALPHA, + TBS_VERT_COLOR, // The vertex color currently set + TBS_VERT_ALPHA, + TBS_ONE_MINUS_VERT_COLOR, + TBS_ONE_MINUS_VERT_ALPHA, + TBS_CONST_COLOR, // The constant color value currently set + TBS_CONST_ALPHA, + TBS_ONE_MINUS_CONST_COLOR, + TBS_ONE_MINUS_CONST_ALPHA + } eTextureBlendSrc; typedef enum { @@ -147,77 +147,77 @@ public: TCS_SRGB } eTextureColorSpace; - LLTexUnit(S32 index = -1); + LLTexUnit(S32 index = -1); + + // Refreshes renderer state of the texture unit to the cached values + // Needed when the render context has changed and invalidated the current state + void refreshState(void); - // Refreshes renderer state of the texture unit to the cached values - // Needed when the render context has changed and invalidated the current state - void refreshState(void); + // returns the index of this texture unit + S32 getIndex(void) const { return mIndex; } - // returns the index of this texture unit - S32 getIndex(void) const { return mIndex; } + // Sets this tex unit to be the currently active one + void activate(void); - // Sets this tex unit to be the currently active one - void activate(void); + // Enables this texture unit for the given texture type + // (automatically disables any previously enabled texture type) + void enable(eTextureType type); - // Enables this texture unit for the given texture type - // (automatically disables any previously enabled texture type) - void enable(eTextureType type); + // Disables the current texture unit + void disable(void); - // Disables the current texture unit - void disable(void); - - // Binds the LLImageGL to this texture unit - // (automatically enables the unit for the LLImageGL's texture type) - bool bind(LLImageGL* texture, bool for_rendering = false, bool forceBind = false, S32 usename = 0); + // Binds the LLImageGL to this texture unit + // (automatically enables the unit for the LLImageGL's texture type) + bool bind(LLImageGL* texture, bool for_rendering = false, bool forceBind = false, S32 usename = 0); bool bind(LLTexture* texture, bool for_rendering = false, bool forceBind = false); // bind implementation for inner loops // makes the following assumptions: - // - No need for gGL.flush() + // - No need for gGL.flush() // - texture is not null // - gl_tex->getTexName() is not zero // - This texture is not being bound redundantly // - USE_SRGB_DECODE is disabled // - mTexOptionsDirty is false - // - + // - void bindFast(LLTexture* texture); - // Binds a cubemap to this texture unit - // (automatically enables the texture unit for cubemaps) - bool bind(LLCubeMap* cubeMap); + // Binds a cubemap to this texture unit + // (automatically enables the texture unit for cubemaps) + bool bind(LLCubeMap* cubeMap); - // Binds a render target to this texture unit - // (automatically enables the texture unit for the RT's texture type) - bool bind(LLRenderTarget * renderTarget, bool bindDepth = false); + // Binds a render target to this texture unit + // (automatically enables the texture unit for the RT's texture type) + bool bind(LLRenderTarget * renderTarget, bool bindDepth = false); - // Manually binds a texture to the texture unit - // (automatically enables the tex unit for the given texture type) - bool bindManual(eTextureType type, U32 texture, bool hasMips = false); - - // Unbinds the currently bound texture of the given type - // (only if there's a texture of the given type currently bound) - void unbind(eTextureType type); + // Manually binds a texture to the texture unit + // (automatically enables the tex unit for the given texture type) + bool bindManual(eTextureType type, U32 texture, bool hasMips = false); + + // Unbinds the currently bound texture of the given type + // (only if there's a texture of the given type currently bound) + void unbind(eTextureType type); // Fast but unsafe version of unbind void unbindFast(eTextureType type); - // Sets the addressing mode used to sample the texture - // Warning: this stays set for the bound texture forever, - // make sure you want to permanently change the address mode for the bound texture. - void setTextureAddressMode(eTextureAddressMode mode); + // Sets the addressing mode used to sample the texture + // Warning: this stays set for the bound texture forever, + // make sure you want to permanently change the address mode for the bound texture. + void setTextureAddressMode(eTextureAddressMode mode); - // Sets the filtering options used to sample the texture - // Warning: this stays set for the bound texture forever, - // make sure you want to permanently change the filtering for the bound texture. - void setTextureFilteringOption(LLTexUnit::eTextureFilterOptions option); + // Sets the filtering options used to sample the texture + // Warning: this stays set for the bound texture forever, + // make sure you want to permanently change the filtering for the bound texture. + void setTextureFilteringOption(LLTexUnit::eTextureFilterOptions option); - static U32 getInternalType(eTextureType type); + static U32 getInternalType(eTextureType type); - U32 getCurrTexture(void) { return mCurrTexture; } + U32 getCurrTexture(void) { return mCurrTexture; } - eTextureType getCurrType(void) { return mCurrTexType; } + eTextureType getCurrType(void) { return mCurrTexType; } - void setHasMipMaps(bool hasMips) { mHasMipMaps = hasMips; } + void setHasMipMaps(bool hasMips) { mHasMipMaps = hasMips; } void setTextureColorSpace(eTextureColorSpace space); @@ -226,293 +226,293 @@ public: protected: friend class LLRender; - S32 mIndex; - U32 mCurrTexture; - eTextureType mCurrTexType; + S32 mIndex; + U32 mCurrTexture; + eTextureType mCurrTexType; eTextureColorSpace mTexColorSpace; - S32 mCurrColorScale; - S32 mCurrAlphaScale; - bool mHasMipMaps; - - void debugTextureUnit(void); - void setColorScale(S32 scale); - void setAlphaScale(S32 scale); - GLint getTextureSource(eTextureBlendSrc src); - GLint getTextureSourceType(eTextureBlendSrc src, bool isAlpha = false); + S32 mCurrColorScale; + S32 mCurrAlphaScale; + bool mHasMipMaps; + + void debugTextureUnit(void); + void setColorScale(S32 scale); + void setAlphaScale(S32 scale); + GLint getTextureSource(eTextureBlendSrc src); + GLint getTextureSourceType(eTextureBlendSrc src, bool isAlpha = false); }; class LLLightState { public: - LLLightState(S32 index = -1); + LLLightState(S32 index = -1); - void enable(); - void disable(); - void setDiffuse(const LLColor4& diffuse); + void enable(); + void disable(); + void setDiffuse(const LLColor4& diffuse); void setDiffuseB(const LLColor4& diffuse); - void setAmbient(const LLColor4& ambient); - void setSpecular(const LLColor4& specular); - void setPosition(const LLVector4& position); - void setConstantAttenuation(const F32& atten); - void setLinearAttenuation(const F32& atten); - void setQuadraticAttenuation(const F32& atten); - void setSpotExponent(const F32& exponent); - void setSpotCutoff(const F32& cutoff); - void setSpotDirection(const LLVector3& direction); + void setAmbient(const LLColor4& ambient); + void setSpecular(const LLColor4& specular); + void setPosition(const LLVector4& position); + void setConstantAttenuation(const F32& atten); + void setLinearAttenuation(const F32& atten); + void setQuadraticAttenuation(const F32& atten); + void setSpotExponent(const F32& exponent); + void setSpotCutoff(const F32& cutoff); + void setSpotDirection(const LLVector3& direction); void setSunPrimary(bool v); void setSize(F32 size); void setFalloff(F32 falloff); protected: - friend class LLRender; + friend class LLRender; - S32 mIndex; - bool mEnabled; - LLColor4 mDiffuse; + S32 mIndex; + bool mEnabled; + LLColor4 mDiffuse; LLColor4 mDiffuseB; bool mSunIsPrimary; - LLColor4 mAmbient; - LLColor4 mSpecular; - LLVector4 mPosition; - LLVector3 mSpotDirection; + LLColor4 mAmbient; + LLColor4 mSpecular; + LLVector4 mPosition; + LLVector3 mSpotDirection; - F32 mConstantAtten; - F32 mLinearAtten; - F32 mQuadraticAtten; + F32 mConstantAtten; + F32 mLinearAtten; + F32 mQuadraticAtten; - F32 mSpotExponent; - F32 mSpotCutoff; + F32 mSpotExponent; + F32 mSpotCutoff; F32 mSize = 0.f; F32 mFalloff = 0.f; }; class LLRender { - friend class LLTexUnit; + friend class LLTexUnit; public: - enum eTexIndex : U8 - { - DIFFUSE_MAP = 0, + enum eTexIndex : U8 + { + DIFFUSE_MAP = 0, ALTERNATE_DIFFUSE_MAP = 1, - NORMAL_MAP = 1, - SPECULAR_MAP = 2, - NUM_TEXTURE_CHANNELS = 3, - }; - - enum eVolumeTexIndex : U8 - { - LIGHT_TEX = 0, - SCULPT_TEX, - NUM_VOLUME_TEXTURE_CHANNELS, - }; - - enum eGeomModes : U8 + NORMAL_MAP = 1, + SPECULAR_MAP = 2, + NUM_TEXTURE_CHANNELS = 3, + }; + + enum eVolumeTexIndex : U8 + { + LIGHT_TEX = 0, + SCULPT_TEX, + NUM_VOLUME_TEXTURE_CHANNELS, + }; + + enum eGeomModes : U8 + { + TRIANGLES = 0, + TRIANGLE_STRIP, + TRIANGLE_FAN, + POINTS, + LINES, + LINE_STRIP, + QUADS, + LINE_LOOP, + NUM_MODES + }; + + enum eCompareFunc : U8 { - TRIANGLES = 0, - TRIANGLE_STRIP, - TRIANGLE_FAN, - POINTS, - LINES, - LINE_STRIP, - QUADS, - LINE_LOOP, - NUM_MODES - }; - - enum eCompareFunc : U8 - { - CF_NEVER = 0, - CF_ALWAYS, - CF_LESS, - CF_LESS_EQUAL, - CF_EQUAL, - CF_NOT_EQUAL, - CF_GREATER_EQUAL, - CF_GREATER, - CF_DEFAULT - }; - - enum eBlendType : U8 - { - BT_ALPHA = 0, - BT_ADD, - BT_ADD_WITH_ALPHA, // Additive blend modulated by the fragment's alpha. - BT_MULT, - BT_MULT_ALPHA, - BT_MULT_X2, - BT_REPLACE - }; - - // WARNING: this MUST match the LL_PART_BF enum in LLPartData, so set values explicitly in case someone + CF_NEVER = 0, + CF_ALWAYS, + CF_LESS, + CF_LESS_EQUAL, + CF_EQUAL, + CF_NOT_EQUAL, + CF_GREATER_EQUAL, + CF_GREATER, + CF_DEFAULT + }; + + enum eBlendType : U8 + { + BT_ALPHA = 0, + BT_ADD, + BT_ADD_WITH_ALPHA, // Additive blend modulated by the fragment's alpha. + BT_MULT, + BT_MULT_ALPHA, + BT_MULT_X2, + BT_REPLACE + }; + + // WARNING: this MUST match the LL_PART_BF enum in LLPartData, so set values explicitly in case someone // decides to add more or reorder them - enum eBlendFactor : U8 - { - BF_ONE = 0, - BF_ZERO = 1, - BF_DEST_COLOR = 2, - BF_SOURCE_COLOR = 3, - BF_ONE_MINUS_DEST_COLOR = 4, - BF_ONE_MINUS_SOURCE_COLOR = 5, - BF_DEST_ALPHA = 6, - BF_SOURCE_ALPHA = 7, - BF_ONE_MINUS_DEST_ALPHA = 8, - BF_ONE_MINUS_SOURCE_ALPHA = 9, - BF_UNDEF - }; - - enum eMatrixMode : U8 - { - MM_MODELVIEW = 0, - MM_PROJECTION, - MM_TEXTURE0, - MM_TEXTURE1, - MM_TEXTURE2, - MM_TEXTURE3, - NUM_MATRIX_MODES, - MM_TEXTURE - }; - - LLRender(); - ~LLRender(); + enum eBlendFactor : U8 + { + BF_ONE = 0, + BF_ZERO = 1, + BF_DEST_COLOR = 2, + BF_SOURCE_COLOR = 3, + BF_ONE_MINUS_DEST_COLOR = 4, + BF_ONE_MINUS_SOURCE_COLOR = 5, + BF_DEST_ALPHA = 6, + BF_SOURCE_ALPHA = 7, + BF_ONE_MINUS_DEST_ALPHA = 8, + BF_ONE_MINUS_SOURCE_ALPHA = 9, + BF_UNDEF + }; + + enum eMatrixMode : U8 + { + MM_MODELVIEW = 0, + MM_PROJECTION, + MM_TEXTURE0, + MM_TEXTURE1, + MM_TEXTURE2, + MM_TEXTURE3, + NUM_MATRIX_MODES, + MM_TEXTURE + }; + + LLRender(); + ~LLRender(); bool init(bool needs_vertex_buffer); void initVertexBuffer(); void resetVertexBuffer(); - void shutdown(); - - // Refreshes renderer state to the cached values - // Needed when the render context has changed and invalidated the current state - void refreshState(void); - - void translatef(const GLfloat& x, const GLfloat& y, const GLfloat& z); - void scalef(const GLfloat& x, const GLfloat& y, const GLfloat& z); - void rotatef(const GLfloat& a, const GLfloat& x, const GLfloat& y, const GLfloat& z); - void ortho(F32 left, F32 right, F32 bottom, F32 top, F32 zNear, F32 zFar); - - void pushMatrix(); - void popMatrix(); - void loadMatrix(const GLfloat* m); - void loadIdentity(); - void multMatrix(const GLfloat* m); - void matrixMode(eMatrixMode mode); - eMatrixMode getMatrixMode(); - - const glh::matrix4f& getModelviewMatrix(); - const glh::matrix4f& getProjectionMatrix(); - - void syncMatrices(); - void syncLightState(); - - void translateUI(F32 x, F32 y, F32 z); - void scaleUI(F32 x, F32 y, F32 z); - void pushUIMatrix(); - void popUIMatrix(); - void loadUIIdentity(); - LLVector3 getUITranslation(); - LLVector3 getUIScale(); - - void flush(); - - void begin(const GLuint& mode); - void end(); - void vertex2i(const GLint& x, const GLint& y); - void vertex2f(const GLfloat& x, const GLfloat& y); - void vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z); - void vertex2fv(const GLfloat* v); - void vertex3fv(const GLfloat* v); - - void texCoord2i(const GLint& x, const GLint& y); - void texCoord2f(const GLfloat& x, const GLfloat& y); - void texCoord2fv(const GLfloat* tc); - - void color4ub(const GLubyte& r, const GLubyte& g, const GLubyte& b, const GLubyte& a); - void color4f(const GLfloat& r, const GLfloat& g, const GLfloat& b, const GLfloat& a); - void color4fv(const GLfloat* c); - void color3f(const GLfloat& r, const GLfloat& g, const GLfloat& b); - void color3fv(const GLfloat* c); - void color4ubv(const GLubyte* c); - - void diffuseColor3f(F32 r, F32 g, F32 b); - void diffuseColor3fv(const F32* c); - void diffuseColor4f(F32 r, F32 g, F32 b, F32 a); - void diffuseColor4fv(const F32* c); - void diffuseColor4ubv(const U8* c); - void diffuseColor4ub(U8 r, U8 g, U8 b, U8 a); - - void vertexBatchPreTransformed(LLVector3* verts, S32 vert_count); - void vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, S32 vert_count); - void vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, LLColor4U*, S32 vert_count); - - void setColorMask(bool writeColor, bool writeAlpha); - void setColorMask(bool writeColorR, bool writeColorG, bool writeColorB, bool writeAlpha); - void setSceneBlendType(eBlendType type); - - // applies blend func to both color and alpha - void blendFunc(eBlendFactor sfactor, eBlendFactor dfactor); - // applies separate blend functions to color and alpha - void blendFunc(eBlendFactor color_sfactor, eBlendFactor color_dfactor, - eBlendFactor alpha_sfactor, eBlendFactor alpha_dfactor); - - LLLightState* getLight(U32 index); - void setAmbientLightColor(const LLColor4& color); - - LLTexUnit* getTexUnit(U32 index); - - U32 getCurrentTexUnitIndex(void) const { return mCurrTextureUnitIndex; } - - bool verifyTexUnitActive(U32 unitToVerify); - - void debugTexUnits(void); - - void clearErrors(); - - struct Vertex - { - GLfloat v[3]; - GLubyte c[4]; - GLfloat uv[2]; - }; + void shutdown(); + + // Refreshes renderer state to the cached values + // Needed when the render context has changed and invalidated the current state + void refreshState(void); + + void translatef(const GLfloat& x, const GLfloat& y, const GLfloat& z); + void scalef(const GLfloat& x, const GLfloat& y, const GLfloat& z); + void rotatef(const GLfloat& a, const GLfloat& x, const GLfloat& y, const GLfloat& z); + void ortho(F32 left, F32 right, F32 bottom, F32 top, F32 zNear, F32 zFar); + + void pushMatrix(); + void popMatrix(); + void loadMatrix(const GLfloat* m); + void loadIdentity(); + void multMatrix(const GLfloat* m); + void matrixMode(eMatrixMode mode); + eMatrixMode getMatrixMode(); + + const glh::matrix4f& getModelviewMatrix(); + const glh::matrix4f& getProjectionMatrix(); + + void syncMatrices(); + void syncLightState(); + + void translateUI(F32 x, F32 y, F32 z); + void scaleUI(F32 x, F32 y, F32 z); + void pushUIMatrix(); + void popUIMatrix(); + void loadUIIdentity(); + LLVector3 getUITranslation(); + LLVector3 getUIScale(); + + void flush(); + + void begin(const GLuint& mode); + void end(); + void vertex2i(const GLint& x, const GLint& y); + void vertex2f(const GLfloat& x, const GLfloat& y); + void vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z); + void vertex2fv(const GLfloat* v); + void vertex3fv(const GLfloat* v); + + void texCoord2i(const GLint& x, const GLint& y); + void texCoord2f(const GLfloat& x, const GLfloat& y); + void texCoord2fv(const GLfloat* tc); + + void color4ub(const GLubyte& r, const GLubyte& g, const GLubyte& b, const GLubyte& a); + void color4f(const GLfloat& r, const GLfloat& g, const GLfloat& b, const GLfloat& a); + void color4fv(const GLfloat* c); + void color3f(const GLfloat& r, const GLfloat& g, const GLfloat& b); + void color3fv(const GLfloat* c); + void color4ubv(const GLubyte* c); + + void diffuseColor3f(F32 r, F32 g, F32 b); + void diffuseColor3fv(const F32* c); + void diffuseColor4f(F32 r, F32 g, F32 b, F32 a); + void diffuseColor4fv(const F32* c); + void diffuseColor4ubv(const U8* c); + void diffuseColor4ub(U8 r, U8 g, U8 b, U8 a); + + void vertexBatchPreTransformed(LLVector3* verts, S32 vert_count); + void vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, S32 vert_count); + void vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, LLColor4U*, S32 vert_count); + + void setColorMask(bool writeColor, bool writeAlpha); + void setColorMask(bool writeColorR, bool writeColorG, bool writeColorB, bool writeAlpha); + void setSceneBlendType(eBlendType type); + + // applies blend func to both color and alpha + void blendFunc(eBlendFactor sfactor, eBlendFactor dfactor); + // applies separate blend functions to color and alpha + void blendFunc(eBlendFactor color_sfactor, eBlendFactor color_dfactor, + eBlendFactor alpha_sfactor, eBlendFactor alpha_dfactor); + + LLLightState* getLight(U32 index); + void setAmbientLightColor(const LLColor4& color); + + LLTexUnit* getTexUnit(U32 index); + + U32 getCurrentTexUnitIndex(void) const { return mCurrTextureUnitIndex; } + + bool verifyTexUnitActive(U32 unitToVerify); + + void debugTexUnits(void); + + void clearErrors(); + + struct Vertex + { + GLfloat v[3]; + GLubyte c[4]; + GLfloat uv[2]; + }; public: - static U32 sUICalls; - static U32 sUIVerts; - static bool sGLCoreProfile; - static bool sNsightDebugSupport; - static LLVector2 sUIGLScaleFactor; + static U32 sUICalls; + static U32 sUIVerts; + static bool sGLCoreProfile; + static bool sNsightDebugSupport; + static LLVector2 sUIGLScaleFactor; private: - friend class LLLightState; - - eMatrixMode mMatrixMode; - U32 mMatIdx[NUM_MATRIX_MODES]; - U32 mMatHash[NUM_MATRIX_MODES]; - glh::matrix4f mMatrix[NUM_MATRIX_MODES][LL_MATRIX_STACK_DEPTH]; - U32 mCurMatHash[NUM_MATRIX_MODES]; - U32 mLightHash; - LLColor4 mAmbientLightColor; - - bool mDirty; - U32 mQuadCycle; - U32 mCount; - U32 mMode; - U32 mCurrTextureUnitIndex; - bool mCurrColorMask[4]; - - LLPointer<LLVertexBuffer> mBuffer; - LLStrider<LLVector3> mVerticesp; - LLStrider<LLVector2> mTexcoordsp; - LLStrider<LLColor4U> mColorsp; - std::array<LLTexUnit, LL_NUM_TEXTURE_LAYERS> mTexUnits; - LLTexUnit mDummyTexUnit; - std::array<LLLightState, LL_NUM_LIGHT_UNITS> mLightState; - - eBlendFactor mCurrBlendColorSFactor; - eBlendFactor mCurrBlendColorDFactor; - eBlendFactor mCurrBlendAlphaSFactor; - eBlendFactor mCurrBlendAlphaDFactor; - - std::vector<LLVector3> mUIOffset; - std::vector<LLVector3> mUIScale; + friend class LLLightState; + + eMatrixMode mMatrixMode; + U32 mMatIdx[NUM_MATRIX_MODES]; + U32 mMatHash[NUM_MATRIX_MODES]; + glh::matrix4f mMatrix[NUM_MATRIX_MODES][LL_MATRIX_STACK_DEPTH]; + U32 mCurMatHash[NUM_MATRIX_MODES]; + U32 mLightHash; + LLColor4 mAmbientLightColor; + + bool mDirty; + U32 mQuadCycle; + U32 mCount; + U32 mMode; + U32 mCurrTextureUnitIndex; + bool mCurrColorMask[4]; + + LLPointer<LLVertexBuffer> mBuffer; + LLStrider<LLVector3> mVerticesp; + LLStrider<LLVector2> mTexcoordsp; + LLStrider<LLColor4U> mColorsp; + std::array<LLTexUnit, LL_NUM_TEXTURE_LAYERS> mTexUnits; + LLTexUnit mDummyTexUnit; + std::array<LLLightState, LL_NUM_LIGHT_UNITS> mLightState; + + eBlendFactor mCurrBlendColorSFactor; + eBlendFactor mCurrBlendColorDFactor; + eBlendFactor mCurrBlendAlphaSFactor; + eBlendFactor mCurrBlendAlphaDFactor; + + std::vector<LLVector3> mUIOffset; + std::vector<LLVector3> mUIScale; }; @@ -526,12 +526,12 @@ extern F32 gGLInverseDeltaModelView[16]; extern thread_local LLRender gGL; -// This rotation matrix moves the default OpenGL reference frame +// This rotation matrix moves the default OpenGL reference frame // (-Z at, Y up) to Cory's favorite reference frame (X at, Z up) -const F32 OGL_TO_CFR_ROTATION[16] = { 0.f, 0.f, -1.f, 0.f, // -Z becomes X - -1.f, 0.f, 0.f, 0.f, // -X becomes Y - 0.f, 1.f, 0.f, 0.f, // Y becomes Z - 0.f, 0.f, 0.f, 1.f }; +const F32 OGL_TO_CFR_ROTATION[16] = { 0.f, 0.f, -1.f, 0.f, // -Z becomes X + -1.f, 0.f, 0.f, 0.f, // -X becomes Y + 0.f, 1.f, 0.f, 0.f, // Y becomes Z + 0.f, 0.f, 0.f, 1.f }; glh::matrix4f copy_matrix(F32* src); glh::matrix4f get_current_modelview(); diff --git a/indra/llrender/llrender2dutils.cpp b/indra/llrender/llrender2dutils.cpp index 52869406d2..e1742f84a1 100644 --- a/indra/llrender/llrender2dutils.cpp +++ b/indra/llrender/llrender2dutils.cpp @@ -1,25 +1,25 @@ -/** +/** * @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$ */ @@ -53,9 +53,9 @@ const LLColor4 UI_VERTEX_COLOR(1.f, 1.f, 1.f, 1.f); 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; + if (x < left || right < x) return FALSE; + if (y < bottom || top < y) return FALSE; + return TRUE; } @@ -63,97 +63,97 @@ BOOL ui_point_in_rect(S32 x, S32 y, S32 left, S32 top, S32 right, S32 bottom) // 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(); + 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.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.color4fv( color.mV ); + 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(); + 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); + 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 * LLRender::sUIGLScaleFactor.mV[VX]) - pixel_offset, - llfloor((F32)top * LLRender::sUIGLScaleFactor.mV[VY]) + pixel_offset, - llfloor((F32)right * LLRender::sUIGLScaleFactor.mV[VX]) + pixel_offset, - llfloor((F32)bottom * LLRender::sUIGLScaleFactor.mV[VY]) - pixel_offset, - filled); - gGL.popUIMatrix(); + 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 * LLRender::sUIGLScaleFactor.mV[VX]) - pixel_offset, + llfloor((F32)top * LLRender::sUIGLScaleFactor.mV[VY]) + pixel_offset, + llfloor((F32)right * LLRender::sUIGLScaleFactor.mV[VX]) + pixel_offset, + llfloor((F32)bottom * LLRender::sUIGLScaleFactor.mV[VY]) - pixel_offset, + filled); + gGL.popUIMatrix(); } void gl_rect_2d(S32 left, S32 top, S32 right, S32 bottom, BOOL filled ) { - 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 - { - 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(); - } + 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 + { + 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(); + } } 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 ); + 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 ); + 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_ @@ -161,715 +161,715 @@ void gl_rect_2d( const LLRect& rect, const LLColor4& color, BOOL filled ) // 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(); + 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 ) { - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - - gGL.begin(LLRender::LINES); - gGL.vertex2i(x1, y1); - gGL.vertex2i(x2, y2); - gGL.end(); + 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 ) { - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.color4fv( color.mV ); + gGL.color4fv( color.mV ); - gGL.begin(LLRender::LINES); - gGL.vertex2i(x1, y1); - gGL.vertex2i(x2, y2); - gGL.end(); + 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(); + 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(); + 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) - { - LL_WARNS() << "image == NULL; aborting function" << LL_ENDL; - return; - } - gl_draw_scaled_rotated_image( x, y, image->getWidth(0), image->getHeight(0), 0.f, image, color, uv_rect ); + if (NULL == image) + { + LL_WARNS() << "image == NULL; aborting function" << LL_ENDL; + return; + } + gl_draw_scaled_rotated_image( x, y, image->getWidth(0), image->getHeight(0), 0.f, image, color, uv_rect ); } void gl_draw_scaled_target(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* target, const LLColor4& color, const LLRectf& uv_rect) { - gl_draw_scaled_rotated_image(x, y, width, height, 0.f, NULL, color, uv_rect, target); + gl_draw_scaled_rotated_image(x, y, width, height, 0.f, NULL, color, uv_rect, target); } 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) - { - LL_WARNS() << "image == NULL; aborting function" << LL_ENDL; - return; - } - gl_draw_scaled_rotated_image( x, y, width, height, 0.f, image, color, uv_rect ); + if (NULL == image) + { + LL_WARNS() << "image == NULL; aborting function" << LL_ENDL; + 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, bool scale_inner) { - if (NULL == image) - { - LL_WARNS() << "image == NULL; aborting function" << LL_ENDL; - 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, scale_inner); + if (NULL == image) + { + LL_WARNS() << "image == NULL; aborting function" << LL_ENDL; + 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, scale_inner); } 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, bool scale_inner) { - stop_glerror(); - - if (NULL == image) - { - LL_WARNS() << "image == NULL; aborting function" << LL_ENDL; - return; - } - - if (solid_color) - { - gSolidColorProgram.bind(); - } - - if (center_rect.mLeft == 0.f - && center_rect.mRight == 1.f - && center_rect.mBottom == 0.f - && center_rect.mTop == 1.f) - { - gl_draw_scaled_image(x, y, width, height, image, color, uv_outer_rect); - } - else - { - // 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 = ll_round(image_width * uv_width); - S32 image_natural_height = ll_round(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); - - if (scale_inner) - { - // scale center region of image to drawn region - draw_center_rect.mRight += width - image_natural_width; - draw_center_rect.mTop += height - image_natural_height; - - const F32 border_shrink_width = llmax(0.f, draw_center_rect.mLeft - draw_center_rect.mRight); - const F32 border_shrink_height = llmax(0.f, draw_center_rect.mBottom - draw_center_rect.mTop); - - const F32 shrink_width_ratio = center_rect.getWidth() == 1.f ? 0.f : border_shrink_width / ((F32)image_natural_width * (1.f - center_rect.getWidth())); - const F32 shrink_height_ratio = center_rect.getHeight() == 1.f ? 0.f : border_shrink_height / ((F32)image_natural_height * (1.f - center_rect.getHeight())); - - const F32 border_shrink_scale = 1.f - llmax(shrink_width_ratio, shrink_height_ratio); - draw_center_rect.mLeft *= border_shrink_scale; - draw_center_rect.mTop = lerp((F32)height, (F32)draw_center_rect.mTop, border_shrink_scale); - draw_center_rect.mRight = lerp((F32)width, (F32)draw_center_rect.mRight, border_shrink_scale); - draw_center_rect.mBottom *= border_shrink_scale; - } - else - { - // keep center region of image at fixed scale, but in same relative position - F32 scale_factor = llmin((F32)width / draw_center_rect.getWidth(), (F32)height / draw_center_rect.getHeight(), 1.f); - F32 scaled_width = draw_center_rect.getWidth() * scale_factor; - F32 scaled_height = draw_center_rect.getHeight() * scale_factor; - draw_center_rect.setCenterAndSize(uv_center_rect.getCenterX() * width, uv_center_rect.getCenterY() * height, scaled_width, scaled_height); - } - - draw_center_rect.mLeft = ll_round(ui_translation.mV[VX] + (F32)draw_center_rect.mLeft * ui_scale.mV[VX]); - draw_center_rect.mTop = ll_round(ui_translation.mV[VY] + (F32)draw_center_rect.mTop * ui_scale.mV[VY]); - draw_center_rect.mRight = ll_round(ui_translation.mV[VX] + (F32)draw_center_rect.mRight * ui_scale.mV[VX]); - draw_center_rect.mBottom = ll_round(ui_translation.mV[VY] + (F32)draw_center_rect.mBottom * 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; - - 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) - { - gUIProgram.bind(); - } + stop_glerror(); + + if (NULL == image) + { + LL_WARNS() << "image == NULL; aborting function" << LL_ENDL; + return; + } + + if (solid_color) + { + gSolidColorProgram.bind(); + } + + if (center_rect.mLeft == 0.f + && center_rect.mRight == 1.f + && center_rect.mBottom == 0.f + && center_rect.mTop == 1.f) + { + gl_draw_scaled_image(x, y, width, height, image, color, uv_outer_rect); + } + else + { + // 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 = ll_round(image_width * uv_width); + S32 image_natural_height = ll_round(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); + + if (scale_inner) + { + // scale center region of image to drawn region + draw_center_rect.mRight += width - image_natural_width; + draw_center_rect.mTop += height - image_natural_height; + + const F32 border_shrink_width = llmax(0.f, draw_center_rect.mLeft - draw_center_rect.mRight); + const F32 border_shrink_height = llmax(0.f, draw_center_rect.mBottom - draw_center_rect.mTop); + + const F32 shrink_width_ratio = center_rect.getWidth() == 1.f ? 0.f : border_shrink_width / ((F32)image_natural_width * (1.f - center_rect.getWidth())); + const F32 shrink_height_ratio = center_rect.getHeight() == 1.f ? 0.f : border_shrink_height / ((F32)image_natural_height * (1.f - center_rect.getHeight())); + + const F32 border_shrink_scale = 1.f - llmax(shrink_width_ratio, shrink_height_ratio); + draw_center_rect.mLeft *= border_shrink_scale; + draw_center_rect.mTop = lerp((F32)height, (F32)draw_center_rect.mTop, border_shrink_scale); + draw_center_rect.mRight = lerp((F32)width, (F32)draw_center_rect.mRight, border_shrink_scale); + draw_center_rect.mBottom *= border_shrink_scale; + } + else + { + // keep center region of image at fixed scale, but in same relative position + F32 scale_factor = llmin((F32)width / draw_center_rect.getWidth(), (F32)height / draw_center_rect.getHeight(), 1.f); + F32 scaled_width = draw_center_rect.getWidth() * scale_factor; + F32 scaled_height = draw_center_rect.getHeight() * scale_factor; + draw_center_rect.setCenterAndSize(uv_center_rect.getCenterX() * width, uv_center_rect.getCenterY() * height, scaled_width, scaled_height); + } + + draw_center_rect.mLeft = ll_round(ui_translation.mV[VX] + (F32)draw_center_rect.mLeft * ui_scale.mV[VX]); + draw_center_rect.mTop = ll_round(ui_translation.mV[VY] + (F32)draw_center_rect.mTop * ui_scale.mV[VY]); + draw_center_rect.mRight = ll_round(ui_translation.mV[VX] + (F32)draw_center_rect.mRight * ui_scale.mV[VX]); + draw_center_rect.mBottom = ll_round(ui_translation.mV[VY] + (F32)draw_center_rect.mBottom * 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; + + 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) + { + gUIProgram.bind(); + } } 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 ); + 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, LLRenderTarget* target) { - if (!image && !target) - { - LL_WARNS() << "image == NULL; aborting function" << LL_ENDL; - return; - } - - LLGLSUIDefault gls_ui; - - if(image != NULL) - { - gGL.getTexUnit(0)->bind(image, true); - } - else - { - gGL.getTexUnit(0)->bind(target); - } - - 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 = ll_round(width * ui_scale.mV[VX]); - S32 scaled_height = ll_round(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); - - if(image != NULL) - { - gGL.getTexUnit(0)->bind(image, true); - } - else - { - gGL.getTexUnit(0)->bind(target); - } - - 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(); - } + if (!image && !target) + { + LL_WARNS() << "image == NULL; aborting function" << LL_ENDL; + return; + } + + LLGLSUIDefault gls_ui; + + if(image != NULL) + { + gGL.getTexUnit(0)->bind(image, true); + } + else + { + gGL.getTexUnit(0)->bind(target); + } + + 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 = ll_round(width * ui_scale.mV[VX]); + S32 scaled_height = ll_round(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); + + if(image != NULL) + { + gGL.getTexUnit(0)->bind(image, true); + } + else + { + gGL.getTexUnit(0)->bind(target); + } + + 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_line_3d( const LLVector3& start, const LLVector3& end, const LLColor4& color) { - gGL.color4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], color.mV[VALPHA]); + gGL.color4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], color.mV[VALPHA]); - gGL.flush(); - glLineWidth(2.5f); + gGL.flush(); + glLineWidth(2.5f); - gGL.begin(LLRender::LINES); - { - gGL.vertex3fv( start.mV ); - gGL.vertex3fv( end.mV ); - } - gGL.end(); + gGL.begin(LLRender::LINES); + { + gGL.vertex3fv( start.mV ); + gGL.vertex3fv( end.mV ); + } + gGL.end(); - LLRender2D::getInstance()->setLineWidth(1.f); + LLRender2D::getInstance()->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(); + 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(); + 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(); + 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(); + 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) { - //polygon stipple is deprecated, use "Checker" texture - LLPointer<LLUIImage> img = LLRender2D::getInstance()->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(); + //polygon stipple is deprecated, use "Checker" texture + LLPointer<LLUIImage> img = LLRender2D::getInstance()->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(); } @@ -877,640 +877,640 @@ void gl_rect_2d_checkerboard(const LLRect& rect, GLfloat alpha) // 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(); + 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(); + 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.begin( LLRender::QUADS ); - gGL.texCoord2f(1.f, 1.f); - gGL.vertex2i(width, height); + gGL.texCoord2f(1.f, 1.f); + gGL.vertex2i(width, height); - gGL.texCoord2f(0.f, 1.f); - gGL.vertex2i(0, height); + gGL.texCoord2f(0.f, 1.f); + gGL.vertex2i(0, height); - gGL.texCoord2f(0.f, 0.f); - gGL.vertex2i(0, 0); + gGL.texCoord2f(0.f, 0.f); + gGL.vertex2i(0, 0); - gGL.texCoord2f(1.f, 0.f); - gGL.vertex2i(width, 0); - - gGL.end(); + 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(); + 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) +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) { LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; - S32 width = llabs(right - left); - S32 height = llabs(top - bottom); + S32 width = llabs(right - left); + S32 height = llabs(top - bottom); - gGL.pushUIMatrix(); + 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); + 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]; - } + 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 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.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], 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(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); + 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); + // 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], 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(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); + 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); + // 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, 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[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); + 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); + // 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], 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(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); + 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); + // 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], 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(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); + 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); + // 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, 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, 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); + 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); + // 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 - 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(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); + 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); + // 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 - 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(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); + 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); + // 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 - 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, 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.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f); + gGL.vertex2fv((width_vec - border_width_right + height_vec).mV); + } + gGL.end(); - gGL.popUIMatrix(); + gGL.popUIMatrix(); } -void gl_segmented_rect_2d_fragment_tex(const LLRect& rect, - const S32 texture_width, - const S32 texture_height, - const S32 border_size, - const F32 start_fragment, - const F32 end_fragment, - const U32 edges) +void gl_segmented_rect_2d_fragment_tex(const LLRect& rect, + const S32 texture_width, + const S32 texture_height, + const S32 border_size, + const F32 start_fragment, + const F32 end_fragment, + const U32 edges) { LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; - const S32 left = rect.mLeft; - const S32 right = rect.mRight; - const S32 top = rect.mTop; - const S32 bottom = rect.mBottom; - 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]; - } + const S32 left = rect.mLeft; + const S32 right = rect.mRight; + const S32 top = rect.mTop; + const S32 bottom = rect.mBottom; + S32 width = llabs(right - left); + S32 height = llabs(top - bottom); - 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.pushUIMatrix(); - F32 middle_start = border_scale / (F32)width; - F32 middle_end = 1.f - middle_start; + gGL.translateUI((F32)left, (F32)bottom, 0.f); + LLVector2 border_uv_scale((F32)border_size / (F32)texture_width, (F32)border_size / (F32)texture_height); - 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; + 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]; + } - // draw bottom left - gGL.texCoord2f(u_min, 0.f); - gGL.vertex2fv(x_min.mV); + 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.texCoord2f(border_uv_scale.mV[VX], 0.f); - gGL.vertex2fv(x_max.mV); + F32 middle_start = border_scale / (F32)width; + F32 middle_end = 1.f - middle_start; - gGL.texCoord2f(u_max, border_uv_scale.mV[VY]); - gGL.vertex2fv((x_max + border_height_bottom).mV); + F32 u_min; + F32 u_max; + LLVector2 x_min; + LLVector2 x_max; - gGL.texCoord2f(u_min, border_uv_scale.mV[VY]); - gGL.vertex2fv((x_min + border_height_bottom).mV); + 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 left - gGL.texCoord2f(u_min, border_uv_scale.mV[VY]); - gGL.vertex2fv((x_min + border_height_bottom).mV); + // draw bottom left + gGL.texCoord2f(u_min, 0.f); + gGL.vertex2fv(x_min.mV); - gGL.texCoord2f(u_max, border_uv_scale.mV[VY]); - gGL.vertex2fv((x_max + border_height_bottom).mV); + gGL.texCoord2f(border_uv_scale.mV[VX], 0.f); + gGL.vertex2fv(x_max.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, border_uv_scale.mV[VY]); + gGL.vertex2fv((x_max + border_height_bottom).mV); - gGL.texCoord2f(u_min, 1.f - border_uv_scale.mV[VY]); - gGL.vertex2fv((x_min + height_vec - border_height_top).mV); + gGL.texCoord2f(u_min, border_uv_scale.mV[VY]); + gGL.vertex2fv((x_min + border_height_bottom).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); + // draw left + gGL.texCoord2f(u_min, border_uv_scale.mV[VY]); + gGL.vertex2fv((x_min + 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_max, border_uv_scale.mV[VY]); + gGL.vertex2fv((x_max + border_height_bottom).mV); - gGL.texCoord2f(u_max, 1.f); - gGL.vertex2fv((x_max + height_vec).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); - gGL.vertex2fv((x_min + height_vec).mV); - } + gGL.texCoord2f(u_min, 1.f - border_uv_scale.mV[VY]); + gGL.vertex2fv((x_min + height_vec - border_height_top).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 top left + gGL.texCoord2f(u_min, 1.f - border_uv_scale.mV[VY]); + gGL.vertex2fv((x_min + height_vec - border_height_top).mV); - // draw bottom middle - gGL.texCoord2f(border_uv_scale.mV[VX], 0.f); - gGL.vertex2fv(x_min.mV); + gGL.texCoord2f(u_max, 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], 0.f); - gGL.vertex2fv((x_max).mV); + gGL.texCoord2f(u_max, 1.f); + gGL.vertex2fv((x_max + height_vec).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(u_min, 1.f); + gGL.vertex2fv((x_min + height_vec).mV); + } - gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]); - gGL.vertex2fv((x_min + border_height_bottom).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 middle - gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]); - gGL.vertex2fv((x_min + border_height_bottom).mV); + // 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], border_uv_scale.mV[VY]); - gGL.vertex2fv((x_max + border_height_bottom).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], 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], border_uv_scale.mV[VY]); + gGL.vertex2fv((x_max + border_height_bottom).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); + gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]); + gGL.vertex2fv((x_min + border_height_bottom).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); + // 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], 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], border_uv_scale.mV[VY]); + gGL.vertex2fv((x_max + border_height_bottom).mV); - gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f); - gGL.vertex2fv((x_max + height_vec).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); - gGL.vertex2fv((x_min + height_vec).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); - if (end_fragment > middle_end) - { - u_min = 1.f - ((1.f - llmax(0.f, (start_fragment - middle_end) / middle_start)) * border_uv_scale.mV[VX]); - u_max = 1.f - ((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 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); - // draw bottom right - gGL.texCoord2f(u_min, 0.f); - gGL.vertex2fv((x_min).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(u_max, 0.f); - gGL.vertex2fv(x_max.mV); + gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f); + gGL.vertex2fv((x_max + height_vec).mV); - gGL.texCoord2f(u_max, border_uv_scale.mV[VY]); - gGL.vertex2fv((x_max + border_height_bottom).mV); + gGL.texCoord2f(border_uv_scale.mV[VX], 1.f); + gGL.vertex2fv((x_min + height_vec).mV); + } - gGL.texCoord2f(u_min, border_uv_scale.mV[VY]); - gGL.vertex2fv((x_min + border_height_bottom).mV); + if (end_fragment > middle_end) + { + u_min = 1.f - ((1.f - llmax(0.f, (start_fragment - middle_end) / middle_start)) * border_uv_scale.mV[VX]); + u_max = 1.f - ((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 right - gGL.texCoord2f(u_min, border_uv_scale.mV[VY]); - gGL.vertex2fv((x_min + border_height_bottom).mV); + // draw bottom right + gGL.texCoord2f(u_min, 0.f); + gGL.vertex2fv((x_min).mV); - gGL.texCoord2f(u_max, border_uv_scale.mV[VY]); - gGL.vertex2fv((x_max + border_height_bottom).mV); + gGL.texCoord2f(u_max, 0.f); + gGL.vertex2fv(x_max.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, border_uv_scale.mV[VY]); + gGL.vertex2fv((x_max + border_height_bottom).mV); - gGL.texCoord2f(u_min, 1.f - border_uv_scale.mV[VY]); - gGL.vertex2fv((x_min + height_vec - border_height_top).mV); + gGL.texCoord2f(u_min, border_uv_scale.mV[VY]); + gGL.vertex2fv((x_min + border_height_bottom).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); + // draw right + gGL.texCoord2f(u_min, border_uv_scale.mV[VY]); + gGL.vertex2fv((x_min + 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_max, border_uv_scale.mV[VY]); + gGL.vertex2fv((x_max + border_height_bottom).mV); - gGL.texCoord2f(u_max, 1.f); - gGL.vertex2fv((x_max + height_vec).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); - gGL.vertex2fv((x_min + height_vec).mV); - } - } - gGL.end(); + gGL.texCoord2f(u_min, 1.f - border_uv_scale.mV[VY]); + gGL.vertex2fv((x_min + height_vec - border_height_top).mV); - gGL.popUIMatrix(); + // 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 LLRectf& clip_rect, const LLRectf& center_uv_rect, const LLRectf& center_draw_rect, - const LLVector3& width_vec, const LLVector3& height_vec) +void gl_segmented_rect_3d_tex(const LLRectf& clip_rect, const LLRectf& center_uv_rect, const LLRectf& center_draw_rect, + const LLVector3& width_vec, const LLVector3& height_vec) { LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; - gGL.begin(LLRender::QUADS); - { - // draw bottom left - gGL.texCoord2f(clip_rect.mLeft, clip_rect.mBottom); - gGL.vertex3f(0.f, 0.f, 0.f); + gGL.begin(LLRender::QUADS); + { + // draw bottom left + gGL.texCoord2f(clip_rect.mLeft, clip_rect.mBottom); + gGL.vertex3f(0.f, 0.f, 0.f); - gGL.texCoord2f(center_uv_rect.mLeft, clip_rect.mBottom); - gGL.vertex3fv((center_draw_rect.mLeft * width_vec).mV); + gGL.texCoord2f(center_uv_rect.mLeft, clip_rect.mBottom); + gGL.vertex3fv((center_draw_rect.mLeft * width_vec).mV); - gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mBottom); - gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mBottom * height_vec).mV); + gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mBottom); + gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mBottom * height_vec).mV); - gGL.texCoord2f(clip_rect.mLeft, center_uv_rect.mBottom); - gGL.vertex3fv((center_draw_rect.mBottom * height_vec).mV); + gGL.texCoord2f(clip_rect.mLeft, center_uv_rect.mBottom); + gGL.vertex3fv((center_draw_rect.mBottom * height_vec).mV); - // draw bottom middle - gGL.texCoord2f(center_uv_rect.mLeft, clip_rect.mBottom); - gGL.vertex3fv((center_draw_rect.mLeft * width_vec).mV); + // draw bottom middle + gGL.texCoord2f(center_uv_rect.mLeft, clip_rect.mBottom); + gGL.vertex3fv((center_draw_rect.mLeft * width_vec).mV); - gGL.texCoord2f(center_uv_rect.mRight, clip_rect.mBottom); - gGL.vertex3fv((center_draw_rect.mRight * width_vec).mV); + gGL.texCoord2f(center_uv_rect.mRight, clip_rect.mBottom); + gGL.vertex3fv((center_draw_rect.mRight * width_vec).mV); - gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mBottom); - gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mBottom * height_vec).mV); + gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mBottom); + gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mBottom * height_vec).mV); - gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mBottom); - gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mBottom * height_vec).mV); + gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mBottom); + gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mBottom * height_vec).mV); - // draw bottom right - gGL.texCoord2f(center_uv_rect.mRight, clip_rect.mBottom); - gGL.vertex3fv((center_draw_rect.mRight * width_vec).mV); + // draw bottom right + gGL.texCoord2f(center_uv_rect.mRight, clip_rect.mBottom); + gGL.vertex3fv((center_draw_rect.mRight * width_vec).mV); - gGL.texCoord2f(clip_rect.mRight, clip_rect.mBottom); - gGL.vertex3fv(width_vec.mV); + gGL.texCoord2f(clip_rect.mRight, clip_rect.mBottom); + gGL.vertex3fv(width_vec.mV); - gGL.texCoord2f(clip_rect.mRight, center_uv_rect.mBottom); - gGL.vertex3fv((width_vec + center_draw_rect.mBottom * height_vec).mV); + gGL.texCoord2f(clip_rect.mRight, center_uv_rect.mBottom); + gGL.vertex3fv((width_vec + center_draw_rect.mBottom * height_vec).mV); - gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mBottom); - gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mBottom * height_vec).mV); + gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mBottom); + gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mBottom * height_vec).mV); - // draw left - gGL.texCoord2f(clip_rect.mLeft, center_uv_rect.mBottom); - gGL.vertex3fv((center_draw_rect.mBottom * height_vec).mV); + // draw left + gGL.texCoord2f(clip_rect.mLeft, center_uv_rect.mBottom); + gGL.vertex3fv((center_draw_rect.mBottom * height_vec).mV); - gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mBottom); - gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mBottom * height_vec).mV); + gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mBottom); + gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mBottom * height_vec).mV); - gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mTop); - gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mTop * height_vec).mV); + gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mTop); + gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mTop * height_vec).mV); - gGL.texCoord2f(clip_rect.mLeft, center_uv_rect.mTop); - gGL.vertex3fv((center_draw_rect.mTop * height_vec).mV); + gGL.texCoord2f(clip_rect.mLeft, center_uv_rect.mTop); + gGL.vertex3fv((center_draw_rect.mTop * height_vec).mV); - // draw middle - gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mBottom); - gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mBottom * height_vec).mV); + // draw middle + gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mBottom); + gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mBottom * height_vec).mV); - gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mBottom); - gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mBottom * height_vec).mV); + gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mBottom); + gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mBottom * height_vec).mV); - gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mTop); - gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mTop * height_vec).mV); + gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mTop); + gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mTop * height_vec).mV); - gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mTop); - gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mTop * height_vec).mV); + gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mTop); + gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mTop * height_vec).mV); - // draw right - gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mBottom); - gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mBottom * height_vec).mV); + // draw right + gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mBottom); + gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mBottom * height_vec).mV); - gGL.texCoord2f(clip_rect.mRight, center_uv_rect.mBottom); - gGL.vertex3fv((width_vec + center_draw_rect.mBottom * height_vec).mV); + gGL.texCoord2f(clip_rect.mRight, center_uv_rect.mBottom); + gGL.vertex3fv((width_vec + center_draw_rect.mBottom * height_vec).mV); - gGL.texCoord2f(clip_rect.mRight, center_uv_rect.mTop); - gGL.vertex3fv((width_vec + center_draw_rect.mTop * height_vec).mV); + gGL.texCoord2f(clip_rect.mRight, center_uv_rect.mTop); + gGL.vertex3fv((width_vec + center_draw_rect.mTop * height_vec).mV); - gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mTop); - gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mTop * height_vec).mV); + gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mTop); + gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mTop * height_vec).mV); - // draw top left - gGL.texCoord2f(clip_rect.mLeft, center_uv_rect.mTop); - gGL.vertex3fv((center_draw_rect.mTop * height_vec).mV); + // draw top left + gGL.texCoord2f(clip_rect.mLeft, center_uv_rect.mTop); + gGL.vertex3fv((center_draw_rect.mTop * height_vec).mV); - gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mTop); - gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mTop * height_vec).mV); + gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mTop); + gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mTop * height_vec).mV); - gGL.texCoord2f(center_uv_rect.mLeft, clip_rect.mTop); - gGL.vertex3fv((center_draw_rect.mLeft * width_vec + height_vec).mV); + gGL.texCoord2f(center_uv_rect.mLeft, clip_rect.mTop); + gGL.vertex3fv((center_draw_rect.mLeft * width_vec + height_vec).mV); - gGL.texCoord2f(clip_rect.mLeft, clip_rect.mTop); - gGL.vertex3fv((height_vec).mV); + gGL.texCoord2f(clip_rect.mLeft, clip_rect.mTop); + gGL.vertex3fv((height_vec).mV); - // draw top middle - gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mTop); - gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mTop * height_vec).mV); + // draw top middle + gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mTop); + gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mTop * height_vec).mV); - gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mTop); - gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mTop * height_vec).mV); + gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mTop); + gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mTop * height_vec).mV); - gGL.texCoord2f(center_uv_rect.mRight, clip_rect.mTop); - gGL.vertex3fv((center_draw_rect.mRight * width_vec + height_vec).mV); + gGL.texCoord2f(center_uv_rect.mRight, clip_rect.mTop); + gGL.vertex3fv((center_draw_rect.mRight * width_vec + height_vec).mV); - gGL.texCoord2f(center_uv_rect.mLeft, clip_rect.mTop); - gGL.vertex3fv((center_draw_rect.mLeft * width_vec + height_vec).mV); + gGL.texCoord2f(center_uv_rect.mLeft, clip_rect.mTop); + gGL.vertex3fv((center_draw_rect.mLeft * width_vec + height_vec).mV); - // draw top right - gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mTop); - gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mTop * height_vec).mV); + // draw top right + gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mTop); + gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mTop * height_vec).mV); - gGL.texCoord2f(clip_rect.mRight, center_uv_rect.mTop); - gGL.vertex3fv((width_vec + center_draw_rect.mTop * height_vec).mV); + gGL.texCoord2f(clip_rect.mRight, center_uv_rect.mTop); + gGL.vertex3fv((width_vec + center_draw_rect.mTop * height_vec).mV); - gGL.texCoord2f(clip_rect.mRight, clip_rect.mTop); - gGL.vertex3fv((width_vec + height_vec).mV); + gGL.texCoord2f(clip_rect.mRight, clip_rect.mTop); + gGL.vertex3fv((width_vec + height_vec).mV); - gGL.texCoord2f(center_uv_rect.mRight, clip_rect.mTop); - gGL.vertex3fv((center_draw_rect.mRight * width_vec + height_vec).mV); - } - gGL.end(); + gGL.texCoord2f(center_uv_rect.mRight, clip_rect.mTop); + gGL.vertex3fv((center_draw_rect.mRight * width_vec + height_vec).mV); + } + gGL.end(); } LLRender2D::LLRender2D(LLImageProviderInterface* image_provider) { - mImageProvider = image_provider; - if(mImageProvider) - { - mImageProvider->addOnRemovalCallback(resetProvider); - } + mImageProvider = image_provider; + if(mImageProvider) + { + mImageProvider->addOnRemovalCallback(resetProvider); + } } LLRender2D::~LLRender2D() { - if(mImageProvider) - { - mImageProvider->cleanUp(); - mImageProvider->deleteOnRemovalCallback(resetProvider); - } + if(mImageProvider) + { + mImageProvider->cleanUp(); + mImageProvider->deleteOnRemovalCallback(resetProvider); + } } // 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; + 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)); + 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(); + 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; + gGL.loadUIIdentity(); + LLFontGL::sCurOrigin.mX = 0; + LLFontGL::sCurOrigin.mY = 0; + LLFontGL::sCurDepth = 0.f; } // static void LLRender2D::setLineWidth(F32 width) { - gGL.flush(); + gGL.flush(); // If outside the allowed range, glLineWidth fails with "invalid value". // On Darwin, the range is [1, 1]. static GLfloat range[2]{0.0}; @@ -1524,22 +1524,22 @@ void LLRender2D::setLineWidth(F32 width) LLPointer<LLUIImage> LLRender2D::getUIImageByID(const LLUUID& image_id, S32 priority) { - if (mImageProvider) - { - return mImageProvider->getUIImageByID(image_id, priority); - } - else - { - return NULL; - } + if (mImageProvider) + { + return mImageProvider->getUIImageByID(image_id, priority); + } + else + { + return NULL; + } } LLPointer<LLUIImage> LLRender2D::getUIImage(const std::string& name, S32 priority) { - if (!name.empty() && mImageProvider) - return mImageProvider->getUIImage(name, priority); - else - return NULL; + if (!name.empty() && mImageProvider) + return mImageProvider->getUIImage(name, priority); + else + return NULL; } // static diff --git a/indra/llrender/llrender2dutils.h b/indra/llrender/llrender2dutils.h index 135738c3ba..c3c6d66b8e 100644 --- a/indra/llrender/llrender2dutils.h +++ b/indra/llrender/llrender2dutils.h @@ -1,25 +1,25 @@ -/** +/** * @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$ */ @@ -30,12 +30,12 @@ #ifndef LL_RENDER2DUTILS_H #define LL_RENDER2DUTILS_H -#include "llpointer.h" // LLPointer<> +#include "llpointer.h" // LLPointer<> #include "llrect.h" #include "llsingleton.h" #include "llglslshader.h" -class LLColor4; +class LLColor4; class LLVector3; class LLVector2; class LLUIImage; @@ -79,30 +79,30 @@ void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degre 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), bool scale_inner = true); 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), bool scale_inner = true); -void gl_line_3d( const LLVector3& start, const LLVector3& end, const LLColor4& color); +void gl_line_3d( const LLVector3& start, const LLVector3& end, const LLColor4& color); void gl_rect_2d_simple_tex( S32 width, S32 height ); // segmented rectangles /* - TL |______TOP_________| TR - /| |\ + TL |______TOP_________| TR + /| |\ _/_|__________________|_\_ L| | MIDDLE | |R _|_|__________________|_|_ - \ | BOTTOM | / + \ | 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 + ROUNDED_RECT_LEFT = 0x1, + ROUNDED_RECT_TOP = 0x2, + ROUNDED_RECT_RIGHT = 0x4, + ROUNDED_RECT_BOTTOM = 0x8, + ROUNDED_RECT_ALL = 0xf }ERoundedEdge; @@ -112,61 +112,61 @@ void gl_segmented_rect_3d_tex(const LLRectf& clip_rect, const LLRectf& center_uv inline void gl_rect_2d( const LLRect& rect, BOOL filled ) { - gl_rect_2d( rect.mLeft, rect.mTop, rect.mRight, rect.mBottom, 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 ); + gl_rect_2d_offset_local( rect.mLeft, rect.mTop, rect.mRight, rect.mBottom, pixel_offset, filled ); } class LLImageProviderInterface; class LLRender2D : public LLParamSingleton<LLRender2D> { - LLSINGLETON(LLRender2D, LLImageProviderInterface* image_provider); - LOG_CLASS(LLRender2D); - ~LLRender2D(); + LLSINGLETON(LLRender2D, LLImageProviderInterface* image_provider); + LOG_CLASS(LLRender2D); + ~LLRender2D(); public: - static void pushMatrix(); - static void popMatrix(); - static void loadIdentity(); - static void translate(F32 x, F32 y, F32 z = 0.0f); + 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 setLineWidth(F32 width); - LLPointer<LLUIImage> getUIImageByID(const LLUUID& image_id, S32 priority = 0); - LLPointer<LLUIImage> getUIImage(const std::string& name, S32 priority = 0); + LLPointer<LLUIImage> getUIImageByID(const LLUUID& image_id, S32 priority = 0); + LLPointer<LLUIImage> getUIImage(const std::string& name, S32 priority = 0); protected: - // since LLRender2D has no control of image provider's lifecycle - // we need a way to tell LLRender2D that provider died and - // LLRender2D needs to be updated. - static void resetProvider(); + // since LLRender2D has no control of image provider's lifecycle + // we need a way to tell LLRender2D that provider died and + // LLRender2D needs to be updated. + static void resetProvider(); private: - LLImageProviderInterface* mImageProvider; + LLImageProviderInterface* mImageProvider; }; class LLImageProviderInterface { protected: - LLImageProviderInterface() {}; - virtual ~LLImageProviderInterface(); + 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; + 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; - // to notify holders when pointer gets deleted - typedef void(*callback_t)(); - void addOnRemovalCallback(callback_t func); - void deleteOnRemovalCallback(callback_t func); + // to notify holders when pointer gets deleted + typedef void(*callback_t)(); + void addOnRemovalCallback(callback_t func); + void deleteOnRemovalCallback(callback_t func); private: - typedef std::list< callback_t > callback_list_t; - callback_list_t mCallbackList; + typedef std::list< callback_t > callback_list_t; + callback_list_t mCallbackList; }; diff --git a/indra/llrender/llrendernavprim.cpp b/indra/llrender/llrendernavprim.cpp index eea3077632..419c8e8755 100644 --- a/indra/llrender/llrendernavprim.cpp +++ b/indra/llrender/llrendernavprim.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llrendernavprim.cpp * @brief Implementation of llrendernavprim * @author Prep@lindenlab.com @@ -43,17 +43,17 @@ void LLRenderNavPrim::renderLLTri( const LLVector3& a, const LLVector3& b, const gGL.color4ubv(color.mV); gGL.begin(LLRender::TRIANGLES); - { - gGL.vertex3fv( a.mV ); - gGL.vertex3fv( b.mV ); - gGL.vertex3fv( c.mV ); - } - gGL.end(); + { + gGL.vertex3fv( a.mV ); + gGL.vertex3fv( b.mV ); + gGL.vertex3fv( c.mV ); + } + gGL.end(); } //============================================================================= void LLRenderNavPrim::renderNavMeshVB( U32 mode, LLVertexBuffer* pVBO, int vertCnt ) -{ - pVBO->setBuffer(); - pVBO->drawArrays( mode, 0, vertCnt ); +{ + pVBO->setBuffer(); + pVBO->drawArrays( mode, 0, vertCnt ); } //============================================================================= diff --git a/indra/llrender/llrendernavprim.h b/indra/llrender/llrendernavprim.h index a3a5dfec3a..a7b003a6cf 100644 --- a/indra/llrender/llrendernavprim.h +++ b/indra/llrender/llrendernavprim.h @@ -1,4 +1,4 @@ -/** +/** * @file llrendernavprim.h * @brief Header file for llrendernavprim * @author Prep@lindenlab.com @@ -37,10 +37,10 @@ class LLVertexBuffer; class LLRenderNavPrim { public: - //Draw simple tri - void renderLLTri( const LLVector3& a, const LLVector3& b, const LLVector3& c, const LLColor4U& color ) const; - //Draw the contents of vertex buffer - void renderNavMeshVB( U32 mode, LLVertexBuffer* pVBO, int vertCnt ); + //Draw simple tri + void renderLLTri( const LLVector3& a, const LLVector3& b, const LLVector3& c, const LLColor4U& color ) const; + //Draw the contents of vertex buffer + void renderNavMeshVB( U32 mode, LLVertexBuffer* pVBO, int vertCnt ); private: }; diff --git a/indra/llrender/llrendersphere.cpp b/indra/llrender/llrendersphere.cpp index 26bfe036e8..9570180554 100644 --- a/indra/llrender/llrendersphere.cpp +++ b/indra/llrender/llrendersphere.cpp @@ -1,32 +1,32 @@ -/** +/** * @file llrendersphere.cpp * @brief implementation of the LLRenderSphere class. * * $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$ */ -// Sphere creates a set of display lists that can then be called to create -// a lit sphere at different LOD levels. You only need one instance of sphere -// per viewer - then call the appropriate list. +// Sphere creates a set of display lists that can then be called to create +// a lit sphere at different LOD levels. You only need one instance of sphere +// per viewer - then call the appropriate list. #include "linden_common.h" @@ -39,53 +39,53 @@ LLRenderSphere gSphere; void LLRenderSphere::render() { - renderGGL(); - gGL.flush(); + renderGGL(); + gGL.flush(); } inline LLVector3 polar_to_cart(F32 latitude, F32 longitude) { - return LLVector3(sin(F_TWO_PI * latitude) * cos(F_TWO_PI * longitude), - sin(F_TWO_PI * latitude) * sin(F_TWO_PI * longitude), - cos(F_TWO_PI * latitude)); + return LLVector3(sin(F_TWO_PI * latitude) * cos(F_TWO_PI * longitude), + sin(F_TWO_PI * latitude) * sin(F_TWO_PI * longitude), + cos(F_TWO_PI * latitude)); } void LLRenderSphere::renderGGL() { - S32 const LATITUDE_SLICES = 20; - S32 const LONGITUDE_SLICES = 30; + S32 const LATITUDE_SLICES = 20; + S32 const LONGITUDE_SLICES = 30; + + if (mSpherePoints.empty()) + { + mSpherePoints.resize(LATITUDE_SLICES + 1); + for (S32 lat_i = 0; lat_i < LATITUDE_SLICES + 1; lat_i++) + { + mSpherePoints[lat_i].resize(LONGITUDE_SLICES + 1); + for (S32 lon_i = 0; lon_i < LONGITUDE_SLICES + 1; lon_i++) + { + F32 lat = (F32)lat_i / LATITUDE_SLICES; + F32 lon = (F32)lon_i / LONGITUDE_SLICES; - if (mSpherePoints.empty()) - { - mSpherePoints.resize(LATITUDE_SLICES + 1); - for (S32 lat_i = 0; lat_i < LATITUDE_SLICES + 1; lat_i++) - { - mSpherePoints[lat_i].resize(LONGITUDE_SLICES + 1); - for (S32 lon_i = 0; lon_i < LONGITUDE_SLICES + 1; lon_i++) - { - F32 lat = (F32)lat_i / LATITUDE_SLICES; - F32 lon = (F32)lon_i / LONGITUDE_SLICES; + mSpherePoints[lat_i][lon_i] = polar_to_cart(lat, lon); + } + } + } - mSpherePoints[lat_i][lon_i] = polar_to_cart(lat, lon); - } - } - } - - gGL.begin(LLRender::TRIANGLES); + gGL.begin(LLRender::TRIANGLES); - for (S32 lat_i = 0; lat_i < LATITUDE_SLICES; lat_i++) - { - for (S32 lon_i = 0; lon_i < LONGITUDE_SLICES; lon_i++) - { - gGL.vertex3fv(mSpherePoints[lat_i][lon_i].mV); - gGL.vertex3fv(mSpherePoints[lat_i][lon_i+1].mV); - gGL.vertex3fv(mSpherePoints[lat_i+1][lon_i].mV); + for (S32 lat_i = 0; lat_i < LATITUDE_SLICES; lat_i++) + { + for (S32 lon_i = 0; lon_i < LONGITUDE_SLICES; lon_i++) + { + gGL.vertex3fv(mSpherePoints[lat_i][lon_i].mV); + gGL.vertex3fv(mSpherePoints[lat_i][lon_i+1].mV); + gGL.vertex3fv(mSpherePoints[lat_i+1][lon_i].mV); - gGL.vertex3fv(mSpherePoints[lat_i+1][lon_i].mV); - gGL.vertex3fv(mSpherePoints[lat_i][lon_i+1].mV); - gGL.vertex3fv(mSpherePoints[lat_i+1][lon_i+1].mV); - } - } - gGL.end(); + gGL.vertex3fv(mSpherePoints[lat_i+1][lon_i].mV); + gGL.vertex3fv(mSpherePoints[lat_i][lon_i+1].mV); + gGL.vertex3fv(mSpherePoints[lat_i+1][lon_i+1].mV); + } + } + gGL.end(); } diff --git a/indra/llrender/llrendersphere.h b/indra/llrender/llrendersphere.h index f8e9e86e7f..e2e886fa06 100644 --- a/indra/llrender/llrendersphere.h +++ b/indra/llrender/llrendersphere.h @@ -1,25 +1,25 @@ -/** +/** * @file llrendersphere.h * @brief interface for the LLRenderSphere class. * * $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$ */ @@ -35,16 +35,16 @@ #include "v4color.h" #include "llgl.h" -void lat2xyz(LLVector3 * result, F32 lat, F32 lon); // utility routine +void lat2xyz(LLVector3 * result, F32 lat, F32 lon); // utility routine -class LLRenderSphere +class LLRenderSphere { public: - void render(); // render at highest LOD - void renderGGL(); // render using LLRender + void render(); // render at highest LOD + void renderGGL(); // render using LLRender private: - std::vector< std::vector<LLVector3> > mSpherePoints; + std::vector< std::vector<LLVector3> > mSpherePoints; }; extern LLRenderSphere gSphere; diff --git a/indra/llrender/lltexture.cpp b/indra/llrender/lltexture.cpp index 6eef36216c..980c0950f9 100644 --- a/indra/llrender/lltexture.cpp +++ b/indra/llrender/lltexture.cpp @@ -1,31 +1,31 @@ -/** +/** * @file lltexture.cpp * * $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 "lltexture.h" -//virtual +//virtual LLTexture::~LLTexture() { } @@ -36,8 +36,8 @@ bool LLTexture::bindDefaultImage(const S32 stage) { llassert(false); return fals bool LLTexture::bindDebugImage(const S32 stage) { llassert(false); return false; } void LLTexture::forceImmediateUpdate() { llassert(false); } void LLTexture::setActive() { llassert(false); } -S32 LLTexture::getWidth(S32 discard_level) const { llassert(false); return 0; } -S32 LLTexture::getHeight(S32 discard_level) const { llassert(false); return 0; } +S32 LLTexture::getWidth(S32 discard_level) const { llassert(false); return 0; } +S32 LLTexture::getHeight(S32 discard_level) const { llassert(false); return 0; } bool LLTexture::isActiveFetching() { llassert(false); return false; } LLImageGL* LLTexture::getGLTexture() const { llassert(false); return nullptr; } void LLTexture::updateBindStatsForTester() { } diff --git a/indra/llrender/lltexture.h b/indra/llrender/lltexture.h index e890a5a30b..35cded86f2 100644 --- a/indra/llrender/lltexture.h +++ b/indra/llrender/lltexture.h @@ -1,30 +1,30 @@ -/** +/** * @file lltexture.h * @brief LLTexture definition * - * This class acts as a wrapper for OpenGL calls. - * The goal of this class is to minimize the number of api calls due to legacy rendering - * code, to define an interface for a multiple rendering API abstraction of the UI - * rendering, and to abstract out direct rendering calls in a way that is cleaner and easier to maintain. + * This class acts as a wrapper for OpenGL calls. + * The goal of this class is to minimize the number of api calls due to legacy rendering + * code, to define an interface for a multiple rendering API abstraction of the UI + * rendering, and to abstract out direct rendering calls in a way that is cleaner and easier to maintain. * * $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$ */ @@ -44,32 +44,32 @@ class LLFontGL ; // class LLTexture : public virtual LLRefCount { - friend class LLTexUnit ; - friend class LLFontGL ; + friend class LLTexUnit ; + friend class LLFontGL ; protected: - virtual ~LLTexture(); + virtual ~LLTexture(); public: - LLTexture() - {} + LLTexture() + {} - // - //interfaces to access LLGLTexture - // - virtual S8 getType() const; - virtual void setKnownDrawSize(S32 width, S32 height); - virtual bool bindDefaultImage(const S32 stage = 0); - virtual bool bindDebugImage(const S32 stage = 0); - virtual void forceImmediateUpdate(); - virtual void setActive(); - virtual S32 getWidth(S32 discard_level = -1) const; - virtual S32 getHeight(S32 discard_level = -1) const; - virtual bool isActiveFetching(); + // + //interfaces to access LLGLTexture + // + virtual S8 getType() const; + virtual void setKnownDrawSize(S32 width, S32 height); + virtual bool bindDefaultImage(const S32 stage = 0); + virtual bool bindDebugImage(const S32 stage = 0); + virtual void forceImmediateUpdate(); + virtual void setActive(); + virtual S32 getWidth(S32 discard_level = -1) const; + virtual S32 getHeight(S32 discard_level = -1) const; + virtual bool isActiveFetching(); virtual LLImageGL* getGLTexture() const; private: - virtual void updateBindStatsForTester(); + virtual void updateBindStatsForTester(); }; #endif diff --git a/indra/llrender/lltexturemanagerbridge.cpp b/indra/llrender/lltexturemanagerbridge.cpp index 33f2185e4f..c243f0697a 100644 --- a/indra/llrender/lltexturemanagerbridge.cpp +++ b/indra/llrender/lltexturemanagerbridge.cpp @@ -1,25 +1,25 @@ - /** + /** * @file lltexturemanagerbridge.cpp * @brief Defined a null texture manager bridge. Applications must provide their own bridge implementaton. * * $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$ */ diff --git a/indra/llrender/lltexturemanagerbridge.h b/indra/llrender/lltexturemanagerbridge.h index f61433ea4d..0b76ee4de8 100644 --- a/indra/llrender/lltexturemanagerbridge.h +++ b/indra/llrender/lltexturemanagerbridge.h @@ -1,25 +1,25 @@ -/** +/** * @file lltexturemanagerbridge.h * @brief Bridge to an application-specific texture manager. * * $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$ */ @@ -36,9 +36,9 @@ class LLTextureManagerBridge public: virtual ~LLTextureManagerBridge() {} - virtual LLPointer<LLGLTexture> getLocalTexture(BOOL usemipmaps = TRUE, BOOL generate_gl_tex = TRUE) = 0; - virtual LLPointer<LLGLTexture> getLocalTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps, BOOL generate_gl_tex = TRUE) = 0; - virtual LLGLTexture* getFetchedTexture(const LLUUID &image_id) = 0; + virtual LLPointer<LLGLTexture> getLocalTexture(BOOL usemipmaps = TRUE, BOOL generate_gl_tex = TRUE) = 0; + virtual LLPointer<LLGLTexture> getLocalTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps, BOOL generate_gl_tex = TRUE) = 0; + virtual LLGLTexture* getFetchedTexture(const LLUUID &image_id) = 0; }; extern LLTextureManagerBridge* gTextureManagerBridgep; diff --git a/indra/llrender/lluiimage.cpp b/indra/llrender/lluiimage.cpp index 424672fe8e..bcf665ca18 100644 --- a/indra/llrender/lluiimage.cpp +++ b/indra/llrender/lluiimage.cpp @@ -1,25 +1,25 @@ -/** +/** * @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$ */ @@ -33,12 +33,12 @@ #include "lluiimage.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), - mImageLoaded(NULL), - mScaleStyle(SCALE_INNER), +: mName(name), + mImage(image), + mScaleRegion(0.f, 1.f, 1.f, 0.f), + mClipRegion(0.f, 1.f, 1.f, 0.f), + mImageLoaded(NULL), + mScaleStyle(SCALE_INNER), mCachedW(-1), mCachedH(-1) { @@ -48,125 +48,125 @@ LLUIImage::LLUIImage(const std::string& name, LLPointer<LLTexture> image) LLUIImage::~LLUIImage() { - delete mImageLoaded; + delete mImageLoaded; } S32 LLUIImage::getWidth() const -{ - // return clipped dimensions of actual image area - return ll_round((F32)mImage->getWidth(0) * mClipRegion.getWidth()); +{ + // return clipped dimensions of actual image area + return ll_round((F32)mImage->getWidth(0) * mClipRegion.getWidth()); } S32 LLUIImage::getHeight() const -{ - // return clipped dimensions of actual image area - return ll_round((F32)mImage->getHeight(0) * mClipRegion.getHeight()); +{ + // return clipped dimensions of actual image area + return ll_round((F32)mImage->getHeight(0) * mClipRegion.getHeight()); } -void LLUIImage::draw3D(const LLVector3& origin_agent, const LLVector3& x_axis, const LLVector3& y_axis, - const LLRect& rect, const LLColor4& color) +void LLUIImage::draw3D(const LLVector3& origin_agent, const LLVector3& x_axis, const LLVector3& y_axis, + const LLRect& rect, const LLColor4& color) { - F32 border_scale = 1.f; - F32 border_height = (1.f - mScaleRegion.getHeight()) * getHeight(); - F32 border_width = (1.f - mScaleRegion.getWidth()) * getWidth(); - if (rect.getHeight() < border_height || rect.getWidth() < border_width) - { - if(border_height - rect.getHeight() > border_width - rect.getWidth()) - { - border_scale = (F32)rect.getHeight() / border_height; - } - else - { - border_scale = (F32)rect.getWidth() / border_width; - } - } - - LLRender2D::getInstance()->pushMatrix(); - { - LLVector3 rect_origin = origin_agent + (rect.mLeft * x_axis) + (rect.mBottom * y_axis); - LLRender2D::getInstance()->translate(rect_origin.mV[VX], - rect_origin.mV[VY], - rect_origin.mV[VZ]); - gGL.getTexUnit(0)->bind(getImage()); - gGL.color4fv(color.mV); - - LLRectf center_uv_rect(mClipRegion.mLeft + mScaleRegion.mLeft * mClipRegion.getWidth(), - mClipRegion.mBottom + mScaleRegion.mTop * mClipRegion.getHeight(), - mClipRegion.mLeft + mScaleRegion.mRight * mClipRegion.getWidth(), - mClipRegion.mBottom + mScaleRegion.mBottom * mClipRegion.getHeight()); - gl_segmented_rect_3d_tex(mClipRegion, - center_uv_rect, - LLRectf(border_width * border_scale * 0.5f / (F32)rect.getWidth(), - (rect.getHeight() - (border_height * border_scale * 0.5f)) / (F32)rect.getHeight(), - (rect.getWidth() - (border_width * border_scale * 0.5f)) / (F32)rect.getWidth(), - (border_height * border_scale * 0.5f) / (F32)rect.getHeight()), - rect.getWidth() * x_axis, - rect.getHeight() * y_axis); - - } LLRender2D::getInstance()->popMatrix(); + F32 border_scale = 1.f; + F32 border_height = (1.f - mScaleRegion.getHeight()) * getHeight(); + F32 border_width = (1.f - mScaleRegion.getWidth()) * getWidth(); + if (rect.getHeight() < border_height || rect.getWidth() < border_width) + { + if(border_height - rect.getHeight() > border_width - rect.getWidth()) + { + border_scale = (F32)rect.getHeight() / border_height; + } + else + { + border_scale = (F32)rect.getWidth() / border_width; + } + } + + LLRender2D::getInstance()->pushMatrix(); + { + LLVector3 rect_origin = origin_agent + (rect.mLeft * x_axis) + (rect.mBottom * y_axis); + LLRender2D::getInstance()->translate(rect_origin.mV[VX], + rect_origin.mV[VY], + rect_origin.mV[VZ]); + gGL.getTexUnit(0)->bind(getImage()); + gGL.color4fv(color.mV); + + LLRectf center_uv_rect(mClipRegion.mLeft + mScaleRegion.mLeft * mClipRegion.getWidth(), + mClipRegion.mBottom + mScaleRegion.mTop * mClipRegion.getHeight(), + mClipRegion.mLeft + mScaleRegion.mRight * mClipRegion.getWidth(), + mClipRegion.mBottom + mScaleRegion.mBottom * mClipRegion.getHeight()); + gl_segmented_rect_3d_tex(mClipRegion, + center_uv_rect, + LLRectf(border_width * border_scale * 0.5f / (F32)rect.getWidth(), + (rect.getHeight() - (border_height * border_scale * 0.5f)) / (F32)rect.getHeight(), + (rect.getWidth() - (border_width * border_scale * 0.5f)) / (F32)rect.getWidth(), + (border_height * border_scale * 0.5f) / (F32)rect.getHeight()), + rect.getWidth() * x_axis, + rect.getHeight() * y_axis); + + } LLRender2D::getInstance()->popMatrix(); } //#include "lluiimage.inl" -boost::signals2::connection LLUIImage::addLoadedCallback( const image_loaded_signal_t::slot_type& cb ) +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); + if (!mImageLoaded) + { + mImageLoaded = new image_loaded_signal_t(); + } + return mImageLoaded->connect(cb); } void LLUIImage::onImageLoaded() { - if (mImageLoaded) - { - (*mImageLoaded)(); - } + if (mImageLoaded) + { + (*mImageLoaded)(); + } } namespace LLInitParam { - void ParamValue<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::getInstance()->getUIImage(name()); - if (imagep) - { - updateValue(imagep); - } - } - - void ParamValue<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); - } + void ParamValue<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::getInstance()->getUIImage(name()); + if (imagep) + { + updateValue(imagep); + } + } + + void ParamValue<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 index e462e19004..7988243a89 100644 --- a/indra/llrender/lluiimage.h +++ b/indra/llrender/lluiimage.h @@ -1,25 +1,25 @@ -/** +/** * @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$ */ @@ -43,70 +43,70 @@ extern const LLColor4 UI_VERTEX_COLOR; class LLUIImage : public LLRefCount { public: - enum EScaleStyle - { - SCALE_INNER, - SCALE_OUTER - }; + enum EScaleStyle + { + SCALE_INNER, + SCALE_OUTER + }; - typedef boost::signals2::signal<void (void)> image_loaded_signal_t; + typedef boost::signals2::signal<void (void)> image_loaded_signal_t; - LLUIImage(const std::string& name, LLPointer<LLTexture> image); - virtual ~LLUIImage(); + LLUIImage(const std::string& name, LLPointer<LLTexture> image); + virtual ~LLUIImage(); - LL_FORCE_INLINE void setClipRegion(const LLRectf& region) - { - mClipRegion = region; + LL_FORCE_INLINE void setClipRegion(const LLRectf& region) + { + mClipRegion = region; } - LL_FORCE_INLINE void setScaleRegion(const LLRectf& region) - { - mScaleRegion = region; + LL_FORCE_INLINE void setScaleRegion(const LLRectf& region) + { + mScaleRegion = region; } - LL_FORCE_INLINE void setScaleStyle(EScaleStyle style) + LL_FORCE_INLINE void setScaleStyle(EScaleStyle style) { - mScaleStyle = style; + mScaleStyle = style; } - LL_FORCE_INLINE LLPointer<LLTexture> getImage() { return mImage; } - LL_FORCE_INLINE const LLPointer<LLTexture>& getImage() const { return mImage; } + LL_FORCE_INLINE LLPointer<LLTexture> getImage() { return mImage; } + LL_FORCE_INLINE const LLPointer<LLTexture>& getImage() const { return mImage; } + + LL_FORCE_INLINE void draw(S32 x, S32 y, S32 width, S32 height, const LLColor4& color = UI_VERTEX_COLOR) const; + LL_FORCE_INLINE void draw(S32 x, S32 y, const LLColor4& color = UI_VERTEX_COLOR) const; + LL_FORCE_INLINE void draw(const LLRect& rect, const LLColor4& color = UI_VERTEX_COLOR) const { draw(rect.mLeft, rect.mBottom, rect.getWidth(), rect.getHeight(), color); } - LL_FORCE_INLINE void draw(S32 x, S32 y, S32 width, S32 height, const LLColor4& color = UI_VERTEX_COLOR) const; - LL_FORCE_INLINE void draw(S32 x, S32 y, const LLColor4& color = UI_VERTEX_COLOR) const; - LL_FORCE_INLINE void draw(const LLRect& rect, const LLColor4& color = UI_VERTEX_COLOR) const { draw(rect.mLeft, rect.mBottom, rect.getWidth(), rect.getHeight(), color); } - - LL_FORCE_INLINE void drawSolid(S32 x, S32 y, S32 width, S32 height, const LLColor4& color) const; - LL_FORCE_INLINE void drawSolid(const LLRect& rect, const LLColor4& color) const { drawSolid(rect.mLeft, rect.mBottom, rect.getWidth(), rect.getHeight(), color); } - LL_FORCE_INLINE void drawSolid(S32 x, S32 y, const LLColor4& color) const { drawSolid(x, y, getWidth(), getHeight(), color); } + LL_FORCE_INLINE void drawSolid(S32 x, S32 y, S32 width, S32 height, const LLColor4& color) const; + LL_FORCE_INLINE void drawSolid(const LLRect& rect, const LLColor4& color) const { drawSolid(rect.mLeft, rect.mBottom, rect.getWidth(), rect.getHeight(), color); } + LL_FORCE_INLINE void drawSolid(S32 x, S32 y, const LLColor4& color) const { drawSolid(x, y, getWidth(), getHeight(), color); } - LL_FORCE_INLINE void drawBorder(S32 x, S32 y, S32 width, S32 height, const LLColor4& color, S32 border_width) const; - LL_FORCE_INLINE void drawBorder(const LLRect& rect, const LLColor4& color, S32 border_width) const { drawBorder(rect.mLeft, rect.mBottom, rect.getWidth(), rect.getHeight(), color, border_width); } - LL_FORCE_INLINE void drawBorder(S32 x, S32 y, const LLColor4& color, S32 border_width) const { drawBorder(x, y, getWidth(), getHeight(), color, border_width); } + LL_FORCE_INLINE void drawBorder(S32 x, S32 y, S32 width, S32 height, const LLColor4& color, S32 border_width) const; + LL_FORCE_INLINE void drawBorder(const LLRect& rect, const LLColor4& color, S32 border_width) const { drawBorder(rect.mLeft, rect.mBottom, rect.getWidth(), rect.getHeight(), color, border_width); } + LL_FORCE_INLINE void drawBorder(S32 x, S32 y, const LLColor4& color, S32 border_width) const { drawBorder(x, y, getWidth(), getHeight(), color, border_width); } - void draw3D(const LLVector3& origin_agent, const LLVector3& x_axis, const LLVector3& y_axis, const LLRect& rect, const LLColor4& color); + void draw3D(const LLVector3& origin_agent, const LLVector3& x_axis, const LLVector3& y_axis, const LLRect& rect, const LLColor4& color); - LL_FORCE_INLINE const std::string& getName() const { return mName; } + LL_FORCE_INLINE const std::string& getName() const { return mName; } - virtual S32 getWidth() const; - virtual S32 getHeight() const; + virtual S32 getWidth() const; + virtual S32 getHeight() const; - // returns dimensions of underlying textures, which might not be equal to ui image portion - LL_FORCE_INLINE S32 getTextureWidth() const; - LL_FORCE_INLINE S32 getTextureHeight() const; + // returns dimensions of underlying textures, which might not be equal to ui image portion + LL_FORCE_INLINE S32 getTextureWidth() const; + LL_FORCE_INLINE S32 getTextureHeight() const; - boost::signals2::connection addLoadedCallback( const image_loaded_signal_t::slot_type& cb ); + boost::signals2::connection addLoadedCallback( const image_loaded_signal_t::slot_type& cb ); - void onImageLoaded(); + void onImageLoaded(); protected: - image_loaded_signal_t* mImageLoaded; + image_loaded_signal_t* mImageLoaded; - std::string mName; - LLRectf mScaleRegion; - LLRectf mClipRegion; - LLPointer<LLTexture> mImage; - EScaleStyle mScaleStyle; + std::string mName; + LLRectf mScaleRegion; + LLRectf mClipRegion; + LLPointer<LLTexture> mImage; + EScaleStyle mScaleStyle; mutable S32 mCachedW; mutable S32 mCachedH; }; @@ -115,33 +115,33 @@ protected: namespace LLInitParam { - template<> - class ParamValue<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 = NULL) - : 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); - }; + template<> + class ParamValue<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 = NULL) + : 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; diff --git a/indra/llrender/lluiimage.inl b/indra/llrender/lluiimage.inl index f5227556f0..a69616c0c1 100644 --- a/indra/llrender/lluiimage.inl +++ b/indra/llrender/lluiimage.inl @@ -1,66 +1,66 @@ -/** +/** * @file lluiimage.inl * @brief UI inline func 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$ */ void LLUIImage::draw(S32 x, S32 y, const LLColor4& color) const { - draw(x, y, getWidth(), getHeight(), color); + draw(x, y, getWidth(), getHeight(), color); } void LLUIImage::draw(S32 x, S32 y, S32 width, S32 height, const LLColor4& color) const { - gl_draw_scaled_image_with_border( - x, y, - width, height, - mImage, - color, - FALSE, - mClipRegion, - mScaleRegion, - mScaleStyle == SCALE_INNER); + gl_draw_scaled_image_with_border( + x, y, + width, height, + mImage, + color, + FALSE, + mClipRegion, + mScaleRegion, + mScaleStyle == SCALE_INNER); } 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, - mScaleStyle == SCALE_INNER); + gl_draw_scaled_image_with_border( + x, y, + width, height, + mImage, + color, + TRUE, + mClipRegion, + mScaleRegion, + mScaleStyle == SCALE_INNER); } 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); + LLRect border_rect; + border_rect.setOriginAndSize(x, y, width, height); + border_rect.stretch(border_width, border_width); + drawSolid(border_rect, color); } // returns dimensions of underlying textures, which might not be equal to ui image portion |