diff options
Diffstat (limited to 'indra/newview/lldrawpoolalpha.cpp')
| -rw-r--r-- | indra/newview/lldrawpoolalpha.cpp | 1870 | 
1 files changed, 935 insertions, 935 deletions
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index 5a868ae887..7e4c1287ff 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -1,935 +1,935 @@ -/**  - * @file lldrawpoolalpha.cpp - * @brief LLDrawPoolAlpha 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$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "lldrawpoolalpha.h" - -#include "llglheaders.h" -#include "llviewercontrol.h" -#include "llcriticaldamp.h" -#include "llfasttimer.h" -#include "llrender.h" - -#include "llcubemap.h" -#include "llsky.h" -#include "lldrawable.h" -#include "llface.h" -#include "llviewercamera.h" -#include "llviewertexturelist.h"	// For debugging -#include "llviewerobjectlist.h" // For debugging -#include "llviewerwindow.h" -#include "pipeline.h" -#include "llviewershadermgr.h" -#include "llviewerregion.h" -#include "lldrawpoolwater.h" -#include "llspatialpartition.h" -#include "llglcommonfunc.h" -#include "llvoavatar.h" - -#include "llenvironment.h" - -bool LLDrawPoolAlpha::sShowDebugAlpha = false; - -#define current_shader (LLGLSLShader::sCurBoundShaderPtr) - -LLVector4 LLDrawPoolAlpha::sWaterPlane; - -// minimum alpha before discarding a fragment -static const F32 MINIMUM_ALPHA = 0.004f; // ~ 1/255 - -// minimum alpha before discarding a fragment when rendering impostors -static const F32 MINIMUM_IMPOSTOR_ALPHA = 0.1f; - -LLDrawPoolAlpha::LLDrawPoolAlpha(U32 type) : -		LLRenderPass(type), target_shader(NULL), -		mColorSFactor(LLRender::BF_UNDEF), mColorDFactor(LLRender::BF_UNDEF), -		mAlphaSFactor(LLRender::BF_UNDEF), mAlphaDFactor(LLRender::BF_UNDEF) -{ -  -} - -LLDrawPoolAlpha::~LLDrawPoolAlpha() -{ -} - - -void LLDrawPoolAlpha::prerender() -{ -	mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT); - -    // TODO: is this even necessay?  These are probably set to never discard -    LLViewerFetchedTexture::sFlatNormalImagep->addTextureStats(1024.f*1024.f); -    LLViewerFetchedTexture::sWhiteImagep->addTextureStats(1024.f * 1024.f); -} - -S32 LLDrawPoolAlpha::getNumPostDeferredPasses()  -{  -    return 1; -} - -// set some common parameters on the given shader to prepare for alpha rendering -static void prepare_alpha_shader(LLGLSLShader* shader, bool textureGamma, bool deferredEnvironment, F32 water_sign) -{ -    static LLCachedControl<F32> displayGamma(gSavedSettings, "RenderDeferredDisplayGamma"); -    F32 gamma = displayGamma; - -    static LLStaticHashedString waterSign("waterSign"); - -    // Does this deferred shader need environment uniforms set such as sun_dir, etc. ? -    // NOTE: We don't actually need a gbuffer since we are doing forward rendering (for transparency) post deferred rendering -    // TODO: bindDeferredShader() probably should have the updating of the environment uniforms factored out into updateShaderEnvironmentUniforms() -    // i.e. shaders\class1\deferred\alphaF.glsl -    if (deferredEnvironment) -    { -        shader->mCanBindFast = false; -    } -     -    shader->bind(); -    shader->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f / 2.2f)); - -    if (LLPipeline::sRenderingHUDs) -    { // for HUD attachments, only the pre-water pass is executed and we never want to clip anything -        LLVector4 near_clip(0, 0, -1, 0); -        shader->uniform1f(waterSign, 1.f); -        shader->uniform4fv(LLShaderMgr::WATER_WATERPLANE, 1, near_clip.mV); -    } -    else -    { -        shader->uniform1f(waterSign, water_sign); -        shader->uniform4fv(LLShaderMgr::WATER_WATERPLANE, 1, LLDrawPoolAlpha::sWaterPlane.mV); -    } - -    if (LLPipeline::sImpostorRender) -    { -        shader->setMinimumAlpha(MINIMUM_IMPOSTOR_ALPHA); -    } -    else -    { -        shader->setMinimumAlpha(MINIMUM_ALPHA); -    } -    if (textureGamma) -    { -        shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f); -    } - -    //also prepare rigged variant -    if (shader->mRiggedVariant && shader->mRiggedVariant != shader) -    {  -        prepare_alpha_shader(shader->mRiggedVariant, textureGamma, deferredEnvironment, water_sign); -    } -} - -extern bool gCubeSnapshot; - -void LLDrawPoolAlpha::renderPostDeferred(S32 pass)  -{  -    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; - -    if (LLPipeline::isWaterClip() && getType() == LLDrawPool::POOL_ALPHA_PRE_WATER) -    { // don't render alpha objects on the other side of the water plane if water is opaque -        return; -    } - -    F32 water_sign = 1.f; - -    if (getType() == LLDrawPool::POOL_ALPHA_PRE_WATER) -    { -        water_sign = -1.f; -    } - -    if (LLPipeline::sUnderWaterRender) -    { -        water_sign *= -1.f; -    } - -    // prepare shaders -    llassert(LLPipeline::sRenderDeferred); - -    emissive_shader = &gDeferredEmissiveProgram; -    prepare_alpha_shader(emissive_shader, true, false, water_sign); - -    pbr_emissive_shader = &gPBRGlowProgram; -    prepare_alpha_shader(pbr_emissive_shader, true, false, water_sign); - - -    fullbright_shader   =  -        (LLPipeline::sImpostorRender) ? &gDeferredFullbrightAlphaMaskProgram : -        (LLPipeline::sRenderingHUDs) ? &gHUDFullbrightAlphaMaskAlphaProgram : -        &gDeferredFullbrightAlphaMaskAlphaProgram; -    prepare_alpha_shader(fullbright_shader, true, true, water_sign); - -    simple_shader   =  -        (LLPipeline::sImpostorRender) ? &gDeferredAlphaImpostorProgram : -        (LLPipeline::sRenderingHUDs) ? &gHUDAlphaProgram : -        &gDeferredAlphaProgram; - -    prepare_alpha_shader(simple_shader, false, true, water_sign); //prime simple shader (loads shadow relevant uniforms) - -    LLGLSLShader* materialShader = gDeferredMaterialProgram; -    for (int i = 0; i < LLMaterial::SHADER_COUNT*2; ++i) -    { -        prepare_alpha_shader(&materialShader[i], false, true, water_sign); -    } - -    pbr_shader =  -        (LLPipeline::sRenderingHUDs) ? &gHUDPBRAlphaProgram :  -        &gDeferredPBRAlphaProgram; - -    prepare_alpha_shader(pbr_shader, false, true, water_sign); - -    // explicitly unbind here so render loop doesn't make assumptions about the last shader -    // already being setup for rendering -    LLGLSLShader::unbind(); - -    if (!LLPipeline::sRenderingHUDs) -    { -        // first pass, render rigged objects only and render to depth buffer -        forwardRender(true); -    } - -    // second pass, regular forward alpha rendering -    forwardRender(); - -    // final pass, render to depth for depth of field effects -    if (!LLPipeline::sImpostorRender && gSavedSettings.getBOOL("RenderDepthOfField") && !gCubeSnapshot && !LLPipeline::sRenderingHUDs && getType() == LLDrawPool::POOL_ALPHA_POST_WATER) -    {  -        //update depth buffer sampler -        simple_shader = fullbright_shader = &gDeferredFullbrightAlphaMaskProgram; - -        simple_shader->bind(); -        simple_shader->setMinimumAlpha(0.33f); - -        // mask off color buffer writes as we're only writing to depth buffer -        gGL.setColorMask(false, false); - -        // If the face is more than 90% transparent, then don't update the Depth buffer for Dof -        // We don't want the nearly invisible objects to cause of DoF effects -        renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2,  -            true); // <--- discard mostly transparent faces - -        gGL.setColorMask(true, false); -    } -} - -void LLDrawPoolAlpha::forwardRender(bool rigged) -{ -    gPipeline.enableLightsDynamic(); - -    LLGLSPipelineAlpha gls_pipeline_alpha; - -    //enable writing to alpha for emissive effects -    gGL.setColorMask(true, true); - -    bool write_depth = rigged || -        LLDrawPoolWater::sSkipScreenCopy -        // we want depth written so that rendered alpha will -        // contribute to the alpha mask used for impostors -        || LLPipeline::sImpostorRenderAlphaDepthPass -        || getType() == LLDrawPoolAlpha::POOL_ALPHA_PRE_WATER; // needed for accurate water fog - - -    LLGLDepthTest depth(GL_TRUE, write_depth ? GL_TRUE : GL_FALSE); - -    mColorSFactor = LLRender::BF_SOURCE_ALPHA;           // } regular alpha blend -    mColorDFactor = LLRender::BF_ONE_MINUS_SOURCE_ALPHA; // } -    mAlphaSFactor = LLRender::BF_ZERO;                         // } glow suppression -    mAlphaDFactor = LLRender::BF_ONE_MINUS_SOURCE_ALPHA;       // } -    gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor); - -    // If the face is more than 90% transparent, then don't update the Depth buffer for Dof -    // We don't want the nearly invisible objects to cause of DoF effects -    renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2, false, rigged); - -    gGL.setColorMask(true, false); - -    if (!rigged) -    { //render "highlight alpha" on final non-rigged pass -        // NOTE -- hacky call here protected by !rigged instead of alongside "forwardRender" -        // so renderDebugAlpha is executed while gls_pipeline_alpha and depth GL state -        // variables above are still in scope -        renderDebugAlpha(); -    } -} - -void LLDrawPoolAlpha::renderDebugAlpha() -{ -	if (sShowDebugAlpha) -	{ -        gHighlightProgram.bind(); -        gGL.diffuseColor4f(1, 0, 0, 1); -        gGL.getTexUnit(0)->bindFast(LLViewerFetchedTexture::getSmokeImage()); - - -        renderAlphaHighlight(); - -		pushUntexturedBatches(LLRenderPass::PASS_ALPHA_MASK); -		pushUntexturedBatches(LLRenderPass::PASS_ALPHA_INVISIBLE); - -		// Material alpha mask -		gGL.diffuseColor4f(0, 0, 1, 1); -		pushUntexturedBatches(LLRenderPass::PASS_MATERIAL_ALPHA_MASK); -		pushUntexturedBatches(LLRenderPass::PASS_NORMMAP_MASK); -		pushUntexturedBatches(LLRenderPass::PASS_SPECMAP_MASK); -		pushUntexturedBatches(LLRenderPass::PASS_NORMSPEC_MASK); -		pushUntexturedBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK); -        pushUntexturedBatches(LLRenderPass::PASS_GLTF_PBR_ALPHA_MASK); - -		gGL.diffuseColor4f(0, 1, 0, 1); -        pushUntexturedBatches(LLRenderPass::PASS_INVISIBLE); - -        gHighlightProgram.mRiggedVariant->bind(); -        gGL.diffuseColor4f(1, 0, 0, 1); - -        pushRiggedBatches(LLRenderPass::PASS_ALPHA_MASK_RIGGED, false); -        pushRiggedBatches(LLRenderPass::PASS_ALPHA_INVISIBLE_RIGGED, false); - -        // Material alpha mask -        gGL.diffuseColor4f(0, 0, 1, 1); -        pushRiggedBatches(LLRenderPass::PASS_MATERIAL_ALPHA_MASK_RIGGED, false); -        pushRiggedBatches(LLRenderPass::PASS_NORMMAP_MASK_RIGGED, false); -        pushRiggedBatches(LLRenderPass::PASS_SPECMAP_MASK_RIGGED, false); -        pushRiggedBatches(LLRenderPass::PASS_NORMSPEC_MASK_RIGGED, false); -        pushRiggedBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK_RIGGED, false); -        pushRiggedBatches(LLRenderPass::PASS_GLTF_PBR_ALPHA_MASK_RIGGED, false); - -        gGL.diffuseColor4f(0, 1, 0, 1); -        pushRiggedBatches(LLRenderPass::PASS_INVISIBLE_RIGGED, false); -        LLGLSLShader::sCurBoundShaderPtr->unbind(); -	} -} - -void LLDrawPoolAlpha::renderAlphaHighlight() -{ -    for (int pass = 0; pass < 2; ++pass) -    { //two passes, one rigged and one not -        LLVOAvatar* lastAvatar = nullptr; -        U64 lastMeshId = 0; - -        LLCullResult::sg_iterator begin = pass == 0 ? gPipeline.beginAlphaGroups() : gPipeline.beginRiggedAlphaGroups(); -        LLCullResult::sg_iterator end = pass == 0 ? gPipeline.endAlphaGroups() : gPipeline.endRiggedAlphaGroups(); - -        for (LLCullResult::sg_iterator i = begin; i != end; ++i) -        { -            LLSpatialGroup* group = *i; -            if (group->getSpatialPartition()->mRenderByGroup && -                !group->isDead()) -            { -                LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[LLRenderPass::PASS_ALPHA+pass]; // <-- hacky + pass to use PASS_ALPHA_RIGGED on second pass  - -                for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) -                { -                    LLDrawInfo& params = **k; - -                    bool rigged = (params.mAvatar != nullptr); -                    gHighlightProgram.bind(rigged); -                    gGL.diffuseColor4f(1, 0, 0, 1); - -                    if (rigged) -                    { -                        if (lastAvatar != params.mAvatar || -                            lastMeshId != params.mSkinInfo->mHash) -                        { -                            if (!uploadMatrixPalette(params)) -                            { -                                continue; -                            } -                            lastAvatar = params.mAvatar; -                            lastMeshId = params.mSkinInfo->mHash; -                        } -                    } - -                    LLRenderPass::applyModelMatrix(params); -                    params.mVertexBuffer->setBuffer(); -                    params.mVertexBuffer->drawRange(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset); -                } -            } -        } -    } - -    // make sure static version of highlight shader is bound before returning -    gHighlightProgram.bind(); -} - -inline bool IsFullbright(LLDrawInfo& params) -{ -    return params.mFullbright; -} - -inline bool IsMaterial(LLDrawInfo& params) -{ -    return params.mMaterial != nullptr; -} - -inline bool IsEmissive(LLDrawInfo& params) -{ -    return params.mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_EMISSIVE); -} - -inline void Draw(LLDrawInfo* draw, U32 mask) -{ -    draw->mVertexBuffer->setBuffer(); -    LLRenderPass::applyModelMatrix(*draw); -	draw->mVertexBuffer->drawRange(LLRender::TRIANGLES, draw->mStart, draw->mEnd, draw->mCount, draw->mOffset);                     -} - -bool LLDrawPoolAlpha::TexSetup(LLDrawInfo* draw, bool use_material) -{ -    bool tex_setup = false; - -    if (draw->mGLTFMaterial) -    { -        if (draw->mTextureMatrix) -        { -            tex_setup = true; -            gGL.getTexUnit(0)->activate(); -            gGL.matrixMode(LLRender::MM_TEXTURE); -            gGL.loadMatrix((GLfloat*)draw->mTextureMatrix->mMatrix); -            gPipeline.mTextureMatrixOps++; -        } -    } -    else -    { -        if (!LLPipeline::sRenderingHUDs && use_material && current_shader) -        { -            if (draw->mNormalMap) -            { -                current_shader->bindTexture(LLShaderMgr::BUMP_MAP, draw->mNormalMap); -            } - -            if (draw->mSpecularMap) -            { -                current_shader->bindTexture(LLShaderMgr::SPECULAR_MAP, draw->mSpecularMap); -            } -        } -        else if (current_shader == simple_shader || current_shader == simple_shader->mRiggedVariant) -        { -            current_shader->bindTexture(LLShaderMgr::BUMP_MAP, LLViewerFetchedTexture::sFlatNormalImagep); -            current_shader->bindTexture(LLShaderMgr::SPECULAR_MAP, LLViewerFetchedTexture::sWhiteImagep); -        } -        if (draw->mTextureList.size() > 1) -        { -            for (U32 i = 0; i < draw->mTextureList.size(); ++i) -            { -                if (draw->mTextureList[i].notNull()) -                { -                    gGL.getTexUnit(i)->bindFast(draw->mTextureList[i]); -                } -            } -        } -        else -        { //not batching textures or batch has only 1 texture -- might need a texture matrix -            if (draw->mTexture.notNull()) -            { -                if (use_material) -                { -                    current_shader->bindTexture(LLShaderMgr::DIFFUSE_MAP, draw->mTexture); -                } -                else -                { -                    gGL.getTexUnit(0)->bindFast(draw->mTexture); -                } - -                if (draw->mTextureMatrix) -                { -                    tex_setup = true; -                    gGL.getTexUnit(0)->activate(); -                    gGL.matrixMode(LLRender::MM_TEXTURE); -                    gGL.loadMatrix((GLfloat*)draw->mTextureMatrix->mMatrix); -                    gPipeline.mTextureMatrixOps++; -                } -            } -            else -            { -                gGL.getTexUnit(0)->unbindFast(LLTexUnit::TT_TEXTURE); -            } -        } -    } -     -    return tex_setup; -} - -void LLDrawPoolAlpha::RestoreTexSetup(bool tex_setup) -{ -    if (tex_setup) -	{ -		gGL.getTexUnit(0)->activate(); -        gGL.matrixMode(LLRender::MM_TEXTURE); -		gGL.loadIdentity(); -		gGL.matrixMode(LLRender::MM_MODELVIEW); -	} -} - -void LLDrawPoolAlpha::drawEmissive(LLDrawInfo* draw) -{ -    LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 1.f); -    draw->mVertexBuffer->setBuffer(); -	draw->mVertexBuffer->drawRange(LLRender::TRIANGLES, draw->mStart, draw->mEnd, draw->mCount, draw->mOffset); -} - - -void LLDrawPoolAlpha::renderEmissives(std::vector<LLDrawInfo*>& emissives) -{ -    emissive_shader->bind(); -    emissive_shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 1.f); - -    for (LLDrawInfo* draw : emissives) -    { -        bool tex_setup = TexSetup(draw, false); -        drawEmissive(draw); -        RestoreTexSetup(tex_setup); -    } -} - -void LLDrawPoolAlpha::renderPbrEmissives(std::vector<LLDrawInfo*>& emissives) -{ -    pbr_emissive_shader->bind(); - -    for (LLDrawInfo* draw : emissives) -    { -        llassert(draw->mGLTFMaterial); -        LLGLDisable cull_face(draw->mGLTFMaterial->mDoubleSided ? GL_CULL_FACE : 0); -        draw->mGLTFMaterial->bind(draw->mTexture); -        draw->mVertexBuffer->setBuffer(); -        draw->mVertexBuffer->drawRange(LLRender::TRIANGLES, draw->mStart, draw->mEnd, draw->mCount, draw->mOffset); -    } -} - -void LLDrawPoolAlpha::renderRiggedEmissives(std::vector<LLDrawInfo*>& emissives) -{ -    LLGLDepthTest depth(GL_TRUE, GL_FALSE); //disable depth writes since "emissive" is additive so sorting doesn't matter -    LLGLSLShader* shader = emissive_shader->mRiggedVariant; -    shader->bind(); -    shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 1.f); - -    LLVOAvatar* lastAvatar = nullptr; -    U64 lastMeshId = 0; - -    for (LLDrawInfo* draw : emissives) -    { -        LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("Emissives"); - -        bool tex_setup = TexSetup(draw, false); -        if (lastAvatar != draw->mAvatar || lastMeshId != draw->mSkinInfo->mHash) -        { -            if (!uploadMatrixPalette(*draw)) -            { // failed to upload matrix palette, skip rendering -                continue; -            } -            lastAvatar = draw->mAvatar; -            lastMeshId = draw->mSkinInfo->mHash; -        } -        drawEmissive(draw); -        RestoreTexSetup(tex_setup); -    } -} - -void LLDrawPoolAlpha::renderRiggedPbrEmissives(std::vector<LLDrawInfo*>& emissives) -{ -    LLGLDepthTest depth(GL_TRUE, GL_FALSE); //disable depth writes since "emissive" is additive so sorting doesn't matter -    pbr_emissive_shader->bind(true); -     -    LLVOAvatar* lastAvatar = nullptr; -    U64 lastMeshId = 0; - -    for (LLDrawInfo* draw : emissives) -    { -        if (lastAvatar != draw->mAvatar || lastMeshId != draw->mSkinInfo->mHash) -        { -            if (!uploadMatrixPalette(*draw)) -            { // failed to upload matrix palette, skip rendering -                continue; -            } -            lastAvatar = draw->mAvatar; -            lastMeshId = draw->mSkinInfo->mHash; -        } - -        LLGLDisable cull_face(draw->mGLTFMaterial->mDoubleSided ? GL_CULL_FACE : 0); -        draw->mGLTFMaterial->bind(draw->mTexture); -        draw->mVertexBuffer->setBuffer(); -        draw->mVertexBuffer->drawRange(LLRender::TRIANGLES, draw->mStart, draw->mEnd, draw->mCount, draw->mOffset); -    } -} - -void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only, bool rigged) -{ -    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; -    bool initialized_lighting = false; -	bool light_enabled = true; - -    LLVOAvatar* lastAvatar = nullptr; -    U64 lastMeshId = 0; -    LLGLSLShader* lastAvatarShader = nullptr; - -    LLCullResult::sg_iterator begin; -    LLCullResult::sg_iterator end; - -    if (rigged) -    { -        begin = gPipeline.beginRiggedAlphaGroups(); -        end = gPipeline.endRiggedAlphaGroups(); -    } -    else -    { -        begin = gPipeline.beginAlphaGroups(); -        end = gPipeline.endAlphaGroups(); -    } -     -    LLEnvironment& env = LLEnvironment::instance(); -    F32 water_height = env.getWaterHeight(); - -    bool above_water = getType() == LLDrawPool::POOL_ALPHA_POST_WATER; -    if (LLPipeline::sUnderWaterRender) -    { -        above_water = !above_water; -    } - - -    for (LLCullResult::sg_iterator i = begin; i != end; ++i) -	{ -        LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("renderAlpha - group"); -		LLSpatialGroup* group = *i; -		llassert(group); -		llassert(group->getSpatialPartition()); - -		if (group->getSpatialPartition()->mRenderByGroup && -		    !group->isDead()) -		{ - -            LLSpatialBridge* bridge = group->getSpatialPartition()->asBridge(); -            const LLVector4a* ext = bridge ? bridge->getSpatialExtents() : group->getExtents(); - -            if (!LLPipeline::sRenderingHUDs) // ignore above/below water for HUD render -            { -                if (above_water) -                { // reject any spatial groups that have no part above water -                    if (ext[1].getF32ptr()[2] < water_height) -                    { -                        continue; -                    } -                } -                else -                { // reject any spatial groups that he no part below water -                    if (ext[0].getF32ptr()[2] > water_height) -                    { -                        continue; -                    } -                } -            } - -            static std::vector<LLDrawInfo*> emissives; -            static std::vector<LLDrawInfo*> rigged_emissives; -            static std::vector<LLDrawInfo*> pbr_emissives; -            static std::vector<LLDrawInfo*> pbr_rigged_emissives; - -            emissives.resize(0); -            rigged_emissives.resize(0); -            pbr_emissives.resize(0); -            pbr_rigged_emissives.resize(0); - -			bool is_particle_or_hud_particle = group->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_PARTICLE -													  || group->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_HUD_PARTICLE; - -			bool disable_cull = is_particle_or_hud_particle; -			LLGLDisable cull(disable_cull ? GL_CULL_FACE : 0); - -			LLSpatialGroup::drawmap_elem_t& draw_info = rigged ? group->mDrawMap[LLRenderPass::PASS_ALPHA_RIGGED] : group->mDrawMap[LLRenderPass::PASS_ALPHA]; - -            for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k)	 -			{ -				LLDrawInfo& params = **k; -                if ((bool)params.mAvatar != rigged) -                { -                    continue; -                } - -                LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("ra - push batch"); - -                LLRenderPass::applyModelMatrix(params); - -                LLMaterial* mat = NULL; -                LLGLTFMaterial *gltf_mat = params.mGLTFMaterial;  - -                LLGLDisable cull_face(gltf_mat && gltf_mat->mDoubleSided ? GL_CULL_FACE : 0); - -                if (gltf_mat && gltf_mat->mAlphaMode == LLGLTFMaterial::ALPHA_MODE_BLEND) -                { -                    target_shader = pbr_shader; -                    if (params.mAvatar != nullptr) -                    { -                        target_shader = target_shader->mRiggedVariant; -                    } - -                    // shader must be bound before LLGLTFMaterial::bind -                    if (current_shader != target_shader) -                    { -                        gPipeline.bindDeferredShaderFast(*target_shader); -                    } - -                    params.mGLTFMaterial->bind(params.mTexture); -                } -                else -                { -                    mat = LLPipeline::sRenderingHUDs ? nullptr : params.mMaterial; - -                    if (params.mFullbright) -                    { -                        // Turn off lighting if it hasn't already been so. -                        if (light_enabled || !initialized_lighting) -                        { -                            initialized_lighting = true; -                            target_shader = fullbright_shader; - -                            light_enabled = false; -                        } -                    } -                    // Turn on lighting if it isn't already. -                    else if (!light_enabled || !initialized_lighting) -                    { -                        initialized_lighting = true; -                        target_shader = simple_shader; -                        light_enabled = true; -                    } - -                    if (LLPipeline::sRenderingHUDs) -                    { -                        target_shader = fullbright_shader; -                    } -                    else if (mat) -                    { -                        U32 mask = params.mShaderMask; - -                        llassert(mask < LLMaterial::SHADER_COUNT); -                        target_shader = &(gDeferredMaterialProgram[mask]); -                    } -                    else if (!params.mFullbright) -                    { -                        target_shader = simple_shader; -                    } -                    else -                    { -                        target_shader = fullbright_shader; -                    } - -                    if (params.mAvatar != nullptr) -                    { -                        llassert(target_shader->mRiggedVariant != nullptr); -                        target_shader = target_shader->mRiggedVariant; -                    } - -                    if (current_shader != target_shader) -                    {// If we need shaders, and we're not ALREADY using the proper shader, then bind it -                    // (this way we won't rebind shaders unnecessarily). -                        gPipeline.bindDeferredShaderFast(*target_shader); - -                        if (params.mFullbright) -                        { // make sure the bind the exposure map for fullbright shaders so they can cancel out exposure -                            S32 channel = target_shader->enableTexture(LLShaderMgr::EXPOSURE_MAP); -                            if (channel > -1) -                            { -                                gGL.getTexUnit(channel)->bind(&gPipeline.mExposureMap); -                            } -                        } -                    } - -                    LLVector4 spec_color(1, 1, 1, 1); -                    F32 env_intensity = 0.0f; -                    F32 brightness = 1.0f; - -                    // We have a material.  Supply the appropriate data here. -                    if (mat) -                    { -                        spec_color = params.mSpecColor; -                        env_intensity = params.mEnvIntensity; -                        brightness = params.mFullbright ? 1.f : 0.f; -                    } - -                    if (current_shader) -                    { -                        current_shader->uniform4f(LLShaderMgr::SPECULAR_COLOR, spec_color.mV[0], spec_color.mV[1], spec_color.mV[2], spec_color.mV[3]); -                        current_shader->uniform1f(LLShaderMgr::ENVIRONMENT_INTENSITY, env_intensity); -                        current_shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, brightness); -                    } -                } - -                if (params.mAvatar != nullptr) -                { -                    if (lastAvatar != params.mAvatar || -                        lastMeshId != params.mSkinInfo->mHash || -                        lastAvatarShader != LLGLSLShader::sCurBoundShaderPtr) -                    { -                        if (!uploadMatrixPalette(params)) -                        { -                            continue; -                        } -                        lastAvatar = params.mAvatar; -                        lastMeshId = params.mSkinInfo->mHash; -                        lastAvatarShader = LLGLSLShader::sCurBoundShaderPtr; -                    } -                } - -                bool tex_setup = TexSetup(¶ms, (mat != nullptr)); - -				{ -					gGL.blendFunc((LLRender::eBlendFactor) params.mBlendFuncSrc, (LLRender::eBlendFactor) params.mBlendFuncDst, mAlphaSFactor, mAlphaDFactor); - -                    bool reset_minimum_alpha = false; -                    if (!LLPipeline::sImpostorRender && -                        params.mBlendFuncDst != LLRender::BF_SOURCE_ALPHA && -                        params.mBlendFuncSrc != LLRender::BF_SOURCE_ALPHA) -                    { // this draw call has a custom blend function that may require rendering of "invisible" fragments -                        current_shader->setMinimumAlpha(0.f); -                        reset_minimum_alpha = true; -                    } -                     -                    params.mVertexBuffer->setBuffer(); -                    params.mVertexBuffer->drawRange(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset); - -                    if (reset_minimum_alpha) -                    { -                        current_shader->setMinimumAlpha(MINIMUM_ALPHA); -                    } -				} - -				// If this alpha mesh has glow, then draw it a second time to add the destination-alpha (=glow).  Interleaving these state-changing calls is expensive, but glow must be drawn Z-sorted with alpha. -				if (getType() != LLDrawPool::POOL_ALPHA_PRE_WATER && -					params.mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_EMISSIVE)) -				{ -                    if (params.mAvatar != nullptr) -                    { -                        if (params.mGLTFMaterial.isNull()) -                        { -                            rigged_emissives.push_back(¶ms); -                        } -                        else -                        { -                            pbr_rigged_emissives.push_back(¶ms); -                        } -                    } -                    else -                    { -                        if (params.mGLTFMaterial.isNull()) -                        { -                            emissives.push_back(¶ms); -                        } -                        else -                        { -                            pbr_emissives.push_back(¶ms); -                        } -                    } -				} -			 -				if (tex_setup) -				{ -					gGL.getTexUnit(0)->activate(); -                    gGL.matrixMode(LLRender::MM_TEXTURE); -					gGL.loadIdentity(); -					gGL.matrixMode(LLRender::MM_MODELVIEW); -				} -			} - -            // render emissive faces into alpha channel for bloom effects -            if (!depth_only) -            { -                gPipeline.enableLightsDynamic(); - -                // install glow-accumulating blend mode -                // don't touch color, add to alpha (glow) -                gGL.blendFunc(LLRender::BF_ZERO, LLRender::BF_ONE, LLRender::BF_ONE, LLRender::BF_ONE); - -                bool rebind = false; -                LLGLSLShader* lastShader = current_shader; -                if (!emissives.empty()) -                { -                    light_enabled = true; -                    renderEmissives(emissives); -                    rebind = true; -                } - -                if (!pbr_emissives.empty()) -                { -                    light_enabled = true; -                    renderPbrEmissives(pbr_emissives); -                    rebind = true; -                } - -                if (!rigged_emissives.empty()) -                { -                    light_enabled = true; -                    renderRiggedEmissives(rigged_emissives); -                    rebind = true; -                } - -                if (!pbr_rigged_emissives.empty()) -                { -                    light_enabled = true; -                    renderRiggedPbrEmissives(pbr_rigged_emissives); -                    rebind = true; -                } - -                // restore our alpha blend mode -                gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor); - -                if (lastShader && rebind) -                { -                    lastShader->bind(); -                } -            } -		} -	} - -	gGL.setSceneBlendType(LLRender::BT_ALPHA); - -	LLVertexBuffer::unbind(); - -	if (!light_enabled) -	{ -		gPipeline.enableLightsDynamic(); -	} -} - -bool LLDrawPoolAlpha::uploadMatrixPalette(const LLDrawInfo& params) -{ -    if (params.mAvatar.isNull()) -    { -        return false; -    } -    const LLVOAvatar::MatrixPaletteCache& mpc = params.mAvatar.get()->updateSkinInfoMatrixPalette(params.mSkinInfo); -    U32 count = mpc.mMatrixPalette.size(); - -    if (count == 0) -    { -        //skin info not loaded yet, don't render -        return false; -    } - -    LLGLSLShader::sCurBoundShaderPtr->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX, -        count, -        false, -        (GLfloat*)&(mpc.mGLMp[0])); - -    return true; -} +/**
 + * @file lldrawpoolalpha.cpp
 + * @brief LLDrawPoolAlpha 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$
 + */
 +
 +#include "llviewerprecompiledheaders.h"
 +
 +#include "lldrawpoolalpha.h"
 +
 +#include "llglheaders.h"
 +#include "llviewercontrol.h"
 +#include "llcriticaldamp.h"
 +#include "llfasttimer.h"
 +#include "llrender.h"
 +
 +#include "llcubemap.h"
 +#include "llsky.h"
 +#include "lldrawable.h"
 +#include "llface.h"
 +#include "llviewercamera.h"
 +#include "llviewertexturelist.h"    // For debugging
 +#include "llviewerobjectlist.h" // For debugging
 +#include "llviewerwindow.h"
 +#include "pipeline.h"
 +#include "llviewershadermgr.h"
 +#include "llviewerregion.h"
 +#include "lldrawpoolwater.h"
 +#include "llspatialpartition.h"
 +#include "llglcommonfunc.h"
 +#include "llvoavatar.h"
 +
 +#include "llenvironment.h"
 +
 +bool LLDrawPoolAlpha::sShowDebugAlpha = false;
 +
 +#define current_shader (LLGLSLShader::sCurBoundShaderPtr)
 +
 +LLVector4 LLDrawPoolAlpha::sWaterPlane;
 +
 +// minimum alpha before discarding a fragment
 +static const F32 MINIMUM_ALPHA = 0.004f; // ~ 1/255
 +
 +// minimum alpha before discarding a fragment when rendering impostors
 +static const F32 MINIMUM_IMPOSTOR_ALPHA = 0.1f;
 +
 +LLDrawPoolAlpha::LLDrawPoolAlpha(U32 type) :
 +        LLRenderPass(type), target_shader(NULL),
 +        mColorSFactor(LLRender::BF_UNDEF), mColorDFactor(LLRender::BF_UNDEF),
 +        mAlphaSFactor(LLRender::BF_UNDEF), mAlphaDFactor(LLRender::BF_UNDEF)
 +{
 +
 +}
 +
 +LLDrawPoolAlpha::~LLDrawPoolAlpha()
 +{
 +}
 +
 +
 +void LLDrawPoolAlpha::prerender()
 +{
 +    mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT);
 +
 +    // TODO: is this even necessay?  These are probably set to never discard
 +    LLViewerFetchedTexture::sFlatNormalImagep->addTextureStats(1024.f*1024.f);
 +    LLViewerFetchedTexture::sWhiteImagep->addTextureStats(1024.f * 1024.f);
 +}
 +
 +S32 LLDrawPoolAlpha::getNumPostDeferredPasses()
 +{
 +    return 1;
 +}
 +
 +// set some common parameters on the given shader to prepare for alpha rendering
 +static void prepare_alpha_shader(LLGLSLShader* shader, bool textureGamma, bool deferredEnvironment, F32 water_sign)
 +{
 +    static LLCachedControl<F32> displayGamma(gSavedSettings, "RenderDeferredDisplayGamma");
 +    F32 gamma = displayGamma;
 +
 +    static LLStaticHashedString waterSign("waterSign");
 +
 +    // Does this deferred shader need environment uniforms set such as sun_dir, etc. ?
 +    // NOTE: We don't actually need a gbuffer since we are doing forward rendering (for transparency) post deferred rendering
 +    // TODO: bindDeferredShader() probably should have the updating of the environment uniforms factored out into updateShaderEnvironmentUniforms()
 +    // i.e. shaders\class1\deferred\alphaF.glsl
 +    if (deferredEnvironment)
 +    {
 +        shader->mCanBindFast = false;
 +    }
 +
 +    shader->bind();
 +    shader->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f / 2.2f));
 +
 +    if (LLPipeline::sRenderingHUDs)
 +    { // for HUD attachments, only the pre-water pass is executed and we never want to clip anything
 +        LLVector4 near_clip(0, 0, -1, 0);
 +        shader->uniform1f(waterSign, 1.f);
 +        shader->uniform4fv(LLShaderMgr::WATER_WATERPLANE, 1, near_clip.mV);
 +    }
 +    else
 +    {
 +        shader->uniform1f(waterSign, water_sign);
 +        shader->uniform4fv(LLShaderMgr::WATER_WATERPLANE, 1, LLDrawPoolAlpha::sWaterPlane.mV);
 +    }
 +
 +    if (LLPipeline::sImpostorRender)
 +    {
 +        shader->setMinimumAlpha(MINIMUM_IMPOSTOR_ALPHA);
 +    }
 +    else
 +    {
 +        shader->setMinimumAlpha(MINIMUM_ALPHA);
 +    }
 +    if (textureGamma)
 +    {
 +        shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
 +    }
 +
 +    //also prepare rigged variant
 +    if (shader->mRiggedVariant && shader->mRiggedVariant != shader)
 +    {
 +        prepare_alpha_shader(shader->mRiggedVariant, textureGamma, deferredEnvironment, water_sign);
 +    }
 +}
 +
 +extern bool gCubeSnapshot;
 +
 +void LLDrawPoolAlpha::renderPostDeferred(S32 pass)
 +{
 +    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 +
 +    if (LLPipeline::isWaterClip() && getType() == LLDrawPool::POOL_ALPHA_PRE_WATER)
 +    { // don't render alpha objects on the other side of the water plane if water is opaque
 +        return;
 +    }
 +
 +    F32 water_sign = 1.f;
 +
 +    if (getType() == LLDrawPool::POOL_ALPHA_PRE_WATER)
 +    {
 +        water_sign = -1.f;
 +    }
 +
 +    if (LLPipeline::sUnderWaterRender)
 +    {
 +        water_sign *= -1.f;
 +    }
 +
 +    // prepare shaders
 +    llassert(LLPipeline::sRenderDeferred);
 +
 +    emissive_shader = &gDeferredEmissiveProgram;
 +    prepare_alpha_shader(emissive_shader, true, false, water_sign);
 +
 +    pbr_emissive_shader = &gPBRGlowProgram;
 +    prepare_alpha_shader(pbr_emissive_shader, true, false, water_sign);
 +
 +
 +    fullbright_shader   =
 +        (LLPipeline::sImpostorRender) ? &gDeferredFullbrightAlphaMaskProgram :
 +        (LLPipeline::sRenderingHUDs) ? &gHUDFullbrightAlphaMaskAlphaProgram :
 +        &gDeferredFullbrightAlphaMaskAlphaProgram;
 +    prepare_alpha_shader(fullbright_shader, true, true, water_sign);
 +
 +    simple_shader   =
 +        (LLPipeline::sImpostorRender) ? &gDeferredAlphaImpostorProgram :
 +        (LLPipeline::sRenderingHUDs) ? &gHUDAlphaProgram :
 +        &gDeferredAlphaProgram;
 +
 +    prepare_alpha_shader(simple_shader, false, true, water_sign); //prime simple shader (loads shadow relevant uniforms)
 +
 +    LLGLSLShader* materialShader = gDeferredMaterialProgram;
 +    for (int i = 0; i < LLMaterial::SHADER_COUNT*2; ++i)
 +    {
 +        prepare_alpha_shader(&materialShader[i], false, true, water_sign);
 +    }
 +
 +    pbr_shader =
 +        (LLPipeline::sRenderingHUDs) ? &gHUDPBRAlphaProgram :
 +        &gDeferredPBRAlphaProgram;
 +
 +    prepare_alpha_shader(pbr_shader, false, true, water_sign);
 +
 +    // explicitly unbind here so render loop doesn't make assumptions about the last shader
 +    // already being setup for rendering
 +    LLGLSLShader::unbind();
 +
 +    if (!LLPipeline::sRenderingHUDs)
 +    {
 +        // first pass, render rigged objects only and render to depth buffer
 +        forwardRender(true);
 +    }
 +
 +    // second pass, regular forward alpha rendering
 +    forwardRender();
 +
 +    // final pass, render to depth for depth of field effects
 +    if (!LLPipeline::sImpostorRender && gSavedSettings.getBOOL("RenderDepthOfField") && !gCubeSnapshot && !LLPipeline::sRenderingHUDs && getType() == LLDrawPool::POOL_ALPHA_POST_WATER)
 +    {
 +        //update depth buffer sampler
 +        simple_shader = fullbright_shader = &gDeferredFullbrightAlphaMaskProgram;
 +
 +        simple_shader->bind();
 +        simple_shader->setMinimumAlpha(0.33f);
 +
 +        // mask off color buffer writes as we're only writing to depth buffer
 +        gGL.setColorMask(false, false);
 +
 +        // If the face is more than 90% transparent, then don't update the Depth buffer for Dof
 +        // We don't want the nearly invisible objects to cause of DoF effects
 +        renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2,
 +            true); // <--- discard mostly transparent faces
 +
 +        gGL.setColorMask(true, false);
 +    }
 +}
 +
 +void LLDrawPoolAlpha::forwardRender(bool rigged)
 +{
 +    gPipeline.enableLightsDynamic();
 +
 +    LLGLSPipelineAlpha gls_pipeline_alpha;
 +
 +    //enable writing to alpha for emissive effects
 +    gGL.setColorMask(true, true);
 +
 +    bool write_depth = rigged ||
 +        LLDrawPoolWater::sSkipScreenCopy
 +        // we want depth written so that rendered alpha will
 +        // contribute to the alpha mask used for impostors
 +        || LLPipeline::sImpostorRenderAlphaDepthPass
 +        || getType() == LLDrawPoolAlpha::POOL_ALPHA_PRE_WATER; // needed for accurate water fog
 +
 +
 +    LLGLDepthTest depth(GL_TRUE, write_depth ? GL_TRUE : GL_FALSE);
 +
 +    mColorSFactor = LLRender::BF_SOURCE_ALPHA;           // } regular alpha blend
 +    mColorDFactor = LLRender::BF_ONE_MINUS_SOURCE_ALPHA; // }
 +    mAlphaSFactor = LLRender::BF_ZERO;                         // } glow suppression
 +    mAlphaDFactor = LLRender::BF_ONE_MINUS_SOURCE_ALPHA;       // }
 +    gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor);
 +
 +    // If the face is more than 90% transparent, then don't update the Depth buffer for Dof
 +    // We don't want the nearly invisible objects to cause of DoF effects
 +    renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2, false, rigged);
 +
 +    gGL.setColorMask(true, false);
 +
 +    if (!rigged)
 +    { //render "highlight alpha" on final non-rigged pass
 +        // NOTE -- hacky call here protected by !rigged instead of alongside "forwardRender"
 +        // so renderDebugAlpha is executed while gls_pipeline_alpha and depth GL state
 +        // variables above are still in scope
 +        renderDebugAlpha();
 +    }
 +}
 +
 +void LLDrawPoolAlpha::renderDebugAlpha()
 +{
 +    if (sShowDebugAlpha)
 +    {
 +        gHighlightProgram.bind();
 +        gGL.diffuseColor4f(1, 0, 0, 1);
 +        gGL.getTexUnit(0)->bindFast(LLViewerFetchedTexture::getSmokeImage());
 +
 +
 +        renderAlphaHighlight();
 +
 +        pushUntexturedBatches(LLRenderPass::PASS_ALPHA_MASK);
 +        pushUntexturedBatches(LLRenderPass::PASS_ALPHA_INVISIBLE);
 +
 +        // Material alpha mask
 +        gGL.diffuseColor4f(0, 0, 1, 1);
 +        pushUntexturedBatches(LLRenderPass::PASS_MATERIAL_ALPHA_MASK);
 +        pushUntexturedBatches(LLRenderPass::PASS_NORMMAP_MASK);
 +        pushUntexturedBatches(LLRenderPass::PASS_SPECMAP_MASK);
 +        pushUntexturedBatches(LLRenderPass::PASS_NORMSPEC_MASK);
 +        pushUntexturedBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK);
 +        pushUntexturedBatches(LLRenderPass::PASS_GLTF_PBR_ALPHA_MASK);
 +
 +        gGL.diffuseColor4f(0, 1, 0, 1);
 +        pushUntexturedBatches(LLRenderPass::PASS_INVISIBLE);
 +
 +        gHighlightProgram.mRiggedVariant->bind();
 +        gGL.diffuseColor4f(1, 0, 0, 1);
 +
 +        pushRiggedBatches(LLRenderPass::PASS_ALPHA_MASK_RIGGED, false);
 +        pushRiggedBatches(LLRenderPass::PASS_ALPHA_INVISIBLE_RIGGED, false);
 +
 +        // Material alpha mask
 +        gGL.diffuseColor4f(0, 0, 1, 1);
 +        pushRiggedBatches(LLRenderPass::PASS_MATERIAL_ALPHA_MASK_RIGGED, false);
 +        pushRiggedBatches(LLRenderPass::PASS_NORMMAP_MASK_RIGGED, false);
 +        pushRiggedBatches(LLRenderPass::PASS_SPECMAP_MASK_RIGGED, false);
 +        pushRiggedBatches(LLRenderPass::PASS_NORMSPEC_MASK_RIGGED, false);
 +        pushRiggedBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK_RIGGED, false);
 +        pushRiggedBatches(LLRenderPass::PASS_GLTF_PBR_ALPHA_MASK_RIGGED, false);
 +
 +        gGL.diffuseColor4f(0, 1, 0, 1);
 +        pushRiggedBatches(LLRenderPass::PASS_INVISIBLE_RIGGED, false);
 +        LLGLSLShader::sCurBoundShaderPtr->unbind();
 +    }
 +}
 +
 +void LLDrawPoolAlpha::renderAlphaHighlight()
 +{
 +    for (int pass = 0; pass < 2; ++pass)
 +    { //two passes, one rigged and one not
 +        LLVOAvatar* lastAvatar = nullptr;
 +        U64 lastMeshId = 0;
 +
 +        LLCullResult::sg_iterator begin = pass == 0 ? gPipeline.beginAlphaGroups() : gPipeline.beginRiggedAlphaGroups();
 +        LLCullResult::sg_iterator end = pass == 0 ? gPipeline.endAlphaGroups() : gPipeline.endRiggedAlphaGroups();
 +
 +        for (LLCullResult::sg_iterator i = begin; i != end; ++i)
 +        {
 +            LLSpatialGroup* group = *i;
 +            if (group->getSpatialPartition()->mRenderByGroup &&
 +                !group->isDead())
 +            {
 +                LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[LLRenderPass::PASS_ALPHA+pass]; // <-- hacky + pass to use PASS_ALPHA_RIGGED on second pass
 +
 +                for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k)
 +                {
 +                    LLDrawInfo& params = **k;
 +
 +                    bool rigged = (params.mAvatar != nullptr);
 +                    gHighlightProgram.bind(rigged);
 +                    gGL.diffuseColor4f(1, 0, 0, 1);
 +
 +                    if (rigged)
 +                    {
 +                        if (lastAvatar != params.mAvatar ||
 +                            lastMeshId != params.mSkinInfo->mHash)
 +                        {
 +                            if (!uploadMatrixPalette(params))
 +                            {
 +                                continue;
 +                            }
 +                            lastAvatar = params.mAvatar;
 +                            lastMeshId = params.mSkinInfo->mHash;
 +                        }
 +                    }
 +
 +                    LLRenderPass::applyModelMatrix(params);
 +                    params.mVertexBuffer->setBuffer();
 +                    params.mVertexBuffer->drawRange(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset);
 +                }
 +            }
 +        }
 +    }
 +
 +    // make sure static version of highlight shader is bound before returning
 +    gHighlightProgram.bind();
 +}
 +
 +inline bool IsFullbright(LLDrawInfo& params)
 +{
 +    return params.mFullbright;
 +}
 +
 +inline bool IsMaterial(LLDrawInfo& params)
 +{
 +    return params.mMaterial != nullptr;
 +}
 +
 +inline bool IsEmissive(LLDrawInfo& params)
 +{
 +    return params.mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_EMISSIVE);
 +}
 +
 +inline void Draw(LLDrawInfo* draw, U32 mask)
 +{
 +    draw->mVertexBuffer->setBuffer();
 +    LLRenderPass::applyModelMatrix(*draw);
 +    draw->mVertexBuffer->drawRange(LLRender::TRIANGLES, draw->mStart, draw->mEnd, draw->mCount, draw->mOffset);
 +}
 +
 +bool LLDrawPoolAlpha::TexSetup(LLDrawInfo* draw, bool use_material)
 +{
 +    bool tex_setup = false;
 +
 +    if (draw->mGLTFMaterial)
 +    {
 +        if (draw->mTextureMatrix)
 +        {
 +            tex_setup = true;
 +            gGL.getTexUnit(0)->activate();
 +            gGL.matrixMode(LLRender::MM_TEXTURE);
 +            gGL.loadMatrix((GLfloat*)draw->mTextureMatrix->mMatrix);
 +            gPipeline.mTextureMatrixOps++;
 +        }
 +    }
 +    else
 +    {
 +        if (!LLPipeline::sRenderingHUDs && use_material && current_shader)
 +        {
 +            if (draw->mNormalMap)
 +            {
 +                current_shader->bindTexture(LLShaderMgr::BUMP_MAP, draw->mNormalMap);
 +            }
 +
 +            if (draw->mSpecularMap)
 +            {
 +                current_shader->bindTexture(LLShaderMgr::SPECULAR_MAP, draw->mSpecularMap);
 +            }
 +        }
 +        else if (current_shader == simple_shader || current_shader == simple_shader->mRiggedVariant)
 +        {
 +            current_shader->bindTexture(LLShaderMgr::BUMP_MAP, LLViewerFetchedTexture::sFlatNormalImagep);
 +            current_shader->bindTexture(LLShaderMgr::SPECULAR_MAP, LLViewerFetchedTexture::sWhiteImagep);
 +        }
 +        if (draw->mTextureList.size() > 1)
 +        {
 +            for (U32 i = 0; i < draw->mTextureList.size(); ++i)
 +            {
 +                if (draw->mTextureList[i].notNull())
 +                {
 +                    gGL.getTexUnit(i)->bindFast(draw->mTextureList[i]);
 +                }
 +            }
 +        }
 +        else
 +        { //not batching textures or batch has only 1 texture -- might need a texture matrix
 +            if (draw->mTexture.notNull())
 +            {
 +                if (use_material)
 +                {
 +                    current_shader->bindTexture(LLShaderMgr::DIFFUSE_MAP, draw->mTexture);
 +                }
 +                else
 +                {
 +                    gGL.getTexUnit(0)->bindFast(draw->mTexture);
 +                }
 +
 +                if (draw->mTextureMatrix)
 +                {
 +                    tex_setup = true;
 +                    gGL.getTexUnit(0)->activate();
 +                    gGL.matrixMode(LLRender::MM_TEXTURE);
 +                    gGL.loadMatrix((GLfloat*)draw->mTextureMatrix->mMatrix);
 +                    gPipeline.mTextureMatrixOps++;
 +                }
 +            }
 +            else
 +            {
 +                gGL.getTexUnit(0)->unbindFast(LLTexUnit::TT_TEXTURE);
 +            }
 +        }
 +    }
 +
 +    return tex_setup;
 +}
 +
 +void LLDrawPoolAlpha::RestoreTexSetup(bool tex_setup)
 +{
 +    if (tex_setup)
 +    {
 +        gGL.getTexUnit(0)->activate();
 +        gGL.matrixMode(LLRender::MM_TEXTURE);
 +        gGL.loadIdentity();
 +        gGL.matrixMode(LLRender::MM_MODELVIEW);
 +    }
 +}
 +
 +void LLDrawPoolAlpha::drawEmissive(LLDrawInfo* draw)
 +{
 +    LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 1.f);
 +    draw->mVertexBuffer->setBuffer();
 +    draw->mVertexBuffer->drawRange(LLRender::TRIANGLES, draw->mStart, draw->mEnd, draw->mCount, draw->mOffset);
 +}
 +
 +
 +void LLDrawPoolAlpha::renderEmissives(std::vector<LLDrawInfo*>& emissives)
 +{
 +    emissive_shader->bind();
 +    emissive_shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 1.f);
 +
 +    for (LLDrawInfo* draw : emissives)
 +    {
 +        bool tex_setup = TexSetup(draw, false);
 +        drawEmissive(draw);
 +        RestoreTexSetup(tex_setup);
 +    }
 +}
 +
 +void LLDrawPoolAlpha::renderPbrEmissives(std::vector<LLDrawInfo*>& emissives)
 +{
 +    pbr_emissive_shader->bind();
 +
 +    for (LLDrawInfo* draw : emissives)
 +    {
 +        llassert(draw->mGLTFMaterial);
 +        LLGLDisable cull_face(draw->mGLTFMaterial->mDoubleSided ? GL_CULL_FACE : 0);
 +        draw->mGLTFMaterial->bind(draw->mTexture);
 +        draw->mVertexBuffer->setBuffer();
 +        draw->mVertexBuffer->drawRange(LLRender::TRIANGLES, draw->mStart, draw->mEnd, draw->mCount, draw->mOffset);
 +    }
 +}
 +
 +void LLDrawPoolAlpha::renderRiggedEmissives(std::vector<LLDrawInfo*>& emissives)
 +{
 +    LLGLDepthTest depth(GL_TRUE, GL_FALSE); //disable depth writes since "emissive" is additive so sorting doesn't matter
 +    LLGLSLShader* shader = emissive_shader->mRiggedVariant;
 +    shader->bind();
 +    shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 1.f);
 +
 +    LLVOAvatar* lastAvatar = nullptr;
 +    U64 lastMeshId = 0;
 +
 +    for (LLDrawInfo* draw : emissives)
 +    {
 +        LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("Emissives");
 +
 +        bool tex_setup = TexSetup(draw, false);
 +        if (lastAvatar != draw->mAvatar || lastMeshId != draw->mSkinInfo->mHash)
 +        {
 +            if (!uploadMatrixPalette(*draw))
 +            { // failed to upload matrix palette, skip rendering
 +                continue;
 +            }
 +            lastAvatar = draw->mAvatar;
 +            lastMeshId = draw->mSkinInfo->mHash;
 +        }
 +        drawEmissive(draw);
 +        RestoreTexSetup(tex_setup);
 +    }
 +}
 +
 +void LLDrawPoolAlpha::renderRiggedPbrEmissives(std::vector<LLDrawInfo*>& emissives)
 +{
 +    LLGLDepthTest depth(GL_TRUE, GL_FALSE); //disable depth writes since "emissive" is additive so sorting doesn't matter
 +    pbr_emissive_shader->bind(true);
 +
 +    LLVOAvatar* lastAvatar = nullptr;
 +    U64 lastMeshId = 0;
 +
 +    for (LLDrawInfo* draw : emissives)
 +    {
 +        if (lastAvatar != draw->mAvatar || lastMeshId != draw->mSkinInfo->mHash)
 +        {
 +            if (!uploadMatrixPalette(*draw))
 +            { // failed to upload matrix palette, skip rendering
 +                continue;
 +            }
 +            lastAvatar = draw->mAvatar;
 +            lastMeshId = draw->mSkinInfo->mHash;
 +        }
 +
 +        LLGLDisable cull_face(draw->mGLTFMaterial->mDoubleSided ? GL_CULL_FACE : 0);
 +        draw->mGLTFMaterial->bind(draw->mTexture);
 +        draw->mVertexBuffer->setBuffer();
 +        draw->mVertexBuffer->drawRange(LLRender::TRIANGLES, draw->mStart, draw->mEnd, draw->mCount, draw->mOffset);
 +    }
 +}
 +
 +void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only, bool rigged)
 +{
 +    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 +    bool initialized_lighting = false;
 +    bool light_enabled = true;
 +
 +    LLVOAvatar* lastAvatar = nullptr;
 +    U64 lastMeshId = 0;
 +    LLGLSLShader* lastAvatarShader = nullptr;
 +
 +    LLCullResult::sg_iterator begin;
 +    LLCullResult::sg_iterator end;
 +
 +    if (rigged)
 +    {
 +        begin = gPipeline.beginRiggedAlphaGroups();
 +        end = gPipeline.endRiggedAlphaGroups();
 +    }
 +    else
 +    {
 +        begin = gPipeline.beginAlphaGroups();
 +        end = gPipeline.endAlphaGroups();
 +    }
 +
 +    LLEnvironment& env = LLEnvironment::instance();
 +    F32 water_height = env.getWaterHeight();
 +
 +    bool above_water = getType() == LLDrawPool::POOL_ALPHA_POST_WATER;
 +    if (LLPipeline::sUnderWaterRender)
 +    {
 +        above_water = !above_water;
 +    }
 +
 +
 +    for (LLCullResult::sg_iterator i = begin; i != end; ++i)
 +    {
 +        LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("renderAlpha - group");
 +        LLSpatialGroup* group = *i;
 +        llassert(group);
 +        llassert(group->getSpatialPartition());
 +
 +        if (group->getSpatialPartition()->mRenderByGroup &&
 +            !group->isDead())
 +        {
 +
 +            LLSpatialBridge* bridge = group->getSpatialPartition()->asBridge();
 +            const LLVector4a* ext = bridge ? bridge->getSpatialExtents() : group->getExtents();
 +
 +            if (!LLPipeline::sRenderingHUDs) // ignore above/below water for HUD render
 +            {
 +                if (above_water)
 +                { // reject any spatial groups that have no part above water
 +                    if (ext[1].getF32ptr()[2] < water_height)
 +                    {
 +                        continue;
 +                    }
 +                }
 +                else
 +                { // reject any spatial groups that he no part below water
 +                    if (ext[0].getF32ptr()[2] > water_height)
 +                    {
 +                        continue;
 +                    }
 +                }
 +            }
 +
 +            static std::vector<LLDrawInfo*> emissives;
 +            static std::vector<LLDrawInfo*> rigged_emissives;
 +            static std::vector<LLDrawInfo*> pbr_emissives;
 +            static std::vector<LLDrawInfo*> pbr_rigged_emissives;
 +
 +            emissives.resize(0);
 +            rigged_emissives.resize(0);
 +            pbr_emissives.resize(0);
 +            pbr_rigged_emissives.resize(0);
 +
 +            bool is_particle_or_hud_particle = group->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_PARTICLE
 +                                                      || group->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_HUD_PARTICLE;
 +
 +            bool disable_cull = is_particle_or_hud_particle;
 +            LLGLDisable cull(disable_cull ? GL_CULL_FACE : 0);
 +
 +            LLSpatialGroup::drawmap_elem_t& draw_info = rigged ? group->mDrawMap[LLRenderPass::PASS_ALPHA_RIGGED] : group->mDrawMap[LLRenderPass::PASS_ALPHA];
 +
 +            for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k)
 +            {
 +                LLDrawInfo& params = **k;
 +                if ((bool)params.mAvatar != rigged)
 +                {
 +                    continue;
 +                }
 +
 +                LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("ra - push batch");
 +
 +                LLRenderPass::applyModelMatrix(params);
 +
 +                LLMaterial* mat = NULL;
 +                LLGLTFMaterial *gltf_mat = params.mGLTFMaterial;
 +
 +                LLGLDisable cull_face(gltf_mat && gltf_mat->mDoubleSided ? GL_CULL_FACE : 0);
 +
 +                if (gltf_mat && gltf_mat->mAlphaMode == LLGLTFMaterial::ALPHA_MODE_BLEND)
 +                {
 +                    target_shader = pbr_shader;
 +                    if (params.mAvatar != nullptr)
 +                    {
 +                        target_shader = target_shader->mRiggedVariant;
 +                    }
 +
 +                    // shader must be bound before LLGLTFMaterial::bind
 +                    if (current_shader != target_shader)
 +                    {
 +                        gPipeline.bindDeferredShaderFast(*target_shader);
 +                    }
 +
 +                    params.mGLTFMaterial->bind(params.mTexture);
 +                }
 +                else
 +                {
 +                    mat = LLPipeline::sRenderingHUDs ? nullptr : params.mMaterial;
 +
 +                    if (params.mFullbright)
 +                    {
 +                        // Turn off lighting if it hasn't already been so.
 +                        if (light_enabled || !initialized_lighting)
 +                        {
 +                            initialized_lighting = true;
 +                            target_shader = fullbright_shader;
 +
 +                            light_enabled = false;
 +                        }
 +                    }
 +                    // Turn on lighting if it isn't already.
 +                    else if (!light_enabled || !initialized_lighting)
 +                    {
 +                        initialized_lighting = true;
 +                        target_shader = simple_shader;
 +                        light_enabled = true;
 +                    }
 +
 +                    if (LLPipeline::sRenderingHUDs)
 +                    {
 +                        target_shader = fullbright_shader;
 +                    }
 +                    else if (mat)
 +                    {
 +                        U32 mask = params.mShaderMask;
 +
 +                        llassert(mask < LLMaterial::SHADER_COUNT);
 +                        target_shader = &(gDeferredMaterialProgram[mask]);
 +                    }
 +                    else if (!params.mFullbright)
 +                    {
 +                        target_shader = simple_shader;
 +                    }
 +                    else
 +                    {
 +                        target_shader = fullbright_shader;
 +                    }
 +
 +                    if (params.mAvatar != nullptr)
 +                    {
 +                        llassert(target_shader->mRiggedVariant != nullptr);
 +                        target_shader = target_shader->mRiggedVariant;
 +                    }
 +
 +                    if (current_shader != target_shader)
 +                    {// If we need shaders, and we're not ALREADY using the proper shader, then bind it
 +                    // (this way we won't rebind shaders unnecessarily).
 +                        gPipeline.bindDeferredShaderFast(*target_shader);
 +
 +                        if (params.mFullbright)
 +                        { // make sure the bind the exposure map for fullbright shaders so they can cancel out exposure
 +                            S32 channel = target_shader->enableTexture(LLShaderMgr::EXPOSURE_MAP);
 +                            if (channel > -1)
 +                            {
 +                                gGL.getTexUnit(channel)->bind(&gPipeline.mExposureMap);
 +                            }
 +                        }
 +                    }
 +
 +                    LLVector4 spec_color(1, 1, 1, 1);
 +                    F32 env_intensity = 0.0f;
 +                    F32 brightness = 1.0f;
 +
 +                    // We have a material.  Supply the appropriate data here.
 +                    if (mat)
 +                    {
 +                        spec_color = params.mSpecColor;
 +                        env_intensity = params.mEnvIntensity;
 +                        brightness = params.mFullbright ? 1.f : 0.f;
 +                    }
 +
 +                    if (current_shader)
 +                    {
 +                        current_shader->uniform4f(LLShaderMgr::SPECULAR_COLOR, spec_color.mV[0], spec_color.mV[1], spec_color.mV[2], spec_color.mV[3]);
 +                        current_shader->uniform1f(LLShaderMgr::ENVIRONMENT_INTENSITY, env_intensity);
 +                        current_shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, brightness);
 +                    }
 +                }
 +
 +                if (params.mAvatar != nullptr)
 +                {
 +                    if (lastAvatar != params.mAvatar ||
 +                        lastMeshId != params.mSkinInfo->mHash ||
 +                        lastAvatarShader != LLGLSLShader::sCurBoundShaderPtr)
 +                    {
 +                        if (!uploadMatrixPalette(params))
 +                        {
 +                            continue;
 +                        }
 +                        lastAvatar = params.mAvatar;
 +                        lastMeshId = params.mSkinInfo->mHash;
 +                        lastAvatarShader = LLGLSLShader::sCurBoundShaderPtr;
 +                    }
 +                }
 +
 +                bool tex_setup = TexSetup(¶ms, (mat != nullptr));
 +
 +                {
 +                    gGL.blendFunc((LLRender::eBlendFactor) params.mBlendFuncSrc, (LLRender::eBlendFactor) params.mBlendFuncDst, mAlphaSFactor, mAlphaDFactor);
 +
 +                    bool reset_minimum_alpha = false;
 +                    if (!LLPipeline::sImpostorRender &&
 +                        params.mBlendFuncDst != LLRender::BF_SOURCE_ALPHA &&
 +                        params.mBlendFuncSrc != LLRender::BF_SOURCE_ALPHA)
 +                    { // this draw call has a custom blend function that may require rendering of "invisible" fragments
 +                        current_shader->setMinimumAlpha(0.f);
 +                        reset_minimum_alpha = true;
 +                    }
 +
 +                    params.mVertexBuffer->setBuffer();
 +                    params.mVertexBuffer->drawRange(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset);
 +
 +                    if (reset_minimum_alpha)
 +                    {
 +                        current_shader->setMinimumAlpha(MINIMUM_ALPHA);
 +                    }
 +                }
 +
 +                // If this alpha mesh has glow, then draw it a second time to add the destination-alpha (=glow).  Interleaving these state-changing calls is expensive, but glow must be drawn Z-sorted with alpha.
 +                if (getType() != LLDrawPool::POOL_ALPHA_PRE_WATER &&
 +                    params.mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_EMISSIVE))
 +                {
 +                    if (params.mAvatar != nullptr)
 +                    {
 +                        if (params.mGLTFMaterial.isNull())
 +                        {
 +                            rigged_emissives.push_back(¶ms);
 +                        }
 +                        else
 +                        {
 +                            pbr_rigged_emissives.push_back(¶ms);
 +                        }
 +                    }
 +                    else
 +                    {
 +                        if (params.mGLTFMaterial.isNull())
 +                        {
 +                            emissives.push_back(¶ms);
 +                        }
 +                        else
 +                        {
 +                            pbr_emissives.push_back(¶ms);
 +                        }
 +                    }
 +                }
 +
 +                if (tex_setup)
 +                {
 +                    gGL.getTexUnit(0)->activate();
 +                    gGL.matrixMode(LLRender::MM_TEXTURE);
 +                    gGL.loadIdentity();
 +                    gGL.matrixMode(LLRender::MM_MODELVIEW);
 +                }
 +            }
 +
 +            // render emissive faces into alpha channel for bloom effects
 +            if (!depth_only)
 +            {
 +                gPipeline.enableLightsDynamic();
 +
 +                // install glow-accumulating blend mode
 +                // don't touch color, add to alpha (glow)
 +                gGL.blendFunc(LLRender::BF_ZERO, LLRender::BF_ONE, LLRender::BF_ONE, LLRender::BF_ONE);
 +
 +                bool rebind = false;
 +                LLGLSLShader* lastShader = current_shader;
 +                if (!emissives.empty())
 +                {
 +                    light_enabled = true;
 +                    renderEmissives(emissives);
 +                    rebind = true;
 +                }
 +
 +                if (!pbr_emissives.empty())
 +                {
 +                    light_enabled = true;
 +                    renderPbrEmissives(pbr_emissives);
 +                    rebind = true;
 +                }
 +
 +                if (!rigged_emissives.empty())
 +                {
 +                    light_enabled = true;
 +                    renderRiggedEmissives(rigged_emissives);
 +                    rebind = true;
 +                }
 +
 +                if (!pbr_rigged_emissives.empty())
 +                {
 +                    light_enabled = true;
 +                    renderRiggedPbrEmissives(pbr_rigged_emissives);
 +                    rebind = true;
 +                }
 +
 +                // restore our alpha blend mode
 +                gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor);
 +
 +                if (lastShader && rebind)
 +                {
 +                    lastShader->bind();
 +                }
 +            }
 +        }
 +    }
 +
 +    gGL.setSceneBlendType(LLRender::BT_ALPHA);
 +
 +    LLVertexBuffer::unbind();
 +
 +    if (!light_enabled)
 +    {
 +        gPipeline.enableLightsDynamic();
 +    }
 +}
 +
 +bool LLDrawPoolAlpha::uploadMatrixPalette(const LLDrawInfo& params)
 +{
 +    if (params.mAvatar.isNull())
 +    {
 +        return false;
 +    }
 +    const LLVOAvatar::MatrixPaletteCache& mpc = params.mAvatar.get()->updateSkinInfoMatrixPalette(params.mSkinInfo);
 +    U32 count = mpc.mMatrixPalette.size();
 +
 +    if (count == 0)
 +    {
 +        //skin info not loaded yet, don't render
 +        return false;
 +    }
 +
 +    LLGLSLShader::sCurBoundShaderPtr->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX,
 +        count,
 +        false,
 +        (GLfloat*)&(mpc.mGLMp[0]));
 +
 +    return true;
 +}
  | 
