/** * @file lldrawpool.cpp * @brief LLDrawPool class implementation * * $LicenseInfo:firstyear=2002&license=viewergpl$ * * Copyright (c) 2002-2007, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab * to you under the terms of the GNU General Public License, version 2.0 * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or * online at http://secondlife.com/developers/opensource/gplv2 * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or * online at http://secondlife.com/developers/opensource/flossexception * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, * and agree to abide by those obligations. * * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, * COMPLETENESS OR PERFORMANCE. * $/LicenseInfo$ */ #include "llviewerprecompiledheaders.h" #include "lldrawpool.h" #include "llfasttimer.h" #include "llviewercontrol.h" #include "lldrawable.h" #include "lldrawpoolalpha.h" #include "lldrawpoolavatar.h" #include "lldrawpoolbump.h" #include "lldrawpoolclouds.h" #include "lldrawpoolground.h" #include "lldrawpoolsimple.h" #include "lldrawpoolsky.h" #include "lldrawpoolstars.h" #include "lldrawpooltree.h" #include "lldrawpoolterrain.h" #include "lldrawpoolwater.h" #include "llface.h" #include "llviewerobjectlist.h" // For debug listing. #include "pipeline.h" S32 LLDrawPool::sNumDrawPools = 0; //============================= // Draw Pool Implementation //============================= LLDrawPool *LLDrawPool::createPool(const U32 type, LLViewerImage *tex0) { LLDrawPool *poolp = NULL; switch (type) { case POOL_SIMPLE: poolp = new LLDrawPoolSimple(); break; case POOL_GLOW: poolp = new LLDrawPoolGlow(); break; case POOL_ALPHA: poolp = new LLDrawPoolAlpha(); break; case POOL_ALPHA_POST_WATER: poolp = new LLDrawPoolAlphaPostWater(); break; case POOL_AVATAR: poolp = new LLDrawPoolAvatar(); break; case POOL_TREE: poolp = new LLDrawPoolTree(tex0); break; case POOL_TERRAIN: poolp = new LLDrawPoolTerrain(tex0); break; case POOL_SKY: poolp = new LLDrawPoolSky(); break; case POOL_STARS: poolp = new LLDrawPoolStars(); break; case POOL_WATER: poolp = new LLDrawPoolWater(); break; case POOL_GROUND: poolp = new LLDrawPoolGround(); break; case POOL_BUMP: poolp = new LLDrawPoolBump(); break; default: llerrs << "Unknown draw pool type!" << llendl; return NULL; } llassert(poolp->mType == type); return poolp; } LLDrawPool::LLDrawPool(const U32 type) { mType = type; sNumDrawPools++; mId = sNumDrawPools; mVertexShaderLevel = 0; mIndicesDrawn = 0; } LLDrawPool::~LLDrawPool() { } LLViewerImage *LLDrawPool::getDebugTexture() { return NULL; } //virtual void LLDrawPool::beginRenderPass( S32 pass ) { } //virtual void LLDrawPool::endRenderPass( S32 pass ) { glDisableClientState ( GL_TEXTURE_COORD_ARRAY ); glDisableClientState ( GL_COLOR_ARRAY ); glDisableClientState ( GL_NORMAL_ARRAY ); } U32 LLDrawPool::getTrianglesDrawn() const { return mIndicesDrawn / 3; } void LLDrawPool::resetTrianglesDrawn() { mIndicesDrawn = 0; } void LLDrawPool::addIndicesDrawn(const U32 indices) { mIndicesDrawn += indices; } //============================= // Face Pool Implementation //============================= LLFacePool::LLFacePool(const U32 type) : LLDrawPool(type) { resetDrawOrders(); } LLFacePool::~LLFacePool() { destroy(); } void LLFacePool::destroy() { if (!mReferences.empty()) { llinfos << mReferences.size() << " references left on deletion of draw pool!" << llendl; } } void LLFacePool::dirtyTextures(const std::set& textures) { } BOOL LLFacePool::moveFace(LLFace *face, LLDrawPool *poolp, BOOL copy_data) { return TRUE; } // static S32 LLFacePool::drawLoop(face_array_t& face_list) { S32 res = 0; if (!face_list.empty()) { for (std::vector::iterator iter = face_list.begin(); iter != face_list.end(); iter++) { LLFace *facep = *iter; //facep->enableLights(); res += facep->renderIndexed(); } } return res; } // static S32 LLFacePool::drawLoopSetTex(face_array_t& face_list, S32 stage) { S32 res = 0; if (!face_list.empty()) { for (std::vector::iterator iter = face_list.begin(); iter != face_list.end(); iter++) { LLFace *facep = *iter; facep->bindTexture(stage); facep->enableLights(); res += facep->renderIndexed(); } } return res; } void LLFacePool::drawLoop() { if (!mDrawFace.empty()) { mIndicesDrawn += drawLoop(mDrawFace); } } void LLFacePool::renderFaceSelected(LLFace *facep, LLImageGL *image, const LLColor4 &color, const S32 index_offset, const S32 index_count) { } void LLFacePool::renderVisibility() { if (mDrawFace.empty()) { return; } // SJB: Note: This may be broken now. If you need it, fix it :) glLineWidth(1.0); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glTranslatef(-0.4f,-0.3f,0); float table[7][3] = { { 1,0,0 }, { 0,1,0 }, { 1,1,0 }, { 0,0,1 }, { 1,0,1 }, { 0,1,1 }, { 1,1,1 } }; glColor4f(0,0,0,0.5); glBegin(GL_POLYGON); glVertex3f(-0.5f,-0.5f,1.0f); glVertex3f(+0.5f,-0.5f,1.0f); glVertex3f(+0.5f,+0.5f,1.0f); glVertex3f(-0.5f,+0.5f,1.0f); glVertex3f(-0.5f,-0.5f,1.0f); glEnd(); for (std::vector::iterator iter = mDrawFace.begin(); iter != mDrawFace.end(); iter++) { LLFace *face = *iter; S32 geom_count = face->getGeomCount(); for (S32 j=0;jgetReferenceIndex() != -1) { if (facep->getReferenceIndex() != (S32)mReferences.size()) { LLFace *back = mReferences.back(); mReferences[facep->getReferenceIndex()] = back; back->setReferenceIndex(facep->getReferenceIndex()); } mReferences.pop_back(); } facep->setReferenceIndex(-1); } void LLFacePool::addFaceReference(LLFace *facep) { if (-1 == facep->getReferenceIndex()) { facep->setReferenceIndex(mReferences.size()); mReferences.push_back(facep); } } BOOL LLFacePool::verify() const { BOOL ok = TRUE; for (std::vector::const_iterator iter = mDrawFace.begin(); iter != mDrawFace.end(); iter++) { const LLFace* facep = *iter; if (facep->getPool() != this) { llinfos << "Face in wrong pool!" << llendl; facep->printDebugInfo(); ok = FALSE; } else if (!facep->verify()) { ok = FALSE; } } return ok; } void LLFacePool::printDebugInfo() const { llinfos << "Pool " << this << " Type: " << getType() << llendl; } BOOL LLFacePool::LLOverrideFaceColor::sOverrideFaceColor = FALSE; void LLFacePool::LLOverrideFaceColor::setColor(const LLColor4& color) { if (mPool->getVertexShaderLevel() > 0 && mPool->getMaterialAttribIndex() > 0) { glVertexAttrib4fvARB(mPool->getMaterialAttribIndex(), color.mV); } else { glColor4fv(color.mV); } } void LLFacePool::LLOverrideFaceColor::setColor(const LLColor4U& color) { if (mPool->getVertexShaderLevel() > 0 && mPool->getMaterialAttribIndex() > 0) { glVertexAttrib4ubvARB(mPool->getMaterialAttribIndex(), color.mV); } else { glColor4ubv(color.mV); } } void LLFacePool::LLOverrideFaceColor::setColor(F32 r, F32 g, F32 b, F32 a) { if (mPool->getVertexShaderLevel() > 0 && mPool->getMaterialAttribIndex() > 0) { glVertexAttrib4fARB(mPool->getMaterialAttribIndex(), r,g,b,a); } else { glColor4f(r,g,b,a); } } //============================= // Render Pass Implementation //============================= LLRenderPass::LLRenderPass(const U32 type) : LLDrawPool(type) { } LLRenderPass::~LLRenderPass() { } LLDrawPool* LLRenderPass::instancePool() { #if LL_RELEASE_FOR_DOWNLOAD llwarns << "Attempting to instance a render pass. Invalid operation." << llendl; #else llerrs << "Attempting to instance a render pass. Invalid operation." << llendl; #endif return NULL; } void LLRenderPass::renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture) { LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[type]; for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) { LLDrawInfo *pparams = *k; if (pparams) { pushBatch(*pparams, mask, texture); } } } void LLRenderPass::renderInvisible(U32 mask) { #if !LL_RELEASE_FOR_DOWNLOAD LLGLState::checkClientArrays(mask); #endif LLSpatialGroup::drawmap_elem_t& draw_info = gPipeline.mRenderMap[LLRenderPass::PASS_INVISIBLE]; for (LLSpatialGroup::drawmap_elem_t::iterator i = draw_info.begin(); i != draw_info.end(); ++i) { LLDrawInfo *pparams = *i; if (pparams && pparams->mVertexBuffer.notNull()) { LLDrawInfo ¶ms = *pparams; params.mVertexBuffer->setBuffer(mask); U32 *indices_pointer = (U32 *) params.mVertexBuffer->getIndicesPointer(); glDrawRangeElements(GL_TRIANGLES, params.mStart, params.mEnd, params.mCount, GL_UNSIGNED_INT, indices_pointer + params.mOffset); gPipeline.mTrianglesDrawn += params.mCount / 3; } } } void LLRenderPass::renderTexture(U32 type, U32 mask) { #if !LL_RELEASE_FOR_DOWNLOAD LLGLState::checkClientArrays(mask); #endif LLSpatialGroup::drawmap_elem_t& draw_info = gPipeline.mRenderMap[type]; for (LLSpatialGroup::drawmap_elem_t::iterator i = draw_info.begin(); i != draw_info.end(); ++i) { LLDrawInfo* pparams = *i; if (pparams) { pushBatch(*pparams, mask, TRUE); } } } void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture) { if (texture) { if (params.mTexture.notNull()) { params.mTexture->bind(); if (params.mTextureMatrix) { glMatrixMode(GL_TEXTURE); glLoadMatrixf((GLfloat*) params.mTextureMatrix->mMatrix); } params.mTexture->addTextureStats(params.mVSize); } else { LLImageGL::unbindTexture(0); } } if (params.mVertexBuffer.notNull()) { params.mVertexBuffer->setBuffer(mask); U32* indices_pointer = (U32*) params.mVertexBuffer->getIndicesPointer(); glDrawRangeElements(GL_TRIANGLES, params.mStart, params.mEnd, params.mCount, GL_UNSIGNED_INT, indices_pointer+params.mOffset); gPipeline.mTrianglesDrawn += params.mCount/3; } if (params.mTextureMatrix && texture && params.mTexture.notNull()) { glLoadIdentity(); glMatrixMode(GL_MODELVIEW); } } void LLRenderPass::renderActive(U32 type, U32 mask, BOOL texture) { #if !LL_RELEASE_FOR_DOWNLOAD LLGLState::checkClientArrays(mask); #endif LLSpatialBridge* last_bridge = NULL; glPushMatrix(); for (LLSpatialGroup::sg_vector_t::iterator i = gPipeline.mActiveGroups.begin(); i != gPipeline.mActiveGroups.end(); ++i) { LLSpatialGroup* group = *i; if (!group->isDead() && gPipeline.hasRenderType(group->mSpatialPartition->mDrawableType) && group->mDrawMap.find(type) != group->mDrawMap.end()) { LLSpatialBridge* bridge = (LLSpatialBridge*) group->mSpatialPartition; if (bridge != last_bridge) { glPopMatrix(); glPushMatrix(); glMultMatrixf((F32*) bridge->mDrawable->getRenderMatrix().mMatrix); last_bridge = bridge; } renderGroup(group,type,mask,texture); } } glPopMatrix(); } void LLRenderPass::renderStatic(U32 type, U32 mask, BOOL texture) { #if !LL_RELEASE_FOR_DOWNLOAD LLGLState::checkClientArrays(mask); #endif for (LLSpatialGroup::sg_vector_t::iterator i = gPipeline.mVisibleGroups.begin(); i != gPipeline.mVisibleGroups.end(); ++i) { LLSpatialGroup* group = *i; if (!group->isDead() && gPipeline.hasRenderType(group->mSpatialPartition->mDrawableType) && group->mDrawMap.find(type) != group->mDrawMap.end()) { renderGroup(group,type,mask,texture); } } }