summaryrefslogtreecommitdiff
path: root/indra/newview/lldrawpoolalpha.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/lldrawpoolalpha.cpp')
-rw-r--r--indra/newview/lldrawpoolalpha.cpp584
1 files changed, 584 insertions, 0 deletions
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
new file mode 100644
index 0000000000..d34695a7be
--- /dev/null
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -0,0 +1,584 @@
+/**
+ * @file lldrawpoolalpha.cpp
+ * @brief LLDrawPoolAlpha class implementation
+ *
+ * Copyright (c) 2002-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "lldrawpoolalpha.h"
+
+#include "llviewercontrol.h"
+#include "llcriticaldamp.h"
+#include "llfasttimer.h"
+
+#include "llagparray.h"
+#include "llcubemap.h"
+#include "llsky.h"
+#include "llagent.h"
+#include "lldrawable.h"
+#include "llface.h"
+#include "llviewercamera.h"
+#include "llviewerimagelist.h" // For debugging
+#include "llviewerobjectlist.h" // For debugging
+#include "llviewerwindow.h"
+#include "pipeline.h"
+
+const F32 MAX_DIST = 512.f;
+const F32 ALPHA_FALLOFF_START_DISTANCE = 0.8f;
+
+BOOL LLDrawPoolAlpha::sShowDebugAlpha = FALSE;
+
+LLDrawPoolAlpha::LLDrawPoolAlpha() :
+ LLDrawPool(POOL_ALPHA,
+ DATA_SIMPLE_IL_MASK | DATA_COLORS_MASK,
+ DATA_SIMPLE_NIL_MASK)
+{
+ mRebuiltLastFrame = FALSE;
+ mMinDistance = 0.f;
+ mMaxDistance = MAX_DIST;
+ mInvBinSize = NUM_ALPHA_BINS/(mMaxDistance - mMinDistance);
+ mCleanupUnused = TRUE;
+ //mRebuildFreq = -1 ; // Only rebuild if nearly full
+
+// for (S32 i = 0; i < NUM_ALPHA_BINS; i++)
+// {
+// mDistanceBins[i].realloc(200);
+// }
+}
+
+LLDrawPoolAlpha::~LLDrawPoolAlpha()
+{
+}
+
+LLDrawPool *LLDrawPoolAlpha::instancePool()
+{
+ llerrs << "Should never be calling instancePool on an alpha pool!" << llendl;
+ return NULL;
+}
+
+void LLDrawPoolAlpha::enqueue(LLFace *facep)
+{
+ if (!facep->isState(LLFace::GLOBAL))
+ {
+ facep->mCenterAgent = facep->mCenterLocal * facep->getRenderMatrix();
+ }
+ facep->mDistance = (facep->mCenterAgent - gCamera->getOrigin()) * gCamera->getAtAxis();
+
+ if (facep->isState(LLFace::BACKLIST))
+ {
+ mMoveFace.put(facep);
+ }
+ else
+ {
+ mDrawFace.put(facep);
+ }
+
+ {
+ S32 dist_bin = lltrunc( (mMaxDistance - (facep->mDistance+32))*mInvBinSize );
+
+ if (dist_bin >= NUM_ALPHA_BINS)
+ {
+ mDistanceBins[NUM_ALPHA_BINS-1].put(facep);
+ //mDistanceBins[NUM_ALPHA_BINS-1].push(facep, (U32)(void*)facep->getTexture());
+ }
+ else if (dist_bin > 0)
+ {
+ mDistanceBins[dist_bin].put(facep);
+ //mDistanceBins[dist_bin].push(facep, (U32)(void*)facep->getTexture());
+ }
+ else
+ {
+ mDistanceBins[0].put(facep);
+ //mDistanceBins[0].push(facep, (U32)(void*)facep->getTexture());
+ }
+ }
+}
+
+BOOL LLDrawPoolAlpha::removeFace(LLFace *facep)
+{
+ BOOL removed = FALSE;
+
+ LLDrawPool::removeFace(facep);
+
+ {
+ for (S32 i = 0; i < NUM_ALPHA_BINS; i++)
+ {
+ if (mDistanceBins[i].removeObj(facep) != -1)
+ {
+ if (removed)
+ {
+ llerrs << "Warning! " << "Face in multiple distance bins on removal" << llendl;
+ }
+ removed = TRUE;
+ }
+ }
+ }
+ if (removed)
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void LLDrawPoolAlpha::prerender()
+{
+ mVertexShaderLevel = gPipeline.getVertexShaderLevel(LLPipeline::SHADER_OBJECT);
+}
+
+void LLDrawPoolAlpha::beginRenderPass(S32 pass)
+{
+ if (mDrawFace.empty())
+ {
+ // No alpha objects, early exit.
+ return;
+ }
+
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_NORMAL_ARRAY);
+ if (gPipeline.getLightingDetail() >= 2)
+ {
+ glEnableClientState(GL_COLOR_ARRAY);
+ }
+}
+
+
+void LLDrawPoolAlpha::render(S32 pass)
+{
+ LLFastTimer t(LLFastTimer::FTM_RENDER_ALPHA);
+
+ if (mDrawFace.empty())
+ {
+ // No alpha objects, early exit.
+ return;
+ }
+
+ GLfloat shiny[4] =
+ {
+ 0.00f,
+ 0.25f,
+ 0.5f,
+ 0.75f
+ };
+
+ GLint specularIndex = (mVertexShaderLevel > 0) ?
+ gPipeline.mObjectAlphaProgram.mAttribute[LLPipeline::GLSL_SPECULAR_COLOR] : 0;
+
+ S32 diffTex = 0;
+ S32 envTex = -1;
+
+ if (mVertexShaderLevel > 0) //alpha pass uses same shader as shiny/bump
+ {
+ envTex = gPipeline.mObjectAlphaProgram.enableTexture(LLPipeline::GLSL_ENVIRONMENT_MAP, GL_TEXTURE_CUBE_MAP_ARB);
+ LLCubeMap* cube_map = gSky.mVOSkyp->getCubeMap();
+ if (envTex >= 0 && cube_map)
+ {
+ cube_map->bind();
+ cube_map->setMatrix(1);
+ }
+
+ if (specularIndex > 0)
+ {
+ glVertexAttrib4fARB(specularIndex, 0, 0, 0, 0);
+ }
+
+ S32 scatterTex = gPipeline.mObjectAlphaProgram.enableTexture(LLPipeline::GLSL_SCATTER_MAP);
+ LLViewerImage::bindTexture(gSky.mVOSkyp->getScatterMap(), scatterTex);
+
+ diffTex = gPipeline.mObjectAlphaProgram.enableTexture(LLPipeline::GLSL_DIFFUSE_MAP);
+ }
+
+ bindGLVertexPointer();
+ bindGLTexCoordPointer();
+ bindGLNormalPointer();
+ if (gPipeline.getLightingDetail() >= 2)
+ {
+ bindGLColorPointer();
+ }
+
+ S32 i, j;
+ glAlphaFunc(GL_GREATER,0.01f);
+ // This needs to be turned off or there will be lots of artifacting with the clouds - djs
+ LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
+
+ LLGLSPipelineAlpha gls_pipeline_alpha;
+
+ LLDynamicArray<LLFace*>* distance_bins;
+ distance_bins = mDistanceBins;
+
+ S32 num_bins_no_alpha_test = ((gPickAlphaThreshold != 0.f) && gUsePickAlpha) ?
+ (NUM_ALPHA_BINS - llmax(2, (S32)(ALPHA_FALLOFF_START_DISTANCE * mInvBinSize))) :
+ NUM_ALPHA_BINS;
+
+ typedef std::vector<LLFace*> face_list_t;
+
+ for (i = 0; i < num_bins_no_alpha_test; i++)
+ {
+ S32 obj_count = distance_bins[i].count();
+
+ if (!obj_count)
+ {
+ continue;
+ }
+ else if (i > (NUM_ALPHA_BINS / 2) && obj_count < 100)
+ {
+ face_list_t pri_queue;
+ pri_queue.reserve(distance_bins[i].count());
+ for (j = 0; j < distance_bins[i].count(); j++)
+ {
+ pri_queue.push_back(distance_bins[i][j]);
+ }
+ std::sort(pri_queue.begin(), pri_queue.end(), LLFace::CompareDistanceGreater());
+
+ for (face_list_t::iterator iter = pri_queue.begin(); iter != pri_queue.end(); iter++)
+ {
+ const LLFace &face = *(*iter);
+ face.enableLights();
+ face.bindTexture(diffTex);
+ if ((mVertexShaderLevel > 0) && face.getTextureEntry() && specularIndex > 0)
+ {
+ U8 s = face.getTextureEntry()->getShiny();
+ glVertexAttrib4fARB(specularIndex, shiny[s], shiny[s], shiny[s], shiny[s]);
+ }
+ face.renderIndexed(getRawIndices());
+ mIndicesDrawn += face.getIndicesCount();
+ }
+ }
+ else
+ {
+ S32 count = distance_bins[i].count();
+ for (j = 0; j < count; j++)
+ {
+ const LLFace &face = *distance_bins[i][j];
+ face.enableLights();
+ face.bindTexture(diffTex);
+ if ((mVertexShaderLevel > 0) && face.getTextureEntry() && specularIndex > 0)
+ {
+ U8 s = face.getTextureEntry()->getShiny();
+ glVertexAttrib4fARB(specularIndex, shiny[s], shiny[s], shiny[s], shiny[s]);
+ }
+ face.renderIndexed(getRawIndices());
+ mIndicesDrawn += face.getIndicesCount();
+ }
+ }
+ }
+
+ GLfloat ogl_matrix[16];
+ gCamera->getOpenGLTransform(ogl_matrix);
+
+ for (i = num_bins_no_alpha_test; i < NUM_ALPHA_BINS; i++)
+ {
+ BOOL use_pri_queue = distance_bins[i].count() < 100;
+
+ face_list_t pri_queue;
+
+ if (use_pri_queue)
+ {
+ pri_queue.reserve(distance_bins[i].count());
+ for (j = 0; j < distance_bins[i].count(); j++)
+ {
+ pri_queue.push_back(distance_bins[i][j]);
+ }
+ std::sort(pri_queue.begin(), pri_queue.end(), LLFace::CompareDistanceGreater());
+ }
+
+ S32 count = distance_bins[i].count();
+ for (j = 0; j < count; j++)
+ {
+ const LLFace &face = use_pri_queue ? *pri_queue[j] : *distance_bins[i][j];
+ F32 fade_value = face.mAlphaFade * gPickAlphaThreshold;
+
+ face.enableLights();
+
+ if (fade_value < 1.f)
+ {
+ {
+ LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE);
+ glAlphaFunc(GL_LESS, fade_value);
+ glBlendFunc(GL_ZERO, GL_ONE);
+ LLViewerImage::bindTexture(gPipeline.mAlphaSizzleImagep, diffTex);
+ LLVector4 s_params(ogl_matrix[2], ogl_matrix[6], ogl_matrix[10], ogl_matrix[14]);
+ LLVector4 t_params(ogl_matrix[1], ogl_matrix[5], ogl_matrix[9], ogl_matrix[13]);
+
+ LLGLEnable gls_texgen_s(GL_TEXTURE_GEN_S);
+ LLGLEnable gls_texgen_t(GL_TEXTURE_GEN_T);
+ glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
+ glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
+ glTexGenfv(GL_S, GL_OBJECT_PLANE, s_params.mV);
+ glTexGenfv(GL_T, GL_OBJECT_PLANE, t_params.mV);
+ if ((mVertexShaderLevel > 0) && face.getTextureEntry() && specularIndex > 0)
+ {
+ U8 s = face.getTextureEntry()->getShiny();
+ glVertexAttrib4fARB(specularIndex, shiny[s], shiny[s], shiny[s], shiny[s]);
+ }
+ face.renderIndexed(getRawIndices());
+ }
+
+ {
+ // should get GL_GREATER to work, as it's faster
+ LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_LESS);
+ glAlphaFunc(GL_GEQUAL, fade_value);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ face.bindTexture(diffTex);
+ if ((mVertexShaderLevel > 0) && face.getTextureEntry() && specularIndex > 0)
+ {
+ U8 s = face.getTextureEntry()->getShiny();
+ glVertexAttrib4fARB(specularIndex, shiny[s], shiny[s], shiny[s], shiny[s]);
+ }
+ face.renderIndexed(getRawIndices());
+ }
+ }
+
+ // render opaque portion of actual texture
+ glAlphaFunc(GL_GREATER, 0.98f);
+
+ face.bindTexture(diffTex);
+ face.renderIndexed(getRawIndices());
+
+ glAlphaFunc(GL_GREATER, 0.01f);
+
+ mIndicesDrawn += face.getIndicesCount();
+ }
+ }
+
+ if (mVertexShaderLevel > 0) //single pass shader driven shiny/bump
+ {
+ gPipeline.mObjectAlphaProgram.disableTexture(LLPipeline::GLSL_ENVIRONMENT_MAP, GL_TEXTURE_CUBE_MAP_ARB);
+ LLCubeMap* cube_map = gSky.mVOSkyp->getCubeMap();
+ if (envTex >= 0 && cube_map)
+ {
+ cube_map->restoreMatrix();
+ }
+ gPipeline.mObjectAlphaProgram.disableTexture(LLPipeline::GLSL_SCATTER_MAP);
+ gPipeline.mObjectAlphaProgram.disableTexture(LLPipeline::GLSL_DIFFUSE_MAP);
+
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ glActiveTextureARB(GL_TEXTURE0_ARB);
+ glEnable(GL_TEXTURE_2D);
+ }
+
+ if (sShowDebugAlpha)
+ {
+ gPipeline.disableLights();
+ if ((mVertexShaderLevel > 0))
+ {
+ gPipeline.mHighlightProgram.bind();
+ }
+
+ LLViewerImage::sSmokeImagep->bind();
+ LLOverrideFaceColor override_color(this, 1.f, 0.f, 0.f, 1.f);
+ glColor4f(1.f, 0.f, 0.f, 1.f); // in case vertex shaders are enabled
+ glDisableClientState(GL_COLOR_ARRAY);
+
+ for (S32 i = 0; i < NUM_ALPHA_BINS; i++)
+ {
+ if (distance_bins[i].count() < 100)
+ {
+ face_list_t pri_queue;
+ pri_queue.reserve(distance_bins[i].count());
+ for (j = 0; j < distance_bins[i].count(); j++)
+ {
+ pri_queue.push_back(distance_bins[i][j]);
+ }
+ std::sort(pri_queue.begin(), pri_queue.end(), LLFace::CompareDistanceGreater());
+
+ for (face_list_t::iterator iter = pri_queue.begin(); iter != pri_queue.end(); iter++)
+ {
+ const LLFace &face = *(*iter);
+ face.renderIndexed(getRawIndices());
+ mIndicesDrawn += face.getIndicesCount();
+ }
+ }
+ else
+ {
+ for (j = 0; j < distance_bins[i].count(); j++)
+ {
+ const LLFace &face = *distance_bins[i][j];
+ face.renderIndexed(getRawIndices());
+ mIndicesDrawn += face.getIndicesCount();
+ }
+ }
+ }
+
+ if ((mVertexShaderLevel > 0))
+ {
+ gPipeline.mHighlightProgram.unbind();
+ }
+
+ }
+
+}
+
+void LLDrawPoolAlpha::renderForSelect()
+{
+ if (mDrawFace.empty() || !mMemory.count())
+ {
+ return;
+ }
+
+ // force faces on focus object to proper alpha cutoff based on object bbox distance
+ if (gAgent.getFocusObject())
+ {
+ LLDrawable* drawablep = gAgent.getFocusObject()->mDrawable;
+
+ if (drawablep)
+ {
+ const S32 num_faces = drawablep->getNumFaces();
+
+ for (S32 f = 0; f < num_faces; f++)
+ {
+ LLFace* facep = drawablep->getFace(f);
+ facep->mDistance = gAgent.getFocusObjectDist();
+ }
+ }
+ }
+
+ glEnableClientState (GL_VERTEX_ARRAY);
+ glEnableClientState (GL_TEXTURE_COORD_ARRAY);
+
+ LLGLSObjectSelectAlpha gls_alpha;
+
+ glBlendFunc(GL_ONE, GL_ZERO);
+ glAlphaFunc(gPickTransparent ? GL_GEQUAL : GL_GREATER, 0.f);
+
+ bindGLVertexPointer();
+ bindGLTexCoordPointer();
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE);
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PRIMARY_COLOR_ARB);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA);
+
+ LLDynamicArray<LLFace*>* distance_bins;
+ distance_bins = mDistanceBins;
+
+ S32 j;
+ S32 num_bins_no_alpha_test = (gPickAlphaThreshold != 0.f) ?
+ (NUM_ALPHA_BINS - llmax(2, (S32)(ALPHA_FALLOFF_START_DISTANCE * mInvBinSize))) :
+ NUM_ALPHA_BINS;
+
+ S32 i;
+ for (i = 0; i < num_bins_no_alpha_test; i++)
+ {
+ S32 distance_bin_size = distance_bins[i].count();
+ for (j = 0; j < distance_bin_size; j++)
+ {
+ const LLFace &face = *distance_bins[i][j];
+ if (face.getDrawable() && !face.getDrawable()->isDead() && (face.getViewerObject()->mGLName))
+ {
+ face.bindTexture();
+ face.renderForSelect();
+ }
+ }
+ }
+
+ for (i = num_bins_no_alpha_test; i < NUM_ALPHA_BINS; i++)
+ {
+ S32 distance_bin_size = distance_bins[i].count();
+ if (distance_bin_size)
+ {
+ for (j = 0; j < distance_bin_size; j++)
+ {
+ const LLFace &face = *distance_bins[i][j];
+
+ glAlphaFunc(GL_GEQUAL, face.mAlphaFade * gPickAlphaTargetThreshold);
+
+ if (face.getDrawable() && !face.getDrawable()->isDead() && (face.getViewerObject()->mGLName))
+ {
+ face.bindTexture();
+ face.renderForSelect();
+ }
+ }
+ }
+ }
+
+ glAlphaFunc(GL_GREATER, 0.01f);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ glDisableClientState (GL_TEXTURE_COORD_ARRAY);
+}
+
+
+void LLDrawPoolAlpha::renderFaceSelected(LLFace *facep,
+ LLImageGL *image,
+ const LLColor4 &color,
+ const S32 index_offset, const S32 index_count)
+{
+ facep->renderSelected(image, color, index_offset, index_count);
+}
+
+
+void LLDrawPoolAlpha::resetDrawOrders()
+{
+ LLDrawPool::resetDrawOrders();
+
+ for (S32 i = 0; i < NUM_ALPHA_BINS; i++)
+ {
+ mDistanceBins[i].resize(0);
+ }
+}
+
+BOOL LLDrawPoolAlpha::verify() const
+{
+ S32 i, j;
+ BOOL ok;
+ ok = LLDrawPool::verify();
+ for (i = 0; i < NUM_ALPHA_BINS; i++)
+ {
+ for (j = 0; j < mDistanceBins[i].count(); j++)
+ {
+ const LLFace &face = *mDistanceBins[i][j];
+ if (!face.verify())
+ {
+ ok = FALSE;
+ }
+ }
+ }
+ return ok;
+}
+
+LLViewerImage *LLDrawPoolAlpha::getDebugTexture()
+{
+ return LLViewerImage::sSmokeImagep;
+}
+
+
+LLColor3 LLDrawPoolAlpha::getDebugColor() const
+{
+ return LLColor3(1.f, 0.f, 0.f);
+}
+
+S32 LLDrawPoolAlpha::getMaterialAttribIndex()
+{
+ return gPipeline.mObjectAlphaProgram.mAttribute[LLPipeline::GLSL_MATERIAL_COLOR];
+}
+
+// virtual
+void LLDrawPoolAlpha::enableShade()
+{
+ glDisableClientState(GL_COLOR_ARRAY);
+}
+
+// virtual
+void LLDrawPoolAlpha::disableShade()
+{
+ glEnableClientState(GL_COLOR_ARRAY);
+}
+
+// virtual
+void LLDrawPoolAlpha::setShade(F32 shade)
+{
+ glColor4f(0,0,0,shade);
+}