diff options
Diffstat (limited to 'indra/llrender')
52 files changed, 11153 insertions, 11086 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..92b373c835 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,823 @@ 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) +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)); + mFallbackFonts.emplace_back(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) + { + return NULL; + } + + llassert(!mIsFallback); + llassert(glyph_type < EFontGlyphType::Count); + //LL_DEBUGS() << "Adding new glyph for " << wch << " to font" << LL_ENDL; + + // Initialize char to glyph map + FT_UInt glyph_index = FT_Get_Char_Index(mFTFace, wch); + if (glyph_index == 0) + { + // No corresponding glyph in this font: look for a glyph in fallback + // fonts. + size_t count = mFallbackFonts.size(); + if (LLStringOps::isEmoji(wch)) + { + // This is a "genuine" emoji (in the range 0x1f000-0x20000): print + // it using the emoji font(s) if possible. HB + for (size_t i = 0; i < count; ++i) + { + const fallback_font_t& pair = mFallbackFonts[i]; + if (!pair.second || !pair.second(wch)) + { + // If this font does not have a functor, or the character + // does not pass the functor, reject it. Note: we keep the + // functor test (despite the fact we already tested for + // LLStringOps::isEmoji(wch) above), in case we would use + // different, more restrictive or partionned functors in + // the future with several different emoji fonts. HB + continue; + } + glyph_index = FT_Get_Char_Index(pair.first->mFTFace, wch); + if (glyph_index) + { + return addGlyphFromFont(pair.first, wch, glyph_index, + glyph_type); + } + } + } + // Then try and find a monochrome fallback font that could print this + // glyph: such fonts do *not* have a functor. We give priority to + // monochrome fonts for non-genuine emojis so that UI elements which + // used to render with them before the emojis font introduction (e.g. + // check marks in menus, or LSL dialogs text and buttons) do render the + // same way as they always did. HB + std::vector<size_t> emoji_fonts_idx; + for (size_t i = 0; i < count; ++i) + { + const fallback_font_t& pair = mFallbackFonts[i]; + if (pair.second) + { + // If this font got a functor, remember the index for later and + // try the next fallback font. HB + emoji_fonts_idx.push_back(i); + continue; + } + glyph_index = FT_Get_Char_Index(pair.first->mFTFace, wch); + if (glyph_index) + { + return addGlyphFromFont(pair.first, wch, glyph_index, + glyph_type); + } + } + // Everything failed so far: this character is not a genuine emoji, + // neither a special character known from our monochrome fallback + // fonts: make a last try, using the emoji font(s), but ignoring the + // functor to render using whatever (colorful) glyph that might be + // available in such fonts for this character. HB + for (size_t j = 0, count2 = emoji_fonts_idx.size(); j < count2; ++j) + { + const fallback_font_t& pair = mFallbackFonts[emoji_fonts_idx[j]]; + glyph_index = FT_Get_Char_Index(pair.first->mFTFace, wch); + if (glyph_index) + { + return addGlyphFromFont(pair.first, wch, glyph_index, + glyph_type); + } + } + } + + auto 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..3714bb1883 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,446 @@ 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); + // Preserve the transparency to render fading emojis in fading text (e.g. + // for the chat console)... HB + LLColor4U emoji_color(255, 255, 255, text_color.mV[VW]); + + 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; + } + + const LLColor4U& col = + bitmap_entry.first == EFontGlyphType::Grayscale ? text_color + : emoji_color; + drawGlyph(glyph_count, vertices, uvs, colors, screen_rect, uv_rect, + col, 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 +570,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 +881,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 +904,178 @@ 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() +LLFontGL* LLFontGL::getFontEmojiSmall() { - static LLFontGL* fontp = getFont(LLFontDescriptor("Emoji", "Large", 0)); - return fontp;; + static LLFontGL* fontp = getFont(LLFontDescriptor("Emoji", "Small", 0)); + return fontp;; +} + +//static +LLFontGL* LLFontGL::getFontEmojiMedium() +{ + static LLFontGL* fontp = getFont(LLFontDescriptor("Emoji", "Medium", 0)); + return fontp;; +} + +//static +LLFontGL* LLFontGL::getFontEmojiLarge() +{ + 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 +1095,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 +1194,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..65f0a8cbfd 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,203 @@ 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* getFontEmojiSmall(); + static LLFontGL* getFontEmojiMedium(); + static LLFontGL* getFontEmojiLarge(); + 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/llglslshader.cpp b/indra/llrender/llglslshader.cpp index ccfb8f69be..97759939c9 100644 --- a/indra/llrender/llglslshader.cpp +++ b/indra/llrender/llglslshader.cpp @@ -422,27 +422,27 @@ BOOL LLGLSLShader::createShader(std::vector<LLStaticHashedString>* attributes, mUsingBinaryProgram = LLShaderMgr::instance()->loadCachedProgramBinary(this); - if (!mUsingBinaryProgram) - { + if (!mUsingBinaryProgram) + { #if DEBUG_SHADER_INCLUDES - fprintf(stderr, "--- %s ---\n", mName.c_str()); + fprintf(stderr, "--- %s ---\n", mName.c_str()); #endif // DEBUG_SHADER_INCLUDES //compile new source - vector< pair<string, GLenum> >::iterator fileIter = mShaderFiles.begin(); - for (; fileIter != mShaderFiles.end(); fileIter++) - { - GLuint shaderhandle = LLShaderMgr::instance()->loadShaderFile((*fileIter).first, mShaderLevel, (*fileIter).second, &mDefines, mFeatures.mIndexedTextureChannels); - LL_DEBUGS("ShaderLoading") << "SHADER FILE: " << (*fileIter).first << " mShaderLevel=" << mShaderLevel << LL_ENDL; - if (shaderhandle) - { - attachObject(shaderhandle); - } - else - { - success = FALSE; - } - } + vector< pair<string, GLenum> >::iterator fileIter = mShaderFiles.begin(); + for (; fileIter != mShaderFiles.end(); fileIter++) + { + GLuint shaderhandle = LLShaderMgr::instance()->loadShaderFile((*fileIter).first, mShaderLevel, (*fileIter).second, &mDefines, mFeatures.mIndexedTextureChannels); + LL_DEBUGS("ShaderLoading") << "SHADER FILE: " << (*fileIter).first << " mShaderLevel=" << mShaderLevel << LL_ENDL; + if (shaderhandle) + { + attachObject(shaderhandle); + } + else + { + success = FALSE; + } + } } // Attach existing objects @@ -606,19 +606,19 @@ BOOL LLGLSLShader::mapAttributes(const std::vector<LLStaticHashedString>* attrib { LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; - BOOL res = TRUE; - if (!mUsingBinaryProgram) - { - //before linking, make sure reserved attributes always have consistent locations - for (U32 i = 0; i < LLShaderMgr::instance()->mReservedAttribs.size(); i++) - { - const char* name = LLShaderMgr::instance()->mReservedAttribs[i].c_str(); - glBindAttribLocation(mProgramObject, i, (const GLchar*)name); - } - - //link the program - res = link(); - } + BOOL res = TRUE; + if (!mUsingBinaryProgram) + { + //before linking, make sure reserved attributes always have consistent locations + for (U32 i = 0; i < LLShaderMgr::instance()->mReservedAttribs.size(); i++) + { + const char* name = LLShaderMgr::instance()->mReservedAttribs[i].c_str(); + glBindAttribLocation(mProgramObject, i, (const GLchar*)name); + } + + //link the program + res = link(); + } mAttribute.clear(); U32 numAttributes = (attributes == NULL) ? 0 : attributes->size(); diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h index 43d095f73a..df568bfea5 100644 --- a/indra/llrender/llglslshader.h +++ b/indra/llrender/llglslshader.h @@ -233,7 +233,7 @@ public: void addConstant(const LLGLSLShader::eShaderConsts shader_const); //enable/disable texture channel for specified uniform - //if given texture uniform is active in the shader, + //if given texture uniform is active in the shader, //the corresponding channel will be active upon return //returns channel texture is enabled in from [0-MAX) S32 enableTexture(S32 uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE, LLTexUnit::eTextureColorSpace space = LLTexUnit::TCS_LINEAR); @@ -255,7 +255,7 @@ public: void bind(); //helper to conditionally bind mRiggedVariant instead of this void bind(bool rigged); - + bool isComplete() const { return mProgramObject != 0; } LLUUID hash(); @@ -329,11 +329,11 @@ private: }; //UI shader (declared here so llui_libtest will link properly) -extern LLGLSLShader gUIProgram; +extern LLGLSLShader gUIProgram; //output vec4(color.rgb,color.a*tex0[tc0].a) -extern LLGLSLShader gSolidColorProgram; +extern LLGLSLShader gSolidColorProgram; //Alpha mask shader (declared here so llappearance can access properly) -extern LLGLSLShader gAlphaMaskProgram; +extern LLGLSLShader gAlphaMaskProgram; #ifdef LL_PROFILER_ENABLE_RENDER_DOC #define LL_SET_SHADER_LABEL(shader) shader.setLabel(#shader) 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/llgltexture.cpp b/indra/llrender/llgltexture.cpp index b616002b49..944a3d0235 100644 --- a/indra/llrender/llgltexture.cpp +++ b/indra/llrender/llgltexture.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llgltexture.cpp * @brief Opengl texture implementation * * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -29,365 +29,365 @@ LLGLTexture::LLGLTexture(BOOL usemipmaps) { - init(); - mUseMipMaps = usemipmaps; + init(); + mUseMipMaps = usemipmaps; } LLGLTexture::LLGLTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps) { - init(); - mFullWidth = width ; - mFullHeight = height ; - mUseMipMaps = usemipmaps; - mComponents = components ; - setTexelsPerImage(); + init(); + mFullWidth = width ; + mFullHeight = height ; + mUseMipMaps = usemipmaps; + mComponents = components ; + setTexelsPerImage(); } LLGLTexture::LLGLTexture(const LLImageRaw* raw, BOOL usemipmaps) { - init(); - mUseMipMaps = usemipmaps ; - // Create an empty image of the specified size and width - mGLTexturep = new LLImageGL(raw, usemipmaps) ; + init(); + mUseMipMaps = usemipmaps ; + // Create an empty image of the specified size and width + mGLTexturep = new LLImageGL(raw, usemipmaps) ; } LLGLTexture::~LLGLTexture() { - cleanup(); + cleanup(); } void LLGLTexture::init() { - mBoostLevel = LLGLTexture::BOOST_NONE; + mBoostLevel = LLGLTexture::BOOST_NONE; - mFullWidth = 0; - mFullHeight = 0; - mTexelsPerImage = 0 ; - mUseMipMaps = FALSE ; - mComponents = 0 ; + mFullWidth = 0; + mFullHeight = 0; + mTexelsPerImage = 0 ; + mUseMipMaps = FALSE ; + mComponents = 0 ; - mTextureState = NO_DELETE ; - mDontDiscard = FALSE; - mNeedsGLTexture = FALSE ; + mTextureState = NO_DELETE ; + mDontDiscard = FALSE; + mNeedsGLTexture = FALSE ; } void LLGLTexture::cleanup() { - if(mGLTexturep) - { - mGLTexturep->cleanup(); - } + if(mGLTexturep) + { + mGLTexturep->cleanup(); + } } // virtual void LLGLTexture::dump() { - if(mGLTexturep) - { - mGLTexturep->dump(); - } + if(mGLTexturep) + { + mGLTexturep->dump(); + } } void LLGLTexture::setBoostLevel(S32 level) { - if(mBoostLevel != level) - { - mBoostLevel = level ; - if(mBoostLevel != LLGLTexture::BOOST_NONE - && mBoostLevel != LLGLTexture::BOOST_ICON + if(mBoostLevel != level) + { + mBoostLevel = level ; + if(mBoostLevel != LLGLTexture::BOOST_NONE + && mBoostLevel != LLGLTexture::BOOST_ICON && mBoostLevel != LLGLTexture::BOOST_THUMBNAIL) - { - setNoDelete() ; - } - } + { + setNoDelete() ; + } + } } void LLGLTexture::forceActive() { - mTextureState = ACTIVE ; + mTextureState = ACTIVE ; } -void LLGLTexture::setActive() -{ - if(mTextureState != NO_DELETE) - { - mTextureState = ACTIVE ; - } +void LLGLTexture::setActive() +{ + if(mTextureState != NO_DELETE) + { + mTextureState = ACTIVE ; + } } //set the texture to stay in memory -void LLGLTexture::setNoDelete() -{ - mTextureState = NO_DELETE ; +void LLGLTexture::setNoDelete() +{ + mTextureState = NO_DELETE ; } -void LLGLTexture::generateGLTexture() -{ - if(mGLTexturep.isNull()) - { - mGLTexturep = new LLImageGL(mFullWidth, mFullHeight, mComponents, mUseMipMaps) ; - } +void LLGLTexture::generateGLTexture() +{ + if(mGLTexturep.isNull()) + { + mGLTexturep = new LLImageGL(mFullWidth, mFullHeight, mComponents, mUseMipMaps) ; + } } LLImageGL* LLGLTexture::getGLTexture() const { - llassert(mGLTexturep.notNull()) ; + llassert(mGLTexturep.notNull()) ; - return mGLTexturep ; + return mGLTexturep ; } -BOOL LLGLTexture::createGLTexture() +BOOL LLGLTexture::createGLTexture() { - if(mGLTexturep.isNull()) - { - generateGLTexture() ; - } + if(mGLTexturep.isNull()) + { + generateGLTexture() ; + } - return mGLTexturep->createGLTexture() ; + return mGLTexturep->createGLTexture() ; } BOOL LLGLTexture::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename, BOOL to_create, S32 category, bool defer_copy, LLGLuint* tex_name) { - llassert(mGLTexturep.notNull()); + llassert(mGLTexturep.notNull()); - BOOL ret = mGLTexturep->createGLTexture(discard_level, imageraw, usename, to_create, category, defer_copy, tex_name) ; + BOOL ret = mGLTexturep->createGLTexture(discard_level, imageraw, usename, to_create, category, defer_copy, tex_name) ; - if(ret) - { - mFullWidth = mGLTexturep->getCurrentWidth() ; - mFullHeight = mGLTexturep->getCurrentHeight() ; - mComponents = mGLTexturep->getComponents() ; - setTexelsPerImage(); - } + if(ret) + { + mFullWidth = mGLTexturep->getCurrentWidth() ; + mFullHeight = mGLTexturep->getCurrentHeight() ; + mComponents = mGLTexturep->getComponents() ; + setTexelsPerImage(); + } - return ret ; + return ret ; } void LLGLTexture::setExplicitFormat(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format, BOOL swap_bytes) { - llassert(mGLTexturep.notNull()) ; - - mGLTexturep->setExplicitFormat(internal_format, primary_format, type_format, swap_bytes) ; + llassert(mGLTexturep.notNull()) ; + + mGLTexturep->setExplicitFormat(internal_format, primary_format, type_format, swap_bytes) ; } void LLGLTexture::setAddressMode(LLTexUnit::eTextureAddressMode mode) { - llassert(mGLTexturep.notNull()) ; - mGLTexturep->setAddressMode(mode) ; + llassert(mGLTexturep.notNull()) ; + mGLTexturep->setAddressMode(mode) ; } void LLGLTexture::setFilteringOption(LLTexUnit::eTextureFilterOptions option) { - llassert(mGLTexturep.notNull()) ; - mGLTexturep->setFilteringOption(option) ; + llassert(mGLTexturep.notNull()) ; + mGLTexturep->setFilteringOption(option) ; } //virtual -S32 LLGLTexture::getWidth(S32 discard_level) const +S32 LLGLTexture::getWidth(S32 discard_level) const { - llassert(mGLTexturep.notNull()) ; - return mGLTexturep->getWidth(discard_level) ; + llassert(mGLTexturep.notNull()) ; + return mGLTexturep->getWidth(discard_level) ; } //virtual -S32 LLGLTexture::getHeight(S32 discard_level) const +S32 LLGLTexture::getHeight(S32 discard_level) const { - llassert(mGLTexturep.notNull()) ; - return mGLTexturep->getHeight(discard_level) ; + llassert(mGLTexturep.notNull()) ; + return mGLTexturep->getHeight(discard_level) ; } S32 LLGLTexture::getMaxDiscardLevel() const { - llassert(mGLTexturep.notNull()) ; - return mGLTexturep->getMaxDiscardLevel() ; + llassert(mGLTexturep.notNull()) ; + return mGLTexturep->getMaxDiscardLevel() ; } S32 LLGLTexture::getDiscardLevel() const { - llassert(mGLTexturep.notNull()) ; - return mGLTexturep->getDiscardLevel() ; + llassert(mGLTexturep.notNull()) ; + return mGLTexturep->getDiscardLevel() ; } -S8 LLGLTexture::getComponents() const -{ - llassert(mGLTexturep.notNull()) ; - - return mGLTexturep->getComponents() ; +S8 LLGLTexture::getComponents() const +{ + llassert(mGLTexturep.notNull()) ; + + return mGLTexturep->getComponents() ; } -LLGLuint LLGLTexture::getTexName() const -{ - llassert(mGLTexturep.notNull()) ; +LLGLuint LLGLTexture::getTexName() const +{ + llassert(mGLTexturep.notNull()) ; - return mGLTexturep->getTexName() ; + return mGLTexturep->getTexName() ; } -BOOL LLGLTexture::hasGLTexture() const +BOOL LLGLTexture::hasGLTexture() const { - if(mGLTexturep.notNull()) - { - return mGLTexturep->getHasGLTexture() ; - } - return FALSE ; + if(mGLTexturep.notNull()) + { + return mGLTexturep->getHasGLTexture() ; + } + return FALSE ; } BOOL LLGLTexture::getBoundRecently() const { - if(mGLTexturep.notNull()) - { - return mGLTexturep->getBoundRecently() ; - } - return FALSE ; + if(mGLTexturep.notNull()) + { + return mGLTexturep->getBoundRecently() ; + } + return FALSE ; } LLTexUnit::eTextureType LLGLTexture::getTarget(void) const { - llassert(mGLTexturep.notNull()) ; - return mGLTexturep->getTarget() ; + llassert(mGLTexturep.notNull()) ; + return mGLTexturep->getTarget() ; } BOOL LLGLTexture::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, LLGLuint use_name) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - llassert(mGLTexturep.notNull()) ; + llassert(mGLTexturep.notNull()) ; - return mGLTexturep->setSubImage(imageraw, x_pos, y_pos, width, height, 0, use_name) ; + return mGLTexturep->setSubImage(imageraw, x_pos, y_pos, width, height, 0, use_name) ; } BOOL LLGLTexture::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, LLGLuint use_name) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - llassert(mGLTexturep.notNull()) ; + llassert(mGLTexturep.notNull()) ; - return mGLTexturep->setSubImage(datap, data_width, data_height, x_pos, y_pos, width, height, 0, use_name) ; + return mGLTexturep->setSubImage(datap, data_width, data_height, x_pos, y_pos, width, height, 0, use_name) ; } void LLGLTexture::setGLTextureCreated (bool initialized) { - llassert(mGLTexturep.notNull()) ; + llassert(mGLTexturep.notNull()) ; - mGLTexturep->setGLTextureCreated (initialized) ; + mGLTexturep->setGLTextureCreated (initialized) ; } -void LLGLTexture::setCategory(S32 category) +void LLGLTexture::setCategory(S32 category) { - llassert(mGLTexturep.notNull()) ; + llassert(mGLTexturep.notNull()) ; - mGLTexturep->setCategory(category) ; + mGLTexturep->setCategory(category) ; } void LLGLTexture::setTexName(LLGLuint texName) { llassert(mGLTexturep.notNull()); - return mGLTexturep->setTexName(texName); + return mGLTexturep->setTexName(texName); } void LLGLTexture::setTarget(const LLGLenum target, const LLTexUnit::eTextureType bind_target) { llassert(mGLTexturep.notNull()); - return mGLTexturep->setTarget(target, bind_target); + return mGLTexturep->setTarget(target, bind_target); } LLTexUnit::eTextureAddressMode LLGLTexture::getAddressMode(void) const { - llassert(mGLTexturep.notNull()) ; + llassert(mGLTexturep.notNull()) ; - return mGLTexturep->getAddressMode() ; + return mGLTexturep->getAddressMode() ; } S32Bytes LLGLTexture::getTextureMemory() const { - llassert(mGLTexturep.notNull()) ; + llassert(mGLTexturep.notNull()) ; - return mGLTexturep->mTextureMemory ; + return mGLTexturep->mTextureMemory ; } LLGLenum LLGLTexture::getPrimaryFormat() const { - llassert(mGLTexturep.notNull()) ; + llassert(mGLTexturep.notNull()) ; - return mGLTexturep->getPrimaryFormat() ; + return mGLTexturep->getPrimaryFormat() ; } BOOL LLGLTexture::getIsAlphaMask() const { - llassert(mGLTexturep.notNull()) ; + llassert(mGLTexturep.notNull()) ; - return mGLTexturep->getIsAlphaMask() ; + return mGLTexturep->getIsAlphaMask() ; } BOOL LLGLTexture::getMask(const LLVector2 &tc) { - llassert(mGLTexturep.notNull()) ; + llassert(mGLTexturep.notNull()) ; - return mGLTexturep->getMask(tc) ; + return mGLTexturep->getMask(tc) ; } F32 LLGLTexture::getTimePassedSinceLastBound() { - llassert(mGLTexturep.notNull()) ; + llassert(mGLTexturep.notNull()) ; - return mGLTexturep->getTimePassedSinceLastBound() ; + return mGLTexturep->getTimePassedSinceLastBound() ; } -BOOL LLGLTexture::getMissed() const +BOOL LLGLTexture::getMissed() const { - llassert(mGLTexturep.notNull()) ; + llassert(mGLTexturep.notNull()) ; - return mGLTexturep->getMissed() ; + return mGLTexturep->getMissed() ; } BOOL LLGLTexture::isJustBound() const { - llassert(mGLTexturep.notNull()) ; + llassert(mGLTexturep.notNull()) ; - return mGLTexturep->isJustBound() ; + return mGLTexturep->isJustBound() ; } void LLGLTexture::forceUpdateBindStats(void) const { - llassert(mGLTexturep.notNull()) ; + llassert(mGLTexturep.notNull()) ; - return mGLTexturep->forceUpdateBindStats() ; + return mGLTexturep->forceUpdateBindStats() ; } U32 LLGLTexture::getTexelsInAtlas() const { - llassert(mGLTexturep.notNull()) ; + llassert(mGLTexturep.notNull()) ; - return mGLTexturep->getTexelsInAtlas() ; + return mGLTexturep->getTexelsInAtlas() ; } U32 LLGLTexture::getTexelsInGLTexture() const { - llassert(mGLTexturep.notNull()) ; + llassert(mGLTexturep.notNull()) ; - return mGLTexturep->getTexelsInGLTexture() ; + return mGLTexturep->getTexelsInGLTexture() ; } BOOL LLGLTexture::isGLTextureCreated() const { - llassert(mGLTexturep.notNull()) ; + llassert(mGLTexturep.notNull()) ; - return mGLTexturep->isGLTextureCreated() ; + return mGLTexturep->isGLTextureCreated() ; } S32 LLGLTexture::getDiscardLevelInAtlas() const { - llassert(mGLTexturep.notNull()) ; + llassert(mGLTexturep.notNull()) ; - return mGLTexturep->getDiscardLevelInAtlas() ; + return mGLTexturep->getDiscardLevelInAtlas() ; } -void LLGLTexture::destroyGLTexture() +void LLGLTexture::destroyGLTexture() { - if(mGLTexturep.notNull() && mGLTexturep->getHasGLTexture()) - { - mGLTexturep->destroyGLTexture() ; - mTextureState = DELETED ; - } + if(mGLTexturep.notNull() && mGLTexturep->getHasGLTexture()) + { + mGLTexturep->destroyGLTexture() ; + mTextureState = DELETED ; + } } void LLGLTexture::setTexelsPerImage() { - U32 fullwidth = llmin(mFullWidth,U32(MAX_IMAGE_SIZE_DEFAULT)); - U32 fullheight = llmin(mFullHeight,U32(MAX_IMAGE_SIZE_DEFAULT)); - mTexelsPerImage = (U32)fullwidth * fullheight; + U32 fullwidth = llmin(mFullWidth,U32(MAX_IMAGE_SIZE_DEFAULT)); + U32 fullheight = llmin(mFullHeight,U32(MAX_IMAGE_SIZE_DEFAULT)); + mTexelsPerImage = (U32)fullwidth * fullheight; } static LLUUID sStubUUID; diff --git a/indra/llrender/llgltexture.h b/indra/llrender/llgltexture.h index 24849d1d1b..88057d7920 100644 --- a/indra/llrender/llgltexture.h +++ b/indra/llrender/llgltexture.h @@ -1,25 +1,25 @@ -/** +/** * @file llgltexture.h * @brief Object for managing opengl textures * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -40,86 +40,86 @@ class LLImageRaw; class LLGLTexture : public LLTexture { public: - enum - { - MAX_IMAGE_SIZE_DEFAULT = 1024, - INVALID_DISCARD_LEVEL = 0x7fff - }; - - enum EBoostLevel - { - BOOST_NONE = 0, - BOOST_AVATAR , + enum + { + MAX_IMAGE_SIZE_DEFAULT = 1024, + INVALID_DISCARD_LEVEL = 0x7fff + }; + + enum EBoostLevel + { + BOOST_NONE = 0, + BOOST_AVATAR , BOOST_AVATAR_BAKED , - BOOST_SCULPTED , - - BOOST_HIGH = 10, - BOOST_BUMP , - BOOST_TERRAIN , // has to be high priority for minimap / low detail - BOOST_SELECTED , - BOOST_AVATAR_BAKED_SELF , - BOOST_AVATAR_SELF , // needed for baking avatar - BOOST_SUPER_HIGH , //textures higher than this need to be downloaded at the required resolution without delay. - BOOST_HUD , - BOOST_ICON , - BOOST_THUMBNAIL , - BOOST_UI , - BOOST_PREVIEW , - BOOST_MAP , - BOOST_MAP_VISIBLE , - BOOST_MAX_LEVEL, - - //other texture Categories - LOCAL = BOOST_MAX_LEVEL, - AVATAR_SCRATCH_TEX, - DYNAMIC_TEX, - MEDIA, - ATLAS, - OTHER, - MAX_GL_IMAGE_CATEGORY - }; - - typedef enum - { - DELETED = 0, //removed from memory - DELETION_CANDIDATE, //ready to be removed from memory - INACTIVE, //not be used for the last certain period (i.e., 30 seconds). - ACTIVE, //just being used, can become inactive if not being used for a certain time (10 seconds). - NO_DELETE = 99 //stay in memory, can not be removed. - } LLGLTextureState; + BOOST_SCULPTED , + + BOOST_HIGH = 10, + BOOST_BUMP , + BOOST_TERRAIN , // has to be high priority for minimap / low detail + BOOST_SELECTED , + BOOST_AVATAR_BAKED_SELF , + BOOST_AVATAR_SELF , // needed for baking avatar + BOOST_SUPER_HIGH , //textures higher than this need to be downloaded at the required resolution without delay. + BOOST_HUD , + BOOST_ICON , + BOOST_THUMBNAIL , + BOOST_UI , + BOOST_PREVIEW , + BOOST_MAP , + BOOST_MAP_VISIBLE , + BOOST_MAX_LEVEL, + + //other texture Categories + LOCAL = BOOST_MAX_LEVEL, + AVATAR_SCRATCH_TEX, + DYNAMIC_TEX, + MEDIA, + ATLAS, + OTHER, + MAX_GL_IMAGE_CATEGORY + }; + + typedef enum + { + DELETED = 0, //removed from memory + DELETION_CANDIDATE, //ready to be removed from memory + INACTIVE, //not be used for the last certain period (i.e., 30 seconds). + ACTIVE, //just being used, can become inactive if not being used for a certain time (10 seconds). + NO_DELETE = 99 //stay in memory, can not be removed. + } LLGLTextureState; protected: - virtual ~LLGLTexture(); - LOG_CLASS(LLGLTexture); + virtual ~LLGLTexture(); + LOG_CLASS(LLGLTexture); public: - LLGLTexture(BOOL usemipmaps = TRUE); - LLGLTexture(const LLImageRaw* raw, BOOL usemipmaps) ; - LLGLTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps) ; + LLGLTexture(BOOL usemipmaps = TRUE); + LLGLTexture(const LLImageRaw* raw, BOOL usemipmaps) ; + LLGLTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps) ; + + virtual void dump(); // debug info to LL_INFOS() - virtual void dump(); // debug info to LL_INFOS() + virtual const LLUUID& getID() const; - virtual const LLUUID& getID() const; + void setBoostLevel(S32 level); + S32 getBoostLevel() { return mBoostLevel; } - void setBoostLevel(S32 level); - S32 getBoostLevel() { return mBoostLevel; } + S32 getFullWidth() const { return mFullWidth; } + S32 getFullHeight() const { return mFullHeight; } - S32 getFullWidth() const { return mFullWidth; } - S32 getFullHeight() const { return mFullHeight; } + void generateGLTexture() ; + void destroyGLTexture() ; - void generateGLTexture() ; - void destroyGLTexture() ; + //--------------------------------------------------------------------------------------------- + //functions to access LLImageGL + //--------------------------------------------------------------------------------------------- + /*virtual*/S32 getWidth(S32 discard_level = -1) const; + /*virtual*/S32 getHeight(S32 discard_level = -1) const; - //--------------------------------------------------------------------------------------------- - //functions to access LLImageGL - //--------------------------------------------------------------------------------------------- - /*virtual*/S32 getWidth(S32 discard_level = -1) const; - /*virtual*/S32 getHeight(S32 discard_level = -1) const; + BOOL hasGLTexture() const ; + LLGLuint getTexName() const ; + BOOL createGLTexture() ; - BOOL hasGLTexture() const ; - LLGLuint getTexName() const ; - BOOL createGLTexture() ; - // Create a GL Texture from an image raw // discard_level - mip level, 0 for highest resultion mip // imageraw - the image to copy from @@ -130,74 +130,74 @@ public: // tex_name - if not null, will be set to the GL name of the texture created BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE, S32 category = LLGLTexture::OTHER, bool defer_copy = false, LLGLuint* tex_name = nullptr); - void setFilteringOption(LLTexUnit::eTextureFilterOptions option); - void setExplicitFormat(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format = 0, BOOL swap_bytes = FALSE); - void setAddressMode(LLTexUnit::eTextureAddressMode mode); - BOOL setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, 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, LLGLuint use_name = 0); - void setGLTextureCreated (bool initialized); - void setCategory(S32 category) ; + void setFilteringOption(LLTexUnit::eTextureFilterOptions option); + void setExplicitFormat(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format = 0, BOOL swap_bytes = FALSE); + void setAddressMode(LLTexUnit::eTextureAddressMode mode); + BOOL setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, 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, LLGLuint use_name = 0); + void setGLTextureCreated (bool initialized); + void setCategory(S32 category) ; void setTexName(LLGLuint); // for forcing w/ externally created textures only void setTarget(const LLGLenum target, const LLTexUnit::eTextureType bind_target); - LLTexUnit::eTextureAddressMode getAddressMode(void) const ; - S32 getMaxDiscardLevel() const; - S32 getDiscardLevel() const; - S8 getComponents() const; - BOOL getBoundRecently() const; - S32Bytes getTextureMemory() const ; - LLGLenum getPrimaryFormat() const; - BOOL getIsAlphaMask() const ; - LLTexUnit::eTextureType getTarget(void) const ; - BOOL getMask(const LLVector2 &tc); - F32 getTimePassedSinceLastBound(); - BOOL getMissed() const ; - BOOL isJustBound()const ; - void forceUpdateBindStats(void) const; - - U32 getTexelsInAtlas() const ; - U32 getTexelsInGLTexture() const ; - BOOL isGLTextureCreated() const ; - S32 getDiscardLevelInAtlas() const ; - LLGLTextureState getTextureState() const { return mTextureState; } - - //--------------------------------------------------------------------------------------------- - //end of functions to access LLImageGL - //--------------------------------------------------------------------------------------------- - - //----------------- - /*virtual*/ void setActive() ; - void forceActive() ; - void setNoDelete() ; - void dontDiscard() { mDontDiscard = 1; mTextureState = NO_DELETE; } - BOOL getDontDiscard() const { return mDontDiscard; } - //----------------- + LLTexUnit::eTextureAddressMode getAddressMode(void) const ; + S32 getMaxDiscardLevel() const; + S32 getDiscardLevel() const; + S8 getComponents() const; + BOOL getBoundRecently() const; + S32Bytes getTextureMemory() const ; + LLGLenum getPrimaryFormat() const; + BOOL getIsAlphaMask() const ; + LLTexUnit::eTextureType getTarget(void) const ; + BOOL getMask(const LLVector2 &tc); + F32 getTimePassedSinceLastBound(); + BOOL getMissed() const ; + BOOL isJustBound()const ; + void forceUpdateBindStats(void) const; + + U32 getTexelsInAtlas() const ; + U32 getTexelsInGLTexture() const ; + BOOL isGLTextureCreated() const ; + S32 getDiscardLevelInAtlas() const ; + LLGLTextureState getTextureState() const { return mTextureState; } + + //--------------------------------------------------------------------------------------------- + //end of functions to access LLImageGL + //--------------------------------------------------------------------------------------------- + + //----------------- + /*virtual*/ void setActive() ; + void forceActive() ; + void setNoDelete() ; + void dontDiscard() { mDontDiscard = 1; mTextureState = NO_DELETE; } + BOOL getDontDiscard() const { return mDontDiscard; } + //----------------- private: - void cleanup(); - void init(); + void cleanup(); + void init(); protected: - void setTexelsPerImage(); + void setTexelsPerImage(); public: - /*virtual*/ LLImageGL* getGLTexture() const ; + /*virtual*/ LLImageGL* getGLTexture() const ; protected: - S32 mBoostLevel; // enum describing priority level - U32 mFullWidth; - U32 mFullHeight; - BOOL mUseMipMaps; - S8 mComponents; - U32 mTexelsPerImage; // Texels per image. - mutable S8 mNeedsGLTexture; - - //GL texture - LLPointer<LLImageGL> mGLTexturep ; - S8 mDontDiscard; // Keep full res version of this image (for UI, etc) + S32 mBoostLevel; // enum describing priority level + U32 mFullWidth; + U32 mFullHeight; + BOOL mUseMipMaps; + S8 mComponents; + U32 mTexelsPerImage; // Texels per image. + mutable S8 mNeedsGLTexture; + + //GL texture + LLPointer<LLImageGL> mGLTexturep ; + S8 mDontDiscard; // Keep full res version of this image (for UI, etc) protected: - LLGLTextureState mTextureState ; + LLGLTextureState mTextureState ; }; 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.cpp b/indra/llrender/llrender.cpp index 4d64dc9e10..1073db3bfd 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -1,25 +1,25 @@ - /** + /** * @file llrender.cpp * @brief LLRender 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$ */ @@ -51,8 +51,8 @@ extern void APIENTRY gl_debug_callback(GLenum source, thread_local LLRender gGL; // Handy copies of last good GL matrices -F32 gGLModelView[16]; -F32 gGLLastModelView[16]; +F32 gGLModelView[16]; +F32 gGLLastModelView[16]; F32 gGLLastProjection[16]; F32 gGLProjection[16]; @@ -60,7 +60,7 @@ F32 gGLProjection[16]; F32 gGLDeltaModelView[16]; F32 gGLInverseDeltaModelView[16]; -S32 gGLViewport[4]; +S32 gGLViewport[4]; U32 LLRender::sUICalls = 0; @@ -80,113 +80,113 @@ static std::unordered_map<U64, LLVBCache> sVBCache; static const GLenum sGLTextureType[] = { - GL_TEXTURE_2D, - GL_TEXTURE_RECTANGLE, - GL_TEXTURE_CUBE_MAP, + GL_TEXTURE_2D, + GL_TEXTURE_RECTANGLE, + GL_TEXTURE_CUBE_MAP, GL_TEXTURE_CUBE_MAP_ARRAY, - GL_TEXTURE_2D_MULTISAMPLE, + GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_3D }; static const GLint sGLAddressMode[] = -{ - GL_REPEAT, - GL_MIRRORED_REPEAT, - GL_CLAMP_TO_EDGE +{ + GL_REPEAT, + GL_MIRRORED_REPEAT, + GL_CLAMP_TO_EDGE }; const U32 immediate_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXCOORD0; static const GLenum sGLBlendFactor[] = { - GL_ONE, - GL_ZERO, - GL_DST_COLOR, - GL_SRC_COLOR, - GL_ONE_MINUS_DST_COLOR, - GL_ONE_MINUS_SRC_COLOR, - GL_DST_ALPHA, - GL_SRC_ALPHA, - GL_ONE_MINUS_DST_ALPHA, - GL_ONE_MINUS_SRC_ALPHA, - - GL_ZERO // 'BF_UNDEF' + GL_ONE, + GL_ZERO, + GL_DST_COLOR, + GL_SRC_COLOR, + GL_ONE_MINUS_DST_COLOR, + GL_ONE_MINUS_SRC_COLOR, + GL_DST_ALPHA, + GL_SRC_ALPHA, + GL_ONE_MINUS_DST_ALPHA, + GL_ONE_MINUS_SRC_ALPHA, + + GL_ZERO // 'BF_UNDEF' }; LLTexUnit::LLTexUnit(S32 index) - : mCurrTexType(TT_NONE), + : mCurrTexType(TT_NONE), mCurrColorScale(1), mCurrAlphaScale(1), mCurrTexture(0), mTexColorSpace(TCS_LINEAR), - mHasMipMaps(false), - mIndex(index) + mHasMipMaps(false), + mIndex(index) { - llassert_always(index < (S32)LL_NUM_TEXTURE_LAYERS); + llassert_always(index < (S32)LL_NUM_TEXTURE_LAYERS); } //static U32 LLTexUnit::getInternalType(eTextureType type) { - return sGLTextureType[type]; + return sGLTextureType[type]; } void LLTexUnit::refreshState(void) { - // We set dirty to true so that the tex unit knows to ignore caching - // and we reset the cached tex unit state + // We set dirty to true so that the tex unit knows to ignore caching + // and we reset the cached tex unit state - gGL.flush(); - - glActiveTexture(GL_TEXTURE0 + mIndex); + gGL.flush(); - if (mCurrTexType != TT_NONE) - { - glBindTexture(sGLTextureType[mCurrTexType], mCurrTexture); - } - else - { - glBindTexture(GL_TEXTURE_2D, 0); - } + glActiveTexture(GL_TEXTURE0 + mIndex); + + if (mCurrTexType != TT_NONE) + { + glBindTexture(sGLTextureType[mCurrTexType], mCurrTexture); + } + else + { + glBindTexture(GL_TEXTURE_2D, 0); + } setTextureColorSpace(mTexColorSpace); } void LLTexUnit::activate(void) { - if (mIndex < 0) return; + if (mIndex < 0) return; - if ((S32)gGL.mCurrTextureUnitIndex != mIndex || gGL.mDirty) - { - gGL.flush(); - glActiveTexture(GL_TEXTURE0 + mIndex); - gGL.mCurrTextureUnitIndex = mIndex; - } + if ((S32)gGL.mCurrTextureUnitIndex != mIndex || gGL.mDirty) + { + gGL.flush(); + glActiveTexture(GL_TEXTURE0 + mIndex); + gGL.mCurrTextureUnitIndex = mIndex; + } } void LLTexUnit::enable(eTextureType type) { - if (mIndex < 0) return; + if (mIndex < 0) return; - if ( (mCurrTexType != type || gGL.mDirty) && (type != TT_NONE) ) - { - activate(); - if (mCurrTexType != TT_NONE && !gGL.mDirty) - { - disable(); // Force a disable of a previous texture type if it's enabled. - } - mCurrTexType = type; + if ( (mCurrTexType != type || gGL.mDirty) && (type != TT_NONE) ) + { + activate(); + if (mCurrTexType != TT_NONE && !gGL.mDirty) + { + disable(); // Force a disable of a previous texture type if it's enabled. + } + mCurrTexType = type; - gGL.flush(); - } + gGL.flush(); + } } void LLTexUnit::disable(void) { - if (mIndex < 0) return; + if (mIndex < 0) return; - if (mCurrTexType != TT_NONE) - { - unbind(mCurrTexType); - mCurrTexType = TT_NONE; - } + if (mCurrTexType != TT_NONE) + { + unbind(mCurrTexType); + mCurrTexType = TT_NONE; + } } void LLTexUnit::bindFast(LLTexture* texture) @@ -211,231 +211,231 @@ void LLTexUnit::bindFast(LLTexture* texture) bool LLTexUnit::bind(LLTexture* texture, bool for_rendering, bool forceBind) { LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; - stop_glerror(); - if (mIndex >= 0) - { - gGL.flush(); - - LLImageGL* gl_tex = NULL ; - - if (texture != NULL && (gl_tex = texture->getGLTexture())) - { - if (gl_tex->getTexName()) //if texture exists - { - //in audit, replace the selected texture by the default one. - if ((mCurrTexture != gl_tex->getTexName()) || forceBind) - { - activate(); - enable(gl_tex->getTarget()); - mCurrTexture = gl_tex->getTexName(); - glBindTexture(sGLTextureType[gl_tex->getTarget()], mCurrTexture); - if(gl_tex->updateBindStats()) - { - texture->setActive() ; - texture->updateBindStatsForTester() ; - } - mHasMipMaps = gl_tex->mHasMipMaps; - if (gl_tex->mTexOptionsDirty) - { - gl_tex->mTexOptionsDirty = false; - setTextureAddressMode(gl_tex->mAddressMode); - setTextureFilteringOption(gl_tex->mFilterOption); + stop_glerror(); + if (mIndex >= 0) + { + gGL.flush(); + + LLImageGL* gl_tex = NULL ; + + if (texture != NULL && (gl_tex = texture->getGLTexture())) + { + if (gl_tex->getTexName()) //if texture exists + { + //in audit, replace the selected texture by the default one. + if ((mCurrTexture != gl_tex->getTexName()) || forceBind) + { + activate(); + enable(gl_tex->getTarget()); + mCurrTexture = gl_tex->getTexName(); + glBindTexture(sGLTextureType[gl_tex->getTarget()], mCurrTexture); + if(gl_tex->updateBindStats()) + { + texture->setActive() ; + texture->updateBindStatsForTester() ; + } + mHasMipMaps = gl_tex->mHasMipMaps; + if (gl_tex->mTexOptionsDirty) + { + gl_tex->mTexOptionsDirty = false; + setTextureAddressMode(gl_tex->mAddressMode); + setTextureFilteringOption(gl_tex->mFilterOption); } setTextureColorSpace(mTexColorSpace); - } - } - else - { - //if deleted, will re-generate it immediately - texture->forceImmediateUpdate() ; - - gl_tex->forceUpdateBindStats() ; - return texture->bindDefaultImage(mIndex); - } - } - else - { - if (texture) - { - LL_DEBUGS() << "NULL LLTexUnit::bind GL image" << LL_ENDL; - } - else - { - LL_DEBUGS() << "NULL LLTexUnit::bind texture" << LL_ENDL; - } - return false; - } - } - else - { // mIndex < 0 - return false; - } - - return true; + } + } + else + { + //if deleted, will re-generate it immediately + texture->forceImmediateUpdate() ; + + gl_tex->forceUpdateBindStats() ; + return texture->bindDefaultImage(mIndex); + } + } + else + { + if (texture) + { + LL_DEBUGS() << "NULL LLTexUnit::bind GL image" << LL_ENDL; + } + else + { + LL_DEBUGS() << "NULL LLTexUnit::bind texture" << LL_ENDL; + } + return false; + } + } + else + { // mIndex < 0 + return false; + } + + return true; } bool LLTexUnit::bind(LLImageGL* texture, bool for_rendering, bool forceBind, S32 usename) { - stop_glerror(); - if (mIndex < 0) return false; + stop_glerror(); + if (mIndex < 0) return false; U32 texname = usename ? usename : texture->getTexName(); - if(!texture) - { - LL_DEBUGS() << "NULL LLTexUnit::bind texture" << LL_ENDL; - return false; - } - - if(!texname) - { - if(LLImageGL::sDefaultGLTexture && LLImageGL::sDefaultGLTexture->getTexName()) - { - return bind(LLImageGL::sDefaultGLTexture) ; - } - stop_glerror(); - return false ; - } - - if ((mCurrTexture != texname) || forceBind) - { - gGL.flush(); - stop_glerror(); - activate(); - stop_glerror(); - enable(texture->getTarget()); - stop_glerror(); - mCurrTexture = texname; - glBindTexture(sGLTextureType[texture->getTarget()], mCurrTexture); - stop_glerror(); + if(!texture) + { + LL_DEBUGS() << "NULL LLTexUnit::bind texture" << LL_ENDL; + return false; + } + + if(!texname) + { + if(LLImageGL::sDefaultGLTexture && LLImageGL::sDefaultGLTexture->getTexName()) + { + return bind(LLImageGL::sDefaultGLTexture) ; + } + stop_glerror(); + return false ; + } + + if ((mCurrTexture != texname) || forceBind) + { + gGL.flush(); + stop_glerror(); + activate(); + stop_glerror(); + enable(texture->getTarget()); + stop_glerror(); + mCurrTexture = texname; + glBindTexture(sGLTextureType[texture->getTarget()], mCurrTexture); + stop_glerror(); texture->updateBindStats(); - mHasMipMaps = texture->mHasMipMaps; - if (texture->mTexOptionsDirty) - { - stop_glerror(); - texture->mTexOptionsDirty = false; - setTextureAddressMode(texture->mAddressMode); - setTextureFilteringOption(texture->mFilterOption); - stop_glerror(); - } + mHasMipMaps = texture->mHasMipMaps; + if (texture->mTexOptionsDirty) + { + stop_glerror(); + texture->mTexOptionsDirty = false; + setTextureAddressMode(texture->mAddressMode); + setTextureFilteringOption(texture->mFilterOption); + stop_glerror(); + } setTextureColorSpace(mTexColorSpace); - } + } - stop_glerror(); + stop_glerror(); - return true; + return true; } bool LLTexUnit::bind(LLCubeMap* cubeMap) { - if (mIndex < 0) return false; + if (mIndex < 0) return false; - gGL.flush(); + gGL.flush(); - if (cubeMap == NULL) - { - LL_WARNS() << "NULL LLTexUnit::bind cubemap" << LL_ENDL; - return false; - } + if (cubeMap == NULL) + { + LL_WARNS() << "NULL LLTexUnit::bind cubemap" << LL_ENDL; + return false; + } - if (mCurrTexture != cubeMap->mImages[0]->getTexName()) - { - if (LLCubeMap::sUseCubeMaps) - { - activate(); - enable(LLTexUnit::TT_CUBE_MAP); + if (mCurrTexture != cubeMap->mImages[0]->getTexName()) + { + if (LLCubeMap::sUseCubeMaps) + { + activate(); + enable(LLTexUnit::TT_CUBE_MAP); mCurrTexture = cubeMap->mImages[0]->getTexName(); - glBindTexture(GL_TEXTURE_CUBE_MAP, mCurrTexture); - mHasMipMaps = cubeMap->mImages[0]->mHasMipMaps; - cubeMap->mImages[0]->updateBindStats(); - if (cubeMap->mImages[0]->mTexOptionsDirty) - { - cubeMap->mImages[0]->mTexOptionsDirty = false; - setTextureAddressMode(cubeMap->mImages[0]->mAddressMode); - setTextureFilteringOption(cubeMap->mImages[0]->mFilterOption); + glBindTexture(GL_TEXTURE_CUBE_MAP, mCurrTexture); + mHasMipMaps = cubeMap->mImages[0]->mHasMipMaps; + cubeMap->mImages[0]->updateBindStats(); + if (cubeMap->mImages[0]->mTexOptionsDirty) + { + cubeMap->mImages[0]->mTexOptionsDirty = false; + setTextureAddressMode(cubeMap->mImages[0]->mAddressMode); + setTextureFilteringOption(cubeMap->mImages[0]->mFilterOption); } setTextureColorSpace(mTexColorSpace); - return true; - } - else - { - LL_WARNS() << "Using cube map without extension!" << LL_ENDL; - return false; - } - } - return true; + return true; + } + else + { + LL_WARNS() << "Using cube map without extension!" << LL_ENDL; + return false; + } + } + return true; } // LLRenderTarget is unavailible on the mapserver since it uses FBOs. bool LLTexUnit::bind(LLRenderTarget* renderTarget, bool bindDepth) { - if (mIndex < 0) return false; + if (mIndex < 0) return false; - gGL.flush(); + gGL.flush(); - if (bindDepth) - { + if (bindDepth) + { llassert(renderTarget->getDepth()); // target MUST have a depth buffer attachment - bindManual(renderTarget->getUsage(), renderTarget->getDepth()); - } - else - { - bindManual(renderTarget->getUsage(), renderTarget->getTexture()); - } + bindManual(renderTarget->getUsage(), renderTarget->getDepth()); + } + else + { + bindManual(renderTarget->getUsage(), renderTarget->getTexture()); + } - return true; + return true; } bool LLTexUnit::bindManual(eTextureType type, U32 texture, bool hasMips) { - if (mIndex < 0) - { - return false; - } - - if(mCurrTexture != texture) - { - gGL.flush(); - - activate(); - enable(type); - mCurrTexture = texture; - glBindTexture(sGLTextureType[type], texture); + if (mIndex < 0) + { + return false; + } + + if(mCurrTexture != texture) + { + gGL.flush(); + + activate(); + enable(type); + mCurrTexture = texture; + glBindTexture(sGLTextureType[type], texture); mHasMipMaps = hasMips; setTextureColorSpace(mTexColorSpace); - } - return true; + } + return true; } void LLTexUnit::unbind(eTextureType type) { - stop_glerror(); + stop_glerror(); - if (mIndex < 0) return; + if (mIndex < 0) return; - //always flush and activate for consistency - // some code paths assume unbind always flushes and sets the active texture - gGL.flush(); - activate(); + //always flush and activate for consistency + // some code paths assume unbind always flushes and sets the active texture + gGL.flush(); + activate(); - // Disabled caching of binding state. - if (mCurrTexType == type) - { - mCurrTexture = 0; + // Disabled caching of binding state. + if (mCurrTexType == type) + { + mCurrTexture = 0; // Always make sure our texture color space is reset to linear. SRGB sampling should be opt-in in the vast majority of cases. Also prevents color space "popping". mTexColorSpace = TCS_LINEAR; - if (type == LLTexUnit::TT_TEXTURE) - { - glBindTexture(sGLTextureType[type], sWhiteTexture); - } - else - { - glBindTexture(sGLTextureType[type], 0); - } - stop_glerror(); - } + if (type == LLTexUnit::TT_TEXTURE) + { + glBindTexture(sGLTextureType[type], sWhiteTexture); + } + else + { + glBindTexture(sGLTextureType[type], 0); + } + stop_glerror(); + } } void LLTexUnit::unbindFast(eTextureType type) @@ -462,184 +462,184 @@ void LLTexUnit::unbindFast(eTextureType type) void LLTexUnit::setTextureAddressMode(eTextureAddressMode mode) { - if (mIndex < 0 || mCurrTexture == 0) return; + if (mIndex < 0 || mCurrTexture == 0) return; - gGL.flush(); + gGL.flush(); - activate(); + activate(); - glTexParameteri (sGLTextureType[mCurrTexType], GL_TEXTURE_WRAP_S, sGLAddressMode[mode]); - glTexParameteri (sGLTextureType[mCurrTexType], GL_TEXTURE_WRAP_T, sGLAddressMode[mode]); - if (mCurrTexType == TT_CUBE_MAP) - { - glTexParameteri (GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, sGLAddressMode[mode]); - } + glTexParameteri (sGLTextureType[mCurrTexType], GL_TEXTURE_WRAP_S, sGLAddressMode[mode]); + glTexParameteri (sGLTextureType[mCurrTexType], GL_TEXTURE_WRAP_T, sGLAddressMode[mode]); + if (mCurrTexType == TT_CUBE_MAP) + { + glTexParameteri (GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, sGLAddressMode[mode]); + } } void LLTexUnit::setTextureFilteringOption(LLTexUnit::eTextureFilterOptions option) { - if (mIndex < 0 || mCurrTexture == 0 || mCurrTexType == LLTexUnit::TT_MULTISAMPLE_TEXTURE) return; - - gGL.flush(); - - if (option == TFO_POINT) - { - glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MAG_FILTER, GL_NEAREST); - } - else - { - glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MAG_FILTER, GL_LINEAR); - } - - if (option >= TFO_TRILINEAR && mHasMipMaps) - { - glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - } - else if (option >= TFO_BILINEAR) - { - if (mHasMipMaps) - { - glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); - } - else - { - glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } - } - else - { - if (mHasMipMaps) - { - glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); - } - else - { - glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_NEAREST); - } - } - - if (gGLManager.mGLVersion >= 4.59f) - { - if (LLImageGL::sGlobalUseAnisotropic && option == TFO_ANISOTROPIC) - { - glTexParameterf(sGLTextureType[mCurrTexType], GL_TEXTURE_MAX_ANISOTROPY, gGLManager.mMaxAnisotropy); - } - else - { - glTexParameterf(sGLTextureType[mCurrTexType], GL_TEXTURE_MAX_ANISOTROPY, 1.f); - } - } + if (mIndex < 0 || mCurrTexture == 0 || mCurrTexType == LLTexUnit::TT_MULTISAMPLE_TEXTURE) return; + + gGL.flush(); + + if (option == TFO_POINT) + { + glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + else + { + glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + + if (option >= TFO_TRILINEAR && mHasMipMaps) + { + glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + } + else if (option >= TFO_BILINEAR) + { + if (mHasMipMaps) + { + glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); + } + else + { + glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } + } + else + { + if (mHasMipMaps) + { + glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); + } + else + { + glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } + } + + if (gGLManager.mGLVersion >= 4.59f) + { + if (LLImageGL::sGlobalUseAnisotropic && option == TFO_ANISOTROPIC) + { + glTexParameterf(sGLTextureType[mCurrTexType], GL_TEXTURE_MAX_ANISOTROPY, gGLManager.mMaxAnisotropy); + } + else + { + glTexParameterf(sGLTextureType[mCurrTexType], GL_TEXTURE_MAX_ANISOTROPY, 1.f); + } + } } GLint LLTexUnit::getTextureSource(eTextureBlendSrc src) { - switch(src) - { - // All four cases should return the same value. - case TBS_PREV_COLOR: - case TBS_PREV_ALPHA: - case TBS_ONE_MINUS_PREV_COLOR: - case TBS_ONE_MINUS_PREV_ALPHA: - return GL_PREVIOUS; - - // All four cases should return the same value. - case TBS_TEX_COLOR: - case TBS_TEX_ALPHA: - case TBS_ONE_MINUS_TEX_COLOR: - case TBS_ONE_MINUS_TEX_ALPHA: - return GL_TEXTURE; - - // All four cases should return the same value. - case TBS_VERT_COLOR: - case TBS_VERT_ALPHA: - case TBS_ONE_MINUS_VERT_COLOR: - case TBS_ONE_MINUS_VERT_ALPHA: - return GL_PRIMARY_COLOR; - - // All four cases should return the same value. - case TBS_CONST_COLOR: - case TBS_CONST_ALPHA: - case TBS_ONE_MINUS_CONST_COLOR: - case TBS_ONE_MINUS_CONST_ALPHA: - return GL_CONSTANT; - - default: - LL_WARNS() << "Unknown eTextureBlendSrc: " << src << ". Using Vertex Color instead." << LL_ENDL; - return GL_PRIMARY_COLOR; - } + switch(src) + { + // All four cases should return the same value. + case TBS_PREV_COLOR: + case TBS_PREV_ALPHA: + case TBS_ONE_MINUS_PREV_COLOR: + case TBS_ONE_MINUS_PREV_ALPHA: + return GL_PREVIOUS; + + // All four cases should return the same value. + case TBS_TEX_COLOR: + case TBS_TEX_ALPHA: + case TBS_ONE_MINUS_TEX_COLOR: + case TBS_ONE_MINUS_TEX_ALPHA: + return GL_TEXTURE; + + // All four cases should return the same value. + case TBS_VERT_COLOR: + case TBS_VERT_ALPHA: + case TBS_ONE_MINUS_VERT_COLOR: + case TBS_ONE_MINUS_VERT_ALPHA: + return GL_PRIMARY_COLOR; + + // All four cases should return the same value. + case TBS_CONST_COLOR: + case TBS_CONST_ALPHA: + case TBS_ONE_MINUS_CONST_COLOR: + case TBS_ONE_MINUS_CONST_ALPHA: + return GL_CONSTANT; + + default: + LL_WARNS() << "Unknown eTextureBlendSrc: " << src << ". Using Vertex Color instead." << LL_ENDL; + return GL_PRIMARY_COLOR; + } } GLint LLTexUnit::getTextureSourceType(eTextureBlendSrc src, bool isAlpha) { - switch(src) - { - // All four cases should return the same value. - case TBS_PREV_COLOR: - case TBS_TEX_COLOR: - case TBS_VERT_COLOR: - case TBS_CONST_COLOR: - return (isAlpha) ? GL_SRC_ALPHA: GL_SRC_COLOR; - - // All four cases should return the same value. - case TBS_PREV_ALPHA: - case TBS_TEX_ALPHA: - case TBS_VERT_ALPHA: - case TBS_CONST_ALPHA: - return GL_SRC_ALPHA; - - // All four cases should return the same value. - case TBS_ONE_MINUS_PREV_COLOR: - case TBS_ONE_MINUS_TEX_COLOR: - case TBS_ONE_MINUS_VERT_COLOR: - case TBS_ONE_MINUS_CONST_COLOR: - return (isAlpha) ? GL_ONE_MINUS_SRC_ALPHA : GL_ONE_MINUS_SRC_COLOR; - - // All four cases should return the same value. - case TBS_ONE_MINUS_PREV_ALPHA: - case TBS_ONE_MINUS_TEX_ALPHA: - case TBS_ONE_MINUS_VERT_ALPHA: - case TBS_ONE_MINUS_CONST_ALPHA: - return GL_ONE_MINUS_SRC_ALPHA; - - default: - LL_WARNS() << "Unknown eTextureBlendSrc: " << src << ". Using Source Color or Alpha instead." << LL_ENDL; - return (isAlpha) ? GL_SRC_ALPHA: GL_SRC_COLOR; - } + switch(src) + { + // All four cases should return the same value. + case TBS_PREV_COLOR: + case TBS_TEX_COLOR: + case TBS_VERT_COLOR: + case TBS_CONST_COLOR: + return (isAlpha) ? GL_SRC_ALPHA: GL_SRC_COLOR; + + // All four cases should return the same value. + case TBS_PREV_ALPHA: + case TBS_TEX_ALPHA: + case TBS_VERT_ALPHA: + case TBS_CONST_ALPHA: + return GL_SRC_ALPHA; + + // All four cases should return the same value. + case TBS_ONE_MINUS_PREV_COLOR: + case TBS_ONE_MINUS_TEX_COLOR: + case TBS_ONE_MINUS_VERT_COLOR: + case TBS_ONE_MINUS_CONST_COLOR: + return (isAlpha) ? GL_ONE_MINUS_SRC_ALPHA : GL_ONE_MINUS_SRC_COLOR; + + // All four cases should return the same value. + case TBS_ONE_MINUS_PREV_ALPHA: + case TBS_ONE_MINUS_TEX_ALPHA: + case TBS_ONE_MINUS_VERT_ALPHA: + case TBS_ONE_MINUS_CONST_ALPHA: + return GL_ONE_MINUS_SRC_ALPHA; + + default: + LL_WARNS() << "Unknown eTextureBlendSrc: " << src << ". Using Source Color or Alpha instead." << LL_ENDL; + return (isAlpha) ? GL_SRC_ALPHA: GL_SRC_COLOR; + } } void LLTexUnit::setColorScale(S32 scale) { - if (mCurrColorScale != scale || gGL.mDirty) - { - mCurrColorScale = scale; - gGL.flush(); - glTexEnvi( GL_TEXTURE_ENV, GL_RGB_SCALE, scale ); - } + if (mCurrColorScale != scale || gGL.mDirty) + { + mCurrColorScale = scale; + gGL.flush(); + glTexEnvi( GL_TEXTURE_ENV, GL_RGB_SCALE, scale ); + } } void LLTexUnit::setAlphaScale(S32 scale) { - if (mCurrAlphaScale != scale || gGL.mDirty) - { - mCurrAlphaScale = scale; - gGL.flush(); - glTexEnvi( GL_TEXTURE_ENV, GL_ALPHA_SCALE, scale ); - } + if (mCurrAlphaScale != scale || gGL.mDirty) + { + mCurrAlphaScale = scale; + gGL.flush(); + glTexEnvi( GL_TEXTURE_ENV, GL_ALPHA_SCALE, scale ); + } } -// Useful for debugging that you've manually assigned a texture operation to the correct +// Useful for debugging that you've manually assigned a texture operation to the correct // texture unit based on the currently set active texture in opengl. void LLTexUnit::debugTextureUnit(void) { - if (mIndex < 0) return; + if (mIndex < 0) return; - GLint activeTexture; - glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTexture); - if ((GL_TEXTURE0 + mIndex) != activeTexture) - { - U32 set_unit = (activeTexture - GL_TEXTURE0); - LL_WARNS() << "Incorrect Texture Unit! Expected: " << set_unit << " Actual: " << mIndex << LL_ENDL; - } + GLint activeTexture; + glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTexture); + if ((GL_TEXTURE0 + mIndex) != activeTexture) + { + U32 set_unit = (activeTexture - GL_TEXTURE0); + LL_WARNS() << "Incorrect Texture Unit! Expected: " << set_unit << " Actual: " << mIndex << LL_ENDL; + } } void LLTexUnit::setTextureColorSpace(eTextureColorSpace space) @@ -656,46 +656,46 @@ LLLightState::LLLightState(S32 index) mSpotExponent(0.f), mSpotCutoff(180.f) { - if (mIndex == 0) - { - mDiffuse.set(1,1,1,1); + if (mIndex == 0) + { + mDiffuse.set(1,1,1,1); mDiffuseB.set(0,0,0,0); - mSpecular.set(1,1,1,1); - } + mSpecular.set(1,1,1,1); + } mSunIsPrimary = true; - mAmbient.set(0,0,0,1); - mPosition.set(0,0,1,0); - mSpotDirection.set(0,0,-1); + mAmbient.set(0,0,0,1); + mPosition.set(0,0,1,0); + mSpotDirection.set(0,0,-1); } void LLLightState::enable() { - mEnabled = true; + mEnabled = true; } void LLLightState::disable() { - mEnabled = false; + mEnabled = false; } void LLLightState::setDiffuse(const LLColor4& diffuse) { - if (mDiffuse != diffuse) - { - ++gGL.mLightHash; - mDiffuse = diffuse; - } + if (mDiffuse != diffuse) + { + ++gGL.mLightHash; + mDiffuse = diffuse; + } } void LLLightState::setDiffuseB(const LLColor4& diffuse) { if (mDiffuseB != diffuse) - { - ++gGL.mLightHash; - mDiffuseB = diffuse; - } + { + ++gGL.mLightHash; + mDiffuseB = diffuse; + } } void LLLightState::setSunPrimary(bool v) @@ -703,7 +703,7 @@ void LLLightState::setSunPrimary(bool v) if (mSunIsPrimary != v) { ++gGL.mLightHash; - mSunIsPrimary = v; + mSunIsPrimary = v; } } @@ -727,134 +727,134 @@ void LLLightState::setFalloff(F32 v) void LLLightState::setAmbient(const LLColor4& ambient) { - if (mAmbient != ambient) - { - ++gGL.mLightHash; - mAmbient = ambient; - } + if (mAmbient != ambient) + { + ++gGL.mLightHash; + mAmbient = ambient; + } } void LLLightState::setSpecular(const LLColor4& specular) { - if (mSpecular != specular) - { - ++gGL.mLightHash; - mSpecular = specular; - } + if (mSpecular != specular) + { + ++gGL.mLightHash; + mSpecular = specular; + } } void LLLightState::setPosition(const LLVector4& position) { - //always set position because modelview matrix may have changed - ++gGL.mLightHash; - mPosition = position; - //transform position by current modelview matrix - glh::vec4f pos(position.mV); - const glh::matrix4f& mat = gGL.getModelviewMatrix(); - mat.mult_matrix_vec(pos); - mPosition.set(pos.v); + //always set position because modelview matrix may have changed + ++gGL.mLightHash; + mPosition = position; + //transform position by current modelview matrix + glh::vec4f pos(position.mV); + const glh::matrix4f& mat = gGL.getModelviewMatrix(); + mat.mult_matrix_vec(pos); + mPosition.set(pos.v); } void LLLightState::setConstantAttenuation(const F32& atten) { - if (mConstantAtten != atten) - { - mConstantAtten = atten; - ++gGL.mLightHash; - } + if (mConstantAtten != atten) + { + mConstantAtten = atten; + ++gGL.mLightHash; + } } void LLLightState::setLinearAttenuation(const F32& atten) { - if (mLinearAtten != atten) - { - ++gGL.mLightHash; - mLinearAtten = atten; - } + if (mLinearAtten != atten) + { + ++gGL.mLightHash; + mLinearAtten = atten; + } } void LLLightState::setQuadraticAttenuation(const F32& atten) { - if (mQuadraticAtten != atten) - { - ++gGL.mLightHash; - mQuadraticAtten = atten; - } + if (mQuadraticAtten != atten) + { + ++gGL.mLightHash; + mQuadraticAtten = atten; + } } void LLLightState::setSpotExponent(const F32& exponent) { - if (mSpotExponent != exponent) - { - ++gGL.mLightHash; - mSpotExponent = exponent; - } + if (mSpotExponent != exponent) + { + ++gGL.mLightHash; + mSpotExponent = exponent; + } } void LLLightState::setSpotCutoff(const F32& cutoff) { - if (mSpotCutoff != cutoff) - { - ++gGL.mLightHash; - mSpotCutoff = cutoff; - } + if (mSpotCutoff != cutoff) + { + ++gGL.mLightHash; + mSpotCutoff = cutoff; + } } void LLLightState::setSpotDirection(const LLVector3& direction) { - //always set direction because modelview matrix may have changed - ++gGL.mLightHash; - mSpotDirection = direction; - //transform direction by current modelview matrix - glh::vec3f dir(direction.mV); - const glh::matrix4f& mat = gGL.getModelviewMatrix(); - mat.mult_matrix_dir(dir); + //always set direction because modelview matrix may have changed + ++gGL.mLightHash; + mSpotDirection = direction; + //transform direction by current modelview matrix + glh::vec3f dir(direction.mV); + const glh::matrix4f& mat = gGL.getModelviewMatrix(); + mat.mult_matrix_dir(dir); - mSpotDirection.set(dir.v); + mSpotDirection.set(dir.v); } LLRender::LLRender() : mDirty(false), mCount(0), - mQuadCycle(0), + mQuadCycle(0), mMode(LLRender::TRIANGLES), mCurrTextureUnitIndex(0) -{ - for (U32 i = 0; i < LL_NUM_TEXTURE_LAYERS; i++) - { +{ + for (U32 i = 0; i < LL_NUM_TEXTURE_LAYERS; i++) + { mTexUnits[i].mIndex = i; - } + } - for (U32 i = 0; i < LL_NUM_LIGHT_UNITS; ++i) - { + for (U32 i = 0; i < LL_NUM_LIGHT_UNITS; ++i) + { mLightState[i].mIndex = i; - } + } - for (U32 i = 0; i < 4; i++) - { - mCurrColorMask[i] = true; - } + for (U32 i = 0; i < 4; i++) + { + mCurrColorMask[i] = true; + } - mCurrBlendColorSFactor = BF_UNDEF; - mCurrBlendAlphaSFactor = BF_UNDEF; - mCurrBlendColorDFactor = BF_UNDEF; - mCurrBlendAlphaDFactor = BF_UNDEF; + mCurrBlendColorSFactor = BF_UNDEF; + mCurrBlendAlphaSFactor = BF_UNDEF; + mCurrBlendColorDFactor = BF_UNDEF; + mCurrBlendAlphaDFactor = BF_UNDEF; - mMatrixMode = LLRender::MM_MODELVIEW; - - for (U32 i = 0; i < NUM_MATRIX_MODES; ++i) - { - mMatIdx[i] = 0; - mMatHash[i] = 0; - mCurMatHash[i] = 0xFFFFFFFF; - } + mMatrixMode = LLRender::MM_MODELVIEW; - mLightHash = 0; + for (U32 i = 0; i < NUM_MATRIX_MODES; ++i) + { + mMatIdx[i] = 0; + mMatHash[i] = 0; + mCurMatHash[i] = 0xFFFFFFFF; + } + + mLightHash = 0; } LLRender::~LLRender() { - shutdown(); + shutdown(); } bool LLRender::init(bool needs_vertex_buffer) @@ -923,22 +923,22 @@ void LLRender::shutdown() void LLRender::refreshState(void) { - mDirty = true; + mDirty = true; + + U32 active_unit = mCurrTextureUnitIndex; - U32 active_unit = mCurrTextureUnitIndex; + for (U32 i = 0; i < mTexUnits.size(); i++) + { + mTexUnits[i].refreshState(); + } - for (U32 i = 0; i < mTexUnits.size(); i++) - { - mTexUnits[i].refreshState(); - } - - mTexUnits[active_unit].activate(); + mTexUnits[active_unit].activate(); + + setColorMask(mCurrColorMask[0], mCurrColorMask[1], mCurrColorMask[2], mCurrColorMask[3]); - setColorMask(mCurrColorMask[0], mCurrColorMask[1], mCurrColorMask[2], mCurrColorMask[3]); - flush(); - mDirty = false; + mDirty = false; } void LLRender::syncLightState() @@ -990,36 +990,36 @@ void LLRender::syncLightState() void LLRender::syncMatrices() { - static const U32 name[] = - { - LLShaderMgr::MODELVIEW_MATRIX, - LLShaderMgr::PROJECTION_MATRIX, - LLShaderMgr::TEXTURE_MATRIX0, - LLShaderMgr::TEXTURE_MATRIX1, - LLShaderMgr::TEXTURE_MATRIX2, - LLShaderMgr::TEXTURE_MATRIX3, - }; + static const U32 name[] = + { + LLShaderMgr::MODELVIEW_MATRIX, + LLShaderMgr::PROJECTION_MATRIX, + LLShaderMgr::TEXTURE_MATRIX0, + LLShaderMgr::TEXTURE_MATRIX1, + LLShaderMgr::TEXTURE_MATRIX2, + LLShaderMgr::TEXTURE_MATRIX3, + }; - LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; - static glh::matrix4f cached_mvp; + static glh::matrix4f cached_mvp; static glh::matrix4f cached_inv_mdv; - static U32 cached_mvp_mdv_hash = 0xFFFFFFFF; - static U32 cached_mvp_proj_hash = 0xFFFFFFFF; - - static glh::matrix4f cached_normal; - static U32 cached_normal_hash = 0xFFFFFFFF; + static U32 cached_mvp_mdv_hash = 0xFFFFFFFF; + static U32 cached_mvp_proj_hash = 0xFFFFFFFF; + + static glh::matrix4f cached_normal; + static U32 cached_normal_hash = 0xFFFFFFFF; - if (shader) - { - //llassert(shader); + if (shader) + { + //llassert(shader); - bool mvp_done = false; + bool mvp_done = false; - U32 i = MM_MODELVIEW; - if (mMatHash[MM_MODELVIEW] != shader->mMatHash[MM_MODELVIEW]) - { //update modelview, normal, and MVP - glh::matrix4f& mat = mMatrix[MM_MODELVIEW][mMatIdx[MM_MODELVIEW]]; + U32 i = MM_MODELVIEW; + if (mMatHash[MM_MODELVIEW] != shader->mMatHash[MM_MODELVIEW]) + { //update modelview, normal, and MVP + glh::matrix4f& mat = mMatrix[MM_MODELVIEW][mMatIdx[MM_MODELVIEW]]; // if MDV has changed, update the cached inverse as well if (cached_mvp_mdv_hash != mMatHash[MM_MODELVIEW]) @@ -1027,240 +1027,240 @@ void LLRender::syncMatrices() cached_inv_mdv = mat.inverse(); } - shader->uniformMatrix4fv(name[MM_MODELVIEW], 1, GL_FALSE, mat.m); - shader->mMatHash[MM_MODELVIEW] = mMatHash[MM_MODELVIEW]; + shader->uniformMatrix4fv(name[MM_MODELVIEW], 1, GL_FALSE, mat.m); + shader->mMatHash[MM_MODELVIEW] = mMatHash[MM_MODELVIEW]; - //update normal matrix - S32 loc = shader->getUniformLocation(LLShaderMgr::NORMAL_MATRIX); - if (loc > -1) - { - if (cached_normal_hash != mMatHash[i]) - { - cached_normal = cached_inv_mdv.transpose(); - cached_normal_hash = mMatHash[i]; - } + //update normal matrix + S32 loc = shader->getUniformLocation(LLShaderMgr::NORMAL_MATRIX); + if (loc > -1) + { + if (cached_normal_hash != mMatHash[i]) + { + cached_normal = cached_inv_mdv.transpose(); + cached_normal_hash = mMatHash[i]; + } - glh::matrix4f& norm = cached_normal; + glh::matrix4f& norm = cached_normal; - F32 norm_mat[] = - { - norm.m[0], norm.m[1], norm.m[2], - norm.m[4], norm.m[5], norm.m[6], - norm.m[8], norm.m[9], norm.m[10] - }; + F32 norm_mat[] = + { + norm.m[0], norm.m[1], norm.m[2], + norm.m[4], norm.m[5], norm.m[6], + norm.m[8], norm.m[9], norm.m[10] + }; - shader->uniformMatrix3fv(LLShaderMgr::NORMAL_MATRIX, 1, GL_FALSE, norm_mat); - } + shader->uniformMatrix3fv(LLShaderMgr::NORMAL_MATRIX, 1, GL_FALSE, norm_mat); + } if (shader->getUniformLocation(LLShaderMgr::INVERSE_MODELVIEW_MATRIX)) - { - shader->uniformMatrix4fv(LLShaderMgr::INVERSE_MODELVIEW_MATRIX, 1, GL_FALSE, cached_inv_mdv.m); + { + shader->uniformMatrix4fv(LLShaderMgr::INVERSE_MODELVIEW_MATRIX, 1, GL_FALSE, cached_inv_mdv.m); } - //update MVP matrix - mvp_done = true; - loc = shader->getUniformLocation(LLShaderMgr::MODELVIEW_PROJECTION_MATRIX); - if (loc > -1) - { - U32 proj = MM_PROJECTION; - - if (cached_mvp_mdv_hash != mMatHash[i] || cached_mvp_proj_hash != mMatHash[MM_PROJECTION]) - { - cached_mvp = mat; - cached_mvp.mult_left(mMatrix[proj][mMatIdx[proj]]); - cached_mvp_mdv_hash = mMatHash[i]; - cached_mvp_proj_hash = mMatHash[MM_PROJECTION]; - } - - shader->uniformMatrix4fv(LLShaderMgr::MODELVIEW_PROJECTION_MATRIX, 1, GL_FALSE, cached_mvp.m); - } - } - - i = MM_PROJECTION; - if (mMatHash[MM_PROJECTION] != shader->mMatHash[MM_PROJECTION]) - { //update projection matrix, normal, and MVP - glh::matrix4f& mat = mMatrix[MM_PROJECTION][mMatIdx[MM_PROJECTION]]; + //update MVP matrix + mvp_done = true; + loc = shader->getUniformLocation(LLShaderMgr::MODELVIEW_PROJECTION_MATRIX); + if (loc > -1) + { + U32 proj = MM_PROJECTION; + + if (cached_mvp_mdv_hash != mMatHash[i] || cached_mvp_proj_hash != mMatHash[MM_PROJECTION]) + { + cached_mvp = mat; + cached_mvp.mult_left(mMatrix[proj][mMatIdx[proj]]); + cached_mvp_mdv_hash = mMatHash[i]; + cached_mvp_proj_hash = mMatHash[MM_PROJECTION]; + } + + shader->uniformMatrix4fv(LLShaderMgr::MODELVIEW_PROJECTION_MATRIX, 1, GL_FALSE, cached_mvp.m); + } + } + + i = MM_PROJECTION; + if (mMatHash[MM_PROJECTION] != shader->mMatHash[MM_PROJECTION]) + { //update projection matrix, normal, and MVP + glh::matrix4f& mat = mMatrix[MM_PROJECTION][mMatIdx[MM_PROJECTION]]; // GZ: This was previously disabled seemingly due to a bug involving the deferred renderer's regular pushing and popping of mats. - // We're reenabling this and cleaning up the code around that - that would've been the appropriate course initially. - // Anything beyond the standard proj and inv proj mats are special cases. Please setup special uniforms accordingly in the future. + // We're reenabling this and cleaning up the code around that - that would've been the appropriate course initially. + // Anything beyond the standard proj and inv proj mats are special cases. Please setup special uniforms accordingly in the future. if (shader->getUniformLocation(LLShaderMgr::INVERSE_PROJECTION_MATRIX)) { - glh::matrix4f inv_proj = mat.inverse(); - shader->uniformMatrix4fv(LLShaderMgr::INVERSE_PROJECTION_MATRIX, 1, FALSE, inv_proj.m); + glh::matrix4f inv_proj = mat.inverse(); + shader->uniformMatrix4fv(LLShaderMgr::INVERSE_PROJECTION_MATRIX, 1, FALSE, inv_proj.m); } - // Used by some full screen effects - such as full screen lights, glow, etc. + // Used by some full screen effects - such as full screen lights, glow, etc. if (shader->getUniformLocation(LLShaderMgr::IDENTITY_MATRIX)) { shader->uniformMatrix4fv(LLShaderMgr::IDENTITY_MATRIX, 1, GL_FALSE, glh::matrix4f::identity().m); } - shader->uniformMatrix4fv(name[MM_PROJECTION], 1, GL_FALSE, mat.m); - shader->mMatHash[MM_PROJECTION] = mMatHash[MM_PROJECTION]; - - if (!mvp_done) - { - //update MVP matrix - S32 loc = shader->getUniformLocation(LLShaderMgr::MODELVIEW_PROJECTION_MATRIX); - if (loc > -1) - { - if (cached_mvp_mdv_hash != mMatHash[MM_PROJECTION] || cached_mvp_proj_hash != mMatHash[MM_PROJECTION]) - { - U32 mdv = MM_MODELVIEW; - cached_mvp = mat; - cached_mvp.mult_right(mMatrix[mdv][mMatIdx[mdv]]); - cached_mvp_mdv_hash = mMatHash[MM_MODELVIEW]; - cached_mvp_proj_hash = mMatHash[MM_PROJECTION]; - } - - shader->uniformMatrix4fv(LLShaderMgr::MODELVIEW_PROJECTION_MATRIX, 1, GL_FALSE, cached_mvp.m); - } - } - } - - for (i = MM_TEXTURE0; i < NUM_MATRIX_MODES; ++i) - { - if (mMatHash[i] != shader->mMatHash[i]) - { - shader->uniformMatrix4fv(name[i], 1, GL_FALSE, mMatrix[i][mMatIdx[i]].m); - shader->mMatHash[i] = mMatHash[i]; - } - } - - - if (shader->mFeatures.hasLighting || shader->mFeatures.calculatesLighting || shader->mFeatures.calculatesAtmospherics) - { //also sync light state - syncLightState(); - } - } + shader->uniformMatrix4fv(name[MM_PROJECTION], 1, GL_FALSE, mat.m); + shader->mMatHash[MM_PROJECTION] = mMatHash[MM_PROJECTION]; + + if (!mvp_done) + { + //update MVP matrix + S32 loc = shader->getUniformLocation(LLShaderMgr::MODELVIEW_PROJECTION_MATRIX); + if (loc > -1) + { + if (cached_mvp_mdv_hash != mMatHash[MM_PROJECTION] || cached_mvp_proj_hash != mMatHash[MM_PROJECTION]) + { + U32 mdv = MM_MODELVIEW; + cached_mvp = mat; + cached_mvp.mult_right(mMatrix[mdv][mMatIdx[mdv]]); + cached_mvp_mdv_hash = mMatHash[MM_MODELVIEW]; + cached_mvp_proj_hash = mMatHash[MM_PROJECTION]; + } + + shader->uniformMatrix4fv(LLShaderMgr::MODELVIEW_PROJECTION_MATRIX, 1, GL_FALSE, cached_mvp.m); + } + } + } + + for (i = MM_TEXTURE0; i < NUM_MATRIX_MODES; ++i) + { + if (mMatHash[i] != shader->mMatHash[i]) + { + shader->uniformMatrix4fv(name[i], 1, GL_FALSE, mMatrix[i][mMatIdx[i]].m); + shader->mMatHash[i] = mMatHash[i]; + } + } + + + if (shader->mFeatures.hasLighting || shader->mFeatures.calculatesLighting || shader->mFeatures.calculatesAtmospherics) + { //also sync light state + syncLightState(); + } + } } void LLRender::translatef(const GLfloat& x, const GLfloat& y, const GLfloat& z) { - flush(); + flush(); - { - glh::matrix4f trans_mat(1,0,0,x, - 0,1,0,y, - 0,0,1,z, - 0,0,0,1); - - mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mult_right(trans_mat); - mMatHash[mMatrixMode]++; - } + { + glh::matrix4f trans_mat(1,0,0,x, + 0,1,0,y, + 0,0,1,z, + 0,0,0,1); + + mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mult_right(trans_mat); + mMatHash[mMatrixMode]++; + } } void LLRender::scalef(const GLfloat& x, const GLfloat& y, const GLfloat& z) { - flush(); - - { - glh::matrix4f scale_mat(x,0,0,0, - 0,y,0,0, - 0,0,z,0, - 0,0,0,1); - - mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mult_right(scale_mat); - mMatHash[mMatrixMode]++; - } + flush(); + + { + glh::matrix4f scale_mat(x,0,0,0, + 0,y,0,0, + 0,0,z,0, + 0,0,0,1); + + mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mult_right(scale_mat); + mMatHash[mMatrixMode]++; + } } void LLRender::ortho(F32 left, F32 right, F32 bottom, F32 top, F32 zNear, F32 zFar) { - flush(); + flush(); + + { - { + glh::matrix4f ortho_mat(2.f/(right-left),0,0, -(right+left)/(right-left), + 0,2.f/(top-bottom),0, -(top+bottom)/(top-bottom), + 0,0,-2.f/(zFar-zNear), -(zFar+zNear)/(zFar-zNear), + 0,0,0,1); - glh::matrix4f ortho_mat(2.f/(right-left),0,0, -(right+left)/(right-left), - 0,2.f/(top-bottom),0, -(top+bottom)/(top-bottom), - 0,0,-2.f/(zFar-zNear), -(zFar+zNear)/(zFar-zNear), - 0,0,0,1); - - mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mult_right(ortho_mat); - mMatHash[mMatrixMode]++; - } + mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mult_right(ortho_mat); + mMatHash[mMatrixMode]++; + } } void LLRender::rotatef(const GLfloat& a, const GLfloat& x, const GLfloat& y, const GLfloat& z) { - flush(); + flush(); + + { + F32 r = a * DEG_TO_RAD; - { - F32 r = a * DEG_TO_RAD; + F32 c = cosf(r); + F32 s = sinf(r); - F32 c = cosf(r); - F32 s = sinf(r); + F32 ic = 1.f-c; - F32 ic = 1.f-c; + glh::matrix4f rot_mat(x*x*ic+c, x*y*ic-z*s, x*z*ic+y*s, 0, + x*y*ic+z*s, y*y*ic+c, y*z*ic-x*s, 0, + x*z*ic-y*s, y*z*ic+x*s, z*z*ic+c, 0, + 0,0,0,1); - glh::matrix4f rot_mat(x*x*ic+c, x*y*ic-z*s, x*z*ic+y*s, 0, - x*y*ic+z*s, y*y*ic+c, y*z*ic-x*s, 0, - x*z*ic-y*s, y*z*ic+x*s, z*z*ic+c, 0, - 0,0,0,1); - - mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mult_right(rot_mat); - mMatHash[mMatrixMode]++; - } + mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mult_right(rot_mat); + mMatHash[mMatrixMode]++; + } } void LLRender::pushMatrix() { - flush(); - - { - if (mMatIdx[mMatrixMode] < LL_MATRIX_STACK_DEPTH-1) - { - mMatrix[mMatrixMode][mMatIdx[mMatrixMode]+1] = mMatrix[mMatrixMode][mMatIdx[mMatrixMode]]; - ++mMatIdx[mMatrixMode]; - } - else - { - LL_WARNS() << "Matrix stack overflow." << LL_ENDL; - } - } + flush(); + + { + if (mMatIdx[mMatrixMode] < LL_MATRIX_STACK_DEPTH-1) + { + mMatrix[mMatrixMode][mMatIdx[mMatrixMode]+1] = mMatrix[mMatrixMode][mMatIdx[mMatrixMode]]; + ++mMatIdx[mMatrixMode]; + } + else + { + LL_WARNS() << "Matrix stack overflow." << LL_ENDL; + } + } } void LLRender::popMatrix() { - flush(); - { - if (mMatIdx[mMatrixMode] > 0) - { - --mMatIdx[mMatrixMode]; - mMatHash[mMatrixMode]++; - } - else - { - LL_WARNS() << "Matrix stack underflow." << LL_ENDL; - } - } + flush(); + { + if (mMatIdx[mMatrixMode] > 0) + { + --mMatIdx[mMatrixMode]; + mMatHash[mMatrixMode]++; + } + else + { + LL_WARNS() << "Matrix stack underflow." << LL_ENDL; + } + } } void LLRender::loadMatrix(const GLfloat* m) { - flush(); - { - mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].set_value((GLfloat*) m); - mMatHash[mMatrixMode]++; - } + flush(); + { + mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].set_value((GLfloat*) m); + mMatHash[mMatrixMode]++; + } } void LLRender::multMatrix(const GLfloat* m) { - flush(); - { - glh::matrix4f mat((GLfloat*) m); - - mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mult_right(mat); - mMatHash[mMatrixMode]++; - } + flush(); + { + glh::matrix4f mat((GLfloat*) m); + + mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mult_right(mat); + mMatHash[mMatrixMode]++; + } } void LLRender::matrixMode(eMatrixMode mode) { - if (mode == MM_TEXTURE) - { + if (mode == MM_TEXTURE) + { U32 tex_index = gGL.getCurrentTexUnitIndex(); // the shaders don't actually reference anything beyond texture_matrix0/1 outside of terrain rendering llassert(tex_index <= 3); @@ -1272,360 +1272,360 @@ void LLRender::matrixMode(eMatrixMode mode) LL_WARNS_ONCE() << "Attempted to assign matrix mode out of bounds: " << mode << LL_ENDL; mode = MM_TEXTURE0; } - } + } - mMatrixMode = mode; + mMatrixMode = mode; } LLRender::eMatrixMode LLRender::getMatrixMode() { - if (mMatrixMode >= MM_TEXTURE0 && mMatrixMode <= MM_TEXTURE3) - { //always return MM_TEXTURE if current matrix mode points at any texture matrix - return MM_TEXTURE; - } + if (mMatrixMode >= MM_TEXTURE0 && mMatrixMode <= MM_TEXTURE3) + { //always return MM_TEXTURE if current matrix mode points at any texture matrix + return MM_TEXTURE; + } - return mMatrixMode; + return mMatrixMode; } void LLRender::loadIdentity() { - flush(); + flush(); - { - llassert_always(mMatrixMode < NUM_MATRIX_MODES) ; + { + llassert_always(mMatrixMode < NUM_MATRIX_MODES) ; - mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].make_identity(); - mMatHash[mMatrixMode]++; - } + mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].make_identity(); + mMatHash[mMatrixMode]++; + } } const glh::matrix4f& LLRender::getModelviewMatrix() { - return mMatrix[MM_MODELVIEW][mMatIdx[MM_MODELVIEW]]; + return mMatrix[MM_MODELVIEW][mMatIdx[MM_MODELVIEW]]; } const glh::matrix4f& LLRender::getProjectionMatrix() { - return mMatrix[MM_PROJECTION][mMatIdx[MM_PROJECTION]]; + return mMatrix[MM_PROJECTION][mMatIdx[MM_PROJECTION]]; } void LLRender::translateUI(F32 x, F32 y, F32 z) { - if (mUIOffset.empty()) - { - LL_ERRS() << "Need to push a UI translation frame before offsetting" << LL_ENDL; - } + if (mUIOffset.empty()) + { + LL_ERRS() << "Need to push a UI translation frame before offsetting" << LL_ENDL; + } - mUIOffset.back().mV[0] += x; - mUIOffset.back().mV[1] += y; - mUIOffset.back().mV[2] += z; + mUIOffset.back().mV[0] += x; + mUIOffset.back().mV[1] += y; + mUIOffset.back().mV[2] += z; } void LLRender::scaleUI(F32 x, F32 y, F32 z) { - if (mUIScale.empty()) - { - LL_ERRS() << "Need to push a UI transformation frame before scaling." << LL_ENDL; - } + if (mUIScale.empty()) + { + LL_ERRS() << "Need to push a UI transformation frame before scaling." << LL_ENDL; + } - mUIScale.back().scaleVec(LLVector3(x,y,z)); + mUIScale.back().scaleVec(LLVector3(x,y,z)); } void LLRender::pushUIMatrix() { - if (mUIOffset.empty()) - { - mUIOffset.push_back(LLVector3(0,0,0)); - } - else - { - mUIOffset.push_back(mUIOffset.back()); - } - - if (mUIScale.empty()) - { - mUIScale.push_back(LLVector3(1,1,1)); - } - else - { - mUIScale.push_back(mUIScale.back()); - } + if (mUIOffset.empty()) + { + mUIOffset.push_back(LLVector3(0,0,0)); + } + else + { + mUIOffset.push_back(mUIOffset.back()); + } + + if (mUIScale.empty()) + { + mUIScale.push_back(LLVector3(1,1,1)); + } + else + { + mUIScale.push_back(mUIScale.back()); + } } void LLRender::popUIMatrix() { - if (mUIOffset.empty()) - { - LL_ERRS() << "UI offset stack blown." << LL_ENDL; - } - mUIOffset.pop_back(); - mUIScale.pop_back(); + if (mUIOffset.empty()) + { + LL_ERRS() << "UI offset stack blown." << LL_ENDL; + } + mUIOffset.pop_back(); + mUIScale.pop_back(); } LLVector3 LLRender::getUITranslation() { - if (mUIOffset.empty()) - { - return LLVector3(0,0,0); - } - return mUIOffset.back(); + if (mUIOffset.empty()) + { + return LLVector3(0,0,0); + } + return mUIOffset.back(); } LLVector3 LLRender::getUIScale() { - if (mUIScale.empty()) - { - return LLVector3(1,1,1); - } - return mUIScale.back(); + if (mUIScale.empty()) + { + return LLVector3(1,1,1); + } + return mUIScale.back(); } void LLRender::loadUIIdentity() { - if (mUIOffset.empty()) - { - LL_ERRS() << "Need to push UI translation frame before clearing offset." << LL_ENDL; - } - mUIOffset.back().setVec(0,0,0); - mUIScale.back().setVec(1,1,1); + if (mUIOffset.empty()) + { + LL_ERRS() << "Need to push UI translation frame before clearing offset." << LL_ENDL; + } + mUIOffset.back().setVec(0,0,0); + mUIScale.back().setVec(1,1,1); } void LLRender::setColorMask(bool writeColor, bool writeAlpha) { - setColorMask(writeColor, writeColor, writeColor, writeAlpha); + setColorMask(writeColor, writeColor, writeColor, writeAlpha); } void LLRender::setColorMask(bool writeColorR, bool writeColorG, bool writeColorB, bool writeAlpha) { - flush(); - - if (mCurrColorMask[0] != writeColorR || - mCurrColorMask[1] != writeColorG || - mCurrColorMask[2] != writeColorB || - mCurrColorMask[3] != writeAlpha) - { - mCurrColorMask[0] = writeColorR; - mCurrColorMask[1] = writeColorG; - mCurrColorMask[2] = writeColorB; - mCurrColorMask[3] = writeAlpha; + flush(); - glColorMask(writeColorR ? GL_TRUE : GL_FALSE, - writeColorG ? GL_TRUE : GL_FALSE, - writeColorB ? GL_TRUE : GL_FALSE, - writeAlpha ? GL_TRUE : GL_FALSE); - } + if (mCurrColorMask[0] != writeColorR || + mCurrColorMask[1] != writeColorG || + mCurrColorMask[2] != writeColorB || + mCurrColorMask[3] != writeAlpha) + { + mCurrColorMask[0] = writeColorR; + mCurrColorMask[1] = writeColorG; + mCurrColorMask[2] = writeColorB; + mCurrColorMask[3] = writeAlpha; + + glColorMask(writeColorR ? GL_TRUE : GL_FALSE, + writeColorG ? GL_TRUE : GL_FALSE, + writeColorB ? GL_TRUE : GL_FALSE, + writeAlpha ? GL_TRUE : GL_FALSE); + } } void LLRender::setSceneBlendType(eBlendType type) { - switch (type) - { - case BT_ALPHA: - blendFunc(BF_SOURCE_ALPHA, BF_ONE_MINUS_SOURCE_ALPHA); - break; - case BT_ADD: - blendFunc(BF_ONE, BF_ONE); - break; - case BT_ADD_WITH_ALPHA: - blendFunc(BF_SOURCE_ALPHA, BF_ONE); - break; - case BT_MULT: - blendFunc(BF_DEST_COLOR, BF_ZERO); - break; - case BT_MULT_ALPHA: - blendFunc(BF_DEST_ALPHA, BF_ZERO); - break; - case BT_MULT_X2: - blendFunc(BF_DEST_COLOR, BF_SOURCE_COLOR); - break; - case BT_REPLACE: - blendFunc(BF_ONE, BF_ZERO); - break; - default: - LL_ERRS() << "Unknown Scene Blend Type: " << type << LL_ENDL; - break; - } + switch (type) + { + case BT_ALPHA: + blendFunc(BF_SOURCE_ALPHA, BF_ONE_MINUS_SOURCE_ALPHA); + break; + case BT_ADD: + blendFunc(BF_ONE, BF_ONE); + break; + case BT_ADD_WITH_ALPHA: + blendFunc(BF_SOURCE_ALPHA, BF_ONE); + break; + case BT_MULT: + blendFunc(BF_DEST_COLOR, BF_ZERO); + break; + case BT_MULT_ALPHA: + blendFunc(BF_DEST_ALPHA, BF_ZERO); + break; + case BT_MULT_X2: + blendFunc(BF_DEST_COLOR, BF_SOURCE_COLOR); + break; + case BT_REPLACE: + blendFunc(BF_ONE, BF_ZERO); + break; + default: + LL_ERRS() << "Unknown Scene Blend Type: " << type << LL_ENDL; + break; + } } void LLRender::blendFunc(eBlendFactor sfactor, eBlendFactor dfactor) { - llassert(sfactor < BF_UNDEF); - llassert(dfactor < BF_UNDEF); - if (mCurrBlendColorSFactor != sfactor || mCurrBlendColorDFactor != dfactor || - mCurrBlendAlphaSFactor != sfactor || mCurrBlendAlphaDFactor != dfactor) - { - mCurrBlendColorSFactor = sfactor; - mCurrBlendAlphaSFactor = sfactor; - mCurrBlendColorDFactor = dfactor; - mCurrBlendAlphaDFactor = dfactor; - flush(); - glBlendFunc(sGLBlendFactor[sfactor], sGLBlendFactor[dfactor]); - } + llassert(sfactor < BF_UNDEF); + llassert(dfactor < BF_UNDEF); + if (mCurrBlendColorSFactor != sfactor || mCurrBlendColorDFactor != dfactor || + mCurrBlendAlphaSFactor != sfactor || mCurrBlendAlphaDFactor != dfactor) + { + mCurrBlendColorSFactor = sfactor; + mCurrBlendAlphaSFactor = sfactor; + mCurrBlendColorDFactor = dfactor; + mCurrBlendAlphaDFactor = dfactor; + flush(); + glBlendFunc(sGLBlendFactor[sfactor], sGLBlendFactor[dfactor]); + } } void LLRender::blendFunc(eBlendFactor color_sfactor, eBlendFactor color_dfactor, - eBlendFactor alpha_sfactor, eBlendFactor alpha_dfactor) -{ - llassert(color_sfactor < BF_UNDEF); - llassert(color_dfactor < BF_UNDEF); - llassert(alpha_sfactor < BF_UNDEF); - llassert(alpha_dfactor < BF_UNDEF); - - if (mCurrBlendColorSFactor != color_sfactor || mCurrBlendColorDFactor != color_dfactor || - mCurrBlendAlphaSFactor != alpha_sfactor || mCurrBlendAlphaDFactor != alpha_dfactor) - { - mCurrBlendColorSFactor = color_sfactor; - mCurrBlendAlphaSFactor = alpha_sfactor; - mCurrBlendColorDFactor = color_dfactor; - mCurrBlendAlphaDFactor = alpha_dfactor; - flush(); - + eBlendFactor alpha_sfactor, eBlendFactor alpha_dfactor) +{ + llassert(color_sfactor < BF_UNDEF); + llassert(color_dfactor < BF_UNDEF); + llassert(alpha_sfactor < BF_UNDEF); + llassert(alpha_dfactor < BF_UNDEF); + + if (mCurrBlendColorSFactor != color_sfactor || mCurrBlendColorDFactor != color_dfactor || + mCurrBlendAlphaSFactor != alpha_sfactor || mCurrBlendAlphaDFactor != alpha_dfactor) + { + mCurrBlendColorSFactor = color_sfactor; + mCurrBlendAlphaSFactor = alpha_sfactor; + mCurrBlendColorDFactor = color_dfactor; + mCurrBlendAlphaDFactor = alpha_dfactor; + flush(); + glBlendFuncSeparate(sGLBlendFactor[color_sfactor], sGLBlendFactor[color_dfactor], sGLBlendFactor[alpha_sfactor], sGLBlendFactor[alpha_dfactor]); - } + } } LLTexUnit* LLRender::getTexUnit(U32 index) { - if (index < mTexUnits.size()) - { - return &mTexUnits[index]; - } - else - { - LL_DEBUGS() << "Non-existing texture unit layer requested: " << index << LL_ENDL; - return &mDummyTexUnit; - } + if (index < mTexUnits.size()) + { + return &mTexUnits[index]; + } + else + { + LL_DEBUGS() << "Non-existing texture unit layer requested: " << index << LL_ENDL; + return &mDummyTexUnit; + } } LLLightState* LLRender::getLight(U32 index) { - if (index < mLightState.size()) - { - return &mLightState[index]; - } - - return NULL; + if (index < mLightState.size()) + { + return &mLightState[index]; + } + + return NULL; } void LLRender::setAmbientLightColor(const LLColor4& color) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE - if (color != mAmbientLightColor) - { - ++mLightHash; - mAmbientLightColor = color; - } + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE + if (color != mAmbientLightColor) + { + ++mLightHash; + mAmbientLightColor = color; + } } bool LLRender::verifyTexUnitActive(U32 unitToVerify) { - if (mCurrTextureUnitIndex == unitToVerify) - { - return true; - } - else - { - LL_WARNS() << "TexUnit currently active: " << mCurrTextureUnitIndex << " (expecting " << unitToVerify << ")" << LL_ENDL; - return false; - } + if (mCurrTextureUnitIndex == unitToVerify) + { + return true; + } + else + { + LL_WARNS() << "TexUnit currently active: " << mCurrTextureUnitIndex << " (expecting " << unitToVerify << ")" << LL_ENDL; + return false; + } } void LLRender::clearErrors() { - while (glGetError()) - { - //loop until no more error flags left - } + while (glGetError()) + { + //loop until no more error flags left + } } void LLRender::begin(const GLuint& mode) { - if (mode != mMode) - { - if (mode == LLRender::QUADS) - { - mQuadCycle = 1; - } - - if (mMode == LLRender::QUADS || - mMode == LLRender::LINES || - mMode == LLRender::TRIANGLES || - mMode == LLRender::POINTS) - { - flush(); - } - else if (mCount != 0) - { - LL_ERRS() << "gGL.begin() called redundantly." << LL_ENDL; - } - - mMode = mode; - } + if (mode != mMode) + { + if (mode == LLRender::QUADS) + { + mQuadCycle = 1; + } + + if (mMode == LLRender::QUADS || + mMode == LLRender::LINES || + mMode == LLRender::TRIANGLES || + mMode == LLRender::POINTS) + { + flush(); + } + else if (mCount != 0) + { + LL_ERRS() << "gGL.begin() called redundantly." << LL_ENDL; + } + + mMode = mode; + } } void LLRender::end() -{ - if (mCount == 0) - { - return; - //IMM_ERRS << "GL begin and end called with no vertices specified." << LL_ENDL; - } - - if ((mMode != LLRender::QUADS && - mMode != LLRender::LINES && - mMode != LLRender::TRIANGLES && - mMode != LLRender::POINTS) || - mCount > 2048) - { - flush(); - } +{ + if (mCount == 0) + { + return; + //IMM_ERRS << "GL begin and end called with no vertices specified." << LL_ENDL; + } + + if ((mMode != LLRender::QUADS && + mMode != LLRender::LINES && + mMode != LLRender::TRIANGLES && + mMode != LLRender::POINTS) || + mCount > 2048) + { + flush(); + } } void LLRender::flush() { - if (mCount > 0) - { + if (mCount > 0) + { LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; llassert(LLGLSLShader::sCurBoundShaderPtr != nullptr); - if (!mUIOffset.empty()) - { - sUICalls++; - sUIVerts += mCount; - } - - //store mCount in a local variable to avoid re-entrance (drawArrays may call flush) - U32 count = mCount; - - if (mMode == LLRender::QUADS && !sGLCoreProfile) - { - if (mCount%4 != 0) - { - count -= (mCount % 4); - LL_WARNS() << "Incomplete quad requested." << LL_ENDL; - } - } - - if (mMode == LLRender::TRIANGLES) - { - if (mCount%3 != 0) - { - count -= (mCount % 3); - LL_WARNS() << "Incomplete triangle requested." << LL_ENDL; - } - } - - if (mMode == LLRender::LINES) - { - if (mCount%2 != 0) - { - count -= (mCount % 2); - LL_WARNS() << "Incomplete line requested." << LL_ENDL; - } - } - - mCount = 0; + if (!mUIOffset.empty()) + { + sUICalls++; + sUIVerts += mCount; + } + + //store mCount in a local variable to avoid re-entrance (drawArrays may call flush) + U32 count = mCount; + + if (mMode == LLRender::QUADS && !sGLCoreProfile) + { + if (mCount%4 != 0) + { + count -= (mCount % 4); + LL_WARNS() << "Incomplete quad requested." << LL_ENDL; + } + } + + if (mMode == LLRender::TRIANGLES) + { + if (mCount%3 != 0) + { + count -= (mCount % 3); + LL_WARNS() << "Incomplete triangle requested." << LL_ENDL; + } + } + + if (mMode == LLRender::LINES) + { + if (mCount%2 != 0) + { + count -= (mCount % 2); + LL_WARNS() << "Incomplete line requested." << LL_ENDL; + } + } + + mCount = 0; if (mBuffer) { @@ -1649,8 +1649,8 @@ void LLRender::flush() hash.finalize(); } - - + + U64 vhash = hash.digest(); // check the VB cache before making a new vertex buffer @@ -1660,7 +1660,7 @@ void LLRender::flush() // Most of our usage of the "immediate mode" style draw calls is actually // sending the same geometry over and over again. // To leverage this, we maintain a running hash of the vertex stream being - // built up before a flush, and then check that hash against a VB + // built up before a flush, and then check that hash against a VB // cache just before creating a vertex buffer in VRAM std::unordered_map<U64, LLVBCache>::iterator cache = sVBCache.find(vhash); @@ -1739,528 +1739,528 @@ void LLRender::flush() LL_ERRS() << "A flush call from outside main rendering thread" << LL_ENDL; } - - mVerticesp[0] = mVerticesp[count]; - mTexcoordsp[0] = mTexcoordsp[count]; - mColorsp[0] = mColorsp[count]; - - mCount = 0; - } + + mVerticesp[0] = mVerticesp[count]; + mTexcoordsp[0] = mTexcoordsp[count]; + mColorsp[0] = mColorsp[count]; + + mCount = 0; + } } void LLRender::vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z) -{ - //the range of mVerticesp, mColorsp and mTexcoordsp is [0, 4095] - if (mCount > 2048) - { //break when buffer gets reasonably full to keep GL command buffers happy and avoid overflow below - switch (mMode) - { - case LLRender::POINTS: flush(); break; - case LLRender::TRIANGLES: if (mCount%3==0) flush(); break; - case LLRender::QUADS: if(mCount%4 == 0) flush(); break; - case LLRender::LINES: if (mCount%2 == 0) flush(); break; - } - } - - if (mCount > 4094) - { - // LL_WARNS() << "GL immediate mode overflow. Some geometry not drawn." << LL_ENDL; - return; - } - - if (mUIOffset.empty()) - { - mVerticesp[mCount] = LLVector3(x,y,z); - } - else - { - LLVector3 vert = (LLVector3(x,y,z)+mUIOffset.back()).scaledVec(mUIScale.back()); - mVerticesp[mCount] = vert; - } - - if (mMode == LLRender::QUADS && LLRender::sGLCoreProfile) - { - mQuadCycle++; - if (mQuadCycle == 4) - { //copy two vertices so fourth quad element will add a triangle - mQuadCycle = 0; - - mCount++; - mVerticesp[mCount] = mVerticesp[mCount-3]; - mColorsp[mCount] = mColorsp[mCount-3]; - mTexcoordsp[mCount] = mTexcoordsp[mCount-3]; - - mCount++; - mVerticesp[mCount] = mVerticesp[mCount-2]; - mColorsp[mCount] = mColorsp[mCount-2]; - mTexcoordsp[mCount] = mTexcoordsp[mCount-2]; - } - } - - mCount++; - mVerticesp[mCount] = mVerticesp[mCount-1]; - mColorsp[mCount] = mColorsp[mCount-1]; - mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; +{ + //the range of mVerticesp, mColorsp and mTexcoordsp is [0, 4095] + if (mCount > 2048) + { //break when buffer gets reasonably full to keep GL command buffers happy and avoid overflow below + switch (mMode) + { + case LLRender::POINTS: flush(); break; + case LLRender::TRIANGLES: if (mCount%3==0) flush(); break; + case LLRender::QUADS: if(mCount%4 == 0) flush(); break; + case LLRender::LINES: if (mCount%2 == 0) flush(); break; + } + } + + if (mCount > 4094) + { + // LL_WARNS() << "GL immediate mode overflow. Some geometry not drawn." << LL_ENDL; + return; + } + + if (mUIOffset.empty()) + { + mVerticesp[mCount] = LLVector3(x,y,z); + } + else + { + LLVector3 vert = (LLVector3(x,y,z)+mUIOffset.back()).scaledVec(mUIScale.back()); + mVerticesp[mCount] = vert; + } + + if (mMode == LLRender::QUADS && LLRender::sGLCoreProfile) + { + mQuadCycle++; + if (mQuadCycle == 4) + { //copy two vertices so fourth quad element will add a triangle + mQuadCycle = 0; + + mCount++; + mVerticesp[mCount] = mVerticesp[mCount-3]; + mColorsp[mCount] = mColorsp[mCount-3]; + mTexcoordsp[mCount] = mTexcoordsp[mCount-3]; + + mCount++; + mVerticesp[mCount] = mVerticesp[mCount-2]; + mColorsp[mCount] = mColorsp[mCount-2]; + mTexcoordsp[mCount] = mTexcoordsp[mCount-2]; + } + } + + mCount++; + mVerticesp[mCount] = mVerticesp[mCount-1]; + mColorsp[mCount] = mColorsp[mCount-1]; + mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; } void LLRender::vertexBatchPreTransformed(LLVector3* verts, S32 vert_count) { - if (mCount + vert_count > 4094) - { - // LL_WARNS() << "GL immediate mode overflow. Some geometry not drawn." << LL_ENDL; - return; - } - - if (sGLCoreProfile && mMode == LLRender::QUADS) - { //quads are deprecated, convert to triangle list - S32 i = 0; - - while (i < vert_count) - { - //read first three - mVerticesp[mCount++] = verts[i++]; - mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; - mColorsp[mCount] = mColorsp[mCount-1]; - - mVerticesp[mCount++] = verts[i++]; - mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; - mColorsp[mCount] = mColorsp[mCount-1]; - - mVerticesp[mCount++] = verts[i++]; - mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; - mColorsp[mCount] = mColorsp[mCount-1]; - - //copy two - mVerticesp[mCount++] = verts[i-3]; - mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; - mColorsp[mCount] = mColorsp[mCount-1]; - - mVerticesp[mCount++] = verts[i-1]; - mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; - mColorsp[mCount] = mColorsp[mCount-1]; - - //copy last one - mVerticesp[mCount++] = verts[i++]; - mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; - mColorsp[mCount] = mColorsp[mCount-1]; - } - } - else - { - for (S32 i = 0; i < vert_count; i++) - { - mVerticesp[mCount] = verts[i]; - - mCount++; - mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; - mColorsp[mCount] = mColorsp[mCount-1]; - } - } - - if( mCount > 0 ) // ND: Guard against crashes if mCount is zero, yes it can happen - mVerticesp[mCount] = mVerticesp[mCount-1]; + if (mCount + vert_count > 4094) + { + // LL_WARNS() << "GL immediate mode overflow. Some geometry not drawn." << LL_ENDL; + return; + } + + if (sGLCoreProfile && mMode == LLRender::QUADS) + { //quads are deprecated, convert to triangle list + S32 i = 0; + + while (i < vert_count) + { + //read first three + mVerticesp[mCount++] = verts[i++]; + mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; + mColorsp[mCount] = mColorsp[mCount-1]; + + mVerticesp[mCount++] = verts[i++]; + mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; + mColorsp[mCount] = mColorsp[mCount-1]; + + mVerticesp[mCount++] = verts[i++]; + mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; + mColorsp[mCount] = mColorsp[mCount-1]; + + //copy two + mVerticesp[mCount++] = verts[i-3]; + mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; + mColorsp[mCount] = mColorsp[mCount-1]; + + mVerticesp[mCount++] = verts[i-1]; + mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; + mColorsp[mCount] = mColorsp[mCount-1]; + + //copy last one + mVerticesp[mCount++] = verts[i++]; + mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; + mColorsp[mCount] = mColorsp[mCount-1]; + } + } + else + { + for (S32 i = 0; i < vert_count; i++) + { + mVerticesp[mCount] = verts[i]; + + mCount++; + mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; + mColorsp[mCount] = mColorsp[mCount-1]; + } + } + + if( mCount > 0 ) // ND: Guard against crashes if mCount is zero, yes it can happen + mVerticesp[mCount] = mVerticesp[mCount-1]; } void LLRender::vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, S32 vert_count) { - if (mCount + vert_count > 4094) - { - // LL_WARNS() << "GL immediate mode overflow. Some geometry not drawn." << LL_ENDL; - return; - } - - if (sGLCoreProfile && mMode == LLRender::QUADS) - { //quads are deprecated, convert to triangle list - S32 i = 0; - - while (i < vert_count) - { - //read first three - mVerticesp[mCount] = verts[i]; - mTexcoordsp[mCount++] = uvs[i++]; - mColorsp[mCount] = mColorsp[mCount-1]; - - mVerticesp[mCount] = verts[i]; - mTexcoordsp[mCount++] = uvs[i++]; - mColorsp[mCount] = mColorsp[mCount-1]; - - mVerticesp[mCount] = verts[i]; - mTexcoordsp[mCount++] = uvs[i++]; - mColorsp[mCount] = mColorsp[mCount-1]; - - //copy last two - mVerticesp[mCount] = verts[i-3]; - mTexcoordsp[mCount++] = uvs[i-3]; - mColorsp[mCount] = mColorsp[mCount-1]; - - mVerticesp[mCount] = verts[i-1]; - mTexcoordsp[mCount++] = uvs[i-1]; - mColorsp[mCount] = mColorsp[mCount-1]; - - //copy last one - mVerticesp[mCount] = verts[i]; - mTexcoordsp[mCount++] = uvs[i++]; - mColorsp[mCount] = mColorsp[mCount-1]; - } - } - else - { - for (S32 i = 0; i < vert_count; i++) - { - mVerticesp[mCount] = verts[i]; - mTexcoordsp[mCount] = uvs[i]; - - mCount++; - mColorsp[mCount] = mColorsp[mCount-1]; - } - } - - if (mCount > 0) - { - mVerticesp[mCount] = mVerticesp[mCount - 1]; - mTexcoordsp[mCount] = mTexcoordsp[mCount - 1]; - } + if (mCount + vert_count > 4094) + { + // LL_WARNS() << "GL immediate mode overflow. Some geometry not drawn." << LL_ENDL; + return; + } + + if (sGLCoreProfile && mMode == LLRender::QUADS) + { //quads are deprecated, convert to triangle list + S32 i = 0; + + while (i < vert_count) + { + //read first three + mVerticesp[mCount] = verts[i]; + mTexcoordsp[mCount++] = uvs[i++]; + mColorsp[mCount] = mColorsp[mCount-1]; + + mVerticesp[mCount] = verts[i]; + mTexcoordsp[mCount++] = uvs[i++]; + mColorsp[mCount] = mColorsp[mCount-1]; + + mVerticesp[mCount] = verts[i]; + mTexcoordsp[mCount++] = uvs[i++]; + mColorsp[mCount] = mColorsp[mCount-1]; + + //copy last two + mVerticesp[mCount] = verts[i-3]; + mTexcoordsp[mCount++] = uvs[i-3]; + mColorsp[mCount] = mColorsp[mCount-1]; + + mVerticesp[mCount] = verts[i-1]; + mTexcoordsp[mCount++] = uvs[i-1]; + mColorsp[mCount] = mColorsp[mCount-1]; + + //copy last one + mVerticesp[mCount] = verts[i]; + mTexcoordsp[mCount++] = uvs[i++]; + mColorsp[mCount] = mColorsp[mCount-1]; + } + } + else + { + for (S32 i = 0; i < vert_count; i++) + { + mVerticesp[mCount] = verts[i]; + mTexcoordsp[mCount] = uvs[i]; + + mCount++; + mColorsp[mCount] = mColorsp[mCount-1]; + } + } + + if (mCount > 0) + { + mVerticesp[mCount] = mVerticesp[mCount - 1]; + mTexcoordsp[mCount] = mTexcoordsp[mCount - 1]; + } } void LLRender::vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, LLColor4U* colors, S32 vert_count) { - if (mCount + vert_count > 4094) - { - // LL_WARNS() << "GL immediate mode overflow. Some geometry not drawn." << LL_ENDL; - return; - } - - - if (sGLCoreProfile && mMode == LLRender::QUADS) - { //quads are deprecated, convert to triangle list - S32 i = 0; - - while (i < vert_count) - { - //read first three - mVerticesp[mCount] = verts[i]; - mTexcoordsp[mCount] = uvs[i]; - mColorsp[mCount++] = colors[i++]; - - mVerticesp[mCount] = verts[i]; - mTexcoordsp[mCount] = uvs[i]; - mColorsp[mCount++] = colors[i++]; - - mVerticesp[mCount] = verts[i]; - mTexcoordsp[mCount] = uvs[i]; - mColorsp[mCount++] = colors[i++]; - - //copy last two - mVerticesp[mCount] = verts[i-3]; - mTexcoordsp[mCount] = uvs[i-3]; - mColorsp[mCount++] = colors[i-3]; - - mVerticesp[mCount] = verts[i-1]; - mTexcoordsp[mCount] = uvs[i-1]; - mColorsp[mCount++] = colors[i-1]; - - //copy last one - mVerticesp[mCount] = verts[i]; - mTexcoordsp[mCount] = uvs[i]; - mColorsp[mCount++] = colors[i++]; - } - } - else - { - for (S32 i = 0; i < vert_count; i++) - { - mVerticesp[mCount] = verts[i]; - mTexcoordsp[mCount] = uvs[i]; - mColorsp[mCount] = colors[i]; - - mCount++; - } - } - - if (mCount > 0) - { - mVerticesp[mCount] = mVerticesp[mCount - 1]; - mTexcoordsp[mCount] = mTexcoordsp[mCount - 1]; - mColorsp[mCount] = mColorsp[mCount - 1]; - } + if (mCount + vert_count > 4094) + { + // LL_WARNS() << "GL immediate mode overflow. Some geometry not drawn." << LL_ENDL; + return; + } + + + if (sGLCoreProfile && mMode == LLRender::QUADS) + { //quads are deprecated, convert to triangle list + S32 i = 0; + + while (i < vert_count) + { + //read first three + mVerticesp[mCount] = verts[i]; + mTexcoordsp[mCount] = uvs[i]; + mColorsp[mCount++] = colors[i++]; + + mVerticesp[mCount] = verts[i]; + mTexcoordsp[mCount] = uvs[i]; + mColorsp[mCount++] = colors[i++]; + + mVerticesp[mCount] = verts[i]; + mTexcoordsp[mCount] = uvs[i]; + mColorsp[mCount++] = colors[i++]; + + //copy last two + mVerticesp[mCount] = verts[i-3]; + mTexcoordsp[mCount] = uvs[i-3]; + mColorsp[mCount++] = colors[i-3]; + + mVerticesp[mCount] = verts[i-1]; + mTexcoordsp[mCount] = uvs[i-1]; + mColorsp[mCount++] = colors[i-1]; + + //copy last one + mVerticesp[mCount] = verts[i]; + mTexcoordsp[mCount] = uvs[i]; + mColorsp[mCount++] = colors[i++]; + } + } + else + { + for (S32 i = 0; i < vert_count; i++) + { + mVerticesp[mCount] = verts[i]; + mTexcoordsp[mCount] = uvs[i]; + mColorsp[mCount] = colors[i]; + + mCount++; + } + } + + if (mCount > 0) + { + mVerticesp[mCount] = mVerticesp[mCount - 1]; + mTexcoordsp[mCount] = mTexcoordsp[mCount - 1]; + mColorsp[mCount] = mColorsp[mCount - 1]; + } } void LLRender::vertex2i(const GLint& x, const GLint& y) { - vertex3f((GLfloat) x, (GLfloat) y, 0); + vertex3f((GLfloat) x, (GLfloat) y, 0); } void LLRender::vertex2f(const GLfloat& x, const GLfloat& y) -{ - vertex3f(x,y,0); +{ + vertex3f(x,y,0); } void LLRender::vertex2fv(const GLfloat* v) -{ - vertex3f(v[0], v[1], 0); +{ + vertex3f(v[0], v[1], 0); } void LLRender::vertex3fv(const GLfloat* v) { - vertex3f(v[0], v[1], v[2]); + vertex3f(v[0], v[1], v[2]); } void LLRender::texCoord2f(const GLfloat& x, const GLfloat& y) -{ - mTexcoordsp[mCount] = LLVector2(x,y); +{ + mTexcoordsp[mCount] = LLVector2(x,y); } void LLRender::texCoord2i(const GLint& x, const GLint& y) -{ - texCoord2f((GLfloat) x, (GLfloat) y); +{ + texCoord2f((GLfloat) x, (GLfloat) y); } void LLRender::texCoord2fv(const GLfloat* tc) -{ - texCoord2f(tc[0], tc[1]); +{ + texCoord2f(tc[0], tc[1]); } void LLRender::color4ub(const GLubyte& r, const GLubyte& g, const GLubyte& b, const GLubyte& a) { - if (!LLGLSLShader::sCurBoundShaderPtr || LLGLSLShader::sCurBoundShaderPtr->mAttributeMask & LLVertexBuffer::MAP_COLOR) - { - mColorsp[mCount] = LLColor4U(r,g,b,a); - } - else - { //not using shaders or shader reads color from a uniform - diffuseColor4ub(r,g,b,a); - } + if (!LLGLSLShader::sCurBoundShaderPtr || LLGLSLShader::sCurBoundShaderPtr->mAttributeMask & LLVertexBuffer::MAP_COLOR) + { + mColorsp[mCount] = LLColor4U(r,g,b,a); + } + else + { //not using shaders or shader reads color from a uniform + diffuseColor4ub(r,g,b,a); + } } void LLRender::color4ubv(const GLubyte* c) { - color4ub(c[0], c[1], c[2], c[3]); + color4ub(c[0], c[1], c[2], c[3]); } void LLRender::color4f(const GLfloat& r, const GLfloat& g, const GLfloat& b, const GLfloat& a) { - color4ub((GLubyte) (llclamp(r, 0.f, 1.f)*255), - (GLubyte) (llclamp(g, 0.f, 1.f)*255), - (GLubyte) (llclamp(b, 0.f, 1.f)*255), - (GLubyte) (llclamp(a, 0.f, 1.f)*255)); + color4ub((GLubyte) (llclamp(r, 0.f, 1.f)*255), + (GLubyte) (llclamp(g, 0.f, 1.f)*255), + (GLubyte) (llclamp(b, 0.f, 1.f)*255), + (GLubyte) (llclamp(a, 0.f, 1.f)*255)); } void LLRender::color4fv(const GLfloat* c) -{ - color4f(c[0],c[1],c[2],c[3]); +{ + color4f(c[0],c[1],c[2],c[3]); } void LLRender::color3f(const GLfloat& r, const GLfloat& g, const GLfloat& b) -{ - color4f(r,g,b,1); +{ + color4f(r,g,b,1); } void LLRender::color3fv(const GLfloat* c) -{ - color4f(c[0],c[1],c[2],1); +{ + color4f(c[0],c[1],c[2],1); } void LLRender::diffuseColor3f(F32 r, F32 g, F32 b) { - LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; - llassert(shader != NULL); + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + llassert(shader != NULL); - if (shader) - { - shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, r,g,b,1.f); - } - else - { - glColor3f(r,g,b); - } + if (shader) + { + shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, r,g,b,1.f); + } + else + { + glColor3f(r,g,b); + } } void LLRender::diffuseColor3fv(const F32* c) { - LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; - llassert(shader != NULL); + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + llassert(shader != NULL); - if (shader) - { - shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, c[0], c[1], c[2], 1.f); - } - else - { - glColor3fv(c); - } + if (shader) + { + shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, c[0], c[1], c[2], 1.f); + } + else + { + glColor3fv(c); + } } void LLRender::diffuseColor4f(F32 r, F32 g, F32 b, F32 a) { - LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; - llassert(shader != NULL); + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + llassert(shader != NULL); - if (shader) - { - shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, r,g,b,a); - } - else - { - glColor4f(r,g,b,a); - } + if (shader) + { + shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, r,g,b,a); + } + else + { + glColor4f(r,g,b,a); + } } void LLRender::diffuseColor4fv(const F32* c) { - LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; - llassert(shader != NULL); + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + llassert(shader != NULL); - if (shader) - { - shader->uniform4fv(LLShaderMgr::DIFFUSE_COLOR, 1, c); - } - else - { - glColor4fv(c); - } + if (shader) + { + shader->uniform4fv(LLShaderMgr::DIFFUSE_COLOR, 1, c); + } + else + { + glColor4fv(c); + } } void LLRender::diffuseColor4ubv(const U8* c) { - LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; - llassert(shader != NULL); + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + llassert(shader != NULL); - if (shader) - { - shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, c[0]/255.f, c[1]/255.f, c[2]/255.f, c[3]/255.f); - } - else - { - glColor4ubv(c); - } + if (shader) + { + shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, c[0]/255.f, c[1]/255.f, c[2]/255.f, c[3]/255.f); + } + else + { + glColor4ubv(c); + } } void LLRender::diffuseColor4ub(U8 r, U8 g, U8 b, U8 a) { - LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; - llassert(shader != NULL); + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + llassert(shader != NULL); - if (shader) - { - shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, r/255.f, g/255.f, b/255.f, a/255.f); - } - else - { - glColor4ub(r,g,b,a); - } + if (shader) + { + shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, r/255.f, g/255.f, b/255.f, a/255.f); + } + else + { + glColor4ub(r,g,b,a); + } } void LLRender::debugTexUnits(void) { - LL_INFOS("TextureUnit") << "Active TexUnit: " << mCurrTextureUnitIndex << LL_ENDL; - std::string active_enabled = "false"; - for (U32 i = 0; i < mTexUnits.size(); i++) - { - if (getTexUnit(i)->mCurrTexType != LLTexUnit::TT_NONE) - { - if (i == mCurrTextureUnitIndex) active_enabled = "true"; - LL_INFOS("TextureUnit") << "TexUnit: " << i << " Enabled" << LL_ENDL; - LL_INFOS("TextureUnit") << "Enabled As: " ; - switch (getTexUnit(i)->mCurrTexType) - { - case LLTexUnit::TT_TEXTURE: - LL_CONT << "Texture 2D"; - break; - case LLTexUnit::TT_RECT_TEXTURE: - LL_CONT << "Texture Rectangle"; - break; - case LLTexUnit::TT_CUBE_MAP: - LL_CONT << "Cube Map"; - break; - default: - LL_CONT << "ARGH!!! NONE!"; - break; - } - LL_CONT << ", Texture Bound: " << getTexUnit(i)->mCurrTexture << LL_ENDL; - } - } - LL_INFOS("TextureUnit") << "Active TexUnit Enabled : " << active_enabled << LL_ENDL; + LL_INFOS("TextureUnit") << "Active TexUnit: " << mCurrTextureUnitIndex << LL_ENDL; + std::string active_enabled = "false"; + for (U32 i = 0; i < mTexUnits.size(); i++) + { + if (getTexUnit(i)->mCurrTexType != LLTexUnit::TT_NONE) + { + if (i == mCurrTextureUnitIndex) active_enabled = "true"; + LL_INFOS("TextureUnit") << "TexUnit: " << i << " Enabled" << LL_ENDL; + LL_INFOS("TextureUnit") << "Enabled As: " ; + switch (getTexUnit(i)->mCurrTexType) + { + case LLTexUnit::TT_TEXTURE: + LL_CONT << "Texture 2D"; + break; + case LLTexUnit::TT_RECT_TEXTURE: + LL_CONT << "Texture Rectangle"; + break; + case LLTexUnit::TT_CUBE_MAP: + LL_CONT << "Cube Map"; + break; + default: + LL_CONT << "ARGH!!! NONE!"; + break; + } + LL_CONT << ", Texture Bound: " << getTexUnit(i)->mCurrTexture << LL_ENDL; + } + } + LL_INFOS("TextureUnit") << "Active TexUnit Enabled : " << active_enabled << LL_ENDL; } glh::matrix4f copy_matrix(F32* src) { - glh::matrix4f ret; - ret.set_value(src); - return ret; + glh::matrix4f ret; + ret.set_value(src); + return ret; } glh::matrix4f get_current_modelview() { - return copy_matrix(gGLModelView); + return copy_matrix(gGLModelView); } glh::matrix4f get_current_projection() { - return copy_matrix(gGLProjection); + return copy_matrix(gGLProjection); } glh::matrix4f get_last_modelview() { - return copy_matrix(gGLLastModelView); + return copy_matrix(gGLLastModelView); } glh::matrix4f get_last_projection() { - return copy_matrix(gGLLastProjection); + return copy_matrix(gGLLastProjection); } void copy_matrix(const glh::matrix4f& src, F32* dst) { - for (U32 i = 0; i < 16; i++) - { - dst[i] = src.m[i]; - } + for (U32 i = 0; i < 16; i++) + { + dst[i] = src.m[i]; + } } void set_current_modelview(const glh::matrix4f& mat) { - copy_matrix(mat, gGLModelView); + copy_matrix(mat, gGLModelView); } void set_current_projection(glh::matrix4f& mat) { - copy_matrix(mat, gGLProjection); + copy_matrix(mat, gGLProjection); } glh::matrix4f gl_ortho(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat znear, GLfloat zfar) { - glh::matrix4f ret( - 2.f/(right-left), 0.f, 0.f, -(right+left)/(right-left), - 0.f, 2.f/(top-bottom), 0.f, -(top+bottom)/(top-bottom), - 0.f, 0.f, -2.f/(zfar-znear), -(zfar+znear)/(zfar-znear), - 0.f, 0.f, 0.f, 1.f); + glh::matrix4f ret( + 2.f/(right-left), 0.f, 0.f, -(right+left)/(right-left), + 0.f, 2.f/(top-bottom), 0.f, -(top+bottom)/(top-bottom), + 0.f, 0.f, -2.f/(zfar-znear), -(zfar+znear)/(zfar-znear), + 0.f, 0.f, 0.f, 1.f); - return ret; + return ret; } glh::matrix4f gl_perspective(GLfloat fovy, GLfloat aspect, GLfloat zNear, GLfloat zFar) { - GLfloat f = 1.f/tanf(DEG_TO_RAD*fovy/2.f); + GLfloat f = 1.f/tanf(DEG_TO_RAD*fovy/2.f); - return glh::matrix4f(f/aspect, 0, 0, 0, - 0, f, 0, 0, - 0, 0, (zFar+zNear)/(zNear-zFar), (2.f*zFar*zNear)/(zNear-zFar), - 0, 0, -1.f, 0); + return glh::matrix4f(f/aspect, 0, 0, 0, + 0, f, 0, 0, + 0, 0, (zFar+zNear)/(zNear-zFar), (2.f*zFar*zNear)/(zNear-zFar), + 0, 0, -1.f, 0); } glh::matrix4f gl_lookat(LLVector3 eye, LLVector3 center, LLVector3 up) { - LLVector3 f = center-eye; - f.normVec(); - up.normVec(); - LLVector3 s = f % up; - LLVector3 u = s % f; - - return glh::matrix4f(s[0], s[1], s[2], 0, - u[0], u[1], u[2], 0, - -f[0], -f[1], -f[2], 0, - 0, 0, 0, 1); - + LLVector3 f = center-eye; + f.normVec(); + up.normVec(); + LLVector3 s = f % up; + LLVector3 u = s % f; + + return glh::matrix4f(s[0], s[1], s[2], 0, + u[0], u[1], u[2], 0, + -f[0], -f[1], -f[2], 0, + 0, 0, 0, 1); + } 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/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp index 88c48e5166..7f0643c3e8 100644 --- a/indra/llrender/llrendertarget.cpp +++ b/indra/llrender/llrendertarget.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llrendertarget.cpp * @brief LLRenderTarget 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$ */ @@ -44,7 +44,7 @@ void check_framebuffer_status() break; default: LL_WARNS() << "check_framebuffer_status failed -- " << std::hex << status << LL_ENDL; - ll_fail("check_framebuffer_status failed"); + ll_fail("check_framebuffer_status failed"); break; } } @@ -75,10 +75,10 @@ LLRenderTarget::~LLRenderTarget() } void LLRenderTarget::resize(U32 resx, U32 resy) -{ +{ //for accounting, get the number of pixels added/subtracted S32 pix_diff = (resx*resy)-(mResX*mResY); - + mResX = resx; mResY = resy; @@ -92,7 +92,7 @@ void LLRenderTarget::resize(U32 resx, U32 resy) } if (mDepth) - { + { gGL.getTexUnit(0)->bindManual(mUsage, mDepth); U32 internal_type = LLTexUnit::getInternalType(mUsage); LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT24, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL, false); @@ -100,7 +100,7 @@ void LLRenderTarget::resize(U32 resx, U32 resy) sBytesAllocated += pix_diff*4; } } - + bool LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, LLTexUnit::eTextureType usage, LLTexUnit::eTextureMipGeneration generateMipMaps) { @@ -112,7 +112,7 @@ bool LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, LLT resy = llmin(resy, (U32) gGLManager.mGLMaxTextureSize); release(); - + mResX = resx; mResY = resy; @@ -125,7 +125,7 @@ bool LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, LLT // Calculate the number of mip levels based upon resolution that we should have. mMipLevels = 1 + floor(log10((float)llmax(mResX, mResY))/log10(2.0)); } - + if (depth) { if (!allocateDepth()) @@ -140,12 +140,12 @@ bool LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, LLT if (mDepth) { glBindFramebuffer(GL_FRAMEBUFFER, mFBO); - + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), mDepth, 0); glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO); } - + return addColorAttachment(color_fmt); } @@ -190,7 +190,7 @@ void LLRenderTarget::releaseColorAttachment() llassert(!isBoundInStack()); llassert(mTex.size() == 1); //cannot use releaseColorAttachment with LLRenderTarget managed color targets llassert(mFBO != 0); // mFBO must be valid - + glBindFramebuffer(GL_FRAMEBUFFER, mFBO); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, LLTexUnit::getInternalType(mUsage), 0, 0); glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO); @@ -238,12 +238,12 @@ bool LLRenderTarget::addColorAttachment(U32 color_fmt) return false; } } - + sBytesAllocated += mResX*mResY*4; stop_glerror(); - + if (offset == 0) { //use bilinear filtering on single texture render targets that aren't multisampled gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); @@ -266,15 +266,15 @@ bool LLRenderTarget::addColorAttachment(U32 color_fmt) gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); stop_glerror(); } - + if (mFBO) { glBindFramebuffer(GL_FRAMEBUFFER, mFBO); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+offset, LLTexUnit::getInternalType(mUsage), tex, 0); - + check_framebuffer_status(); - + glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO); } @@ -286,8 +286,8 @@ bool LLRenderTarget::addColorAttachment(U32 color_fmt) bindTarget(); flush(); } - - + + return true; } @@ -296,7 +296,7 @@ bool LLRenderTarget::allocateDepth() LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; LLImageGL::generateTextures(1, &mDepth); gGL.getTexUnit(0)->bindManual(mUsage, mDepth); - + U32 internal_type = LLTexUnit::getInternalType(mUsage); stop_glerror(); clear_glerror(); @@ -336,7 +336,7 @@ void LLRenderTarget::shareDepthBuffer(LLRenderTarget& target) if (mDepth) { glBindFramebuffer(GL_FRAMEBUFFER, target.mFBO); - + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), mDepth, 0); check_framebuffer_status(); @@ -355,7 +355,7 @@ void LLRenderTarget::release() if (mDepth) { LLImageGL::deleteTextures(1, &mDepth); - + mDepth = 0; sBytesAllocated -= mResX*mResY*4; @@ -408,7 +408,7 @@ void LLRenderTarget::release() mTex.clear(); mInternalFormat.clear(); - + mResX = mResY = 0; } @@ -417,7 +417,7 @@ void LLRenderTarget::bindTarget() LL_PROFILE_GPU_ZONE("bindTarget"); llassert(mFBO); llassert(!isBoundInStack()); - + glBindFramebuffer(GL_FRAMEBUFFER, mFBO); sCurFBO = mFBO; @@ -427,7 +427,7 @@ void LLRenderTarget::bindTarget() GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3}; glDrawBuffers(mTex.size(), drawbuffers); - + if (mTex.empty()) { //no color buffer to draw to glDrawBuffer(GL_NONE); @@ -452,7 +452,7 @@ void LLRenderTarget::clear(U32 mask_in) if (mUseDepth) { mask |= GL_DEPTH_BUFFER_BIT; - + } if (mFBO) { @@ -560,7 +560,7 @@ bool LLRenderTarget::isBoundInStack() const { LLRenderTarget* cur = sBoundTarget; while (cur && cur != this) - { + { cur = cur->mPreviousRT; } diff --git a/indra/llrender/llrendertarget.h b/indra/llrender/llrendertarget.h index 9fcea35e3d..b5745b5b49 100644 --- a/indra/llrender/llrendertarget.h +++ b/indra/llrender/llrendertarget.h @@ -1,25 +1,25 @@ -/** +/** * @file llrendertarget.h * @brief Off screen render target abstraction. Loose wrapper for GL_EXT_framebuffer_objects. * * $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$ */ @@ -37,56 +37,56 @@ SAMPLE USAGE: - LLRenderTarget target; + LLRenderTarget target; - ... + ... - //allocate a 256x256 RGBA render target with depth buffer - target.allocate(256,256,GL_RGBA,TRUE); + //allocate a 256x256 RGBA render target with depth buffer + target.allocate(256,256,GL_RGBA,TRUE); - //render to contents of offscreen buffer - target.bindTarget(); - target.clear(); - ... <issue drawing commands> ... - target.flush(); + //render to contents of offscreen buffer + target.bindTarget(); + target.clear(); + ... <issue drawing commands> ... + target.flush(); - ... + ... - //use target as a texture - gGL.getTexUnit(INDEX)->bind(&target); - ... <issue drawing commands> ... + //use target as a texture + gGL.getTexUnit(INDEX)->bind(&target); + ... <issue drawing commands> ... */ class LLRenderTarget { public: - //whether or not to use FBO implementation - static bool sUseFBO; - static U32 sBytesAllocated; - static U32 sCurFBO; - static U32 sCurResX; - static U32 sCurResY; + //whether or not to use FBO implementation + static bool sUseFBO; + static U32 sBytesAllocated; + static U32 sCurFBO; + static U32 sCurResX; + static U32 sCurResY; - LLRenderTarget(); - ~LLRenderTarget(); + LLRenderTarget(); + ~LLRenderTarget(); - //allocate resources for rendering - //must be called before use - //multiple calls will release previously allocated resources + //allocate resources for rendering + //must be called before use + //multiple calls will release previously allocated resources // resX - width // resY - height // color_fmt - GL color format (e.g. GL_RGB) // depth - if true, allocate a depth buffer // usage - deprecated, should always be TT_TEXTURE - bool allocate(U32 resx, U32 resy, U32 color_fmt, bool depth = false, LLTexUnit::eTextureType usage = LLTexUnit::TT_TEXTURE, LLTexUnit::eTextureMipGeneration generateMipMaps = LLTexUnit::TMG_NONE); + bool allocate(U32 resx, U32 resy, U32 color_fmt, bool depth = false, LLTexUnit::eTextureType usage = LLTexUnit::TT_TEXTURE, LLTexUnit::eTextureMipGeneration generateMipMaps = LLTexUnit::TMG_NONE); - //resize existing attachments to use new resolution and color format - // CAUTION: if the GL runs out of memory attempting to resize, this render target will be undefined - // DO NOT use for screen space buffers or for scratch space for an image that might be uploaded - // DO use for render targets that resize often and aren't likely to ruin someone's day if they break - void resize(U32 resx, U32 resy); + //resize existing attachments to use new resolution and color format + // CAUTION: if the GL runs out of memory attempting to resize, this render target will be undefined + // DO NOT use for screen space buffers or for scratch space for an image that might be uploaded + // DO use for render targets that resize often and aren't likely to ruin someone's day if they break + void resize(U32 resx, U32 resy); //point this render target at a particular LLImageGL // Intended usage: @@ -96,95 +96,95 @@ public: // < issue GL calls> // target.flush(); // target.releaseColorAttachment(); - // + // // attachment -- LLImageGL to render into // use_name -- optional texture name to target instead of attachment->getTexName() // NOTE: setColorAttachment and releaseColorAttachment cannot be used in conjuction with - // addColorAttachment, allocateDepth, resize, etc. + // addColorAttachment, allocateDepth, resize, etc. void setColorAttachment(LLImageGL* attachment, LLGLuint use_name = 0); // detach from current color attachment void releaseColorAttachment(); - //add color buffer attachment - //limit of 4 color attachments per render target - bool addColorAttachment(U32 color_fmt); + //add color buffer attachment + //limit of 4 color attachments per render target + bool addColorAttachment(U32 color_fmt); - //allocate a depth texture - bool allocateDepth(); + //allocate a depth texture + bool allocateDepth(); - //share depth buffer with provided render target - void shareDepthBuffer(LLRenderTarget& target); + //share depth buffer with provided render target + void shareDepthBuffer(LLRenderTarget& target); - //free any allocated resources - //safe to call redundantly + //free any allocated resources + //safe to call redundantly // asserts that this target is not currently bound or present in the RT stack - void release(); + void release(); - //bind target for rendering - //applies appropriate viewport - // If an LLRenderTarget is currently bound, stores a reference to that LLRenderTarget + //bind target for rendering + //applies appropriate viewport + // If an LLRenderTarget is currently bound, stores a reference to that LLRenderTarget // and restores previous binding on flush() (maintains a stack of Render Targets) // Asserts that this target is not currently bound in the stack - void bindTarget(); + void bindTarget(); - //clear render targer, clears depth buffer if present, - //uses scissor rect if in copy-to-texture mode + //clear render targer, clears depth buffer if present, + //uses scissor rect if in copy-to-texture mode // asserts that this target is currently bound - void clear(U32 mask = 0xFFFFFFFF); - - //get applied viewport - void getViewport(S32* viewport); + void clear(U32 mask = 0xFFFFFFFF); + + //get applied viewport + void getViewport(S32* viewport); - //get X resolution - U32 getWidth() const { return mResX; } + //get X resolution + U32 getWidth() const { return mResX; } - //get Y resolution - U32 getHeight() const { return mResY; } + //get Y resolution + U32 getHeight() const { return mResY; } - LLTexUnit::eTextureType getUsage(void) const { return mUsage; } + LLTexUnit::eTextureType getUsage(void) const { return mUsage; } - U32 getTexture(U32 attachment = 0) const; - U32 getNumTextures() const; + U32 getTexture(U32 attachment = 0) const; + U32 getNumTextures() const; - U32 getDepth(void) const { return mDepth; } + U32 getDepth(void) const { return mDepth; } - void bindTexture(U32 index, S32 channel, LLTexUnit::eTextureFilterOptions filter_options = LLTexUnit::TFO_BILINEAR); + void bindTexture(U32 index, S32 channel, LLTexUnit::eTextureFilterOptions filter_options = LLTexUnit::TFO_BILINEAR); - //flush rendering operations - //must be called when rendering is complete - //should be used 1:1 with bindTarget - // call bindTarget once, do all your rendering, call flush once + //flush rendering operations + //must be called when rendering is complete + //should be used 1:1 with bindTarget + // call bindTarget once, do all your rendering, call flush once // If an LLRenderTarget was bound when bindTarget was called, binds that RenderTarget for rendering (maintains RT stack) // asserts that this target is currently bound - void flush(); + void flush(); - //Returns TRUE if target is ready to be rendered into. - //That is, if the target has been allocated with at least - //one renderable attachment (i.e. color buffer, depth buffer). - bool isComplete() const; + //Returns TRUE if target is ready to be rendered into. + //That is, if the target has been allocated with at least + //one renderable attachment (i.e. color buffer, depth buffer). + bool isComplete() const; // Returns true if this RenderTarget is bound somewhere in the stack bool isBoundInStack() const; - static LLRenderTarget* getCurrentBoundTarget() { return sBoundTarget; } + static LLRenderTarget* getCurrentBoundTarget() { return sBoundTarget; } protected: - U32 mResX; - U32 mResY; - std::vector<U32> mTex; - std::vector<U32> mInternalFormat; - U32 mFBO; + U32 mResX; + U32 mResY; + std::vector<U32> mTex; + std::vector<U32> mInternalFormat; + U32 mFBO; LLRenderTarget* mPreviousRT = nullptr; U32 mDepth; bool mUseDepth; - LLTexUnit::eTextureMipGeneration mGenerateMipMaps; - U32 mMipLevels; + LLTexUnit::eTextureMipGeneration mGenerateMipMaps; + U32 mMipLevels; + + LLTexUnit::eTextureType mUsage; - LLTexUnit::eTextureType mUsage; - - static LLRenderTarget* sBoundTarget; + static LLRenderTarget* sBoundTarget; }; #endif diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index f78be910d2..85644a95fb 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llshadermgr.cpp * @brief Shader manager implementation. * * $LicenseInfo:firstyear=2005&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,90 +57,90 @@ LLShaderMgr::~LLShaderMgr() // static LLShaderMgr * LLShaderMgr::instance() { - if(NULL == sInstance) - { - LL_ERRS("Shaders") << "LLShaderMgr should already have been instantiated by the application!" << LL_ENDL; - } + if(NULL == sInstance) + { + LL_ERRS("Shaders") << "LLShaderMgr should already have been instantiated by the application!" << LL_ENDL; + } - return sInstance; + return sInstance; } BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) { - llassert_always(shader != NULL); - LLShaderFeatures *features = & shader->mFeatures; - - if (features->attachNothing) - { - return TRUE; - } - ////////////////////////////////////// - // Attach Vertex Shader Features First - ////////////////////////////////////// - - // NOTE order of shader object attaching is VERY IMPORTANT!!! - if (features->calculatesAtmospherics) - { - if (!shader->attachVertexObject("windlight/atmosphericsVarsV.glsl")) - { - return FALSE; - } - } - - if (features->calculatesLighting || features->calculatesAtmospherics) - { - if (!shader->attachVertexObject("windlight/atmosphericsHelpersV.glsl")) - { - return FALSE; - } - } - - if (features->calculatesLighting) - { - if (features->isSpecular) - { + llassert_always(shader != NULL); + LLShaderFeatures *features = & shader->mFeatures; + + if (features->attachNothing) + { + return TRUE; + } + ////////////////////////////////////// + // Attach Vertex Shader Features First + ////////////////////////////////////// + + // NOTE order of shader object attaching is VERY IMPORTANT!!! + if (features->calculatesAtmospherics) + { + if (!shader->attachVertexObject("windlight/atmosphericsVarsV.glsl")) + { + return FALSE; + } + } + + if (features->calculatesLighting || features->calculatesAtmospherics) + { + if (!shader->attachVertexObject("windlight/atmosphericsHelpersV.glsl")) + { + return FALSE; + } + } + + if (features->calculatesLighting) + { + if (features->isSpecular) + { if (!shader->attachVertexObject("lighting/lightFuncSpecularV.glsl")) - { - return FALSE; - } - - if (!features->isAlphaLighting) - { + { + return FALSE; + } + + if (!features->isAlphaLighting) + { if (!shader->attachVertexObject("lighting/sumLightsSpecularV.glsl")) - { - return FALSE; - } - } - + { + return FALSE; + } + } + if (!shader->attachVertexObject("lighting/lightSpecularV.glsl")) - { - return FALSE; - } - } - else - { + { + return FALSE; + } + } + else + { if (!shader->attachVertexObject("lighting/lightFuncV.glsl")) - { - return FALSE; - } - - if (!features->isAlphaLighting) - { + { + return FALSE; + } + + if (!features->isAlphaLighting) + { if (!shader->attachVertexObject("lighting/sumLightsV.glsl")) - { - return FALSE; - } - } - + { + return FALSE; + } + } + if (!shader->attachVertexObject("lighting/lightV.glsl")) - { - return FALSE; - } - } - } - - // NOTE order of shader object attaching is VERY IMPORTANT!!! - if (features->calculatesAtmospherics) + { + return FALSE; + } + } + } + + // NOTE order of shader object attaching is VERY IMPORTANT!!! + if (features->calculatesAtmospherics) { if (!shader->attachVertexObject("environment/srgbF.glsl")) // NOTE -- "F" suffix is superfluous here, there is nothing fragment specific in srgbF { @@ -152,36 +152,36 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) } if (!shader->attachVertexObject("windlight/atmosphericsV.glsl")) - { - return FALSE; - } - } + { + return FALSE; + } + } - if (features->hasSkinning) - { + if (features->hasSkinning) + { if (!shader->attachVertexObject("avatar/avatarSkinV.glsl")) - { - return FALSE; - } - } + { + return FALSE; + } + } - if (features->hasObjectSkinning) - { + if (features->hasObjectSkinning) + { shader->mRiggedVariant = shader; if (!shader->attachVertexObject("avatar/objectSkinV.glsl")) - { - return FALSE; - } - } + { + return FALSE; + } + } if (!shader->attachVertexObject("deferred/textureUtilV.glsl")) { return FALSE; } - - /////////////////////////////////////// - // Attach Fragment Shader Features Next - /////////////////////////////////////// + + /////////////////////////////////////// + // Attach Fragment Shader Features Next + /////////////////////////////////////// // NOTE order of shader object attaching is VERY IMPORTANT!!! if (features->hasSrgb || features->hasAtmospherics || features->calculatesAtmospherics || features->isDeferred) @@ -192,46 +192,46 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) } } - if(features->calculatesAtmospherics || features->hasGamma || features->isDeferred) - { - if (!shader->attachFragmentObject("windlight/atmosphericsVarsF.glsl")) - { - return FALSE; - } - } + if(features->calculatesAtmospherics || features->hasGamma || features->isDeferred) + { + if (!shader->attachFragmentObject("windlight/atmosphericsVarsF.glsl")) + { + return FALSE; + } + } if (features->calculatesLighting || features->calculatesAtmospherics) - { + { if (!shader->attachFragmentObject("windlight/atmosphericsHelpersF.glsl")) - { - return FALSE; - } - } + { + return FALSE; + } + } // we want this BEFORE shadows and AO because those facilities use pos/norm access if (features->isDeferred || features->hasReflectionProbes) - { + { if (!shader->attachFragmentObject("deferred/deferredUtil.glsl")) - { - return FALSE; - } - } + { + return FALSE; + } + } - if (features->hasScreenSpaceReflections || features->hasReflectionProbes) - { + if (features->hasScreenSpaceReflections || features->hasReflectionProbes) + { if (!shader->attachFragmentObject("deferred/screenSpaceReflUtil.glsl")) { return FALSE; } - } + } if (features->hasShadows) - { + { if (!shader->attachFragmentObject("deferred/shadowUtil.glsl")) - { - return FALSE; - } - } + { + return FALSE; + } + } if (features->hasReflectionProbes) { @@ -242,105 +242,105 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) } if (features->hasAmbientOcclusion) - { + { if (!shader->attachFragmentObject("deferred/aoUtil.glsl")) - { - return FALSE; - } - } + { + return FALSE; + } + } - if (features->hasGamma || features->isDeferred) - { + if (features->hasGamma || features->isDeferred) + { if (!shader->attachFragmentObject("windlight/gammaF.glsl")) - { - return FALSE; - } - } + { + return FALSE; + } + } if (features->encodesNormal) - { + { if (!shader->attachFragmentObject("environment/encodeNormF.glsl")) - { - return FALSE; - } - } + { + return FALSE; + } + } - if (features->hasAtmospherics || features->isDeferred) + if (features->hasAtmospherics || features->isDeferred) { if (!shader->attachFragmentObject("windlight/atmosphericsFuncs.glsl")) { return FALSE; } if (!shader->attachFragmentObject("windlight/atmosphericsF.glsl")) - { - return FALSE; - } - } - - // NOTE order of shader object attaching is VERY IMPORTANT!!! - if (features->hasAtmospherics) - { + { + return FALSE; + } + } + + // NOTE order of shader object attaching is VERY IMPORTANT!!! + if (features->hasAtmospherics) + { if (!shader->attachFragmentObject("environment/waterFogF.glsl")) - { - return FALSE; - } - } - - if (features->hasLighting) - { - if (features->disableTextureIndex) - { - if (features->hasAlphaMask) - { + { + return FALSE; + } + } + + if (features->hasLighting) + { + if (features->disableTextureIndex) + { + if (features->hasAlphaMask) + { if (!shader->attachFragmentObject("lighting/lightAlphaMaskNonIndexedF.glsl")) - { - return FALSE; - } - } - else - { + { + return FALSE; + } + } + else + { if (!shader->attachFragmentObject("lighting/lightNonIndexedF.glsl")) - { - return FALSE; - } - } - } - else - { - if (features->hasAlphaMask) - { + { + return FALSE; + } + } + } + else + { + if (features->hasAlphaMask) + { if (!shader->attachFragmentObject("lighting/lightAlphaMaskF.glsl")) - { - return FALSE; - } - } - else - { + { + return FALSE; + } + } + else + { if (!shader->attachFragmentObject("lighting/lightF.glsl")) - { - return FALSE; - } - } - shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1); - } - } - - if (features->mIndexedTextureChannels <= 1) - { - if (!shader->attachVertexObject("objects/nonindexedTextureV.glsl")) - { - return FALSE; - } - } - else - { + { + return FALSE; + } + } + shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1); + } + } + + if (features->mIndexedTextureChannels <= 1) + { + if (!shader->attachVertexObject("objects/nonindexedTextureV.glsl")) + { + return FALSE; + } + } + else + { if (!shader->attachVertexObject("objects/indexedTextureV.glsl")) - { - return FALSE; - } - } + { + return FALSE; + } + } - return TRUE; + return TRUE; } //============================================================================ @@ -348,20 +348,20 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) static std::string get_shader_log(GLuint ret) { - std::string res; - - //get log length - GLint length; + std::string res; + + //get log length + GLint length; glGetShaderiv(ret, GL_INFO_LOG_LENGTH, &length); - if (length > 0) - { - //the log could be any size, so allocate appropriately - GLchar* log = new GLchar[length]; + if (length > 0) + { + //the log could be any size, so allocate appropriately + GLchar* log = new GLchar[length]; glGetShaderInfoLog(ret, length, &length, log); - res = std::string((char *)log); - delete[] log; - } - return res; + res = std::string((char *)log); + delete[] log; + } + return res; } static std::string get_program_log(GLuint ret) @@ -369,7 +369,7 @@ static std::string get_program_log(GLuint ret) LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; std::string res; - //get log length + //get log length GLint length; glGetProgramiv(ret, GL_INFO_LOG_LENGTH, &length); if (length > 0) @@ -401,16 +401,16 @@ static std::string get_object_log(GLuint ret) //dump shader source for debugging void LLShaderMgr::dumpShaderSource(U32 shader_code_count, GLchar** shader_code_text) { - char num_str[16]; // U32 = max 10 digits + char num_str[16]; // U32 = max 10 digits - LL_SHADER_LOADING_WARNS() << "\n"; + LL_SHADER_LOADING_WARNS() << "\n"; - for (U32 i = 0; i < shader_code_count; i++) - { - snprintf(num_str, sizeof(num_str), "%4d: ", i+1); - std::string line_number(num_str); - LL_CONT << line_number << shader_code_text[i]; - } + for (U32 i = 0; i < shader_code_count; i++) + { + snprintf(num_str, sizeof(num_str), "%4d: ", i+1); + std::string line_number(num_str); + LL_CONT << line_number << shader_code_text[i]; + } LL_CONT << LL_ENDL; } @@ -424,11 +424,11 @@ void LLShaderMgr::dumpObjectLog(GLuint ret, BOOL warns, const std::string& filen fname = "unknown shader file"; } - if (log.length() > 0) - { + if (log.length() > 0) + { LL_SHADER_LOADING_WARNS() << "Shader loading from " << fname << LL_ENDL; LL_SHADER_LOADING_WARNS() << "\n" << log << LL_ENDL; - } + } } GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type, std::map<std::string, std::string>* defines, S32 texture_index_channels) @@ -442,25 +442,25 @@ GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_lev } #endif - GLenum error = GL_NO_ERROR; + GLenum error = GL_NO_ERROR; + + error = glGetError(); + if (error != GL_NO_ERROR) + { + LL_SHADER_LOADING_WARNS() << "GL ERROR entering loadShaderFile(): " << error << " for file: " << filename << LL_ENDL; + } - error = glGetError(); - if (error != GL_NO_ERROR) - { - LL_SHADER_LOADING_WARNS() << "GL ERROR entering loadShaderFile(): " << error << " for file: " << filename << LL_ENDL; - } - - if (filename.empty()) - { - return 0; - } + if (filename.empty()) + { + return 0; + } - //read in from file - LLFILE* file = NULL; + //read in from file + LLFILE* file = NULL; - S32 try_gpu_class = shader_level; - S32 gpu_class; + S32 try_gpu_class = shader_level; + S32 gpu_class; std::string open_file_name; @@ -485,7 +485,7 @@ GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_lev { //find the most relevant file for (gpu_class = try_gpu_class; gpu_class > 0; gpu_class--) - { //search from the current gpu class down to class 1 to find the most relevant shader + { //search from the current gpu class down to class 1 to find the most relevant shader std::stringstream fname; fname << getShaderDirPrefix(); fname << gpu_class << "/" << filename; @@ -506,7 +506,7 @@ GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_lev */ LL_DEBUGS("ShaderLoading") << "Looking in " << open_file_name << LL_ENDL; - file = LLFile::fopen(open_file_name, "r"); /* Flawfinder: ignore */ + file = LLFile::fopen(open_file_name, "r"); /* Flawfinder: ignore */ if (file) { LL_DEBUGS("ShaderLoading") << "Loading file: " << open_file_name << " (Want class " << gpu_class << ")" << LL_ENDL; @@ -514,31 +514,31 @@ GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_lev } } } - - if (file == NULL) - { - LL_WARNS("ShaderLoading") << "GLSL Shader file not found: " << open_file_name << LL_ENDL; - return 0; - } - - //we can't have any lines longer than 1024 characters - //or any shaders longer than 4096 lines... deal - DaveP + + if (file == NULL) + { + LL_WARNS("ShaderLoading") << "GLSL Shader file not found: " << open_file_name << LL_ENDL; + return 0; + } + + //we can't have any lines longer than 1024 characters + //or any shaders longer than 4096 lines... deal - DaveP GLchar buff[1024]; GLchar *extra_code_text[1024]; GLchar *shader_code_text[4096 + LL_ARRAY_SIZE(extra_code_text)] = { NULL }; GLuint extra_code_count = 0, shader_code_count = 0; BOOST_STATIC_ASSERT(LL_ARRAY_SIZE(extra_code_text) < LL_ARRAY_SIZE(shader_code_text)); - - - S32 major_version = gGLManager.mGLSLVersionMajor; - S32 minor_version = gGLManager.mGLSLVersionMinor; - - if (major_version == 1 && minor_version < 30) - { + + + S32 major_version = gGLManager.mGLSLVersionMajor; + S32 minor_version = gGLManager.mGLSLVersionMinor; + + if (major_version == 1 && minor_version < 30) + { llassert(false); // GL 3.1 or later required - } - else - { + } + else + { if (major_version >= 4) { //set version to 400 or 420 @@ -554,33 +554,33 @@ GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_lev else if (major_version == 3) { if (minor_version < 10) - { - shader_code_text[shader_code_count++] = strdup("#version 300\n"); - } - else if (minor_version <= 19) - { - shader_code_text[shader_code_count++] = strdup("#version 310\n"); - } - else if (minor_version <= 29) - { - shader_code_text[shader_code_count++] = strdup("#version 320\n"); - } + { + shader_code_text[shader_code_count++] = strdup("#version 300\n"); + } + else if (minor_version <= 19) + { + shader_code_text[shader_code_count++] = strdup("#version 310\n"); + } + else if (minor_version <= 29) + { + shader_code_text[shader_code_count++] = strdup("#version 320\n"); + } else { shader_code_text[shader_code_count++] = strdup("#version 330\n"); } } - else - { - //set version to 1.40 - shader_code_text[shader_code_count++] = strdup("#version 140\n"); - //some implementations of GLSL 1.30 require integer precision be explicitly declared - extra_code_text[extra_code_count++] = strdup("precision mediump int;\n"); - extra_code_text[extra_code_count++] = strdup("precision highp float;\n"); - } - - extra_code_text[extra_code_count++] = strdup("#define FXAA_GLSL_130 1\n"); - } + else + { + //set version to 1.40 + shader_code_text[shader_code_count++] = strdup("#version 140\n"); + //some implementations of GLSL 1.30 require integer precision be explicitly declared + extra_code_text[extra_code_count++] = strdup("precision mediump int;\n"); + extra_code_text[extra_code_count++] = strdup("precision highp float;\n"); + } + + extra_code_text[extra_code_count++] = strdup("#define FXAA_GLSL_130 1\n"); + } // Use alpha float to store bit flags // See: C++: addDeferredAttachment(), shader: frag_data[2] @@ -589,125 +589,125 @@ GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_lev extra_code_text[extra_code_count++] = strdup("#define GBUFFER_FLAG_HAS_PBR 0.67\n"); // bit 1 extra_code_text[extra_code_count++] = strdup("#define GET_GBUFFER_FLAG(flag) (abs(norm.w-flag)< 0.1)\n"); - if (defines) - { - for (auto iter = defines->begin(); iter != defines->end(); ++iter) - { - std::string define = "#define " + iter->first + " " + iter->second + "\n"; - extra_code_text[extra_code_count++] = (GLchar *) strdup(define.c_str()); - } - } - - if( gGLManager.mIsAMD ) - { - extra_code_text[extra_code_count++] = strdup( "#define IS_AMD_CARD 1\n" ); - } - - if (texture_index_channels > 0 && type == GL_FRAGMENT_SHADER) - { - //use specified number of texture channels for indexed texture rendering - - /* prepend shader code that looks like this: - - uniform sampler2D tex0; - uniform sampler2D tex1; - uniform sampler2D tex2; - . - . - . - uniform sampler2D texN; - - flat in int vary_texture_index; - - vec4 ret = vec4(1,0,1,1); - - vec4 diffuseLookup(vec2 texcoord) - { - switch (vary_texture_index) - { - case 0: ret = texture(tex0, texcoord); break; - case 1: ret = texture(tex1, texcoord); break; - case 2: ret = texture(tex2, texcoord); break; - . - . - . - case N: return texture(texN, texcoord); break; - } - - return ret; - } - */ - - extra_code_text[extra_code_count++] = strdup("#define HAS_DIFFUSE_LOOKUP\n"); - - //uniform declartion - for (S32 i = 0; i < texture_index_channels; ++i) - { - std::string decl = llformat("uniform sampler2D tex%d;\n", i); - extra_code_text[extra_code_count++] = strdup(decl.c_str()); - } - - if (texture_index_channels > 1) - { - extra_code_text[extra_code_count++] = strdup("flat in int vary_texture_index;\n"); - } - - extra_code_text[extra_code_count++] = strdup("vec4 diffuseLookup(vec2 texcoord)\n"); - extra_code_text[extra_code_count++] = strdup("{\n"); - - - if (texture_index_channels == 1) - { //don't use flow control, that's silly - extra_code_text[extra_code_count++] = strdup("return texture(tex0, texcoord);\n"); - extra_code_text[extra_code_count++] = strdup("}\n"); - } - else if (major_version > 1 || minor_version >= 30) - { //switches are supported in GLSL 1.30 and later - if (gGLManager.mIsNVIDIA) - { //switches are unreliable on some NVIDIA drivers - for (U32 i = 0; i < texture_index_channels; ++i) - { - std::string if_string = llformat("\t%sif (vary_texture_index == %d) { return texture(tex%d, texcoord); }\n", i > 0 ? "else " : "", i, i); - extra_code_text[extra_code_count++] = strdup(if_string.c_str()); - } - extra_code_text[extra_code_count++] = strdup("\treturn vec4(1,0,1,1);\n"); - extra_code_text[extra_code_count++] = strdup("}\n"); - } - else - { - extra_code_text[extra_code_count++] = strdup("\tvec4 ret = vec4(1,0,1,1);\n"); - extra_code_text[extra_code_count++] = strdup("\tswitch (vary_texture_index)\n"); - extra_code_text[extra_code_count++] = strdup("\t{\n"); - - //switch body - for (S32 i = 0; i < texture_index_channels; ++i) - { - std::string case_str = llformat("\t\tcase %d: return texture(tex%d, texcoord);\n", i, i); - extra_code_text[extra_code_count++] = strdup(case_str.c_str()); - } - - extra_code_text[extra_code_count++] = strdup("\t}\n"); - extra_code_text[extra_code_count++] = strdup("\treturn ret;\n"); - extra_code_text[extra_code_count++] = strdup("}\n"); - } - } - else - { //should never get here. Indexed texture rendering requires GLSL 1.30 or later - // (for passing integers between vertex and fragment shaders) - LL_ERRS() << "Indexed texture rendering requires GLSL 1.30 or later." << LL_ENDL; - } - } - - //copy file into memory - enum { - flag_write_to_out_of_extra_block_area = 0x01 - , flag_extra_block_marker_was_found = 0x02 - }; - - unsigned char flags = flag_write_to_out_of_extra_block_area; - - GLuint out_of_extra_block_counter = 0, start_shader_code = shader_code_count, file_lines_count = 0; - + if (defines) + { + for (auto iter = defines->begin(); iter != defines->end(); ++iter) + { + std::string define = "#define " + iter->first + " " + iter->second + "\n"; + extra_code_text[extra_code_count++] = (GLchar *) strdup(define.c_str()); + } + } + + if( gGLManager.mIsAMD ) + { + extra_code_text[extra_code_count++] = strdup( "#define IS_AMD_CARD 1\n" ); + } + + if (texture_index_channels > 0 && type == GL_FRAGMENT_SHADER) + { + //use specified number of texture channels for indexed texture rendering + + /* prepend shader code that looks like this: + + uniform sampler2D tex0; + uniform sampler2D tex1; + uniform sampler2D tex2; + . + . + . + uniform sampler2D texN; + + flat in int vary_texture_index; + + vec4 ret = vec4(1,0,1,1); + + vec4 diffuseLookup(vec2 texcoord) + { + switch (vary_texture_index) + { + case 0: ret = texture(tex0, texcoord); break; + case 1: ret = texture(tex1, texcoord); break; + case 2: ret = texture(tex2, texcoord); break; + . + . + . + case N: return texture(texN, texcoord); break; + } + + return ret; + } + */ + + extra_code_text[extra_code_count++] = strdup("#define HAS_DIFFUSE_LOOKUP\n"); + + //uniform declartion + for (S32 i = 0; i < texture_index_channels; ++i) + { + std::string decl = llformat("uniform sampler2D tex%d;\n", i); + extra_code_text[extra_code_count++] = strdup(decl.c_str()); + } + + if (texture_index_channels > 1) + { + extra_code_text[extra_code_count++] = strdup("flat in int vary_texture_index;\n"); + } + + extra_code_text[extra_code_count++] = strdup("vec4 diffuseLookup(vec2 texcoord)\n"); + extra_code_text[extra_code_count++] = strdup("{\n"); + + + if (texture_index_channels == 1) + { //don't use flow control, that's silly + extra_code_text[extra_code_count++] = strdup("return texture(tex0, texcoord);\n"); + extra_code_text[extra_code_count++] = strdup("}\n"); + } + else if (major_version > 1 || minor_version >= 30) + { //switches are supported in GLSL 1.30 and later + if (gGLManager.mIsNVIDIA) + { //switches are unreliable on some NVIDIA drivers + for (U32 i = 0; i < texture_index_channels; ++i) + { + std::string if_string = llformat("\t%sif (vary_texture_index == %d) { return texture(tex%d, texcoord); }\n", i > 0 ? "else " : "", i, i); + extra_code_text[extra_code_count++] = strdup(if_string.c_str()); + } + extra_code_text[extra_code_count++] = strdup("\treturn vec4(1,0,1,1);\n"); + extra_code_text[extra_code_count++] = strdup("}\n"); + } + else + { + extra_code_text[extra_code_count++] = strdup("\tvec4 ret = vec4(1,0,1,1);\n"); + extra_code_text[extra_code_count++] = strdup("\tswitch (vary_texture_index)\n"); + extra_code_text[extra_code_count++] = strdup("\t{\n"); + + //switch body + for (S32 i = 0; i < texture_index_channels; ++i) + { + std::string case_str = llformat("\t\tcase %d: return texture(tex%d, texcoord);\n", i, i); + extra_code_text[extra_code_count++] = strdup(case_str.c_str()); + } + + extra_code_text[extra_code_count++] = strdup("\t}\n"); + extra_code_text[extra_code_count++] = strdup("\treturn ret;\n"); + extra_code_text[extra_code_count++] = strdup("}\n"); + } + } + else + { //should never get here. Indexed texture rendering requires GLSL 1.30 or later + // (for passing integers between vertex and fragment shaders) + LL_ERRS() << "Indexed texture rendering requires GLSL 1.30 or later." << LL_ENDL; + } + } + + //copy file into memory + enum { + flag_write_to_out_of_extra_block_area = 0x01 + , flag_extra_block_marker_was_found = 0x02 + }; + + unsigned char flags = flag_write_to_out_of_extra_block_area; + + GLuint out_of_extra_block_counter = 0, start_shader_code = shader_code_count, file_lines_count = 0; + #define TOUCH_SHADERS 0 #if TOUCH_SHADERS @@ -715,13 +715,13 @@ GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_lev bool touched = false; #endif - while(NULL != fgets((char *)buff, 1024, file) - && shader_code_count < (LL_ARRAY_SIZE(shader_code_text) - LL_ARRAY_SIZE(extra_code_text))) - { - file_lines_count++; + while(NULL != fgets((char *)buff, 1024, file) + && shader_code_count < (LL_ARRAY_SIZE(shader_code_text) - LL_ARRAY_SIZE(extra_code_text))) + { + file_lines_count++; + + bool extra_block_area_found = NULL != strstr((const char*)buff, "[EXTRA_CODE_HERE]"); - bool extra_block_area_found = NULL != strstr((const char*)buff, "[EXTRA_CODE_HERE]"); - #if TOUCH_SHADERS if (NULL != strstr((const char*)buff, marker)) { @@ -729,67 +729,67 @@ GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_lev } #endif - if(extra_block_area_found && !(flag_extra_block_marker_was_found & flags)) - { - if(!(flag_write_to_out_of_extra_block_area & flags)) - { - //shift - for(GLuint to = start_shader_code, from = extra_code_count + start_shader_code; - from < shader_code_count; ++to, ++from) - { - shader_code_text[to] = shader_code_text[from]; - } - - shader_code_count -= extra_code_count; - } - - //copy extra code - for(GLuint n = 0; n < extra_code_count - && shader_code_count < (LL_ARRAY_SIZE(shader_code_text) - LL_ARRAY_SIZE(extra_code_text)); ++n) - { - shader_code_text[shader_code_count++] = extra_code_text[n]; - } - - extra_code_count = 0; - - flags &= ~flag_write_to_out_of_extra_block_area; - flags |= flag_extra_block_marker_was_found; - } + if(extra_block_area_found && !(flag_extra_block_marker_was_found & flags)) + { + if(!(flag_write_to_out_of_extra_block_area & flags)) + { + //shift + for(GLuint to = start_shader_code, from = extra_code_count + start_shader_code; + from < shader_code_count; ++to, ++from) + { + shader_code_text[to] = shader_code_text[from]; + } + + shader_code_count -= extra_code_count; + } + + //copy extra code + for(GLuint n = 0; n < extra_code_count + && shader_code_count < (LL_ARRAY_SIZE(shader_code_text) - LL_ARRAY_SIZE(extra_code_text)); ++n) + { + shader_code_text[shader_code_count++] = extra_code_text[n]; + } + + extra_code_count = 0; + + flags &= ~flag_write_to_out_of_extra_block_area; + flags |= flag_extra_block_marker_was_found; + } else { shader_code_text[shader_code_count] = (GLchar *)strdup((char *)buff); - + if(flag_write_to_out_of_extra_block_area & flags) { shader_code_text[extra_code_count + start_shader_code + out_of_extra_block_counter] = shader_code_text[shader_code_count]; out_of_extra_block_counter++; - + if(out_of_extra_block_counter == extra_code_count) { shader_code_count += extra_code_count; flags &= ~flag_write_to_out_of_extra_block_area; } } - + ++shader_code_count; - } - } //while - - if(!(flag_extra_block_marker_was_found & flags)) - { - for(GLuint n = start_shader_code; n < extra_code_count + start_shader_code; ++n) - { - shader_code_text[n] = extra_code_text[n - start_shader_code]; - } - - if (file_lines_count < extra_code_count) - { - shader_code_count += extra_code_count; - } - - extra_code_count = 0; - } + } + } //while + + if(!(flag_extra_block_marker_was_found & flags)) + { + for(GLuint n = start_shader_code; n < extra_code_count + start_shader_code; ++n) + { + shader_code_text[n] = extra_code_text[n - start_shader_code]; + } + + if (file_lines_count < extra_code_count) + { + shader_code_count += extra_code_count; + } + + extra_code_count = 0; + } #if TOUCH_SHADERS if (!touched) @@ -798,106 +798,106 @@ GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_lev } #endif - fclose(file); + fclose(file); - //create shader object + //create shader object GLuint ret = glCreateShader(type); - error = glGetError(); - if (error != GL_NO_ERROR) - { - LL_WARNS("ShaderLoading") << "GL ERROR in glCreateShader: " << error << " for file: " << open_file_name << LL_ENDL; - if (ret) - { - glDeleteShader(ret); //no longer need handle - ret = 0; - } - } - - //load source - if (ret) - { - glShaderSource(ret, shader_code_count, (const GLchar**)shader_code_text, NULL); - - error = glGetError(); - if (error != GL_NO_ERROR) - { - LL_WARNS("ShaderLoading") << "GL ERROR in glShaderSource: " << error << " for file: " << open_file_name << LL_ENDL; - glDeleteShader(ret); //no longer need handle - ret = 0; - } - } - - //compile source - if (ret) - { - glCompileShader(ret); - - error = glGetError(); - if (error != GL_NO_ERROR) - { - LL_WARNS("ShaderLoading") << "GL ERROR in glCompileShader: " << error << " for file: " << open_file_name << LL_ENDL; - glDeleteShader(ret); //no longer need handle - ret = 0; - } - } - - if (error == GL_NO_ERROR) - { - //check for errors - GLint success = GL_TRUE; + error = glGetError(); + if (error != GL_NO_ERROR) + { + LL_WARNS("ShaderLoading") << "GL ERROR in glCreateShader: " << error << " for file: " << open_file_name << LL_ENDL; + if (ret) + { + glDeleteShader(ret); //no longer need handle + ret = 0; + } + } + + //load source + if (ret) + { + glShaderSource(ret, shader_code_count, (const GLchar**)shader_code_text, NULL); + + error = glGetError(); + if (error != GL_NO_ERROR) + { + LL_WARNS("ShaderLoading") << "GL ERROR in glShaderSource: " << error << " for file: " << open_file_name << LL_ENDL; + glDeleteShader(ret); //no longer need handle + ret = 0; + } + } + + //compile source + if (ret) + { + glCompileShader(ret); + + error = glGetError(); + if (error != GL_NO_ERROR) + { + LL_WARNS("ShaderLoading") << "GL ERROR in glCompileShader: " << error << " for file: " << open_file_name << LL_ENDL; + glDeleteShader(ret); //no longer need handle + ret = 0; + } + } + + if (error == GL_NO_ERROR) + { + //check for errors + GLint success = GL_TRUE; glGetShaderiv(ret, GL_COMPILE_STATUS, &success); - error = glGetError(); - if (error != GL_NO_ERROR || success == GL_FALSE) - { - //an error occured, print log - LL_WARNS("ShaderLoading") << "GLSL Compilation Error:" << LL_ENDL; - dumpObjectLog(ret, TRUE, open_file_name); - dumpShaderSource(shader_code_count, shader_code_text); - glDeleteShader(ret); //no longer need handle - ret = 0; - } - } - else - { - ret = 0; - } - stop_glerror(); - - //free memory - for (GLuint i = 0; i < shader_code_count; i++) - { - free(shader_code_text[i]); - } - - //successfully loaded, save results - if (ret) - { - // Add shader file to map + error = glGetError(); + if (error != GL_NO_ERROR || success == GL_FALSE) + { + //an error occured, print log + LL_WARNS("ShaderLoading") << "GLSL Compilation Error:" << LL_ENDL; + dumpObjectLog(ret, TRUE, open_file_name); + dumpShaderSource(shader_code_count, shader_code_text); + glDeleteShader(ret); //no longer need handle + ret = 0; + } + } + else + { + ret = 0; + } + stop_glerror(); + + //free memory + for (GLuint i = 0; i < shader_code_count; i++) + { + free(shader_code_text[i]); + } + + //successfully loaded, save results + if (ret) + { + // Add shader file to map if (type == GL_VERTEX_SHADER) { mVertexShaderObjects[filename] = ret; } else if (type == GL_FRAGMENT_SHADER) { mFragmentShaderObjects[filename] = ret; } - shader_level = try_gpu_class; - } - else - { - if (shader_level > 1) - { - shader_level--; - return loadShaderFile(filename, shader_level, type, defines, texture_index_channels); - } - LL_WARNS("ShaderLoading") << "Failed to load " << filename << LL_ENDL; - } - return ret; + shader_level = try_gpu_class; + } + else + { + if (shader_level > 1) + { + shader_level--; + return loadShaderFile(filename, shader_level, type, defines, texture_index_channels); + } + LL_WARNS("ShaderLoading") << "Failed to load " << filename << LL_ENDL; + } + return ret; } BOOL LLShaderMgr::linkProgramObject(GLuint obj, BOOL suppress_errors) { - //check for errors + //check for errors { LL_PROFILE_ZONE_NAMED_CATEGORY_SHADER("glLinkProgram"); glLinkProgram(obj); @@ -917,238 +917,238 @@ BOOL LLShaderMgr::linkProgramObject(GLuint obj, BOOL suppress_errors) } } - std::string log = get_program_log(obj); - LLStringUtil::toLower(log); - if (log.find("software") != std::string::npos) - { - LL_SHADER_LOADING_WARNS() << "GLSL Linker: Running in Software:" << LL_ENDL; - success = GL_FALSE; - suppress_errors = FALSE; - } - return success; + std::string log = get_program_log(obj); + LLStringUtil::toLower(log); + if (log.find("software") != std::string::npos) + { + LL_SHADER_LOADING_WARNS() << "GLSL Linker: Running in Software:" << LL_ENDL; + success = GL_FALSE; + suppress_errors = FALSE; + } + return success; } BOOL LLShaderMgr::validateProgramObject(GLuint obj) { - //check program validity against current GL - glValidateProgram(obj); - GLint success = GL_TRUE; + //check program validity against current GL + glValidateProgram(obj); + GLint success = GL_TRUE; glGetProgramiv(obj, GL_LINK_STATUS, &success); - if (success == GL_FALSE) - { - LL_SHADER_LOADING_WARNS() << "GLSL program not valid: " << LL_ENDL; - dumpObjectLog(obj); - } - else - { - dumpObjectLog(obj, FALSE); - } - - return success; + if (success == GL_FALSE) + { + LL_SHADER_LOADING_WARNS() << "GLSL program not valid: " << LL_ENDL; + dumpObjectLog(obj); + } + else + { + dumpObjectLog(obj, FALSE); + } + + return success; } void LLShaderMgr::initShaderCache(bool enabled, const LLUUID& old_cache_version, const LLUUID& current_cache_version) { - LL_INFOS() << "Initializing shader cache" << LL_ENDL; - - mShaderCacheEnabled = gGLManager.mGLVersion >= 4.09 && enabled; - - if(!mShaderCacheEnabled || mShaderCacheInitialized) - return; - - mShaderCacheInitialized = true; - - mShaderCacheDir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "shader_cache"); - LLFile::mkdir(mShaderCacheDir); - - { - std::string meta_out_path = gDirUtilp->add(mShaderCacheDir, "shaderdata.llsd"); - if (gDirUtilp->fileExists(meta_out_path)) - { - LL_INFOS() << "Loading shader cache metadata" << LL_ENDL; - - llifstream instream(meta_out_path); - LLSD in_data; - LLSDSerialize::fromNotation(in_data, instream, LLSDSerialize::SIZE_UNLIMITED); - instream.close(); - - if (old_cache_version == current_cache_version) - { - for (const auto& data_pair : llsd::inMap(in_data)) - { - ProgramBinaryData binary_info = ProgramBinaryData(); - binary_info.mBinaryFormat = data_pair.second["binary_format"].asInteger(); - binary_info.mBinaryLength = data_pair.second["binary_size"].asInteger(); - binary_info.mLastUsedTime = data_pair.second["last_used"].asReal(); - mShaderBinaryCache.insert_or_assign(LLUUID(data_pair.first), binary_info); - } - } - else - { - LL_INFOS() << "Shader cache version mismatch detected. Purging." << LL_ENDL; - clearShaderCache(); - } - } - } + LL_INFOS() << "Initializing shader cache" << LL_ENDL; + + mShaderCacheEnabled = gGLManager.mGLVersion >= 4.09 && enabled; + + if(!mShaderCacheEnabled || mShaderCacheInitialized) + return; + + mShaderCacheInitialized = true; + + mShaderCacheDir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "shader_cache"); + LLFile::mkdir(mShaderCacheDir); + + { + std::string meta_out_path = gDirUtilp->add(mShaderCacheDir, "shaderdata.llsd"); + if (gDirUtilp->fileExists(meta_out_path)) + { + LL_INFOS() << "Loading shader cache metadata" << LL_ENDL; + + llifstream instream(meta_out_path); + LLSD in_data; + LLSDSerialize::fromNotation(in_data, instream, LLSDSerialize::SIZE_UNLIMITED); + instream.close(); + + if (old_cache_version == current_cache_version) + { + for (const auto& data_pair : llsd::inMap(in_data)) + { + ProgramBinaryData binary_info = ProgramBinaryData(); + binary_info.mBinaryFormat = data_pair.second["binary_format"].asInteger(); + binary_info.mBinaryLength = data_pair.second["binary_size"].asInteger(); + binary_info.mLastUsedTime = data_pair.second["last_used"].asReal(); + mShaderBinaryCache.insert_or_assign(LLUUID(data_pair.first), binary_info); + } + } + else + { + LL_INFOS() << "Shader cache version mismatch detected. Purging." << LL_ENDL; + clearShaderCache(); + } + } + } } void LLShaderMgr::clearShaderCache() { - std::string shader_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "shader_cache"); - LL_INFOS() << "Removing shader cache at " << shader_cache << LL_ENDL; - const std::string mask = "*"; - gDirUtilp->deleteFilesInDir(shader_cache, mask); - mShaderBinaryCache.clear(); + std::string shader_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "shader_cache"); + LL_INFOS() << "Removing shader cache at " << shader_cache << LL_ENDL; + const std::string mask = "*"; + gDirUtilp->deleteFilesInDir(shader_cache, mask); + mShaderBinaryCache.clear(); } void LLShaderMgr::persistShaderCacheMetadata() { - if(!mShaderCacheEnabled) return; - - LL_INFOS() << "Persisting shader cache metadata to disk" << LL_ENDL; - - LLSD out = LLSD::emptyMap(); - - static const F32 LRU_TIME = (60.f * 60.f) * 24.f * 7.f; // 14 days - const F32 current_time = LLTimer::getTotalSeconds(); - for (auto it = mShaderBinaryCache.begin(); it != mShaderBinaryCache.end();) - { - const ProgramBinaryData& shader_metadata = it->second; - if ((shader_metadata.mLastUsedTime + LRU_TIME) < current_time) - { - std::string shader_path = gDirUtilp->add(mShaderCacheDir, it->first.asString() + ".shaderbin"); - LLFile::remove(shader_path); - it = mShaderBinaryCache.erase(it); - } - else - { - LLSD data = LLSD::emptyMap(); - data["binary_format"] = LLSD::Integer(shader_metadata.mBinaryFormat); - data["binary_size"] = LLSD::Integer(shader_metadata.mBinaryLength); - data["last_used"] = LLSD::Real(shader_metadata.mLastUsedTime); - out[it->first.asString()] = data; - ++it; - } - } - - std::string meta_out_path = gDirUtilp->add(mShaderCacheDir, "shaderdata.llsd"); - llofstream outstream(meta_out_path); - LLSDSerialize::toNotation(out, outstream); - outstream.close(); + if(!mShaderCacheEnabled) return; + + LL_INFOS() << "Persisting shader cache metadata to disk" << LL_ENDL; + + LLSD out = LLSD::emptyMap(); + + static const F32 LRU_TIME = (60.f * 60.f) * 24.f * 7.f; // 14 days + const F32 current_time = LLTimer::getTotalSeconds(); + for (auto it = mShaderBinaryCache.begin(); it != mShaderBinaryCache.end();) + { + const ProgramBinaryData& shader_metadata = it->second; + if ((shader_metadata.mLastUsedTime + LRU_TIME) < current_time) + { + std::string shader_path = gDirUtilp->add(mShaderCacheDir, it->first.asString() + ".shaderbin"); + LLFile::remove(shader_path); + it = mShaderBinaryCache.erase(it); + } + else + { + LLSD data = LLSD::emptyMap(); + data["binary_format"] = LLSD::Integer(shader_metadata.mBinaryFormat); + data["binary_size"] = LLSD::Integer(shader_metadata.mBinaryLength); + data["last_used"] = LLSD::Real(shader_metadata.mLastUsedTime); + out[it->first.asString()] = data; + ++it; + } + } + + std::string meta_out_path = gDirUtilp->add(mShaderCacheDir, "shaderdata.llsd"); + llofstream outstream(meta_out_path); + LLSDSerialize::toNotation(out, outstream); + outstream.close(); } bool LLShaderMgr::loadCachedProgramBinary(LLGLSLShader* shader) { - if (!mShaderCacheEnabled) return false; - - glProgramParameteri(shader->mProgramObject, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE); - - auto binary_iter = mShaderBinaryCache.find(shader->mShaderHash); - if (binary_iter != mShaderBinaryCache.end()) - { - std::string in_path = gDirUtilp->add(mShaderCacheDir, shader->mShaderHash.asString() + ".shaderbin"); - auto& shader_info = binary_iter->second; - if (shader_info.mBinaryLength > 0) - { - std::vector<U8> in_data; - in_data.resize(shader_info.mBinaryLength); - - LLUniqueFile filep = LLFile::fopen(in_path, "rb"); - if (filep) - { - size_t result = fread(in_data.data(), sizeof(U8), in_data.size(), filep); - filep.close(); - - if (result == in_data.size()) - { - GLenum error = glGetError(); // Clear current error - glProgramBinary(shader->mProgramObject, shader_info.mBinaryFormat, in_data.data(), shader_info.mBinaryLength); - - error = glGetError(); - GLint success = GL_TRUE; - glGetProgramiv(shader->mProgramObject, GL_LINK_STATUS, &success); - if (error == GL_NO_ERROR && success == GL_TRUE) - { - binary_iter->second.mLastUsedTime = LLTimer::getTotalSeconds(); - LL_INFOS() << "Loaded cached binary for shader: " << shader->mName << LL_ENDL; - return true; - } - } - } - } - //an error occured, normally we would print log but in this case it means the shader needs recompiling. - LL_INFOS() << "Failed to load cached binary for shader: " << shader->mName << " falling back to compilation" << LL_ENDL; - LLFile::remove(in_path); - mShaderBinaryCache.erase(binary_iter); - } - return false; + if (!mShaderCacheEnabled) return false; + + glProgramParameteri(shader->mProgramObject, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE); + + auto binary_iter = mShaderBinaryCache.find(shader->mShaderHash); + if (binary_iter != mShaderBinaryCache.end()) + { + std::string in_path = gDirUtilp->add(mShaderCacheDir, shader->mShaderHash.asString() + ".shaderbin"); + auto& shader_info = binary_iter->second; + if (shader_info.mBinaryLength > 0) + { + std::vector<U8> in_data; + in_data.resize(shader_info.mBinaryLength); + + LLUniqueFile filep = LLFile::fopen(in_path, "rb"); + if (filep) + { + size_t result = fread(in_data.data(), sizeof(U8), in_data.size(), filep); + filep.close(); + + if (result == in_data.size()) + { + GLenum error = glGetError(); // Clear current error + glProgramBinary(shader->mProgramObject, shader_info.mBinaryFormat, in_data.data(), shader_info.mBinaryLength); + + error = glGetError(); + GLint success = GL_TRUE; + glGetProgramiv(shader->mProgramObject, GL_LINK_STATUS, &success); + if (error == GL_NO_ERROR && success == GL_TRUE) + { + binary_iter->second.mLastUsedTime = LLTimer::getTotalSeconds(); + LL_INFOS() << "Loaded cached binary for shader: " << shader->mName << LL_ENDL; + return true; + } + } + } + } + //an error occured, normally we would print log but in this case it means the shader needs recompiling. + LL_INFOS() << "Failed to load cached binary for shader: " << shader->mName << " falling back to compilation" << LL_ENDL; + LLFile::remove(in_path); + mShaderBinaryCache.erase(binary_iter); + } + return false; } bool LLShaderMgr::saveCachedProgramBinary(LLGLSLShader* shader) { - if (!mShaderCacheEnabled) return true; - - ProgramBinaryData binary_info = ProgramBinaryData(); - glGetProgramiv(shader->mProgramObject, GL_PROGRAM_BINARY_LENGTH, &binary_info.mBinaryLength); - if (binary_info.mBinaryLength > 0) - { - std::vector<U8> program_binary; - program_binary.resize(binary_info.mBinaryLength); - - GLenum error = glGetError(); // Clear current error - glGetProgramBinary(shader->mProgramObject, program_binary.size() * sizeof(U8), nullptr, &binary_info.mBinaryFormat, program_binary.data()); - error = glGetError(); - if (error == GL_NO_ERROR) - { - std::string out_path = gDirUtilp->add(mShaderCacheDir, shader->mShaderHash.asString() + ".shaderbin"); - LLUniqueFile outfile = LLFile::fopen(out_path, "wb"); - if (outfile) - { - fwrite(program_binary.data(), sizeof(U8), program_binary.size(), outfile); - outfile.close(); - - binary_info.mLastUsedTime = LLTimer::getTotalSeconds(); - - mShaderBinaryCache.insert_or_assign(shader->mShaderHash, binary_info); - return true; - } - } - } - return false; + if (!mShaderCacheEnabled) return true; + + ProgramBinaryData binary_info = ProgramBinaryData(); + glGetProgramiv(shader->mProgramObject, GL_PROGRAM_BINARY_LENGTH, &binary_info.mBinaryLength); + if (binary_info.mBinaryLength > 0) + { + std::vector<U8> program_binary; + program_binary.resize(binary_info.mBinaryLength); + + GLenum error = glGetError(); // Clear current error + glGetProgramBinary(shader->mProgramObject, program_binary.size() * sizeof(U8), nullptr, &binary_info.mBinaryFormat, program_binary.data()); + error = glGetError(); + if (error == GL_NO_ERROR) + { + std::string out_path = gDirUtilp->add(mShaderCacheDir, shader->mShaderHash.asString() + ".shaderbin"); + LLUniqueFile outfile = LLFile::fopen(out_path, "wb"); + if (outfile) + { + fwrite(program_binary.data(), sizeof(U8), program_binary.size(), outfile); + outfile.close(); + + binary_info.mLastUsedTime = LLTimer::getTotalSeconds(); + + mShaderBinaryCache.insert_or_assign(shader->mShaderHash, binary_info); + return true; + } + } + } + return false; } //virtual void LLShaderMgr::initAttribsAndUniforms() { - //MUST match order of enum in LLVertexBuffer.h - mReservedAttribs.push_back("position"); - mReservedAttribs.push_back("normal"); - mReservedAttribs.push_back("texcoord0"); - mReservedAttribs.push_back("texcoord1"); - mReservedAttribs.push_back("texcoord2"); - mReservedAttribs.push_back("texcoord3"); - mReservedAttribs.push_back("diffuse_color"); - mReservedAttribs.push_back("emissive"); - mReservedAttribs.push_back("tangent"); - mReservedAttribs.push_back("weight"); - mReservedAttribs.push_back("weight4"); - mReservedAttribs.push_back("clothing"); - mReservedAttribs.push_back("texture_index"); - - //matrix state - mReservedUniforms.push_back("modelview_matrix"); - mReservedUniforms.push_back("projection_matrix"); - mReservedUniforms.push_back("inv_proj"); - mReservedUniforms.push_back("modelview_projection_matrix"); + //MUST match order of enum in LLVertexBuffer.h + mReservedAttribs.push_back("position"); + mReservedAttribs.push_back("normal"); + mReservedAttribs.push_back("texcoord0"); + mReservedAttribs.push_back("texcoord1"); + mReservedAttribs.push_back("texcoord2"); + mReservedAttribs.push_back("texcoord3"); + mReservedAttribs.push_back("diffuse_color"); + mReservedAttribs.push_back("emissive"); + mReservedAttribs.push_back("tangent"); + mReservedAttribs.push_back("weight"); + mReservedAttribs.push_back("weight4"); + mReservedAttribs.push_back("clothing"); + mReservedAttribs.push_back("texture_index"); + + //matrix state + mReservedUniforms.push_back("modelview_matrix"); + mReservedUniforms.push_back("projection_matrix"); + mReservedUniforms.push_back("inv_proj"); + mReservedUniforms.push_back("modelview_projection_matrix"); mReservedUniforms.push_back("inv_modelview"); mReservedUniforms.push_back("identity_matrix"); - mReservedUniforms.push_back("normal_matrix"); - mReservedUniforms.push_back("texture_matrix0"); - mReservedUniforms.push_back("texture_matrix1"); - mReservedUniforms.push_back("texture_matrix2"); - mReservedUniforms.push_back("texture_matrix3"); - mReservedUniforms.push_back("object_plane_s"); - mReservedUniforms.push_back("object_plane_t"); + mReservedUniforms.push_back("normal_matrix"); + mReservedUniforms.push_back("texture_matrix0"); + mReservedUniforms.push_back("texture_matrix1"); + mReservedUniforms.push_back("texture_matrix2"); + mReservedUniforms.push_back("texture_matrix3"); + mReservedUniforms.push_back("object_plane_s"); + mReservedUniforms.push_back("object_plane_t"); mReservedUniforms.push_back("texture_base_color_transform"); // (GLTF) mReservedUniforms.push_back("texture_normal_transform"); // (GLTF) @@ -1157,130 +1157,130 @@ void LLShaderMgr::initAttribsAndUniforms() llassert(mReservedUniforms.size() == LLShaderMgr::TEXTURE_EMISSIVE_TRANSFORM+1); - mReservedUniforms.push_back("viewport"); + mReservedUniforms.push_back("viewport"); - mReservedUniforms.push_back("light_position"); - mReservedUniforms.push_back("light_direction"); - mReservedUniforms.push_back("light_attenuation"); + mReservedUniforms.push_back("light_position"); + mReservedUniforms.push_back("light_direction"); + mReservedUniforms.push_back("light_attenuation"); mReservedUniforms.push_back("light_deferred_attenuation"); - mReservedUniforms.push_back("light_diffuse"); - mReservedUniforms.push_back("light_ambient"); - mReservedUniforms.push_back("light_count"); - mReservedUniforms.push_back("light"); - mReservedUniforms.push_back("light_col"); - mReservedUniforms.push_back("far_z"); + mReservedUniforms.push_back("light_diffuse"); + mReservedUniforms.push_back("light_ambient"); + mReservedUniforms.push_back("light_count"); + mReservedUniforms.push_back("light"); + mReservedUniforms.push_back("light_col"); + mReservedUniforms.push_back("far_z"); - llassert(mReservedUniforms.size() == LLShaderMgr::MULTI_LIGHT_FAR_Z+1); + llassert(mReservedUniforms.size() == LLShaderMgr::MULTI_LIGHT_FAR_Z+1); //NOTE: MUST match order in eGLSLReservedUniforms - mReservedUniforms.push_back("proj_mat"); - mReservedUniforms.push_back("proj_near"); - mReservedUniforms.push_back("proj_p"); - mReservedUniforms.push_back("proj_n"); - mReservedUniforms.push_back("proj_origin"); - mReservedUniforms.push_back("proj_range"); - mReservedUniforms.push_back("proj_ambiance"); - mReservedUniforms.push_back("proj_shadow_idx"); - mReservedUniforms.push_back("shadow_fade"); - mReservedUniforms.push_back("proj_focus"); - mReservedUniforms.push_back("proj_lod"); - mReservedUniforms.push_back("proj_ambient_lod"); - - llassert(mReservedUniforms.size() == LLShaderMgr::PROJECTOR_AMBIENT_LOD+1); - - mReservedUniforms.push_back("color"); + mReservedUniforms.push_back("proj_mat"); + mReservedUniforms.push_back("proj_near"); + mReservedUniforms.push_back("proj_p"); + mReservedUniforms.push_back("proj_n"); + mReservedUniforms.push_back("proj_origin"); + mReservedUniforms.push_back("proj_range"); + mReservedUniforms.push_back("proj_ambiance"); + mReservedUniforms.push_back("proj_shadow_idx"); + mReservedUniforms.push_back("shadow_fade"); + mReservedUniforms.push_back("proj_focus"); + mReservedUniforms.push_back("proj_lod"); + mReservedUniforms.push_back("proj_ambient_lod"); + + llassert(mReservedUniforms.size() == LLShaderMgr::PROJECTOR_AMBIENT_LOD+1); + + mReservedUniforms.push_back("color"); mReservedUniforms.push_back("emissiveColor"); mReservedUniforms.push_back("metallicFactor"); mReservedUniforms.push_back("roughnessFactor"); - mReservedUniforms.push_back("diffuseMap"); + mReservedUniforms.push_back("diffuseMap"); mReservedUniforms.push_back("altDiffuseMap"); - mReservedUniforms.push_back("specularMap"); + mReservedUniforms.push_back("specularMap"); mReservedUniforms.push_back("emissiveMap"); - mReservedUniforms.push_back("bumpMap"); + mReservedUniforms.push_back("bumpMap"); mReservedUniforms.push_back("bumpMap2"); - mReservedUniforms.push_back("environmentMap"); + mReservedUniforms.push_back("environmentMap"); mReservedUniforms.push_back("sceneMap"); mReservedUniforms.push_back("sceneDepth"); mReservedUniforms.push_back("reflectionProbes"); mReservedUniforms.push_back("irradianceProbes"); - mReservedUniforms.push_back("cloud_noise_texture"); + mReservedUniforms.push_back("cloud_noise_texture"); mReservedUniforms.push_back("cloud_noise_texture_next"); - mReservedUniforms.push_back("fullbright"); - mReservedUniforms.push_back("lightnorm"); - mReservedUniforms.push_back("sunlight_color"); - mReservedUniforms.push_back("ambient_color"); + mReservedUniforms.push_back("fullbright"); + mReservedUniforms.push_back("lightnorm"); + mReservedUniforms.push_back("sunlight_color"); + mReservedUniforms.push_back("ambient_color"); mReservedUniforms.push_back("sky_hdr_scale"); mReservedUniforms.push_back("sky_sunlight_scale"); mReservedUniforms.push_back("sky_ambient_scale"); - mReservedUniforms.push_back("blue_horizon"); + mReservedUniforms.push_back("blue_horizon"); mReservedUniforms.push_back("blue_density"); mReservedUniforms.push_back("haze_horizon"); - mReservedUniforms.push_back("haze_density"); - mReservedUniforms.push_back("cloud_shadow"); - mReservedUniforms.push_back("density_multiplier"); - mReservedUniforms.push_back("distance_multiplier"); - mReservedUniforms.push_back("max_y"); - mReservedUniforms.push_back("glow"); - mReservedUniforms.push_back("cloud_color"); - mReservedUniforms.push_back("cloud_pos_density1"); - mReservedUniforms.push_back("cloud_pos_density2"); - mReservedUniforms.push_back("cloud_scale"); - mReservedUniforms.push_back("gamma"); - mReservedUniforms.push_back("scene_light_strength"); + mReservedUniforms.push_back("haze_density"); + mReservedUniforms.push_back("cloud_shadow"); + mReservedUniforms.push_back("density_multiplier"); + mReservedUniforms.push_back("distance_multiplier"); + mReservedUniforms.push_back("max_y"); + mReservedUniforms.push_back("glow"); + mReservedUniforms.push_back("cloud_color"); + mReservedUniforms.push_back("cloud_pos_density1"); + mReservedUniforms.push_back("cloud_pos_density2"); + mReservedUniforms.push_back("cloud_scale"); + mReservedUniforms.push_back("gamma"); + mReservedUniforms.push_back("scene_light_strength"); - llassert(mReservedUniforms.size() == LLShaderMgr::SCENE_LIGHT_STRENGTH+1); + llassert(mReservedUniforms.size() == LLShaderMgr::SCENE_LIGHT_STRENGTH+1); - mReservedUniforms.push_back("center"); - mReservedUniforms.push_back("size"); - mReservedUniforms.push_back("falloff"); + mReservedUniforms.push_back("center"); + mReservedUniforms.push_back("size"); + mReservedUniforms.push_back("falloff"); - mReservedUniforms.push_back("box_center"); - mReservedUniforms.push_back("box_size"); + mReservedUniforms.push_back("box_center"); + mReservedUniforms.push_back("box_size"); - mReservedUniforms.push_back("minLuminance"); - mReservedUniforms.push_back("maxExtractAlpha"); - mReservedUniforms.push_back("lumWeights"); - mReservedUniforms.push_back("warmthWeights"); - mReservedUniforms.push_back("warmthAmount"); - mReservedUniforms.push_back("glowStrength"); - mReservedUniforms.push_back("glowDelta"); - mReservedUniforms.push_back("glowNoiseMap"); + mReservedUniforms.push_back("minLuminance"); + mReservedUniforms.push_back("maxExtractAlpha"); + mReservedUniforms.push_back("lumWeights"); + mReservedUniforms.push_back("warmthWeights"); + mReservedUniforms.push_back("warmthAmount"); + mReservedUniforms.push_back("glowStrength"); + mReservedUniforms.push_back("glowDelta"); + mReservedUniforms.push_back("glowNoiseMap"); - llassert(mReservedUniforms.size() == LLShaderMgr::GLOW_NOISE_MAP+1); + llassert(mReservedUniforms.size() == LLShaderMgr::GLOW_NOISE_MAP+1); - mReservedUniforms.push_back("minimum_alpha"); - mReservedUniforms.push_back("emissive_brightness"); + mReservedUniforms.push_back("minimum_alpha"); + mReservedUniforms.push_back("emissive_brightness"); // Deferred - mReservedUniforms.push_back("shadow_matrix"); - mReservedUniforms.push_back("env_mat"); - mReservedUniforms.push_back("shadow_clip"); - mReservedUniforms.push_back("sun_wash"); - mReservedUniforms.push_back("shadow_noise"); - mReservedUniforms.push_back("blur_size"); - mReservedUniforms.push_back("ssao_radius"); - mReservedUniforms.push_back("ssao_max_radius"); - mReservedUniforms.push_back("ssao_factor"); - mReservedUniforms.push_back("ssao_factor_inv"); - mReservedUniforms.push_back("ssao_effect_mat"); - mReservedUniforms.push_back("screen_res"); - mReservedUniforms.push_back("near_clip"); - mReservedUniforms.push_back("shadow_offset"); - mReservedUniforms.push_back("shadow_bias"); - mReservedUniforms.push_back("spot_shadow_bias"); - mReservedUniforms.push_back("spot_shadow_offset"); - mReservedUniforms.push_back("sun_dir"); + mReservedUniforms.push_back("shadow_matrix"); + mReservedUniforms.push_back("env_mat"); + mReservedUniforms.push_back("shadow_clip"); + mReservedUniforms.push_back("sun_wash"); + mReservedUniforms.push_back("shadow_noise"); + mReservedUniforms.push_back("blur_size"); + mReservedUniforms.push_back("ssao_radius"); + mReservedUniforms.push_back("ssao_max_radius"); + mReservedUniforms.push_back("ssao_factor"); + mReservedUniforms.push_back("ssao_factor_inv"); + mReservedUniforms.push_back("ssao_effect_mat"); + mReservedUniforms.push_back("screen_res"); + mReservedUniforms.push_back("near_clip"); + mReservedUniforms.push_back("shadow_offset"); + mReservedUniforms.push_back("shadow_bias"); + mReservedUniforms.push_back("spot_shadow_bias"); + mReservedUniforms.push_back("spot_shadow_offset"); + mReservedUniforms.push_back("sun_dir"); mReservedUniforms.push_back("moon_dir"); - mReservedUniforms.push_back("shadow_res"); - mReservedUniforms.push_back("proj_shadow_res"); - mReservedUniforms.push_back("depth_cutoff"); - mReservedUniforms.push_back("norm_cutoff"); - mReservedUniforms.push_back("shadow_target_width"); - - llassert(mReservedUniforms.size() == LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH + 1); + mReservedUniforms.push_back("shadow_res"); + mReservedUniforms.push_back("proj_shadow_res"); + mReservedUniforms.push_back("depth_cutoff"); + mReservedUniforms.push_back("norm_cutoff"); + mReservedUniforms.push_back("shadow_target_width"); + + llassert(mReservedUniforms.size() == LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH + 1); mReservedUniforms.push_back("iterationCount"); mReservedUniforms.push_back("rayStep"); @@ -1294,90 +1294,90 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("inv_modelview_delta"); mReservedUniforms.push_back("cube_snapshot"); - mReservedUniforms.push_back("tc_scale"); - mReservedUniforms.push_back("rcp_screen_res"); - mReservedUniforms.push_back("rcp_frame_opt"); - mReservedUniforms.push_back("rcp_frame_opt2"); - - mReservedUniforms.push_back("focal_distance"); - mReservedUniforms.push_back("blur_constant"); - mReservedUniforms.push_back("tan_pixel_angle"); - mReservedUniforms.push_back("magnification"); - mReservedUniforms.push_back("max_cof"); - mReservedUniforms.push_back("res_scale"); - mReservedUniforms.push_back("dof_width"); - mReservedUniforms.push_back("dof_height"); - - mReservedUniforms.push_back("depthMap"); - mReservedUniforms.push_back("shadowMap0"); - mReservedUniforms.push_back("shadowMap1"); - mReservedUniforms.push_back("shadowMap2"); - mReservedUniforms.push_back("shadowMap3"); - mReservedUniforms.push_back("shadowMap4"); - mReservedUniforms.push_back("shadowMap5"); - - llassert(mReservedUniforms.size() == LLShaderMgr::DEFERRED_SHADOW5+1); - - mReservedUniforms.push_back("normalMap"); - mReservedUniforms.push_back("positionMap"); - mReservedUniforms.push_back("diffuseRect"); - mReservedUniforms.push_back("specularRect"); + mReservedUniforms.push_back("tc_scale"); + mReservedUniforms.push_back("rcp_screen_res"); + mReservedUniforms.push_back("rcp_frame_opt"); + mReservedUniforms.push_back("rcp_frame_opt2"); + + mReservedUniforms.push_back("focal_distance"); + mReservedUniforms.push_back("blur_constant"); + mReservedUniforms.push_back("tan_pixel_angle"); + mReservedUniforms.push_back("magnification"); + mReservedUniforms.push_back("max_cof"); + mReservedUniforms.push_back("res_scale"); + mReservedUniforms.push_back("dof_width"); + mReservedUniforms.push_back("dof_height"); + + mReservedUniforms.push_back("depthMap"); + mReservedUniforms.push_back("shadowMap0"); + mReservedUniforms.push_back("shadowMap1"); + mReservedUniforms.push_back("shadowMap2"); + mReservedUniforms.push_back("shadowMap3"); + mReservedUniforms.push_back("shadowMap4"); + mReservedUniforms.push_back("shadowMap5"); + + llassert(mReservedUniforms.size() == LLShaderMgr::DEFERRED_SHADOW5+1); + + mReservedUniforms.push_back("normalMap"); + mReservedUniforms.push_back("positionMap"); + mReservedUniforms.push_back("diffuseRect"); + mReservedUniforms.push_back("specularRect"); mReservedUniforms.push_back("emissiveRect"); mReservedUniforms.push_back("exposureMap"); mReservedUniforms.push_back("brdfLut"); - mReservedUniforms.push_back("noiseMap"); - mReservedUniforms.push_back("lightFunc"); - mReservedUniforms.push_back("lightMap"); - mReservedUniforms.push_back("bloomMap"); - mReservedUniforms.push_back("projectionMap"); - mReservedUniforms.push_back("norm_mat"); - mReservedUniforms.push_back("texture_gamma"); - - mReservedUniforms.push_back("specular_color"); - mReservedUniforms.push_back("env_intensity"); - - mReservedUniforms.push_back("matrixPalette"); - mReservedUniforms.push_back("translationPalette"); - - mReservedUniforms.push_back("screenTex"); - mReservedUniforms.push_back("screenDepth"); - mReservedUniforms.push_back("refTex"); - mReservedUniforms.push_back("eyeVec"); - mReservedUniforms.push_back("time"); - mReservedUniforms.push_back("waveDir1"); - mReservedUniforms.push_back("waveDir2"); - mReservedUniforms.push_back("lightDir"); - mReservedUniforms.push_back("specular"); - mReservedUniforms.push_back("lightExp"); - mReservedUniforms.push_back("waterFogColor"); + mReservedUniforms.push_back("noiseMap"); + mReservedUniforms.push_back("lightFunc"); + mReservedUniforms.push_back("lightMap"); + mReservedUniforms.push_back("bloomMap"); + mReservedUniforms.push_back("projectionMap"); + mReservedUniforms.push_back("norm_mat"); + mReservedUniforms.push_back("texture_gamma"); + + mReservedUniforms.push_back("specular_color"); + mReservedUniforms.push_back("env_intensity"); + + mReservedUniforms.push_back("matrixPalette"); + mReservedUniforms.push_back("translationPalette"); + + mReservedUniforms.push_back("screenTex"); + mReservedUniforms.push_back("screenDepth"); + mReservedUniforms.push_back("refTex"); + mReservedUniforms.push_back("eyeVec"); + mReservedUniforms.push_back("time"); + mReservedUniforms.push_back("waveDir1"); + mReservedUniforms.push_back("waveDir2"); + mReservedUniforms.push_back("lightDir"); + mReservedUniforms.push_back("specular"); + mReservedUniforms.push_back("lightExp"); + mReservedUniforms.push_back("waterFogColor"); mReservedUniforms.push_back("waterFogColorLinear"); - mReservedUniforms.push_back("waterFogDensity"); - mReservedUniforms.push_back("waterFogKS"); - mReservedUniforms.push_back("refScale"); - mReservedUniforms.push_back("waterHeight"); - mReservedUniforms.push_back("waterPlane"); - mReservedUniforms.push_back("normScale"); - mReservedUniforms.push_back("fresnelScale"); - mReservedUniforms.push_back("fresnelOffset"); - mReservedUniforms.push_back("blurMultiplier"); - mReservedUniforms.push_back("sunAngle"); - mReservedUniforms.push_back("scaledAngle"); - mReservedUniforms.push_back("sunAngle2"); - - mReservedUniforms.push_back("camPosLocal"); - - mReservedUniforms.push_back("gWindDir"); - mReservedUniforms.push_back("gSinWaveParams"); - mReservedUniforms.push_back("gGravity"); - - mReservedUniforms.push_back("detail_0"); - mReservedUniforms.push_back("detail_1"); - mReservedUniforms.push_back("detail_2"); - mReservedUniforms.push_back("detail_3"); - mReservedUniforms.push_back("alpha_ramp"); - - mReservedUniforms.push_back("origin"); - mReservedUniforms.push_back("display_gamma"); + mReservedUniforms.push_back("waterFogDensity"); + mReservedUniforms.push_back("waterFogKS"); + mReservedUniforms.push_back("refScale"); + mReservedUniforms.push_back("waterHeight"); + mReservedUniforms.push_back("waterPlane"); + mReservedUniforms.push_back("normScale"); + mReservedUniforms.push_back("fresnelScale"); + mReservedUniforms.push_back("fresnelOffset"); + mReservedUniforms.push_back("blurMultiplier"); + mReservedUniforms.push_back("sunAngle"); + mReservedUniforms.push_back("scaledAngle"); + mReservedUniforms.push_back("sunAngle2"); + + mReservedUniforms.push_back("camPosLocal"); + + mReservedUniforms.push_back("gWindDir"); + mReservedUniforms.push_back("gSinWaveParams"); + mReservedUniforms.push_back("gGravity"); + + mReservedUniforms.push_back("detail_0"); + mReservedUniforms.push_back("detail_1"); + mReservedUniforms.push_back("detail_2"); + mReservedUniforms.push_back("detail_3"); + mReservedUniforms.push_back("alpha_ramp"); + + mReservedUniforms.push_back("origin"); + mReservedUniforms.push_back("display_gamma"); mReservedUniforms.push_back("inscatter"); mReservedUniforms.push_back("sun_size"); @@ -1407,17 +1407,17 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("sun_up_factor"); mReservedUniforms.push_back("moonlight_color"); - llassert(mReservedUniforms.size() == END_RESERVED_UNIFORMS); + llassert(mReservedUniforms.size() == END_RESERVED_UNIFORMS); - std::set<std::string> dupe_check; + std::set<std::string> dupe_check; - for (U32 i = 0; i < mReservedUniforms.size(); ++i) - { - if (dupe_check.find(mReservedUniforms[i]) != dupe_check.end()) - { - LL_ERRS() << "Duplicate reserved uniform name found: " << mReservedUniforms[i] << LL_ENDL; - } - dupe_check.insert(mReservedUniforms[i]); - } + for (U32 i = 0; i < mReservedUniforms.size(); ++i) + { + if (dupe_check.find(mReservedUniforms[i]) != dupe_check.end()) + { + LL_ERRS() << "Duplicate reserved uniform name found: " << mReservedUniforms[i] << LL_ENDL; + } + dupe_check.insert(mReservedUniforms[i]); + } } diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h index 79a24773e1..e655dda98d 100644 --- a/indra/llrender/llshadermgr.h +++ b/indra/llrender/llshadermgr.h @@ -1,25 +1,25 @@ -/** +/** * @file llshadermgr.h * @brief Shader Manager * * $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$ */ @@ -33,8 +33,8 @@ class LLShaderMgr { public: - LLShaderMgr(); - virtual ~LLShaderMgr(); + LLShaderMgr(); + virtual ~LLShaderMgr(); // clang-format off typedef enum @@ -291,23 +291,23 @@ public: } eGLSLReservedUniforms; // clang-format on - // singleton pattern implementation - static LLShaderMgr * instance(); + // singleton pattern implementation + static LLShaderMgr * instance(); - virtual void initAttribsAndUniforms(void); + virtual void initAttribsAndUniforms(void); - BOOL attachShaderFeatures(LLGLSLShader * shader); - void dumpObjectLog(GLuint ret, BOOL warns = TRUE, const std::string& filename = ""); + BOOL attachShaderFeatures(LLGLSLShader * shader); + void dumpObjectLog(GLuint ret, BOOL warns = TRUE, const std::string& filename = ""); void dumpShaderSource(U32 shader_code_count, GLchar** shader_code_text); - BOOL linkProgramObject(GLuint obj, BOOL suppress_errors = FALSE); - BOOL validateProgramObject(GLuint obj); - GLuint loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type, std::map<std::string, std::string>* defines = NULL, S32 texture_index_channels = -1); + BOOL linkProgramObject(GLuint obj, BOOL suppress_errors = FALSE); + BOOL validateProgramObject(GLuint obj); + GLuint loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type, std::map<std::string, std::string>* defines = NULL, S32 texture_index_channels = -1); - // Implemented in the application to actually point to the shader directory. - virtual std::string getShaderDirPrefix(void) = 0; // Pure Virtual + // Implemented in the application to actually point to the shader directory. + virtual std::string getShaderDirPrefix(void) = 0; // Pure Virtual - // Implemented in the application to actually update out of date uniforms for a particular shader - virtual void updateShaderUniforms(LLGLSLShader * shader) = 0; // Pure Virtual + // Implemented in the application to actually update out of date uniforms for a particular shader + virtual void updateShaderUniforms(LLGLSLShader * shader) = 0; // Pure Virtual void initShaderCache(bool enabled, const LLUUID& old_cache_version, const LLUUID& current_cache_version); void clearShaderCache(); @@ -317,14 +317,14 @@ public: bool saveCachedProgramBinary(LLGLSLShader* shader); public: - // Map of shader names to compiled + // Map of shader names to compiled std::map<std::string, GLuint> mVertexShaderObjects; std::map<std::string, GLuint> mFragmentShaderObjects; - //global (reserved slot) shader parameters - std::vector<std::string> mReservedAttribs; + //global (reserved slot) shader parameters + std::vector<std::string> mReservedAttribs; - std::vector<std::string> mReservedUniforms; + std::vector<std::string> mReservedUniforms; struct ProgramBinaryData { @@ -339,8 +339,8 @@ public: protected: - // our parameter manager singleton instance - static LLShaderMgr * sInstance; + // our parameter manager singleton instance + static LLShaderMgr * sInstance; }; //LLShaderMgr 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 diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index de27636c33..c98de6bf06 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llvertexbuffer.cpp * @brief LLVertexBuffer implementation * * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -41,25 +41,25 @@ //helper function, returns first number > v that is a power of 2, or v if v is already a power of 2 U32 nhpo2(U32 v) { - U32 r = 1; - while (r < v) { - r *= 2; - } - return r; + U32 r = 1; + while (r < v) { + r *= 2; + } + return r; } //which power of 2 is i? //assumes i is a power of 2 > 0 U32 wpo2(U32 i) { - llassert(i > 0); - llassert(nhpo2(i) == i); + llassert(i > 0); + llassert(nhpo2(i) == i); - U32 r = 0; + U32 r = 0; - while (i >>= 1) ++r; + while (i >>= 1) ++r; - return r; + return r; } struct CompareMappedRegion @@ -381,7 +381,7 @@ public: Entry& entry = entries.back(); name = entry.mGLName; data = entry.mData; - + entries.pop_back(); if (entries.empty()) { @@ -474,9 +474,9 @@ public: } #if 0 - LL_INFOS() << llformat("(%d/%d)/%d MB (distributed/allocated)/total in VBO Pool. Overhead: %d percent. Hit rate: %d percent", - mDistributed / 1000000, - mAllocated / 1000000, + LL_INFOS() << llformat("(%d/%d)/%d MB (distributed/allocated)/total in VBO Pool. Overhead: %d percent. Hit rate: %d percent", + mDistributed / 1000000, + mAllocated / 1000000, (mAllocated + mReserved) / 1000000, // total bytes ((mAllocated+mReserved-mDistributed)*100)/llmax(mDistributed, (U64) 1), // overhead percent (mHits*100)/llmax(mMisses+mHits, (U32)1)) // hit rate percent @@ -522,7 +522,7 @@ U64 LLVertexBuffer::getBytesAllocated() } //============================================================================ -// +// //static U32 LLVertexBuffer::sGLRenderBuffer = 0; U32 LLVertexBuffer::sGLRenderIndices = 0; @@ -533,50 +533,50 @@ U32 LLVertexBuffer::sVertexCount = 0; //NOTE: each component must be AT LEAST 4 bytes in size to avoid a performance penalty on AMD hardware const U32 LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_MAX] = { - sizeof(LLVector4), // TYPE_VERTEX, - sizeof(LLVector4), // TYPE_NORMAL, - sizeof(LLVector2), // TYPE_TEXCOORD0, - sizeof(LLVector2), // TYPE_TEXCOORD1, - sizeof(LLVector2), // TYPE_TEXCOORD2, - sizeof(LLVector2), // TYPE_TEXCOORD3, - sizeof(LLColor4U), // TYPE_COLOR, - sizeof(LLColor4U), // TYPE_EMISSIVE, only alpha is used currently - sizeof(LLVector4), // TYPE_TANGENT, - sizeof(F32), // TYPE_WEIGHT, - sizeof(LLVector4), // TYPE_WEIGHT4, - sizeof(LLVector4), // TYPE_CLOTHWEIGHT, - sizeof(LLVector4), // TYPE_TEXTURE_INDEX (actually exists as position.w), no extra data, but stride is 16 bytes + sizeof(LLVector4), // TYPE_VERTEX, + sizeof(LLVector4), // TYPE_NORMAL, + sizeof(LLVector2), // TYPE_TEXCOORD0, + sizeof(LLVector2), // TYPE_TEXCOORD1, + sizeof(LLVector2), // TYPE_TEXCOORD2, + sizeof(LLVector2), // TYPE_TEXCOORD3, + sizeof(LLColor4U), // TYPE_COLOR, + sizeof(LLColor4U), // TYPE_EMISSIVE, only alpha is used currently + sizeof(LLVector4), // TYPE_TANGENT, + sizeof(F32), // TYPE_WEIGHT, + sizeof(LLVector4), // TYPE_WEIGHT4, + sizeof(LLVector4), // TYPE_CLOTHWEIGHT, + sizeof(LLVector4), // TYPE_TEXTURE_INDEX (actually exists as position.w), no extra data, but stride is 16 bytes }; static const std::string vb_type_name[] = { - "TYPE_VERTEX", - "TYPE_NORMAL", - "TYPE_TEXCOORD0", - "TYPE_TEXCOORD1", - "TYPE_TEXCOORD2", - "TYPE_TEXCOORD3", - "TYPE_COLOR", - "TYPE_EMISSIVE", - "TYPE_TANGENT", - "TYPE_WEIGHT", - "TYPE_WEIGHT4", - "TYPE_CLOTHWEIGHT", - "TYPE_TEXTURE_INDEX", - "TYPE_MAX", - "TYPE_INDEX", + "TYPE_VERTEX", + "TYPE_NORMAL", + "TYPE_TEXCOORD0", + "TYPE_TEXCOORD1", + "TYPE_TEXCOORD2", + "TYPE_TEXCOORD3", + "TYPE_COLOR", + "TYPE_EMISSIVE", + "TYPE_TANGENT", + "TYPE_WEIGHT", + "TYPE_WEIGHT4", + "TYPE_CLOTHWEIGHT", + "TYPE_TEXTURE_INDEX", + "TYPE_MAX", + "TYPE_INDEX", }; const U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] = { - GL_TRIANGLES, - GL_TRIANGLE_STRIP, - GL_TRIANGLE_FAN, - GL_POINTS, - GL_LINES, - GL_LINE_STRIP, - GL_QUADS, - GL_LINE_LOOP, + GL_TRIANGLES, + GL_TRIANGLE_STRIP, + GL_TRIANGLE_FAN, + GL_POINTS, + GL_LINES, + GL_LINE_STRIP, + GL_QUADS, + GL_LINE_LOOP, }; //static @@ -598,7 +598,7 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask) } } else - { //was disabled + { //was disabled if (data_mask & mask) { //needs to be enabled glEnableVertexAttribArray(loc); @@ -627,18 +627,18 @@ void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos) void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, U32 num_indices, const U16* indicesp) { LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX; - llassert(LLGLSLShader::sCurBoundShaderPtr != NULL); + llassert(LLGLSLShader::sCurBoundShaderPtr != NULL); + + gGL.syncMatrices(); - gGL.syncMatrices(); + U32 mask = LLVertexBuffer::MAP_VERTEX; + if (tc) + { + mask = mask | LLVertexBuffer::MAP_TEXCOORD0; + } - U32 mask = LLVertexBuffer::MAP_VERTEX; - if (tc) - { - mask = mask | LLVertexBuffer::MAP_TEXCOORD0; - } + unbind(); - unbind(); - gGL.begin(mode); if (tc != nullptr) @@ -672,32 +672,32 @@ bool LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_of llassert(start < (U32)mNumVerts); llassert(end < (U32)mNumVerts); - if (start >= (U32) mNumVerts || - end >= (U32) mNumVerts) - { - LL_ERRS() << "Bad vertex buffer draw range: [" << start << ", " << end << "] vs " << mNumVerts << LL_ENDL; - } + if (start >= (U32) mNumVerts || + end >= (U32) mNumVerts) + { + LL_ERRS() << "Bad vertex buffer draw range: [" << start << ", " << end << "] vs " << mNumVerts << LL_ENDL; + } - llassert(mNumIndices >= 0); + llassert(mNumIndices >= 0); - if (indices_offset >= (U32) mNumIndices || - indices_offset + count > (U32) mNumIndices) - { - LL_ERRS() << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << LL_ENDL; - } + if (indices_offset >= (U32) mNumIndices || + indices_offset + count > (U32) mNumIndices) + { + LL_ERRS() << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << LL_ENDL; + } - { - U16* idx = (U16*) mMappedIndexData+indices_offset; - for (U32 i = 0; i < count; ++i) - { + { + U16* idx = (U16*) mMappedIndexData+indices_offset; + for (U32 i = 0; i < count; ++i) + { llassert(idx[i] >= start); llassert(idx[i] <= end); - if (idx[i] < start || idx[i] > end) - { - LL_ERRS() << "Index out of range: " << idx[i] << " not in [" << start << ", " << end << "]" << LL_ENDL; - } - } + if (idx[i] < start || idx[i] > end) + { + LL_ERRS() << "Index out of range: " << idx[i] << " not in [" << start << ", " << end << "]" << LL_ENDL; + } + } LLVector4a* v = (LLVector4a*)mMappedData; @@ -709,29 +709,29 @@ bool LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_of } } - LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + + if (shader && shader->mFeatures.mIndexedTextureChannels > 1) + { + LLVector4a* v = (LLVector4a*) mMappedData; - if (shader && shader->mFeatures.mIndexedTextureChannels > 1) - { - LLVector4a* v = (LLVector4a*) mMappedData; - - for (U32 i = start; i < end; i++) - { + for (U32 i = start; i < end; i++) + { U32 idx = (U32) (v[i][3]+0.25f); - if (idx >= shader->mFeatures.mIndexedTextureChannels) - { - LL_ERRS() << "Bad texture index found in vertex data stream." << LL_ENDL; - } - } - } - } + if (idx >= shader->mFeatures.mIndexedTextureChannels) + { + LL_ERRS() << "Bad texture index found in vertex data stream." << LL_ENDL; + } + } + } + } return true; } #ifdef LL_PROFILER_ENABLE_RENDER_DOC void LLVertexBuffer::setLabel(const char* label) { - LL_LABEL_OBJECT_GL(GL_BUFFER, mGLBuffer, strlen(label), label); + LL_LABEL_OBJECT_GL(GL_BUFFER, mGLBuffer, strlen(label), label); } #endif @@ -756,7 +756,7 @@ void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const llassert(first + count <= mNumVerts); llassert(mGLBuffer == sGLRenderBuffer); llassert(mGLIndices == sGLRenderIndices); - + gGL.syncMatrices(); glDrawArrays(sGLMode[mode], first, count); } @@ -778,21 +778,21 @@ void LLVertexBuffer::initClass(LLWindow* window) #endif } -//static +//static void LLVertexBuffer::unbind() { glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - sGLRenderBuffer = 0; - sGLRenderIndices = 0; + sGLRenderBuffer = 0; + sGLRenderIndices = 0; } //static void LLVertexBuffer::cleanupClass() { - unbind(); - + unbind(); + delete sVBOPool; sVBOPool = nullptr; @@ -812,71 +812,71 @@ void LLVertexBuffer::cleanupClass() //---------------------------------------------------------------------------- -LLVertexBuffer::LLVertexBuffer(U32 typemask) -: LLRefCount(), - mTypeMask(typemask) +LLVertexBuffer::LLVertexBuffer(U32 typemask) +: LLRefCount(), + mTypeMask(typemask) { - //zero out offsets - for (U32 i = 0; i < TYPE_MAX; i++) - { - mOffsets[i] = 0; - } + //zero out offsets + for (U32 i = 0; i < TYPE_MAX; i++) + { + mOffsets[i] = 0; + } } //static U32 LLVertexBuffer::calcOffsets(const U32& typemask, U32* offsets, U32 num_vertices) { U32 offset = 0; - for (U32 i=0; i<TYPE_TEXTURE_INDEX; i++) - { - U32 mask = 1<<i; - if (typemask & mask) - { - if (offsets && LLVertexBuffer::sTypeSize[i]) - { - offsets[i] = offset; - offset += LLVertexBuffer::sTypeSize[i]*num_vertices; - offset = (offset + 0xF) & ~0xF; - } - } - } - - offsets[TYPE_TEXTURE_INDEX] = offsets[TYPE_VERTEX] + 12; - - return offset; + for (U32 i=0; i<TYPE_TEXTURE_INDEX; i++) + { + U32 mask = 1<<i; + if (typemask & mask) + { + if (offsets && LLVertexBuffer::sTypeSize[i]) + { + offsets[i] = offset; + offset += LLVertexBuffer::sTypeSize[i]*num_vertices; + offset = (offset + 0xF) & ~0xF; + } + } + } + + offsets[TYPE_TEXTURE_INDEX] = offsets[TYPE_VERTEX] + 12; + + return offset; } -//static +//static U32 LLVertexBuffer::calcVertexSize(const U32& typemask) { U32 size = 0; - for (U32 i = 0; i < TYPE_TEXTURE_INDEX; i++) - { - U32 mask = 1<<i; - if (typemask & mask) - { - size += LLVertexBuffer::sTypeSize[i]; - } - } - - return size; + for (U32 i = 0; i < TYPE_TEXTURE_INDEX; i++) + { + U32 mask = 1<<i; + if (typemask & mask) + { + size += LLVertexBuffer::sTypeSize[i]; + } + } + + return size; } // protected, use unref() //virtual LLVertexBuffer::~LLVertexBuffer() { - destroyGLBuffer(); - destroyGLIndices(); - - if (mMappedData) - { - LL_ERRS() << "Failed to clear vertex buffer's vertices" << LL_ENDL; - } - if (mMappedIndexData) - { - LL_ERRS() << "Failed to clear vertex buffer's indices" << LL_ENDL; - } + destroyGLBuffer(); + destroyGLIndices(); + + if (mMappedData) + { + LL_ERRS() << "Failed to clear vertex buffer's vertices" << LL_ENDL; + } + if (mMappedIndexData) + { + LL_ERRS() << "Failed to clear vertex buffer's indices" << LL_ENDL; + } }; //---------------------------------------------------------------------------- @@ -914,54 +914,54 @@ void LLVertexBuffer::genIndices(U32 size) bool LLVertexBuffer::createGLBuffer(U32 size) { - if (mGLBuffer || mMappedData) - { - destroyGLBuffer(); - } - - if (size == 0) - { - return true; - } - - bool success = true; - - genBuffer(size); - - if (!mMappedData) - { - success = false; - } - return success; + if (mGLBuffer || mMappedData) + { + destroyGLBuffer(); + } + + if (size == 0) + { + return true; + } + + bool success = true; + + genBuffer(size); + + if (!mMappedData) + { + success = false; + } + return success; } bool LLVertexBuffer::createGLIndices(U32 size) { - if (mGLIndices) - { - destroyGLIndices(); - } - - if (size == 0) - { - return true; - } - - bool success = true; - - genIndices(size); - - if (!mMappedIndexData) - { - success = false; - } - return success; + if (mGLIndices) + { + destroyGLIndices(); + } + + if (size == 0) + { + return true; + } + + bool success = true; + + genIndices(size); + + if (!mMappedIndexData) + { + success = false; + } + return success; } void LLVertexBuffer::destroyGLBuffer() { - if (mGLBuffer || mMappedData) - { + if (mGLBuffer || mMappedData) + { LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX; //llassert(sVBOPool); if (sVBOPool) @@ -972,13 +972,13 @@ void LLVertexBuffer::destroyGLBuffer() mSize = 0; mGLBuffer = 0; mMappedData = nullptr; - } + } } void LLVertexBuffer::destroyGLIndices() { - if (mGLIndices || mMappedIndexData) - { + if (mGLIndices || mMappedIndexData) + { LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX; //llassert(sVBOPool); if (sVBOPool) @@ -989,22 +989,22 @@ void LLVertexBuffer::destroyGLIndices() mIndicesSize = 0; mGLIndices = 0; mMappedIndexData = nullptr; - } + } } bool LLVertexBuffer::updateNumVerts(U32 nverts) { - llassert(nverts >= 0); + llassert(nverts >= 0); - bool success = true; + bool success = true; - if (nverts > 65536) - { - LL_WARNS() << "Vertex buffer overflow!" << LL_ENDL; - nverts = 65536; - } + if (nverts > 65536) + { + LL_WARNS() << "Vertex buffer overflow!" << LL_ENDL; + nverts = 65536; + } - U32 needed_size = calcOffsets(mTypeMask, mOffsets, nverts); + U32 needed_size = calcOffsets(mTypeMask, mOffsets, nverts); if (needed_size != mSize) { @@ -1012,42 +1012,42 @@ bool LLVertexBuffer::updateNumVerts(U32 nverts) } llassert(mSize == needed_size); - mNumVerts = nverts; - return success; + mNumVerts = nverts; + return success; } bool LLVertexBuffer::updateNumIndices(U32 nindices) { - llassert(nindices >= 0); + llassert(nindices >= 0); - bool success = true; + bool success = true; - U32 needed_size = sizeof(U16) * nindices; + U32 needed_size = sizeof(U16) * nindices; - if (needed_size != mIndicesSize) - { - success &= createGLIndices(needed_size); - } + if (needed_size != mIndicesSize) + { + success &= createGLIndices(needed_size); + } llassert(mIndicesSize == needed_size); - mNumIndices = nindices; - return success; + mNumIndices = nindices; + return success; } bool LLVertexBuffer::allocateBuffer(U32 nverts, U32 nindices) { - if (nverts < 0 || nindices < 0 || - nverts > 65536) - { - LL_ERRS() << "Bad vertex buffer allocation: " << nverts << " : " << nindices << LL_ENDL; - } + if (nverts < 0 || nindices < 0 || + nverts > 65536) + { + LL_ERRS() << "Bad vertex buffer allocation: " << nverts << " : " << nindices << LL_ENDL; + } + + bool success = true; - bool success = true; + success &= updateNumVerts(nverts); + success &= updateNumIndices(nindices); - success &= updateNumVerts(nverts); - success &= updateNumIndices(nindices); - - return success; + return success; } //---------------------------------------------------------------------------- @@ -1056,17 +1056,17 @@ bool LLVertexBuffer::allocateBuffer(U32 nverts, U32 nindices) // otherwise return false bool expand_region(LLVertexBuffer::MappedRegion& region, U32 start, U32 end) { - - if (end < region.mStart || - start > region.mEnd) - { //gap exists, do not merge - return false; - } + + if (end < region.mStart || + start > region.mEnd) + { //gap exists, do not merge + return false; + } region.mStart = llmin(region.mStart, start); region.mEnd = llmax(region.mEnd, end); - return true; + return true; } @@ -1074,7 +1074,7 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, U32 start, U32 end) U8* LLVertexBuffer::mapVertexBuffer(LLVertexBuffer::AttributeType type, U32 index, S32 count) { LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX; - + if (count == -1) { count = mNumVerts - index; @@ -1083,24 +1083,24 @@ U8* LLVertexBuffer::mapVertexBuffer(LLVertexBuffer::AttributeType type, U32 inde U32 start = mOffsets[type] + sTypeSize[type] * index; U32 end = start + sTypeSize[type] * count-1; - bool flagged = false; - // flag region as mapped - for (U32 i = 0; i < mMappedVertexRegions.size(); ++i) - { - MappedRegion& region = mMappedVertexRegions[i]; + bool flagged = false; + // flag region as mapped + for (U32 i = 0; i < mMappedVertexRegions.size(); ++i) + { + MappedRegion& region = mMappedVertexRegions[i]; if (expand_region(region, start, end)) { flagged = true; break; } - } + } - if (!flagged) - { - //didn't expand an existing region, make a new one + if (!flagged) + { + //didn't expand an existing region, make a new one mMappedVertexRegions.push_back({ start, end }); - } - + } + return mMappedData+mOffsets[type]+sTypeSize[type]*index; } @@ -1108,11 +1108,11 @@ U8* LLVertexBuffer::mapVertexBuffer(LLVertexBuffer::AttributeType type, U32 inde U8* LLVertexBuffer::mapIndexBuffer(U32 index, S32 count) { LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX; - - if (count == -1) - { - count = mNumIndices-index; - } + + if (count == -1) + { + count = mNumIndices-index; + } U32 start = sizeof(U16) * index; U32 end = start + sizeof(U16) * count-1; @@ -1175,23 +1175,23 @@ void LLVertexBuffer::unmapBuffer() } }; - if (!mMappedVertexRegions.empty()) - { + if (!mMappedVertexRegions.empty()) + { LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - vertex"); if (sGLRenderBuffer != mGLBuffer) { glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer); sGLRenderBuffer = mGLBuffer; } - + U32 start = 0; U32 end = 0; std::sort(mMappedVertexRegions.begin(), mMappedVertexRegions.end(), SortMappedRegion()); - for (U32 i = 0; i < mMappedVertexRegions.size(); ++i) - { - const MappedRegion& region = mMappedVertexRegions[i]; + for (U32 i = 0; i < mMappedVertexRegions.size(); ++i) + { + const MappedRegion& region = mMappedVertexRegions[i]; if (region.mStart == end + 1) { end = region.mEnd; @@ -1202,15 +1202,15 @@ void LLVertexBuffer::unmapBuffer() start = region.mStart; end = region.mEnd; } - } + } flush_vbo(GL_ARRAY_BUFFER, start, end, (U8*)mMappedData + start); - mMappedVertexRegions.clear(); - } - - if (!mMappedIndexRegions.empty()) - { + mMappedVertexRegions.clear(); + } + + if (!mMappedIndexRegions.empty()) + { LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - index"); if (mGLIndices != sGLRenderIndices) @@ -1240,114 +1240,114 @@ void LLVertexBuffer::unmapBuffer() flush_vbo(GL_ELEMENT_ARRAY_BUFFER, start, end, (U8*)mMappedIndexData + start); - mMappedIndexRegions.clear(); - } + mMappedIndexRegions.clear(); + } } //---------------------------------------------------------------------------- template <class T,LLVertexBuffer::AttributeType type> struct VertexBufferStrider { - typedef LLStrider<T> strider_t; - static bool get(LLVertexBuffer& vbo, - strider_t& strider, - S32 index, S32 count) - { - if (type == LLVertexBuffer::TYPE_INDEX) - { - U8* ptr = vbo.mapIndexBuffer(index, count); - - if (ptr == NULL) - { - LL_WARNS() << "mapIndexBuffer failed!" << LL_ENDL; - return false; - } - - strider = (T*)ptr; - strider.setStride(0); - return true; - } - else if (vbo.hasDataType(type)) - { + typedef LLStrider<T> strider_t; + static bool get(LLVertexBuffer& vbo, + strider_t& strider, + S32 index, S32 count) + { + if (type == LLVertexBuffer::TYPE_INDEX) + { + U8* ptr = vbo.mapIndexBuffer(index, count); + + if (ptr == NULL) + { + LL_WARNS() << "mapIndexBuffer failed!" << LL_ENDL; + return false; + } + + strider = (T*)ptr; + strider.setStride(0); + return true; + } + else if (vbo.hasDataType(type)) + { U32 stride = LLVertexBuffer::sTypeSize[type]; - U8* ptr = vbo.mapVertexBuffer(type, index, count); - - if (ptr == NULL) - { - LL_WARNS() << "mapVertexBuffer failed!" << LL_ENDL; - return false; - } - - strider = (T*)ptr; - strider.setStride(stride); - return true; - } - else - { - LL_ERRS() << "VertexBufferStrider could not find valid vertex data." << LL_ENDL; - } - return false; - } + U8* ptr = vbo.mapVertexBuffer(type, index, count); + + if (ptr == NULL) + { + LL_WARNS() << "mapVertexBuffer failed!" << LL_ENDL; + return false; + } + + strider = (T*)ptr; + strider.setStride(stride); + return true; + } + else + { + LL_ERRS() << "VertexBufferStrider could not find valid vertex data." << LL_ENDL; + } + return false; + } }; bool LLVertexBuffer::getVertexStrider(LLStrider<LLVector3>& strider, U32 index, S32 count) { - return VertexBufferStrider<LLVector3,TYPE_VERTEX>::get(*this, strider, index, count); + return VertexBufferStrider<LLVector3,TYPE_VERTEX>::get(*this, strider, index, count); } bool LLVertexBuffer::getVertexStrider(LLStrider<LLVector4a>& strider, U32 index, S32 count) { - return VertexBufferStrider<LLVector4a,TYPE_VERTEX>::get(*this, strider, index, count); + return VertexBufferStrider<LLVector4a,TYPE_VERTEX>::get(*this, strider, index, count); } bool LLVertexBuffer::getIndexStrider(LLStrider<U16>& strider, U32 index, S32 count) { - return VertexBufferStrider<U16,TYPE_INDEX>::get(*this, strider, index, count); + return VertexBufferStrider<U16,TYPE_INDEX>::get(*this, strider, index, count); } bool LLVertexBuffer::getTexCoord0Strider(LLStrider<LLVector2>& strider, U32 index, S32 count) { - return VertexBufferStrider<LLVector2,TYPE_TEXCOORD0>::get(*this, strider, index, count); + return VertexBufferStrider<LLVector2,TYPE_TEXCOORD0>::get(*this, strider, index, count); } bool LLVertexBuffer::getTexCoord1Strider(LLStrider<LLVector2>& strider, U32 index, S32 count) { - return VertexBufferStrider<LLVector2,TYPE_TEXCOORD1>::get(*this, strider, index, count); + return VertexBufferStrider<LLVector2,TYPE_TEXCOORD1>::get(*this, strider, index, count); } bool LLVertexBuffer::getTexCoord2Strider(LLStrider<LLVector2>& strider, U32 index, S32 count) { - return VertexBufferStrider<LLVector2,TYPE_TEXCOORD2>::get(*this, strider, index, count); + return VertexBufferStrider<LLVector2,TYPE_TEXCOORD2>::get(*this, strider, index, count); } bool LLVertexBuffer::getNormalStrider(LLStrider<LLVector3>& strider, U32 index, S32 count) { - return VertexBufferStrider<LLVector3,TYPE_NORMAL>::get(*this, strider, index, count); + return VertexBufferStrider<LLVector3,TYPE_NORMAL>::get(*this, strider, index, count); } bool LLVertexBuffer::getTangentStrider(LLStrider<LLVector3>& strider, U32 index, S32 count) { - return VertexBufferStrider<LLVector3,TYPE_TANGENT>::get(*this, strider, index, count); + return VertexBufferStrider<LLVector3,TYPE_TANGENT>::get(*this, strider, index, count); } bool LLVertexBuffer::getTangentStrider(LLStrider<LLVector4a>& strider, U32 index, S32 count) { - return VertexBufferStrider<LLVector4a,TYPE_TANGENT>::get(*this, strider, index, count); + return VertexBufferStrider<LLVector4a,TYPE_TANGENT>::get(*this, strider, index, count); } bool LLVertexBuffer::getColorStrider(LLStrider<LLColor4U>& strider, U32 index, S32 count) { - return VertexBufferStrider<LLColor4U,TYPE_COLOR>::get(*this, strider, index, count); + return VertexBufferStrider<LLColor4U,TYPE_COLOR>::get(*this, strider, index, count); } bool LLVertexBuffer::getEmissiveStrider(LLStrider<LLColor4U>& strider, U32 index, S32 count) { - return VertexBufferStrider<LLColor4U,TYPE_EMISSIVE>::get(*this, strider, index, count); + return VertexBufferStrider<LLColor4U,TYPE_EMISSIVE>::get(*this, strider, index, count); } bool LLVertexBuffer::getWeightStrider(LLStrider<F32>& strider, U32 index, S32 count) { - return VertexBufferStrider<F32,TYPE_WEIGHT>::get(*this, strider, index, count); + return VertexBufferStrider<F32,TYPE_WEIGHT>::get(*this, strider, index, count); } bool LLVertexBuffer::getWeight4Strider(LLStrider<LLVector4>& strider, U32 index, S32 count) { - return VertexBufferStrider<LLVector4,TYPE_WEIGHT4>::get(*this, strider, index, count); + return VertexBufferStrider<LLVector4,TYPE_WEIGHT4>::get(*this, strider, index, count); } bool LLVertexBuffer::getClothWeightStrider(LLStrider<LLVector4>& strider, U32 index, S32 count) { - return VertexBufferStrider<LLVector4,TYPE_CLOTHWEIGHT>::get(*this, strider, index, count); + return VertexBufferStrider<LLVector4,TYPE_CLOTHWEIGHT>::get(*this, strider, index, count); } //---------------------------------------------------------------------------- @@ -1367,7 +1367,7 @@ void LLVertexBuffer::setBuffer() // this Vertex Buffer must provide all necessary attributes for currently bound shader llassert_msg((data_mask & mTypeMask) == data_mask, - "Attribute mask mismatch! mTypeMask should be a superset of data_mask. data_mask: 0x" + "Attribute mask mismatch! mTypeMask should be a superset of data_mask. data_mask: 0x" << std::hex << data_mask << " mTypeMask: 0x" << mTypeMask << " Missing: 0x" << (data_mask & ~mTypeMask) << std::dec); if (sGLRenderBuffer != mGLBuffer) @@ -1382,7 +1382,7 @@ void LLVertexBuffer::setBuffer() setupVertexBuffer(); sLastMask = data_mask; } - + if (mGLIndices != sGLRenderIndices) { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices); diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h index f2d146d4bb..545917cdec 100644 --- a/indra/llrender/llvertexbuffer.h +++ b/indra/llrender/llvertexbuffer.h @@ -1,25 +1,25 @@ -/** +/** * @file llvertexbuffer.h * @brief LLVertexBuffer wrapper for OpengGL vertex buffer objects * * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -51,51 +51,51 @@ //============================================================================ -// base class +// base class class LLPrivateMemoryPool; class LLVertexBuffer final : public LLRefCount { public: - struct MappedRegion - { + struct MappedRegion + { U32 mStart; U32 mEnd; - }; + }; - LLVertexBuffer(const LLVertexBuffer& rhs) - { - *this = rhs; - } + LLVertexBuffer(const LLVertexBuffer& rhs) + { + *this = rhs; + } - const LLVertexBuffer& operator=(const LLVertexBuffer& rhs) - { - LL_ERRS() << "Illegal operation!" << LL_ENDL; - return *this; - } + const LLVertexBuffer& operator=(const LLVertexBuffer& rhs) + { + LL_ERRS() << "Illegal operation!" << LL_ENDL; + return *this; + } - static void initClass(LLWindow* window); - static void cleanupClass(); - static void setupClientArrays(U32 data_mask); - static void drawArrays(U32 mode, const std::vector<LLVector3>& pos); - static void drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, U32 num_indices, const U16* indicesp); + static void initClass(LLWindow* window); + static void cleanupClass(); + static void setupClientArrays(U32 data_mask); + static void drawArrays(U32 mode, const std::vector<LLVector3>& pos); + static void drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, U32 num_indices, const U16* indicesp); - static void unbind(); //unbind any bound vertex buffer + static void unbind(); //unbind any bound vertex buffer - //get the size of a vertex with the given typemask - static U32 calcVertexSize(const U32& typemask); + //get the size of a vertex with the given typemask + static U32 calcVertexSize(const U32& typemask); - //get the size of a buffer with the given typemask and vertex count - //fill offsets with the offset of each vertex component array into the buffer - // indexed by the following enum - static U32 calcOffsets(const U32& typemask, U32* offsets, U32 num_vertices); + //get the size of a buffer with the given typemask and vertex count + //fill offsets with the offset of each vertex component array into the buffer + // indexed by the following enum + static U32 calcOffsets(const U32& typemask, U32* offsets, U32 num_vertices); - //WARNING -- when updating these enums you MUST - // 1 - update LLVertexBuffer::sTypeSize + //WARNING -- when updating these enums you MUST + // 1 - update LLVertexBuffer::sTypeSize // 2 - update LLVertexBuffer::vb_type_name - // 3 - add a strider accessor - // 4 - modify LLVertexBuffer::setupVertexBuffer - // 6 - modify LLViewerShaderMgr::mReservedAttribs - + // 3 - add a strider accessor + // 4 - modify LLVertexBuffer::setupVertexBuffer + // 6 - modify LLViewerShaderMgr::mReservedAttribs + // clang-format off enum AttributeType { // Shader attribute name, set in LLShaderMgr::initAttribsAndUniforms() TYPE_VERTEX = 0, // "position" @@ -112,158 +112,158 @@ public: TYPE_CLOTHWEIGHT, // "clothing" TYPE_TEXTURE_INDEX, // "texture_index" TYPE_MAX, // TYPE_MAX is the size/boundary marker for attributes that go in the vertex buffer - TYPE_INDEX, // TYPE_INDEX is beyond _MAX because it lives in a separate (index) buffer + TYPE_INDEX, // TYPE_INDEX is beyond _MAX because it lives in a separate (index) buffer }; // clang-format on enum { - MAP_VERTEX = (1<<TYPE_VERTEX), - MAP_NORMAL = (1<<TYPE_NORMAL), - MAP_TEXCOORD0 = (1<<TYPE_TEXCOORD0), - MAP_TEXCOORD1 = (1<<TYPE_TEXCOORD1), - MAP_TEXCOORD2 = (1<<TYPE_TEXCOORD2), - MAP_TEXCOORD3 = (1<<TYPE_TEXCOORD3), - MAP_COLOR = (1<<TYPE_COLOR), - MAP_EMISSIVE = (1<<TYPE_EMISSIVE), - MAP_TANGENT = (1<<TYPE_TANGENT), - MAP_WEIGHT = (1<<TYPE_WEIGHT), - MAP_WEIGHT4 = (1<<TYPE_WEIGHT4), - MAP_CLOTHWEIGHT = (1<<TYPE_CLOTHWEIGHT), - MAP_TEXTURE_INDEX = (1<<TYPE_TEXTURE_INDEX), - }; - + MAP_VERTEX = (1<<TYPE_VERTEX), + MAP_NORMAL = (1<<TYPE_NORMAL), + MAP_TEXCOORD0 = (1<<TYPE_TEXCOORD0), + MAP_TEXCOORD1 = (1<<TYPE_TEXCOORD1), + MAP_TEXCOORD2 = (1<<TYPE_TEXCOORD2), + MAP_TEXCOORD3 = (1<<TYPE_TEXCOORD3), + MAP_COLOR = (1<<TYPE_COLOR), + MAP_EMISSIVE = (1<<TYPE_EMISSIVE), + MAP_TANGENT = (1<<TYPE_TANGENT), + MAP_WEIGHT = (1<<TYPE_WEIGHT), + MAP_WEIGHT4 = (1<<TYPE_WEIGHT4), + MAP_CLOTHWEIGHT = (1<<TYPE_CLOTHWEIGHT), + MAP_TEXTURE_INDEX = (1<<TYPE_TEXTURE_INDEX), + }; + protected: - friend class LLRender; + friend class LLRender; - ~LLVertexBuffer(); // use unref() + ~LLVertexBuffer(); // use unref() - void setupVertexBuffer(); + void setupVertexBuffer(); - void genBuffer(U32 size); - void genIndices(U32 size); - bool createGLBuffer(U32 size); - bool createGLIndices(U32 size); - void destroyGLBuffer(); - void destroyGLIndices(); - bool updateNumVerts(U32 nverts); - bool updateNumIndices(U32 nindices); + void genBuffer(U32 size); + void genIndices(U32 size); + bool createGLBuffer(U32 size); + bool createGLIndices(U32 size); + void destroyGLBuffer(); + void destroyGLIndices(); + bool updateNumVerts(U32 nverts); + bool updateNumIndices(U32 nindices); public: - LLVertexBuffer(U32 typemask); - + LLVertexBuffer(U32 typemask); + // allocate buffer - bool allocateBuffer(U32 nverts, U32 nindices); + bool allocateBuffer(U32 nverts, U32 nindices); - // map for data access (see also getFooStrider below) - U8* mapVertexBuffer(AttributeType type, U32 index, S32 count = -1); - U8* mapIndexBuffer(U32 index, S32 count = -1); - void unmapBuffer(); + // map for data access (see also getFooStrider below) + U8* mapVertexBuffer(AttributeType type, U32 index, S32 count = -1); + U8* mapIndexBuffer(U32 index, S32 count = -1); + void unmapBuffer(); - // set for rendering + // set for rendering // assumes (and will assert on) the following: // - this buffer has no pending unampBuffer call // - a shader is currently bound // - This buffer has sufficient attributes within it to satisfy the needs of the currently bound shader - void setBuffer(); - - // Only call each getVertexPointer, etc, once before calling unmapBuffer() - // call unmapBuffer() after calls to getXXXStrider() before any cals to setBuffer() - // example: - // vb->getVertexBuffer(verts); - // vb->getNormalStrider(norms); - // setVertsNorms(verts, norms); - // vb->unmapBuffer(); - bool getVertexStrider(LLStrider<LLVector3>& strider, U32 index=0, S32 count = -1); - bool getVertexStrider(LLStrider<LLVector4a>& strider, U32 index=0, S32 count = -1); - bool getIndexStrider(LLStrider<U16>& strider, U32 index=0, S32 count = -1); - bool getTexCoord0Strider(LLStrider<LLVector2>& strider, U32 index=0, S32 count = -1); - bool getTexCoord1Strider(LLStrider<LLVector2>& strider, U32 index=0, S32 count = -1); - bool getTexCoord2Strider(LLStrider<LLVector2>& strider, U32 index=0, S32 count = -1); - bool getNormalStrider(LLStrider<LLVector3>& strider, U32 index=0, S32 count = -1); - bool getTangentStrider(LLStrider<LLVector3>& strider, U32 index=0, S32 count = -1); - bool getTangentStrider(LLStrider<LLVector4a>& strider, U32 index=0, S32 count = -1); - bool getColorStrider(LLStrider<LLColor4U>& strider, U32 index=0, S32 count = -1); - bool getEmissiveStrider(LLStrider<LLColor4U>& strider, U32 index=0, S32 count = -1); - bool getWeightStrider(LLStrider<F32>& strider, U32 index=0, S32 count = -1); - bool getWeight4Strider(LLStrider<LLVector4>& strider, U32 index=0, S32 count = -1); - bool getClothWeightStrider(LLStrider<LLVector4>& strider, U32 index=0, S32 count = -1); + void setBuffer(); + + // Only call each getVertexPointer, etc, once before calling unmapBuffer() + // call unmapBuffer() after calls to getXXXStrider() before any cals to setBuffer() + // example: + // vb->getVertexBuffer(verts); + // vb->getNormalStrider(norms); + // setVertsNorms(verts, norms); + // vb->unmapBuffer(); + bool getVertexStrider(LLStrider<LLVector3>& strider, U32 index=0, S32 count = -1); + bool getVertexStrider(LLStrider<LLVector4a>& strider, U32 index=0, S32 count = -1); + bool getIndexStrider(LLStrider<U16>& strider, U32 index=0, S32 count = -1); + bool getTexCoord0Strider(LLStrider<LLVector2>& strider, U32 index=0, S32 count = -1); + bool getTexCoord1Strider(LLStrider<LLVector2>& strider, U32 index=0, S32 count = -1); + bool getTexCoord2Strider(LLStrider<LLVector2>& strider, U32 index=0, S32 count = -1); + bool getNormalStrider(LLStrider<LLVector3>& strider, U32 index=0, S32 count = -1); + bool getTangentStrider(LLStrider<LLVector3>& strider, U32 index=0, S32 count = -1); + bool getTangentStrider(LLStrider<LLVector4a>& strider, U32 index=0, S32 count = -1); + bool getColorStrider(LLStrider<LLColor4U>& strider, U32 index=0, S32 count = -1); + bool getEmissiveStrider(LLStrider<LLColor4U>& strider, U32 index=0, S32 count = -1); + bool getWeightStrider(LLStrider<F32>& strider, U32 index=0, S32 count = -1); + bool getWeight4Strider(LLStrider<LLVector4>& strider, U32 index=0, S32 count = -1); + bool getClothWeightStrider(LLStrider<LLVector4>& strider, U32 index=0, S32 count = -1); bool getBasecolorTexcoordStrider(LLStrider<LLVector2>& strider, U32 index=0, S32 count = -1); bool getNormalTexcoordStrider(LLStrider<LLVector2>& strider, U32 index=0, S32 count = -1); bool getMetallicRoughnessTexcoordStrider(LLStrider<LLVector2>& strider, U32 index=0, S32 count = -1); bool getEmissiveTexcoordStrider(LLStrider<LLVector2>& strider, U32 index=0, S32 count = -1); - + void setPositionData(const LLVector4a* data); void setTexCoordData(const LLVector2* data); void setColorData(const LLColor4U* data); - U32 getNumVerts() const { return mNumVerts; } - U32 getNumIndices() const { return mNumIndices; } - - U32 getTypeMask() const { return mTypeMask; } - bool hasDataType(AttributeType type) const { return ((1 << type) & getTypeMask()); } + U32 getNumVerts() const { return mNumVerts; } + U32 getNumIndices() const { return mNumIndices; } + + U32 getTypeMask() const { return mTypeMask; } + bool hasDataType(AttributeType type) const { return ((1 << type) & getTypeMask()); } U32 getSize() const { return mSize; } - U32 getIndicesSize() const { return mIndicesSize; } - U8* getMappedData() const { return mMappedData; } - U8* getMappedIndices() const { return mMappedIndexData; } - U32 getOffset(AttributeType type) const { return mOffsets[type]; } - + U32 getIndicesSize() const { return mIndicesSize; } + U8* getMappedData() const { return mMappedData; } + U8* getMappedIndices() const { return mMappedIndexData; } + U32 getOffset(AttributeType type) const { return mOffsets[type]; } + // these functions assume (and assert on) the current VBO being bound // Detailed error checking can be enabled by setting gDebugGL to true - void draw(U32 mode, U32 count, U32 indices_offset) const; - void drawArrays(U32 mode, U32 offset, U32 count) const; + void draw(U32 mode, U32 count, U32 indices_offset) const; + void drawArrays(U32 mode, U32 offset, U32 count) const; void drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const; - //for debugging, validate data in given range is valid - bool validateRange(U32 start, U32 end, U32 count, U32 offset) const; + //for debugging, validate data in given range is valid + bool validateRange(U32 start, U32 end, U32 count, U32 offset) const; + + #ifdef LL_PROFILER_ENABLE_RENDER_DOC + void setLabel(const char* label); + #endif - #ifdef LL_PROFILER_ENABLE_RENDER_DOC - void setLabel(const char* label); - #endif - -protected: - U32 mGLBuffer = 0; // GL VBO handle - U32 mGLIndices = 0; // GL IBO handle - U32 mNumVerts = 0; // Number of vertices allocated - U32 mNumIndices = 0; // Number of indices allocated - U32 mOffsets[TYPE_MAX]; // byte offsets into mMappedData of each attribute +protected: + U32 mGLBuffer = 0; // GL VBO handle + U32 mGLIndices = 0; // GL IBO handle + U32 mNumVerts = 0; // Number of vertices allocated + U32 mNumIndices = 0; // Number of indices allocated + U32 mOffsets[TYPE_MAX]; // byte offsets into mMappedData of each attribute + + U8* mMappedData = nullptr; // pointer to currently mapped data (NULL if unmapped) + U8* mMappedIndexData = nullptr; // pointer to currently mapped indices (NULL if unmapped) - U8* mMappedData = nullptr; // pointer to currently mapped data (NULL if unmapped) - U8* mMappedIndexData = nullptr; // pointer to currently mapped indices (NULL if unmapped) + U32 mTypeMask = 0; // bitmask of present vertex attributes - U32 mTypeMask = 0; // bitmask of present vertex attributes - - U32 mSize = 0; // size in bytes of mMappedData - U32 mIndicesSize = 0; // size in bytes of mMappedIndexData + U32 mSize = 0; // size in bytes of mMappedData + U32 mIndicesSize = 0; // size in bytes of mMappedIndexData - std::vector<MappedRegion> mMappedVertexRegions; // list of mMappedData byte ranges that must be sent to GL - std::vector<MappedRegion> mMappedIndexRegions; // list of mMappedIndexData byte ranges that must be sent to GL + std::vector<MappedRegion> mMappedVertexRegions; // list of mMappedData byte ranges that must be sent to GL + std::vector<MappedRegion> mMappedIndexRegions; // list of mMappedIndexData byte ranges that must be sent to GL private: // DEPRECATED - // These function signatures are deprecated, but for some reason + // These function signatures are deprecated, but for some reason // there are classes in an external package that depend on LLVertexBuffer - + // TODO: move these classes into viewer repository friend class LLNavShapeVBOManager; friend class LLNavMeshVBOManager; - + LLVertexBuffer(U32 typemask, U32 usage) : LLVertexBuffer(typemask) {} - bool allocateBuffer(S32 nverts, S32 nindices, BOOL create) { return allocateBuffer(nverts, nindices); } + bool allocateBuffer(S32 nverts, S32 nindices, BOOL create) { return allocateBuffer(nverts, nindices); } public: static U64 getBytesAllocated(); - static const U32 sTypeSize[TYPE_MAX]; - static const U32 sGLMode[LLRender::NUM_MODES]; - static U32 sGLRenderBuffer; - static U32 sGLRenderIndices; - static U32 sLastMask; - static U32 sVertexCount; + static const U32 sTypeSize[TYPE_MAX]; + static const U32 sGLMode[LLRender::NUM_MODES]; + static U32 sGLRenderBuffer; + static U32 sGLRenderIndices; + static U32 sLastMask; + static U32 sVertexCount; }; #ifdef LL_PROFILER_ENABLE_RENDER_DOC |