/** * @file lldrawpoolavatar.cpp * @brief LLDrawPoolAvatar class implementation * * 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. */ #include "llviewerprecompiledheaders.h" #include "lldrawpoolavatar.h" #include "llvoavatar.h" #include "m3math.h" #include "llagent.h" #include "lldrawable.h" #include "llface.h" #include "llsky.h" #include "llviewercamera.h" #include "llviewerregion.h" #include "noise.h" #include "pipeline.h" #include "llglslshader.h" static U32 sDataMask = LLDrawPoolAvatar::VERTEX_DATA_MASK; static U32 sBufferUsage = GL_STREAM_DRAW_ARB; static U32 sShaderLevel = 0; static LLGLSLShader* sVertexProgram = NULL; extern F32 gFrameDTClamped; extern BOOL gUseGLPick; F32 CLOTHING_GRAVITY_EFFECT = 0.7f; F32 CLOTHING_ACCEL_FORCE_FACTOR = 0.2f; const S32 NUM_TEST_AVATARS = 30; const S32 MIN_PIXEL_AREA_2_PASS_SKINNING = 500000000; // Format for gAGPVertices // vertex format for bumpmapping: // vertices 12 // pad 4 // normals 12 // pad 4 // texcoords0 8 // texcoords1 8 // total 48 // // for no bumpmapping // vertices 12 // texcoords 8 // normals 12 // total 32 // S32 AVATAR_OFFSET_POS = 0; S32 AVATAR_OFFSET_NORMAL = 16; S32 AVATAR_OFFSET_TEX0 = 32; S32 AVATAR_OFFSET_TEX1 = 40; S32 AVATAR_VERTEX_BYTES = 48; BOOL gAvatarEmbossBumpMap = FALSE; static BOOL sRenderingSkinned = FALSE; LLDrawPoolAvatar::LLDrawPoolAvatar() : LLFacePool(POOL_AVATAR) { //LLDebugVarMessageBox::show("acceleration", &CLOTHING_ACCEL_FORCE_FACTOR, 10.f, 0.1f); //LLDebugVarMessageBox::show("gravity", &CLOTHING_GRAVITY_EFFECT, 10.f, 0.1f); } //----------------------------------------------------------------------------- // instancePool() //----------------------------------------------------------------------------- LLDrawPool *LLDrawPoolAvatar::instancePool() { return new LLDrawPoolAvatar(); } BOOL gRenderAvatar = TRUE; S32 LLDrawPoolAvatar::getVertexShaderLevel() const { return sShaderLevel; //return (S32) LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_AVATAR); } void LLDrawPoolAvatar::prerender() { mVertexShaderLevel = LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_AVATAR); sShaderLevel = mVertexShaderLevel; if (sShaderLevel > 0) { sBufferUsage = GL_STATIC_DRAW_ARB; } else { sBufferUsage = GL_STREAM_DRAW_ARB; } } LLMatrix4& LLDrawPoolAvatar::getModelView() { static LLMatrix4 ret; ret.initRows(LLVector4(gGLModelView+0), LLVector4(gGLModelView+4), LLVector4(gGLModelView+8), LLVector4(gGLModelView+12)); return ret; } //----------------------------------------------------------------------------- // render() //----------------------------------------------------------------------------- S32 LLDrawPoolAvatar::getNumPasses() { return 3; } void LLDrawPoolAvatar::render(S32 pass) { LLFastTimer t(LLFastTimer::FTM_RENDER_CHARACTERS); renderAvatars(NULL, pass); // render all avatars } void LLDrawPoolAvatar::beginRenderPass(S32 pass) { //reset vertex buffer mappings LLVertexBuffer::unbind(); switch (pass) { case 0: beginFootShadow(); break; case 1: beginRigid(); break; case 2: beginSkinned(); break; } } void LLDrawPoolAvatar::endRenderPass(S32 pass) { switch (pass) { case 0: endFootShadow(); break; case 1: endRigid(); break; case 2: endSkinned(); } } void LLDrawPoolAvatar::beginFootShadow() { glDepthMask(GL_FALSE); gPipeline.enableLightsFullbright(LLColor4(1,1,1,1)); glEnableClientState(GL_TEXTURE_COORD_ARRAY); } void LLDrawPoolAvatar::endFootShadow() { gPipeline.enableLightsDynamic(1.f); glDepthMask(GL_TRUE); glDisableClientState(GL_TEXTURE_COORD_ARRAY); } void LLDrawPoolAvatar::beginRigid() { sVertexProgram = NULL; sShaderLevel = 0; glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); /*if (sShaderLevel > 0) { //eyeballs render with the specular shader gAvatarEyeballProgram.bind(); gMaterialIndex = gAvatarEyeballProgram.mAttribute[LLShaderMgr::MATERIAL_COLOR]; gSpecularIndex = gAvatarEyeballProgram.mAttribute[LLShaderMgr::SPECULAR_COLOR]; }*/ } void LLDrawPoolAvatar::endRigid() { sShaderLevel = mVertexShaderLevel; glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); } void LLDrawPoolAvatar::beginSkinned() { glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); sVertexProgram = &gAvatarProgram; if (sShaderLevel > 0) // for hardware blending { sRenderingSkinned = TRUE; glClientActiveTextureARB(GL_TEXTURE1_ARB); if (sShaderLevel >= SHADER_LEVEL_BUMP) { gMaterialIndex = sVertexProgram->mAttribute[LLShaderMgr::MATERIAL_COLOR]; gSpecularIndex = sVertexProgram->mAttribute[LLShaderMgr::SPECULAR_COLOR]; } sVertexProgram->bind(); if (sShaderLevel >= SHADER_LEVEL_CLOTH) { enable_cloth_weights(sVertexProgram->mAttribute[LLShaderMgr::AVATAR_CLOTHING]); } enable_vertex_weighting(sVertexProgram->mAttribute[LLShaderMgr::AVATAR_WEIGHT]); if (sShaderLevel >= SHADER_LEVEL_BUMP) { enable_binormals(sVertexProgram->mAttribute[LLShaderMgr::BINORMAL]); } sVertexProgram->enableTexture(LLShaderMgr::BUMP_MAP); glActiveTextureARB(GL_TEXTURE0_ARB); } } void LLDrawPoolAvatar::endSkinned() { // if we're in software-blending, remember to set the fence _after_ we draw so we wait till this rendering is done if (sShaderLevel > 0) { sRenderingSkinned = FALSE; sVertexProgram->disableTexture(LLShaderMgr::BUMP_MAP); glActiveTextureARB(GL_TEXTURE0_ARB); glClientActiveTextureARB(GL_TEXTURE0_ARB); disable_vertex_weighting(sVertexProgram->mAttribute[LLShaderMgr::AVATAR_WEIGHT]); if (sShaderLevel >= SHADER_LEVEL_BUMP) { disable_binormals(sVertexProgram->mAttribute[LLShaderMgr::BINORMAL]); } if ((sShaderLevel >= SHADER_LEVEL_CLOTH)) { disable_cloth_weights(sVertexProgram->mAttribute[LLShaderMgr::AVATAR_CLOTHING]); } sVertexProgram->unbind(); } glActiveTextureARB(GL_TEXTURE0_ARB); glClientActiveTextureARB(GL_TEXTURE0_ARB); glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); } void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) { if (pass == -1) { for (S32 i = 1; i < getNumPasses(); i++) { //skip foot shadows prerender(); beginRenderPass(i); renderAvatars(single_avatar, i); endRenderPass(i); } return; } if (!gRenderAvatar) { return; } if (mDrawFace.empty() && !single_avatar) { return; } LLVOAvatar *avatarp; if (single_avatar) { avatarp = single_avatar; } else { const LLFace *facep = mDrawFace[0]; if (!facep->getDrawable()) { return; } avatarp = (LLVOAvatar *)facep->getDrawable()->getVObj().get(); } if (avatarp->isDead() || avatarp->mDrawable.isNull()) { return; } LLOverrideFaceColor color(this, 1.0f, 1.0f, 1.0f, 1.0f); if (pass == 0) { if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FOOT_SHADOWS)) { mIndicesDrawn += avatarp->renderFootShadows(); } return; } if (avatarp->mSpecialRenderMode == 0) // normal { gPipeline.enableLightsAvatar(avatarp->mDrawable->getSunShadowFactor()); } else if (avatarp->mSpecialRenderMode == 1) // anim preview { gPipeline.enableLightsAvatarEdit(LLColor4(0.7f, 0.6f, 0.3f, 1.f)); } else // 2=image preview, 3=morph view { gPipeline.enableLightsAvatarEdit(LLColor4(.5f, .5f, .5f, 1.f)); } if (pass == 1) { // render rigid meshes (eyeballs) first mIndicesDrawn += avatarp->renderRigid(); if (!gRenderForSelect && avatarp->mIsSelf && LLVOAvatar::sAvatarLoadTest) { LLVector3 orig_pos_root = avatarp->mRoot.getPosition(); LLVector3 next_pos_root = orig_pos_root; for (S32 i = 0; i < NUM_TEST_AVATARS; i++) { next_pos_root.mV[VX] += 1.f; if (i % 5 == 0) { next_pos_root.mV[VY] += 1.f; next_pos_root.mV[VX] = orig_pos_root.mV[VX]; } avatarp->mRoot.setPosition(next_pos_root); // avatar load test avatarp->mRoot.updateWorldMatrixChildren(); // avatar load test mIndicesDrawn += avatarp->renderRigid(); } avatarp->mRoot.setPosition(orig_pos_root); // avatar load test avatarp->mRoot.updateWorldMatrixChildren(); // avatar load test } return; } if (sShaderLevel > 0) { gAvatarMatrixParam = sVertexProgram->mUniform[LLShaderMgr::AVATAR_MATRIX]; } if ((sShaderLevel >= SHADER_LEVEL_CLOTH)) { LLMatrix4 rot_mat; gCamera->getMatrixToLocal(rot_mat); LLMatrix4 cfr(OGL_TO_CFR_ROTATION); rot_mat *= cfr; LLVector4 wind; wind.setVec(avatarp->mWindVec); wind.mV[VW] = 0; wind = wind * rot_mat; wind.mV[VW] = avatarp->mWindVec.mV[VW]; sVertexProgram->vertexAttrib4fv(LLShaderMgr::AVATAR_WIND, wind.mV); F32 phase = -1.f * (avatarp->mRipplePhase); F32 freq = 7.f + (noise1(avatarp->mRipplePhase) * 2.f); LLVector4 sin_params(freq, freq, freq, phase); sVertexProgram->vertexAttrib4fv(LLShaderMgr::AVATAR_SINWAVE, sin_params.mV); LLVector4 gravity(0.f, 0.f, -CLOTHING_GRAVITY_EFFECT, 0.f); gravity = gravity * rot_mat; sVertexProgram->vertexAttrib4fv(LLShaderMgr::AVATAR_GRAVITY, gravity.mV); } if( !single_avatar || (avatarp == single_avatar) ) { if (LLVOAvatar::sShowCollisionVolumes) { LLGLSNoTexture no_texture; avatarp->renderCollisionVolumes(); } if (avatarp->mIsSelf && LLAgent::sDebugDisplayTarget) { LLGLSNoTexture gls_no_texture; LLVector3 pos = avatarp->getPositionAgent(); color.setColor(1.0f, 0.0f, 0.0f, 0.8f); glBegin(GL_LINES); { glVertex3fv((pos - LLVector3(0.2f, 0.f, 0.f)).mV); glVertex3fv((pos + LLVector3(0.2f, 0.f, 0.f)).mV); glVertex3fv((pos - LLVector3(0.f, 0.2f, 0.f)).mV); glVertex3fv((pos + LLVector3(0.f, 0.2f, 0.f)).mV); glVertex3fv((pos - LLVector3(0.f, 0.f, 0.2f)).mV); glVertex3fv((pos + LLVector3(0.f, 0.f, 0.2f)).mV); }glEnd(); pos = avatarp->mDrawable->getPositionAgent(); color.setColor(1.0f, 0.0f, 0.0f, 0.8f); glBegin(GL_LINES); { glVertex3fv((pos - LLVector3(0.2f, 0.f, 0.f)).mV); glVertex3fv((pos + LLVector3(0.2f, 0.f, 0.f)).mV); glVertex3fv((pos - LLVector3(0.f, 0.2f, 0.f)).mV); glVertex3fv((pos + LLVector3(0.f, 0.2f, 0.f)).mV); glVertex3fv((pos - LLVector3(0.f, 0.f, 0.2f)).mV); glVertex3fv((pos + LLVector3(0.f, 0.f, 0.2f)).mV); }glEnd(); pos = avatarp->mRoot.getWorldPosition(); color.setColor(1.0f, 1.0f, 1.0f, 0.8f); glBegin(GL_LINES); { glVertex3fv((pos - LLVector3(0.2f, 0.f, 0.f)).mV); glVertex3fv((pos + LLVector3(0.2f, 0.f, 0.f)).mV); glVertex3fv((pos - LLVector3(0.f, 0.2f, 0.f)).mV); glVertex3fv((pos + LLVector3(0.f, 0.2f, 0.f)).mV); glVertex3fv((pos - LLVector3(0.f, 0.f, 0.2f)).mV); glVertex3fv((pos + LLVector3(0.f, 0.f, 0.2f)).mV); }glEnd(); pos = avatarp->mPelvisp->getWorldPosition(); color.setColor(0.0f, 0.0f, 1.0f, 0.8f); glBegin(GL_LINES); { glVertex3fv((pos - LLVector3(0.2f, 0.f, 0.f)).mV); glVertex3fv((pos + LLVector3(0.2f, 0.f, 0.f)).mV); glVertex3fv((pos - LLVector3(0.f, 0.2f, 0.f)).mV); glVertex3fv((pos + LLVector3(0.f, 0.2f, 0.f)).mV); glVertex3fv((pos - LLVector3(0.f, 0.f, 0.2f)).mV); glVertex3fv((pos + LLVector3(0.f, 0.f, 0.2f)).mV); }glEnd(); color.setColor(1.0f, 1.0f, 1.0f, 1.0f); } mIndicesDrawn += avatarp->renderSkinned(AVATAR_RENDER_PASS_SINGLE); if (!gRenderForSelect && avatarp->mIsSelf && LLVOAvatar::sAvatarLoadTest) { LLVector3 orig_pos_root = avatarp->mRoot.getPosition(); LLVector3 next_pos_root = orig_pos_root; for (S32 i = 0; i < NUM_TEST_AVATARS; i++) { next_pos_root.mV[VX] += 1.f; if (i % 5 == 0) { next_pos_root.mV[VY] += 1.f; next_pos_root.mV[VX] = orig_pos_root.mV[VX]; } avatarp->mRoot.setPosition(next_pos_root); // avatar load test avatarp->mRoot.updateWorldMatrixChildren(); // avatar load test mIndicesDrawn += avatarp->renderSkinned(AVATAR_RENDER_PASS_SINGLE); } avatarp->mRoot.setPosition(orig_pos_root); // avatar load test avatarp->mRoot.updateWorldMatrixChildren(); // avatar load test } } } //----------------------------------------------------------------------------- // renderForSelect() //----------------------------------------------------------------------------- void LLDrawPoolAvatar::renderForSelect() { if (gUseGLPick) { return; } if (!gRenderAvatar) { return; } if (mDrawFace.empty()) { return; } const LLFace *facep = mDrawFace[0]; if (!facep->getDrawable()) { return; } LLVOAvatar *avatarp = (LLVOAvatar *)facep->getDrawable()->getVObj().get(); if (avatarp->isDead() || avatarp->mIsDummy || avatarp->mDrawable.isNull()) { return; } glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); sVertexProgram = &gAvatarPickProgram; if (sShaderLevel > 0) { gAvatarMatrixParam = sVertexProgram->mUniform[LLShaderMgr::AVATAR_MATRIX]; } glAlphaFunc(GL_GEQUAL, 0.2f); glBlendFunc(GL_ONE, GL_ZERO); S32 name = avatarp->mDrawable->getVObj()->mGLName; LLColor4U color((U8)(name >> 16), (U8)(name >> 8), (U8)name); glColor4ubv(color.mV); // render rigid meshes (eyeballs) first //mIndicesDrawn += avatarp->renderRigid(); if ((sShaderLevel > 0) && !gUseGLPick) // for hardware blending { glClientActiveTextureARB(GL_TEXTURE0_ARB); sRenderingSkinned = TRUE; sVertexProgram->bind(); enable_vertex_weighting(sVertexProgram->mAttribute[LLShaderMgr::AVATAR_WEIGHT]); } mIndicesDrawn += avatarp->renderSkinned(AVATAR_RENDER_PASS_SINGLE); // if we're in software-blending, remember to set the fence _after_ we draw so we wait till this rendering is done if ((sShaderLevel > 0) && !gUseGLPick) { sRenderingSkinned = FALSE; sVertexProgram->unbind(); disable_vertex_weighting(sVertexProgram->mAttribute[LLShaderMgr::AVATAR_WEIGHT]); } glAlphaFunc(GL_GREATER, 0.01f); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // restore texture mode glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); } //----------------------------------------------------------------------------- // getDebugTexture() //----------------------------------------------------------------------------- LLViewerImage *LLDrawPoolAvatar::getDebugTexture() { if (mReferences.empty()) { return NULL; } LLFace *face = mReferences[0]; if (!face->getDrawable()) { return NULL; } const LLViewerObject *objectp = face->getDrawable()->getVObj(); // Avatar should always have at least 1 (maybe 3?) TE's. return objectp->getTEImage(0); } LLColor3 LLDrawPoolAvatar::getDebugColor() const { return LLColor3(0.f, 1.f, 0.f); } LLVertexBufferAvatar::LLVertexBufferAvatar() : LLVertexBuffer(sDataMask, LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_AVATAR) > 0 ? GL_STATIC_DRAW_ARB : GL_STREAM_DRAW_ARB) { } void LLVertexBufferAvatar::setupVertexBuffer(U32 data_mask) const { if (sRenderingSkinned) { U8* base = useVBOs() ? NULL : mMappedData; glVertexPointer(3,GL_FLOAT, mStride, (void*)(base + 0)); glNormalPointer(GL_FLOAT, mStride, (void*)(base + mOffsets[TYPE_NORMAL])); glClientActiveTextureARB(GL_TEXTURE1_ARB); glTexCoordPointer(2,GL_FLOAT, mStride, (void*)(base + mOffsets[TYPE_TEXCOORD2])); glClientActiveTextureARB(GL_TEXTURE0_ARB); glTexCoordPointer(2,GL_FLOAT, mStride, (void*)(base + mOffsets[TYPE_TEXCOORD])); set_vertex_weights(sVertexProgram->mAttribute[LLShaderMgr::AVATAR_WEIGHT], mStride, (F32*)(base + mOffsets[TYPE_WEIGHT])); if (sShaderLevel >= LLDrawPoolAvatar::SHADER_LEVEL_BUMP) { set_binormals(sVertexProgram->mAttribute[LLShaderMgr::BINORMAL], mStride, (LLVector3*)(base + mOffsets[TYPE_BINORMAL])); } if (sShaderLevel >= LLDrawPoolAvatar::SHADER_LEVEL_CLOTH) { set_vertex_clothing_weights(sVertexProgram->mAttribute[LLShaderMgr::AVATAR_CLOTHING], mStride, (LLVector4*)(base + mOffsets[TYPE_CLOTHWEIGHT])); } } else { LLVertexBuffer::setupVertexBuffer(data_mask); } }