diff options
-rw-r--r-- | indra/llmath/llmath.h | 7 | ||||
-rw-r--r-- | indra/llwindow/llwindowmacosx.cpp | 1 | ||||
-rw-r--r-- | indra/llwindow/llwindowsdl.cpp | 3 | ||||
-rw-r--r-- | indra/llwindow/llwindowwin32.cpp | 1 | ||||
-rw-r--r-- | indra/newview/app_settings/settings.xml | 84 | ||||
-rw-r--r-- | indra/newview/llchathistory.cpp | 2 | ||||
-rw-r--r-- | indra/newview/llfloatertools.cpp | 32 | ||||
-rw-r--r-- | indra/newview/llfloatertools.h | 1 | ||||
-rw-r--r-- | indra/newview/llselectmgr.cpp | 4 | ||||
-rw-r--r-- | indra/newview/llspatialpartition.cpp | 116 | ||||
-rw-r--r-- | indra/newview/llviewercontrol.cpp | 8 | ||||
-rw-r--r-- | indra/newview/llviewerobjectlist.cpp | 4 | ||||
-rw-r--r-- | indra/newview/llvoavatar.cpp | 53 | ||||
-rw-r--r-- | indra/newview/llvoavatar.h | 2198 | ||||
-rwxr-xr-x | indra/newview/llvovolume.cpp | 9967 | ||||
-rw-r--r-- | indra/newview/llvovolume.h | 16 | ||||
-rw-r--r-- | indra/newview/pipeline.h | 1 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/menu_viewer.xml | 12 |
18 files changed, 6449 insertions, 6061 deletions
diff --git a/indra/llmath/llmath.h b/indra/llmath/llmath.h index eea7c977fb..9297bcbac2 100644 --- a/indra/llmath/llmath.h +++ b/indra/llmath/llmath.h @@ -510,6 +510,13 @@ inline void ll_remove_outliers(std::vector<VEC_TYPE>& data, F32 k) VEC_TYPE Q1 = data[data.size()/4]; VEC_TYPE Q3 = data[data.size()-data.size()/4-1]; + if ((F32)(Q3-Q1) < 1.f) + { + // not enough variation to detect outliers + return; + } + + VEC_TYPE min = (VEC_TYPE) ((F32) Q1-k * (F32) (Q3-Q1)); VEC_TYPE max = (VEC_TYPE) ((F32) Q3+k * (F32) (Q3-Q1)); diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index cb2abc5bc0..4dd11541b9 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -1266,6 +1266,7 @@ BOOL LLWindowMacOSX::setSize(const LLCoordScreen size) void LLWindowMacOSX::swapBuffers() { + glFinish(); aglSwapBuffers(mContext); } diff --git a/indra/llwindow/llwindowsdl.cpp b/indra/llwindow/llwindowsdl.cpp index b65287715c..e41aa9820f 100644 --- a/indra/llwindow/llwindowsdl.cpp +++ b/indra/llwindow/llwindowsdl.cpp @@ -984,7 +984,10 @@ BOOL LLWindowSDL::setSize(const LLCoordScreen size) void LLWindowSDL::swapBuffers() { if (mWindow) + { + glFinish(); SDL_GL_SwapBuffers(); + } } U32 LLWindowSDL::getFSAASamples() diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 551d487cc8..20286b4ca8 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -2865,6 +2865,7 @@ BOOL LLWindowWin32::resetDisplayResolution() void LLWindowWin32::swapBuffers() { + glFinish(); SwapBuffers(mhDC); } diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 01842d1037..66e8610d59 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -7317,7 +7317,89 @@ <key>Value</key> <integer>1</integer> </map> - <key>RenderAvatarLODFactor</key> + <key>RenderAvatarComplexityLimit</key> + <map> + <key>Comment</key> + <string>Max visual complexity of avatars in a scene</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>S32</string> + <key>Value</key> + <integer>-1</integer> + </map> + <key>RenderComplexityColorMin</key> + <map> + <key>Comment</key> + <string>Max visual complexity of avatars in a scene</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Color4</string> + <key>Value</key> + <array> + <real>0.0</real> + <real>0.0</real> + <real>1.0</real> + <real>0.5</real> + </array> + </map> + <key>RenderComplexityColorMid</key> + <map> + <key>Comment</key> + <string>Max visual complexity of avatars in a scene</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Color4</string> + <key>Value</key> + <array> + <real>0.0</real> + <real>1.0</real> + <real>0.0</real> + <real>0.5</real> + </array> + </map> + <key>RenderComplexityColorMax</key> + <map> + <key>Comment</key> + <string>Max visual complexity of avatars in a scene</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Color4</string> + <key>Value</key> + <array> + <real>1.0</real> + <real>0.0</real> + <real>0.0</real> + <real>0.5</real> + </array> + </map> + <key>RenderComplexityThreshold</key> + <map> + <key>Comment</key> + <string>Only color objects higher than render threshold</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>S32</string> + <key>Value</key> + <integer>-1</integer> + </map> + <key>RenderComplexityStaticMax</key> + <map> + <key>Comment</key> + <string>Sets a static max value for scaling of RenderComplexity + display (-1 for dynamic scaling)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>S32</string> + <key>Value</key> + <integer>-1</integer> + </map> + <key>RenderAvatarLODFactor</key> <map> <key>Comment</key> <string>Controls level of detail of avatars (multiplier for current screen area when calculated level of detail)</string> diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index c0c9ea1451..913d2f34b0 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -255,7 +255,7 @@ public: mSourceType = chat.mSourceType; //*TODO overly defensive thing, source type should be maintained out there - if((chat.mFromID.isNull() && chat.mFromName.empty()) || chat.mFromName == SYSTEM_FROM && chat.mFromID.isNull()) + if((chat.mFromID.isNull() && chat.mFromName.empty()) || (chat.mFromName == SYSTEM_FROM && chat.mFromID.isNull())) { mSourceType = CHAT_SOURCE_SYSTEM; } diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp index 00a0da3cde..c3b5cd4260 100644 --- a/indra/newview/llfloatertools.cpp +++ b/indra/newview/llfloatertools.cpp @@ -435,7 +435,8 @@ void LLFloaterTools::refresh() if (sShowObjectCost) { std::string prim_cost_string; - LLResMgr::getInstance()->getIntegerString(prim_cost_string, calcRenderCost()); + S32 cost = LLSelectMgr::getInstance()->getSelection()->getSelectedObjectRenderCost(); + LLResMgr::getInstance()->getIntegerString(prim_cost_string, cost); getChild<LLUICtrl>("RenderingCost")->setTextArg("[COUNT]", prim_cost_string); } @@ -1014,35 +1015,6 @@ void LLFloaterTools::onClickGridOptions() //floaterp->addDependentFloater(LLFloaterBuildOptions::getInstance(), FALSE); } -S32 LLFloaterTools::calcRenderCost() -{ - S32 cost = 0; - std::set<LLUUID> textures; - - for (LLObjectSelection::iterator selection_iter = LLSelectMgr::getInstance()->getSelection()->begin(); - selection_iter != LLSelectMgr::getInstance()->getSelection()->end(); - ++selection_iter) - { - LLSelectNode *select_node = *selection_iter; - if (select_node) - { - LLViewerObject *vobj = select_node->getObject(); - if (vobj->getVolume()) - { - LLVOVolume* volume = (LLVOVolume*) vobj; - - cost += volume->getRenderCost(textures); - cost += textures.size() * LLVOVolume::ARC_TEXTURE_COST; - textures.clear(); - } - } - } - - - return cost; -} - - // static void LLFloaterTools::setEditTool(void* tool_pointer) { diff --git a/indra/newview/llfloatertools.h b/indra/newview/llfloatertools.h index 69636190fc..8c4cb721d3 100644 --- a/indra/newview/llfloatertools.h +++ b/indra/newview/llfloatertools.h @@ -113,7 +113,6 @@ private: static bool multipleFacesSelectedConfirm(const LLSD& notification, const LLSD& response); static void setObjectType( LLPCode pcode ); void onClickGridOptions(); - S32 calcRenderCost(); public: LLButton *mBtnFocus; diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 8fa4065fa6..9c85817a28 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -6522,7 +6522,7 @@ U32 LLObjectSelection::getSelectedObjectTriangleCount() return count; } -/*S32 LLObjectSelection::getSelectedObjectRenderCost() +S32 LLObjectSelection::getSelectedObjectRenderCost() { S32 cost = 0; LLVOVolume::texture_cost_t textures; @@ -6546,7 +6546,7 @@ U32 LLObjectSelection::getSelectedObjectTriangleCount() return cost; -}*/ +} //----------------------------------------------------------------------------- diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index e23b431457..8654d6d635 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -2758,6 +2758,115 @@ void renderUpdateType(LLDrawable* drawablep) } } +void renderComplexityDisplay(LLDrawable* drawablep) +{ + LLViewerObject* vobj = drawablep->getVObj(); + if (!vobj) + { + return; + } + + LLVOVolume *voVol = dynamic_cast<LLVOVolume*>(vobj); + + if (!voVol) + { + return; + } + + if (!voVol->isRoot()) + { + return; + } + + LLVOVolume::texture_cost_t textures; + F32 cost = (F32) voVol->getRenderCost(textures); + + // add any child volumes + LLViewerObject::const_child_list_t children = voVol->getChildren(); + for (LLViewerObject::const_child_list_t::const_iterator iter = children.begin(); iter != children.end(); ++iter) + { + const LLViewerObject *child = *iter; + const LLVOVolume *child_volume = dynamic_cast<const LLVOVolume*>(child); + if (child_volume) + { + cost += child_volume->getRenderCost(textures); + } + } + + // add texture cost + for (LLVOVolume::texture_cost_t::iterator iter = textures.begin(); iter != textures.end(); ++iter) + { + // add the cost of each individual texture in the linkset + cost += iter->second; + } + + F32 cost_max = (F32) LLVOVolume::getRenderComplexityMax(); + + + + // allow user to set a static color scale + if (gSavedSettings.getS32("RenderComplexityStaticMax") > 0) + { + cost_max = gSavedSettings.getS32("RenderComplexityStaticMax"); + } + + F32 cost_ratio = cost / cost_max; + + // cap cost ratio at 1.0f in case cost_max is at a low threshold + cost_ratio = cost_ratio > 1.0f ? 1.0f : cost_ratio; + + LLGLEnable blend(GL_BLEND); + + LLColor4 color; + const LLColor4 color_min = gSavedSettings.getColor4("RenderComplexityColorMin"); + const LLColor4 color_mid = gSavedSettings.getColor4("RenderComplexityColorMid"); + const LLColor4 color_max = gSavedSettings.getColor4("RenderComplexityColorMax"); + + if (cost_ratio < 0.5f) + { + color = color_min * (1 - cost_ratio * 2) + color_mid * (cost_ratio * 2); + } + else + { + color = color_mid * (1 - (cost_ratio - 0.5) * 2) + color_max * ((cost_ratio - 0.5) * 2); + } + + LLSD color_val = color.getValue(); + + // don't highlight objects below the threshold + if (cost > gSavedSettings.getS32("RenderComplexityThreshold")) + { + glColor4f(color[0],color[1],color[2],0.5f); + + + S32 num_faces = drawablep->getNumFaces(); + if (num_faces) + { + for (S32 i = 0; i < num_faces; ++i) + { + pushVerts(drawablep->getFace(i), LLVertexBuffer::MAP_VERTEX); + } + } + LLViewerObject::const_child_list_t children = voVol->getChildren(); + for (LLViewerObject::const_child_list_t::const_iterator iter = children.begin(); iter != children.end(); ++iter) + { + const LLViewerObject *child = *iter; + if (child) + { + num_faces = child->getNumFaces(); + if (num_faces) + { + for (S32 i = 0; i < num_faces; ++i) + { + pushVerts(child->mDrawable->getFace(i), LLVertexBuffer::MAP_VERTEX); + } + } + } + } + } + + voVol->setDebugText(llformat("%4.0f", cost)); +} void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE) { @@ -3862,6 +3971,10 @@ public: { renderUpdateType(drawable); } + if(gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RENDER_COMPLEXITY)) + { + renderComplexityDisplay(drawable); + } LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(drawable->getVObj().get()); @@ -4110,7 +4223,8 @@ void LLSpatialPartition::renderDebug() LLPipeline::RENDER_DEBUG_AVATAR_VOLUME | LLPipeline::RENDER_DEBUG_AGENT_TARGET | //LLPipeline::RENDER_DEBUG_BUILD_QUEUE | - LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) + LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA | + LLPipeline::RENDER_DEBUG_RENDER_COMPLEXITY)) { return; } diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 2bafca70b6..0f0b7d7e78 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -142,7 +142,6 @@ static bool handleRenderPerfTestChanged(const LLSD& newvalue) LLPipeline::RENDER_TYPE_WATER, LLPipeline::RENDER_TYPE_PASS_GRASS, LLPipeline::RENDER_TYPE_HUD, - LLPipeline::RENDER_TYPE_PARTICLES, LLPipeline::RENDER_TYPE_CLOUDS, LLPipeline::RENDER_TYPE_HUD_PARTICLES, LLPipeline::END_RENDER_TYPES); @@ -158,7 +157,6 @@ static bool handleRenderPerfTestChanged(const LLSD& newvalue) LLPipeline::RENDER_TYPE_WATER, LLPipeline::RENDER_TYPE_PASS_GRASS, LLPipeline::RENDER_TYPE_HUD, - LLPipeline::RENDER_TYPE_PARTICLES, LLPipeline::RENDER_TYPE_CLOUDS, LLPipeline::RENDER_TYPE_HUD_PARTICLES, LLPipeline::END_RENDER_TYPES); @@ -168,6 +166,11 @@ static bool handleRenderPerfTestChanged(const LLSD& newvalue) return true; } +bool handleRenderAvatarComplexityLimitChanged(const LLSD& newvalue) +{ + return true; +} + bool handleRenderTransparentWaterChanged(const LLSD& newvalue) { LLWorld::getInstance()->updateWaterObjects(); @@ -611,6 +614,7 @@ void settings_setup_listeners() gSavedSettings.getControl("WindLightUseAtmosShaders")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); gSavedSettings.getControl("RenderGammaFull")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); gSavedSettings.getControl("RenderAvatarMaxVisible")->getSignal()->connect(boost::bind(&handleAvatarMaxVisibleChanged, _2)); + gSavedSettings.getControl("RenderAvatarComplexityLimit")->getSignal()->connect(boost::bind(&handleRenderAvatarComplexityLimitChanged, _2)); gSavedSettings.getControl("RenderVolumeLODFactor")->getSignal()->connect(boost::bind(&handleVolumeLODChanged, _2)); gSavedSettings.getControl("RenderAvatarLODFactor")->getSignal()->connect(boost::bind(&handleAvatarLODChanged, _2)); gSavedSettings.getControl("RenderAvatarPhysicsLODFactor")->getSignal()->connect(boost::bind(&handleAvatarPhysicsLODChanged, _2)); diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index f8aaded310..ce88c8759f 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -58,6 +58,7 @@ #include "llviewerregion.h" #include "llviewerstats.h" #include "llviewerstatsrecorder.h" +#include "llvovolume.h" #include "llvoavatarself.h" #include "lltoolmgr.h" #include "lltoolpie.h" @@ -993,6 +994,9 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world) mNumSizeCulled = 0; mNumVisCulled = 0; + // update max computed render cost + LLVOVolume::updateRenderComplexity(); + // compute all sorts of time-based stats // don't factor frames that were paused into the stats if (! mWasPaused) diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index b5be3cd552..c77c4f167b 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -2803,7 +2803,10 @@ void LLVOAvatar::idleUpdateLoadingEffect() LLPartData::LL_PART_EMISSIVE_MASK | // LLPartData::LL_PART_FOLLOW_SRC_MASK | LLPartData::LL_PART_TARGET_POS_MASK ); - setParticleSource(particle_parameters, getID()); + if (!isTooComplex()) // do not generate particles for overly-complex avatars + { + setParticleSource(particle_parameters, getID()); + } } } } @@ -6383,6 +6386,11 @@ BOOL LLVOAvatar::getIsCloud() { return TRUE; } + + if (isTooComplex()) + { + return TRUE; + } return FALSE; } @@ -6477,6 +6485,16 @@ BOOL LLVOAvatar::isFullyLoaded() const return mFullyLoaded; } +bool LLVOAvatar::isTooComplex() const +{ + if (gSavedSettings.getS32("RenderAvatarComplexityLimit") > 0 && mVisualComplexity >= gSavedSettings.getS32("RenderAvatarComplexityLimit")) + { + return true; + } + + return false; +} + //----------------------------------------------------------------------------- // findMotion() @@ -8310,7 +8328,7 @@ void LLVOAvatar::getImpostorValues(LLVector4a* extents, LLVector3& angle, F32& d void LLVOAvatar::idleUpdateRenderCost() { - static const U32 ARC_BODY_PART_COST = 20; + static const U32 ARC_BODY_PART_COST = 200; static const U32 ARC_LIMIT = 2048; static std::set<LLUUID> all_textures; @@ -8321,7 +8339,7 @@ void LLVOAvatar::idleUpdateRenderCost() } U32 cost = 0; - std::set<LLUUID> textures; + LLVOVolume::texture_cost_t textures; for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++) { @@ -8348,6 +8366,7 @@ void LLVOAvatar::idleUpdateRenderCost() const LLViewerObject* attached_object = (*attachment_iter); if (attached_object && !attached_object->isHUDAttachment()) { + textures.clear(); const LLDrawable* drawable = attached_object->mDrawable; if (drawable) { @@ -8355,6 +8374,25 @@ void LLVOAvatar::idleUpdateRenderCost() if (volume) { cost += volume->getRenderCost(textures); + + const_child_list_t children = volume->getChildren(); + for (const_child_list_t::const_iterator child_iter = children.begin(); + child_iter != children.end(); + ++child_iter) + { + LLViewerObject* child_obj = *child_iter; + LLVOVolume *child = dynamic_cast<LLVOVolume*>( child_obj ); + if (child) + { + cost += volume->getRenderCost(textures); + } + } + + for (LLVOVolume::texture_cost_t::iterator iter = textures.begin(); iter != textures.end(); ++iter) + { + // add the cost of each individual texture in the linkset + cost += iter->second; + } } } } @@ -8362,15 +8400,17 @@ void LLVOAvatar::idleUpdateRenderCost() } + + // Diagnostic output to identify all avatar-related textures. // Does not affect rendering cost calculation. // Could be wrapped in a debug option if output becomes problematic. if (isSelf()) { // print any attachment textures we didn't already know about. - for (std::set<LLUUID>::iterator it = textures.begin(); it != textures.end(); ++it) + for (LLVOVolume::texture_cost_t::iterator it = textures.begin(); it != textures.end(); ++it) { - LLUUID image_id = *it; + LLUUID image_id = it->first; if( image_id.isNull() || image_id == IMG_DEFAULT || image_id == IMG_DEFAULT_AVATAR) continue; if (all_textures.find(image_id) == all_textures.end()) @@ -8402,9 +8442,8 @@ void LLVOAvatar::idleUpdateRenderCost() } } - cost += textures.size() * LLVOVolume::ARC_TEXTURE_COST; - setDebugText(llformat("%d", cost)); + mVisualComplexity = cost; F32 green = 1.f-llclamp(((F32) cost-(F32)ARC_LIMIT)/(F32)ARC_LIMIT, 0.f, 1.f); F32 red = llmin((F32) cost/(F32)ARC_LIMIT, 1.f); mText->setColor(LLColor4(red,green,0,1)); diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 03c0498a2a..6f14b42513 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -1,1098 +1,1100 @@ -/** - * @file llvoavatar.h - * @brief Declaration of LLVOAvatar class which is a derivation of - * LLViewerObject - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLVOAVATAR_H -#define LL_LLVOAVATAR_H - -#include <map> -#include <deque> -#include <string> -#include <vector> - -#include <boost/signals2.hpp> - -#include "imageids.h" // IMG_INVISIBLE -#include "llchat.h" -#include "lldrawpoolalpha.h" -#include "llviewerobject.h" -#include "llcharacter.h" -#include "llviewerjointmesh.h" -#include "llviewerjointattachment.h" -#include "llrendertarget.h" -#include "llvoavatardefines.h" -#include "lltexglobalcolor.h" -#include "lldriverparam.h" -#include "material_codes.h" // LL_MCODE_END - -extern const LLUUID ANIM_AGENT_BODY_NOISE; -extern const LLUUID ANIM_AGENT_BREATHE_ROT; -extern const LLUUID ANIM_AGENT_PHYSICS_MOTION; -extern const LLUUID ANIM_AGENT_EDITING; -extern const LLUUID ANIM_AGENT_EYE; -extern const LLUUID ANIM_AGENT_FLY_ADJUST; -extern const LLUUID ANIM_AGENT_HAND_MOTION; -extern const LLUUID ANIM_AGENT_HEAD_ROT; -extern const LLUUID ANIM_AGENT_PELVIS_FIX; -extern const LLUUID ANIM_AGENT_TARGET; -extern const LLUUID ANIM_AGENT_WALK_ADJUST; - -class LLTexLayerSet; -class LLVoiceVisualizer; -class LLHUDNameTag; -class LLHUDEffectSpiral; -class LLTexGlobalColor; -class LLVOAvatarBoneInfo; -class LLVOAvatarSkeletonInfo; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// LLVOAvatar -// -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLVOAvatar : - public LLViewerObject, - public LLCharacter, - public boost::signals2::trackable -{ -public: - friend class LLVOAvatarSelf; -protected: - struct LLVOAvatarXmlInfo; - struct LLMaskedMorph; - -/******************************************************************************** - ** ** - ** INITIALIZATION - **/ - -public: - LLVOAvatar(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp); - virtual void markDead(); - static void initClass(); // Initialize data that's only init'd once per class. - static void cleanupClass(); // Cleanup data that's only init'd once per class. - virtual void initInstance(); // Called after construction to initialize the class. -protected: - virtual ~LLVOAvatar(); - BOOL loadSkeletonNode(); - BOOL loadMeshNodes(); - virtual BOOL loadLayersets(); - -/** Initialization - ** ** - *******************************************************************************/ - -/******************************************************************************** - ** ** - ** INHERITED - **/ - - //-------------------------------------------------------------------- - // LLViewerObject interface and related - //-------------------------------------------------------------------- -public: - virtual void updateGL(); - virtual LLVOAvatar* asAvatar(); - virtual U32 processUpdateMessage(LLMessageSystem *mesgsys, - void **user_data, - U32 block_num, - const EObjectUpdateType update_type, - LLDataPacker *dp); - virtual BOOL idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time); - virtual BOOL updateLOD(); - BOOL updateJointLODs(); - void updateLODRiggedAttachments( void ); - virtual BOOL isActive() const; // Whether this object needs to do an idleUpdate. - virtual void updateTextures(); - virtual S32 setTETexture(const U8 te, const LLUUID& uuid); // If setting a baked texture, need to request it from a non-local sim. - virtual void onShift(const LLVector4a& shift_vector); - virtual U32 getPartitionType() const; - virtual const LLVector3 getRenderPosition() const; - virtual void updateDrawable(BOOL force_damped); - virtual LLDrawable* createDrawable(LLPipeline *pipeline); - virtual BOOL updateGeometry(LLDrawable *drawable); - virtual void setPixelAreaAndAngle(LLAgent &agent); - virtual void updateRegion(LLViewerRegion *regionp); - virtual void updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax); - virtual void getSpatialExtents(LLVector4a& newMin, LLVector4a& newMax); - virtual BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end, - S32 face = -1, // which face to check, -1 = ALL_SIDES - BOOL pick_transparent = FALSE, - S32* face_hit = NULL, // which face was hit - LLVector3* intersection = NULL, // return the intersection point - LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point - LLVector3* normal = NULL, // return the surface normal at the intersection point - LLVector3* bi_normal = NULL); // return the surface bi-normal at the intersection point - LLViewerObject* lineSegmentIntersectRiggedAttachments(const LLVector3& start, const LLVector3& end, - S32 face = -1, // which face to check, -1 = ALL_SIDES - BOOL pick_transparent = FALSE, - S32* face_hit = NULL, // which face was hit - LLVector3* intersection = NULL, // return the intersection point - LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point - LLVector3* normal = NULL, // return the surface normal at the intersection point - LLVector3* bi_normal = NULL); // return the surface bi-normal at the intersection point - - //-------------------------------------------------------------------- - // LLCharacter interface and related - //-------------------------------------------------------------------- -public: - virtual LLVector3 getCharacterPosition(); - virtual LLQuaternion getCharacterRotation(); - virtual LLVector3 getCharacterVelocity(); - virtual LLVector3 getCharacterAngularVelocity(); - virtual LLJoint* getCharacterJoint(U32 num); - virtual BOOL allocateCharacterJoints(U32 num); - - virtual LLUUID remapMotionID(const LLUUID& id); - virtual BOOL startMotion(const LLUUID& id, F32 time_offset = 0.f); - virtual BOOL stopMotion(const LLUUID& id, BOOL stop_immediate = FALSE); - virtual void stopMotionFromSource(const LLUUID& source_id); - virtual void requestStopMotion(LLMotion* motion); - LLMotion* findMotion(const LLUUID& id) const; - void startDefaultMotions(); - void dumpAnimationState(); - - virtual LLJoint* getJoint(const std::string &name); - virtual LLJoint* getRootJoint() { return &mRoot; } - - void resetJointPositions( void ); - void resetJointPositionsToDefault( void ); - void resetSpecificJointPosition( const std::string& name ); - - virtual const char* getAnimationPrefix() { return "avatar"; } - virtual const LLUUID& getID(); - virtual LLVector3 getVolumePos(S32 joint_index, LLVector3& volume_offset); - virtual LLJoint* findCollisionVolume(U32 volume_id); - virtual S32 getCollisionVolumeID(std::string &name); - virtual void addDebugText(const std::string& text); - virtual F32 getTimeDilation(); - virtual void getGround(const LLVector3 &inPos, LLVector3 &outPos, LLVector3 &outNorm); - virtual F32 getPixelArea() const; - virtual LLPolyMesh* getHeadMesh(); - virtual LLPolyMesh* getUpperBodyMesh(); - virtual LLVector3d getPosGlobalFromAgent(const LLVector3 &position); - virtual LLVector3 getPosAgentFromGlobal(const LLVector3d &position); - virtual void updateVisualParams(); - - -/** Inherited - ** ** - *******************************************************************************/ - -/******************************************************************************** - ** ** - ** STATE - **/ - -public: - virtual bool isSelf() const { return false; } // True if this avatar is for this viewer's agent - bool isBuilt() const { return mIsBuilt; } - -private: //aligned members - LLVector4a mImpostorExtents[2]; - -private: - BOOL mSupportsAlphaLayers; // For backwards compatibility, TRUE for 1.23+ clients - - //-------------------------------------------------------------------- - // Updates - //-------------------------------------------------------------------- -public: - virtual BOOL updateCharacter(LLAgent &agent); - void idleUpdateVoiceVisualizer(bool voice_enabled); - void idleUpdateMisc(bool detailed_update); - virtual void idleUpdateAppearanceAnimation(); - void idleUpdateLipSync(bool voice_enabled); - void idleUpdateLoadingEffect(); - void idleUpdateWindEffect(); - void idleUpdateNameTag(const LLVector3& root_pos_last); - void idleUpdateNameTagText(BOOL new_name); - LLVector3 idleUpdateNameTagPosition(const LLVector3& root_pos_last); - void idleUpdateNameTagAlpha(BOOL new_name, F32 alpha); - LLColor4 getNameTagColor(bool is_friend); - void clearNameTag(); - static void invalidateNameTag(const LLUUID& agent_id); - // force all name tags to rebuild, useful when display names turned on/off - static void invalidateNameTags(); - void addNameTagLine(const std::string& line, const LLColor4& color, S32 style, const LLFontGL* font); - void idleUpdateRenderCost(); - void idleUpdateBelowWater(); - - //-------------------------------------------------------------------- - // Static preferences (controlled by user settings/menus) - //-------------------------------------------------------------------- -public: - static S32 sRenderName; - static BOOL sRenderGroupTitles; - static U32 sMaxVisible; //(affected by control "RenderAvatarMaxVisible") - static F32 sRenderDistance; //distance at which avatars will render. - static BOOL sShowAnimationDebug; // show animation debug info - static BOOL sUseImpostors; //use impostors for far away avatars - static BOOL sShowFootPlane; // show foot collision plane reported by server - static BOOL sShowCollisionVolumes; // show skeletal collision volumes - static BOOL sVisibleInFirstPerson; - static S32 sNumLODChangesThisFrame; - static S32 sNumVisibleChatBubbles; - static BOOL sDebugInvisible; - static BOOL sShowAttachmentPoints; - static F32 sLODFactor; // user-settable LOD factor - static F32 sPhysicsLODFactor; // user-settable physics LOD factor - static BOOL sJointDebug; // output total number of joints being touched for each avatar - static BOOL sDebugAvatarRotation; - - //-------------------------------------------------------------------- - // Region state - //-------------------------------------------------------------------- -public: - LLHost getObjectHost() const; - - //-------------------------------------------------------------------- - // Loading state - //-------------------------------------------------------------------- -public: - BOOL isFullyLoaded() const; - bool visualParamWeightsAreDefault(); -protected: - virtual BOOL getIsCloud(); - BOOL updateIsFullyLoaded(); - BOOL processFullyLoadedChange(bool loading); - void updateRuthTimer(bool loading); - F32 calcMorphAmount(); -private: - BOOL mFullyLoaded; - BOOL mPreviousFullyLoaded; - BOOL mFullyLoadedInitialized; - S32 mFullyLoadedFrameCounter; - LLFrameTimer mFullyLoadedTimer; - LLFrameTimer mRuthTimer; -protected: - LLFrameTimer mInvisibleTimer; - -/** State - ** ** - *******************************************************************************/ - -/******************************************************************************** - ** ** - ** SKELETON - **/ - -public: - void updateHeadOffset(); - F32 getPelvisToFoot() const { return mPelvisToFoot; } - void setPelvisOffset( bool hasOffset, const LLVector3& translation, F32 offset ) ; - bool hasPelvisOffset( void ) { return mHasPelvisOffset; } - void postPelvisSetRecalc( void ); - void setPelvisOffset( F32 pelvixFixupAmount ); - - bool mHasPelvisOffset; - LLVector3 mPelvisOffset; - F32 mLastPelvisToFoot; - F32 mPelvisFixup; - F32 mLastPelvisFixup; - - LLVector3 mHeadOffset; // current head position - LLViewerJoint mRoot; -protected: - static BOOL parseSkeletonFile(const std::string& filename); - void buildCharacter(); - virtual BOOL loadAvatar(); - - BOOL setupBone(const LLVOAvatarBoneInfo* info, LLViewerJoint* parent, S32 ¤t_volume_num, S32 ¤t_joint_num); - BOOL buildSkeleton(const LLVOAvatarSkeletonInfo *info); -private: - BOOL mIsBuilt; // state of deferred character building - S32 mNumJoints; - LLViewerJoint* mSkeleton; - - //-------------------------------------------------------------------- - // Pelvis height adjustment members. - //-------------------------------------------------------------------- -public: - LLVector3 mBodySize; - S32 mLastSkeletonSerialNum; -private: - F32 mPelvisToFoot; - - //-------------------------------------------------------------------- - // Cached pointers to well known joints - //-------------------------------------------------------------------- -public: - LLViewerJoint* mPelvisp; - LLViewerJoint* mTorsop; - LLViewerJoint* mChestp; - LLViewerJoint* mNeckp; - LLViewerJoint* mHeadp; - LLViewerJoint* mSkullp; - LLViewerJoint* mEyeLeftp; - LLViewerJoint* mEyeRightp; - LLViewerJoint* mHipLeftp; - LLViewerJoint* mHipRightp; - LLViewerJoint* mKneeLeftp; - LLViewerJoint* mKneeRightp; - LLViewerJoint* mAnkleLeftp; - LLViewerJoint* mAnkleRightp; - LLViewerJoint* mFootLeftp; - LLViewerJoint* mFootRightp; - LLViewerJoint* mWristLeftp; - LLViewerJoint* mWristRightp; - - //-------------------------------------------------------------------- - // XML parse tree - //-------------------------------------------------------------------- -private: - static LLXmlTree sXMLTree; // avatar config file - static LLXmlTree sSkeletonXMLTree; // avatar skeleton file - -/** Skeleton - ** ** - *******************************************************************************/ - -/******************************************************************************** - ** ** - ** RENDERING - **/ - -public: - U32 renderImpostor(LLColor4U color = LLColor4U(255,255,255,255), S32 diffuse_channel = 0); - U32 renderRigid(); - U32 renderSkinned(EAvatarRenderPass pass); - F32 getLastSkinTime() { return mLastSkinTime; } - U32 renderSkinnedAttachments(); - U32 renderTransparent(BOOL first_pass); - void renderCollisionVolumes(); - static void deleteCachedImages(bool clearAll=true); - static void destroyGL(); - static void restoreGL(); - BOOL mIsDummy; // for special views - S32 mSpecialRenderMode; // special lighting -private: - bool shouldAlphaMask(); - - BOOL mNeedsSkin; // avatar has been animated and verts have not been updated - F32 mLastSkinTime; //value of gFrameTimeSeconds at last skin update - - S32 mUpdatePeriod; - S32 mNumInitFaces; //number of faces generated when creating the avatar drawable, does not inculde splitted faces due to long vertex buffer. - - //-------------------------------------------------------------------- - // Morph masks - //-------------------------------------------------------------------- -public: - BOOL morphMaskNeedsUpdate(LLVOAvatarDefines::EBakedTextureIndex index = LLVOAvatarDefines::BAKED_NUM_INDICES); - void addMaskedMorph(LLVOAvatarDefines::EBakedTextureIndex index, LLPolyMorphTarget* morph_target, BOOL invert, std::string layer); - void applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components, LLVOAvatarDefines::EBakedTextureIndex index = LLVOAvatarDefines::BAKED_NUM_INDICES); - - //-------------------------------------------------------------------- - // Visibility - //-------------------------------------------------------------------- -protected: - void updateVisibility(); -private: - U32 mVisibilityRank; - BOOL mVisible; - - //-------------------------------------------------------------------- - // Shadowing - //-------------------------------------------------------------------- -public: - void updateShadowFaces(); - LLDrawable* mShadow; -private: - LLFace* mShadow0Facep; - LLFace* mShadow1Facep; - LLPointer<LLViewerTexture> mShadowImagep; - - //-------------------------------------------------------------------- - // Impostors - //-------------------------------------------------------------------- -public: - BOOL isImpostor() const; - BOOL needsImpostorUpdate() const; - const LLVector3& getImpostorOffset() const; - const LLVector2& getImpostorDim() const; - void getImpostorValues(LLVector4a* extents, LLVector3& angle, F32& distance) const; - void cacheImpostorValues(); - void setImpostorDim(const LLVector2& dim); - static void resetImpostors(); - static void updateImpostors(); - LLRenderTarget mImpostor; - BOOL mNeedsImpostorUpdate; -private: - LLVector3 mImpostorOffset; - LLVector2 mImpostorDim; - BOOL mNeedsAnimUpdate; - LLVector3 mImpostorAngle; - F32 mImpostorDistance; - F32 mImpostorPixelArea; - LLVector3 mLastAnimExtents[2]; - - //-------------------------------------------------------------------- - // Wind rippling in clothes - //-------------------------------------------------------------------- -public: - LLVector4 mWindVec; - F32 mRipplePhase; - BOOL mBelowWater; -private: - F32 mWindFreq; - LLFrameTimer mRippleTimer; - F32 mRippleTimeLast; - LLVector3 mRippleAccel; - LLVector3 mLastVel; - - //-------------------------------------------------------------------- - // Culling - //-------------------------------------------------------------------- -public: - static void cullAvatarsByPixelArea(); - BOOL isCulled() const { return mCulled; } -private: - BOOL mCulled; - - //-------------------------------------------------------------------- - // Freeze counter - //-------------------------------------------------------------------- -public: - static void updateFreezeCounter(S32 counter = 0); -private: - static S32 sFreezeCounter; - - //-------------------------------------------------------------------- - // Constants - //-------------------------------------------------------------------- -public: - virtual LLViewerTexture::EBoostLevel getAvatarBoostLevel() const { return LLViewerTexture::BOOST_AVATAR; } - virtual LLViewerTexture::EBoostLevel getAvatarBakedBoostLevel() const { return LLViewerTexture::BOOST_AVATAR_BAKED; } - virtual S32 getTexImageSize() const; - virtual S32 getTexImageArea() const { return getTexImageSize()*getTexImageSize(); } - -/** Rendering - ** ** - *******************************************************************************/ - -/******************************************************************************** - ** ** - ** TEXTURES - **/ - - //-------------------------------------------------------------------- - // Loading status - //-------------------------------------------------------------------- -public: - virtual BOOL isTextureDefined(LLVOAvatarDefines::ETextureIndex type, U32 index = 0) const; - virtual BOOL isTextureVisible(LLVOAvatarDefines::ETextureIndex type, U32 index = 0) const; - virtual BOOL isTextureVisible(LLVOAvatarDefines::ETextureIndex type, LLWearable *wearable) const; - -protected: - BOOL isFullyBaked(); - static BOOL areAllNearbyInstancesBaked(S32& grey_avatars); - - //-------------------------------------------------------------------- - // Baked textures - //-------------------------------------------------------------------- -public: - void releaseComponentTextures(); // ! BACKWARDS COMPATIBILITY ! -protected: - static void onBakedTextureMasksLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata); - static void onInitialBakedTextureLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata); - static void onBakedTextureLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata); - virtual void removeMissingBakedTextures(); - void useBakedTexture(const LLUUID& id); - - typedef std::deque<LLMaskedMorph *> morph_list_t; - struct BakedTextureData - { - LLUUID mLastTextureIndex; - LLTexLayerSet* mTexLayerSet; // Only exists for self - bool mIsLoaded; - bool mIsUsed; - LLVOAvatarDefines::ETextureIndex mTextureIndex; - U32 mMaskTexName; - // Stores pointers to the joint meshes that this baked texture deals with - std::vector< LLViewerJointMesh * > mMeshes; // std::vector<LLViewerJointMesh> mJoints[i]->mMeshParts - morph_list_t mMaskedMorphs; - }; - typedef std::vector<BakedTextureData> bakedtexturedata_vec_t; - bakedtexturedata_vec_t mBakedTextureDatas; - LLLoadedCallbackEntry::source_callback_list_t mCallbackTextureList ; - BOOL mLoadedCallbacksPaused; - //-------------------------------------------------------------------- - // Local Textures - //-------------------------------------------------------------------- -protected: - virtual void setLocalTexture(LLVOAvatarDefines::ETextureIndex type, LLViewerTexture* tex, BOOL baked_version_exits, U32 index = 0); - virtual void addLocalTextureStats(LLVOAvatarDefines::ETextureIndex type, LLViewerFetchedTexture* imagep, F32 texel_area_ratio, BOOL rendered, BOOL covered_by_baked, U32 index = 0); - // MULTI-WEARABLE: make self-only? - virtual void setBakedReady(LLVOAvatarDefines::ETextureIndex type, BOOL baked_version_exists, U32 index = 0); - - //-------------------------------------------------------------------- - // Texture accessors - //-------------------------------------------------------------------- -private: - virtual void setImage(const U8 te, LLViewerTexture *imagep, const U32 index); - virtual LLViewerTexture* getImage(const U8 te, const U32 index) const; - - virtual const LLTextureEntry* getTexEntry(const U8 te_num) const; - virtual void setTexEntry(const U8 index, const LLTextureEntry &te); - - void checkTextureLoading() ; - //-------------------------------------------------------------------- - // Layers - //-------------------------------------------------------------------- -protected: - void deleteLayerSetCaches(bool clearAll = true); - void addBakedTextureStats(LLViewerFetchedTexture* imagep, F32 pixel_area, F32 texel_area_ratio, S32 boost_level); - - //-------------------------------------------------------------------- - // Composites - //-------------------------------------------------------------------- -public: - virtual void invalidateComposite(LLTexLayerSet* layerset, BOOL upload_result); - virtual void invalidateAll(); - virtual void setCompositeUpdatesEnabled(bool b) {} - virtual void setCompositeUpdatesEnabled(U32 index, bool b) {} - virtual bool isCompositeUpdateEnabled(U32 index) { return false; } - - //-------------------------------------------------------------------- - // Static texture/mesh/baked dictionary - //-------------------------------------------------------------------- -public: - static BOOL isIndexLocalTexture(LLVOAvatarDefines::ETextureIndex i); - static BOOL isIndexBakedTexture(LLVOAvatarDefines::ETextureIndex i); -private: - static const LLVOAvatarDefines::LLVOAvatarDictionary *getDictionary() { return sAvatarDictionary; } - static LLVOAvatarDefines::LLVOAvatarDictionary* sAvatarDictionary; - static LLVOAvatarSkeletonInfo* sAvatarSkeletonInfo; - static LLVOAvatarXmlInfo* sAvatarXmlInfo; - - //-------------------------------------------------------------------- - // Messaging - //-------------------------------------------------------------------- -public: - void onFirstTEMessageReceived(); -private: - BOOL mFirstTEMessageReceived; - BOOL mFirstAppearanceMessageReceived; - -/** Textures - ** ** - *******************************************************************************/ - -/******************************************************************************** - ** ** - ** MESHES - **/ - -public: - void updateMeshTextures(); - void updateSexDependentLayerSets(BOOL upload_bake); - void dirtyMesh(); // Dirty the avatar mesh - void updateMeshData(); -protected: - void releaseMeshData(); - virtual void restoreMeshData(); -private: - void dirtyMesh(S32 priority); // Dirty the avatar mesh, with priority - S32 mDirtyMesh; // 0 -- not dirty, 1 -- morphed, 2 -- LOD - BOOL mMeshTexturesDirty; - - typedef std::multimap<std::string, LLPolyMesh*> polymesh_map_t; - polymesh_map_t mMeshes; - std::vector<LLViewerJoint *> mMeshLOD; - - //-------------------------------------------------------------------- - // Destroy invisible mesh - //-------------------------------------------------------------------- -protected: - BOOL mMeshValid; - LLFrameTimer mMeshInvisibleTime; - -/** Meshes - ** ** - *******************************************************************************/ - -/******************************************************************************** - ** ** - ** APPEARANCE - **/ - -public: - void processAvatarAppearance(LLMessageSystem* mesgsys); - void hideSkirt(); - void startAppearanceAnimation(); - - //-------------------------------------------------------------------- - // Appearance morphing - //-------------------------------------------------------------------- -public: - BOOL getIsAppearanceAnimating() const { return mAppearanceAnimating; } -private: - BOOL mAppearanceAnimating; - LLFrameTimer mAppearanceMorphTimer; - F32 mLastAppearanceBlendTime; - - //-------------------------------------------------------------------- - // Clothing colors (convenience functions to access visual parameters) - //-------------------------------------------------------------------- -public: - void setClothesColor(LLVOAvatarDefines::ETextureIndex te, const LLColor4& new_color, BOOL upload_bake); - LLColor4 getClothesColor(LLVOAvatarDefines::ETextureIndex te); - static BOOL teToColorParams(LLVOAvatarDefines::ETextureIndex te, U32 *param_name); - - //-------------------------------------------------------------------- - // Global colors - //-------------------------------------------------------------------- -public: - LLColor4 getGlobalColor(const std::string& color_name ) const; - void onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL upload_bake); -private: - LLTexGlobalColor* mTexSkinColor; - LLTexGlobalColor* mTexHairColor; - LLTexGlobalColor* mTexEyeColor; - - //-------------------------------------------------------------------- - // Visibility - //-------------------------------------------------------------------- -public: - BOOL isVisible() const; - void setVisibilityRank(U32 rank); - U32 getVisibilityRank() const { return mVisibilityRank; } // unused - static S32 sNumVisibleAvatars; // Number of instances of this class - static LLColor4 getDummyColor(); -/** Appearance - ** ** - *******************************************************************************/ - -/******************************************************************************** - ** ** - ** WEARABLES - **/ - -public: - virtual BOOL isWearingWearableType(LLWearableType::EType type ) const; - - //-------------------------------------------------------------------- - // Attachments - //-------------------------------------------------------------------- -public: - void clampAttachmentPositions(); - virtual const LLViewerJointAttachment* attachObject(LLViewerObject *viewer_object); - virtual BOOL detachObject(LLViewerObject *viewer_object); - void cleanupAttachedMesh( LLViewerObject* pVO ); - static LLVOAvatar* findAvatarFromAttachment(LLViewerObject* obj); -protected: - LLViewerJointAttachment* getTargetAttachmentPoint(LLViewerObject* viewer_object); - void lazyAttach(); - void rebuildRiggedAttachments( void ); - - //-------------------------------------------------------------------- - // Map of attachment points, by ID - //-------------------------------------------------------------------- -public: - S32 getAttachmentCount(); // Warning: order(N) not order(1) // currently used only by -self - typedef std::map<S32, LLViewerJointAttachment*> attachment_map_t; - attachment_map_t mAttachmentPoints; - std::vector<LLPointer<LLViewerObject> > mPendingAttachment; - - //-------------------------------------------------------------------- - // HUD functions - //-------------------------------------------------------------------- -public: - BOOL hasHUDAttachment() const; - LLBBox getHUDBBox() const; - void rebuildHUD(); - void resetHUDAttachments(); - BOOL canAttachMoreObjects() const; - BOOL canAttachMoreObjects(U32 n) const; -protected: - U32 getNumAttachments() const; // O(N), not O(1) - -/** Wearables - ** ** - *******************************************************************************/ - -/******************************************************************************** - ** ** - ** ACTIONS - **/ - - //-------------------------------------------------------------------- - // Animations - //-------------------------------------------------------------------- -public: - BOOL isAnyAnimationSignaled(const LLUUID *anim_array, const S32 num_anims) const; - void processAnimationStateChanges(); -protected: - BOOL processSingleAnimationStateChange(const LLUUID &anim_id, BOOL start); - void resetAnimations(); -private: - LLTimer mAnimTimer; - F32 mTimeLast; - - //-------------------------------------------------------------------- - // Animation state data - //-------------------------------------------------------------------- -public: - typedef std::map<LLUUID, S32>::iterator AnimIterator; - std::map<LLUUID, S32> mSignaledAnimations; // requested state of Animation name/value - std::map<LLUUID, S32> mPlayingAnimations; // current state of Animation name/value - - typedef std::multimap<LLUUID, LLUUID> AnimationSourceMap; - typedef AnimationSourceMap::iterator AnimSourceIterator; - AnimationSourceMap mAnimationSources; // object ids that triggered anim ids - - //-------------------------------------------------------------------- - // Chat - //-------------------------------------------------------------------- -public: - void addChat(const LLChat& chat); - void clearChat(); - void startTyping() { mTyping = TRUE; mTypingTimer.reset(); } - void stopTyping() { mTyping = FALSE; } -private: - BOOL mVisibleChat; - - //-------------------------------------------------------------------- - // Lip synch morphs - //-------------------------------------------------------------------- -private: - bool mLipSyncActive; // we're morphing for lip sync - LLVisualParam* mOohMorph; // cached pointers morphs for lip sync - LLVisualParam* mAahMorph; // cached pointers morphs for lip sync - - //-------------------------------------------------------------------- - // Flight - //-------------------------------------------------------------------- -public: - BOOL mInAir; - LLFrameTimer mTimeInAir; - -/** Actions - ** ** - *******************************************************************************/ - -/******************************************************************************** - ** ** - ** PHYSICS - **/ - -private: - F32 mSpeedAccum; // measures speed (for diagnostics mostly). - BOOL mTurning; // controls hysteresis on avatar rotation - F32 mSpeed; // misc. animation repeated state - - //-------------------------------------------------------------------- - // Collision volumes - //-------------------------------------------------------------------- -public: - S32 mNumCollisionVolumes; - LLViewerJointCollisionVolume* mCollisionVolumes; -protected: - BOOL allocateCollisionVolumes(U32 num); - - //-------------------------------------------------------------------- - // Dimensions - //-------------------------------------------------------------------- -public: - void resolveHeightGlobal(const LLVector3d &inPos, LLVector3d &outPos, LLVector3 &outNorm); - bool distanceToGround( const LLVector3d &startPoint, LLVector3d &collisionPoint, F32 distToIntersectionAlongRay ); - void resolveHeightAgent(const LLVector3 &inPos, LLVector3 &outPos, LLVector3 &outNorm); - void resolveRayCollisionAgent(const LLVector3d start_pt, const LLVector3d end_pt, LLVector3d &out_pos, LLVector3 &out_norm); - void slamPosition(); // Slam position to transmitted position (for teleport); -protected: - void computeBodySize(); - - //-------------------------------------------------------------------- - // Material being stepped on - //-------------------------------------------------------------------- -private: - BOOL mStepOnLand; - U8 mStepMaterial; - LLVector3 mStepObjectVelocity; - -/** Physics - ** ** - *******************************************************************************/ - -/******************************************************************************** - ** ** - ** HIERARCHY - **/ - -public: - virtual BOOL setParent(LLViewerObject* parent); - virtual void addChild(LLViewerObject *childp); - virtual void removeChild(LLViewerObject *childp); - - //-------------------------------------------------------------------- - // Sitting - //-------------------------------------------------------------------- -public: - void sitDown(BOOL bSitting); - BOOL isSitting(){return mIsSitting;} - void sitOnObject(LLViewerObject *sit_object); - void getOffObject(); -private: - // set this property only with LLVOAvatar::sitDown method - BOOL mIsSitting; - -/** Hierarchy - ** ** - *******************************************************************************/ - -/******************************************************************************** - ** ** - ** NAME - **/ - -public: - std::string getFullname() const; // Returns "FirstName LastName" -protected: - static void getAnimLabels(LLDynamicArray<std::string>* labels); - static void getAnimNames(LLDynamicArray<std::string>* names); -private: - std::string mNameString; // UTF-8 title + name + status - std::string mTitle; - bool mNameAway; - bool mNameBusy; - bool mNameMute; - bool mNameAppearance; - bool mNameFriend; - bool mNameCloud; - F32 mNameAlpha; - BOOL mRenderGroupTitles; - - //-------------------------------------------------------------------- - // Display the name (then optionally fade it out) - //-------------------------------------------------------------------- -public: - LLFrameTimer mChatTimer; - LLPointer<LLHUDNameTag> mNameText; -private: - LLFrameTimer mTimeVisible; - std::deque<LLChat> mChats; - BOOL mTyping; - LLFrameTimer mTypingTimer; - -/** Name - ** ** - *******************************************************************************/ - -/******************************************************************************** - ** ** - ** SOUNDS - **/ - - //-------------------------------------------------------------------- - // Voice visualizer - //-------------------------------------------------------------------- -public: - // Responsible for detecting the user's voice signal (and when the - // user speaks, it puts a voice symbol over the avatar's head) and gesticulations - LLPointer<LLVoiceVisualizer> mVoiceVisualizer; - int mCurrentGesticulationLevel; - - //-------------------------------------------------------------------- - // Step sound - //-------------------------------------------------------------------- -protected: - const LLUUID& getStepSound() const; -private: - // Global table of sound ids per material, and the ground - const static LLUUID sStepSounds[LL_MCODE_END]; - const static LLUUID sStepSoundOnLand; - - //-------------------------------------------------------------------- - // Foot step state (for generating sounds) - //-------------------------------------------------------------------- -public: - void setFootPlane(const LLVector4 &plane) { mFootPlane = plane; } - LLVector4 mFootPlane; -private: - BOOL mWasOnGroundLeft; - BOOL mWasOnGroundRight; - -/** Sounds - ** ** - *******************************************************************************/ - -/******************************************************************************** - ** ** - ** DIAGNOSTICS - **/ - - //-------------------------------------------------------------------- - // General - //-------------------------------------------------------------------- -public: - static void dumpArchetypeXML(void*); - static void dumpBakedStatus(); - const std::string getBakedStatusForPrintout() const; - void dumpAvatarTEs(const std::string& context) const; - - static F32 sUnbakedTime; // Total seconds with >=1 unbaked avatars - static F32 sUnbakedUpdateTime; // Last time stats were updated (to prevent multiple updates per frame) - static F32 sGreyTime; // Total seconds with >=1 grey avatars - static F32 sGreyUpdateTime; // Last time stats were updated (to prevent multiple updates per frame) -protected: - S32 getUnbakedPixelAreaRank(); - BOOL mHasGrey; -private: - F32 mMinPixelArea; - F32 mMaxPixelArea; - F32 mAdjustedPixelArea; - std::string mDebugText; - - - //-------------------------------------------------------------------- - // Avatar Rez Metrics - //-------------------------------------------------------------------- -public: - F32 debugGetExistenceTimeElapsedF32() const { return mDebugExistenceTimer.getElapsedTimeF32(); } -protected: - LLFrameTimer mRuthDebugTimer; // For tracking how long it takes for av to rez - LLFrameTimer mDebugExistenceTimer; // Debugging for how long the avatar has been in memory. - -/** Diagnostics - ** ** - *******************************************************************************/ - -/******************************************************************************** - ** ** - ** SUPPORT CLASSES - **/ - -protected: // Shared with LLVOAvatarSelf - - struct LLVOAvatarXmlInfo - { - LLVOAvatarXmlInfo(); - ~LLVOAvatarXmlInfo(); - - BOOL parseXmlSkeletonNode(LLXmlTreeNode* root); - BOOL parseXmlMeshNodes(LLXmlTreeNode* root); - BOOL parseXmlColorNodes(LLXmlTreeNode* root); - BOOL parseXmlLayerNodes(LLXmlTreeNode* root); - BOOL parseXmlDriverNodes(LLXmlTreeNode* root); - BOOL parseXmlMorphNodes(LLXmlTreeNode* root); - - struct LLVOAvatarMeshInfo - { - typedef std::pair<LLPolyMorphTargetInfo*,BOOL> morph_info_pair_t; - typedef std::vector<morph_info_pair_t> morph_info_list_t; - - LLVOAvatarMeshInfo() : mLOD(0), mMinPixelArea(.1f) {} - ~LLVOAvatarMeshInfo() - { - morph_info_list_t::iterator iter; - for (iter = mPolyMorphTargetInfoList.begin(); iter != mPolyMorphTargetInfoList.end(); iter++) - { - delete iter->first; - } - mPolyMorphTargetInfoList.clear(); - } - - std::string mType; - S32 mLOD; - std::string mMeshFileName; - std::string mReferenceMeshName; - F32 mMinPixelArea; - morph_info_list_t mPolyMorphTargetInfoList; - }; - typedef std::vector<LLVOAvatarMeshInfo*> mesh_info_list_t; - mesh_info_list_t mMeshInfoList; - - typedef std::vector<LLPolySkeletalDistortionInfo*> skeletal_distortion_info_list_t; - skeletal_distortion_info_list_t mSkeletalDistortionInfoList; - - struct LLVOAvatarAttachmentInfo - { - LLVOAvatarAttachmentInfo() - : mGroup(-1), mAttachmentID(-1), mPieMenuSlice(-1), mVisibleFirstPerson(FALSE), - mIsHUDAttachment(FALSE), mHasPosition(FALSE), mHasRotation(FALSE) {} - std::string mName; - std::string mJointName; - LLVector3 mPosition; - LLVector3 mRotationEuler; - S32 mGroup; - S32 mAttachmentID; - S32 mPieMenuSlice; - BOOL mVisibleFirstPerson; - BOOL mIsHUDAttachment; - BOOL mHasPosition; - BOOL mHasRotation; - }; - typedef std::vector<LLVOAvatarAttachmentInfo*> attachment_info_list_t; - attachment_info_list_t mAttachmentInfoList; - - LLTexGlobalColorInfo *mTexSkinColorInfo; - LLTexGlobalColorInfo *mTexHairColorInfo; - LLTexGlobalColorInfo *mTexEyeColorInfo; - - typedef std::vector<LLTexLayerSetInfo*> layer_info_list_t; - layer_info_list_t mLayerInfoList; - - typedef std::vector<LLDriverParamInfo*> driver_info_list_t; - driver_info_list_t mDriverInfoList; - - struct LLVOAvatarMorphInfo - { - LLVOAvatarMorphInfo() - : mInvert(FALSE) {} - std::string mName; - std::string mRegion; - std::string mLayer; - BOOL mInvert; - }; - - typedef std::vector<LLVOAvatarMorphInfo*> morph_info_list_t; - morph_info_list_t mMorphMaskInfoList; - }; - - struct LLMaskedMorph - { - LLMaskedMorph(LLPolyMorphTarget *morph_target, BOOL invert, std::string layer) : - mMorphTarget(morph_target), - mInvert(invert), - mLayer(layer) - { - morph_target->addPendingMorphMask(); - } - - LLPolyMorphTarget *mMorphTarget; - BOOL mInvert; - std::string mLayer; - }; - -/** Support classes - ** ** - *******************************************************************************/ - -}; // LLVOAvatar -extern const F32 SELF_ADDITIONAL_PRI; -extern const S32 MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL; - -#endif // LL_VO_AVATAR_H +/**
+ * @file llvoavatar.h
+ * @brief Declaration of LLVOAvatar class which is a derivation of
+ * LLViewerObject
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLVOAVATAR_H
+#define LL_LLVOAVATAR_H
+
+#include <map>
+#include <deque>
+#include <string>
+#include <vector>
+
+#include <boost/signals2.hpp>
+
+#include "imageids.h" // IMG_INVISIBLE
+#include "llchat.h"
+#include "lldrawpoolalpha.h"
+#include "llviewerobject.h"
+#include "llcharacter.h"
+#include "llviewerjointmesh.h"
+#include "llviewerjointattachment.h"
+#include "llrendertarget.h"
+#include "llvoavatardefines.h"
+#include "lltexglobalcolor.h"
+#include "lldriverparam.h"
+#include "material_codes.h" // LL_MCODE_END
+
+extern const LLUUID ANIM_AGENT_BODY_NOISE;
+extern const LLUUID ANIM_AGENT_BREATHE_ROT;
+extern const LLUUID ANIM_AGENT_PHYSICS_MOTION;
+extern const LLUUID ANIM_AGENT_EDITING;
+extern const LLUUID ANIM_AGENT_EYE;
+extern const LLUUID ANIM_AGENT_FLY_ADJUST;
+extern const LLUUID ANIM_AGENT_HAND_MOTION;
+extern const LLUUID ANIM_AGENT_HEAD_ROT;
+extern const LLUUID ANIM_AGENT_PELVIS_FIX;
+extern const LLUUID ANIM_AGENT_TARGET;
+extern const LLUUID ANIM_AGENT_WALK_ADJUST;
+
+class LLTexLayerSet;
+class LLVoiceVisualizer;
+class LLHUDNameTag;
+class LLHUDEffectSpiral;
+class LLTexGlobalColor;
+class LLVOAvatarBoneInfo;
+class LLVOAvatarSkeletonInfo;
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// LLVOAvatar
+//
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class LLVOAvatar :
+ public LLViewerObject,
+ public LLCharacter,
+ public boost::signals2::trackable
+{
+public:
+ friend class LLVOAvatarSelf;
+protected:
+ struct LLVOAvatarXmlInfo;
+ struct LLMaskedMorph;
+
+/********************************************************************************
+ ** **
+ ** INITIALIZATION
+ **/
+
+public:
+ LLVOAvatar(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp);
+ virtual void markDead();
+ static void initClass(); // Initialize data that's only init'd once per class.
+ static void cleanupClass(); // Cleanup data that's only init'd once per class.
+ virtual void initInstance(); // Called after construction to initialize the class.
+protected:
+ virtual ~LLVOAvatar();
+ BOOL loadSkeletonNode();
+ BOOL loadMeshNodes();
+ virtual BOOL loadLayersets();
+
+/** Initialization
+ ** **
+ *******************************************************************************/
+
+/********************************************************************************
+ ** **
+ ** INHERITED
+ **/
+
+ //--------------------------------------------------------------------
+ // LLViewerObject interface and related
+ //--------------------------------------------------------------------
+public:
+ virtual void updateGL();
+ virtual LLVOAvatar* asAvatar();
+ virtual U32 processUpdateMessage(LLMessageSystem *mesgsys,
+ void **user_data,
+ U32 block_num,
+ const EObjectUpdateType update_type,
+ LLDataPacker *dp);
+ virtual BOOL idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time);
+ virtual BOOL updateLOD();
+ BOOL updateJointLODs();
+ void updateLODRiggedAttachments( void );
+ virtual BOOL isActive() const; // Whether this object needs to do an idleUpdate.
+ virtual void updateTextures();
+ virtual S32 setTETexture(const U8 te, const LLUUID& uuid); // If setting a baked texture, need to request it from a non-local sim.
+ virtual void onShift(const LLVector4a& shift_vector);
+ virtual U32 getPartitionType() const;
+ virtual const LLVector3 getRenderPosition() const;
+ virtual void updateDrawable(BOOL force_damped);
+ virtual LLDrawable* createDrawable(LLPipeline *pipeline);
+ virtual BOOL updateGeometry(LLDrawable *drawable);
+ virtual void setPixelAreaAndAngle(LLAgent &agent);
+ virtual void updateRegion(LLViewerRegion *regionp);
+ virtual void updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax);
+ virtual void getSpatialExtents(LLVector4a& newMin, LLVector4a& newMax);
+ virtual BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
+ S32 face = -1, // which face to check, -1 = ALL_SIDES
+ BOOL pick_transparent = FALSE,
+ S32* face_hit = NULL, // which face was hit
+ LLVector3* intersection = NULL, // return the intersection point
+ LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point
+ LLVector3* normal = NULL, // return the surface normal at the intersection point
+ LLVector3* bi_normal = NULL); // return the surface bi-normal at the intersection point
+ LLViewerObject* lineSegmentIntersectRiggedAttachments(const LLVector3& start, const LLVector3& end,
+ S32 face = -1, // which face to check, -1 = ALL_SIDES
+ BOOL pick_transparent = FALSE,
+ S32* face_hit = NULL, // which face was hit
+ LLVector3* intersection = NULL, // return the intersection point
+ LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point
+ LLVector3* normal = NULL, // return the surface normal at the intersection point
+ LLVector3* bi_normal = NULL); // return the surface bi-normal at the intersection point
+
+ //--------------------------------------------------------------------
+ // LLCharacter interface and related
+ //--------------------------------------------------------------------
+public:
+ virtual LLVector3 getCharacterPosition();
+ virtual LLQuaternion getCharacterRotation();
+ virtual LLVector3 getCharacterVelocity();
+ virtual LLVector3 getCharacterAngularVelocity();
+ virtual LLJoint* getCharacterJoint(U32 num);
+ virtual BOOL allocateCharacterJoints(U32 num);
+
+ virtual LLUUID remapMotionID(const LLUUID& id);
+ virtual BOOL startMotion(const LLUUID& id, F32 time_offset = 0.f);
+ virtual BOOL stopMotion(const LLUUID& id, BOOL stop_immediate = FALSE);
+ virtual void stopMotionFromSource(const LLUUID& source_id);
+ virtual void requestStopMotion(LLMotion* motion);
+ LLMotion* findMotion(const LLUUID& id) const;
+ void startDefaultMotions();
+ void dumpAnimationState();
+
+ virtual LLJoint* getJoint(const std::string &name);
+ virtual LLJoint* getRootJoint() { return &mRoot; }
+
+ void resetJointPositions( void );
+ void resetJointPositionsToDefault( void );
+ void resetSpecificJointPosition( const std::string& name );
+
+ virtual const char* getAnimationPrefix() { return "avatar"; }
+ virtual const LLUUID& getID();
+ virtual LLVector3 getVolumePos(S32 joint_index, LLVector3& volume_offset);
+ virtual LLJoint* findCollisionVolume(U32 volume_id);
+ virtual S32 getCollisionVolumeID(std::string &name);
+ virtual void addDebugText(const std::string& text);
+ virtual F32 getTimeDilation();
+ virtual void getGround(const LLVector3 &inPos, LLVector3 &outPos, LLVector3 &outNorm);
+ virtual F32 getPixelArea() const;
+ virtual LLPolyMesh* getHeadMesh();
+ virtual LLPolyMesh* getUpperBodyMesh();
+ virtual LLVector3d getPosGlobalFromAgent(const LLVector3 &position);
+ virtual LLVector3 getPosAgentFromGlobal(const LLVector3d &position);
+ virtual void updateVisualParams();
+
+
+/** Inherited
+ ** **
+ *******************************************************************************/
+
+/********************************************************************************
+ ** **
+ ** STATE
+ **/
+
+public:
+ virtual bool isSelf() const { return false; } // True if this avatar is for this viewer's agent
+ bool isBuilt() const { return mIsBuilt; }
+
+private: //aligned members
+ LLVector4a mImpostorExtents[2];
+
+private:
+ BOOL mSupportsAlphaLayers; // For backwards compatibility, TRUE for 1.23+ clients
+
+ //--------------------------------------------------------------------
+ // Updates
+ //--------------------------------------------------------------------
+public:
+ virtual BOOL updateCharacter(LLAgent &agent);
+ void idleUpdateVoiceVisualizer(bool voice_enabled);
+ void idleUpdateMisc(bool detailed_update);
+ virtual void idleUpdateAppearanceAnimation();
+ void idleUpdateLipSync(bool voice_enabled);
+ void idleUpdateLoadingEffect();
+ void idleUpdateWindEffect();
+ void idleUpdateNameTag(const LLVector3& root_pos_last);
+ void idleUpdateNameTagText(BOOL new_name);
+ LLVector3 idleUpdateNameTagPosition(const LLVector3& root_pos_last);
+ void idleUpdateNameTagAlpha(BOOL new_name, F32 alpha);
+ LLColor4 getNameTagColor(bool is_friend);
+ void clearNameTag();
+ static void invalidateNameTag(const LLUUID& agent_id);
+ // force all name tags to rebuild, useful when display names turned on/off
+ static void invalidateNameTags();
+ void addNameTagLine(const std::string& line, const LLColor4& color, S32 style, const LLFontGL* font);
+ void idleUpdateRenderCost();
+ void idleUpdateBelowWater();
+
+ //--------------------------------------------------------------------
+ // Static preferences (controlled by user settings/menus)
+ //--------------------------------------------------------------------
+public:
+ static S32 sRenderName;
+ static BOOL sRenderGroupTitles;
+ static U32 sMaxVisible; //(affected by control "RenderAvatarMaxVisible")
+ static F32 sRenderDistance; //distance at which avatars will render.
+ static BOOL sShowAnimationDebug; // show animation debug info
+ static BOOL sUseImpostors; //use impostors for far away avatars
+ static BOOL sShowFootPlane; // show foot collision plane reported by server
+ static BOOL sShowCollisionVolumes; // show skeletal collision volumes
+ static BOOL sVisibleInFirstPerson;
+ static S32 sNumLODChangesThisFrame;
+ static S32 sNumVisibleChatBubbles;
+ static BOOL sDebugInvisible;
+ static BOOL sShowAttachmentPoints;
+ static F32 sLODFactor; // user-settable LOD factor
+ static F32 sPhysicsLODFactor; // user-settable physics LOD factor
+ static BOOL sJointDebug; // output total number of joints being touched for each avatar
+ static BOOL sDebugAvatarRotation;
+
+ //--------------------------------------------------------------------
+ // Region state
+ //--------------------------------------------------------------------
+public:
+ LLHost getObjectHost() const;
+
+ //--------------------------------------------------------------------
+ // Loading state
+ //--------------------------------------------------------------------
+public:
+ BOOL isFullyLoaded() const;
+ bool isTooComplex() const;
+ bool visualParamWeightsAreDefault();
+protected:
+ virtual BOOL getIsCloud();
+ BOOL updateIsFullyLoaded();
+ BOOL processFullyLoadedChange(bool loading);
+ void updateRuthTimer(bool loading);
+ F32 calcMorphAmount();
+private:
+ BOOL mFullyLoaded;
+ BOOL mPreviousFullyLoaded;
+ BOOL mFullyLoadedInitialized;
+ S32 mFullyLoadedFrameCounter;
+ S32 mVisualComplexity;
+ LLFrameTimer mFullyLoadedTimer;
+ LLFrameTimer mRuthTimer;
+protected:
+ LLFrameTimer mInvisibleTimer;
+
+/** State
+ ** **
+ *******************************************************************************/
+
+/********************************************************************************
+ ** **
+ ** SKELETON
+ **/
+
+public:
+ void updateHeadOffset();
+ F32 getPelvisToFoot() const { return mPelvisToFoot; }
+ void setPelvisOffset( bool hasOffset, const LLVector3& translation, F32 offset ) ;
+ bool hasPelvisOffset( void ) { return mHasPelvisOffset; }
+ void postPelvisSetRecalc( void );
+ void setPelvisOffset( F32 pelvixFixupAmount );
+
+ bool mHasPelvisOffset;
+ LLVector3 mPelvisOffset;
+ F32 mLastPelvisToFoot;
+ F32 mPelvisFixup;
+ F32 mLastPelvisFixup;
+
+ LLVector3 mHeadOffset; // current head position
+ LLViewerJoint mRoot;
+protected:
+ static BOOL parseSkeletonFile(const std::string& filename);
+ void buildCharacter();
+ virtual BOOL loadAvatar();
+
+ BOOL setupBone(const LLVOAvatarBoneInfo* info, LLViewerJoint* parent, S32 ¤t_volume_num, S32 ¤t_joint_num);
+ BOOL buildSkeleton(const LLVOAvatarSkeletonInfo *info);
+private:
+ BOOL mIsBuilt; // state of deferred character building
+ S32 mNumJoints;
+ LLViewerJoint* mSkeleton;
+
+ //--------------------------------------------------------------------
+ // Pelvis height adjustment members.
+ //--------------------------------------------------------------------
+public:
+ LLVector3 mBodySize;
+ S32 mLastSkeletonSerialNum;
+private:
+ F32 mPelvisToFoot;
+
+ //--------------------------------------------------------------------
+ // Cached pointers to well known joints
+ //--------------------------------------------------------------------
+public:
+ LLViewerJoint* mPelvisp;
+ LLViewerJoint* mTorsop;
+ LLViewerJoint* mChestp;
+ LLViewerJoint* mNeckp;
+ LLViewerJoint* mHeadp;
+ LLViewerJoint* mSkullp;
+ LLViewerJoint* mEyeLeftp;
+ LLViewerJoint* mEyeRightp;
+ LLViewerJoint* mHipLeftp;
+ LLViewerJoint* mHipRightp;
+ LLViewerJoint* mKneeLeftp;
+ LLViewerJoint* mKneeRightp;
+ LLViewerJoint* mAnkleLeftp;
+ LLViewerJoint* mAnkleRightp;
+ LLViewerJoint* mFootLeftp;
+ LLViewerJoint* mFootRightp;
+ LLViewerJoint* mWristLeftp;
+ LLViewerJoint* mWristRightp;
+
+ //--------------------------------------------------------------------
+ // XML parse tree
+ //--------------------------------------------------------------------
+private:
+ static LLXmlTree sXMLTree; // avatar config file
+ static LLXmlTree sSkeletonXMLTree; // avatar skeleton file
+
+/** Skeleton
+ ** **
+ *******************************************************************************/
+
+/********************************************************************************
+ ** **
+ ** RENDERING
+ **/
+
+public:
+ U32 renderImpostor(LLColor4U color = LLColor4U(255,255,255,255), S32 diffuse_channel = 0);
+ U32 renderRigid();
+ U32 renderSkinned(EAvatarRenderPass pass);
+ F32 getLastSkinTime() { return mLastSkinTime; }
+ U32 renderSkinnedAttachments();
+ U32 renderTransparent(BOOL first_pass);
+ void renderCollisionVolumes();
+ static void deleteCachedImages(bool clearAll=true);
+ static void destroyGL();
+ static void restoreGL();
+ BOOL mIsDummy; // for special views
+ S32 mSpecialRenderMode; // special lighting
+private:
+ bool shouldAlphaMask();
+
+ BOOL mNeedsSkin; // avatar has been animated and verts have not been updated
+ F32 mLastSkinTime; //value of gFrameTimeSeconds at last skin update
+
+ S32 mUpdatePeriod;
+ S32 mNumInitFaces; //number of faces generated when creating the avatar drawable, does not inculde splitted faces due to long vertex buffer.
+
+ //--------------------------------------------------------------------
+ // Morph masks
+ //--------------------------------------------------------------------
+public:
+ BOOL morphMaskNeedsUpdate(LLVOAvatarDefines::EBakedTextureIndex index = LLVOAvatarDefines::BAKED_NUM_INDICES);
+ void addMaskedMorph(LLVOAvatarDefines::EBakedTextureIndex index, LLPolyMorphTarget* morph_target, BOOL invert, std::string layer);
+ void applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components, LLVOAvatarDefines::EBakedTextureIndex index = LLVOAvatarDefines::BAKED_NUM_INDICES);
+
+ //--------------------------------------------------------------------
+ // Visibility
+ //--------------------------------------------------------------------
+protected:
+ void updateVisibility();
+private:
+ U32 mVisibilityRank;
+ BOOL mVisible;
+
+ //--------------------------------------------------------------------
+ // Shadowing
+ //--------------------------------------------------------------------
+public:
+ void updateShadowFaces();
+ LLDrawable* mShadow;
+private:
+ LLFace* mShadow0Facep;
+ LLFace* mShadow1Facep;
+ LLPointer<LLViewerTexture> mShadowImagep;
+
+ //--------------------------------------------------------------------
+ // Impostors
+ //--------------------------------------------------------------------
+public:
+ BOOL isImpostor() const;
+ BOOL needsImpostorUpdate() const;
+ const LLVector3& getImpostorOffset() const;
+ const LLVector2& getImpostorDim() const;
+ void getImpostorValues(LLVector4a* extents, LLVector3& angle, F32& distance) const;
+ void cacheImpostorValues();
+ void setImpostorDim(const LLVector2& dim);
+ static void resetImpostors();
+ static void updateImpostors();
+ LLRenderTarget mImpostor;
+ BOOL mNeedsImpostorUpdate;
+private:
+ LLVector3 mImpostorOffset;
+ LLVector2 mImpostorDim;
+ BOOL mNeedsAnimUpdate;
+ LLVector3 mImpostorAngle;
+ F32 mImpostorDistance;
+ F32 mImpostorPixelArea;
+ LLVector3 mLastAnimExtents[2];
+
+ //--------------------------------------------------------------------
+ // Wind rippling in clothes
+ //--------------------------------------------------------------------
+public:
+ LLVector4 mWindVec;
+ F32 mRipplePhase;
+ BOOL mBelowWater;
+private:
+ F32 mWindFreq;
+ LLFrameTimer mRippleTimer;
+ F32 mRippleTimeLast;
+ LLVector3 mRippleAccel;
+ LLVector3 mLastVel;
+
+ //--------------------------------------------------------------------
+ // Culling
+ //--------------------------------------------------------------------
+public:
+ static void cullAvatarsByPixelArea();
+ BOOL isCulled() const { return mCulled; }
+private:
+ BOOL mCulled;
+
+ //--------------------------------------------------------------------
+ // Freeze counter
+ //--------------------------------------------------------------------
+public:
+ static void updateFreezeCounter(S32 counter = 0);
+private:
+ static S32 sFreezeCounter;
+
+ //--------------------------------------------------------------------
+ // Constants
+ //--------------------------------------------------------------------
+public:
+ virtual LLViewerTexture::EBoostLevel getAvatarBoostLevel() const { return LLViewerTexture::BOOST_AVATAR; }
+ virtual LLViewerTexture::EBoostLevel getAvatarBakedBoostLevel() const { return LLViewerTexture::BOOST_AVATAR_BAKED; }
+ virtual S32 getTexImageSize() const;
+ virtual S32 getTexImageArea() const { return getTexImageSize()*getTexImageSize(); }
+
+/** Rendering
+ ** **
+ *******************************************************************************/
+
+/********************************************************************************
+ ** **
+ ** TEXTURES
+ **/
+
+ //--------------------------------------------------------------------
+ // Loading status
+ //--------------------------------------------------------------------
+public:
+ virtual BOOL isTextureDefined(LLVOAvatarDefines::ETextureIndex type, U32 index = 0) const;
+ virtual BOOL isTextureVisible(LLVOAvatarDefines::ETextureIndex type, U32 index = 0) const;
+ virtual BOOL isTextureVisible(LLVOAvatarDefines::ETextureIndex type, LLWearable *wearable) const;
+
+protected:
+ BOOL isFullyBaked();
+ static BOOL areAllNearbyInstancesBaked(S32& grey_avatars);
+
+ //--------------------------------------------------------------------
+ // Baked textures
+ //--------------------------------------------------------------------
+public:
+ void releaseComponentTextures(); // ! BACKWARDS COMPATIBILITY !
+protected:
+ static void onBakedTextureMasksLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata);
+ static void onInitialBakedTextureLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata);
+ static void onBakedTextureLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata);
+ virtual void removeMissingBakedTextures();
+ void useBakedTexture(const LLUUID& id);
+
+ typedef std::deque<LLMaskedMorph *> morph_list_t;
+ struct BakedTextureData
+ {
+ LLUUID mLastTextureIndex;
+ LLTexLayerSet* mTexLayerSet; // Only exists for self
+ bool mIsLoaded;
+ bool mIsUsed;
+ LLVOAvatarDefines::ETextureIndex mTextureIndex;
+ U32 mMaskTexName;
+ // Stores pointers to the joint meshes that this baked texture deals with
+ std::vector< LLViewerJointMesh * > mMeshes; // std::vector<LLViewerJointMesh> mJoints[i]->mMeshParts
+ morph_list_t mMaskedMorphs;
+ };
+ typedef std::vector<BakedTextureData> bakedtexturedata_vec_t;
+ bakedtexturedata_vec_t mBakedTextureDatas;
+ LLLoadedCallbackEntry::source_callback_list_t mCallbackTextureList ;
+ BOOL mLoadedCallbacksPaused;
+ //--------------------------------------------------------------------
+ // Local Textures
+ //--------------------------------------------------------------------
+protected:
+ virtual void setLocalTexture(LLVOAvatarDefines::ETextureIndex type, LLViewerTexture* tex, BOOL baked_version_exits, U32 index = 0);
+ virtual void addLocalTextureStats(LLVOAvatarDefines::ETextureIndex type, LLViewerFetchedTexture* imagep, F32 texel_area_ratio, BOOL rendered, BOOL covered_by_baked, U32 index = 0);
+ // MULTI-WEARABLE: make self-only?
+ virtual void setBakedReady(LLVOAvatarDefines::ETextureIndex type, BOOL baked_version_exists, U32 index = 0);
+
+ //--------------------------------------------------------------------
+ // Texture accessors
+ //--------------------------------------------------------------------
+private:
+ virtual void setImage(const U8 te, LLViewerTexture *imagep, const U32 index);
+ virtual LLViewerTexture* getImage(const U8 te, const U32 index) const;
+
+ virtual const LLTextureEntry* getTexEntry(const U8 te_num) const;
+ virtual void setTexEntry(const U8 index, const LLTextureEntry &te);
+
+ void checkTextureLoading() ;
+ //--------------------------------------------------------------------
+ // Layers
+ //--------------------------------------------------------------------
+protected:
+ void deleteLayerSetCaches(bool clearAll = true);
+ void addBakedTextureStats(LLViewerFetchedTexture* imagep, F32 pixel_area, F32 texel_area_ratio, S32 boost_level);
+
+ //--------------------------------------------------------------------
+ // Composites
+ //--------------------------------------------------------------------
+public:
+ virtual void invalidateComposite(LLTexLayerSet* layerset, BOOL upload_result);
+ virtual void invalidateAll();
+ virtual void setCompositeUpdatesEnabled(bool b) {}
+ virtual void setCompositeUpdatesEnabled(U32 index, bool b) {}
+ virtual bool isCompositeUpdateEnabled(U32 index) { return false; }
+
+ //--------------------------------------------------------------------
+ // Static texture/mesh/baked dictionary
+ //--------------------------------------------------------------------
+public:
+ static BOOL isIndexLocalTexture(LLVOAvatarDefines::ETextureIndex i);
+ static BOOL isIndexBakedTexture(LLVOAvatarDefines::ETextureIndex i);
+private:
+ static const LLVOAvatarDefines::LLVOAvatarDictionary *getDictionary() { return sAvatarDictionary; }
+ static LLVOAvatarDefines::LLVOAvatarDictionary* sAvatarDictionary;
+ static LLVOAvatarSkeletonInfo* sAvatarSkeletonInfo;
+ static LLVOAvatarXmlInfo* sAvatarXmlInfo;
+
+ //--------------------------------------------------------------------
+ // Messaging
+ //--------------------------------------------------------------------
+public:
+ void onFirstTEMessageReceived();
+private:
+ BOOL mFirstTEMessageReceived;
+ BOOL mFirstAppearanceMessageReceived;
+
+/** Textures
+ ** **
+ *******************************************************************************/
+
+/********************************************************************************
+ ** **
+ ** MESHES
+ **/
+
+public:
+ void updateMeshTextures();
+ void updateSexDependentLayerSets(BOOL upload_bake);
+ void dirtyMesh(); // Dirty the avatar mesh
+ void updateMeshData();
+protected:
+ void releaseMeshData();
+ virtual void restoreMeshData();
+private:
+ void dirtyMesh(S32 priority); // Dirty the avatar mesh, with priority
+ S32 mDirtyMesh; // 0 -- not dirty, 1 -- morphed, 2 -- LOD
+ BOOL mMeshTexturesDirty;
+
+ typedef std::multimap<std::string, LLPolyMesh*> polymesh_map_t;
+ polymesh_map_t mMeshes;
+ std::vector<LLViewerJoint *> mMeshLOD;
+
+ //--------------------------------------------------------------------
+ // Destroy invisible mesh
+ //--------------------------------------------------------------------
+protected:
+ BOOL mMeshValid;
+ LLFrameTimer mMeshInvisibleTime;
+
+/** Meshes
+ ** **
+ *******************************************************************************/
+
+/********************************************************************************
+ ** **
+ ** APPEARANCE
+ **/
+
+public:
+ void processAvatarAppearance(LLMessageSystem* mesgsys);
+ void hideSkirt();
+ void startAppearanceAnimation();
+
+ //--------------------------------------------------------------------
+ // Appearance morphing
+ //--------------------------------------------------------------------
+public:
+ BOOL getIsAppearanceAnimating() const { return mAppearanceAnimating; }
+private:
+ BOOL mAppearanceAnimating;
+ LLFrameTimer mAppearanceMorphTimer;
+ F32 mLastAppearanceBlendTime;
+
+ //--------------------------------------------------------------------
+ // Clothing colors (convenience functions to access visual parameters)
+ //--------------------------------------------------------------------
+public:
+ void setClothesColor(LLVOAvatarDefines::ETextureIndex te, const LLColor4& new_color, BOOL upload_bake);
+ LLColor4 getClothesColor(LLVOAvatarDefines::ETextureIndex te);
+ static BOOL teToColorParams(LLVOAvatarDefines::ETextureIndex te, U32 *param_name);
+
+ //--------------------------------------------------------------------
+ // Global colors
+ //--------------------------------------------------------------------
+public:
+ LLColor4 getGlobalColor(const std::string& color_name ) const;
+ void onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL upload_bake);
+private:
+ LLTexGlobalColor* mTexSkinColor;
+ LLTexGlobalColor* mTexHairColor;
+ LLTexGlobalColor* mTexEyeColor;
+
+ //--------------------------------------------------------------------
+ // Visibility
+ //--------------------------------------------------------------------
+public:
+ BOOL isVisible() const;
+ void setVisibilityRank(U32 rank);
+ U32 getVisibilityRank() const { return mVisibilityRank; } // unused
+ static S32 sNumVisibleAvatars; // Number of instances of this class
+ static LLColor4 getDummyColor();
+/** Appearance
+ ** **
+ *******************************************************************************/
+
+/********************************************************************************
+ ** **
+ ** WEARABLES
+ **/
+
+public:
+ virtual BOOL isWearingWearableType(LLWearableType::EType type ) const;
+
+ //--------------------------------------------------------------------
+ // Attachments
+ //--------------------------------------------------------------------
+public:
+ void clampAttachmentPositions();
+ virtual const LLViewerJointAttachment* attachObject(LLViewerObject *viewer_object);
+ virtual BOOL detachObject(LLViewerObject *viewer_object);
+ void cleanupAttachedMesh( LLViewerObject* pVO );
+ static LLVOAvatar* findAvatarFromAttachment(LLViewerObject* obj);
+protected:
+ LLViewerJointAttachment* getTargetAttachmentPoint(LLViewerObject* viewer_object);
+ void lazyAttach();
+ void rebuildRiggedAttachments( void );
+
+ //--------------------------------------------------------------------
+ // Map of attachment points, by ID
+ //--------------------------------------------------------------------
+public:
+ S32 getAttachmentCount(); // Warning: order(N) not order(1) // currently used only by -self
+ typedef std::map<S32, LLViewerJointAttachment*> attachment_map_t;
+ attachment_map_t mAttachmentPoints;
+ std::vector<LLPointer<LLViewerObject> > mPendingAttachment;
+
+ //--------------------------------------------------------------------
+ // HUD functions
+ //--------------------------------------------------------------------
+public:
+ BOOL hasHUDAttachment() const;
+ LLBBox getHUDBBox() const;
+ void rebuildHUD();
+ void resetHUDAttachments();
+ BOOL canAttachMoreObjects() const;
+ BOOL canAttachMoreObjects(U32 n) const;
+protected:
+ U32 getNumAttachments() const; // O(N), not O(1)
+
+/** Wearables
+ ** **
+ *******************************************************************************/
+
+/********************************************************************************
+ ** **
+ ** ACTIONS
+ **/
+
+ //--------------------------------------------------------------------
+ // Animations
+ //--------------------------------------------------------------------
+public:
+ BOOL isAnyAnimationSignaled(const LLUUID *anim_array, const S32 num_anims) const;
+ void processAnimationStateChanges();
+protected:
+ BOOL processSingleAnimationStateChange(const LLUUID &anim_id, BOOL start);
+ void resetAnimations();
+private:
+ LLTimer mAnimTimer;
+ F32 mTimeLast;
+
+ //--------------------------------------------------------------------
+ // Animation state data
+ //--------------------------------------------------------------------
+public:
+ typedef std::map<LLUUID, S32>::iterator AnimIterator;
+ std::map<LLUUID, S32> mSignaledAnimations; // requested state of Animation name/value
+ std::map<LLUUID, S32> mPlayingAnimations; // current state of Animation name/value
+
+ typedef std::multimap<LLUUID, LLUUID> AnimationSourceMap;
+ typedef AnimationSourceMap::iterator AnimSourceIterator;
+ AnimationSourceMap mAnimationSources; // object ids that triggered anim ids
+
+ //--------------------------------------------------------------------
+ // Chat
+ //--------------------------------------------------------------------
+public:
+ void addChat(const LLChat& chat);
+ void clearChat();
+ void startTyping() { mTyping = TRUE; mTypingTimer.reset(); }
+ void stopTyping() { mTyping = FALSE; }
+private:
+ BOOL mVisibleChat;
+
+ //--------------------------------------------------------------------
+ // Lip synch morphs
+ //--------------------------------------------------------------------
+private:
+ bool mLipSyncActive; // we're morphing for lip sync
+ LLVisualParam* mOohMorph; // cached pointers morphs for lip sync
+ LLVisualParam* mAahMorph; // cached pointers morphs for lip sync
+
+ //--------------------------------------------------------------------
+ // Flight
+ //--------------------------------------------------------------------
+public:
+ BOOL mInAir;
+ LLFrameTimer mTimeInAir;
+
+/** Actions
+ ** **
+ *******************************************************************************/
+
+/********************************************************************************
+ ** **
+ ** PHYSICS
+ **/
+
+private:
+ F32 mSpeedAccum; // measures speed (for diagnostics mostly).
+ BOOL mTurning; // controls hysteresis on avatar rotation
+ F32 mSpeed; // misc. animation repeated state
+
+ //--------------------------------------------------------------------
+ // Collision volumes
+ //--------------------------------------------------------------------
+public:
+ S32 mNumCollisionVolumes;
+ LLViewerJointCollisionVolume* mCollisionVolumes;
+protected:
+ BOOL allocateCollisionVolumes(U32 num);
+
+ //--------------------------------------------------------------------
+ // Dimensions
+ //--------------------------------------------------------------------
+public:
+ void resolveHeightGlobal(const LLVector3d &inPos, LLVector3d &outPos, LLVector3 &outNorm);
+ bool distanceToGround( const LLVector3d &startPoint, LLVector3d &collisionPoint, F32 distToIntersectionAlongRay );
+ void resolveHeightAgent(const LLVector3 &inPos, LLVector3 &outPos, LLVector3 &outNorm);
+ void resolveRayCollisionAgent(const LLVector3d start_pt, const LLVector3d end_pt, LLVector3d &out_pos, LLVector3 &out_norm);
+ void slamPosition(); // Slam position to transmitted position (for teleport);
+protected:
+ void computeBodySize();
+
+ //--------------------------------------------------------------------
+ // Material being stepped on
+ //--------------------------------------------------------------------
+private:
+ BOOL mStepOnLand;
+ U8 mStepMaterial;
+ LLVector3 mStepObjectVelocity;
+
+/** Physics
+ ** **
+ *******************************************************************************/
+
+/********************************************************************************
+ ** **
+ ** HIERARCHY
+ **/
+
+public:
+ virtual BOOL setParent(LLViewerObject* parent);
+ virtual void addChild(LLViewerObject *childp);
+ virtual void removeChild(LLViewerObject *childp);
+
+ //--------------------------------------------------------------------
+ // Sitting
+ //--------------------------------------------------------------------
+public:
+ void sitDown(BOOL bSitting);
+ BOOL isSitting(){return mIsSitting;}
+ void sitOnObject(LLViewerObject *sit_object);
+ void getOffObject();
+private:
+ // set this property only with LLVOAvatar::sitDown method
+ BOOL mIsSitting;
+
+/** Hierarchy
+ ** **
+ *******************************************************************************/
+
+/********************************************************************************
+ ** **
+ ** NAME
+ **/
+
+public:
+ std::string getFullname() const; // Returns "FirstName LastName"
+protected:
+ static void getAnimLabels(LLDynamicArray<std::string>* labels);
+ static void getAnimNames(LLDynamicArray<std::string>* names);
+private:
+ std::string mNameString; // UTF-8 title + name + status
+ std::string mTitle;
+ bool mNameAway;
+ bool mNameBusy;
+ bool mNameMute;
+ bool mNameAppearance;
+ bool mNameFriend;
+ bool mNameCloud;
+ F32 mNameAlpha;
+ BOOL mRenderGroupTitles;
+
+ //--------------------------------------------------------------------
+ // Display the name (then optionally fade it out)
+ //--------------------------------------------------------------------
+public:
+ LLFrameTimer mChatTimer;
+ LLPointer<LLHUDNameTag> mNameText;
+private:
+ LLFrameTimer mTimeVisible;
+ std::deque<LLChat> mChats;
+ BOOL mTyping;
+ LLFrameTimer mTypingTimer;
+
+/** Name
+ ** **
+ *******************************************************************************/
+
+/********************************************************************************
+ ** **
+ ** SOUNDS
+ **/
+
+ //--------------------------------------------------------------------
+ // Voice visualizer
+ //--------------------------------------------------------------------
+public:
+ // Responsible for detecting the user's voice signal (and when the
+ // user speaks, it puts a voice symbol over the avatar's head) and gesticulations
+ LLPointer<LLVoiceVisualizer> mVoiceVisualizer;
+ int mCurrentGesticulationLevel;
+
+ //--------------------------------------------------------------------
+ // Step sound
+ //--------------------------------------------------------------------
+protected:
+ const LLUUID& getStepSound() const;
+private:
+ // Global table of sound ids per material, and the ground
+ const static LLUUID sStepSounds[LL_MCODE_END];
+ const static LLUUID sStepSoundOnLand;
+
+ //--------------------------------------------------------------------
+ // Foot step state (for generating sounds)
+ //--------------------------------------------------------------------
+public:
+ void setFootPlane(const LLVector4 &plane) { mFootPlane = plane; }
+ LLVector4 mFootPlane;
+private:
+ BOOL mWasOnGroundLeft;
+ BOOL mWasOnGroundRight;
+
+/** Sounds
+ ** **
+ *******************************************************************************/
+
+/********************************************************************************
+ ** **
+ ** DIAGNOSTICS
+ **/
+
+ //--------------------------------------------------------------------
+ // General
+ //--------------------------------------------------------------------
+public:
+ static void dumpArchetypeXML(void*);
+ static void dumpBakedStatus();
+ const std::string getBakedStatusForPrintout() const;
+ void dumpAvatarTEs(const std::string& context) const;
+
+ static F32 sUnbakedTime; // Total seconds with >=1 unbaked avatars
+ static F32 sUnbakedUpdateTime; // Last time stats were updated (to prevent multiple updates per frame)
+ static F32 sGreyTime; // Total seconds with >=1 grey avatars
+ static F32 sGreyUpdateTime; // Last time stats were updated (to prevent multiple updates per frame)
+protected:
+ S32 getUnbakedPixelAreaRank();
+ BOOL mHasGrey;
+private:
+ F32 mMinPixelArea;
+ F32 mMaxPixelArea;
+ F32 mAdjustedPixelArea;
+ std::string mDebugText;
+
+
+ //--------------------------------------------------------------------
+ // Avatar Rez Metrics
+ //--------------------------------------------------------------------
+public:
+ F32 debugGetExistenceTimeElapsedF32() const { return mDebugExistenceTimer.getElapsedTimeF32(); }
+protected:
+ LLFrameTimer mRuthDebugTimer; // For tracking how long it takes for av to rez
+ LLFrameTimer mDebugExistenceTimer; // Debugging for how long the avatar has been in memory.
+
+/** Diagnostics
+ ** **
+ *******************************************************************************/
+
+/********************************************************************************
+ ** **
+ ** SUPPORT CLASSES
+ **/
+
+protected: // Shared with LLVOAvatarSelf
+
+ struct LLVOAvatarXmlInfo
+ {
+ LLVOAvatarXmlInfo();
+ ~LLVOAvatarXmlInfo();
+
+ BOOL parseXmlSkeletonNode(LLXmlTreeNode* root);
+ BOOL parseXmlMeshNodes(LLXmlTreeNode* root);
+ BOOL parseXmlColorNodes(LLXmlTreeNode* root);
+ BOOL parseXmlLayerNodes(LLXmlTreeNode* root);
+ BOOL parseXmlDriverNodes(LLXmlTreeNode* root);
+ BOOL parseXmlMorphNodes(LLXmlTreeNode* root);
+
+ struct LLVOAvatarMeshInfo
+ {
+ typedef std::pair<LLPolyMorphTargetInfo*,BOOL> morph_info_pair_t;
+ typedef std::vector<morph_info_pair_t> morph_info_list_t;
+
+ LLVOAvatarMeshInfo() : mLOD(0), mMinPixelArea(.1f) {}
+ ~LLVOAvatarMeshInfo()
+ {
+ morph_info_list_t::iterator iter;
+ for (iter = mPolyMorphTargetInfoList.begin(); iter != mPolyMorphTargetInfoList.end(); iter++)
+ {
+ delete iter->first;
+ }
+ mPolyMorphTargetInfoList.clear();
+ }
+
+ std::string mType;
+ S32 mLOD;
+ std::string mMeshFileName;
+ std::string mReferenceMeshName;
+ F32 mMinPixelArea;
+ morph_info_list_t mPolyMorphTargetInfoList;
+ };
+ typedef std::vector<LLVOAvatarMeshInfo*> mesh_info_list_t;
+ mesh_info_list_t mMeshInfoList;
+
+ typedef std::vector<LLPolySkeletalDistortionInfo*> skeletal_distortion_info_list_t;
+ skeletal_distortion_info_list_t mSkeletalDistortionInfoList;
+
+ struct LLVOAvatarAttachmentInfo
+ {
+ LLVOAvatarAttachmentInfo()
+ : mGroup(-1), mAttachmentID(-1), mPieMenuSlice(-1), mVisibleFirstPerson(FALSE),
+ mIsHUDAttachment(FALSE), mHasPosition(FALSE), mHasRotation(FALSE) {}
+ std::string mName;
+ std::string mJointName;
+ LLVector3 mPosition;
+ LLVector3 mRotationEuler;
+ S32 mGroup;
+ S32 mAttachmentID;
+ S32 mPieMenuSlice;
+ BOOL mVisibleFirstPerson;
+ BOOL mIsHUDAttachment;
+ BOOL mHasPosition;
+ BOOL mHasRotation;
+ };
+ typedef std::vector<LLVOAvatarAttachmentInfo*> attachment_info_list_t;
+ attachment_info_list_t mAttachmentInfoList;
+
+ LLTexGlobalColorInfo *mTexSkinColorInfo;
+ LLTexGlobalColorInfo *mTexHairColorInfo;
+ LLTexGlobalColorInfo *mTexEyeColorInfo;
+
+ typedef std::vector<LLTexLayerSetInfo*> layer_info_list_t;
+ layer_info_list_t mLayerInfoList;
+
+ typedef std::vector<LLDriverParamInfo*> driver_info_list_t;
+ driver_info_list_t mDriverInfoList;
+
+ struct LLVOAvatarMorphInfo
+ {
+ LLVOAvatarMorphInfo()
+ : mInvert(FALSE) {}
+ std::string mName;
+ std::string mRegion;
+ std::string mLayer;
+ BOOL mInvert;
+ };
+
+ typedef std::vector<LLVOAvatarMorphInfo*> morph_info_list_t;
+ morph_info_list_t mMorphMaskInfoList;
+ };
+
+ struct LLMaskedMorph
+ {
+ LLMaskedMorph(LLPolyMorphTarget *morph_target, BOOL invert, std::string layer) :
+ mMorphTarget(morph_target),
+ mInvert(invert),
+ mLayer(layer)
+ {
+ morph_target->addPendingMorphMask();
+ }
+
+ LLPolyMorphTarget *mMorphTarget;
+ BOOL mInvert;
+ std::string mLayer;
+ };
+
+/** Support classes
+ ** **
+ *******************************************************************************/
+
+}; // LLVOAvatar
+extern const F32 SELF_ADDITIONAL_PRI;
+extern const S32 MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL;
+
+#endif // LL_VO_AVATAR_H
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index cbfd64cffb..2882e644c8 100755 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -1,4913 +1,5054 @@ -/** - * @file llvovolume.cpp - * @brief LLVOVolume class implementation - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -// A "volume" is a box, cylinder, sphere, or other primitive shape. - -#include "llviewerprecompiledheaders.h" - -#include "llvovolume.h" - -#include <sstream> - -#include "llviewercontrol.h" -#include "lldir.h" -#include "llflexibleobject.h" -#include "llfloatertools.h" -#include "llmaterialtable.h" -#include "llprimitive.h" -#include "llvolume.h" -#include "llvolumeoctree.h" -#include "llvolumemgr.h" -#include "llvolumemessage.h" -#include "material_codes.h" -#include "message.h" -#include "llpluginclassmedia.h" // for code in the mediaEvent handler -#include "object_flags.h" -#include "llagentconstants.h" -#include "lldrawable.h" -#include "lldrawpoolavatar.h" -#include "lldrawpoolbump.h" -#include "llface.h" -#include "llspatialpartition.h" -#include "llhudmanager.h" -#include "llflexibleobject.h" -#include "llsky.h" -#include "lltexturefetch.h" -#include "llvector4a.h" -#include "llviewercamera.h" -#include "llviewertexturelist.h" -#include "llviewerobjectlist.h" -#include "llviewerregion.h" -#include "llviewertextureanim.h" -#include "llworld.h" -#include "llselectmgr.h" -#include "pipeline.h" -#include "llsdutil.h" -#include "llmatrix4a.h" -#include "llmediaentry.h" -#include "llmediadataclient.h" -#include "llmeshrepository.h" -#include "llagent.h" -#include "llviewermediafocus.h" -#include "lldatapacker.h" -#include "llviewershadermgr.h" -#include "llvoavatar.h" -#include "llvocache.h" - -const S32 MIN_QUIET_FRAMES_COALESCE = 30; -const F32 FORCE_SIMPLE_RENDER_AREA = 512.f; -const F32 FORCE_CULL_AREA = 8.f; -const F32 MAX_LOD_DISTANCE = 24.f; - - -BOOL gAnimateTextures = TRUE; -//extern BOOL gHideSelectedObjects; - -F32 LLVOVolume::sLODFactor = 1.f; -F32 LLVOVolume::sLODSlopDistanceFactor = 0.5f; //Changing this to zero, effectively disables the LOD transition slop -F32 LLVOVolume::sDistanceFactor = 1.0f; -S32 LLVOVolume::sNumLODChanges = 0; -LLPointer<LLObjectMediaDataClient> LLVOVolume::sObjectMediaClient = NULL; -LLPointer<LLObjectMediaNavigateClient> LLVOVolume::sObjectMediaNavigateClient = NULL; - -static LLFastTimer::DeclareTimer FTM_GEN_TRIANGLES("Generate Triangles"); -static LLFastTimer::DeclareTimer FTM_GEN_VOLUME("Generate Volumes"); -static LLFastTimer::DeclareTimer FTM_VOLUME_TEXTURES("Volume Textures"); - -// Implementation class of LLMediaDataClientObject. See llmediadataclient.h -class LLMediaDataClientObjectImpl : public LLMediaDataClientObject -{ -public: - LLMediaDataClientObjectImpl(LLVOVolume *obj, bool isNew) : mObject(obj), mNew(isNew) - { - mObject->addMDCImpl(); - } - ~LLMediaDataClientObjectImpl() - { - mObject->removeMDCImpl(); - } - - virtual U8 getMediaDataCount() const - { return mObject->getNumTEs(); } - - virtual LLSD getMediaDataLLSD(U8 index) const - { - LLSD result; - LLTextureEntry *te = mObject->getTE(index); - if (NULL != te) - { - llassert((te->getMediaData() != NULL) == te->hasMedia()); - if (te->getMediaData() != NULL) - { - result = te->getMediaData()->asLLSD(); - // XXX HACK: workaround bug in asLLSD() where whitelist is not set properly - // See DEV-41949 - if (!result.has(LLMediaEntry::WHITELIST_KEY)) - { - result[LLMediaEntry::WHITELIST_KEY] = LLSD::emptyArray(); - } - } - } - return result; - } - virtual bool isCurrentMediaUrl(U8 index, const std::string &url) const - { - LLTextureEntry *te = mObject->getTE(index); - if (te) - { - if (te->getMediaData()) - { - return (te->getMediaData()->getCurrentURL() == url); - } - } - return url.empty(); - } - - virtual LLUUID getID() const - { return mObject->getID(); } - - virtual void mediaNavigateBounceBack(U8 index) - { mObject->mediaNavigateBounceBack(index); } - - virtual bool hasMedia() const - { return mObject->hasMedia(); } - - virtual void updateObjectMediaData(LLSD const &data, const std::string &version_string) - { mObject->updateObjectMediaData(data, version_string); } - - virtual F64 getMediaInterest() const - { - F64 interest = mObject->getTotalMediaInterest(); - if (interest < (F64)0.0) - { - // media interest not valid yet, try pixel area - interest = mObject->getPixelArea(); - // HACK: force recalculation of pixel area if interest is the "magic default" of 1024. - if (interest == 1024.f) - { - const_cast<LLVOVolume*>(static_cast<LLVOVolume*>(mObject))->setPixelAreaAndAngle(gAgent); - interest = mObject->getPixelArea(); - } - } - return interest; - } - - virtual bool isInterestingEnough() const - { - return LLViewerMedia::isInterestingEnough(mObject, getMediaInterest()); - } - - virtual std::string getCapabilityUrl(const std::string &name) const - { return mObject->getRegion()->getCapability(name); } - - virtual bool isDead() const - { return mObject->isDead(); } - - virtual U32 getMediaVersion() const - { return LLTextureEntry::getVersionFromMediaVersionString(mObject->getMediaURL()); } - - virtual bool isNew() const - { return mNew; } - -private: - LLPointer<LLVOVolume> mObject; - bool mNew; -}; - - -LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) - : LLViewerObject(id, pcode, regionp), - mVolumeImpl(NULL) -{ - mTexAnimMode = 0; - mRelativeXform.setIdentity(); - mRelativeXformInvTrans.setIdentity(); - - mFaceMappingChanged = FALSE; - mLOD = MIN_LOD; - mTextureAnimp = NULL; - mVolumeChanged = FALSE; - mVObjRadius = LLVector3(1,1,0.5f).length(); - mNumFaces = 0; - mLODChanged = FALSE; - mSculptChanged = FALSE; - mSpotLightPriority = 0.f; - - mMediaImplList.resize(getNumTEs()); - mLastFetchedMediaVersion = -1; - mIndexInTex = 0; - mMDCImplCount = 0; -} - -LLVOVolume::~LLVOVolume() -{ - delete mTextureAnimp; - mTextureAnimp = NULL; - delete mVolumeImpl; - mVolumeImpl = NULL; - - if(!mMediaImplList.empty()) - { - for(U32 i = 0 ; i < mMediaImplList.size() ; i++) - { - if(mMediaImplList[i].notNull()) - { - mMediaImplList[i]->removeObject(this) ; - } - } - } -} - -void LLVOVolume::markDead() -{ - if (!mDead) - { - if(getMDCImplCount() > 0) - { - LLMediaDataClientObject::ptr_t obj = new LLMediaDataClientObjectImpl(const_cast<LLVOVolume*>(this), false); - if (sObjectMediaClient) sObjectMediaClient->removeFromQueue(obj); - if (sObjectMediaNavigateClient) sObjectMediaNavigateClient->removeFromQueue(obj); - } - - // Detach all media impls from this object - for(U32 i = 0 ; i < mMediaImplList.size() ; i++) - { - removeMediaImpl(i); - } - - if (mSculptTexture.notNull()) - { - mSculptTexture->removeVolume(this); - } - } - - LLViewerObject::markDead(); -} - - -// static -void LLVOVolume::initClass() -{ - // gSavedSettings better be around - if (gSavedSettings.getBOOL("PrimMediaMasterEnabled")) - { - const F32 queue_timer_delay = gSavedSettings.getF32("PrimMediaRequestQueueDelay"); - const F32 retry_timer_delay = gSavedSettings.getF32("PrimMediaRetryTimerDelay"); - const U32 max_retries = gSavedSettings.getU32("PrimMediaMaxRetries"); - const U32 max_sorted_queue_size = gSavedSettings.getU32("PrimMediaMaxSortedQueueSize"); - const U32 max_round_robin_queue_size = gSavedSettings.getU32("PrimMediaMaxRoundRobinQueueSize"); - sObjectMediaClient = new LLObjectMediaDataClient(queue_timer_delay, retry_timer_delay, max_retries, - max_sorted_queue_size, max_round_robin_queue_size); - sObjectMediaNavigateClient = new LLObjectMediaNavigateClient(queue_timer_delay, retry_timer_delay, - max_retries, max_sorted_queue_size, max_round_robin_queue_size); - } -} - -// static -void LLVOVolume::cleanupClass() -{ - sObjectMediaClient = NULL; - sObjectMediaNavigateClient = NULL; -} - -U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys, - void **user_data, - U32 block_num, EObjectUpdateType update_type, - LLDataPacker *dp) -{ - LLColor4U color; - const S32 teDirtyBits = (TEM_CHANGE_TEXTURE|TEM_CHANGE_COLOR|TEM_CHANGE_MEDIA); - - // Do base class updates... - U32 retval = LLViewerObject::processUpdateMessage(mesgsys, user_data, block_num, update_type, dp); - - LLUUID sculpt_id; - U8 sculpt_type = 0; - if (isSculpted()) - { - LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT); - sculpt_id = sculpt_params->getSculptTexture(); - sculpt_type = sculpt_params->getSculptType(); - } - - if (!dp) - { - if (update_type == OUT_FULL) - { - //////////////////////////////// - // - // Unpack texture animation data - // - // - - if (mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_TextureAnim)) - { - if (!mTextureAnimp) - { - mTextureAnimp = new LLViewerTextureAnim(); - } - else - { - if (!(mTextureAnimp->mMode & LLTextureAnim::SMOOTH)) - { - mTextureAnimp->reset(); - } - } - mTexAnimMode = 0; - mTextureAnimp->unpackTAMessage(mesgsys, block_num); - } - else - { - if (mTextureAnimp) - { - delete mTextureAnimp; - mTextureAnimp = NULL; - gPipeline.markTextured(mDrawable); - mFaceMappingChanged = TRUE; - mTexAnimMode = 0; - } - } - - // Unpack volume data - LLVolumeParams volume_params; - LLVolumeMessage::unpackVolumeParams(&volume_params, mesgsys, _PREHASH_ObjectData, block_num); - volume_params.setSculptID(sculpt_id, sculpt_type); - - if (setVolume(volume_params, 0)) - { - markForUpdate(TRUE); - } - } - - // Sigh, this needs to be done AFTER the volume is set as well, otherwise bad stuff happens... - //////////////////////////// - // - // Unpack texture entry data - // - S32 result = unpackTEMessage(mesgsys, _PREHASH_ObjectData, block_num); - if (result & teDirtyBits) - { - updateTEData(); - } - if (result & TEM_CHANGE_MEDIA) - { - retval |= MEDIA_FLAGS_CHANGED; - } - } - else - { - // CORY TO DO: Figure out how to get the value here - if (update_type != OUT_TERSE_IMPROVED) - { - LLVolumeParams volume_params; - BOOL res = LLVolumeMessage::unpackVolumeParams(&volume_params, *dp); - if (!res) - { - llwarns << "Bogus volume parameters in object " << getID() << llendl; - llwarns << getRegion()->getOriginGlobal() << llendl; - } - - volume_params.setSculptID(sculpt_id, sculpt_type); - - if (setVolume(volume_params, 0)) - { - markForUpdate(TRUE); - } - S32 res2 = unpackTEMessage(*dp); - if (TEM_INVALID == res2) - { - // There's something bogus in the data that we're unpacking. - dp->dumpBufferToLog(); - llwarns << "Flushing cache files" << llendl; - - if(LLVOCache::hasInstance() && getRegion()) - { - LLVOCache::getInstance()->removeEntry(getRegion()->getHandle()) ; - } - - llwarns << "Bogus TE data in " << getID() << llendl; - } - else - { - if (res2 & teDirtyBits) - { - updateTEData(); - } - if (res2 & TEM_CHANGE_MEDIA) - { - retval |= MEDIA_FLAGS_CHANGED; - } - } - - U32 value = dp->getPassFlags(); - - if (value & 0x40) - { - if (!mTextureAnimp) - { - mTextureAnimp = new LLViewerTextureAnim(); - } - else - { - if (!(mTextureAnimp->mMode & LLTextureAnim::SMOOTH)) - { - mTextureAnimp->reset(); - } - } - mTexAnimMode = 0; - mTextureAnimp->unpackTAMessage(*dp); - } - else if (mTextureAnimp) - { - delete mTextureAnimp; - mTextureAnimp = NULL; - gPipeline.markTextured(mDrawable); - mFaceMappingChanged = TRUE; - mTexAnimMode = 0; - } - } - else - { - S32 texture_length = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_TextureEntry); - if (texture_length) - { - U8 tdpbuffer[1024]; - LLDataPackerBinaryBuffer tdp(tdpbuffer, 1024); - mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_TextureEntry, tdpbuffer, 0, block_num); - S32 result = unpackTEMessage(tdp); - if (result & teDirtyBits) - { - updateTEData(); - } - if (result & TEM_CHANGE_MEDIA) - { - retval |= MEDIA_FLAGS_CHANGED; - } - } - } - } - if (retval & (MEDIA_URL_REMOVED | MEDIA_URL_ADDED | MEDIA_URL_UPDATED | MEDIA_FLAGS_CHANGED)) - { - // If only the media URL changed, and it isn't a media version URL, - // ignore it - if ( ! ( retval & (MEDIA_URL_ADDED | MEDIA_URL_UPDATED) && - mMedia && ! mMedia->mMediaURL.empty() && - ! LLTextureEntry::isMediaVersionString(mMedia->mMediaURL) ) ) - { - // If the media changed at all, request new media data - LL_DEBUGS("MediaOnAPrim") << "Media update: " << getID() << ": retval=" << retval << " Media URL: " << - ((mMedia) ? mMedia->mMediaURL : std::string("")) << LL_ENDL; - requestMediaDataUpdate(retval & MEDIA_FLAGS_CHANGED); - } - else { - LL_INFOS("MediaOnAPrim") << "Ignoring media update for: " << getID() << " Media URL: " << - ((mMedia) ? mMedia->mMediaURL : std::string("")) << LL_ENDL; - } - } - // ...and clean up any media impls - cleanUpMediaImpls(); - - return retval; -} - - -void LLVOVolume::animateTextures() -{ - F32 off_s = 0.f, off_t = 0.f, scale_s = 1.f, scale_t = 1.f, rot = 0.f; - S32 result = mTextureAnimp->animateTextures(off_s, off_t, scale_s, scale_t, rot); - - if (result) - { - if (!mTexAnimMode) - { - mFaceMappingChanged = TRUE; - gPipeline.markTextured(mDrawable); - } - mTexAnimMode = result | mTextureAnimp->mMode; - - S32 start=0, end=mDrawable->getNumFaces()-1; - if (mTextureAnimp->mFace >= 0 && mTextureAnimp->mFace <= end) - { - start = end = mTextureAnimp->mFace; - } - - for (S32 i = start; i <= end; i++) - { - LLFace* facep = mDrawable->getFace(i); - if(facep->getVirtualSize() <= MIN_TEX_ANIM_SIZE && facep->mTextureMatrix) continue; - - const LLTextureEntry* te = facep->getTextureEntry(); - - if (!te) - { - continue; - } - - if (!(result & LLViewerTextureAnim::ROTATE)) - { - te->getRotation(&rot); - } - if (!(result & LLViewerTextureAnim::TRANSLATE)) - { - te->getOffset(&off_s,&off_t); - } - if (!(result & LLViewerTextureAnim::SCALE)) - { - te->getScale(&scale_s, &scale_t); - } - - if (!facep->mTextureMatrix) - { - facep->mTextureMatrix = new LLMatrix4(); - } - - LLMatrix4& tex_mat = *facep->mTextureMatrix; - tex_mat.setIdentity(); - LLVector3 trans ; - - if(facep->isAtlasInUse()) - { - // - //if use atlas for animated texture - //apply the following transform to the animation matrix. - // - - F32 tcoord_xoffset = 0.f ; - F32 tcoord_yoffset = 0.f ; - F32 tcoord_xscale = 1.f ; - F32 tcoord_yscale = 1.f ; - if(facep->isAtlasInUse()) - { - const LLVector2* tmp = facep->getTexCoordOffset() ; - tcoord_xoffset = tmp->mV[0] ; - tcoord_yoffset = tmp->mV[1] ; - - tmp = facep->getTexCoordScale() ; - tcoord_xscale = tmp->mV[0] ; - tcoord_yscale = tmp->mV[1] ; - } - trans.set(LLVector3(tcoord_xoffset + tcoord_xscale * (off_s+0.5f), tcoord_yoffset + tcoord_yscale * (off_t+0.5f), 0.f)); - - tex_mat.translate(LLVector3(-(tcoord_xoffset + tcoord_xscale * 0.5f), -(tcoord_yoffset + tcoord_yscale * 0.5f), 0.f)); - } - else //non atlas - { - trans.set(LLVector3(off_s+0.5f, off_t+0.5f, 0.f)); - tex_mat.translate(LLVector3(-0.5f, -0.5f, 0.f)); - } - - LLVector3 scale(scale_s, scale_t, 1.f); - LLQuaternion quat; - quat.setQuat(rot, 0, 0, -1.f); - - tex_mat.rotate(quat); - - LLMatrix4 mat; - mat.initAll(scale, LLQuaternion(), LLVector3()); - tex_mat *= mat; - - tex_mat.translate(trans); - } - } - else - { - if (mTexAnimMode && mTextureAnimp->mRate == 0) - { - U8 start, count; - - if (mTextureAnimp->mFace == -1) - { - start = 0; - count = getNumTEs(); - } - else - { - start = (U8) mTextureAnimp->mFace; - count = 1; - } - - for (S32 i = start; i < start + count; i++) - { - if (mTexAnimMode & LLViewerTextureAnim::TRANSLATE) - { - setTEOffset(i, mTextureAnimp->mOffS, mTextureAnimp->mOffT); - } - if (mTexAnimMode & LLViewerTextureAnim::SCALE) - { - setTEScale(i, mTextureAnimp->mScaleS, mTextureAnimp->mScaleT); - } - if (mTexAnimMode & LLViewerTextureAnim::ROTATE) - { - setTERotation(i, mTextureAnimp->mRot); - } - } - - gPipeline.markTextured(mDrawable); - mFaceMappingChanged = TRUE; - mTexAnimMode = 0; - } - } -} -BOOL LLVOVolume::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) -{ - LLViewerObject::idleUpdate(agent, world, time); - - static LLFastTimer::DeclareTimer ftm("Volume"); - LLFastTimer t(ftm); - - if (mDead || mDrawable.isNull()) - { - return TRUE; - } - - /////////////////////// - // - // Do texture animation stuff - // - - if (mTextureAnimp && gAnimateTextures) - { - animateTextures(); - } - - // Dispatch to implementation - if (mVolumeImpl) - { - mVolumeImpl->doIdleUpdate(agent, world, time); - } - - const S32 MAX_ACTIVE_OBJECT_QUIET_FRAMES = 40; - - if (mDrawable->isActive()) - { - if (mDrawable->isRoot() && - mDrawable->mQuietCount++ > MAX_ACTIVE_OBJECT_QUIET_FRAMES && - (!mDrawable->getParent() || !mDrawable->getParent()->isActive())) - { - mDrawable->makeStatic(); - } - } - - return TRUE; -} - -void LLVOVolume::updateTextures() -{ - const F32 TEXTURE_AREA_REFRESH_TIME = 5.f; // seconds - if (mTextureUpdateTimer.getElapsedTimeF32() > TEXTURE_AREA_REFRESH_TIME) - { - updateTextureVirtualSize(); - } -} - -BOOL LLVOVolume::isVisible() const -{ - if(mDrawable.notNull() && mDrawable->isVisible()) - { - return TRUE ; - } - - if(isAttachment()) - { - LLViewerObject* objp = (LLViewerObject*)getParent() ; - while(objp && !objp->isAvatar()) - { - objp = (LLViewerObject*)objp->getParent() ; - } - - return objp && objp->mDrawable.notNull() && objp->mDrawable->isVisible() ; - } - - return FALSE ; -} - -void LLVOVolume::updateTextureVirtualSize() -{ - LLFastTimer ftm(FTM_VOLUME_TEXTURES); - // Update the pixel area of all faces - - if(!isVisible()) - { - return ; - } - - if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SIMPLE)) - { - return; - } - - static LLCachedControl<bool> dont_load_textures(gSavedSettings,"TextureDisable"); - - if (dont_load_textures || LLAppViewer::getTextureFetch()->mDebugPause) // || !mDrawable->isVisible()) - { - return; - } - - mTextureUpdateTimer.reset(); - - F32 old_area = mPixelArea; - mPixelArea = 0.f; - - const S32 num_faces = mDrawable->getNumFaces(); - F32 min_vsize=999999999.f, max_vsize=0.f; - LLViewerCamera* camera = LLViewerCamera::getInstance(); - for (S32 i = 0; i < num_faces; i++) - { - LLFace* face = mDrawable->getFace(i); - const LLTextureEntry *te = face->getTextureEntry(); - LLViewerTexture *imagep = face->getTexture(); - if (!imagep || !te || - face->mExtents[0].equals3(face->mExtents[1])) - { - continue; - } - - F32 vsize; - F32 old_size = face->getVirtualSize(); - - if (isHUDAttachment()) - { - F32 area = (F32) camera->getScreenPixelArea(); - vsize = area; - imagep->setBoostLevel(LLViewerTexture::BOOST_HUD); - face->setPixelArea(area); // treat as full screen - face->setVirtualSize(vsize); - } - else - { - vsize = face->getTextureVirtualSize(); - } - - mPixelArea = llmax(mPixelArea, face->getPixelArea()); - - if (face->mTextureMatrix != NULL) - { - if ((vsize < MIN_TEX_ANIM_SIZE && old_size > MIN_TEX_ANIM_SIZE) || - (vsize > MIN_TEX_ANIM_SIZE && old_size < MIN_TEX_ANIM_SIZE)) - { - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD, FALSE); - } - } - - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA)) - { - if (vsize < min_vsize) min_vsize = vsize; - if (vsize > max_vsize) max_vsize = vsize; - } - else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY)) - { - LLViewerFetchedTexture* img = LLViewerTextureManager::staticCastToFetchedTexture(imagep) ; - if(img) - { - F32 pri = img->getDecodePriority(); - pri = llmax(pri, 0.0f); - if (pri < min_vsize) min_vsize = pri; - if (pri > max_vsize) max_vsize = pri; - } - } - else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_FACE_AREA)) - { - F32 pri = mPixelArea; - if (pri < min_vsize) min_vsize = pri; - if (pri > max_vsize) max_vsize = pri; - } - } - - if (isSculpted()) - { - LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT); - LLUUID id = sculpt_params->getSculptTexture(); - - updateSculptTexture(); - - - - if (mSculptTexture.notNull()) - { - mSculptTexture->setBoostLevel(llmax((S32)mSculptTexture->getBoostLevel(), - (S32)LLViewerTexture::BOOST_SCULPTED)); - mSculptTexture->setForSculpt() ; - - if(!mSculptTexture->isCachedRawImageReady()) - { - S32 lod = llmin(mLOD, 3); - F32 lodf = ((F32)(lod + 1.0f)/4.f); - F32 tex_size = lodf * LLViewerTexture::sMaxSculptRez ; - mSculptTexture->addTextureStats(2.f * tex_size * tex_size, FALSE); - - //if the sculpty very close to the view point, load first - { - LLVector3 lookAt = getPositionAgent() - camera->getOrigin(); - F32 dist = lookAt.normVec() ; - F32 cos_angle_to_view_dir = lookAt * camera->getXAxis() ; - mSculptTexture->setAdditionalDecodePriority(0.8f * LLFace::calcImportanceToCamera(cos_angle_to_view_dir, dist)) ; - } - } - - S32 texture_discard = mSculptTexture->getDiscardLevel(); //try to match the texture - S32 current_discard = getVolume() ? getVolume()->getSculptLevel() : -2 ; - - if (texture_discard >= 0 && //texture has some data available - (texture_discard < current_discard || //texture has more data than last rebuild - current_discard < 0)) //no previous rebuild - { - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, FALSE); - mSculptChanged = TRUE; - } - - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SCULPTED)) - { - setDebugText(llformat("T%d C%d V%d\n%dx%d", - texture_discard, current_discard, getVolume()->getSculptLevel(), - mSculptTexture->getHeight(), mSculptTexture->getWidth())); - } - } - - } - - if (getLightTextureID().notNull()) - { - LLLightImageParams* params = (LLLightImageParams*) getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE); - LLUUID id = params->getLightTexture(); - mLightTexture = LLViewerTextureManager::getFetchedTexture(id); - if (mLightTexture.notNull()) - { - F32 rad = getLightRadius(); - mLightTexture->addTextureStats(gPipeline.calcPixelArea(getPositionAgent(), - LLVector3(rad,rad,rad), - *camera)); - } - } - - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA)) - { - setDebugText(llformat("%.0f:%.0f", (F32) sqrt(min_vsize),(F32) sqrt(max_vsize))); - } - else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY)) - { - setDebugText(llformat("%.0f:%.0f", (F32) sqrt(min_vsize),(F32) sqrt(max_vsize))); - } - else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_FACE_AREA)) - { - setDebugText(llformat("%.0f:%.0f", (F32) sqrt(min_vsize),(F32) sqrt(max_vsize))); - } - - if (mPixelArea == 0) - { //flexi phasing issues make this happen - mPixelArea = old_area; - } -} - -BOOL LLVOVolume::isActive() const -{ - return !mStatic || mTextureAnimp || (mVolumeImpl && mVolumeImpl->isActive()) || - (mDrawable.notNull() && mDrawable->isActive()); -} - -BOOL LLVOVolume::setMaterial(const U8 material) -{ - BOOL res = LLViewerObject::setMaterial(material); - - return res; -} - -void LLVOVolume::setTexture(const S32 face) -{ - llassert(face < getNumTEs()); - gGL.getTexUnit(0)->bind(getTEImage(face)); -} - -void LLVOVolume::setScale(const LLVector3 &scale, BOOL damped) -{ - if (scale != getScale()) - { - // store local radius - LLViewerObject::setScale(scale); - - if (mVolumeImpl) - { - mVolumeImpl->onSetScale(scale, damped); - } - - updateRadius(); - - //since drawable transforms do not include scale, changing volume scale - //requires an immediate rebuild of volume verts. - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_POSITION, TRUE); - } -} - -LLFace* LLVOVolume::addFace(S32 f) -{ - const LLTextureEntry* te = getTE(f); - LLViewerTexture* imagep = getTEImage(f); - return mDrawable->addFace(te, imagep); -} - -LLDrawable *LLVOVolume::createDrawable(LLPipeline *pipeline) -{ - pipeline->allocDrawable(this); - - mDrawable->setRenderType(LLPipeline::RENDER_TYPE_VOLUME); - - S32 max_tes_to_set = getNumTEs(); - for (S32 i = 0; i < max_tes_to_set; i++) - { - addFace(i); - } - mNumFaces = max_tes_to_set; - - if (isAttachment()) - { - mDrawable->makeActive(); - } - - if (getIsLight()) - { - // Add it to the pipeline mLightSet - gPipeline.setLight(mDrawable, TRUE); - } - - updateRadius(); - bool force_update = true; // avoid non-alpha mDistance update being optimized away - mDrawable->updateDistance(*LLViewerCamera::getInstance(), force_update); - - return mDrawable; -} - -BOOL LLVOVolume::setVolume(const LLVolumeParams ¶ms_in, const S32 detail, bool unique_volume) -{ - LLVolumeParams volume_params = params_in; - - S32 last_lod = mVolumep.notNull() ? LLVolumeLODGroup::getVolumeDetailFromScale(mVolumep->getDetail()) : -1; - S32 lod = mLOD; - - BOOL is404 = FALSE; - - if (isSculpted()) - { - // if it's a mesh - if ((volume_params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH) - { //meshes might not have all LODs, get the force detail to best existing LOD - - LLUUID mesh_id = volume_params.getSculptID(); - - //profile and path params don't matter for meshes - volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); - - lod = gMeshRepo.getActualMeshLOD(volume_params, lod); - if (lod == -1) - { - is404 = TRUE; - lod = 0; - } - } - } - - // Check if we need to change implementations - bool is_flexible = (volume_params.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE); - if (is_flexible) - { - setParameterEntryInUse(LLNetworkData::PARAMS_FLEXIBLE, TRUE, false); - if (!mVolumeImpl) - { - LLFlexibleObjectData* data = (LLFlexibleObjectData*)getParameterEntry(LLNetworkData::PARAMS_FLEXIBLE); - mVolumeImpl = new LLVolumeImplFlexible(this, data); - } - } - else - { - // Mark the parameter not in use - setParameterEntryInUse(LLNetworkData::PARAMS_FLEXIBLE, FALSE, false); - if (mVolumeImpl) - { - delete mVolumeImpl; - mVolumeImpl = NULL; - if (mDrawable.notNull()) - { - // Undo the damage we did to this matrix - mDrawable->updateXform(FALSE); - } - } - } - - if (is404) - { - setIcon(LLViewerTextureManager::getFetchedTextureFromFile("icons/Inv_Mesh.png", TRUE, LLViewerTexture::BOOST_UI)); - //render prim proxy when mesh loading attempts give up - volume_params.setSculptID(LLUUID::null, LL_SCULPT_TYPE_NONE); - - } - - if ((LLPrimitive::setVolume(volume_params, lod, (mVolumeImpl && mVolumeImpl->isVolumeUnique()))) || mSculptChanged) - { - mFaceMappingChanged = TRUE; - - if (mVolumeImpl) - { - mVolumeImpl->onSetVolume(volume_params, mLOD); - } - - updateSculptTexture(); - - - if (isSculpted()) - { - updateSculptTexture(); - // if it's a mesh - if ((volume_params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH) - { - if (getVolume()->getNumVolumeFaces() == 0 || getVolume()->isTetrahedron()) - { - //load request not yet issued, request pipeline load this mesh - LLUUID asset_id = volume_params.getSculptID(); - S32 available_lod = gMeshRepo.loadMesh(this, volume_params, lod, last_lod); - if (available_lod != lod) - { - LLPrimitive::setVolume(volume_params, available_lod); - } - } - - } - else // otherwise is sculptie - { - if (mSculptTexture.notNull()) - { - sculpt(); - } - } - } - - return TRUE; - } - - return FALSE; -} - -void LLVOVolume::updateSculptTexture() -{ - LLPointer<LLViewerFetchedTexture> old_sculpt = mSculptTexture; - - if (isSculpted() && !isMesh()) - { - LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT); - LLUUID id = sculpt_params->getSculptTexture(); - if (id.notNull()) - { - mSculptTexture = LLViewerTextureManager::getFetchedTexture(id, TRUE, LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); - } - } - else - { - mSculptTexture = NULL; - } - - if (mSculptTexture != old_sculpt) - { - if (old_sculpt.notNull()) - { - old_sculpt->removeVolume(this); - } - if (mSculptTexture.notNull()) - { - mSculptTexture->addVolume(this); - } - } - -} - -void LLVOVolume::notifyMeshLoaded() -{ - mSculptChanged = TRUE; - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE); -} - -// sculpt replaces generate() for sculpted surfaces -void LLVOVolume::sculpt() -{ - if (mSculptTexture.notNull()) - { - U16 sculpt_height = 0; - U16 sculpt_width = 0; - S8 sculpt_components = 0; - const U8* sculpt_data = NULL; - - S32 discard_level = mSculptTexture->getDiscardLevel() ; - LLImageRaw* raw_image = mSculptTexture->getCachedRawImage() ; - - S32 max_discard = mSculptTexture->getMaxDiscardLevel(); - if (discard_level > max_discard) - discard_level = max_discard; // clamp to the best we can do - - S32 current_discard = getVolume()->getSculptLevel() ; - if(current_discard < -2) - { - llwarns << "WARNING!!: Current discard of sculpty at " << current_discard - << " is less than -2." << llendl; - - // corrupted volume... don't update the sculpty - return; - } - else if (current_discard > MAX_DISCARD_LEVEL) - { - llwarns << "WARNING!!: Current discard of sculpty at " << current_discard - << " is more than than allowed max of " << MAX_DISCARD_LEVEL << llendl; - - // corrupted volume... don't update the sculpty - return; - } - - if (current_discard == discard_level) // no work to do here - return; - - if(!raw_image) - { - llassert(discard_level < 0) ; - - sculpt_width = 0; - sculpt_height = 0; - sculpt_data = NULL ; - - if(LLViewerTextureManager::sTesterp) - { - LLViewerTextureManager::sTesterp->updateGrayTextureBinding(); - } - } - else - { - sculpt_height = raw_image->getHeight(); - sculpt_width = raw_image->getWidth(); - sculpt_components = raw_image->getComponents(); - - sculpt_data = raw_image->getData(); - - if(LLViewerTextureManager::sTesterp) - { - mSculptTexture->updateBindStatsForTester() ; - } - } - getVolume()->sculpt(sculpt_width, sculpt_height, sculpt_components, sculpt_data, discard_level); - - //notify rebuild any other VOVolumes that reference this sculpty volume - for (S32 i = 0; i < mSculptTexture->getNumVolumes(); ++i) - { - LLVOVolume* volume = (*(mSculptTexture->getVolumeList()))[i]; - if (volume != this && volume->getVolume() == getVolume()) - { - gPipeline.markRebuild(volume->mDrawable, LLDrawable::REBUILD_GEOMETRY, FALSE); - } - } - } -} - -S32 LLVOVolume::computeLODDetail(F32 distance, F32 radius) -{ - S32 cur_detail; - if (LLPipeline::sDynamicLOD) - { - // We've got LOD in the profile, and in the twist. Use radius. - F32 tan_angle = (LLVOVolume::sLODFactor*radius)/distance; - cur_detail = LLVolumeLODGroup::getDetailFromTan(llround(tan_angle, 0.01f)); - } - else - { - cur_detail = llclamp((S32) (sqrtf(radius)*LLVOVolume::sLODFactor*4.f), 0, 3); - } - return cur_detail; -} - -BOOL LLVOVolume::calcLOD() -{ - if (mDrawable.isNull()) - { - return FALSE; - } - - S32 cur_detail = 0; - - F32 radius; - F32 distance; - - if (mDrawable->isState(LLDrawable::RIGGED)) - { - LLVOAvatar* avatar = getAvatar(); - distance = avatar->mDrawable->mDistanceWRTCamera; - radius = avatar->getBinRadius(); - } - else - { - distance = mDrawable->mDistanceWRTCamera; - radius = getVolume()->mLODScaleBias.scaledVec(getScale()).length(); - } - - //hold onto unmodified distance for debugging - //F32 debug_distance = distance; - - distance *= sDistanceFactor; - - F32 rampDist = LLVOVolume::sLODFactor * 2; - - if (distance < rampDist) - { - // Boost LOD when you're REALLY close - distance *= 1.0f/rampDist; - distance *= distance; - distance *= rampDist; - } - - // DON'T Compensate for field of view changing on FOV zoom. - distance *= F_PI/3.f; - - cur_detail = computeLODDetail(llround(distance, 0.01f), - llround(radius, 0.01f)); - - - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_LOD_INFO)) - { - //setDebugText(llformat("%.2f:%.2f, %d", debug_distance, radius, cur_detail)); - - setDebugText(llformat("%d", mDrawable->getFace(0)->getTextureIndex())); - } - - if (cur_detail != mLOD) - { - mAppAngle = llround((F32) atan2( mDrawable->getRadius(), mDrawable->mDistanceWRTCamera) * RAD_TO_DEG, 0.01f); - mLOD = cur_detail; - return TRUE; - } - else - { - return FALSE; - } -} - -BOOL LLVOVolume::updateLOD() -{ - if (mDrawable.isNull()) - { - return FALSE; - } - - BOOL lod_changed = calcLOD(); - - if (lod_changed) - { - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, FALSE); - mLODChanged = TRUE; - } - else - { - F32 new_radius = getBinRadius(); - F32 old_radius = mDrawable->getBinRadius(); - if (new_radius < old_radius * 0.9f || new_radius > old_radius*1.1f) - { - gPipeline.markPartitionMove(mDrawable); - } - } - - lod_changed = lod_changed || LLViewerObject::updateLOD(); - - return lod_changed; -} - -BOOL LLVOVolume::setDrawableParent(LLDrawable* parentp) -{ - if (!LLViewerObject::setDrawableParent(parentp)) - { - // no change in drawable parent - return FALSE; - } - - if (!mDrawable->isRoot()) - { - // rebuild vertices in parent relative space - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE); - - if (mDrawable->isActive() && !parentp->isActive()) - { - parentp->makeActive(); - } - else if (mDrawable->isStatic() && parentp->isActive()) - { - mDrawable->makeActive(); - } - } - - return TRUE; -} - -void LLVOVolume::updateFaceFlags() -{ - for (S32 i = 0; i < getVolume()->getNumFaces(); i++) - { - LLFace *face = mDrawable->getFace(i); - if (!face) - { - return; - } - - BOOL fullbright = getTE(i)->getFullbright(); - face->clearState(LLFace::FULLBRIGHT | LLFace::HUD_RENDER | LLFace::LIGHT); - - if (fullbright || (mMaterial == LL_MCODE_LIGHT)) - { - face->setState(LLFace::FULLBRIGHT); - } - if (mDrawable->isLight()) - { - face->setState(LLFace::LIGHT); - } - if (isHUDAttachment()) - { - face->setState(LLFace::HUD_RENDER); - } - } -} - -BOOL LLVOVolume::setParent(LLViewerObject* parent) -{ - BOOL ret = FALSE ; - if (parent != getParent()) - { - ret = LLViewerObject::setParent(parent); - if (ret && mDrawable) - { - gPipeline.markMoved(mDrawable); - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE); - } - } - - return ret ; -} - -// NOTE: regenFaces() MUST be followed by genTriangles()! -void LLVOVolume::regenFaces() -{ - // remove existing faces - BOOL count_changed = mNumFaces != getNumTEs(); - - if (count_changed) - { - deleteFaces(); - // add new faces - mNumFaces = getNumTEs(); - } - - for (S32 i = 0; i < mNumFaces; i++) - { - LLFace* facep = count_changed ? addFace(i) : mDrawable->getFace(i); - facep->setTEOffset(i); - facep->setTexture(getTEImage(i)); - facep->setViewerObject(this); - - // If the face had media on it, this will have broken the link between the LLViewerMediaTexture and the face. - // Re-establish the link. - if((int)mMediaImplList.size() > i) - { - if(mMediaImplList[i]) - { - LLViewerMediaTexture* media_tex = LLViewerTextureManager::findMediaTexture(mMediaImplList[i]->getMediaTextureID()) ; - if(media_tex) - { - media_tex->addMediaToFace(facep) ; - } - } - } - } - - if (!count_changed) - { - updateFaceFlags(); - } -} - -BOOL LLVOVolume::genBBoxes(BOOL force_global) -{ - BOOL res = TRUE; - - LLVector4a min,max; - - min.clear(); - max.clear(); - - BOOL rebuild = mDrawable->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION | LLDrawable::REBUILD_RIGGED); - -// bool rigged = false; - LLVolume* volume = mRiggedVolume; - if (!volume) - { - volume = getVolume(); - } - - for (S32 i = 0; i < getVolume()->getNumVolumeFaces(); i++) - { - LLFace *face = mDrawable->getFace(i); - if (!face) - { - continue; - } - res &= face->genVolumeBBoxes(*volume, i, - mRelativeXform, mRelativeXformInvTrans, - (mVolumeImpl && mVolumeImpl->isVolumeGlobal()) || force_global); - - if (rebuild) - { - if (i == 0) - { - min = face->mExtents[0]; - max = face->mExtents[1]; - } - else - { - min.setMin(min, face->mExtents[0]); - max.setMax(max, face->mExtents[1]); - } - } - } - - if (rebuild) - { - mDrawable->setSpatialExtents(min,max); - min.add(max); - min.mul(0.5f); - mDrawable->setPositionGroup(min); - } - - updateRadius(); - mDrawable->movePartition(); - - return res; -} - -void LLVOVolume::preRebuild() -{ - if (mVolumeImpl != NULL) - { - mVolumeImpl->preRebuild(); - } -} - -void LLVOVolume::updateRelativeXform() -{ - if (mVolumeImpl) - { - mVolumeImpl->updateRelativeXform(); - return; - } - - LLDrawable* drawable = mDrawable; - - if (drawable->isState(LLDrawable::RIGGED) && mRiggedVolume.notNull()) - { //rigged volume (which is in agent space) is used for generating bounding boxes etc - //inverse of render matrix should go to partition space - mRelativeXform = getRenderMatrix(); - - F32* dst = (F32*) mRelativeXformInvTrans.mMatrix; - F32* src = (F32*) mRelativeXform.mMatrix; - dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; - dst[3] = src[4]; dst[4] = src[5]; dst[5] = src[6]; - dst[6] = src[8]; dst[7] = src[9]; dst[8] = src[10]; - - mRelativeXform.invert(); - mRelativeXformInvTrans.transpose(); - } - else if (drawable->isActive()) - { - // setup relative transforms - LLQuaternion delta_rot; - LLVector3 delta_pos, delta_scale; - - //matrix from local space to parent relative/global space - delta_rot = drawable->isSpatialRoot() ? LLQuaternion() : mDrawable->getRotation(); - delta_pos = drawable->isSpatialRoot() ? LLVector3(0,0,0) : mDrawable->getPosition(); - delta_scale = mDrawable->getScale(); - - // Vertex transform (4x4) - LLVector3 x_axis = LLVector3(delta_scale.mV[VX], 0.f, 0.f) * delta_rot; - LLVector3 y_axis = LLVector3(0.f, delta_scale.mV[VY], 0.f) * delta_rot; - LLVector3 z_axis = LLVector3(0.f, 0.f, delta_scale.mV[VZ]) * delta_rot; - - mRelativeXform.initRows(LLVector4(x_axis, 0.f), - LLVector4(y_axis, 0.f), - LLVector4(z_axis, 0.f), - LLVector4(delta_pos, 1.f)); - - - // compute inverse transpose for normals - // mRelativeXformInvTrans.setRows(x_axis, y_axis, z_axis); - // mRelativeXformInvTrans.invert(); - // mRelativeXformInvTrans.setRows(x_axis, y_axis, z_axis); - // grumble - invert is NOT a matrix invert, so we do it by hand: - - LLMatrix3 rot_inverse = LLMatrix3(~delta_rot); - - LLMatrix3 scale_inverse; - scale_inverse.setRows(LLVector3(1.0, 0.0, 0.0) / delta_scale.mV[VX], - LLVector3(0.0, 1.0, 0.0) / delta_scale.mV[VY], - LLVector3(0.0, 0.0, 1.0) / delta_scale.mV[VZ]); - - - mRelativeXformInvTrans = rot_inverse * scale_inverse; - - mRelativeXformInvTrans.transpose(); - } - else - { - LLVector3 pos = getPosition(); - LLVector3 scale = getScale(); - LLQuaternion rot = getRotation(); - - if (mParent) - { - pos *= mParent->getRotation(); - pos += mParent->getPosition(); - rot *= mParent->getRotation(); - } - - //LLViewerRegion* region = getRegion(); - //pos += region->getOriginAgent(); - - LLVector3 x_axis = LLVector3(scale.mV[VX], 0.f, 0.f) * rot; - LLVector3 y_axis = LLVector3(0.f, scale.mV[VY], 0.f) * rot; - LLVector3 z_axis = LLVector3(0.f, 0.f, scale.mV[VZ]) * rot; - - mRelativeXform.initRows(LLVector4(x_axis, 0.f), - LLVector4(y_axis, 0.f), - LLVector4(z_axis, 0.f), - LLVector4(pos, 1.f)); - - // compute inverse transpose for normals - LLMatrix3 rot_inverse = LLMatrix3(~rot); - - LLMatrix3 scale_inverse; - scale_inverse.setRows(LLVector3(1.0, 0.0, 0.0) / scale.mV[VX], - LLVector3(0.0, 1.0, 0.0) / scale.mV[VY], - LLVector3(0.0, 0.0, 1.0) / scale.mV[VZ]); - - - mRelativeXformInvTrans = rot_inverse * scale_inverse; - - mRelativeXformInvTrans.transpose(); - } -} - -static LLFastTimer::DeclareTimer FTM_GEN_FLEX("Generate Flexies"); -static LLFastTimer::DeclareTimer FTM_UPDATE_PRIMITIVES("Update Primitives"); -static LLFastTimer::DeclareTimer FTM_UPDATE_RIGGED_VOLUME("Update Rigged"); - -BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) -{ - LLFastTimer t(FTM_UPDATE_PRIMITIVES); - - if (mDrawable->isState(LLDrawable::REBUILD_RIGGED)) - { - { - LLFastTimer t(FTM_UPDATE_RIGGED_VOLUME); - updateRiggedVolume(); - } - genBBoxes(FALSE); - mDrawable->clearState(LLDrawable::REBUILD_RIGGED); - } - - if (mVolumeImpl != NULL) - { - BOOL res; - { - LLFastTimer t(FTM_GEN_FLEX); - res = mVolumeImpl->doUpdateGeometry(drawable); - } - updateFaceFlags(); - return res; - } - - dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1)); - - BOOL compiled = FALSE; - - updateRelativeXform(); - - if (mDrawable.isNull()) // Not sure why this is happening, but it is... - { - return TRUE; // No update to complete - } - - if (mVolumeChanged || mFaceMappingChanged ) - { - compiled = TRUE; - - if (mVolumeChanged) - { - LLFastTimer ftm(FTM_GEN_VOLUME); - LLVolumeParams volume_params = getVolume()->getParams(); - setVolume(volume_params, 0); - drawable->setState(LLDrawable::REBUILD_VOLUME); - } - - { - LLFastTimer t(FTM_GEN_TRIANGLES); - regenFaces(); - genBBoxes(FALSE); - } - } - else if ((mLODChanged) || (mSculptChanged)) - { - LLVolume *old_volumep, *new_volumep; - F32 old_lod, new_lod; - S32 old_num_faces, new_num_faces ; - - old_volumep = getVolume(); - old_lod = old_volumep->getDetail(); - old_num_faces = old_volumep->getNumFaces() ; - old_volumep = NULL ; - - { - LLFastTimer ftm(FTM_GEN_VOLUME); - LLVolumeParams volume_params = getVolume()->getParams(); - setVolume(volume_params, 0); - } - - new_volumep = getVolume(); - new_lod = new_volumep->getDetail(); - new_num_faces = new_volumep->getNumFaces() ; - new_volumep = NULL ; - - if ((new_lod != old_lod) || mSculptChanged) - { - compiled = TRUE; - sNumLODChanges += new_num_faces ; - - drawable->setState(LLDrawable::REBUILD_VOLUME); // for face->genVolumeTriangles() - - { - LLFastTimer t(FTM_GEN_TRIANGLES); - if (new_num_faces != old_num_faces) - { - regenFaces(); - } - genBBoxes(FALSE); - - if (mSculptChanged) - { //changes in sculpt maps can thrash an object bounding box without - //triggering a spatial group bounding box update -- force spatial group - //to update bounding boxes - LLSpatialGroup* group = mDrawable->getSpatialGroup(); - if (group) - { - group->unbound(); - } - } - } - } - } - // it has its own drawable (it's moved) or it has changed UVs or it has changed xforms from global<->local - else - { - compiled = TRUE; - // All it did was move or we changed the texture coordinate offset - LLFastTimer t(FTM_GEN_TRIANGLES); - genBBoxes(FALSE); - } - - // Update face flags - updateFaceFlags(); - - if(compiled) - { - LLPipeline::sCompiles++; - } - - mVolumeChanged = FALSE; - mLODChanged = FALSE; - mSculptChanged = FALSE; - mFaceMappingChanged = FALSE; - - return LLViewerObject::updateGeometry(drawable); -} - -void LLVOVolume::updateFaceSize(S32 idx) -{ - LLFace* facep = mDrawable->getFace(idx); - if (idx >= getVolume()->getNumVolumeFaces()) - { - facep->setSize(0,0, true); - } - else - { - const LLVolumeFace& vol_face = getVolume()->getVolumeFace(idx); - facep->setSize(vol_face.mNumVertices, vol_face.mNumIndices, - true); // <--- volume faces should be padded for 16-byte alignment - - } -} - -BOOL LLVOVolume::isRootEdit() const -{ - if (mParent && !((LLViewerObject*)mParent)->isAvatar()) - { - return FALSE; - } - return TRUE; -} - -//virtual -void LLVOVolume::setNumTEs(const U8 num_tes) -{ - const U8 old_num_tes = getNumTEs() ; - - if(old_num_tes && old_num_tes < num_tes) //new faces added - { - LLViewerObject::setNumTEs(num_tes) ; - - if(mMediaImplList.size() >= old_num_tes && mMediaImplList[old_num_tes -1].notNull())//duplicate the last media textures if exists. - { - mMediaImplList.resize(num_tes) ; - const LLTextureEntry* te = getTE(old_num_tes - 1) ; - for(U8 i = old_num_tes; i < num_tes ; i++) - { - setTE(i, *te) ; - mMediaImplList[i] = mMediaImplList[old_num_tes -1] ; - } - mMediaImplList[old_num_tes -1]->setUpdated(TRUE) ; - } - } - else if(old_num_tes > num_tes && mMediaImplList.size() > num_tes) //old faces removed - { - U8 end = mMediaImplList.size() ; - for(U8 i = num_tes; i < end ; i++) - { - removeMediaImpl(i) ; - } - mMediaImplList.resize(num_tes) ; - - LLViewerObject::setNumTEs(num_tes) ; - } - else - { - LLViewerObject::setNumTEs(num_tes) ; - } - - return ; -} - -void LLVOVolume::setTEImage(const U8 te, LLViewerTexture *imagep) -{ - BOOL changed = (mTEImages[te] != imagep); - LLViewerObject::setTEImage(te, imagep); - if (changed) - { - gPipeline.markTextured(mDrawable); - mFaceMappingChanged = TRUE; - } -} - -S32 LLVOVolume::setTETexture(const U8 te, const LLUUID &uuid) -{ - S32 res = LLViewerObject::setTETexture(te, uuid); - if (res) - { - gPipeline.markTextured(mDrawable); - mFaceMappingChanged = TRUE; - } - return res; -} - -S32 LLVOVolume::setTEColor(const U8 te, const LLColor3& color) -{ - return setTEColor(te, LLColor4(color)); -} - -S32 LLVOVolume::setTEColor(const U8 te, const LLColor4& color) -{ - S32 retval = 0; - const LLTextureEntry *tep = getTE(te); - if (!tep) - { - llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl; - } - else if (color != tep->getColor()) - { - if (color.mV[3] != tep->getColor().mV[3]) - { - gPipeline.markTextured(mDrawable); - } - retval = LLPrimitive::setTEColor(te, color); - if (mDrawable.notNull() && retval) - { - // These should only happen on updates which are not the initial update. - mDrawable->setState(LLDrawable::REBUILD_COLOR); - dirtyMesh(); - } - } - - return retval; -} - -S32 LLVOVolume::setTEBumpmap(const U8 te, const U8 bumpmap) -{ - S32 res = LLViewerObject::setTEBumpmap(te, bumpmap); - if (res) - { - gPipeline.markTextured(mDrawable); - mFaceMappingChanged = TRUE; - } - return res; -} - -S32 LLVOVolume::setTETexGen(const U8 te, const U8 texgen) -{ - S32 res = LLViewerObject::setTETexGen(te, texgen); - if (res) - { - gPipeline.markTextured(mDrawable); - mFaceMappingChanged = TRUE; - } - return res; -} - -S32 LLVOVolume::setTEMediaTexGen(const U8 te, const U8 media) -{ - S32 res = LLViewerObject::setTEMediaTexGen(te, media); - if (res) - { - gPipeline.markTextured(mDrawable); - mFaceMappingChanged = TRUE; - } - return res; -} - -S32 LLVOVolume::setTEShiny(const U8 te, const U8 shiny) -{ - S32 res = LLViewerObject::setTEShiny(te, shiny); - if (res) - { - gPipeline.markTextured(mDrawable); - mFaceMappingChanged = TRUE; - } - return res; -} - -S32 LLVOVolume::setTEFullbright(const U8 te, const U8 fullbright) -{ - S32 res = LLViewerObject::setTEFullbright(te, fullbright); - if (res) - { - gPipeline.markTextured(mDrawable); - mFaceMappingChanged = TRUE; - } - return res; -} - -S32 LLVOVolume::setTEBumpShinyFullbright(const U8 te, const U8 bump) -{ - S32 res = LLViewerObject::setTEBumpShinyFullbright(te, bump); - if (res) - { - gPipeline.markTextured(mDrawable); - mFaceMappingChanged = TRUE; - } - return res; -} - -S32 LLVOVolume::setTEMediaFlags(const U8 te, const U8 media_flags) -{ - S32 res = LLViewerObject::setTEMediaFlags(te, media_flags); - if (res) - { - gPipeline.markTextured(mDrawable); - mFaceMappingChanged = TRUE; - } - return res; -} - -S32 LLVOVolume::setTEGlow(const U8 te, const F32 glow) -{ - S32 res = LLViewerObject::setTEGlow(te, glow); - if (res) - { - gPipeline.markTextured(mDrawable); - mFaceMappingChanged = TRUE; - } - return res; -} - -S32 LLVOVolume::setTEScale(const U8 te, const F32 s, const F32 t) -{ - S32 res = LLViewerObject::setTEScale(te, s, t); - if (res) - { - gPipeline.markTextured(mDrawable); - mFaceMappingChanged = TRUE; - } - return res; -} - -S32 LLVOVolume::setTEScaleS(const U8 te, const F32 s) -{ - S32 res = LLViewerObject::setTEScaleS(te, s); - if (res) - { - gPipeline.markTextured(mDrawable); - mFaceMappingChanged = TRUE; - } - return res; -} - -S32 LLVOVolume::setTEScaleT(const U8 te, const F32 t) -{ - S32 res = LLViewerObject::setTEScaleT(te, t); - if (res) - { - gPipeline.markTextured(mDrawable); - mFaceMappingChanged = TRUE; - } - return res; -} - -void LLVOVolume::updateTEData() -{ - /*if (mDrawable.notNull()) - { - mFaceMappingChanged = TRUE; - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_MATERIAL, TRUE); - }*/ -} - -bool LLVOVolume::hasMedia() const -{ - bool result = false; - const U8 numTEs = getNumTEs(); - for (U8 i = 0; i < numTEs; i++) - { - const LLTextureEntry* te = getTE(i); - if(te->hasMedia()) - { - result = true; - break; - } - } - return result; -} - -LLVector3 LLVOVolume::getApproximateFaceNormal(U8 face_id) -{ - LLVolume* volume = getVolume(); - LLVector4a result; - result.clear(); - - LLVector3 ret; - - if (volume && face_id < volume->getNumVolumeFaces()) - { - const LLVolumeFace& face = volume->getVolumeFace(face_id); - for (S32 i = 0; i < (S32)face.mNumVertices; ++i) - { - result.add(face.mNormals[i]); - } - - LLVector3 ret(result.getF32ptr()); - ret = volumeDirectionToAgent(ret); - ret.normVec(); - } - - return ret; -} - -void LLVOVolume::requestMediaDataUpdate(bool isNew) -{ - if (sObjectMediaClient) - sObjectMediaClient->fetchMedia(new LLMediaDataClientObjectImpl(this, isNew)); -} - -bool LLVOVolume::isMediaDataBeingFetched() const -{ - // I know what I'm doing by const_casting this away: this is just - // a wrapper class that is only going to do a lookup. - return (sObjectMediaClient) ? sObjectMediaClient->isInQueue(new LLMediaDataClientObjectImpl(const_cast<LLVOVolume*>(this), false)) : false; -} - -void LLVOVolume::cleanUpMediaImpls() -{ - // Iterate through our TEs and remove any Impls that are no longer used - const U8 numTEs = getNumTEs(); - for (U8 i = 0; i < numTEs; i++) - { - const LLTextureEntry* te = getTE(i); - if( ! te->hasMedia()) - { - // Delete the media IMPL! - removeMediaImpl(i) ; - } - } -} - -void LLVOVolume::updateObjectMediaData(const LLSD &media_data_array, const std::string &media_version) -{ - // media_data_array is an array of media entry maps - // media_version is the version string in the response. - U32 fetched_version = LLTextureEntry::getVersionFromMediaVersionString(media_version); - - // Only update it if it is newer! - if ( (S32)fetched_version > mLastFetchedMediaVersion) - { - mLastFetchedMediaVersion = fetched_version; - //llinfos << "updating:" << this->getID() << " " << ll_pretty_print_sd(media_data_array) << llendl; - - LLSD::array_const_iterator iter = media_data_array.beginArray(); - LLSD::array_const_iterator end = media_data_array.endArray(); - U8 texture_index = 0; - for (; iter != end; ++iter, ++texture_index) - { - syncMediaData(texture_index, *iter, false/*merge*/, false/*ignore_agent*/); - } - } -} - -void LLVOVolume::syncMediaData(S32 texture_index, const LLSD &media_data, bool merge, bool ignore_agent) -{ - if(mDead) - { - // If the object has been marked dead, don't process media updates. - return; - } - - LLTextureEntry *te = getTE(texture_index); - if(!te) - { - return ; - } - - LL_DEBUGS("MediaOnAPrim") << "BEFORE: texture_index = " << texture_index - << " hasMedia = " << te->hasMedia() << " : " - << ((NULL == te->getMediaData()) ? "NULL MEDIA DATA" : ll_pretty_print_sd(te->getMediaData()->asLLSD())) << llendl; - - std::string previous_url; - LLMediaEntry* mep = te->getMediaData(); - if(mep) - { - // Save the "current url" from before the update so we can tell if - // it changes. - previous_url = mep->getCurrentURL(); - } - - if (merge) - { - te->mergeIntoMediaData(media_data); - } - else { - // XXX Question: what if the media data is undefined LLSD, but the - // update we got above said that we have media flags?? Here we clobber - // that, assuming the data from the service is more up-to-date. - te->updateMediaData(media_data); - } - - mep = te->getMediaData(); - if(mep) - { - bool update_from_self = false; - if (!ignore_agent) - { - LLUUID updating_agent = LLTextureEntry::getAgentIDFromMediaVersionString(getMediaURL()); - update_from_self = (updating_agent == gAgent.getID()); - } - viewer_media_t media_impl = LLViewerMedia::updateMediaImpl(mep, previous_url, update_from_self); - - addMediaImpl(media_impl, texture_index) ; - } - else - { - removeMediaImpl(texture_index); - } - - LL_DEBUGS("MediaOnAPrim") << "AFTER: texture_index = " << texture_index - << " hasMedia = " << te->hasMedia() << " : " - << ((NULL == te->getMediaData()) ? "NULL MEDIA DATA" : ll_pretty_print_sd(te->getMediaData()->asLLSD())) << llendl; -} - -void LLVOVolume::mediaNavigateBounceBack(U8 texture_index) -{ - // Find the media entry for this navigate - const LLMediaEntry* mep = NULL; - viewer_media_t impl = getMediaImpl(texture_index); - LLTextureEntry *te = getTE(texture_index); - if(te) - { - mep = te->getMediaData(); - } - - if (mep && impl) - { - std::string url = mep->getCurrentURL(); - // Look for a ":", if not there, assume "http://" - if (!url.empty() && std::string::npos == url.find(':')) - { - url = "http://" + url; - } - // If the url we're trying to "bounce back" to is either empty or not - // allowed by the whitelist, try the home url. If *that* doesn't work, - // set the media as failed and unload it - if (url.empty() || !mep->checkCandidateUrl(url)) - { - url = mep->getHomeURL(); - // Look for a ":", if not there, assume "http://" - if (!url.empty() && std::string::npos == url.find(':')) - { - url = "http://" + url; - } - } - if (url.empty() || !mep->checkCandidateUrl(url)) - { - // The url to navigate back to is not good, and we have nowhere else - // to go. - LL_WARNS("MediaOnAPrim") << "FAILED to bounce back URL \"" << url << "\" -- unloading impl" << LL_ENDL; - impl->setMediaFailed(true); - } - else { - // Okay, navigate now - LL_INFOS("MediaOnAPrim") << "bouncing back to URL: " << url << LL_ENDL; - impl->navigateTo(url, "", false, true); - } - } -} - -bool LLVOVolume::hasMediaPermission(const LLMediaEntry* media_entry, MediaPermType perm_type) -{ - // NOTE: This logic ALMOST duplicates the logic in the server (in particular, in llmediaservice.cpp). - if (NULL == media_entry ) return false; // XXX should we assert here? - - // The agent has permissions if: - // - world permissions are on, or - // - group permissions are on, and agent_id is in the group, or - // - agent permissions are on, and agent_id is the owner - - // *NOTE: We *used* to check for modify permissions here (i.e. permissions were - // granted if permModify() was true). However, this doesn't make sense in the - // viewer: we don't want to show controls or allow interaction if the author - // has deemed it so. See DEV-42115. - - U8 media_perms = (perm_type == MEDIA_PERM_INTERACT) ? media_entry->getPermsInteract() : media_entry->getPermsControl(); - - // World permissions - if (0 != (media_perms & LLMediaEntry::PERM_ANYONE)) - { - return true; - } - - // Group permissions - else if (0 != (media_perms & LLMediaEntry::PERM_GROUP)) - { - LLPermissions* obj_perm = LLSelectMgr::getInstance()->findObjectPermissions(this); - if (obj_perm && gAgent.isInGroup(obj_perm->getGroup())) - { - return true; - } - } - - // Owner permissions - else if (0 != (media_perms & LLMediaEntry::PERM_OWNER) && permYouOwner()) - { - return true; - } - - return false; - -} - -void LLVOVolume::mediaNavigated(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin, std::string new_location) -{ - bool block_navigation = false; - // FIXME: if/when we allow the same media impl to be used by multiple faces, the logic here will need to be fixed - // to deal with multiple face indices. - int face_index = getFaceIndexWithMediaImpl(impl, -1); - - // Find the media entry for this navigate - LLMediaEntry* mep = NULL; - LLTextureEntry *te = getTE(face_index); - if(te) - { - mep = te->getMediaData(); - } - - if(mep) - { - if(!mep->checkCandidateUrl(new_location)) - { - block_navigation = true; - } - if (!block_navigation && !hasMediaPermission(mep, MEDIA_PERM_INTERACT)) - { - block_navigation = true; - } - } - else - { - LL_WARNS("MediaOnAPrim") << "Couldn't find media entry!" << LL_ENDL; - } - - if(block_navigation) - { - LL_INFOS("MediaOnAPrim") << "blocking navigate to URI " << new_location << LL_ENDL; - - // "bounce back" to the current URL from the media entry - mediaNavigateBounceBack(face_index); - } - else if (sObjectMediaNavigateClient) - { - - LL_DEBUGS("MediaOnAPrim") << "broadcasting navigate with URI " << new_location << LL_ENDL; - - sObjectMediaNavigateClient->navigate(new LLMediaDataClientObjectImpl(this, false), face_index, new_location); - } -} - -void LLVOVolume::mediaEvent(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin, LLViewerMediaObserver::EMediaEvent event) -{ - switch(event) - { - - case LLViewerMediaObserver::MEDIA_EVENT_LOCATION_CHANGED: - { - switch(impl->getNavState()) - { - case LLViewerMediaImpl::MEDIANAVSTATE_FIRST_LOCATION_CHANGED: - { - // This is the first location changed event after the start of a non-server-directed nav. It may need to be broadcast or bounced back. - mediaNavigated(impl, plugin, plugin->getLocation()); - } - break; - - case LLViewerMediaImpl::MEDIANAVSTATE_FIRST_LOCATION_CHANGED_SPURIOUS: - // This navigate didn't change the current URL. - LL_DEBUGS("MediaOnAPrim") << " NOT broadcasting navigate (spurious)" << LL_ENDL; - break; - - case LLViewerMediaImpl::MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED: - // This is the first location changed event after the start of a server-directed nav. Don't broadcast it. - LL_INFOS("MediaOnAPrim") << " NOT broadcasting navigate (server-directed)" << LL_ENDL; - break; - - default: - // This is a subsequent location-changed due to a redirect. Don't broadcast. - LL_INFOS("MediaOnAPrim") << " NOT broadcasting navigate (redirect)" << LL_ENDL; - break; - } - } - break; - - case LLViewerMediaObserver::MEDIA_EVENT_NAVIGATE_COMPLETE: - { - switch(impl->getNavState()) - { - case LLViewerMediaImpl::MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED: - { - // This is the first location changed event after the start of a non-server-directed nav. It may need to be broadcast or bounced back. - mediaNavigated(impl, plugin, plugin->getNavigateURI()); - } - break; - - case LLViewerMediaImpl::MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED_SPURIOUS: - // This navigate didn't change the current URL. - LL_DEBUGS("MediaOnAPrim") << " NOT broadcasting navigate (spurious)" << LL_ENDL; - break; - - case LLViewerMediaImpl::MEDIANAVSTATE_SERVER_COMPLETE_BEFORE_LOCATION_CHANGED: - // This is the the navigate complete event from a server-directed nav. Don't broadcast it. - LL_INFOS("MediaOnAPrim") << " NOT broadcasting navigate (server-directed)" << LL_ENDL; - break; - - default: - // For all other states, the navigate should have been handled by LOCATION_CHANGED events already. - break; - } - } - break; - - default: - break; - } - -} - -void LLVOVolume::sendMediaDataUpdate() -{ - if (sObjectMediaClient) - sObjectMediaClient->updateMedia(new LLMediaDataClientObjectImpl(this, false)); -} - -void LLVOVolume::removeMediaImpl(S32 texture_index) -{ - if(mMediaImplList.size() <= (U32)texture_index || mMediaImplList[texture_index].isNull()) - { - return ; - } - - //make the face referencing to mMediaImplList[texture_index] to point back to the old texture. - if(mDrawable && texture_index < mDrawable->getNumFaces()) - { - LLFace* facep = mDrawable->getFace(texture_index) ; - if(facep) - { - LLViewerMediaTexture* media_tex = LLViewerTextureManager::findMediaTexture(mMediaImplList[texture_index]->getMediaTextureID()) ; - if(media_tex) - { - media_tex->removeMediaFromFace(facep) ; - } - } - } - - //check if some other face(s) of this object reference(s)to this media impl. - S32 i ; - S32 end = (S32)mMediaImplList.size() ; - for(i = 0; i < end ; i++) - { - if( i != texture_index && mMediaImplList[i] == mMediaImplList[texture_index]) - { - break ; - } - } - - if(i == end) //this object does not need this media impl. - { - mMediaImplList[texture_index]->removeObject(this) ; - } - - mMediaImplList[texture_index] = NULL ; - return ; -} - -void LLVOVolume::addMediaImpl(LLViewerMediaImpl* media_impl, S32 texture_index) -{ - if((S32)mMediaImplList.size() < texture_index + 1) - { - mMediaImplList.resize(texture_index + 1) ; - } - - if(mMediaImplList[texture_index].notNull()) - { - if(mMediaImplList[texture_index] == media_impl) - { - return ; - } - - removeMediaImpl(texture_index) ; - } - - mMediaImplList[texture_index] = media_impl; - media_impl->addObject(this) ; - - //add the face to show the media if it is in playing - if(mDrawable) - { - LLFace* facep = mDrawable->getFace(texture_index) ; - if(facep) - { - LLViewerMediaTexture* media_tex = LLViewerTextureManager::findMediaTexture(mMediaImplList[texture_index]->getMediaTextureID()) ; - if(media_tex) - { - media_tex->addMediaToFace(facep) ; - } - } - else //the face is not available now, start media on this face later. - { - media_impl->setUpdated(TRUE) ; - } - } - return ; -} - -viewer_media_t LLVOVolume::getMediaImpl(U8 face_id) const -{ - if(mMediaImplList.size() > face_id) - { - return mMediaImplList[face_id]; - } - return NULL; -} - -F64 LLVOVolume::getTotalMediaInterest() const -{ - // If this object is currently focused, this object has "high" interest - if (LLViewerMediaFocus::getInstance()->getFocusedObjectID() == getID()) - return F64_MAX; - - F64 interest = (F64)-1.0; // means not interested; - - // If this object is selected, this object has "high" interest, but since - // there can be more than one, we still add in calculated impl interest - // XXX Sadly, 'contains()' doesn't take a const :( - if (LLSelectMgr::getInstance()->getSelection()->contains(const_cast<LLVOVolume*>(this))) - interest = F64_MAX / 2.0; - - int i = 0; - const int end = getNumTEs(); - for ( ; i < end; ++i) - { - const viewer_media_t &impl = getMediaImpl(i); - if (!impl.isNull()) - { - if (interest == (F64)-1.0) interest = (F64)0.0; - interest += impl->getInterest(); - } - } - return interest; -} - -S32 LLVOVolume::getFaceIndexWithMediaImpl(const LLViewerMediaImpl* media_impl, S32 start_face_id) -{ - S32 end = (S32)mMediaImplList.size() ; - for(S32 face_id = start_face_id + 1; face_id < end; face_id++) - { - if(mMediaImplList[face_id] == media_impl) - { - return face_id ; - } - } - return -1 ; -} - -//---------------------------------------------------------------------------- - -void LLVOVolume::setLightTextureID(LLUUID id) -{ - if (id.notNull()) - { - if (!hasLightTexture()) - { - setParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE, TRUE, true); - } - LLLightImageParams* param_block = (LLLightImageParams*) getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE); - if (param_block && param_block->getLightTexture() != id) - { - param_block->setLightTexture(id); - parameterChanged(LLNetworkData::PARAMS_LIGHT_IMAGE, true); - } - } - else - { - if (hasLightTexture()) - { - setParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE, FALSE, true); - mLightTexture = NULL; - } - } -} - -void LLVOVolume::setSpotLightParams(LLVector3 params) -{ - LLLightImageParams* param_block = (LLLightImageParams*) getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE); - if (param_block && param_block->getParams() != params) - { - param_block->setParams(params); - parameterChanged(LLNetworkData::PARAMS_LIGHT_IMAGE, true); - } -} - -void LLVOVolume::setIsLight(BOOL is_light) -{ - if (is_light != getIsLight()) - { - if (is_light) - { - setParameterEntryInUse(LLNetworkData::PARAMS_LIGHT, TRUE, true); - } - else - { - setParameterEntryInUse(LLNetworkData::PARAMS_LIGHT, FALSE, true); - } - - if (is_light) - { - // Add it to the pipeline mLightSet - gPipeline.setLight(mDrawable, TRUE); - } - else - { - // Not a light. Remove it from the pipeline's light set. - gPipeline.setLight(mDrawable, FALSE); - } - } -} - -void LLVOVolume::setLightColor(const LLColor3& color) -{ - LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); - if (param_block) - { - if (param_block->getColor() != color) - { - param_block->setColor(LLColor4(color, param_block->getColor().mV[3])); - parameterChanged(LLNetworkData::PARAMS_LIGHT, true); - gPipeline.markTextured(mDrawable); - mFaceMappingChanged = TRUE; - } - } -} - -void LLVOVolume::setLightIntensity(F32 intensity) -{ - LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); - if (param_block) - { - if (param_block->getColor().mV[3] != intensity) - { - param_block->setColor(LLColor4(LLColor3(param_block->getColor()), intensity)); - parameterChanged(LLNetworkData::PARAMS_LIGHT, true); - } - } -} - -void LLVOVolume::setLightRadius(F32 radius) -{ - LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); - if (param_block) - { - if (param_block->getRadius() != radius) - { - param_block->setRadius(radius); - parameterChanged(LLNetworkData::PARAMS_LIGHT, true); - } - } -} - -void LLVOVolume::setLightFalloff(F32 falloff) -{ - LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); - if (param_block) - { - if (param_block->getFalloff() != falloff) - { - param_block->setFalloff(falloff); - parameterChanged(LLNetworkData::PARAMS_LIGHT, true); - } - } -} - -void LLVOVolume::setLightCutoff(F32 cutoff) -{ - LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); - if (param_block) - { - if (param_block->getCutoff() != cutoff) - { - param_block->setCutoff(cutoff); - parameterChanged(LLNetworkData::PARAMS_LIGHT, true); - } - } -} - -//---------------------------------------------------------------------------- - -BOOL LLVOVolume::getIsLight() const -{ - return getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT); -} - -LLColor3 LLVOVolume::getLightBaseColor() const -{ - const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); - if (param_block) - { - return LLColor3(param_block->getColor()); - } - else - { - return LLColor3(1,1,1); - } -} - -LLColor3 LLVOVolume::getLightColor() const -{ - const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); - if (param_block) - { - return LLColor3(param_block->getColor()) * param_block->getColor().mV[3]; - } - else - { - return LLColor3(1,1,1); - } -} - -LLUUID LLVOVolume::getLightTextureID() const -{ - if (getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE)) - { - const LLLightImageParams *param_block = (const LLLightImageParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE); - if (param_block) - { - return param_block->getLightTexture(); - } - } - - return LLUUID::null; -} - - -LLVector3 LLVOVolume::getSpotLightParams() const -{ - if (getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE)) - { - const LLLightImageParams *param_block = (const LLLightImageParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE); - if (param_block) - { - return param_block->getParams(); - } - } - - return LLVector3(); -} - -F32 LLVOVolume::getSpotLightPriority() const -{ - return mSpotLightPriority; -} - -void LLVOVolume::updateSpotLightPriority() -{ - LLVector3 pos = mDrawable->getPositionAgent(); - LLVector3 at(0,0,-1); - at *= getRenderRotation(); - - F32 r = getLightRadius()*0.5f; - - pos += at * r; - - at = LLViewerCamera::getInstance()->getAtAxis(); - - pos -= at * r; - - mSpotLightPriority = gPipeline.calcPixelArea(pos, LLVector3(r,r,r), *LLViewerCamera::getInstance()); - - if (mLightTexture.notNull()) - { - mLightTexture->addTextureStats(mSpotLightPriority); - mLightTexture->setBoostLevel(LLViewerTexture::BOOST_CLOUDS); - } -} - - -bool LLVOVolume::isLightSpotlight() const -{ - LLLightImageParams* params = (LLLightImageParams*) getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE); - if (params) - { - return params->isLightSpotlight(); - } - return false; -} - - -LLViewerTexture* LLVOVolume::getLightTexture() -{ - LLUUID id = getLightTextureID(); - - if (id.notNull()) - { - if (mLightTexture.isNull() || id != mLightTexture->getID()) - { - mLightTexture = LLViewerTextureManager::getFetchedTexture(id); - } - } - else - { - mLightTexture = NULL; - } - - return mLightTexture; -} - -F32 LLVOVolume::getLightIntensity() const -{ - const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); - if (param_block) - { - return param_block->getColor().mV[3]; - } - else - { - return 1.f; - } -} - -F32 LLVOVolume::getLightRadius() const -{ - const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); - if (param_block) - { - return param_block->getRadius(); - } - else - { - return 0.f; - } -} - -F32 LLVOVolume::getLightFalloff() const -{ - const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); - if (param_block) - { - return param_block->getFalloff(); - } - else - { - return 0.f; - } -} - -F32 LLVOVolume::getLightCutoff() const -{ - const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); - if (param_block) - { - return param_block->getCutoff(); - } - else - { - return 0.f; - } -} - -U32 LLVOVolume::getVolumeInterfaceID() const -{ - if (mVolumeImpl) - { - return mVolumeImpl->getID(); - } - - return 0; -} - -BOOL LLVOVolume::isFlexible() const -{ - if (getParameterEntryInUse(LLNetworkData::PARAMS_FLEXIBLE)) - { - LLVolume* volume = getVolume(); - if (volume && volume->getParams().getPathParams().getCurveType() != LL_PCODE_PATH_FLEXIBLE) - { - LLVolumeParams volume_params = getVolume()->getParams(); - U8 profile_and_hole = volume_params.getProfileParams().getCurveType(); - volume_params.setType(profile_and_hole, LL_PCODE_PATH_FLEXIBLE); - } - return TRUE; - } - else - { - return FALSE; - } -} - -BOOL LLVOVolume::isSculpted() const -{ - if (getParameterEntryInUse(LLNetworkData::PARAMS_SCULPT)) - { - return TRUE; - } - - return FALSE; -} - -BOOL LLVOVolume::isMesh() const -{ - if (isSculpted()) - { - LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT); - U8 sculpt_type = sculpt_params->getSculptType(); - - if ((sculpt_type & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH) - // mesh is a mesh - { - return TRUE; - } - } - - return FALSE; -} - -BOOL LLVOVolume::hasLightTexture() const -{ - if (getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE)) - { - return TRUE; - } - - return FALSE; -} - -BOOL LLVOVolume::isVolumeGlobal() const -{ - if (mVolumeImpl) - { - return mVolumeImpl->isVolumeGlobal() ? TRUE : FALSE; - } - else if (mRiggedVolume.notNull()) - { - return TRUE; - } - - return FALSE; -} - -BOOL LLVOVolume::canBeFlexible() const -{ - U8 path = getVolume()->getParams().getPathParams().getCurveType(); - return (path == LL_PCODE_PATH_FLEXIBLE || path == LL_PCODE_PATH_LINE); -} - -BOOL LLVOVolume::setIsFlexible(BOOL is_flexible) -{ - BOOL res = FALSE; - BOOL was_flexible = isFlexible(); - LLVolumeParams volume_params; - if (is_flexible) - { - if (!was_flexible) - { - volume_params = getVolume()->getParams(); - U8 profile_and_hole = volume_params.getProfileParams().getCurveType(); - volume_params.setType(profile_and_hole, LL_PCODE_PATH_FLEXIBLE); - res = TRUE; - setFlags(FLAGS_USE_PHYSICS, FALSE); - setFlags(FLAGS_PHANTOM, TRUE); - setParameterEntryInUse(LLNetworkData::PARAMS_FLEXIBLE, TRUE, true); - if (mDrawable) - { - mDrawable->makeActive(); - } - } - } - else - { - if (was_flexible) - { - volume_params = getVolume()->getParams(); - U8 profile_and_hole = volume_params.getProfileParams().getCurveType(); - volume_params.setType(profile_and_hole, LL_PCODE_PATH_LINE); - res = TRUE; - setFlags(FLAGS_PHANTOM, FALSE); - setParameterEntryInUse(LLNetworkData::PARAMS_FLEXIBLE, FALSE, true); - } - } - if (res) - { - res = setVolume(volume_params, 1); - if (res) - { - markForUpdate(TRUE); - } - } - return res; -} - -//---------------------------------------------------------------------------- - -void LLVOVolume::generateSilhouette(LLSelectNode* nodep, const LLVector3& view_point) -{ - LLVolume *volume = getVolume(); - - if (volume) - { - LLVector3 view_vector; - view_vector = view_point; - - //transform view vector into volume space - view_vector -= getRenderPosition(); - mDrawable->mDistanceWRTCamera = view_vector.length(); - LLQuaternion worldRot = getRenderRotation(); - view_vector = view_vector * ~worldRot; - if (!isVolumeGlobal()) - { - LLVector3 objScale = getScale(); - LLVector3 invObjScale(1.f / objScale.mV[VX], 1.f / objScale.mV[VY], 1.f / objScale.mV[VZ]); - view_vector.scaleVec(invObjScale); - } - - updateRelativeXform(); - LLMatrix4 trans_mat = mRelativeXform; - if (mDrawable->isStatic()) - { - trans_mat.translate(getRegion()->getOriginAgent()); - } - - volume->generateSilhouetteVertices(nodep->mSilhouetteVertices, nodep->mSilhouetteNormals, view_vector, trans_mat, mRelativeXformInvTrans, nodep->getTESelectMask()); - - nodep->mSilhouetteExists = TRUE; - } -} - -void LLVOVolume::deleteFaces() -{ - S32 face_count = mNumFaces; - if (mDrawable.notNull()) - { - mDrawable->deleteFaces(0, face_count); - } - - mNumFaces = 0; -} - -void LLVOVolume::updateRadius() -{ - if (mDrawable.isNull()) - { - return; - } - - mVObjRadius = getScale().length(); - mDrawable->setRadius(mVObjRadius); -} - - -BOOL LLVOVolume::isAttachment() const -{ - return mState != 0 ; -} - -BOOL LLVOVolume::isHUDAttachment() const -{ - // *NOTE: we assume hud attachment points are in defined range - // since this range is constant for backwards compatibility - // reasons this is probably a reasonable assumption to make - S32 attachment_id = ATTACHMENT_ID_FROM_STATE(mState); - return ( attachment_id >= 31 && attachment_id <= 38 ); -} - - -const LLMatrix4 LLVOVolume::getRenderMatrix() const -{ - if (mDrawable->isActive() && !mDrawable->isRoot()) - { - return mDrawable->getParent()->getWorldMatrix(); - } - return mDrawable->getWorldMatrix(); -} - -// Returns a base cost and adds textures to passed in set. -// total cost is returned value + 5 * size of the resulting set. -// Cannot include cost of textures, as they may be re-used in linked -// children, and cost should only be increased for unique textures -Nyx -U32 LLVOVolume::getRenderCost(std::set<LLUUID> &textures) const -{ - // base cost of each prim should be 10 points - static const U32 ARC_PRIM_COST = 10; - // per-prim costs - static const U32 ARC_INVISI_COST = 1; - static const U32 ARC_SHINY_COST = 1; - static const U32 ARC_GLOW_COST = 1; - static const U32 ARC_FLEXI_COST = 8; - static const U32 ARC_PARTICLE_COST = 16; - static const U32 ARC_BUMP_COST = 4; - - // per-face costs - static const U32 ARC_PLANAR_COST = 1; - static const U32 ARC_ANIM_TEX_COST = 4; - static const U32 ARC_ALPHA_COST = 4; - - U32 shame = ARC_PRIM_COST; - - U32 invisi = 0; - U32 shiny = 0; - U32 glow = 0; - U32 alpha = 0; - U32 flexi = 0; - U32 animtex = 0; - U32 particles = 0; - U32 scale = 0; - U32 bump = 0; - U32 planar = 0; - - if (isFlexible()) - { - flexi = 1; - } - if (isParticleSource()) - { - particles = 1; - } - - const LLVector3& sc = getScale(); - scale += (U32) sc.mV[0] + (U32) sc.mV[1] + (U32) sc.mV[2]; - - const LLDrawable* drawablep = mDrawable; - - if (isSculpted()) - { - const LLSculptParams *sculpt_params = (LLSculptParams *) getParameterEntry(LLNetworkData::PARAMS_SCULPT); - LLUUID sculpt_id = sculpt_params->getSculptTexture(); - textures.insert(sculpt_id); - } - - for (S32 i = 0; i < drawablep->getNumFaces(); ++i) - { - const LLFace* face = drawablep->getFace(i); - const LLTextureEntry* te = face->getTextureEntry(); - const LLViewerTexture* img = face->getTexture(); - - if (img) - { - textures.insert(img->getID()); - } - - if (face->getPoolType() == LLDrawPool::POOL_ALPHA) - { - alpha++; - } - else if (img && img->getPrimaryFormat() == GL_ALPHA) - { - invisi = 1; - } - - if (te) - { - if (te->getBumpmap()) - { - bump = 1; - } - if (te->getShiny()) - { - shiny = 1; - } - if (te->getGlow() > 0.f) - { - glow = 1; - } - if (face->mTextureMatrix != NULL) - { - animtex++; - } - if (te->getTexGen()) - { - planar++; - } - } - } - - - shame += invisi * ARC_INVISI_COST; - shame += shiny * ARC_SHINY_COST; - shame += glow * ARC_GLOW_COST; - shame += alpha * ARC_ALPHA_COST; - shame += flexi * ARC_FLEXI_COST; - shame += animtex * ARC_ANIM_TEX_COST; - shame += particles * ARC_PARTICLE_COST; - shame += bump * ARC_BUMP_COST; - shame += planar * ARC_PLANAR_COST; - shame += scale; - - LLViewerObject::const_child_list_t& child_list = getChildren(); - for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); - iter != child_list.end(); - ++iter) - { - const LLViewerObject* child_objectp = *iter; - const LLDrawable* child_drawablep = child_objectp->mDrawable; - if (child_drawablep) - { - const LLVOVolume* child_volumep = child_drawablep->getVOVolume(); - if (child_volumep) - { - shame += child_volumep->getRenderCost(textures); - } - } - } - - return shame; - -} - -F32 LLVOVolume::getStreamingCost(S32* bytes, S32* visible_bytes) -{ - F32 radius = getScale().length()*0.5f; - - if (isMesh()) - { - LLSD& header = gMeshRepo.getMeshHeader(getVolume()->getParams().getSculptID()); - - return LLMeshRepository::getStreamingCost(header, radius, bytes, visible_bytes, mLOD); - } - else - { - LLVolume* volume = getVolume(); - S32 counts[4]; - LLVolume::getLoDTriangleCounts(volume->getParams(), counts); - - LLSD header; - header["lowest_lod"]["size"] = counts[0] * 10; - header["low_lod"]["size"] = counts[1] * 10; - header["medium_lod"]["size"] = counts[2] * 10; - header["high_lod"]["size"] = counts[3] * 10; - - return LLMeshRepository::getStreamingCost(header, radius); - } -} - -U32 LLVOVolume::getTriangleCount() -{ - U32 count = 0; - LLVolume* volume = getVolume(); - if (volume) - { - count = volume->getNumTriangles(); - } - - return count; -} - -U32 LLVOVolume::getHighLODTriangleCount() -{ - U32 ret = 0; - - LLVolume* volume = getVolume(); - - if (!isSculpted()) - { - LLVolume* ref = LLPrimitive::getVolumeManager()->refVolume(volume->getParams(), 3); - ret = ref->getNumTriangles(); - LLPrimitive::getVolumeManager()->unrefVolume(ref); - } - else if (isMesh()) - { - LLVolume* ref = LLPrimitive::getVolumeManager()->refVolume(volume->getParams(), 3); - if (ref->isTetrahedron() || ref->getNumVolumeFaces() == 0) - { - gMeshRepo.loadMesh(this, volume->getParams(), LLModel::LOD_HIGH); - } - ret = ref->getNumTriangles(); - LLPrimitive::getVolumeManager()->unrefVolume(ref); - } - else - { //default sculpts have a constant number of triangles - ret = 31*2*31; //31 rows of 31 columns of quads for a 32x32 vertex patch - } - - return ret; -} - -//static -void LLVOVolume::preUpdateGeom() -{ - sNumLODChanges = 0; -} - -void LLVOVolume::parameterChanged(U16 param_type, bool local_origin) -{ - LLViewerObject::parameterChanged(param_type, local_origin); -} - -void LLVOVolume::parameterChanged(U16 param_type, LLNetworkData* data, BOOL in_use, bool local_origin) -{ - LLViewerObject::parameterChanged(param_type, data, in_use, local_origin); - if (mVolumeImpl) - { - mVolumeImpl->onParameterChanged(param_type, data, in_use, local_origin); - } - if (mDrawable.notNull()) - { - BOOL is_light = getIsLight(); - if (is_light != mDrawable->isState(LLDrawable::LIGHT)) - { - gPipeline.setLight(mDrawable, is_light); - } - } -} - -void LLVOVolume::setSelected(BOOL sel) -{ - LLViewerObject::setSelected(sel); - if (mDrawable.notNull()) - { - markForUpdate(TRUE); - } -} - -void LLVOVolume::updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) -{ -} - -F32 LLVOVolume::getBinRadius() -{ - F32 radius; - - F32 scale = 1.f; - - S32 size_factor = llmax(gSavedSettings.getS32("OctreeStaticObjectSizeFactor"), 1); - S32 attachment_size_factor = llmax(gSavedSettings.getS32("OctreeAttachmentSizeFactor"), 1); - LLVector3 distance_factor = gSavedSettings.getVector3("OctreeDistanceFactor"); - LLVector3 alpha_distance_factor = gSavedSettings.getVector3("OctreeAlphaDistanceFactor"); - const LLVector4a* ext = mDrawable->getSpatialExtents(); - - BOOL shrink_wrap = mDrawable->isAnimating(); - BOOL alpha_wrap = FALSE; - - if (!isHUDAttachment()) - { - for (S32 i = 0; i < mDrawable->getNumFaces(); i++) - { - LLFace* face = mDrawable->getFace(i); - if (face->getPoolType() == LLDrawPool::POOL_ALPHA && - !face->canRenderAsMask()) - { - alpha_wrap = TRUE; - break; - } - } - } - else - { - shrink_wrap = FALSE; - } - - if (alpha_wrap) - { - LLVector3 bounds = getScale(); - radius = llmin(bounds.mV[1], bounds.mV[2]); - radius = llmin(radius, bounds.mV[0]); - radius *= 0.5f; - radius *= 1.f+mDrawable->mDistanceWRTCamera*alpha_distance_factor[1]; - radius += mDrawable->mDistanceWRTCamera*alpha_distance_factor[0]; - } - else if (shrink_wrap) - { - LLVector4a rad; - rad.setSub(ext[1], ext[0]); - - radius = rad.getLength3().getF32()*0.5f; - } - else if (mDrawable->isStatic()) - { - radius = llmax((S32) mDrawable->getRadius(), 1)*size_factor; - radius *= 1.f + mDrawable->mDistanceWRTCamera * distance_factor[1]; - radius += mDrawable->mDistanceWRTCamera * distance_factor[0]; - } - else if (mDrawable->getVObj()->isAttachment()) - { - radius = llmax((S32) mDrawable->getRadius(),1)*attachment_size_factor; - } - else - { - radius = mDrawable->getRadius(); - radius *= 1.f + mDrawable->mDistanceWRTCamera * distance_factor[1]; - radius += mDrawable->mDistanceWRTCamera * distance_factor[0]; - } - - return llclamp(radius*scale, 0.5f, 256.f); -} - -const LLVector3 LLVOVolume::getPivotPositionAgent() const -{ - if (mVolumeImpl) - { - return mVolumeImpl->getPivotPosition(); - } - return LLViewerObject::getPivotPositionAgent(); -} - -void LLVOVolume::onShift(const LLVector4a &shift_vector) -{ - if (mVolumeImpl) - { - mVolumeImpl->onShift(shift_vector); - } - - updateRelativeXform(); -} - -const LLMatrix4& LLVOVolume::getWorldMatrix(LLXformMatrix* xform) const -{ - if (mVolumeImpl) - { - return mVolumeImpl->getWorldMatrix(xform); - } - return xform->getWorldMatrix(); -} - -LLVector3 LLVOVolume::agentPositionToVolume(const LLVector3& pos) const -{ - LLVector3 ret = pos - getRenderPosition(); - ret = ret * ~getRenderRotation(); - LLVector3 objScale = isVolumeGlobal() ? LLVector3(1,1,1) : getScale(); - LLVector3 invObjScale(1.f / objScale.mV[VX], 1.f / objScale.mV[VY], 1.f / objScale.mV[VZ]); - ret.scaleVec(invObjScale); - - return ret; -} - -LLVector3 LLVOVolume::agentDirectionToVolume(const LLVector3& dir) const -{ - LLVector3 ret = dir * ~getRenderRotation(); - - LLVector3 objScale = isVolumeGlobal() ? LLVector3(1,1,1) : getScale(); - ret.scaleVec(objScale); - - return ret; -} - -LLVector3 LLVOVolume::volumePositionToAgent(const LLVector3& dir) const -{ - LLVector3 ret = dir; - LLVector3 objScale = isVolumeGlobal() ? LLVector3(1,1,1) : getScale(); - ret.scaleVec(objScale); - ret = ret * getRenderRotation(); - ret += getRenderPosition(); - - return ret; -} - -LLVector3 LLVOVolume::volumeDirectionToAgent(const LLVector3& dir) const -{ - LLVector3 ret = dir; - LLVector3 objScale = isVolumeGlobal() ? LLVector3(1,1,1) : getScale(); - LLVector3 invObjScale(1.f / objScale.mV[VX], 1.f / objScale.mV[VY], 1.f / objScale.mV[VZ]); - ret.scaleVec(invObjScale); - ret = ret * getRenderRotation(); - - return ret; -} - - -BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, S32 face, BOOL pick_transparent, S32 *face_hitp, - LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal) - -{ - if (!mbCanSelect - || mDrawable->isDead() - || !gPipeline.hasRenderType(mDrawable->getRenderType())) - { - return FALSE; - } - - BOOL ret = FALSE; - - LLVolume* volume = getVolume(); - - bool transform = true; - - if (mDrawable->isState(LLDrawable::RIGGED)) - { - if (LLFloater::isVisible(gFloaterTools) && getAvatar()->isSelf()) - { - updateRiggedVolume(); - genBBoxes(FALSE); - volume = mRiggedVolume; - transform = false; - } - else - { //cannot pick rigged attachments on other avatars or when not in build mode - return FALSE; - } - } - - if (volume) - { - LLVector3 v_start, v_end, v_dir; - - if (transform) - { - v_start = agentPositionToVolume(start); - v_end = agentPositionToVolume(end); - } - else - { - v_start = start; - v_end = end; - } - - LLVector3 p; - LLVector3 n; - LLVector2 tc; - LLVector3 bn; - - if (intersection != NULL) - { - p = *intersection; - } - - if (tex_coord != NULL) - { - tc = *tex_coord; - } - - if (normal != NULL) - { - n = *normal; - } - - if (bi_normal != NULL) - { - bn = *bi_normal; - } - - S32 face_hit = -1; - - S32 start_face, end_face; - if (face == -1) - { - start_face = 0; - end_face = volume->getNumVolumeFaces(); - } - else - { - start_face = face; - end_face = face+1; - } - - bool special_cursor = specialHoverCursor(); - for (S32 i = start_face; i < end_face; ++i) - { - if (!special_cursor && !pick_transparent && getTE(i)->getColor().mV[3] == 0.f) - { //don't attempt to pick completely transparent faces unless - //pick_transparent is true - continue; - } - - face_hit = volume->lineSegmentIntersect(v_start, v_end, i, - &p, &tc, &n, &bn); - - if (face_hit >= 0 && mDrawable->getNumFaces() > face_hit) - { - LLFace* face = mDrawable->getFace(face_hit); - - if (pick_transparent || !face->getTexture() || !face->getTexture()->hasGLTexture() || face->getTexture()->getMask(face->surfaceToTexture(tc, p, n))) - { - v_end = p; - if (face_hitp != NULL) - { - *face_hitp = face_hit; - } - - if (intersection != NULL) - { - if (transform) - { - *intersection = volumePositionToAgent(p); // must map back to agent space - } - else - { - *intersection = p; - } - } - - if (normal != NULL) - { - if (transform) - { - *normal = volumeDirectionToAgent(n); - } - else - { - *normal = n; - } - - (*normal).normVec(); - } - - if (bi_normal != NULL) - { - if (transform) - { - *bi_normal = volumeDirectionToAgent(bn); - } - else - { - *bi_normal = bn; - } - (*bi_normal).normVec(); - } - - if (tex_coord != NULL) - { - *tex_coord = tc; - } - - ret = TRUE; - } - } - } - } - - return ret; -} - -bool LLVOVolume::treatAsRigged() -{ - return LLFloater::isVisible(gFloaterTools) && - isAttachment() && - getAvatar() && - getAvatar()->isSelf() && - mDrawable.notNull() && - mDrawable->isState(LLDrawable::RIGGED); -} - -LLRiggedVolume* LLVOVolume::getRiggedVolume() -{ - return mRiggedVolume; -} - -void LLVOVolume::clearRiggedVolume() -{ - if (mRiggedVolume.notNull()) - { - mRiggedVolume = NULL; - updateRelativeXform(); - } -} - -void LLVOVolume::updateRiggedVolume() -{ - //Update mRiggedVolume to match current animation frame of avatar. - //Also update position/size in octree. - - if (!treatAsRigged()) - { - clearRiggedVolume(); - - return; - } - - LLVolume* volume = getVolume(); - - const LLMeshSkinInfo* skin = gMeshRepo.getSkinInfo(volume->getParams().getSculptID(), this); - - if (!skin) - { - clearRiggedVolume(); - return; - } - - LLVOAvatar* avatar = getAvatar(); - - if (!avatar) - { - clearRiggedVolume(); - return; - } - - if (!mRiggedVolume) - { - LLVolumeParams p; - mRiggedVolume = new LLRiggedVolume(p); - updateRelativeXform(); - } - - mRiggedVolume->update(skin, avatar, volume); - -} - -static LLFastTimer::DeclareTimer FTM_SKIN_RIGGED("Skin"); -static LLFastTimer::DeclareTimer FTM_RIGGED_OCTREE("Octree"); - -void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, const LLVolume* volume) -{ - bool copy = false; - if (volume->getNumVolumeFaces() != getNumVolumeFaces()) - { - copy = true; - } - - for (S32 i = 0; i < volume->getNumVolumeFaces() && !copy; ++i) - { - const LLVolumeFace& src_face = volume->getVolumeFace(i); - const LLVolumeFace& dst_face = getVolumeFace(i); - - if (src_face.mNumIndices != dst_face.mNumIndices || - src_face.mNumVertices != dst_face.mNumVertices) - { - copy = true; - } - } - - if (copy) - { - copyVolumeFaces(volume); - } - - //build matrix palette - LLMatrix4a mp[64]; - LLMatrix4* mat = (LLMatrix4*) mp; - - for (U32 j = 0; j < skin->mJointNames.size(); ++j) - { - LLJoint* joint = avatar->getJoint(skin->mJointNames[j]); - if (joint) - { - mat[j] = skin->mInvBindMatrix[j]; - mat[j] *= joint->getWorldMatrix(); - } - } - - for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i) - { - const LLVolumeFace& vol_face = volume->getVolumeFace(i); - - LLVolumeFace& dst_face = mVolumeFaces[i]; - - LLVector4a* weight = vol_face.mWeights; - - LLMatrix4a bind_shape_matrix; - bind_shape_matrix.loadu(skin->mBindShapeMatrix); - - LLVector4a* pos = dst_face.mPositions; - - { - LLFastTimer t(FTM_SKIN_RIGGED); - - for (U32 j = 0; j < dst_face.mNumVertices; ++j) - { - LLMatrix4a final_mat; - final_mat.clear(); - - S32 idx[4]; - - LLVector4 wght; - - F32 scale = 0.f; - for (U32 k = 0; k < 4; k++) - { - F32 w = weight[j][k]; - - idx[k] = (S32) floorf(w); - wght[k] = w - floorf(w); - scale += wght[k]; - } - - wght *= 1.f/scale; - - for (U32 k = 0; k < 4; k++) - { - F32 w = wght[k]; - - LLMatrix4a src; - src.setMul(mp[idx[k]], w); - - final_mat.add(src); - } - - - LLVector4a& v = vol_face.mPositions[j]; - LLVector4a t; - LLVector4a dst; - bind_shape_matrix.affineTransform(v, t); - final_mat.affineTransform(t, dst); - pos[j] = dst; - } - - //update bounding box - LLVector4a& min = dst_face.mExtents[0]; - LLVector4a& max = dst_face.mExtents[1]; - - min = pos[0]; - max = pos[1]; - - for (U32 j = 1; j < dst_face.mNumVertices; ++j) - { - min.setMin(min, pos[j]); - max.setMax(max, pos[j]); - } - - dst_face.mCenter->setAdd(dst_face.mExtents[0], dst_face.mExtents[1]); - dst_face.mCenter->mul(0.5f); - - } - - { - LLFastTimer t(FTM_RIGGED_OCTREE); - delete dst_face.mOctree; - dst_face.mOctree = NULL; - - LLVector4a size; - size.setSub(dst_face.mExtents[1], dst_face.mExtents[0]); - size.splat(size.getLength3().getF32()*0.5f); - - dst_face.createOctree(1.f); - } - } -} - -U32 LLVOVolume::getPartitionType() const -{ - if (isHUDAttachment()) - { - return LLViewerRegion::PARTITION_HUD; - } - - return LLViewerRegion::PARTITION_VOLUME; -} - -LLVolumePartition::LLVolumePartition() -: LLSpatialPartition(LLVOVolume::VERTEX_DATA_MASK, TRUE, GL_DYNAMIC_DRAW_ARB) -{ - mLODPeriod = 32; - mDepthMask = FALSE; - mDrawableType = LLPipeline::RENDER_TYPE_VOLUME; - mPartitionType = LLViewerRegion::PARTITION_VOLUME; - mSlopRatio = 0.25f; - mBufferUsage = GL_DYNAMIC_DRAW_ARB; -} - -LLVolumeBridge::LLVolumeBridge(LLDrawable* drawablep) -: LLSpatialBridge(drawablep, TRUE, LLVOVolume::VERTEX_DATA_MASK) -{ - mDepthMask = FALSE; - mLODPeriod = 32; - mDrawableType = LLPipeline::RENDER_TYPE_VOLUME; - mPartitionType = LLViewerRegion::PARTITION_BRIDGE; - - mBufferUsage = GL_DYNAMIC_DRAW_ARB; - - mSlopRatio = 0.25f; -} - -bool can_batch_texture(LLFace* facep) -{ - if (facep->getTextureEntry()->getBumpmap()) - { //bump maps aren't worked into texture batching yet - return false; - } - - if (facep->getTexture() && facep->getTexture()->getPrimaryFormat() == GL_ALPHA) - { //can't batch invisiprims - return false; - } - - if (facep->isState(LLFace::TEXTURE_ANIM) && facep->getVirtualSize() > MIN_TEX_ANIM_SIZE) - { //texture animation breaks batches - return false; - } - - return true; -} - -void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, U32 type) -{ - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - - if (facep->getViewerObject()->isSelected() && LLSelectMgr::getInstance()->mHideSelectedObjects) - { - return; - } - - //add face to drawmap - LLSpatialGroup::drawmap_elem_t& draw_vec = group->mDrawMap[type]; - - S32 idx = draw_vec.size()-1; - - BOOL fullbright = (type == LLRenderPass::PASS_FULLBRIGHT) || - (type == LLRenderPass::PASS_INVISIBLE) || - (type == LLRenderPass::PASS_ALPHA && facep->isState(LLFace::FULLBRIGHT)); - - if (!fullbright && type != LLRenderPass::PASS_GLOW && !facep->getVertexBuffer()->hasDataType(LLVertexBuffer::TYPE_NORMAL)) - { - llwarns << "Non fullbright face has no normals!" << llendl; - return; - } - - const LLMatrix4* tex_mat = NULL; - if (facep->isState(LLFace::TEXTURE_ANIM) && facep->getVirtualSize() > MIN_TEX_ANIM_SIZE) - { - tex_mat = facep->mTextureMatrix; - } - - const LLMatrix4* model_mat = NULL; - - LLDrawable* drawable = facep->getDrawable(); - if (drawable->isActive()) - { - model_mat = &(drawable->getRenderMatrix()); - } - else - { - model_mat = &(drawable->getRegion()->mRenderMatrix); - if (model_mat->isIdentity()) - { - model_mat = NULL; - } - } - - U8 bump = (type == LLRenderPass::PASS_BUMP || type == LLRenderPass::PASS_POST_BUMP) ? facep->getTextureEntry()->getBumpmap() : 0; - - LLViewerTexture* tex = facep->getTexture(); - - U8 index = facep->getTextureIndex(); - - bool batchable = false; - - if (index < 255 && idx >= 0) - { - if (index < draw_vec[idx]->mTextureList.size()) - { - if (draw_vec[idx]->mTextureList[index].isNull()) - { - batchable = true; - draw_vec[idx]->mTextureList[index] = tex; - } - else if (draw_vec[idx]->mTextureList[index] == tex) - { //this face's texture index can be used with this batch - batchable = true; - } - } - else - { //texture list can be expanded to fit this texture index - batchable = true; - } - } - - U8 glow = (U8) (facep->getTextureEntry()->getGlow() * 255); - - if (idx >= 0 && - draw_vec[idx]->mVertexBuffer == facep->getVertexBuffer() && - draw_vec[idx]->mEnd == facep->getGeomIndex()-1 && - (LLPipeline::sTextureBindTest || draw_vec[idx]->mTexture == tex || batchable) && -#if LL_DARWIN - draw_vec[idx]->mEnd - draw_vec[idx]->mStart + facep->getGeomCount() <= (U32) gGLManager.mGLMaxVertexRange && - draw_vec[idx]->mCount + facep->getIndicesCount() <= (U32) gGLManager.mGLMaxIndexRange && -#endif - draw_vec[idx]->mGlowColor.mV[3] == glow && - draw_vec[idx]->mFullbright == fullbright && - draw_vec[idx]->mBump == bump && - draw_vec[idx]->mTextureMatrix == tex_mat && - draw_vec[idx]->mModelMatrix == model_mat) - { - draw_vec[idx]->mCount += facep->getIndicesCount(); - draw_vec[idx]->mEnd += facep->getGeomCount(); - draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, facep->getVirtualSize()); - - if (index >= draw_vec[idx]->mTextureList.size()) - { - draw_vec[idx]->mTextureList.resize(index+1); - draw_vec[idx]->mTextureList[index] = tex; - } - draw_vec[idx]->validate(); - update_min_max(draw_vec[idx]->mExtents[0], draw_vec[idx]->mExtents[1], facep->mExtents[0]); - update_min_max(draw_vec[idx]->mExtents[0], draw_vec[idx]->mExtents[1], facep->mExtents[1]); - } - else - { - U32 start = facep->getGeomIndex(); - U32 end = start + facep->getGeomCount()-1; - U32 offset = facep->getIndicesStart(); - U32 count = facep->getIndicesCount(); - LLPointer<LLDrawInfo> draw_info = new LLDrawInfo(start,end,count,offset, tex, - facep->getVertexBuffer(), fullbright, bump); - draw_info->mGroup = group; - draw_info->mVSize = facep->getVirtualSize(); - draw_vec.push_back(draw_info); - draw_info->mTextureMatrix = tex_mat; - draw_info->mModelMatrix = model_mat; - draw_info->mGlowColor.setVec(0,0,0,glow); - if (type == LLRenderPass::PASS_ALPHA) - { //for alpha sorting - facep->setDrawInfo(draw_info); - } - draw_info->mExtents[0] = facep->mExtents[0]; - draw_info->mExtents[1] = facep->mExtents[1]; - - if (LLPipeline::sUseTriStrips) - { - draw_info->mDrawMode = LLRender::TRIANGLE_STRIP; - } - - if (index < 255) - { //initialize texture list for texture batching - draw_info->mTextureList.resize(index+1); - draw_info->mTextureList[index] = tex; - } - draw_info->validate(); - } -} - -void LLVolumeGeometryManager::getGeometry(LLSpatialGroup* group) -{ - -} - -static LLFastTimer::DeclareTimer FTM_REBUILD_VOLUME_VB("Volume"); -static LLFastTimer::DeclareTimer FTM_REBUILD_VBO("VBO Rebuilt"); - -static LLDrawPoolAvatar* get_avatar_drawpool(LLViewerObject* vobj) -{ - LLVOAvatar* avatar = vobj->getAvatar(); - - if (avatar) - { - LLDrawable* drawable = avatar->mDrawable; - if (drawable && drawable->getNumFaces() > 0) - { - LLFace* face = drawable->getFace(0); - if (face) - { - LLDrawPool* drawpool = face->getPool(); - if (drawpool) - { - if (drawpool->getType() == LLDrawPool::POOL_AVATAR) - { - return (LLDrawPoolAvatar*) drawpool; - } - } - } - } - } - - return NULL; -} - -void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) -{ - if (group->changeLOD()) - { - group->mLastUpdateDistance = group->mDistance; - } - - group->mLastUpdateViewAngle = group->mViewAngle; - - if (!group->isState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::ALPHA_DIRTY)) - { - if (group->isState(LLSpatialGroup::MESH_DIRTY) && !LLPipeline::sDelayVBUpdate) - { - LLFastTimer ftm(FTM_REBUILD_VBO); - LLFastTimer ftm2(FTM_REBUILD_VOLUME_VB); - - rebuildMesh(group); - } - return; - } - - group->mBuilt = 1.f; - LLFastTimer ftm(FTM_REBUILD_VBO); - - LLFastTimer ftm2(FTM_REBUILD_VOLUME_VB); - - group->clearDrawMap(); - - mFaceList.clear(); - - std::vector<LLFace*> fullbright_faces; - std::vector<LLFace*> bump_faces; - std::vector<LLFace*> simple_faces; - - std::vector<LLFace*> alpha_faces; - U32 useage = group->mSpatialPartition->mBufferUsage; - - U32 max_vertices = (gSavedSettings.getS32("RenderMaxVBOSize")*1024)/LLVertexBuffer::calcVertexSize(group->mSpatialPartition->mVertexDataMask); - U32 max_total = (gSavedSettings.getS32("RenderMaxNodeSize")*1024)/LLVertexBuffer::calcVertexSize(group->mSpatialPartition->mVertexDataMask); - max_vertices = llmin(max_vertices, (U32) 65535); - - U32 cur_total = 0; - - //get all the faces into a list - for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter) - { - LLDrawable* drawablep = *drawable_iter; - - if (drawablep->isDead() || drawablep->isState(LLDrawable::FORCE_INVISIBLE) ) - { - continue; - } - - if (drawablep->isAnimating()) - { //fall back to stream draw for animating verts - useage = GL_STREAM_DRAW_ARB; - } - - LLVOVolume* vobj = drawablep->getVOVolume(); - - if (vobj->getVolume() && vobj->getVolume()->isTetrahedron() || (vobj->isMesh() && !gMeshRepo.meshRezEnabled())) - { - continue; - } - - llassert_always(vobj); - vobj->updateTextureVirtualSize(); - vobj->preRebuild(); - - drawablep->clearState(LLDrawable::HAS_ALPHA); - - bool rigged = vobj->isAttachment() && - vobj->isMesh() && - gMeshRepo.getSkinInfo(vobj->getVolume()->getParams().getSculptID(), vobj); - - bool bake_sunlight = LLPipeline::sBakeSunlight && drawablep->isStatic(); - - bool is_rigged = false; - - //for each face - for (S32 i = 0; i < drawablep->getNumFaces(); i++) - { - LLFace* facep = drawablep->getFace(i); - - //ALWAYS null out vertex buffer on rebuild -- if the face lands in a render - // batch, it will recover its vertex buffer reference from the spatial group - facep->setVertexBuffer(NULL); - - //sum up face verts and indices - drawablep->updateFaceSize(i); - - - - if (rigged) - { - if (!facep->isState(LLFace::RIGGED)) - { //completely reset vertex buffer - facep->clearVertexBuffer(); - } - - facep->setState(LLFace::RIGGED); - is_rigged = true; - - //get drawpool of avatar with rigged face - LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj); - - //Determine if we've received skininfo that contains an - //alternate bind matrix - if it does then apply the translational component - //to the joints of the avatar. - LLVOAvatar* pAvatarVO = vobj->getAvatar(); - bool pelvisGotSet = false; - - if ( pAvatarVO ) - { - LLUUID currentId = vobj->getVolume()->getParams().getSculptID(); - const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( currentId, vobj ); - - if ( pSkinData ) - { - const int bindCnt = pSkinData->mAlternateBindMatrix.size(); - if ( bindCnt > 0 ) - { - const int jointCnt = pSkinData->mJointNames.size(); - const F32 pelvisZOffset = pSkinData->mPelvisOffset; - bool fullRig = (jointCnt>=20) ? true : false; - if ( fullRig ) - { - for ( int i=0; i<jointCnt; ++i ) - { - std::string lookingForJoint = pSkinData->mJointNames[i].c_str(); - //llinfos<<"joint name "<<lookingForJoint.c_str()<<llendl; - LLJoint* pJoint = pAvatarVO->getJoint( lookingForJoint ); - if ( pJoint && pJoint->getId() != currentId ) - { - pJoint->setId( currentId ); - const LLVector3& jointPos = pSkinData->mAlternateBindMatrix[i].getTranslation(); - //Set the joint position - pJoint->storeCurrentXform( jointPos ); - //If joint is a pelvis then handle old/new pelvis to foot values - if ( lookingForJoint == "mPelvis" ) - { - pJoint->storeCurrentXform( jointPos ); - if ( !pAvatarVO->hasPelvisOffset() ) - { - pAvatarVO->setPelvisOffset( true, jointPos, pelvisZOffset ); - //Trigger to rebuild viewer AV - pelvisGotSet = true; - } - } - } - } - } - } - } - } - //If we've set the pelvis to a new position we need to also rebuild some information that the - //viewer does at launch (e.g. body size etc.) - if ( pelvisGotSet ) - { - pAvatarVO->postPelvisSetRecalc(); - } - - if (pool) - { - const LLTextureEntry* te = facep->getTextureEntry(); - - //remove face from old pool if it exists - LLDrawPool* old_pool = facep->getPool(); - if (old_pool && old_pool->getType() == LLDrawPool::POOL_AVATAR) - { - ((LLDrawPoolAvatar*) old_pool)->removeRiggedFace(facep); - } - - //add face to new pool - LLViewerTexture* tex = facep->getTexture(); - U32 type = gPipeline.getPoolTypeFromTE(te, tex); - - if (type == LLDrawPool::POOL_ALPHA) - { - if (te->getFullbright()) - { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA); - } - else - { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_ALPHA); - } - } - else if (te->getShiny()) - { - if (te->getFullbright()) - { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY); - } - else - { - if (LLPipeline::sRenderDeferred) - { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE); - } - else - { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SHINY); - } - } - } - else - { - if (te->getFullbright()) - { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT); - } - else - { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE); - } - } - - if (te->getGlow()) - { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_GLOW); - } - - if (LLPipeline::sRenderDeferred) - { - if (type != LLDrawPool::POOL_ALPHA && !te->getFullbright()) - { - if (te->getBumpmap()) - { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_BUMP); - } - else - { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_SIMPLE); - } - } - } - } - - continue; - } - else - { - if (facep->isState(LLFace::RIGGED)) - { //face is not rigged but used to be, remove from rigged face pool - LLDrawPoolAvatar* pool = (LLDrawPoolAvatar*) facep->getPool(); - if (pool) - { - pool->removeRiggedFace(facep); - } - facep->clearState(LLFace::RIGGED); - } - } - - if (cur_total > max_total || facep->getIndicesCount() <= 0 || facep->getGeomCount() <= 0) - { - facep->clearVertexBuffer(); - continue; - } - - cur_total += facep->getGeomCount(); - - if (facep->hasGeometry() && facep->getPixelArea() > FORCE_CULL_AREA) - { - const LLTextureEntry* te = facep->getTextureEntry(); - LLViewerTexture* tex = facep->getTexture(); - - if (facep->isState(LLFace::TEXTURE_ANIM)) - { - if (!vobj->mTexAnimMode) - { - facep->clearState(LLFace::TEXTURE_ANIM); - } - } - - BOOL force_simple = (facep->getPixelArea() < FORCE_SIMPLE_RENDER_AREA); - U32 type = gPipeline.getPoolTypeFromTE(te, tex); - if (type != LLDrawPool::POOL_ALPHA && force_simple) - { - type = LLDrawPool::POOL_SIMPLE; - } - facep->setPoolType(type); - - if (vobj->isHUDAttachment()) - { - facep->setState(LLFace::FULLBRIGHT); - } - - if (vobj->mTextureAnimp && vobj->mTexAnimMode) - { - if (vobj->mTextureAnimp->mFace <= -1) - { - S32 face; - for (face = 0; face < vobj->getNumTEs(); face++) - { - drawablep->getFace(face)->setState(LLFace::TEXTURE_ANIM); - } - } - else if (vobj->mTextureAnimp->mFace < vobj->getNumTEs()) - { - drawablep->getFace(vobj->mTextureAnimp->mFace)->setState(LLFace::TEXTURE_ANIM); - } - } - - if (type == LLDrawPool::POOL_ALPHA) - { - if (facep->canRenderAsMask()) - { //can be treated as alpha mask - simple_faces.push_back(facep); - } - else - { - drawablep->setState(LLDrawable::HAS_ALPHA); - alpha_faces.push_back(facep); - } - } - else - { - if (drawablep->isState(LLDrawable::REBUILD_VOLUME)) - { - facep->mLastUpdateTime = gFrameTimeSeconds; - } - - if (gPipeline.canUseWindLightShadersOnObjects() - && LLPipeline::sRenderBump) - { - if (te->getBumpmap()) - { //needs normal + binormal - bump_faces.push_back(facep); - } - else if (te->getShiny() || !te->getFullbright()) - { //needs normal - simple_faces.push_back(facep); - } - else - { //doesn't need normal - facep->setState(LLFace::FULLBRIGHT); - fullbright_faces.push_back(facep); - } - } - else - { - if (te->getBumpmap() && LLPipeline::sRenderBump) - { //needs normal + binormal - bump_faces.push_back(facep); - } - else if ((te->getShiny() && LLPipeline::sRenderBump) || - !(te->getFullbright() || bake_sunlight)) - { //needs normal - simple_faces.push_back(facep); - } - else - { //doesn't need normal - facep->setState(LLFace::FULLBRIGHT); - fullbright_faces.push_back(facep); - } - } - } - } - else - { //face has no renderable geometry - facep->clearVertexBuffer(); - } - } - - if (is_rigged) - { - drawablep->setState(LLDrawable::RIGGED); - } - else - { - drawablep->clearState(LLDrawable::RIGGED); - } - } - - group->mBufferUsage = useage; - - //PROCESS NON-ALPHA FACES - U32 simple_mask = LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR; - U32 alpha_mask = simple_mask | 0x80000000; //hack to give alpha verts their own VBO - U32 bump_mask = LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR; - U32 fullbright_mask = LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR; - - bool batch_textures = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 1; - - if (batch_textures) - { - bump_mask |= LLVertexBuffer::MAP_BINORMAL; - genDrawInfo(group, simple_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, simple_faces, FALSE, TRUE); - genDrawInfo(group, fullbright_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, fullbright_faces, FALSE, TRUE); - genDrawInfo(group, bump_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, bump_faces, FALSE, TRUE); - genDrawInfo(group, alpha_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, alpha_faces, TRUE, TRUE); - } - else - { - genDrawInfo(group, simple_mask, simple_faces); - genDrawInfo(group, fullbright_mask, fullbright_faces); - genDrawInfo(group, bump_mask, bump_faces, FALSE, TRUE); - genDrawInfo(group, alpha_mask, alpha_faces, TRUE); - } - - - if (!LLPipeline::sDelayVBUpdate) - { - //drawables have been rebuilt, clear rebuild status - for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter) - { - LLDrawable* drawablep = *drawable_iter; - drawablep->clearState(LLDrawable::REBUILD_ALL); - } - } - - group->mLastUpdateTime = gFrameTimeSeconds; - group->mBuilt = 1.f; - group->clearState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::ALPHA_DIRTY); - - if (LLPipeline::sDelayVBUpdate) - { - group->setState(LLSpatialGroup::MESH_DIRTY | LLSpatialGroup::NEW_DRAWINFO); - } - - mFaceList.clear(); -} - -static LLFastTimer::DeclareTimer FTM_VOLUME_GEOM("Volume Geometry"); -static LLFastTimer::DeclareTimer FTM_VOLUME_GEOM_PARTIAL("Terse Rebuild"); - -void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) -{ - llassert(group); - if (group && group->isState(LLSpatialGroup::MESH_DIRTY) && !group->isState(LLSpatialGroup::GEOM_DIRTY)) - { - LLFastTimer tm(FTM_VOLUME_GEOM); - S32 num_mapped_veretx_buffer = LLVertexBuffer::sMappedCount ; - - group->mBuilt = 1.f; - - std::set<LLVertexBuffer*> mapped_buffers; - - for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter) - { - LLFastTimer t(FTM_VOLUME_GEOM_PARTIAL); - LLDrawable* drawablep = *drawable_iter; - - if (!drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) ) - { - LLVOVolume* vobj = drawablep->getVOVolume(); - vobj->preRebuild(); - - LLVolume* volume = vobj->getVolume(); - for (S32 i = 0; i < drawablep->getNumFaces(); ++i) - { - LLFace* face = drawablep->getFace(i); - if (face) - { - LLVertexBuffer* buff = face->getVertexBuffer(); - if (buff) - { - face->getGeometryVolume(*volume, face->getTEOffset(), - vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), face->getGeomIndex()); - - if (buff->isLocked()) - { - mapped_buffers.insert(buff); - } - } - } - } - - drawablep->clearState(LLDrawable::REBUILD_ALL); - } - } - - for (std::set<LLVertexBuffer*>::iterator iter = mapped_buffers.begin(); iter != mapped_buffers.end(); ++iter) - { - (*iter)->setBuffer(0); - } - - // don't forget alpha - if(group != NULL && - !group->mVertexBuffer.isNull() && - group->mVertexBuffer->isLocked()) - { - group->mVertexBuffer->setBuffer(0); - } - - //if not all buffers are unmapped - if(num_mapped_veretx_buffer != LLVertexBuffer::sMappedCount) - { - llwarns << "Not all mapped vertex buffers are unmapped!" << llendl ; - for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter) - { - LLDrawable* drawablep = *drawable_iter; - for (S32 i = 0; i < drawablep->getNumFaces(); ++i) - { - LLFace* face = drawablep->getFace(i); - LLVertexBuffer* buff = face->getVertexBuffer(); - if (face && buff && buff->isLocked()) - { - buff->setBuffer(0) ; - } - } - } - } - - group->clearState(LLSpatialGroup::MESH_DIRTY | LLSpatialGroup::NEW_DRAWINFO); - } - - llassert(!group || !group->isState(LLSpatialGroup::NEW_DRAWINFO)); -} - -struct CompareBatchBreakerModified -{ - bool operator()(const LLFace* const& lhs, const LLFace* const& rhs) - { - const LLTextureEntry* lte = lhs->getTextureEntry(); - const LLTextureEntry* rte = rhs->getTextureEntry(); - - if (lte->getBumpmap() != rte->getBumpmap()) - { - return lte->getBumpmap() < rte->getBumpmap(); - } - else if (lte->getFullbright() != rte->getFullbright()) - { - return lte->getFullbright() < rte->getFullbright(); - } - else if (lte->getGlow() != rte->getGlow()) - { - return lte->getGlow() < rte->getGlow(); - } - else - { - return lhs->getTexture() < rhs->getTexture(); - } - - } -}; - -void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::vector<LLFace*>& faces, BOOL distance_sort, BOOL batch_textures) -{ - //calculate maximum number of vertices to store in a single buffer - U32 max_vertices = (gSavedSettings.getS32("RenderMaxVBOSize")*1024)/LLVertexBuffer::calcVertexSize(group->mSpatialPartition->mVertexDataMask); - max_vertices = llmin(max_vertices, (U32) 65535); - - if (!distance_sort) - { - //sort faces by things that break batches - std::sort(faces.begin(), faces.end(), CompareBatchBreakerModified()); - } - else - { - //sort faces by distance - std::sort(faces.begin(), faces.end(), LLFace::CompareDistanceGreater()); - } - - std::vector<LLFace*>::iterator face_iter = faces.begin(); - - LLSpatialGroup::buffer_map_t buffer_map; - - LLViewerTexture* last_tex = NULL; - S32 buffer_index = 0; - - if (distance_sort) - { - buffer_index = -1; - } - - S32 texture_index_channels = gGLManager.mNumTextureImageUnits-1; //always reserve one for shiny for now just for simplicity - - if (gGLManager.mGLVersion < 3.1f) - { - texture_index_channels = 1; - } - - if (LLPipeline::sRenderDeferred && distance_sort) - { - texture_index_channels = gDeferredAlphaProgram.mFeatures.mIndexedTextureChannels; - } - - texture_index_channels = llmin(texture_index_channels, (S32) gSavedSettings.getU32("RenderMaxTextureIndex")); - - - while (face_iter != faces.end()) - { - //pull off next face - LLFace* facep = *face_iter; - LLViewerTexture* tex = facep->getTexture(); - - if (distance_sort) - { - tex = NULL; - } - - if (last_tex == tex) - { - buffer_index++; - } - else - { - last_tex = tex; - buffer_index = 0; - } - - bool bake_sunlight = LLPipeline::sBakeSunlight && facep->getDrawable()->isStatic(); - - U32 index_count = facep->getIndicesCount(); - U32 geom_count = facep->getGeomCount(); - - //sum up vertices needed for this render batch - std::vector<LLFace*>::iterator i = face_iter; - ++i; - - std::vector<LLViewerTexture*> texture_list; - - if (batch_textures) - { - U8 cur_tex = 0; - facep->setTextureIndex(cur_tex); - texture_list.push_back(tex); - - //if (can_batch_texture(facep)) - { - while (i != faces.end()) - { - facep = *i; - if (facep->getTexture() != tex) - { - if (distance_sort) - { //textures might be out of order, see if texture exists in current batch - bool found = false; - for (U32 tex_idx = 0; tex_idx < texture_list.size(); ++tex_idx) - { - if (facep->getTexture() == texture_list[tex_idx]) - { - cur_tex = tex_idx; - found = true; - break; - } - } - - if (!found) - { - cur_tex = texture_list.size(); - } - } - else - { - cur_tex++; - } - - if (!can_batch_texture(facep)) - { //face is bump mapped or has an animated texture matrix -- can't - //batch more than 1 texture at a time - break; - } - - if (cur_tex >= texture_index_channels) - { //cut batches when index channels are depleted - break; - } - - tex = facep->getTexture(); - - texture_list.push_back(tex); - } - - if (geom_count + facep->getGeomCount() > max_vertices) - { //cut batches on geom count too big - break; - } - - ++i; - index_count += facep->getIndicesCount(); - geom_count += facep->getGeomCount(); - - facep->setTextureIndex(cur_tex); - } - } - - tex = texture_list[0]; - } - else - { - while (i != faces.end() && - (LLPipeline::sTextureBindTest || (distance_sort || (*i)->getTexture() == tex))) - { - facep = *i; - - - //face has no texture index - facep->mDrawInfo = NULL; - facep->setTextureIndex(255); - - if (geom_count + facep->getGeomCount() > max_vertices) - { //cut batches on geom count too big - break; - } - - ++i; - index_count += facep->getIndicesCount(); - geom_count += facep->getGeomCount(); - } - } - - //create/delete/resize vertex buffer if needed - LLVertexBuffer* buffer = NULL; - LLSpatialGroup::buffer_texture_map_t::iterator found_iter = group->mBufferMap[mask].find(*face_iter); - - if (found_iter != group->mBufferMap[mask].end()) - { - if ((U32) buffer_index < found_iter->second.size()) - { - buffer = found_iter->second[buffer_index]; - } - } - - if (!buffer) - { //create new buffer if needed - buffer = createVertexBuffer(mask, - group->mBufferUsage); - buffer->allocateBuffer(geom_count, index_count, TRUE); - } - else - { //resize pre-existing buffer - if (LLVertexBuffer::sEnableVBOs && buffer->getUsage() != group->mBufferUsage || - buffer->getTypeMask() != mask) - { - buffer = createVertexBuffer(mask, - group->mBufferUsage); - buffer->allocateBuffer(geom_count, index_count, TRUE); - } - else - { - buffer->resizeBuffer(geom_count, index_count); - } - } - - buffer_map[mask][*face_iter].push_back(buffer); - - //add face geometry - - U32 indices_index = 0; - U16 index_offset = 0; - - while (face_iter < i) - { //update face indices for new buffer - facep = *face_iter; - facep->setIndicesIndex(indices_index); - facep->setGeomIndex(index_offset); - facep->setVertexBuffer(buffer); - - if (batch_textures && facep->getTextureIndex() == 255) - { - llerrs << "Invalid texture index." << llendl; - } - - { - //for debugging, set last time face was updated vs moved - facep->updateRebuildFlags(); - - if (!LLPipeline::sDelayVBUpdate) - { //copy face geometry into vertex buffer - LLDrawable* drawablep = facep->getDrawable(); - LLVOVolume* vobj = drawablep->getVOVolume(); - LLVolume* volume = vobj->getVolume(); - - U32 te_idx = facep->getTEOffset(); - - facep->getGeometryVolume(*volume, te_idx, - vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), index_offset); - } - } - - index_offset += facep->getGeomCount(); - indices_index += facep->getIndicesCount(); - - - //append face to appropriate render batch - - BOOL force_simple = facep->getPixelArea() < FORCE_SIMPLE_RENDER_AREA; - BOOL fullbright = facep->isState(LLFace::FULLBRIGHT); - if ((mask & LLVertexBuffer::MAP_NORMAL) == 0) - { //paranoia check to make sure GL doesn't try to read non-existant normals - fullbright = TRUE; - } - - const LLTextureEntry* te = facep->getTextureEntry(); - tex = facep->getTexture(); - - BOOL is_alpha = (facep->getPoolType() == LLDrawPool::POOL_ALPHA) ? TRUE : FALSE; - - if (is_alpha) - { - // can we safely treat this as an alpha mask? - if (facep->canRenderAsMask()) - { - if (te->getFullbright() || LLPipeline::sNoAlpha) - { - registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK); - } - else - { - registerFace(group, facep, LLRenderPass::PASS_ALPHA_MASK); - } - } - else - { - registerFace(group, facep, LLRenderPass::PASS_ALPHA); - } - - if (LLPipeline::sRenderDeferred) - { - registerFace(group, facep, LLRenderPass::PASS_ALPHA_SHADOW); - } - } - else if (gPipeline.canUseVertexShaders() - && group->mSpatialPartition->mPartitionType != LLViewerRegion::PARTITION_HUD - && LLPipeline::sRenderBump - && te->getShiny()) - { //shiny - if (tex->getPrimaryFormat() == GL_ALPHA) - { //invisiprim+shiny - registerFace(group, facep, LLRenderPass::PASS_INVISI_SHINY); - registerFace(group, facep, LLRenderPass::PASS_INVISIBLE); - } - else if (LLPipeline::sRenderDeferred) - { //deferred rendering - if (te->getFullbright()) - { //register in post deferred fullbright shiny pass - registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT_SHINY); - if (te->getBumpmap()) - { //register in post deferred bump pass - registerFace(group, facep, LLRenderPass::PASS_POST_BUMP); - } - } - else if (te->getBumpmap()) - { //register in deferred bump pass - registerFace(group, facep, LLRenderPass::PASS_BUMP); - } - else - { //register in deferred simple pass (deferred simple includes shiny) - llassert(mask & LLVertexBuffer::MAP_NORMAL); - registerFace(group, facep, LLRenderPass::PASS_SIMPLE); - } - } - else if (fullbright) - { //not deferred, register in standard fullbright shiny pass - registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT_SHINY); - } - else - { //not deferred or fullbright, register in standard shiny pass - registerFace(group, facep, LLRenderPass::PASS_SHINY); - } - } - else - { //not alpha and not shiny - if (!is_alpha && tex->getPrimaryFormat() == GL_ALPHA) - { //invisiprim - registerFace(group, facep, LLRenderPass::PASS_INVISIBLE); - } - else if (fullbright || bake_sunlight) - { //fullbright - registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT); - if (LLPipeline::sRenderDeferred && LLPipeline::sRenderBump && te->getBumpmap()) - { //if this is the deferred render and a bump map is present, register in post deferred bump - registerFace(group, facep, LLRenderPass::PASS_POST_BUMP); - } - } - else - { - if (LLPipeline::sRenderDeferred && LLPipeline::sRenderBump && te->getBumpmap()) - { //non-shiny or fullbright deferred bump - registerFace(group, facep, LLRenderPass::PASS_BUMP); - } - else - { //all around simple - llassert(mask & LLVertexBuffer::MAP_NORMAL); - registerFace(group, facep, LLRenderPass::PASS_SIMPLE); - } - } - - //not sure why this is here -- shiny HUD attachments maybe? -- davep 5/11/2010 - if (!is_alpha && te->getShiny() && LLPipeline::sRenderBump) - { - registerFace(group, facep, LLRenderPass::PASS_SHINY); - } - } - - //not sure why this is here, and looks like it might cause bump mapped objects to get rendered redundantly -- davep 5/11/2010 - if (!is_alpha && !LLPipeline::sRenderDeferred) - { - llassert((mask & LLVertexBuffer::MAP_NORMAL) || fullbright); - facep->setPoolType((fullbright) ? LLDrawPool::POOL_FULLBRIGHT : LLDrawPool::POOL_SIMPLE); - - if (!force_simple && te->getBumpmap() && LLPipeline::sRenderBump) - { - registerFace(group, facep, LLRenderPass::PASS_BUMP); - } - } - - if (!is_alpha && LLPipeline::sRenderGlow && te->getGlow() > 0.f) - { - registerFace(group, facep, LLRenderPass::PASS_GLOW); - } - - ++face_iter; - } - - buffer->setBuffer(0); - } - - group->mBufferMap[mask].clear(); - for (LLSpatialGroup::buffer_texture_map_t::iterator i = buffer_map[mask].begin(); i != buffer_map[mask].end(); ++i) - { - group->mBufferMap[mask][i->first] = i->second; - } -} - -void LLGeometryManager::addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32 &index_count) -{ - //initialize to default usage for this partition - U32 usage = group->mSpatialPartition->mBufferUsage; - - //clear off any old faces - mFaceList.clear(); - - //for each drawable - for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter) - { - LLDrawable* drawablep = *drawable_iter; - - if (drawablep->isDead()) - { - continue; - } - - if (drawablep->isAnimating()) - { //fall back to stream draw for animating verts - usage = GL_STREAM_DRAW_ARB; - } - - //for each face - for (S32 i = 0; i < drawablep->getNumFaces(); i++) - { - //sum up face verts and indices - drawablep->updateFaceSize(i); - LLFace* facep = drawablep->getFace(i); - if (facep->hasGeometry() && facep->getPixelArea() > FORCE_CULL_AREA) - { - vertex_count += facep->getGeomCount(); - index_count += facep->getIndicesCount(); - llassert(facep->getIndicesCount() < 65536); - //remember face (for sorting) - mFaceList.push_back(facep); - } - else - { - facep->clearVertexBuffer(); - } - } - } - - group->mBufferUsage = usage; -} - -LLHUDPartition::LLHUDPartition() -{ - mPartitionType = LLViewerRegion::PARTITION_HUD; - mDrawableType = LLPipeline::RENDER_TYPE_HUD; - mSlopRatio = 0.f; - mLODPeriod = 1; -} - -void LLHUDPartition::shift(const LLVector4a &offset) -{ - //HUD objects don't shift with region crossing. That would be silly. -} - - +/**
+ * @file llvovolume.cpp
+ * @brief LLVOVolume class implementation
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+// A "volume" is a box, cylinder, sphere, or other primitive shape.
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llvovolume.h"
+
+#include <sstream>
+
+#include "llviewercontrol.h"
+#include "lldir.h"
+#include "llflexibleobject.h"
+#include "llfloatertools.h"
+#include "llmaterialtable.h"
+#include "llprimitive.h"
+#include "llvolume.h"
+#include "llvolumeoctree.h"
+#include "llvolumemgr.h"
+#include "llvolumemessage.h"
+#include "material_codes.h"
+#include "message.h"
+#include "llpluginclassmedia.h" // for code in the mediaEvent handler
+#include "object_flags.h"
+#include "llagentconstants.h"
+#include "lldrawable.h"
+#include "lldrawpoolavatar.h"
+#include "lldrawpoolbump.h"
+#include "llface.h"
+#include "llspatialpartition.h"
+#include "llhudmanager.h"
+#include "llflexibleobject.h"
+#include "llsky.h"
+#include "lltexturefetch.h"
+#include "llvector4a.h"
+#include "llviewercamera.h"
+#include "llviewertexturelist.h"
+#include "llviewerobjectlist.h"
+#include "llviewerregion.h"
+#include "llviewertextureanim.h"
+#include "llworld.h"
+#include "llselectmgr.h"
+#include "pipeline.h"
+#include "llsdutil.h"
+#include "llmatrix4a.h"
+#include "llmediaentry.h"
+#include "llmediadataclient.h"
+#include "llmeshrepository.h"
+#include "llagent.h"
+#include "llviewermediafocus.h"
+#include "lldatapacker.h"
+#include "llviewershadermgr.h"
+#include "llvoavatar.h"
+#include "llvocache.h"
+
+const S32 MIN_QUIET_FRAMES_COALESCE = 30;
+const F32 FORCE_SIMPLE_RENDER_AREA = 512.f;
+const F32 FORCE_CULL_AREA = 8.f;
+const F32 MAX_LOD_DISTANCE = 24.f;
+
+
+BOOL gAnimateTextures = TRUE;
+//extern BOOL gHideSelectedObjects;
+
+F32 LLVOVolume::sLODFactor = 1.f;
+F32 LLVOVolume::sLODSlopDistanceFactor = 0.5f; //Changing this to zero, effectively disables the LOD transition slop
+F32 LLVOVolume::sDistanceFactor = 1.0f;
+S32 LLVOVolume::sNumLODChanges = 0;
+S32 LLVOVolume::mRenderComplexity_last = 0;
+S32 LLVOVolume::mRenderComplexity_current = 0;
+LLPointer<LLObjectMediaDataClient> LLVOVolume::sObjectMediaClient = NULL;
+LLPointer<LLObjectMediaNavigateClient> LLVOVolume::sObjectMediaNavigateClient = NULL;
+
+static LLFastTimer::DeclareTimer FTM_GEN_TRIANGLES("Generate Triangles");
+static LLFastTimer::DeclareTimer FTM_GEN_VOLUME("Generate Volumes");
+static LLFastTimer::DeclareTimer FTM_VOLUME_TEXTURES("Volume Textures");
+
+// Implementation class of LLMediaDataClientObject. See llmediadataclient.h
+class LLMediaDataClientObjectImpl : public LLMediaDataClientObject
+{
+public:
+ LLMediaDataClientObjectImpl(LLVOVolume *obj, bool isNew) : mObject(obj), mNew(isNew)
+ {
+ mObject->addMDCImpl();
+ }
+ ~LLMediaDataClientObjectImpl()
+ {
+ mObject->removeMDCImpl();
+ }
+
+ virtual U8 getMediaDataCount() const
+ { return mObject->getNumTEs(); }
+
+ virtual LLSD getMediaDataLLSD(U8 index) const
+ {
+ LLSD result;
+ LLTextureEntry *te = mObject->getTE(index);
+ if (NULL != te)
+ {
+ llassert((te->getMediaData() != NULL) == te->hasMedia());
+ if (te->getMediaData() != NULL)
+ {
+ result = te->getMediaData()->asLLSD();
+ // XXX HACK: workaround bug in asLLSD() where whitelist is not set properly
+ // See DEV-41949
+ if (!result.has(LLMediaEntry::WHITELIST_KEY))
+ {
+ result[LLMediaEntry::WHITELIST_KEY] = LLSD::emptyArray();
+ }
+ }
+ }
+ return result;
+ }
+ virtual bool isCurrentMediaUrl(U8 index, const std::string &url) const
+ {
+ LLTextureEntry *te = mObject->getTE(index);
+ if (te)
+ {
+ if (te->getMediaData())
+ {
+ return (te->getMediaData()->getCurrentURL() == url);
+ }
+ }
+ return url.empty();
+ }
+
+ virtual LLUUID getID() const
+ { return mObject->getID(); }
+
+ virtual void mediaNavigateBounceBack(U8 index)
+ { mObject->mediaNavigateBounceBack(index); }
+
+ virtual bool hasMedia() const
+ { return mObject->hasMedia(); }
+
+ virtual void updateObjectMediaData(LLSD const &data, const std::string &version_string)
+ { mObject->updateObjectMediaData(data, version_string); }
+
+ virtual F64 getMediaInterest() const
+ {
+ F64 interest = mObject->getTotalMediaInterest();
+ if (interest < (F64)0.0)
+ {
+ // media interest not valid yet, try pixel area
+ interest = mObject->getPixelArea();
+ // HACK: force recalculation of pixel area if interest is the "magic default" of 1024.
+ if (interest == 1024.f)
+ {
+ const_cast<LLVOVolume*>(static_cast<LLVOVolume*>(mObject))->setPixelAreaAndAngle(gAgent);
+ interest = mObject->getPixelArea();
+ }
+ }
+ return interest;
+ }
+
+ virtual bool isInterestingEnough() const
+ {
+ return LLViewerMedia::isInterestingEnough(mObject, getMediaInterest());
+ }
+
+ virtual std::string getCapabilityUrl(const std::string &name) const
+ { return mObject->getRegion()->getCapability(name); }
+
+ virtual bool isDead() const
+ { return mObject->isDead(); }
+
+ virtual U32 getMediaVersion() const
+ { return LLTextureEntry::getVersionFromMediaVersionString(mObject->getMediaURL()); }
+
+ virtual bool isNew() const
+ { return mNew; }
+
+private:
+ LLPointer<LLVOVolume> mObject;
+ bool mNew;
+};
+
+
+LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
+ : LLViewerObject(id, pcode, regionp),
+ mVolumeImpl(NULL)
+{
+ mTexAnimMode = 0;
+ mRelativeXform.setIdentity();
+ mRelativeXformInvTrans.setIdentity();
+
+ mFaceMappingChanged = FALSE;
+ mLOD = MIN_LOD;
+ mTextureAnimp = NULL;
+ mVolumeChanged = FALSE;
+ mVObjRadius = LLVector3(1,1,0.5f).length();
+ mNumFaces = 0;
+ mLODChanged = FALSE;
+ mSculptChanged = FALSE;
+ mSpotLightPriority = 0.f;
+
+ mMediaImplList.resize(getNumTEs());
+ mLastFetchedMediaVersion = -1;
+ mIndexInTex = 0;
+ mMDCImplCount = 0;
+}
+
+LLVOVolume::~LLVOVolume()
+{
+ delete mTextureAnimp;
+ mTextureAnimp = NULL;
+ delete mVolumeImpl;
+ mVolumeImpl = NULL;
+
+ if(!mMediaImplList.empty())
+ {
+ for(U32 i = 0 ; i < mMediaImplList.size() ; i++)
+ {
+ if(mMediaImplList[i].notNull())
+ {
+ mMediaImplList[i]->removeObject(this) ;
+ }
+ }
+ }
+}
+
+void LLVOVolume::markDead()
+{
+ if (!mDead)
+ {
+ if(getMDCImplCount() > 0)
+ {
+ LLMediaDataClientObject::ptr_t obj = new LLMediaDataClientObjectImpl(const_cast<LLVOVolume*>(this), false);
+ if (sObjectMediaClient) sObjectMediaClient->removeFromQueue(obj);
+ if (sObjectMediaNavigateClient) sObjectMediaNavigateClient->removeFromQueue(obj);
+ }
+
+ // Detach all media impls from this object
+ for(U32 i = 0 ; i < mMediaImplList.size() ; i++)
+ {
+ removeMediaImpl(i);
+ }
+
+ if (mSculptTexture.notNull())
+ {
+ mSculptTexture->removeVolume(this);
+ }
+ }
+
+ LLViewerObject::markDead();
+}
+
+
+// static
+void LLVOVolume::initClass()
+{
+ // gSavedSettings better be around
+ if (gSavedSettings.getBOOL("PrimMediaMasterEnabled"))
+ {
+ const F32 queue_timer_delay = gSavedSettings.getF32("PrimMediaRequestQueueDelay");
+ const F32 retry_timer_delay = gSavedSettings.getF32("PrimMediaRetryTimerDelay");
+ const U32 max_retries = gSavedSettings.getU32("PrimMediaMaxRetries");
+ const U32 max_sorted_queue_size = gSavedSettings.getU32("PrimMediaMaxSortedQueueSize");
+ const U32 max_round_robin_queue_size = gSavedSettings.getU32("PrimMediaMaxRoundRobinQueueSize");
+ sObjectMediaClient = new LLObjectMediaDataClient(queue_timer_delay, retry_timer_delay, max_retries,
+ max_sorted_queue_size, max_round_robin_queue_size);
+ sObjectMediaNavigateClient = new LLObjectMediaNavigateClient(queue_timer_delay, retry_timer_delay,
+ max_retries, max_sorted_queue_size, max_round_robin_queue_size);
+ }
+}
+
+// static
+void LLVOVolume::cleanupClass()
+{
+ sObjectMediaClient = NULL;
+ sObjectMediaNavigateClient = NULL;
+}
+
+U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys,
+ void **user_data,
+ U32 block_num, EObjectUpdateType update_type,
+ LLDataPacker *dp)
+{
+ LLColor4U color;
+ const S32 teDirtyBits = (TEM_CHANGE_TEXTURE|TEM_CHANGE_COLOR|TEM_CHANGE_MEDIA);
+
+ // Do base class updates...
+ U32 retval = LLViewerObject::processUpdateMessage(mesgsys, user_data, block_num, update_type, dp);
+
+ LLUUID sculpt_id;
+ U8 sculpt_type = 0;
+ if (isSculpted())
+ {
+ LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT);
+ sculpt_id = sculpt_params->getSculptTexture();
+ sculpt_type = sculpt_params->getSculptType();
+ }
+
+ if (!dp)
+ {
+ if (update_type == OUT_FULL)
+ {
+ ////////////////////////////////
+ //
+ // Unpack texture animation data
+ //
+ //
+
+ if (mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_TextureAnim))
+ {
+ if (!mTextureAnimp)
+ {
+ mTextureAnimp = new LLViewerTextureAnim();
+ }
+ else
+ {
+ if (!(mTextureAnimp->mMode & LLTextureAnim::SMOOTH))
+ {
+ mTextureAnimp->reset();
+ }
+ }
+ mTexAnimMode = 0;
+ mTextureAnimp->unpackTAMessage(mesgsys, block_num);
+ }
+ else
+ {
+ if (mTextureAnimp)
+ {
+ delete mTextureAnimp;
+ mTextureAnimp = NULL;
+ gPipeline.markTextured(mDrawable);
+ mFaceMappingChanged = TRUE;
+ mTexAnimMode = 0;
+ }
+ }
+
+ // Unpack volume data
+ LLVolumeParams volume_params;
+ LLVolumeMessage::unpackVolumeParams(&volume_params, mesgsys, _PREHASH_ObjectData, block_num);
+ volume_params.setSculptID(sculpt_id, sculpt_type);
+
+ if (setVolume(volume_params, 0))
+ {
+ markForUpdate(TRUE);
+ }
+ }
+
+ // Sigh, this needs to be done AFTER the volume is set as well, otherwise bad stuff happens...
+ ////////////////////////////
+ //
+ // Unpack texture entry data
+ //
+ S32 result = unpackTEMessage(mesgsys, _PREHASH_ObjectData, block_num);
+ if (result & teDirtyBits)
+ {
+ updateTEData();
+ }
+ if (result & TEM_CHANGE_MEDIA)
+ {
+ retval |= MEDIA_FLAGS_CHANGED;
+ }
+ }
+ else
+ {
+ // CORY TO DO: Figure out how to get the value here
+ if (update_type != OUT_TERSE_IMPROVED)
+ {
+ LLVolumeParams volume_params;
+ BOOL res = LLVolumeMessage::unpackVolumeParams(&volume_params, *dp);
+ if (!res)
+ {
+ llwarns << "Bogus volume parameters in object " << getID() << llendl;
+ llwarns << getRegion()->getOriginGlobal() << llendl;
+ }
+
+ volume_params.setSculptID(sculpt_id, sculpt_type);
+
+ if (setVolume(volume_params, 0))
+ {
+ markForUpdate(TRUE);
+ }
+ S32 res2 = unpackTEMessage(*dp);
+ if (TEM_INVALID == res2)
+ {
+ // There's something bogus in the data that we're unpacking.
+ dp->dumpBufferToLog();
+ llwarns << "Flushing cache files" << llendl;
+
+ if(LLVOCache::hasInstance() && getRegion())
+ {
+ LLVOCache::getInstance()->removeEntry(getRegion()->getHandle()) ;
+ }
+
+ llwarns << "Bogus TE data in " << getID() << llendl;
+ }
+ else
+ {
+ if (res2 & teDirtyBits)
+ {
+ updateTEData();
+ }
+ if (res2 & TEM_CHANGE_MEDIA)
+ {
+ retval |= MEDIA_FLAGS_CHANGED;
+ }
+ }
+
+ U32 value = dp->getPassFlags();
+
+ if (value & 0x40)
+ {
+ if (!mTextureAnimp)
+ {
+ mTextureAnimp = new LLViewerTextureAnim();
+ }
+ else
+ {
+ if (!(mTextureAnimp->mMode & LLTextureAnim::SMOOTH))
+ {
+ mTextureAnimp->reset();
+ }
+ }
+ mTexAnimMode = 0;
+ mTextureAnimp->unpackTAMessage(*dp);
+ }
+ else if (mTextureAnimp)
+ {
+ delete mTextureAnimp;
+ mTextureAnimp = NULL;
+ gPipeline.markTextured(mDrawable);
+ mFaceMappingChanged = TRUE;
+ mTexAnimMode = 0;
+ }
+ }
+ else
+ {
+ S32 texture_length = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_TextureEntry);
+ if (texture_length)
+ {
+ U8 tdpbuffer[1024];
+ LLDataPackerBinaryBuffer tdp(tdpbuffer, 1024);
+ mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_TextureEntry, tdpbuffer, 0, block_num);
+ S32 result = unpackTEMessage(tdp);
+ if (result & teDirtyBits)
+ {
+ updateTEData();
+ }
+ if (result & TEM_CHANGE_MEDIA)
+ {
+ retval |= MEDIA_FLAGS_CHANGED;
+ }
+ }
+ }
+ }
+ if (retval & (MEDIA_URL_REMOVED | MEDIA_URL_ADDED | MEDIA_URL_UPDATED | MEDIA_FLAGS_CHANGED))
+ {
+ // If only the media URL changed, and it isn't a media version URL,
+ // ignore it
+ if ( ! ( retval & (MEDIA_URL_ADDED | MEDIA_URL_UPDATED) &&
+ mMedia && ! mMedia->mMediaURL.empty() &&
+ ! LLTextureEntry::isMediaVersionString(mMedia->mMediaURL) ) )
+ {
+ // If the media changed at all, request new media data
+ LL_DEBUGS("MediaOnAPrim") << "Media update: " << getID() << ": retval=" << retval << " Media URL: " <<
+ ((mMedia) ? mMedia->mMediaURL : std::string("")) << LL_ENDL;
+ requestMediaDataUpdate(retval & MEDIA_FLAGS_CHANGED);
+ }
+ else {
+ LL_INFOS("MediaOnAPrim") << "Ignoring media update for: " << getID() << " Media URL: " <<
+ ((mMedia) ? mMedia->mMediaURL : std::string("")) << LL_ENDL;
+ }
+ }
+ // ...and clean up any media impls
+ cleanUpMediaImpls();
+
+ return retval;
+}
+
+
+void LLVOVolume::animateTextures()
+{
+ F32 off_s = 0.f, off_t = 0.f, scale_s = 1.f, scale_t = 1.f, rot = 0.f;
+ S32 result = mTextureAnimp->animateTextures(off_s, off_t, scale_s, scale_t, rot);
+
+ if (result)
+ {
+ if (!mTexAnimMode)
+ {
+ mFaceMappingChanged = TRUE;
+ gPipeline.markTextured(mDrawable);
+ }
+ mTexAnimMode = result | mTextureAnimp->mMode;
+
+ S32 start=0, end=mDrawable->getNumFaces()-1;
+ if (mTextureAnimp->mFace >= 0 && mTextureAnimp->mFace <= end)
+ {
+ start = end = mTextureAnimp->mFace;
+ }
+
+ for (S32 i = start; i <= end; i++)
+ {
+ LLFace* facep = mDrawable->getFace(i);
+ if(facep->getVirtualSize() <= MIN_TEX_ANIM_SIZE && facep->mTextureMatrix) continue;
+
+ const LLTextureEntry* te = facep->getTextureEntry();
+
+ if (!te)
+ {
+ continue;
+ }
+
+ if (!(result & LLViewerTextureAnim::ROTATE))
+ {
+ te->getRotation(&rot);
+ }
+ if (!(result & LLViewerTextureAnim::TRANSLATE))
+ {
+ te->getOffset(&off_s,&off_t);
+ }
+ if (!(result & LLViewerTextureAnim::SCALE))
+ {
+ te->getScale(&scale_s, &scale_t);
+ }
+
+ if (!facep->mTextureMatrix)
+ {
+ facep->mTextureMatrix = new LLMatrix4();
+ }
+
+ LLMatrix4& tex_mat = *facep->mTextureMatrix;
+ tex_mat.setIdentity();
+ LLVector3 trans ;
+
+ if(facep->isAtlasInUse())
+ {
+ //
+ //if use atlas for animated texture
+ //apply the following transform to the animation matrix.
+ //
+
+ F32 tcoord_xoffset = 0.f ;
+ F32 tcoord_yoffset = 0.f ;
+ F32 tcoord_xscale = 1.f ;
+ F32 tcoord_yscale = 1.f ;
+ if(facep->isAtlasInUse())
+ {
+ const LLVector2* tmp = facep->getTexCoordOffset() ;
+ tcoord_xoffset = tmp->mV[0] ;
+ tcoord_yoffset = tmp->mV[1] ;
+
+ tmp = facep->getTexCoordScale() ;
+ tcoord_xscale = tmp->mV[0] ;
+ tcoord_yscale = tmp->mV[1] ;
+ }
+ trans.set(LLVector3(tcoord_xoffset + tcoord_xscale * (off_s+0.5f), tcoord_yoffset + tcoord_yscale * (off_t+0.5f), 0.f));
+
+ tex_mat.translate(LLVector3(-(tcoord_xoffset + tcoord_xscale * 0.5f), -(tcoord_yoffset + tcoord_yscale * 0.5f), 0.f));
+ }
+ else //non atlas
+ {
+ trans.set(LLVector3(off_s+0.5f, off_t+0.5f, 0.f));
+ tex_mat.translate(LLVector3(-0.5f, -0.5f, 0.f));
+ }
+
+ LLVector3 scale(scale_s, scale_t, 1.f);
+ LLQuaternion quat;
+ quat.setQuat(rot, 0, 0, -1.f);
+
+ tex_mat.rotate(quat);
+
+ LLMatrix4 mat;
+ mat.initAll(scale, LLQuaternion(), LLVector3());
+ tex_mat *= mat;
+
+ tex_mat.translate(trans);
+ }
+ }
+ else
+ {
+ if (mTexAnimMode && mTextureAnimp->mRate == 0)
+ {
+ U8 start, count;
+
+ if (mTextureAnimp->mFace == -1)
+ {
+ start = 0;
+ count = getNumTEs();
+ }
+ else
+ {
+ start = (U8) mTextureAnimp->mFace;
+ count = 1;
+ }
+
+ for (S32 i = start; i < start + count; i++)
+ {
+ if (mTexAnimMode & LLViewerTextureAnim::TRANSLATE)
+ {
+ setTEOffset(i, mTextureAnimp->mOffS, mTextureAnimp->mOffT);
+ }
+ if (mTexAnimMode & LLViewerTextureAnim::SCALE)
+ {
+ setTEScale(i, mTextureAnimp->mScaleS, mTextureAnimp->mScaleT);
+ }
+ if (mTexAnimMode & LLViewerTextureAnim::ROTATE)
+ {
+ setTERotation(i, mTextureAnimp->mRot);
+ }
+ }
+
+ gPipeline.markTextured(mDrawable);
+ mFaceMappingChanged = TRUE;
+ mTexAnimMode = 0;
+ }
+ }
+}
+BOOL LLVOVolume::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
+{
+ LLViewerObject::idleUpdate(agent, world, time);
+
+ static LLFastTimer::DeclareTimer ftm("Volume");
+ LLFastTimer t(ftm);
+
+ if (mDead || mDrawable.isNull())
+ {
+ return TRUE;
+ }
+
+ ///////////////////////
+ //
+ // Do texture animation stuff
+ //
+
+ if (mTextureAnimp && gAnimateTextures)
+ {
+ animateTextures();
+ }
+
+ // Dispatch to implementation
+ if (mVolumeImpl)
+ {
+ mVolumeImpl->doIdleUpdate(agent, world, time);
+ }
+
+ const S32 MAX_ACTIVE_OBJECT_QUIET_FRAMES = 40;
+
+ if (mDrawable->isActive())
+ {
+ if (mDrawable->isRoot() &&
+ mDrawable->mQuietCount++ > MAX_ACTIVE_OBJECT_QUIET_FRAMES &&
+ (!mDrawable->getParent() || !mDrawable->getParent()->isActive()))
+ {
+ mDrawable->makeStatic();
+ }
+ }
+
+ return TRUE;
+}
+
+void LLVOVolume::updateTextures()
+{
+ const F32 TEXTURE_AREA_REFRESH_TIME = 5.f; // seconds
+ if (mTextureUpdateTimer.getElapsedTimeF32() > TEXTURE_AREA_REFRESH_TIME)
+ {
+ updateTextureVirtualSize();
+ }
+}
+
+BOOL LLVOVolume::isVisible() const
+{
+ if(mDrawable.notNull() && mDrawable->isVisible())
+ {
+ return TRUE ;
+ }
+
+ if(isAttachment())
+ {
+ LLViewerObject* objp = (LLViewerObject*)getParent() ;
+ while(objp && !objp->isAvatar())
+ {
+ objp = (LLViewerObject*)objp->getParent() ;
+ }
+
+ return objp && objp->mDrawable.notNull() && objp->mDrawable->isVisible() ;
+ }
+
+ return FALSE ;
+}
+
+void LLVOVolume::updateTextureVirtualSize()
+{
+ LLFastTimer ftm(FTM_VOLUME_TEXTURES);
+ // Update the pixel area of all faces
+
+ if(!isVisible())
+ {
+ return ;
+ }
+
+ if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SIMPLE))
+ {
+ return;
+ }
+
+ static LLCachedControl<bool> dont_load_textures(gSavedSettings,"TextureDisable");
+
+ if (dont_load_textures || LLAppViewer::getTextureFetch()->mDebugPause) // || !mDrawable->isVisible())
+ {
+ return;
+ }
+
+ mTextureUpdateTimer.reset();
+
+ F32 old_area = mPixelArea;
+ mPixelArea = 0.f;
+
+ const S32 num_faces = mDrawable->getNumFaces();
+ F32 min_vsize=999999999.f, max_vsize=0.f;
+ LLViewerCamera* camera = LLViewerCamera::getInstance();
+ for (S32 i = 0; i < num_faces; i++)
+ {
+ LLFace* face = mDrawable->getFace(i);
+ const LLTextureEntry *te = face->getTextureEntry();
+ LLViewerTexture *imagep = face->getTexture();
+ if (!imagep || !te ||
+ face->mExtents[0].equals3(face->mExtents[1]))
+ {
+ continue;
+ }
+
+ F32 vsize;
+ F32 old_size = face->getVirtualSize();
+
+ if (isHUDAttachment())
+ {
+ F32 area = (F32) camera->getScreenPixelArea();
+ vsize = area;
+ imagep->setBoostLevel(LLViewerTexture::BOOST_HUD);
+ face->setPixelArea(area); // treat as full screen
+ face->setVirtualSize(vsize);
+ }
+ else
+ {
+ vsize = face->getTextureVirtualSize();
+ }
+
+ mPixelArea = llmax(mPixelArea, face->getPixelArea());
+
+ if (face->mTextureMatrix != NULL)
+ {
+ if ((vsize < MIN_TEX_ANIM_SIZE && old_size > MIN_TEX_ANIM_SIZE) ||
+ (vsize > MIN_TEX_ANIM_SIZE && old_size < MIN_TEX_ANIM_SIZE))
+ {
+ gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD, FALSE);
+ }
+ }
+
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA))
+ {
+ if (vsize < min_vsize) min_vsize = vsize;
+ if (vsize > max_vsize) max_vsize = vsize;
+ }
+ else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY))
+ {
+ LLViewerFetchedTexture* img = LLViewerTextureManager::staticCastToFetchedTexture(imagep) ;
+ if(img)
+ {
+ F32 pri = img->getDecodePriority();
+ pri = llmax(pri, 0.0f);
+ if (pri < min_vsize) min_vsize = pri;
+ if (pri > max_vsize) max_vsize = pri;
+ }
+ }
+ else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_FACE_AREA))
+ {
+ F32 pri = mPixelArea;
+ if (pri < min_vsize) min_vsize = pri;
+ if (pri > max_vsize) max_vsize = pri;
+ }
+ }
+
+ if (isSculpted())
+ {
+ LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT);
+ LLUUID id = sculpt_params->getSculptTexture();
+
+ updateSculptTexture();
+
+
+
+ if (mSculptTexture.notNull())
+ {
+ mSculptTexture->setBoostLevel(llmax((S32)mSculptTexture->getBoostLevel(),
+ (S32)LLViewerTexture::BOOST_SCULPTED));
+ mSculptTexture->setForSculpt() ;
+
+ if(!mSculptTexture->isCachedRawImageReady())
+ {
+ S32 lod = llmin(mLOD, 3);
+ F32 lodf = ((F32)(lod + 1.0f)/4.f);
+ F32 tex_size = lodf * LLViewerTexture::sMaxSculptRez ;
+ mSculptTexture->addTextureStats(2.f * tex_size * tex_size, FALSE);
+
+ //if the sculpty very close to the view point, load first
+ {
+ LLVector3 lookAt = getPositionAgent() - camera->getOrigin();
+ F32 dist = lookAt.normVec() ;
+ F32 cos_angle_to_view_dir = lookAt * camera->getXAxis() ;
+ mSculptTexture->setAdditionalDecodePriority(0.8f * LLFace::calcImportanceToCamera(cos_angle_to_view_dir, dist)) ;
+ }
+ }
+
+ S32 texture_discard = mSculptTexture->getDiscardLevel(); //try to match the texture
+ S32 current_discard = getVolume() ? getVolume()->getSculptLevel() : -2 ;
+
+ if (texture_discard >= 0 && //texture has some data available
+ (texture_discard < current_discard || //texture has more data than last rebuild
+ current_discard < 0)) //no previous rebuild
+ {
+ gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, FALSE);
+ mSculptChanged = TRUE;
+ }
+
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SCULPTED))
+ {
+ setDebugText(llformat("T%d C%d V%d\n%dx%d",
+ texture_discard, current_discard, getVolume()->getSculptLevel(),
+ mSculptTexture->getHeight(), mSculptTexture->getWidth()));
+ }
+ }
+
+ }
+
+ if (getLightTextureID().notNull())
+ {
+ LLLightImageParams* params = (LLLightImageParams*) getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE);
+ LLUUID id = params->getLightTexture();
+ mLightTexture = LLViewerTextureManager::getFetchedTexture(id);
+ if (mLightTexture.notNull())
+ {
+ F32 rad = getLightRadius();
+ mLightTexture->addTextureStats(gPipeline.calcPixelArea(getPositionAgent(),
+ LLVector3(rad,rad,rad),
+ *camera));
+ }
+ }
+
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA))
+ {
+ setDebugText(llformat("%.0f:%.0f", (F32) sqrt(min_vsize),(F32) sqrt(max_vsize)));
+ }
+ else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY))
+ {
+ setDebugText(llformat("%.0f:%.0f", (F32) sqrt(min_vsize),(F32) sqrt(max_vsize)));
+ }
+ else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_FACE_AREA))
+ {
+ setDebugText(llformat("%.0f:%.0f", (F32) sqrt(min_vsize),(F32) sqrt(max_vsize)));
+ }
+
+ if (mPixelArea == 0)
+ { //flexi phasing issues make this happen
+ mPixelArea = old_area;
+ }
+}
+
+BOOL LLVOVolume::isActive() const
+{
+ return !mStatic || mTextureAnimp || (mVolumeImpl && mVolumeImpl->isActive()) ||
+ (mDrawable.notNull() && mDrawable->isActive());
+}
+
+BOOL LLVOVolume::setMaterial(const U8 material)
+{
+ BOOL res = LLViewerObject::setMaterial(material);
+
+ return res;
+}
+
+void LLVOVolume::setTexture(const S32 face)
+{
+ llassert(face < getNumTEs());
+ gGL.getTexUnit(0)->bind(getTEImage(face));
+}
+
+void LLVOVolume::setScale(const LLVector3 &scale, BOOL damped)
+{
+ if (scale != getScale())
+ {
+ // store local radius
+ LLViewerObject::setScale(scale);
+
+ if (mVolumeImpl)
+ {
+ mVolumeImpl->onSetScale(scale, damped);
+ }
+
+ updateRadius();
+
+ //since drawable transforms do not include scale, changing volume scale
+ //requires an immediate rebuild of volume verts.
+ gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_POSITION, TRUE);
+ }
+}
+
+LLFace* LLVOVolume::addFace(S32 f)
+{
+ const LLTextureEntry* te = getTE(f);
+ LLViewerTexture* imagep = getTEImage(f);
+ return mDrawable->addFace(te, imagep);
+}
+
+LLDrawable *LLVOVolume::createDrawable(LLPipeline *pipeline)
+{
+ pipeline->allocDrawable(this);
+
+ mDrawable->setRenderType(LLPipeline::RENDER_TYPE_VOLUME);
+
+ S32 max_tes_to_set = getNumTEs();
+ for (S32 i = 0; i < max_tes_to_set; i++)
+ {
+ addFace(i);
+ }
+ mNumFaces = max_tes_to_set;
+
+ if (isAttachment())
+ {
+ mDrawable->makeActive();
+ }
+
+ if (getIsLight())
+ {
+ // Add it to the pipeline mLightSet
+ gPipeline.setLight(mDrawable, TRUE);
+ }
+
+ updateRadius();
+ bool force_update = true; // avoid non-alpha mDistance update being optimized away
+ mDrawable->updateDistance(*LLViewerCamera::getInstance(), force_update);
+
+ return mDrawable;
+}
+
+BOOL LLVOVolume::setVolume(const LLVolumeParams ¶ms_in, const S32 detail, bool unique_volume)
+{
+ LLVolumeParams volume_params = params_in;
+
+ S32 last_lod = mVolumep.notNull() ? LLVolumeLODGroup::getVolumeDetailFromScale(mVolumep->getDetail()) : -1;
+ S32 lod = mLOD;
+
+ BOOL is404 = FALSE;
+
+ if (isSculpted())
+ {
+ // if it's a mesh
+ if ((volume_params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)
+ { //meshes might not have all LODs, get the force detail to best existing LOD
+
+ LLUUID mesh_id = volume_params.getSculptID();
+
+ //profile and path params don't matter for meshes
+ volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
+
+ lod = gMeshRepo.getActualMeshLOD(volume_params, lod);
+ if (lod == -1)
+ {
+ is404 = TRUE;
+ lod = 0;
+ }
+ }
+ }
+
+ // Check if we need to change implementations
+ bool is_flexible = (volume_params.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE);
+ if (is_flexible)
+ {
+ setParameterEntryInUse(LLNetworkData::PARAMS_FLEXIBLE, TRUE, false);
+ if (!mVolumeImpl)
+ {
+ LLFlexibleObjectData* data = (LLFlexibleObjectData*)getParameterEntry(LLNetworkData::PARAMS_FLEXIBLE);
+ mVolumeImpl = new LLVolumeImplFlexible(this, data);
+ }
+ }
+ else
+ {
+ // Mark the parameter not in use
+ setParameterEntryInUse(LLNetworkData::PARAMS_FLEXIBLE, FALSE, false);
+ if (mVolumeImpl)
+ {
+ delete mVolumeImpl;
+ mVolumeImpl = NULL;
+ if (mDrawable.notNull())
+ {
+ // Undo the damage we did to this matrix
+ mDrawable->updateXform(FALSE);
+ }
+ }
+ }
+
+ if (is404)
+ {
+ setIcon(LLViewerTextureManager::getFetchedTextureFromFile("icons/Inv_Mesh.png", TRUE, LLViewerTexture::BOOST_UI));
+ //render prim proxy when mesh loading attempts give up
+ volume_params.setSculptID(LLUUID::null, LL_SCULPT_TYPE_NONE);
+
+ }
+
+ if ((LLPrimitive::setVolume(volume_params, lod, (mVolumeImpl && mVolumeImpl->isVolumeUnique()))) || mSculptChanged)
+ {
+ mFaceMappingChanged = TRUE;
+
+ if (mVolumeImpl)
+ {
+ mVolumeImpl->onSetVolume(volume_params, mLOD);
+ }
+
+ updateSculptTexture();
+
+
+ if (isSculpted())
+ {
+ updateSculptTexture();
+ // if it's a mesh
+ if ((volume_params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)
+ {
+ if (getVolume()->getNumVolumeFaces() == 0 || getVolume()->isTetrahedron())
+ {
+ //load request not yet issued, request pipeline load this mesh
+ LLUUID asset_id = volume_params.getSculptID();
+ S32 available_lod = gMeshRepo.loadMesh(this, volume_params, lod, last_lod);
+ if (available_lod != lod)
+ {
+ LLPrimitive::setVolume(volume_params, available_lod);
+ }
+ }
+
+ }
+ else // otherwise is sculptie
+ {
+ if (mSculptTexture.notNull())
+ {
+ sculpt();
+ }
+ }
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void LLVOVolume::updateSculptTexture()
+{
+ LLPointer<LLViewerFetchedTexture> old_sculpt = mSculptTexture;
+
+ if (isSculpted() && !isMesh())
+ {
+ LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT);
+ LLUUID id = sculpt_params->getSculptTexture();
+ if (id.notNull())
+ {
+ mSculptTexture = LLViewerTextureManager::getFetchedTexture(id, TRUE, LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
+ }
+ }
+ else
+ {
+ mSculptTexture = NULL;
+ }
+
+ if (mSculptTexture != old_sculpt)
+ {
+ if (old_sculpt.notNull())
+ {
+ old_sculpt->removeVolume(this);
+ }
+ if (mSculptTexture.notNull())
+ {
+ mSculptTexture->addVolume(this);
+ }
+ }
+
+}
+
+void LLVOVolume::notifyMeshLoaded()
+{
+ mSculptChanged = TRUE;
+ gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE);
+}
+
+// sculpt replaces generate() for sculpted surfaces
+void LLVOVolume::sculpt()
+{
+ if (mSculptTexture.notNull())
+ {
+ U16 sculpt_height = 0;
+ U16 sculpt_width = 0;
+ S8 sculpt_components = 0;
+ const U8* sculpt_data = NULL;
+
+ S32 discard_level = mSculptTexture->getDiscardLevel() ;
+ LLImageRaw* raw_image = mSculptTexture->getCachedRawImage() ;
+
+ S32 max_discard = mSculptTexture->getMaxDiscardLevel();
+ if (discard_level > max_discard)
+ discard_level = max_discard; // clamp to the best we can do
+
+ S32 current_discard = getVolume()->getSculptLevel() ;
+ if(current_discard < -2)
+ {
+ llwarns << "WARNING!!: Current discard of sculpty at " << current_discard
+ << " is less than -2." << llendl;
+
+ // corrupted volume... don't update the sculpty
+ return;
+ }
+ else if (current_discard > MAX_DISCARD_LEVEL)
+ {
+ llwarns << "WARNING!!: Current discard of sculpty at " << current_discard
+ << " is more than than allowed max of " << MAX_DISCARD_LEVEL << llendl;
+
+ // corrupted volume... don't update the sculpty
+ return;
+ }
+
+ if (current_discard == discard_level) // no work to do here
+ return;
+
+ if(!raw_image)
+ {
+ llassert(discard_level < 0) ;
+
+ sculpt_width = 0;
+ sculpt_height = 0;
+ sculpt_data = NULL ;
+
+ if(LLViewerTextureManager::sTesterp)
+ {
+ LLViewerTextureManager::sTesterp->updateGrayTextureBinding();
+ }
+ }
+ else
+ {
+ sculpt_height = raw_image->getHeight();
+ sculpt_width = raw_image->getWidth();
+ sculpt_components = raw_image->getComponents();
+
+ sculpt_data = raw_image->getData();
+
+ if(LLViewerTextureManager::sTesterp)
+ {
+ mSculptTexture->updateBindStatsForTester() ;
+ }
+ }
+ getVolume()->sculpt(sculpt_width, sculpt_height, sculpt_components, sculpt_data, discard_level);
+
+ //notify rebuild any other VOVolumes that reference this sculpty volume
+ for (S32 i = 0; i < mSculptTexture->getNumVolumes(); ++i)
+ {
+ LLVOVolume* volume = (*(mSculptTexture->getVolumeList()))[i];
+ if (volume != this && volume->getVolume() == getVolume())
+ {
+ gPipeline.markRebuild(volume->mDrawable, LLDrawable::REBUILD_GEOMETRY, FALSE);
+ }
+ }
+ }
+}
+
+S32 LLVOVolume::computeLODDetail(F32 distance, F32 radius)
+{
+ S32 cur_detail;
+ if (LLPipeline::sDynamicLOD)
+ {
+ // We've got LOD in the profile, and in the twist. Use radius.
+ F32 tan_angle = (LLVOVolume::sLODFactor*radius)/distance;
+ cur_detail = LLVolumeLODGroup::getDetailFromTan(llround(tan_angle, 0.01f));
+ }
+ else
+ {
+ cur_detail = llclamp((S32) (sqrtf(radius)*LLVOVolume::sLODFactor*4.f), 0, 3);
+ }
+ return cur_detail;
+}
+
+BOOL LLVOVolume::calcLOD()
+{
+ if (mDrawable.isNull())
+ {
+ return FALSE;
+ }
+
+ S32 cur_detail = 0;
+
+ F32 radius;
+ F32 distance;
+
+ if (mDrawable->isState(LLDrawable::RIGGED))
+ {
+ LLVOAvatar* avatar = getAvatar();
+ distance = avatar->mDrawable->mDistanceWRTCamera;
+ radius = avatar->getBinRadius();
+ }
+ else
+ {
+ distance = mDrawable->mDistanceWRTCamera;
+ radius = getVolume()->mLODScaleBias.scaledVec(getScale()).length();
+ }
+
+ //hold onto unmodified distance for debugging
+ //F32 debug_distance = distance;
+
+ distance *= sDistanceFactor;
+
+ F32 rampDist = LLVOVolume::sLODFactor * 2;
+
+ if (distance < rampDist)
+ {
+ // Boost LOD when you're REALLY close
+ distance *= 1.0f/rampDist;
+ distance *= distance;
+ distance *= rampDist;
+ }
+
+ // DON'T Compensate for field of view changing on FOV zoom.
+ distance *= F_PI/3.f;
+
+ cur_detail = computeLODDetail(llround(distance, 0.01f),
+ llround(radius, 0.01f));
+
+
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_LOD_INFO))
+ {
+ //setDebugText(llformat("%.2f:%.2f, %d", debug_distance, radius, cur_detail));
+
+ setDebugText(llformat("%d", mDrawable->getFace(0)->getTextureIndex()));
+ }
+
+ if (cur_detail != mLOD)
+ {
+ mAppAngle = llround((F32) atan2( mDrawable->getRadius(), mDrawable->mDistanceWRTCamera) * RAD_TO_DEG, 0.01f);
+ mLOD = cur_detail;
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+BOOL LLVOVolume::updateLOD()
+{
+ if (mDrawable.isNull())
+ {
+ return FALSE;
+ }
+
+ BOOL lod_changed = calcLOD();
+
+ if (lod_changed)
+ {
+ gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, FALSE);
+ mLODChanged = TRUE;
+ }
+ else
+ {
+ F32 new_radius = getBinRadius();
+ F32 old_radius = mDrawable->getBinRadius();
+ if (new_radius < old_radius * 0.9f || new_radius > old_radius*1.1f)
+ {
+ gPipeline.markPartitionMove(mDrawable);
+ }
+ }
+
+ lod_changed = lod_changed || LLViewerObject::updateLOD();
+
+ return lod_changed;
+}
+
+BOOL LLVOVolume::setDrawableParent(LLDrawable* parentp)
+{
+ if (!LLViewerObject::setDrawableParent(parentp))
+ {
+ // no change in drawable parent
+ return FALSE;
+ }
+
+ if (!mDrawable->isRoot())
+ {
+ // rebuild vertices in parent relative space
+ gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE);
+
+ if (mDrawable->isActive() && !parentp->isActive())
+ {
+ parentp->makeActive();
+ }
+ else if (mDrawable->isStatic() && parentp->isActive())
+ {
+ mDrawable->makeActive();
+ }
+ }
+
+ return TRUE;
+}
+
+void LLVOVolume::updateFaceFlags()
+{
+ for (S32 i = 0; i < getVolume()->getNumFaces(); i++)
+ {
+ LLFace *face = mDrawable->getFace(i);
+ if (!face)
+ {
+ return;
+ }
+
+ BOOL fullbright = getTE(i)->getFullbright();
+ face->clearState(LLFace::FULLBRIGHT | LLFace::HUD_RENDER | LLFace::LIGHT);
+
+ if (fullbright || (mMaterial == LL_MCODE_LIGHT))
+ {
+ face->setState(LLFace::FULLBRIGHT);
+ }
+ if (mDrawable->isLight())
+ {
+ face->setState(LLFace::LIGHT);
+ }
+ if (isHUDAttachment())
+ {
+ face->setState(LLFace::HUD_RENDER);
+ }
+ }
+}
+
+BOOL LLVOVolume::setParent(LLViewerObject* parent)
+{
+ BOOL ret = FALSE ;
+ if (parent != getParent())
+ {
+ ret = LLViewerObject::setParent(parent);
+ if (ret && mDrawable)
+ {
+ gPipeline.markMoved(mDrawable);
+ gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE);
+ }
+ }
+
+ return ret ;
+}
+
+// NOTE: regenFaces() MUST be followed by genTriangles()!
+void LLVOVolume::regenFaces()
+{
+ // remove existing faces
+ BOOL count_changed = mNumFaces != getNumTEs();
+
+ if (count_changed)
+ {
+ deleteFaces();
+ // add new faces
+ mNumFaces = getNumTEs();
+ }
+
+ for (S32 i = 0; i < mNumFaces; i++)
+ {
+ LLFace* facep = count_changed ? addFace(i) : mDrawable->getFace(i);
+ facep->setTEOffset(i);
+ facep->setTexture(getTEImage(i));
+ facep->setViewerObject(this);
+
+ // If the face had media on it, this will have broken the link between the LLViewerMediaTexture and the face.
+ // Re-establish the link.
+ if((int)mMediaImplList.size() > i)
+ {
+ if(mMediaImplList[i])
+ {
+ LLViewerMediaTexture* media_tex = LLViewerTextureManager::findMediaTexture(mMediaImplList[i]->getMediaTextureID()) ;
+ if(media_tex)
+ {
+ media_tex->addMediaToFace(facep) ;
+ }
+ }
+ }
+ }
+
+ if (!count_changed)
+ {
+ updateFaceFlags();
+ }
+}
+
+BOOL LLVOVolume::genBBoxes(BOOL force_global)
+{
+ BOOL res = TRUE;
+
+ LLVector4a min,max;
+
+ min.clear();
+ max.clear();
+
+ BOOL rebuild = mDrawable->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION | LLDrawable::REBUILD_RIGGED);
+
+// bool rigged = false;
+ LLVolume* volume = mRiggedVolume;
+ if (!volume)
+ {
+ volume = getVolume();
+ }
+
+ for (S32 i = 0; i < getVolume()->getNumVolumeFaces(); i++)
+ {
+ LLFace *face = mDrawable->getFace(i);
+ if (!face)
+ {
+ continue;
+ }
+ res &= face->genVolumeBBoxes(*volume, i,
+ mRelativeXform, mRelativeXformInvTrans,
+ (mVolumeImpl && mVolumeImpl->isVolumeGlobal()) || force_global);
+
+ if (rebuild)
+ {
+ if (i == 0)
+ {
+ min = face->mExtents[0];
+ max = face->mExtents[1];
+ }
+ else
+ {
+ min.setMin(min, face->mExtents[0]);
+ max.setMax(max, face->mExtents[1]);
+ }
+ }
+ }
+
+ if (rebuild)
+ {
+ mDrawable->setSpatialExtents(min,max);
+ min.add(max);
+ min.mul(0.5f);
+ mDrawable->setPositionGroup(min);
+ }
+
+ updateRadius();
+ mDrawable->movePartition();
+
+ return res;
+}
+
+void LLVOVolume::preRebuild()
+{
+ if (mVolumeImpl != NULL)
+ {
+ mVolumeImpl->preRebuild();
+ }
+}
+
+void LLVOVolume::updateRelativeXform()
+{
+ if (mVolumeImpl)
+ {
+ mVolumeImpl->updateRelativeXform();
+ return;
+ }
+
+ LLDrawable* drawable = mDrawable;
+
+ if (drawable->isState(LLDrawable::RIGGED) && mRiggedVolume.notNull())
+ { //rigged volume (which is in agent space) is used for generating bounding boxes etc
+ //inverse of render matrix should go to partition space
+ mRelativeXform = getRenderMatrix();
+
+ F32* dst = (F32*) mRelativeXformInvTrans.mMatrix;
+ F32* src = (F32*) mRelativeXform.mMatrix;
+ dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2];
+ dst[3] = src[4]; dst[4] = src[5]; dst[5] = src[6];
+ dst[6] = src[8]; dst[7] = src[9]; dst[8] = src[10];
+
+ mRelativeXform.invert();
+ mRelativeXformInvTrans.transpose();
+ }
+ else if (drawable->isActive())
+ {
+ // setup relative transforms
+ LLQuaternion delta_rot;
+ LLVector3 delta_pos, delta_scale;
+
+ //matrix from local space to parent relative/global space
+ delta_rot = drawable->isSpatialRoot() ? LLQuaternion() : mDrawable->getRotation();
+ delta_pos = drawable->isSpatialRoot() ? LLVector3(0,0,0) : mDrawable->getPosition();
+ delta_scale = mDrawable->getScale();
+
+ // Vertex transform (4x4)
+ LLVector3 x_axis = LLVector3(delta_scale.mV[VX], 0.f, 0.f) * delta_rot;
+ LLVector3 y_axis = LLVector3(0.f, delta_scale.mV[VY], 0.f) * delta_rot;
+ LLVector3 z_axis = LLVector3(0.f, 0.f, delta_scale.mV[VZ]) * delta_rot;
+
+ mRelativeXform.initRows(LLVector4(x_axis, 0.f),
+ LLVector4(y_axis, 0.f),
+ LLVector4(z_axis, 0.f),
+ LLVector4(delta_pos, 1.f));
+
+
+ // compute inverse transpose for normals
+ // mRelativeXformInvTrans.setRows(x_axis, y_axis, z_axis);
+ // mRelativeXformInvTrans.invert();
+ // mRelativeXformInvTrans.setRows(x_axis, y_axis, z_axis);
+ // grumble - invert is NOT a matrix invert, so we do it by hand:
+
+ LLMatrix3 rot_inverse = LLMatrix3(~delta_rot);
+
+ LLMatrix3 scale_inverse;
+ scale_inverse.setRows(LLVector3(1.0, 0.0, 0.0) / delta_scale.mV[VX],
+ LLVector3(0.0, 1.0, 0.0) / delta_scale.mV[VY],
+ LLVector3(0.0, 0.0, 1.0) / delta_scale.mV[VZ]);
+
+
+ mRelativeXformInvTrans = rot_inverse * scale_inverse;
+
+ mRelativeXformInvTrans.transpose();
+ }
+ else
+ {
+ LLVector3 pos = getPosition();
+ LLVector3 scale = getScale();
+ LLQuaternion rot = getRotation();
+
+ if (mParent)
+ {
+ pos *= mParent->getRotation();
+ pos += mParent->getPosition();
+ rot *= mParent->getRotation();
+ }
+
+ //LLViewerRegion* region = getRegion();
+ //pos += region->getOriginAgent();
+
+ LLVector3 x_axis = LLVector3(scale.mV[VX], 0.f, 0.f) * rot;
+ LLVector3 y_axis = LLVector3(0.f, scale.mV[VY], 0.f) * rot;
+ LLVector3 z_axis = LLVector3(0.f, 0.f, scale.mV[VZ]) * rot;
+
+ mRelativeXform.initRows(LLVector4(x_axis, 0.f),
+ LLVector4(y_axis, 0.f),
+ LLVector4(z_axis, 0.f),
+ LLVector4(pos, 1.f));
+
+ // compute inverse transpose for normals
+ LLMatrix3 rot_inverse = LLMatrix3(~rot);
+
+ LLMatrix3 scale_inverse;
+ scale_inverse.setRows(LLVector3(1.0, 0.0, 0.0) / scale.mV[VX],
+ LLVector3(0.0, 1.0, 0.0) / scale.mV[VY],
+ LLVector3(0.0, 0.0, 1.0) / scale.mV[VZ]);
+
+
+ mRelativeXformInvTrans = rot_inverse * scale_inverse;
+
+ mRelativeXformInvTrans.transpose();
+ }
+}
+
+static LLFastTimer::DeclareTimer FTM_GEN_FLEX("Generate Flexies");
+static LLFastTimer::DeclareTimer FTM_UPDATE_PRIMITIVES("Update Primitives");
+static LLFastTimer::DeclareTimer FTM_UPDATE_RIGGED_VOLUME("Update Rigged");
+
+BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
+{
+ LLFastTimer t(FTM_UPDATE_PRIMITIVES);
+
+ if (mDrawable->isState(LLDrawable::REBUILD_RIGGED))
+ {
+ {
+ LLFastTimer t(FTM_UPDATE_RIGGED_VOLUME);
+ updateRiggedVolume();
+ }
+ genBBoxes(FALSE);
+ mDrawable->clearState(LLDrawable::REBUILD_RIGGED);
+ }
+
+ if (mVolumeImpl != NULL)
+ {
+ BOOL res;
+ {
+ LLFastTimer t(FTM_GEN_FLEX);
+ res = mVolumeImpl->doUpdateGeometry(drawable);
+ }
+ updateFaceFlags();
+ return res;
+ }
+
+ dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1));
+
+ BOOL compiled = FALSE;
+
+ updateRelativeXform();
+
+ if (mDrawable.isNull()) // Not sure why this is happening, but it is...
+ {
+ return TRUE; // No update to complete
+ }
+
+ if (mVolumeChanged || mFaceMappingChanged )
+ {
+ compiled = TRUE;
+
+ if (mVolumeChanged)
+ {
+ LLFastTimer ftm(FTM_GEN_VOLUME);
+ LLVolumeParams volume_params = getVolume()->getParams();
+ setVolume(volume_params, 0);
+ drawable->setState(LLDrawable::REBUILD_VOLUME);
+ }
+
+ {
+ LLFastTimer t(FTM_GEN_TRIANGLES);
+ regenFaces();
+ genBBoxes(FALSE);
+ }
+ }
+ else if ((mLODChanged) || (mSculptChanged))
+ {
+ LLVolume *old_volumep, *new_volumep;
+ F32 old_lod, new_lod;
+ S32 old_num_faces, new_num_faces ;
+
+ old_volumep = getVolume();
+ old_lod = old_volumep->getDetail();
+ old_num_faces = old_volumep->getNumFaces() ;
+ old_volumep = NULL ;
+
+ {
+ LLFastTimer ftm(FTM_GEN_VOLUME);
+ LLVolumeParams volume_params = getVolume()->getParams();
+ setVolume(volume_params, 0);
+ }
+
+ new_volumep = getVolume();
+ new_lod = new_volumep->getDetail();
+ new_num_faces = new_volumep->getNumFaces() ;
+ new_volumep = NULL ;
+
+ if ((new_lod != old_lod) || mSculptChanged)
+ {
+ compiled = TRUE;
+ sNumLODChanges += new_num_faces ;
+
+ drawable->setState(LLDrawable::REBUILD_VOLUME); // for face->genVolumeTriangles()
+
+ {
+ LLFastTimer t(FTM_GEN_TRIANGLES);
+ if (new_num_faces != old_num_faces)
+ {
+ regenFaces();
+ }
+ genBBoxes(FALSE);
+
+ if (mSculptChanged)
+ { //changes in sculpt maps can thrash an object bounding box without
+ //triggering a spatial group bounding box update -- force spatial group
+ //to update bounding boxes
+ LLSpatialGroup* group = mDrawable->getSpatialGroup();
+ if (group)
+ {
+ group->unbound();
+ }
+ }
+ }
+ }
+ }
+ // it has its own drawable (it's moved) or it has changed UVs or it has changed xforms from global<->local
+ else
+ {
+ compiled = TRUE;
+ // All it did was move or we changed the texture coordinate offset
+ LLFastTimer t(FTM_GEN_TRIANGLES);
+ genBBoxes(FALSE);
+ }
+
+ // Update face flags
+ updateFaceFlags();
+
+ if(compiled)
+ {
+ LLPipeline::sCompiles++;
+ }
+
+ mVolumeChanged = FALSE;
+ mLODChanged = FALSE;
+ mSculptChanged = FALSE;
+ mFaceMappingChanged = FALSE;
+
+ return LLViewerObject::updateGeometry(drawable);
+}
+
+void LLVOVolume::updateFaceSize(S32 idx)
+{
+ LLFace* facep = mDrawable->getFace(idx);
+ if (idx >= getVolume()->getNumVolumeFaces())
+ {
+ facep->setSize(0,0, true);
+ }
+ else
+ {
+ const LLVolumeFace& vol_face = getVolume()->getVolumeFace(idx);
+ facep->setSize(vol_face.mNumVertices, vol_face.mNumIndices,
+ true); // <--- volume faces should be padded for 16-byte alignment
+
+ }
+}
+
+BOOL LLVOVolume::isRootEdit() const
+{
+ if (mParent && !((LLViewerObject*)mParent)->isAvatar())
+ {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+//virtual
+void LLVOVolume::setNumTEs(const U8 num_tes)
+{
+ const U8 old_num_tes = getNumTEs() ;
+
+ if(old_num_tes && old_num_tes < num_tes) //new faces added
+ {
+ LLViewerObject::setNumTEs(num_tes) ;
+
+ if(mMediaImplList.size() >= old_num_tes && mMediaImplList[old_num_tes -1].notNull())//duplicate the last media textures if exists.
+ {
+ mMediaImplList.resize(num_tes) ;
+ const LLTextureEntry* te = getTE(old_num_tes - 1) ;
+ for(U8 i = old_num_tes; i < num_tes ; i++)
+ {
+ setTE(i, *te) ;
+ mMediaImplList[i] = mMediaImplList[old_num_tes -1] ;
+ }
+ mMediaImplList[old_num_tes -1]->setUpdated(TRUE) ;
+ }
+ }
+ else if(old_num_tes > num_tes && mMediaImplList.size() > num_tes) //old faces removed
+ {
+ U8 end = mMediaImplList.size() ;
+ for(U8 i = num_tes; i < end ; i++)
+ {
+ removeMediaImpl(i) ;
+ }
+ mMediaImplList.resize(num_tes) ;
+
+ LLViewerObject::setNumTEs(num_tes) ;
+ }
+ else
+ {
+ LLViewerObject::setNumTEs(num_tes) ;
+ }
+
+ return ;
+}
+
+void LLVOVolume::setTEImage(const U8 te, LLViewerTexture *imagep)
+{
+ BOOL changed = (mTEImages[te] != imagep);
+ LLViewerObject::setTEImage(te, imagep);
+ if (changed)
+ {
+ gPipeline.markTextured(mDrawable);
+ mFaceMappingChanged = TRUE;
+ }
+}
+
+S32 LLVOVolume::setTETexture(const U8 te, const LLUUID &uuid)
+{
+ S32 res = LLViewerObject::setTETexture(te, uuid);
+ if (res)
+ {
+ gPipeline.markTextured(mDrawable);
+ mFaceMappingChanged = TRUE;
+ }
+ return res;
+}
+
+S32 LLVOVolume::setTEColor(const U8 te, const LLColor3& color)
+{
+ return setTEColor(te, LLColor4(color));
+}
+
+S32 LLVOVolume::setTEColor(const U8 te, const LLColor4& color)
+{
+ S32 retval = 0;
+ const LLTextureEntry *tep = getTE(te);
+ if (!tep)
+ {
+ llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl;
+ }
+ else if (color != tep->getColor())
+ {
+ if (color.mV[3] != tep->getColor().mV[3])
+ {
+ gPipeline.markTextured(mDrawable);
+ }
+ retval = LLPrimitive::setTEColor(te, color);
+ if (mDrawable.notNull() && retval)
+ {
+ // These should only happen on updates which are not the initial update.
+ mDrawable->setState(LLDrawable::REBUILD_COLOR);
+ dirtyMesh();
+ }
+ }
+
+ return retval;
+}
+
+S32 LLVOVolume::setTEBumpmap(const U8 te, const U8 bumpmap)
+{
+ S32 res = LLViewerObject::setTEBumpmap(te, bumpmap);
+ if (res)
+ {
+ gPipeline.markTextured(mDrawable);
+ mFaceMappingChanged = TRUE;
+ }
+ return res;
+}
+
+S32 LLVOVolume::setTETexGen(const U8 te, const U8 texgen)
+{
+ S32 res = LLViewerObject::setTETexGen(te, texgen);
+ if (res)
+ {
+ gPipeline.markTextured(mDrawable);
+ mFaceMappingChanged = TRUE;
+ }
+ return res;
+}
+
+S32 LLVOVolume::setTEMediaTexGen(const U8 te, const U8 media)
+{
+ S32 res = LLViewerObject::setTEMediaTexGen(te, media);
+ if (res)
+ {
+ gPipeline.markTextured(mDrawable);
+ mFaceMappingChanged = TRUE;
+ }
+ return res;
+}
+
+S32 LLVOVolume::setTEShiny(const U8 te, const U8 shiny)
+{
+ S32 res = LLViewerObject::setTEShiny(te, shiny);
+ if (res)
+ {
+ gPipeline.markTextured(mDrawable);
+ mFaceMappingChanged = TRUE;
+ }
+ return res;
+}
+
+S32 LLVOVolume::setTEFullbright(const U8 te, const U8 fullbright)
+{
+ S32 res = LLViewerObject::setTEFullbright(te, fullbright);
+ if (res)
+ {
+ gPipeline.markTextured(mDrawable);
+ mFaceMappingChanged = TRUE;
+ }
+ return res;
+}
+
+S32 LLVOVolume::setTEBumpShinyFullbright(const U8 te, const U8 bump)
+{
+ S32 res = LLViewerObject::setTEBumpShinyFullbright(te, bump);
+ if (res)
+ {
+ gPipeline.markTextured(mDrawable);
+ mFaceMappingChanged = TRUE;
+ }
+ return res;
+}
+
+S32 LLVOVolume::setTEMediaFlags(const U8 te, const U8 media_flags)
+{
+ S32 res = LLViewerObject::setTEMediaFlags(te, media_flags);
+ if (res)
+ {
+ gPipeline.markTextured(mDrawable);
+ mFaceMappingChanged = TRUE;
+ }
+ return res;
+}
+
+S32 LLVOVolume::setTEGlow(const U8 te, const F32 glow)
+{
+ S32 res = LLViewerObject::setTEGlow(te, glow);
+ if (res)
+ {
+ gPipeline.markTextured(mDrawable);
+ mFaceMappingChanged = TRUE;
+ }
+ return res;
+}
+
+S32 LLVOVolume::setTEScale(const U8 te, const F32 s, const F32 t)
+{
+ S32 res = LLViewerObject::setTEScale(te, s, t);
+ if (res)
+ {
+ gPipeline.markTextured(mDrawable);
+ mFaceMappingChanged = TRUE;
+ }
+ return res;
+}
+
+S32 LLVOVolume::setTEScaleS(const U8 te, const F32 s)
+{
+ S32 res = LLViewerObject::setTEScaleS(te, s);
+ if (res)
+ {
+ gPipeline.markTextured(mDrawable);
+ mFaceMappingChanged = TRUE;
+ }
+ return res;
+}
+
+S32 LLVOVolume::setTEScaleT(const U8 te, const F32 t)
+{
+ S32 res = LLViewerObject::setTEScaleT(te, t);
+ if (res)
+ {
+ gPipeline.markTextured(mDrawable);
+ mFaceMappingChanged = TRUE;
+ }
+ return res;
+}
+
+void LLVOVolume::updateTEData()
+{
+ /*if (mDrawable.notNull())
+ {
+ mFaceMappingChanged = TRUE;
+ gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_MATERIAL, TRUE);
+ }*/
+}
+
+bool LLVOVolume::hasMedia() const
+{
+ bool result = false;
+ const U8 numTEs = getNumTEs();
+ for (U8 i = 0; i < numTEs; i++)
+ {
+ const LLTextureEntry* te = getTE(i);
+ if(te->hasMedia())
+ {
+ result = true;
+ break;
+ }
+ }
+ return result;
+}
+
+LLVector3 LLVOVolume::getApproximateFaceNormal(U8 face_id)
+{
+ LLVolume* volume = getVolume();
+ LLVector4a result;
+ result.clear();
+
+ LLVector3 ret;
+
+ if (volume && face_id < volume->getNumVolumeFaces())
+ {
+ const LLVolumeFace& face = volume->getVolumeFace(face_id);
+ for (S32 i = 0; i < (S32)face.mNumVertices; ++i)
+ {
+ result.add(face.mNormals[i]);
+ }
+
+ LLVector3 ret(result.getF32ptr());
+ ret = volumeDirectionToAgent(ret);
+ ret.normVec();
+ }
+
+ return ret;
+}
+
+void LLVOVolume::requestMediaDataUpdate(bool isNew)
+{
+ if (sObjectMediaClient)
+ sObjectMediaClient->fetchMedia(new LLMediaDataClientObjectImpl(this, isNew));
+}
+
+bool LLVOVolume::isMediaDataBeingFetched() const
+{
+ // I know what I'm doing by const_casting this away: this is just
+ // a wrapper class that is only going to do a lookup.
+ return (sObjectMediaClient) ? sObjectMediaClient->isInQueue(new LLMediaDataClientObjectImpl(const_cast<LLVOVolume*>(this), false)) : false;
+}
+
+void LLVOVolume::cleanUpMediaImpls()
+{
+ // Iterate through our TEs and remove any Impls that are no longer used
+ const U8 numTEs = getNumTEs();
+ for (U8 i = 0; i < numTEs; i++)
+ {
+ const LLTextureEntry* te = getTE(i);
+ if( ! te->hasMedia())
+ {
+ // Delete the media IMPL!
+ removeMediaImpl(i) ;
+ }
+ }
+}
+
+void LLVOVolume::updateObjectMediaData(const LLSD &media_data_array, const std::string &media_version)
+{
+ // media_data_array is an array of media entry maps
+ // media_version is the version string in the response.
+ U32 fetched_version = LLTextureEntry::getVersionFromMediaVersionString(media_version);
+
+ // Only update it if it is newer!
+ if ( (S32)fetched_version > mLastFetchedMediaVersion)
+ {
+ mLastFetchedMediaVersion = fetched_version;
+ //llinfos << "updating:" << this->getID() << " " << ll_pretty_print_sd(media_data_array) << llendl;
+
+ LLSD::array_const_iterator iter = media_data_array.beginArray();
+ LLSD::array_const_iterator end = media_data_array.endArray();
+ U8 texture_index = 0;
+ for (; iter != end; ++iter, ++texture_index)
+ {
+ syncMediaData(texture_index, *iter, false/*merge*/, false/*ignore_agent*/);
+ }
+ }
+}
+
+void LLVOVolume::syncMediaData(S32 texture_index, const LLSD &media_data, bool merge, bool ignore_agent)
+{
+ if(mDead)
+ {
+ // If the object has been marked dead, don't process media updates.
+ return;
+ }
+
+ LLTextureEntry *te = getTE(texture_index);
+ if(!te)
+ {
+ return ;
+ }
+
+ LL_DEBUGS("MediaOnAPrim") << "BEFORE: texture_index = " << texture_index
+ << " hasMedia = " << te->hasMedia() << " : "
+ << ((NULL == te->getMediaData()) ? "NULL MEDIA DATA" : ll_pretty_print_sd(te->getMediaData()->asLLSD())) << llendl;
+
+ std::string previous_url;
+ LLMediaEntry* mep = te->getMediaData();
+ if(mep)
+ {
+ // Save the "current url" from before the update so we can tell if
+ // it changes.
+ previous_url = mep->getCurrentURL();
+ }
+
+ if (merge)
+ {
+ te->mergeIntoMediaData(media_data);
+ }
+ else {
+ // XXX Question: what if the media data is undefined LLSD, but the
+ // update we got above said that we have media flags?? Here we clobber
+ // that, assuming the data from the service is more up-to-date.
+ te->updateMediaData(media_data);
+ }
+
+ mep = te->getMediaData();
+ if(mep)
+ {
+ bool update_from_self = false;
+ if (!ignore_agent)
+ {
+ LLUUID updating_agent = LLTextureEntry::getAgentIDFromMediaVersionString(getMediaURL());
+ update_from_self = (updating_agent == gAgent.getID());
+ }
+ viewer_media_t media_impl = LLViewerMedia::updateMediaImpl(mep, previous_url, update_from_self);
+
+ addMediaImpl(media_impl, texture_index) ;
+ }
+ else
+ {
+ removeMediaImpl(texture_index);
+ }
+
+ LL_DEBUGS("MediaOnAPrim") << "AFTER: texture_index = " << texture_index
+ << " hasMedia = " << te->hasMedia() << " : "
+ << ((NULL == te->getMediaData()) ? "NULL MEDIA DATA" : ll_pretty_print_sd(te->getMediaData()->asLLSD())) << llendl;
+}
+
+void LLVOVolume::mediaNavigateBounceBack(U8 texture_index)
+{
+ // Find the media entry for this navigate
+ const LLMediaEntry* mep = NULL;
+ viewer_media_t impl = getMediaImpl(texture_index);
+ LLTextureEntry *te = getTE(texture_index);
+ if(te)
+ {
+ mep = te->getMediaData();
+ }
+
+ if (mep && impl)
+ {
+ std::string url = mep->getCurrentURL();
+ // Look for a ":", if not there, assume "http://"
+ if (!url.empty() && std::string::npos == url.find(':'))
+ {
+ url = "http://" + url;
+ }
+ // If the url we're trying to "bounce back" to is either empty or not
+ // allowed by the whitelist, try the home url. If *that* doesn't work,
+ // set the media as failed and unload it
+ if (url.empty() || !mep->checkCandidateUrl(url))
+ {
+ url = mep->getHomeURL();
+ // Look for a ":", if not there, assume "http://"
+ if (!url.empty() && std::string::npos == url.find(':'))
+ {
+ url = "http://" + url;
+ }
+ }
+ if (url.empty() || !mep->checkCandidateUrl(url))
+ {
+ // The url to navigate back to is not good, and we have nowhere else
+ // to go.
+ LL_WARNS("MediaOnAPrim") << "FAILED to bounce back URL \"" << url << "\" -- unloading impl" << LL_ENDL;
+ impl->setMediaFailed(true);
+ }
+ else {
+ // Okay, navigate now
+ LL_INFOS("MediaOnAPrim") << "bouncing back to URL: " << url << LL_ENDL;
+ impl->navigateTo(url, "", false, true);
+ }
+ }
+}
+
+bool LLVOVolume::hasMediaPermission(const LLMediaEntry* media_entry, MediaPermType perm_type)
+{
+ // NOTE: This logic ALMOST duplicates the logic in the server (in particular, in llmediaservice.cpp).
+ if (NULL == media_entry ) return false; // XXX should we assert here?
+
+ // The agent has permissions if:
+ // - world permissions are on, or
+ // - group permissions are on, and agent_id is in the group, or
+ // - agent permissions are on, and agent_id is the owner
+
+ // *NOTE: We *used* to check for modify permissions here (i.e. permissions were
+ // granted if permModify() was true). However, this doesn't make sense in the
+ // viewer: we don't want to show controls or allow interaction if the author
+ // has deemed it so. See DEV-42115.
+
+ U8 media_perms = (perm_type == MEDIA_PERM_INTERACT) ? media_entry->getPermsInteract() : media_entry->getPermsControl();
+
+ // World permissions
+ if (0 != (media_perms & LLMediaEntry::PERM_ANYONE))
+ {
+ return true;
+ }
+
+ // Group permissions
+ else if (0 != (media_perms & LLMediaEntry::PERM_GROUP))
+ {
+ LLPermissions* obj_perm = LLSelectMgr::getInstance()->findObjectPermissions(this);
+ if (obj_perm && gAgent.isInGroup(obj_perm->getGroup()))
+ {
+ return true;
+ }
+ }
+
+ // Owner permissions
+ else if (0 != (media_perms & LLMediaEntry::PERM_OWNER) && permYouOwner())
+ {
+ return true;
+ }
+
+ return false;
+
+}
+
+void LLVOVolume::mediaNavigated(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin, std::string new_location)
+{
+ bool block_navigation = false;
+ // FIXME: if/when we allow the same media impl to be used by multiple faces, the logic here will need to be fixed
+ // to deal with multiple face indices.
+ int face_index = getFaceIndexWithMediaImpl(impl, -1);
+
+ // Find the media entry for this navigate
+ LLMediaEntry* mep = NULL;
+ LLTextureEntry *te = getTE(face_index);
+ if(te)
+ {
+ mep = te->getMediaData();
+ }
+
+ if(mep)
+ {
+ if(!mep->checkCandidateUrl(new_location))
+ {
+ block_navigation = true;
+ }
+ if (!block_navigation && !hasMediaPermission(mep, MEDIA_PERM_INTERACT))
+ {
+ block_navigation = true;
+ }
+ }
+ else
+ {
+ LL_WARNS("MediaOnAPrim") << "Couldn't find media entry!" << LL_ENDL;
+ }
+
+ if(block_navigation)
+ {
+ LL_INFOS("MediaOnAPrim") << "blocking navigate to URI " << new_location << LL_ENDL;
+
+ // "bounce back" to the current URL from the media entry
+ mediaNavigateBounceBack(face_index);
+ }
+ else if (sObjectMediaNavigateClient)
+ {
+
+ LL_DEBUGS("MediaOnAPrim") << "broadcasting navigate with URI " << new_location << LL_ENDL;
+
+ sObjectMediaNavigateClient->navigate(new LLMediaDataClientObjectImpl(this, false), face_index, new_location);
+ }
+}
+
+void LLVOVolume::mediaEvent(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin, LLViewerMediaObserver::EMediaEvent event)
+{
+ switch(event)
+ {
+
+ case LLViewerMediaObserver::MEDIA_EVENT_LOCATION_CHANGED:
+ {
+ switch(impl->getNavState())
+ {
+ case LLViewerMediaImpl::MEDIANAVSTATE_FIRST_LOCATION_CHANGED:
+ {
+ // This is the first location changed event after the start of a non-server-directed nav. It may need to be broadcast or bounced back.
+ mediaNavigated(impl, plugin, plugin->getLocation());
+ }
+ break;
+
+ case LLViewerMediaImpl::MEDIANAVSTATE_FIRST_LOCATION_CHANGED_SPURIOUS:
+ // This navigate didn't change the current URL.
+ LL_DEBUGS("MediaOnAPrim") << " NOT broadcasting navigate (spurious)" << LL_ENDL;
+ break;
+
+ case LLViewerMediaImpl::MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED:
+ // This is the first location changed event after the start of a server-directed nav. Don't broadcast it.
+ LL_INFOS("MediaOnAPrim") << " NOT broadcasting navigate (server-directed)" << LL_ENDL;
+ break;
+
+ default:
+ // This is a subsequent location-changed due to a redirect. Don't broadcast.
+ LL_INFOS("MediaOnAPrim") << " NOT broadcasting navigate (redirect)" << LL_ENDL;
+ break;
+ }
+ }
+ break;
+
+ case LLViewerMediaObserver::MEDIA_EVENT_NAVIGATE_COMPLETE:
+ {
+ switch(impl->getNavState())
+ {
+ case LLViewerMediaImpl::MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED:
+ {
+ // This is the first location changed event after the start of a non-server-directed nav. It may need to be broadcast or bounced back.
+ mediaNavigated(impl, plugin, plugin->getNavigateURI());
+ }
+ break;
+
+ case LLViewerMediaImpl::MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED_SPURIOUS:
+ // This navigate didn't change the current URL.
+ LL_DEBUGS("MediaOnAPrim") << " NOT broadcasting navigate (spurious)" << LL_ENDL;
+ break;
+
+ case LLViewerMediaImpl::MEDIANAVSTATE_SERVER_COMPLETE_BEFORE_LOCATION_CHANGED:
+ // This is the the navigate complete event from a server-directed nav. Don't broadcast it.
+ LL_INFOS("MediaOnAPrim") << " NOT broadcasting navigate (server-directed)" << LL_ENDL;
+ break;
+
+ default:
+ // For all other states, the navigate should have been handled by LOCATION_CHANGED events already.
+ break;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+}
+
+void LLVOVolume::sendMediaDataUpdate()
+{
+ if (sObjectMediaClient)
+ sObjectMediaClient->updateMedia(new LLMediaDataClientObjectImpl(this, false));
+}
+
+void LLVOVolume::removeMediaImpl(S32 texture_index)
+{
+ if(mMediaImplList.size() <= (U32)texture_index || mMediaImplList[texture_index].isNull())
+ {
+ return ;
+ }
+
+ //make the face referencing to mMediaImplList[texture_index] to point back to the old texture.
+ if(mDrawable && texture_index < mDrawable->getNumFaces())
+ {
+ LLFace* facep = mDrawable->getFace(texture_index) ;
+ if(facep)
+ {
+ LLViewerMediaTexture* media_tex = LLViewerTextureManager::findMediaTexture(mMediaImplList[texture_index]->getMediaTextureID()) ;
+ if(media_tex)
+ {
+ media_tex->removeMediaFromFace(facep) ;
+ }
+ }
+ }
+
+ //check if some other face(s) of this object reference(s)to this media impl.
+ S32 i ;
+ S32 end = (S32)mMediaImplList.size() ;
+ for(i = 0; i < end ; i++)
+ {
+ if( i != texture_index && mMediaImplList[i] == mMediaImplList[texture_index])
+ {
+ break ;
+ }
+ }
+
+ if(i == end) //this object does not need this media impl.
+ {
+ mMediaImplList[texture_index]->removeObject(this) ;
+ }
+
+ mMediaImplList[texture_index] = NULL ;
+ return ;
+}
+
+void LLVOVolume::addMediaImpl(LLViewerMediaImpl* media_impl, S32 texture_index)
+{
+ if((S32)mMediaImplList.size() < texture_index + 1)
+ {
+ mMediaImplList.resize(texture_index + 1) ;
+ }
+
+ if(mMediaImplList[texture_index].notNull())
+ {
+ if(mMediaImplList[texture_index] == media_impl)
+ {
+ return ;
+ }
+
+ removeMediaImpl(texture_index) ;
+ }
+
+ mMediaImplList[texture_index] = media_impl;
+ media_impl->addObject(this) ;
+
+ //add the face to show the media if it is in playing
+ if(mDrawable)
+ {
+ LLFace* facep = mDrawable->getFace(texture_index) ;
+ if(facep)
+ {
+ LLViewerMediaTexture* media_tex = LLViewerTextureManager::findMediaTexture(mMediaImplList[texture_index]->getMediaTextureID()) ;
+ if(media_tex)
+ {
+ media_tex->addMediaToFace(facep) ;
+ }
+ }
+ else //the face is not available now, start media on this face later.
+ {
+ media_impl->setUpdated(TRUE) ;
+ }
+ }
+ return ;
+}
+
+viewer_media_t LLVOVolume::getMediaImpl(U8 face_id) const
+{
+ if(mMediaImplList.size() > face_id)
+ {
+ return mMediaImplList[face_id];
+ }
+ return NULL;
+}
+
+F64 LLVOVolume::getTotalMediaInterest() const
+{
+ // If this object is currently focused, this object has "high" interest
+ if (LLViewerMediaFocus::getInstance()->getFocusedObjectID() == getID())
+ return F64_MAX;
+
+ F64 interest = (F64)-1.0; // means not interested;
+
+ // If this object is selected, this object has "high" interest, but since
+ // there can be more than one, we still add in calculated impl interest
+ // XXX Sadly, 'contains()' doesn't take a const :(
+ if (LLSelectMgr::getInstance()->getSelection()->contains(const_cast<LLVOVolume*>(this)))
+ interest = F64_MAX / 2.0;
+
+ int i = 0;
+ const int end = getNumTEs();
+ for ( ; i < end; ++i)
+ {
+ const viewer_media_t &impl = getMediaImpl(i);
+ if (!impl.isNull())
+ {
+ if (interest == (F64)-1.0) interest = (F64)0.0;
+ interest += impl->getInterest();
+ }
+ }
+ return interest;
+}
+
+S32 LLVOVolume::getFaceIndexWithMediaImpl(const LLViewerMediaImpl* media_impl, S32 start_face_id)
+{
+ S32 end = (S32)mMediaImplList.size() ;
+ for(S32 face_id = start_face_id + 1; face_id < end; face_id++)
+ {
+ if(mMediaImplList[face_id] == media_impl)
+ {
+ return face_id ;
+ }
+ }
+ return -1 ;
+}
+
+//----------------------------------------------------------------------------
+
+void LLVOVolume::setLightTextureID(LLUUID id)
+{
+ if (id.notNull())
+ {
+ if (!hasLightTexture())
+ {
+ setParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE, TRUE, true);
+ }
+ LLLightImageParams* param_block = (LLLightImageParams*) getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE);
+ if (param_block && param_block->getLightTexture() != id)
+ {
+ param_block->setLightTexture(id);
+ parameterChanged(LLNetworkData::PARAMS_LIGHT_IMAGE, true);
+ }
+ }
+ else
+ {
+ if (hasLightTexture())
+ {
+ setParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE, FALSE, true);
+ mLightTexture = NULL;
+ }
+ }
+}
+
+void LLVOVolume::setSpotLightParams(LLVector3 params)
+{
+ LLLightImageParams* param_block = (LLLightImageParams*) getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE);
+ if (param_block && param_block->getParams() != params)
+ {
+ param_block->setParams(params);
+ parameterChanged(LLNetworkData::PARAMS_LIGHT_IMAGE, true);
+ }
+}
+
+void LLVOVolume::setIsLight(BOOL is_light)
+{
+ if (is_light != getIsLight())
+ {
+ if (is_light)
+ {
+ setParameterEntryInUse(LLNetworkData::PARAMS_LIGHT, TRUE, true);
+ }
+ else
+ {
+ setParameterEntryInUse(LLNetworkData::PARAMS_LIGHT, FALSE, true);
+ }
+
+ if (is_light)
+ {
+ // Add it to the pipeline mLightSet
+ gPipeline.setLight(mDrawable, TRUE);
+ }
+ else
+ {
+ // Not a light. Remove it from the pipeline's light set.
+ gPipeline.setLight(mDrawable, FALSE);
+ }
+ }
+}
+
+void LLVOVolume::setLightColor(const LLColor3& color)
+{
+ LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
+ if (param_block)
+ {
+ if (param_block->getColor() != color)
+ {
+ param_block->setColor(LLColor4(color, param_block->getColor().mV[3]));
+ parameterChanged(LLNetworkData::PARAMS_LIGHT, true);
+ gPipeline.markTextured(mDrawable);
+ mFaceMappingChanged = TRUE;
+ }
+ }
+}
+
+void LLVOVolume::setLightIntensity(F32 intensity)
+{
+ LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
+ if (param_block)
+ {
+ if (param_block->getColor().mV[3] != intensity)
+ {
+ param_block->setColor(LLColor4(LLColor3(param_block->getColor()), intensity));
+ parameterChanged(LLNetworkData::PARAMS_LIGHT, true);
+ }
+ }
+}
+
+void LLVOVolume::setLightRadius(F32 radius)
+{
+ LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
+ if (param_block)
+ {
+ if (param_block->getRadius() != radius)
+ {
+ param_block->setRadius(radius);
+ parameterChanged(LLNetworkData::PARAMS_LIGHT, true);
+ }
+ }
+}
+
+void LLVOVolume::setLightFalloff(F32 falloff)
+{
+ LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
+ if (param_block)
+ {
+ if (param_block->getFalloff() != falloff)
+ {
+ param_block->setFalloff(falloff);
+ parameterChanged(LLNetworkData::PARAMS_LIGHT, true);
+ }
+ }
+}
+
+void LLVOVolume::setLightCutoff(F32 cutoff)
+{
+ LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
+ if (param_block)
+ {
+ if (param_block->getCutoff() != cutoff)
+ {
+ param_block->setCutoff(cutoff);
+ parameterChanged(LLNetworkData::PARAMS_LIGHT, true);
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+
+BOOL LLVOVolume::getIsLight() const
+{
+ return getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT);
+}
+
+LLColor3 LLVOVolume::getLightBaseColor() const
+{
+ const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
+ if (param_block)
+ {
+ return LLColor3(param_block->getColor());
+ }
+ else
+ {
+ return LLColor3(1,1,1);
+ }
+}
+
+LLColor3 LLVOVolume::getLightColor() const
+{
+ const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
+ if (param_block)
+ {
+ return LLColor3(param_block->getColor()) * param_block->getColor().mV[3];
+ }
+ else
+ {
+ return LLColor3(1,1,1);
+ }
+}
+
+LLUUID LLVOVolume::getLightTextureID() const
+{
+ if (getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE))
+ {
+ const LLLightImageParams *param_block = (const LLLightImageParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE);
+ if (param_block)
+ {
+ return param_block->getLightTexture();
+ }
+ }
+
+ return LLUUID::null;
+}
+
+
+LLVector3 LLVOVolume::getSpotLightParams() const
+{
+ if (getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE))
+ {
+ const LLLightImageParams *param_block = (const LLLightImageParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE);
+ if (param_block)
+ {
+ return param_block->getParams();
+ }
+ }
+
+ return LLVector3();
+}
+
+F32 LLVOVolume::getSpotLightPriority() const
+{
+ return mSpotLightPriority;
+}
+
+void LLVOVolume::updateSpotLightPriority()
+{
+ LLVector3 pos = mDrawable->getPositionAgent();
+ LLVector3 at(0,0,-1);
+ at *= getRenderRotation();
+
+ F32 r = getLightRadius()*0.5f;
+
+ pos += at * r;
+
+ at = LLViewerCamera::getInstance()->getAtAxis();
+
+ pos -= at * r;
+
+ mSpotLightPriority = gPipeline.calcPixelArea(pos, LLVector3(r,r,r), *LLViewerCamera::getInstance());
+
+ if (mLightTexture.notNull())
+ {
+ mLightTexture->addTextureStats(mSpotLightPriority);
+ mLightTexture->setBoostLevel(LLViewerTexture::BOOST_CLOUDS);
+ }
+}
+
+
+bool LLVOVolume::isLightSpotlight() const
+{
+ LLLightImageParams* params = (LLLightImageParams*) getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE);
+ if (params)
+ {
+ return params->isLightSpotlight();
+ }
+ return false;
+}
+
+
+LLViewerTexture* LLVOVolume::getLightTexture()
+{
+ LLUUID id = getLightTextureID();
+
+ if (id.notNull())
+ {
+ if (mLightTexture.isNull() || id != mLightTexture->getID())
+ {
+ mLightTexture = LLViewerTextureManager::getFetchedTexture(id);
+ }
+ }
+ else
+ {
+ mLightTexture = NULL;
+ }
+
+ return mLightTexture;
+}
+
+F32 LLVOVolume::getLightIntensity() const
+{
+ const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
+ if (param_block)
+ {
+ return param_block->getColor().mV[3];
+ }
+ else
+ {
+ return 1.f;
+ }
+}
+
+F32 LLVOVolume::getLightRadius() const
+{
+ const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
+ if (param_block)
+ {
+ return param_block->getRadius();
+ }
+ else
+ {
+ return 0.f;
+ }
+}
+
+F32 LLVOVolume::getLightFalloff() const
+{
+ const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
+ if (param_block)
+ {
+ return param_block->getFalloff();
+ }
+ else
+ {
+ return 0.f;
+ }
+}
+
+F32 LLVOVolume::getLightCutoff() const
+{
+ const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
+ if (param_block)
+ {
+ return param_block->getCutoff();
+ }
+ else
+ {
+ return 0.f;
+ }
+}
+
+U32 LLVOVolume::getVolumeInterfaceID() const
+{
+ if (mVolumeImpl)
+ {
+ return mVolumeImpl->getID();
+ }
+
+ return 0;
+}
+
+BOOL LLVOVolume::isFlexible() const
+{
+ if (getParameterEntryInUse(LLNetworkData::PARAMS_FLEXIBLE))
+ {
+ LLVolume* volume = getVolume();
+ if (volume && volume->getParams().getPathParams().getCurveType() != LL_PCODE_PATH_FLEXIBLE)
+ {
+ LLVolumeParams volume_params = getVolume()->getParams();
+ U8 profile_and_hole = volume_params.getProfileParams().getCurveType();
+ volume_params.setType(profile_and_hole, LL_PCODE_PATH_FLEXIBLE);
+ }
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+BOOL LLVOVolume::isSculpted() const
+{
+ if (getParameterEntryInUse(LLNetworkData::PARAMS_SCULPT))
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+BOOL LLVOVolume::isMesh() const
+{
+ if (isSculpted())
+ {
+ LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT);
+ U8 sculpt_type = sculpt_params->getSculptType();
+
+ if ((sculpt_type & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)
+ // mesh is a mesh
+ {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+BOOL LLVOVolume::hasLightTexture() const
+{
+ if (getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE))
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+BOOL LLVOVolume::isVolumeGlobal() const
+{
+ if (mVolumeImpl)
+ {
+ return mVolumeImpl->isVolumeGlobal() ? TRUE : FALSE;
+ }
+ else if (mRiggedVolume.notNull())
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+BOOL LLVOVolume::canBeFlexible() const
+{
+ U8 path = getVolume()->getParams().getPathParams().getCurveType();
+ return (path == LL_PCODE_PATH_FLEXIBLE || path == LL_PCODE_PATH_LINE);
+}
+
+BOOL LLVOVolume::setIsFlexible(BOOL is_flexible)
+{
+ BOOL res = FALSE;
+ BOOL was_flexible = isFlexible();
+ LLVolumeParams volume_params;
+ if (is_flexible)
+ {
+ if (!was_flexible)
+ {
+ volume_params = getVolume()->getParams();
+ U8 profile_and_hole = volume_params.getProfileParams().getCurveType();
+ volume_params.setType(profile_and_hole, LL_PCODE_PATH_FLEXIBLE);
+ res = TRUE;
+ setFlags(FLAGS_USE_PHYSICS, FALSE);
+ setFlags(FLAGS_PHANTOM, TRUE);
+ setParameterEntryInUse(LLNetworkData::PARAMS_FLEXIBLE, TRUE, true);
+ if (mDrawable)
+ {
+ mDrawable->makeActive();
+ }
+ }
+ }
+ else
+ {
+ if (was_flexible)
+ {
+ volume_params = getVolume()->getParams();
+ U8 profile_and_hole = volume_params.getProfileParams().getCurveType();
+ volume_params.setType(profile_and_hole, LL_PCODE_PATH_LINE);
+ res = TRUE;
+ setFlags(FLAGS_PHANTOM, FALSE);
+ setParameterEntryInUse(LLNetworkData::PARAMS_FLEXIBLE, FALSE, true);
+ }
+ }
+ if (res)
+ {
+ res = setVolume(volume_params, 1);
+ if (res)
+ {
+ markForUpdate(TRUE);
+ }
+ }
+ return res;
+}
+
+//----------------------------------------------------------------------------
+
+void LLVOVolume::generateSilhouette(LLSelectNode* nodep, const LLVector3& view_point)
+{
+ LLVolume *volume = getVolume();
+
+ if (volume)
+ {
+ LLVector3 view_vector;
+ view_vector = view_point;
+
+ //transform view vector into volume space
+ view_vector -= getRenderPosition();
+ mDrawable->mDistanceWRTCamera = view_vector.length();
+ LLQuaternion worldRot = getRenderRotation();
+ view_vector = view_vector * ~worldRot;
+ if (!isVolumeGlobal())
+ {
+ LLVector3 objScale = getScale();
+ LLVector3 invObjScale(1.f / objScale.mV[VX], 1.f / objScale.mV[VY], 1.f / objScale.mV[VZ]);
+ view_vector.scaleVec(invObjScale);
+ }
+
+ updateRelativeXform();
+ LLMatrix4 trans_mat = mRelativeXform;
+ if (mDrawable->isStatic())
+ {
+ trans_mat.translate(getRegion()->getOriginAgent());
+ }
+
+ volume->generateSilhouetteVertices(nodep->mSilhouetteVertices, nodep->mSilhouetteNormals, view_vector, trans_mat, mRelativeXformInvTrans, nodep->getTESelectMask());
+
+ nodep->mSilhouetteExists = TRUE;
+ }
+}
+
+void LLVOVolume::deleteFaces()
+{
+ S32 face_count = mNumFaces;
+ if (mDrawable.notNull())
+ {
+ mDrawable->deleteFaces(0, face_count);
+ }
+
+ mNumFaces = 0;
+}
+
+void LLVOVolume::updateRadius()
+{
+ if (mDrawable.isNull())
+ {
+ return;
+ }
+
+ mVObjRadius = getScale().length();
+ mDrawable->setRadius(mVObjRadius);
+}
+
+
+BOOL LLVOVolume::isAttachment() const
+{
+ return mState != 0 ;
+}
+
+BOOL LLVOVolume::isHUDAttachment() const
+{
+ // *NOTE: we assume hud attachment points are in defined range
+ // since this range is constant for backwards compatibility
+ // reasons this is probably a reasonable assumption to make
+ S32 attachment_id = ATTACHMENT_ID_FROM_STATE(mState);
+ return ( attachment_id >= 31 && attachment_id <= 38 );
+}
+
+
+const LLMatrix4 LLVOVolume::getRenderMatrix() const
+{
+ if (mDrawable->isActive() && !mDrawable->isRoot())
+ {
+ return mDrawable->getParent()->getWorldMatrix();
+ }
+ return mDrawable->getWorldMatrix();
+}
+
+// Returns a base cost and adds textures to passed in set.
+// total cost is returned value + 5 * size of the resulting set.
+// Cannot include cost of textures, as they may be re-used in linked
+// children, and cost should only be increased for unique textures -Nyx
+U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const
+{
+ // Get access to params we'll need at various points.
+ // Skip if this is object doesn't have a volume (e.g. is an avatar).
+ BOOL has_volume = (getVolume() != NULL);
+ LLVolumeParams volume_params;
+ LLPathParams path_params;
+ LLProfileParams profile_params;
+
+ U32 num_triangles = 0;
+
+ // per-prim costs
+ static const U32 ARC_PARTICLE_COST = 1; // determined experimentally
+ static const U32 ARC_PARTICLE_MAX = 2048; // default values
+ static const U32 ARC_TEXTURE_COST = 16; // multiplier for texture resolution - performance tested
+
+ // per-prim multipliers
+ static const F32 ARC_GLOW_MULT = 1.5f; // tested based on performance
+ static const F32 ARC_BUMP_MULT = 1.25f; // tested based on performance
+ static const F32 ARC_FLEXI_MULT = 5; // tested based on performance
+ static const F32 ARC_SHINY_MULT = 1.6f; // tested based on performance
+ static const F32 ARC_INVISI_COST = 1.2f; // tested based on performance
+ static const F32 ARC_WEIGHTED_MESH = 1.2f; // tested based on performance
+
+ static const F32 ARC_PLANAR_COST = 1.0f; // tested based on performance to have negligible impact
+ static const F32 ARC_ANIM_TEX_COST = 1.4f; // 1.4x max
+ static const F32 ARC_ALPHA_COST = 4.f; // 4x max - based on performance
+
+ F32 shame = 0;
+
+ U32 invisi = 0;
+ U32 shiny = 0;
+ U32 glow = 0;
+ U32 alpha = 0;
+ U32 flexi = 0;
+ U32 animtex = 0;
+ U32 particles = 0;
+ U32 bump = 0;
+ U32 planar = 0;
+ U32 weighted_mesh = 0;
+
+ // these multipliers are variable and can be floating point
+ F32 scale = 0.f;
+
+ const LLDrawable* drawablep = mDrawable;
+ U32 num_faces = drawablep->getNumFaces();
+
+ if (has_volume)
+ {
+ volume_params = getVolume()->getParams();
+ path_params = volume_params.getPathParams();
+ profile_params = volume_params.getProfileParams();
+
+ F32 radius = getVolume()->mLODScaleBias.scaledVec(getScale()).length();
+ S32 default_detail = llclamp((S32) (sqrtf(radius)*LLVOVolume::sLODFactor*4.f), 0, 3);
+ if (default_detail == getLOD())
+ {
+ num_triangles = getTriangleCount();
+ }
+ else
+ {
+ LLVolume* default_volume = LLPrimitive::getVolumeManager()->refVolume(volume_params, default_detail);
+ if(default_volume != NULL)
+ {
+ num_triangles = default_volume->getNumTriangles();
+ LLPrimitive::getVolumeManager()->unrefVolume(default_volume);
+ default_volume = NULL;
+ }
+ else
+ {
+ has_volume = false;
+ }
+ }
+ }
+
+ if (isSculpted())
+ {
+ if (isMesh())
+ {
+ // base cost is dependent on mesh complexity
+ // note that 3 is the highest LOD as of the time of this coding.
+ S32 size = gMeshRepo.getMeshSize(volume_params.getSculptID(),3);
+ if ( size > 0)
+ {
+ num_triangles = (U32)(size / 10.f); // avg 1 triangle per 10 bytes
+ if (gMeshRepo.getSkinInfo(volume_params.getSculptID()))
+ {
+ // weighted attachment - 1 point for every 3 bytes
+ weighted_mesh = 1;
+ }
+
+ if (num_triangles == 0)
+ {
+ // someone made a really tiny mesh. Approximate with a tetrahedron.
+ num_triangles = 4;
+ }
+ }
+ else
+ {
+ // something went wrong - user should know their content isn't render-free
+ return 0;
+ }
+ }
+ else
+ {
+ const LLSculptParams *sculpt_params = (LLSculptParams *) getParameterEntry(LLNetworkData::PARAMS_SCULPT);
+ LLUUID sculpt_id = sculpt_params->getSculptTexture();
+ if (textures.find(sculpt_id) == textures.end())
+ {
+ LLViewerFetchedTexture *texture = LLViewerTextureManager::getFetchedTexture(sculpt_id);
+ if (texture)
+ {
+ S32 texture_cost = 256 + (S32)(ARC_TEXTURE_COST * (texture->getFullHeight() / 128.f + texture->getFullWidth() / 128.f));
+ textures.insert(texture_cost_t::value_type(sculpt_id, texture_cost));
+ }
+ }
+ }
+ }
+
+ if (isFlexible())
+ {
+ flexi = 1;
+ }
+ if (isParticleSource())
+ {
+ particles = 1;
+ }
+
+ const LLVector3& sc = getScale();
+ scale += (sc.mV[0] + sc.mV[1] + sc.mV[2]) / 4.f; // scale to 1/4 the sum of the size
+ // enforce scale multiplier to be in the range [1,7] (7 was determined to experimentally be a reasonable max)
+ scale = scale > 7.f ? 7.f : scale;
+ scale = scale < 1.f ? 1.f : scale;
+
+ for (S32 i = 0; i < num_faces; ++i)
+ {
+ const LLFace* face = drawablep->getFace(i);
+ const LLTextureEntry* te = face->getTextureEntry();
+ const LLViewerTexture* img = face->getTexture();
+
+ if (img)
+ {
+ if (textures.find(img->getID()) == textures.end())
+ {
+ S32 texture_cost = 256 + (S32)(ARC_TEXTURE_COST * (img->getFullHeight() / 128.f + img->getFullWidth() / 128.f));
+ textures.insert(texture_cost_t::value_type(img->getID(), texture_cost));
+ }
+ }
+
+ if (face->getPoolType() == LLDrawPool::POOL_ALPHA)
+ {
+ alpha = 1;
+ }
+ else if (img && img->getPrimaryFormat() == GL_ALPHA)
+ {
+ invisi = 1;
+ }
+
+ if (te)
+ {
+ if (te->getBumpmap())
+ {
+ // bump is a multiplier, don't add per-face
+ bump = 1;
+ }
+ if (te->getShiny())
+ {
+ // shiny is a multiplier, don't add per-face
+ shiny = 1;
+ }
+ if (te->getGlow() > 0.f)
+ {
+ // glow is a multiplier, don't add per-face
+ glow = 1;
+ }
+ if (face->mTextureMatrix != NULL)
+ {
+ animtex = 1;
+ }
+ if (te->getTexGen())
+ {
+ planar = 1;
+ }
+ }
+ }
+
+ // shame currently has the "base" cost of 1 point per 15 triangles, min 2.
+ shame = num_triangles / 15.f;
+ shame = shame < 2.f ? 2.f : shame;
+
+ // factor in scale
+ shame *= scale;
+
+ // multiply by per-face modifiers
+ if (planar)
+ {
+ shame *= planar * ARC_PLANAR_COST;
+ }
+
+ if (animtex)
+ {
+ shame *= animtex * ARC_ANIM_TEX_COST;
+ }
+
+ if (alpha)
+ {
+ shame *= alpha * ARC_ALPHA_COST;
+ }
+
+ if(invisi)
+ {
+ shame *= invisi * ARC_INVISI_COST;
+ }
+
+ if (glow)
+ {
+ shame *= glow * ARC_GLOW_MULT;
+ }
+
+ if (bump)
+ {
+ shame *= bump * ARC_BUMP_MULT;
+ }
+
+ if (shiny)
+ {
+ shame *= shiny * ARC_SHINY_MULT;
+ }
+
+
+ // multiply shame by multipliers
+ if (weighted_mesh)
+ {
+ shame *= weighted_mesh * ARC_WEIGHTED_MESH;
+ }
+
+ if (flexi)
+ {
+ shame *= flexi * ARC_FLEXI_MULT;
+ }
+
+
+ // add additional costs
+ if (particles)
+ {
+ const LLPartSysData *part_sys_data = &(mPartSourcep->mPartSysData);
+ const LLPartData *part_data = &(part_sys_data->mPartData);
+ U32 num_particles = (U32)(part_sys_data->mBurstPartCount * llceil( part_data->mMaxAge / part_sys_data->mBurstRate));
+ num_particles = num_particles > ARC_PARTICLE_MAX ? ARC_PARTICLE_MAX : num_particles;
+ F32 part_size = (llmax(part_data->mStartScale[0], part_data->mEndScale[0]) + llmax(part_data->mStartScale[1], part_data->mEndScale[1])) / 2.f;
+ shame += num_particles * part_size * ARC_PARTICLE_COST;
+ }
+
+ if (shame > mRenderComplexity_current)
+ {
+ mRenderComplexity_current = (S32)shame;
+ }
+
+ return (U32)shame;
+}
+
+F32 LLVOVolume::getStreamingCost(S32* bytes, S32* visible_bytes)
+{
+ F32 radius = getScale().length()*0.5f;
+
+ if (isMesh())
+ {
+ LLSD& header = gMeshRepo.getMeshHeader(getVolume()->getParams().getSculptID());
+
+ return LLMeshRepository::getStreamingCost(header, radius, bytes, visible_bytes, mLOD);
+ }
+ else
+ {
+ LLVolume* volume = getVolume();
+ S32 counts[4];
+ LLVolume::getLoDTriangleCounts(volume->getParams(), counts);
+
+ LLSD header;
+ header["lowest_lod"]["size"] = counts[0] * 10;
+ header["low_lod"]["size"] = counts[1] * 10;
+ header["medium_lod"]["size"] = counts[2] * 10;
+ header["high_lod"]["size"] = counts[3] * 10;
+
+ return LLMeshRepository::getStreamingCost(header, radius);
+ }
+}
+
+//static
+void LLVOVolume::updateRenderComplexity()
+{
+ mRenderComplexity_last = mRenderComplexity_current;
+ mRenderComplexity_current = 0;
+}
+
+U32 LLVOVolume::getTriangleCount() const
+{
+ U32 count = 0;
+ LLVolume* volume = getVolume();
+ if (volume)
+ {
+ count = volume->getNumTriangles();
+ }
+
+ return count;
+}
+
+U32 LLVOVolume::getHighLODTriangleCount()
+{
+ U32 ret = 0;
+
+ LLVolume* volume = getVolume();
+
+ if (!isSculpted())
+ {
+ LLVolume* ref = LLPrimitive::getVolumeManager()->refVolume(volume->getParams(), 3);
+ ret = ref->getNumTriangles();
+ LLPrimitive::getVolumeManager()->unrefVolume(ref);
+ }
+ else if (isMesh())
+ {
+ LLVolume* ref = LLPrimitive::getVolumeManager()->refVolume(volume->getParams(), 3);
+ if (ref->isTetrahedron() || ref->getNumVolumeFaces() == 0)
+ {
+ gMeshRepo.loadMesh(this, volume->getParams(), LLModel::LOD_HIGH);
+ }
+ ret = ref->getNumTriangles();
+ LLPrimitive::getVolumeManager()->unrefVolume(ref);
+ }
+ else
+ { //default sculpts have a constant number of triangles
+ ret = 31*2*31; //31 rows of 31 columns of quads for a 32x32 vertex patch
+ }
+
+ return ret;
+}
+
+//static
+void LLVOVolume::preUpdateGeom()
+{
+ sNumLODChanges = 0;
+}
+
+void LLVOVolume::parameterChanged(U16 param_type, bool local_origin)
+{
+ LLViewerObject::parameterChanged(param_type, local_origin);
+}
+
+void LLVOVolume::parameterChanged(U16 param_type, LLNetworkData* data, BOOL in_use, bool local_origin)
+{
+ LLViewerObject::parameterChanged(param_type, data, in_use, local_origin);
+ if (mVolumeImpl)
+ {
+ mVolumeImpl->onParameterChanged(param_type, data, in_use, local_origin);
+ }
+ if (mDrawable.notNull())
+ {
+ BOOL is_light = getIsLight();
+ if (is_light != mDrawable->isState(LLDrawable::LIGHT))
+ {
+ gPipeline.setLight(mDrawable, is_light);
+ }
+ }
+}
+
+void LLVOVolume::setSelected(BOOL sel)
+{
+ LLViewerObject::setSelected(sel);
+ if (mDrawable.notNull())
+ {
+ markForUpdate(TRUE);
+ }
+}
+
+void LLVOVolume::updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
+{
+}
+
+F32 LLVOVolume::getBinRadius()
+{
+ F32 radius;
+
+ F32 scale = 1.f;
+
+ S32 size_factor = llmax(gSavedSettings.getS32("OctreeStaticObjectSizeFactor"), 1);
+ S32 attachment_size_factor = llmax(gSavedSettings.getS32("OctreeAttachmentSizeFactor"), 1);
+ LLVector3 distance_factor = gSavedSettings.getVector3("OctreeDistanceFactor");
+ LLVector3 alpha_distance_factor = gSavedSettings.getVector3("OctreeAlphaDistanceFactor");
+ const LLVector4a* ext = mDrawable->getSpatialExtents();
+
+ BOOL shrink_wrap = mDrawable->isAnimating();
+ BOOL alpha_wrap = FALSE;
+
+ if (!isHUDAttachment())
+ {
+ for (S32 i = 0; i < mDrawable->getNumFaces(); i++)
+ {
+ LLFace* face = mDrawable->getFace(i);
+ if (face->getPoolType() == LLDrawPool::POOL_ALPHA &&
+ !face->canRenderAsMask())
+ {
+ alpha_wrap = TRUE;
+ break;
+ }
+ }
+ }
+ else
+ {
+ shrink_wrap = FALSE;
+ }
+
+ if (alpha_wrap)
+ {
+ LLVector3 bounds = getScale();
+ radius = llmin(bounds.mV[1], bounds.mV[2]);
+ radius = llmin(radius, bounds.mV[0]);
+ radius *= 0.5f;
+ radius *= 1.f+mDrawable->mDistanceWRTCamera*alpha_distance_factor[1];
+ radius += mDrawable->mDistanceWRTCamera*alpha_distance_factor[0];
+ }
+ else if (shrink_wrap)
+ {
+ LLVector4a rad;
+ rad.setSub(ext[1], ext[0]);
+
+ radius = rad.getLength3().getF32()*0.5f;
+ }
+ else if (mDrawable->isStatic())
+ {
+ radius = llmax((S32) mDrawable->getRadius(), 1)*size_factor;
+ radius *= 1.f + mDrawable->mDistanceWRTCamera * distance_factor[1];
+ radius += mDrawable->mDistanceWRTCamera * distance_factor[0];
+ }
+ else if (mDrawable->getVObj()->isAttachment())
+ {
+ radius = llmax((S32) mDrawable->getRadius(),1)*attachment_size_factor;
+ }
+ else
+ {
+ radius = mDrawable->getRadius();
+ radius *= 1.f + mDrawable->mDistanceWRTCamera * distance_factor[1];
+ radius += mDrawable->mDistanceWRTCamera * distance_factor[0];
+ }
+
+ return llclamp(radius*scale, 0.5f, 256.f);
+}
+
+const LLVector3 LLVOVolume::getPivotPositionAgent() const
+{
+ if (mVolumeImpl)
+ {
+ return mVolumeImpl->getPivotPosition();
+ }
+ return LLViewerObject::getPivotPositionAgent();
+}
+
+void LLVOVolume::onShift(const LLVector4a &shift_vector)
+{
+ if (mVolumeImpl)
+ {
+ mVolumeImpl->onShift(shift_vector);
+ }
+
+ updateRelativeXform();
+}
+
+const LLMatrix4& LLVOVolume::getWorldMatrix(LLXformMatrix* xform) const
+{
+ if (mVolumeImpl)
+ {
+ return mVolumeImpl->getWorldMatrix(xform);
+ }
+ return xform->getWorldMatrix();
+}
+
+LLVector3 LLVOVolume::agentPositionToVolume(const LLVector3& pos) const
+{
+ LLVector3 ret = pos - getRenderPosition();
+ ret = ret * ~getRenderRotation();
+ LLVector3 objScale = isVolumeGlobal() ? LLVector3(1,1,1) : getScale();
+ LLVector3 invObjScale(1.f / objScale.mV[VX], 1.f / objScale.mV[VY], 1.f / objScale.mV[VZ]);
+ ret.scaleVec(invObjScale);
+
+ return ret;
+}
+
+LLVector3 LLVOVolume::agentDirectionToVolume(const LLVector3& dir) const
+{
+ LLVector3 ret = dir * ~getRenderRotation();
+
+ LLVector3 objScale = isVolumeGlobal() ? LLVector3(1,1,1) : getScale();
+ ret.scaleVec(objScale);
+
+ return ret;
+}
+
+LLVector3 LLVOVolume::volumePositionToAgent(const LLVector3& dir) const
+{
+ LLVector3 ret = dir;
+ LLVector3 objScale = isVolumeGlobal() ? LLVector3(1,1,1) : getScale();
+ ret.scaleVec(objScale);
+ ret = ret * getRenderRotation();
+ ret += getRenderPosition();
+
+ return ret;
+}
+
+LLVector3 LLVOVolume::volumeDirectionToAgent(const LLVector3& dir) const
+{
+ LLVector3 ret = dir;
+ LLVector3 objScale = isVolumeGlobal() ? LLVector3(1,1,1) : getScale();
+ LLVector3 invObjScale(1.f / objScale.mV[VX], 1.f / objScale.mV[VY], 1.f / objScale.mV[VZ]);
+ ret.scaleVec(invObjScale);
+ ret = ret * getRenderRotation();
+
+ return ret;
+}
+
+
+BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, S32 face, BOOL pick_transparent, S32 *face_hitp,
+ LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal)
+
+{
+ if (!mbCanSelect
+ || mDrawable->isDead()
+ || !gPipeline.hasRenderType(mDrawable->getRenderType()))
+ {
+ return FALSE;
+ }
+
+ BOOL ret = FALSE;
+
+ LLVolume* volume = getVolume();
+
+ bool transform = true;
+
+ if (mDrawable->isState(LLDrawable::RIGGED))
+ {
+ if (LLFloater::isVisible(gFloaterTools) && getAvatar()->isSelf())
+ {
+ updateRiggedVolume();
+ genBBoxes(FALSE);
+ volume = mRiggedVolume;
+ transform = false;
+ }
+ else
+ { //cannot pick rigged attachments on other avatars or when not in build mode
+ return FALSE;
+ }
+ }
+
+ if (volume)
+ {
+ LLVector3 v_start, v_end, v_dir;
+
+ if (transform)
+ {
+ v_start = agentPositionToVolume(start);
+ v_end = agentPositionToVolume(end);
+ }
+ else
+ {
+ v_start = start;
+ v_end = end;
+ }
+
+ LLVector3 p;
+ LLVector3 n;
+ LLVector2 tc;
+ LLVector3 bn;
+
+ if (intersection != NULL)
+ {
+ p = *intersection;
+ }
+
+ if (tex_coord != NULL)
+ {
+ tc = *tex_coord;
+ }
+
+ if (normal != NULL)
+ {
+ n = *normal;
+ }
+
+ if (bi_normal != NULL)
+ {
+ bn = *bi_normal;
+ }
+
+ S32 face_hit = -1;
+
+ S32 start_face, end_face;
+ if (face == -1)
+ {
+ start_face = 0;
+ end_face = volume->getNumVolumeFaces();
+ }
+ else
+ {
+ start_face = face;
+ end_face = face+1;
+ }
+
+ bool special_cursor = specialHoverCursor();
+ for (S32 i = start_face; i < end_face; ++i)
+ {
+ if (!special_cursor && !pick_transparent && getTE(i)->getColor().mV[3] == 0.f)
+ { //don't attempt to pick completely transparent faces unless
+ //pick_transparent is true
+ continue;
+ }
+
+ face_hit = volume->lineSegmentIntersect(v_start, v_end, i,
+ &p, &tc, &n, &bn);
+
+ if (face_hit >= 0 && mDrawable->getNumFaces() > face_hit)
+ {
+ LLFace* face = mDrawable->getFace(face_hit);
+
+ if (pick_transparent || !face->getTexture() || !face->getTexture()->hasGLTexture() || face->getTexture()->getMask(face->surfaceToTexture(tc, p, n)))
+ {
+ v_end = p;
+ if (face_hitp != NULL)
+ {
+ *face_hitp = face_hit;
+ }
+
+ if (intersection != NULL)
+ {
+ if (transform)
+ {
+ *intersection = volumePositionToAgent(p); // must map back to agent space
+ }
+ else
+ {
+ *intersection = p;
+ }
+ }
+
+ if (normal != NULL)
+ {
+ if (transform)
+ {
+ *normal = volumeDirectionToAgent(n);
+ }
+ else
+ {
+ *normal = n;
+ }
+
+ (*normal).normVec();
+ }
+
+ if (bi_normal != NULL)
+ {
+ if (transform)
+ {
+ *bi_normal = volumeDirectionToAgent(bn);
+ }
+ else
+ {
+ *bi_normal = bn;
+ }
+ (*bi_normal).normVec();
+ }
+
+ if (tex_coord != NULL)
+ {
+ *tex_coord = tc;
+ }
+
+ ret = TRUE;
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+bool LLVOVolume::treatAsRigged()
+{
+ return LLFloater::isVisible(gFloaterTools) &&
+ isAttachment() &&
+ getAvatar() &&
+ getAvatar()->isSelf() &&
+ mDrawable.notNull() &&
+ mDrawable->isState(LLDrawable::RIGGED);
+}
+
+LLRiggedVolume* LLVOVolume::getRiggedVolume()
+{
+ return mRiggedVolume;
+}
+
+void LLVOVolume::clearRiggedVolume()
+{
+ if (mRiggedVolume.notNull())
+ {
+ mRiggedVolume = NULL;
+ updateRelativeXform();
+ }
+}
+
+void LLVOVolume::updateRiggedVolume()
+{
+ //Update mRiggedVolume to match current animation frame of avatar.
+ //Also update position/size in octree.
+
+ if (!treatAsRigged())
+ {
+ clearRiggedVolume();
+
+ return;
+ }
+
+ LLVolume* volume = getVolume();
+
+ const LLMeshSkinInfo* skin = gMeshRepo.getSkinInfo(volume->getParams().getSculptID(), this);
+
+ if (!skin)
+ {
+ clearRiggedVolume();
+ return;
+ }
+
+ LLVOAvatar* avatar = getAvatar();
+
+ if (!avatar)
+ {
+ clearRiggedVolume();
+ return;
+ }
+
+ if (!mRiggedVolume)
+ {
+ LLVolumeParams p;
+ mRiggedVolume = new LLRiggedVolume(p);
+ updateRelativeXform();
+ }
+
+ mRiggedVolume->update(skin, avatar, volume);
+
+}
+
+static LLFastTimer::DeclareTimer FTM_SKIN_RIGGED("Skin");
+static LLFastTimer::DeclareTimer FTM_RIGGED_OCTREE("Octree");
+
+void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, const LLVolume* volume)
+{
+ bool copy = false;
+ if (volume->getNumVolumeFaces() != getNumVolumeFaces())
+ {
+ copy = true;
+ }
+
+ for (S32 i = 0; i < volume->getNumVolumeFaces() && !copy; ++i)
+ {
+ const LLVolumeFace& src_face = volume->getVolumeFace(i);
+ const LLVolumeFace& dst_face = getVolumeFace(i);
+
+ if (src_face.mNumIndices != dst_face.mNumIndices ||
+ src_face.mNumVertices != dst_face.mNumVertices)
+ {
+ copy = true;
+ }
+ }
+
+ if (copy)
+ {
+ copyVolumeFaces(volume);
+ }
+
+ //build matrix palette
+ LLMatrix4a mp[64];
+ LLMatrix4* mat = (LLMatrix4*) mp;
+
+ for (U32 j = 0; j < skin->mJointNames.size(); ++j)
+ {
+ LLJoint* joint = avatar->getJoint(skin->mJointNames[j]);
+ if (joint)
+ {
+ mat[j] = skin->mInvBindMatrix[j];
+ mat[j] *= joint->getWorldMatrix();
+ }
+ }
+
+ for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
+ {
+ const LLVolumeFace& vol_face = volume->getVolumeFace(i);
+
+ LLVolumeFace& dst_face = mVolumeFaces[i];
+
+ LLVector4a* weight = vol_face.mWeights;
+
+ LLMatrix4a bind_shape_matrix;
+ bind_shape_matrix.loadu(skin->mBindShapeMatrix);
+
+ LLVector4a* pos = dst_face.mPositions;
+
+ {
+ LLFastTimer t(FTM_SKIN_RIGGED);
+
+ for (U32 j = 0; j < dst_face.mNumVertices; ++j)
+ {
+ LLMatrix4a final_mat;
+ final_mat.clear();
+
+ S32 idx[4];
+
+ LLVector4 wght;
+
+ F32 scale = 0.f;
+ for (U32 k = 0; k < 4; k++)
+ {
+ F32 w = weight[j][k];
+
+ idx[k] = (S32) floorf(w);
+ wght[k] = w - floorf(w);
+ scale += wght[k];
+ }
+
+ wght *= 1.f/scale;
+
+ for (U32 k = 0; k < 4; k++)
+ {
+ F32 w = wght[k];
+
+ LLMatrix4a src;
+ src.setMul(mp[idx[k]], w);
+
+ final_mat.add(src);
+ }
+
+
+ LLVector4a& v = vol_face.mPositions[j];
+ LLVector4a t;
+ LLVector4a dst;
+ bind_shape_matrix.affineTransform(v, t);
+ final_mat.affineTransform(t, dst);
+ pos[j] = dst;
+ }
+
+ //update bounding box
+ LLVector4a& min = dst_face.mExtents[0];
+ LLVector4a& max = dst_face.mExtents[1];
+
+ min = pos[0];
+ max = pos[1];
+
+ for (U32 j = 1; j < dst_face.mNumVertices; ++j)
+ {
+ min.setMin(min, pos[j]);
+ max.setMax(max, pos[j]);
+ }
+
+ dst_face.mCenter->setAdd(dst_face.mExtents[0], dst_face.mExtents[1]);
+ dst_face.mCenter->mul(0.5f);
+
+ }
+
+ {
+ LLFastTimer t(FTM_RIGGED_OCTREE);
+ delete dst_face.mOctree;
+ dst_face.mOctree = NULL;
+
+ LLVector4a size;
+ size.setSub(dst_face.mExtents[1], dst_face.mExtents[0]);
+ size.splat(size.getLength3().getF32()*0.5f);
+
+ dst_face.createOctree(1.f);
+ }
+ }
+}
+
+U32 LLVOVolume::getPartitionType() const
+{
+ if (isHUDAttachment())
+ {
+ return LLViewerRegion::PARTITION_HUD;
+ }
+
+ return LLViewerRegion::PARTITION_VOLUME;
+}
+
+LLVolumePartition::LLVolumePartition()
+: LLSpatialPartition(LLVOVolume::VERTEX_DATA_MASK, TRUE, GL_DYNAMIC_DRAW_ARB)
+{
+ mLODPeriod = 32;
+ mDepthMask = FALSE;
+ mDrawableType = LLPipeline::RENDER_TYPE_VOLUME;
+ mPartitionType = LLViewerRegion::PARTITION_VOLUME;
+ mSlopRatio = 0.25f;
+ mBufferUsage = GL_DYNAMIC_DRAW_ARB;
+}
+
+LLVolumeBridge::LLVolumeBridge(LLDrawable* drawablep)
+: LLSpatialBridge(drawablep, TRUE, LLVOVolume::VERTEX_DATA_MASK)
+{
+ mDepthMask = FALSE;
+ mLODPeriod = 32;
+ mDrawableType = LLPipeline::RENDER_TYPE_VOLUME;
+ mPartitionType = LLViewerRegion::PARTITION_BRIDGE;
+
+ mBufferUsage = GL_DYNAMIC_DRAW_ARB;
+
+ mSlopRatio = 0.25f;
+}
+
+bool can_batch_texture(LLFace* facep)
+{
+ if (facep->getTextureEntry()->getBumpmap())
+ { //bump maps aren't worked into texture batching yet
+ return false;
+ }
+
+ if (facep->getTexture() && facep->getTexture()->getPrimaryFormat() == GL_ALPHA)
+ { //can't batch invisiprims
+ return false;
+ }
+
+ if (facep->isState(LLFace::TEXTURE_ANIM) && facep->getVirtualSize() > MIN_TEX_ANIM_SIZE)
+ { //texture animation breaks batches
+ return false;
+ }
+
+ return true;
+}
+
+void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, U32 type)
+{
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+
+ if (facep->getViewerObject()->isSelected() && LLSelectMgr::getInstance()->mHideSelectedObjects)
+ {
+ return;
+ }
+
+ //add face to drawmap
+ LLSpatialGroup::drawmap_elem_t& draw_vec = group->mDrawMap[type];
+
+ S32 idx = draw_vec.size()-1;
+
+ BOOL fullbright = (type == LLRenderPass::PASS_FULLBRIGHT) ||
+ (type == LLRenderPass::PASS_INVISIBLE) ||
+ (type == LLRenderPass::PASS_ALPHA && facep->isState(LLFace::FULLBRIGHT));
+
+ if (!fullbright && type != LLRenderPass::PASS_GLOW && !facep->getVertexBuffer()->hasDataType(LLVertexBuffer::TYPE_NORMAL))
+ {
+ llwarns << "Non fullbright face has no normals!" << llendl;
+ return;
+ }
+
+ const LLMatrix4* tex_mat = NULL;
+ if (facep->isState(LLFace::TEXTURE_ANIM) && facep->getVirtualSize() > MIN_TEX_ANIM_SIZE)
+ {
+ tex_mat = facep->mTextureMatrix;
+ }
+
+ const LLMatrix4* model_mat = NULL;
+
+ LLDrawable* drawable = facep->getDrawable();
+ if (drawable->isActive())
+ {
+ model_mat = &(drawable->getRenderMatrix());
+ }
+ else
+ {
+ model_mat = &(drawable->getRegion()->mRenderMatrix);
+ if (model_mat->isIdentity())
+ {
+ model_mat = NULL;
+ }
+ }
+
+ U8 bump = (type == LLRenderPass::PASS_BUMP || type == LLRenderPass::PASS_POST_BUMP) ? facep->getTextureEntry()->getBumpmap() : 0;
+
+ LLViewerTexture* tex = facep->getTexture();
+
+ U8 index = facep->getTextureIndex();
+
+ bool batchable = false;
+
+ if (index < 255 && idx >= 0)
+ {
+ if (index < draw_vec[idx]->mTextureList.size())
+ {
+ if (draw_vec[idx]->mTextureList[index].isNull())
+ {
+ batchable = true;
+ draw_vec[idx]->mTextureList[index] = tex;
+ }
+ else if (draw_vec[idx]->mTextureList[index] == tex)
+ { //this face's texture index can be used with this batch
+ batchable = true;
+ }
+ }
+ else
+ { //texture list can be expanded to fit this texture index
+ batchable = true;
+ }
+ }
+
+ U8 glow = (U8) (facep->getTextureEntry()->getGlow() * 255);
+
+ if (idx >= 0 &&
+ draw_vec[idx]->mVertexBuffer == facep->getVertexBuffer() &&
+ draw_vec[idx]->mEnd == facep->getGeomIndex()-1 &&
+ (LLPipeline::sTextureBindTest || draw_vec[idx]->mTexture == tex || batchable) &&
+#if LL_DARWIN
+ draw_vec[idx]->mEnd - draw_vec[idx]->mStart + facep->getGeomCount() <= (U32) gGLManager.mGLMaxVertexRange &&
+ draw_vec[idx]->mCount + facep->getIndicesCount() <= (U32) gGLManager.mGLMaxIndexRange &&
+#endif
+ draw_vec[idx]->mGlowColor.mV[3] == glow &&
+ draw_vec[idx]->mFullbright == fullbright &&
+ draw_vec[idx]->mBump == bump &&
+ draw_vec[idx]->mTextureMatrix == tex_mat &&
+ draw_vec[idx]->mModelMatrix == model_mat)
+ {
+ draw_vec[idx]->mCount += facep->getIndicesCount();
+ draw_vec[idx]->mEnd += facep->getGeomCount();
+ draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, facep->getVirtualSize());
+
+ if (index >= draw_vec[idx]->mTextureList.size())
+ {
+ draw_vec[idx]->mTextureList.resize(index+1);
+ draw_vec[idx]->mTextureList[index] = tex;
+ }
+ draw_vec[idx]->validate();
+ update_min_max(draw_vec[idx]->mExtents[0], draw_vec[idx]->mExtents[1], facep->mExtents[0]);
+ update_min_max(draw_vec[idx]->mExtents[0], draw_vec[idx]->mExtents[1], facep->mExtents[1]);
+ }
+ else
+ {
+ U32 start = facep->getGeomIndex();
+ U32 end = start + facep->getGeomCount()-1;
+ U32 offset = facep->getIndicesStart();
+ U32 count = facep->getIndicesCount();
+ LLPointer<LLDrawInfo> draw_info = new LLDrawInfo(start,end,count,offset, tex,
+ facep->getVertexBuffer(), fullbright, bump);
+ draw_info->mGroup = group;
+ draw_info->mVSize = facep->getVirtualSize();
+ draw_vec.push_back(draw_info);
+ draw_info->mTextureMatrix = tex_mat;
+ draw_info->mModelMatrix = model_mat;
+ draw_info->mGlowColor.setVec(0,0,0,glow);
+ if (type == LLRenderPass::PASS_ALPHA)
+ { //for alpha sorting
+ facep->setDrawInfo(draw_info);
+ }
+ draw_info->mExtents[0] = facep->mExtents[0];
+ draw_info->mExtents[1] = facep->mExtents[1];
+
+ if (LLPipeline::sUseTriStrips)
+ {
+ draw_info->mDrawMode = LLRender::TRIANGLE_STRIP;
+ }
+
+ if (index < 255)
+ { //initialize texture list for texture batching
+ draw_info->mTextureList.resize(index+1);
+ draw_info->mTextureList[index] = tex;
+ }
+ draw_info->validate();
+ }
+}
+
+void LLVolumeGeometryManager::getGeometry(LLSpatialGroup* group)
+{
+
+}
+
+static LLFastTimer::DeclareTimer FTM_REBUILD_VOLUME_VB("Volume");
+static LLFastTimer::DeclareTimer FTM_REBUILD_VBO("VBO Rebuilt");
+
+static LLDrawPoolAvatar* get_avatar_drawpool(LLViewerObject* vobj)
+{
+ LLVOAvatar* avatar = vobj->getAvatar();
+
+ if (avatar)
+ {
+ LLDrawable* drawable = avatar->mDrawable;
+ if (drawable && drawable->getNumFaces() > 0)
+ {
+ LLFace* face = drawable->getFace(0);
+ if (face)
+ {
+ LLDrawPool* drawpool = face->getPool();
+ if (drawpool)
+ {
+ if (drawpool->getType() == LLDrawPool::POOL_AVATAR)
+ {
+ return (LLDrawPoolAvatar*) drawpool;
+ }
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
+{
+ if (group->changeLOD())
+ {
+ group->mLastUpdateDistance = group->mDistance;
+ }
+
+ group->mLastUpdateViewAngle = group->mViewAngle;
+
+ if (!group->isState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::ALPHA_DIRTY))
+ {
+ if (group->isState(LLSpatialGroup::MESH_DIRTY) && !LLPipeline::sDelayVBUpdate)
+ {
+ LLFastTimer ftm(FTM_REBUILD_VBO);
+ LLFastTimer ftm2(FTM_REBUILD_VOLUME_VB);
+
+ rebuildMesh(group);
+ }
+ return;
+ }
+
+ group->mBuilt = 1.f;
+ LLFastTimer ftm(FTM_REBUILD_VBO);
+
+ LLFastTimer ftm2(FTM_REBUILD_VOLUME_VB);
+
+ group->clearDrawMap();
+
+ mFaceList.clear();
+
+ std::vector<LLFace*> fullbright_faces;
+ std::vector<LLFace*> bump_faces;
+ std::vector<LLFace*> simple_faces;
+
+ std::vector<LLFace*> alpha_faces;
+ U32 useage = group->mSpatialPartition->mBufferUsage;
+
+ U32 max_vertices = (gSavedSettings.getS32("RenderMaxVBOSize")*1024)/LLVertexBuffer::calcVertexSize(group->mSpatialPartition->mVertexDataMask);
+ U32 max_total = (gSavedSettings.getS32("RenderMaxNodeSize")*1024)/LLVertexBuffer::calcVertexSize(group->mSpatialPartition->mVertexDataMask);
+ max_vertices = llmin(max_vertices, (U32) 65535);
+
+ U32 cur_total = 0;
+
+ //get all the faces into a list
+ for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter)
+ {
+ LLDrawable* drawablep = *drawable_iter;
+
+ if (drawablep->isDead() || drawablep->isState(LLDrawable::FORCE_INVISIBLE) )
+ {
+ continue;
+ }
+
+ if (drawablep->isAnimating())
+ { //fall back to stream draw for animating verts
+ useage = GL_STREAM_DRAW_ARB;
+ }
+
+ LLVOVolume* vobj = drawablep->getVOVolume();
+
+ if (vobj->getVolume() && vobj->getVolume()->isTetrahedron() || (vobj->isMesh() && !gMeshRepo.meshRezEnabled()))
+ {
+ continue;
+ }
+
+ llassert_always(vobj);
+ vobj->updateTextureVirtualSize();
+ vobj->preRebuild();
+
+ drawablep->clearState(LLDrawable::HAS_ALPHA);
+
+ bool rigged = vobj->isAttachment() &&
+ vobj->isMesh() &&
+ gMeshRepo.getSkinInfo(vobj->getVolume()->getParams().getSculptID(), vobj);
+
+ bool bake_sunlight = LLPipeline::sBakeSunlight && drawablep->isStatic();
+
+ bool is_rigged = false;
+
+ //for each face
+ for (S32 i = 0; i < drawablep->getNumFaces(); i++)
+ {
+ LLFace* facep = drawablep->getFace(i);
+
+ //ALWAYS null out vertex buffer on rebuild -- if the face lands in a render
+ // batch, it will recover its vertex buffer reference from the spatial group
+ facep->setVertexBuffer(NULL);
+
+ //sum up face verts and indices
+ drawablep->updateFaceSize(i);
+
+
+
+ if (rigged)
+ {
+ if (!facep->isState(LLFace::RIGGED))
+ { //completely reset vertex buffer
+ facep->clearVertexBuffer();
+ }
+
+ facep->setState(LLFace::RIGGED);
+ is_rigged = true;
+
+ //get drawpool of avatar with rigged face
+ LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj);
+
+ //Determine if we've received skininfo that contains an
+ //alternate bind matrix - if it does then apply the translational component
+ //to the joints of the avatar.
+ LLVOAvatar* pAvatarVO = vobj->getAvatar();
+ bool pelvisGotSet = false;
+
+ if ( pAvatarVO )
+ {
+ LLUUID currentId = vobj->getVolume()->getParams().getSculptID();
+ const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( currentId, vobj );
+
+ if ( pSkinData )
+ {
+ const int bindCnt = pSkinData->mAlternateBindMatrix.size();
+ if ( bindCnt > 0 )
+ {
+ const int jointCnt = pSkinData->mJointNames.size();
+ const F32 pelvisZOffset = pSkinData->mPelvisOffset;
+ bool fullRig = (jointCnt>=20) ? true : false;
+ if ( fullRig )
+ {
+ for ( int i=0; i<jointCnt; ++i )
+ {
+ std::string lookingForJoint = pSkinData->mJointNames[i].c_str();
+ //llinfos<<"joint name "<<lookingForJoint.c_str()<<llendl;
+ LLJoint* pJoint = pAvatarVO->getJoint( lookingForJoint );
+ if ( pJoint && pJoint->getId() != currentId )
+ {
+ pJoint->setId( currentId );
+ const LLVector3& jointPos = pSkinData->mAlternateBindMatrix[i].getTranslation();
+ //Set the joint position
+ pJoint->storeCurrentXform( jointPos );
+ //If joint is a pelvis then handle old/new pelvis to foot values
+ if ( lookingForJoint == "mPelvis" )
+ {
+ pJoint->storeCurrentXform( jointPos );
+ if ( !pAvatarVO->hasPelvisOffset() )
+ {
+ pAvatarVO->setPelvisOffset( true, jointPos, pelvisZOffset );
+ //Trigger to rebuild viewer AV
+ pelvisGotSet = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ //If we've set the pelvis to a new position we need to also rebuild some information that the
+ //viewer does at launch (e.g. body size etc.)
+ if ( pelvisGotSet )
+ {
+ pAvatarVO->postPelvisSetRecalc();
+ }
+
+ if (pool)
+ {
+ const LLTextureEntry* te = facep->getTextureEntry();
+
+ //remove face from old pool if it exists
+ LLDrawPool* old_pool = facep->getPool();
+ if (old_pool && old_pool->getType() == LLDrawPool::POOL_AVATAR)
+ {
+ ((LLDrawPoolAvatar*) old_pool)->removeRiggedFace(facep);
+ }
+
+ //add face to new pool
+ LLViewerTexture* tex = facep->getTexture();
+ U32 type = gPipeline.getPoolTypeFromTE(te, tex);
+
+ if (type == LLDrawPool::POOL_ALPHA)
+ {
+ if (te->getFullbright())
+ {
+ pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA);
+ }
+ else
+ {
+ pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_ALPHA);
+ }
+ }
+ else if (te->getShiny())
+ {
+ if (te->getFullbright())
+ {
+ pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY);
+ }
+ else
+ {
+ if (LLPipeline::sRenderDeferred)
+ {
+ pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE);
+ }
+ else
+ {
+ pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SHINY);
+ }
+ }
+ }
+ else
+ {
+ if (te->getFullbright())
+ {
+ pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT);
+ }
+ else
+ {
+ pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE);
+ }
+ }
+
+ if (te->getGlow())
+ {
+ pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_GLOW);
+ }
+
+ if (LLPipeline::sRenderDeferred)
+ {
+ if (type != LLDrawPool::POOL_ALPHA && !te->getFullbright())
+ {
+ if (te->getBumpmap())
+ {
+ pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_BUMP);
+ }
+ else
+ {
+ pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_SIMPLE);
+ }
+ }
+ }
+ }
+
+ continue;
+ }
+ else
+ {
+ if (facep->isState(LLFace::RIGGED))
+ { //face is not rigged but used to be, remove from rigged face pool
+ LLDrawPoolAvatar* pool = (LLDrawPoolAvatar*) facep->getPool();
+ if (pool)
+ {
+ pool->removeRiggedFace(facep);
+ }
+ facep->clearState(LLFace::RIGGED);
+ }
+ }
+
+ if (cur_total > max_total || facep->getIndicesCount() <= 0 || facep->getGeomCount() <= 0)
+ {
+ facep->clearVertexBuffer();
+ continue;
+ }
+
+ cur_total += facep->getGeomCount();
+
+ if (facep->hasGeometry() && facep->getPixelArea() > FORCE_CULL_AREA)
+ {
+ const LLTextureEntry* te = facep->getTextureEntry();
+ LLViewerTexture* tex = facep->getTexture();
+
+ if (facep->isState(LLFace::TEXTURE_ANIM))
+ {
+ if (!vobj->mTexAnimMode)
+ {
+ facep->clearState(LLFace::TEXTURE_ANIM);
+ }
+ }
+
+ BOOL force_simple = (facep->getPixelArea() < FORCE_SIMPLE_RENDER_AREA);
+ U32 type = gPipeline.getPoolTypeFromTE(te, tex);
+ if (type != LLDrawPool::POOL_ALPHA && force_simple)
+ {
+ type = LLDrawPool::POOL_SIMPLE;
+ }
+ facep->setPoolType(type);
+
+ if (vobj->isHUDAttachment())
+ {
+ facep->setState(LLFace::FULLBRIGHT);
+ }
+
+ if (vobj->mTextureAnimp && vobj->mTexAnimMode)
+ {
+ if (vobj->mTextureAnimp->mFace <= -1)
+ {
+ S32 face;
+ for (face = 0; face < vobj->getNumTEs(); face++)
+ {
+ drawablep->getFace(face)->setState(LLFace::TEXTURE_ANIM);
+ }
+ }
+ else if (vobj->mTextureAnimp->mFace < vobj->getNumTEs())
+ {
+ drawablep->getFace(vobj->mTextureAnimp->mFace)->setState(LLFace::TEXTURE_ANIM);
+ }
+ }
+
+ if (type == LLDrawPool::POOL_ALPHA)
+ {
+ if (facep->canRenderAsMask())
+ { //can be treated as alpha mask
+ simple_faces.push_back(facep);
+ }
+ else
+ {
+ drawablep->setState(LLDrawable::HAS_ALPHA);
+ alpha_faces.push_back(facep);
+ }
+ }
+ else
+ {
+ if (drawablep->isState(LLDrawable::REBUILD_VOLUME))
+ {
+ facep->mLastUpdateTime = gFrameTimeSeconds;
+ }
+
+ if (gPipeline.canUseWindLightShadersOnObjects()
+ && LLPipeline::sRenderBump)
+ {
+ if (te->getBumpmap())
+ { //needs normal + binormal
+ bump_faces.push_back(facep);
+ }
+ else if (te->getShiny() || !te->getFullbright())
+ { //needs normal
+ simple_faces.push_back(facep);
+ }
+ else
+ { //doesn't need normal
+ facep->setState(LLFace::FULLBRIGHT);
+ fullbright_faces.push_back(facep);
+ }
+ }
+ else
+ {
+ if (te->getBumpmap() && LLPipeline::sRenderBump)
+ { //needs normal + binormal
+ bump_faces.push_back(facep);
+ }
+ else if ((te->getShiny() && LLPipeline::sRenderBump) ||
+ !(te->getFullbright() || bake_sunlight))
+ { //needs normal
+ simple_faces.push_back(facep);
+ }
+ else
+ { //doesn't need normal
+ facep->setState(LLFace::FULLBRIGHT);
+ fullbright_faces.push_back(facep);
+ }
+ }
+ }
+ }
+ else
+ { //face has no renderable geometry
+ facep->clearVertexBuffer();
+ }
+ }
+
+ if (is_rigged)
+ {
+ drawablep->setState(LLDrawable::RIGGED);
+ }
+ else
+ {
+ drawablep->clearState(LLDrawable::RIGGED);
+ }
+ }
+
+ group->mBufferUsage = useage;
+
+ //PROCESS NON-ALPHA FACES
+ U32 simple_mask = LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR;
+ U32 alpha_mask = simple_mask | 0x80000000; //hack to give alpha verts their own VBO
+ U32 bump_mask = LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR;
+ U32 fullbright_mask = LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR;
+
+ bool batch_textures = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 1;
+
+ if (batch_textures)
+ {
+ bump_mask |= LLVertexBuffer::MAP_BINORMAL;
+ genDrawInfo(group, simple_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, simple_faces, FALSE, TRUE);
+ genDrawInfo(group, fullbright_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, fullbright_faces, FALSE, TRUE);
+ genDrawInfo(group, bump_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, bump_faces, FALSE, TRUE);
+ genDrawInfo(group, alpha_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, alpha_faces, TRUE, TRUE);
+ }
+ else
+ {
+ genDrawInfo(group, simple_mask, simple_faces);
+ genDrawInfo(group, fullbright_mask, fullbright_faces);
+ genDrawInfo(group, bump_mask, bump_faces, FALSE, TRUE);
+ genDrawInfo(group, alpha_mask, alpha_faces, TRUE);
+ }
+
+
+ if (!LLPipeline::sDelayVBUpdate)
+ {
+ //drawables have been rebuilt, clear rebuild status
+ for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter)
+ {
+ LLDrawable* drawablep = *drawable_iter;
+ drawablep->clearState(LLDrawable::REBUILD_ALL);
+ }
+ }
+
+ group->mLastUpdateTime = gFrameTimeSeconds;
+ group->mBuilt = 1.f;
+ group->clearState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::ALPHA_DIRTY);
+
+ if (LLPipeline::sDelayVBUpdate)
+ {
+ group->setState(LLSpatialGroup::MESH_DIRTY | LLSpatialGroup::NEW_DRAWINFO);
+ }
+
+ mFaceList.clear();
+}
+
+static LLFastTimer::DeclareTimer FTM_VOLUME_GEOM("Volume Geometry");
+static LLFastTimer::DeclareTimer FTM_VOLUME_GEOM_PARTIAL("Terse Rebuild");
+
+void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
+{
+ llassert(group);
+ if (group && group->isState(LLSpatialGroup::MESH_DIRTY) && !group->isState(LLSpatialGroup::GEOM_DIRTY))
+ {
+ LLFastTimer tm(FTM_VOLUME_GEOM);
+ S32 num_mapped_veretx_buffer = LLVertexBuffer::sMappedCount ;
+
+ group->mBuilt = 1.f;
+
+ std::set<LLVertexBuffer*> mapped_buffers;
+
+ for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter)
+ {
+ LLFastTimer t(FTM_VOLUME_GEOM_PARTIAL);
+ LLDrawable* drawablep = *drawable_iter;
+
+ if (!drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) )
+ {
+ LLVOVolume* vobj = drawablep->getVOVolume();
+ vobj->preRebuild();
+
+ LLVolume* volume = vobj->getVolume();
+ for (S32 i = 0; i < drawablep->getNumFaces(); ++i)
+ {
+ LLFace* face = drawablep->getFace(i);
+ if (face)
+ {
+ LLVertexBuffer* buff = face->getVertexBuffer();
+ if (buff)
+ {
+ face->getGeometryVolume(*volume, face->getTEOffset(),
+ vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), face->getGeomIndex());
+
+ if (buff->isLocked())
+ {
+ mapped_buffers.insert(buff);
+ }
+ }
+ }
+ }
+
+ drawablep->clearState(LLDrawable::REBUILD_ALL);
+ }
+ }
+
+ for (std::set<LLVertexBuffer*>::iterator iter = mapped_buffers.begin(); iter != mapped_buffers.end(); ++iter)
+ {
+ (*iter)->setBuffer(0);
+ }
+
+ // don't forget alpha
+ if(group != NULL &&
+ !group->mVertexBuffer.isNull() &&
+ group->mVertexBuffer->isLocked())
+ {
+ group->mVertexBuffer->setBuffer(0);
+ }
+
+ //if not all buffers are unmapped
+ if(num_mapped_veretx_buffer != LLVertexBuffer::sMappedCount)
+ {
+ llwarns << "Not all mapped vertex buffers are unmapped!" << llendl ;
+ for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter)
+ {
+ LLDrawable* drawablep = *drawable_iter;
+ for (S32 i = 0; i < drawablep->getNumFaces(); ++i)
+ {
+ LLFace* face = drawablep->getFace(i);
+ LLVertexBuffer* buff = face->getVertexBuffer();
+ if (face && buff && buff->isLocked())
+ {
+ buff->setBuffer(0) ;
+ }
+ }
+ }
+ }
+
+ group->clearState(LLSpatialGroup::MESH_DIRTY | LLSpatialGroup::NEW_DRAWINFO);
+ }
+
+ llassert(!group || !group->isState(LLSpatialGroup::NEW_DRAWINFO));
+}
+
+struct CompareBatchBreakerModified
+{
+ bool operator()(const LLFace* const& lhs, const LLFace* const& rhs)
+ {
+ const LLTextureEntry* lte = lhs->getTextureEntry();
+ const LLTextureEntry* rte = rhs->getTextureEntry();
+
+ if (lte->getBumpmap() != rte->getBumpmap())
+ {
+ return lte->getBumpmap() < rte->getBumpmap();
+ }
+ else if (lte->getFullbright() != rte->getFullbright())
+ {
+ return lte->getFullbright() < rte->getFullbright();
+ }
+ else if (lte->getGlow() != rte->getGlow())
+ {
+ return lte->getGlow() < rte->getGlow();
+ }
+ else
+ {
+ return lhs->getTexture() < rhs->getTexture();
+ }
+
+ }
+};
+
+void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::vector<LLFace*>& faces, BOOL distance_sort, BOOL batch_textures)
+{
+ //calculate maximum number of vertices to store in a single buffer
+ U32 max_vertices = (gSavedSettings.getS32("RenderMaxVBOSize")*1024)/LLVertexBuffer::calcVertexSize(group->mSpatialPartition->mVertexDataMask);
+ max_vertices = llmin(max_vertices, (U32) 65535);
+
+ if (!distance_sort)
+ {
+ //sort faces by things that break batches
+ std::sort(faces.begin(), faces.end(), CompareBatchBreakerModified());
+ }
+ else
+ {
+ //sort faces by distance
+ std::sort(faces.begin(), faces.end(), LLFace::CompareDistanceGreater());
+ }
+
+ std::vector<LLFace*>::iterator face_iter = faces.begin();
+
+ LLSpatialGroup::buffer_map_t buffer_map;
+
+ LLViewerTexture* last_tex = NULL;
+ S32 buffer_index = 0;
+
+ if (distance_sort)
+ {
+ buffer_index = -1;
+ }
+
+ S32 texture_index_channels = gGLManager.mNumTextureImageUnits-1; //always reserve one for shiny for now just for simplicity
+
+ if (gGLManager.mGLVersion < 3.1f)
+ {
+ texture_index_channels = 1;
+ }
+
+ if (LLPipeline::sRenderDeferred && distance_sort)
+ {
+ texture_index_channels = gDeferredAlphaProgram.mFeatures.mIndexedTextureChannels;
+ }
+
+ texture_index_channels = llmin(texture_index_channels, (S32) gSavedSettings.getU32("RenderMaxTextureIndex"));
+
+
+ while (face_iter != faces.end())
+ {
+ //pull off next face
+ LLFace* facep = *face_iter;
+ LLViewerTexture* tex = facep->getTexture();
+
+ if (distance_sort)
+ {
+ tex = NULL;
+ }
+
+ if (last_tex == tex)
+ {
+ buffer_index++;
+ }
+ else
+ {
+ last_tex = tex;
+ buffer_index = 0;
+ }
+
+ bool bake_sunlight = LLPipeline::sBakeSunlight && facep->getDrawable()->isStatic();
+
+ U32 index_count = facep->getIndicesCount();
+ U32 geom_count = facep->getGeomCount();
+
+ //sum up vertices needed for this render batch
+ std::vector<LLFace*>::iterator i = face_iter;
+ ++i;
+
+ std::vector<LLViewerTexture*> texture_list;
+
+ if (batch_textures)
+ {
+ U8 cur_tex = 0;
+ facep->setTextureIndex(cur_tex);
+ texture_list.push_back(tex);
+
+ //if (can_batch_texture(facep))
+ {
+ while (i != faces.end())
+ {
+ facep = *i;
+ if (facep->getTexture() != tex)
+ {
+ if (distance_sort)
+ { //textures might be out of order, see if texture exists in current batch
+ bool found = false;
+ for (U32 tex_idx = 0; tex_idx < texture_list.size(); ++tex_idx)
+ {
+ if (facep->getTexture() == texture_list[tex_idx])
+ {
+ cur_tex = tex_idx;
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ cur_tex = texture_list.size();
+ }
+ }
+ else
+ {
+ cur_tex++;
+ }
+
+ if (!can_batch_texture(facep))
+ { //face is bump mapped or has an animated texture matrix -- can't
+ //batch more than 1 texture at a time
+ break;
+ }
+
+ if (cur_tex >= texture_index_channels)
+ { //cut batches when index channels are depleted
+ break;
+ }
+
+ tex = facep->getTexture();
+
+ texture_list.push_back(tex);
+ }
+
+ if (geom_count + facep->getGeomCount() > max_vertices)
+ { //cut batches on geom count too big
+ break;
+ }
+
+ ++i;
+ index_count += facep->getIndicesCount();
+ geom_count += facep->getGeomCount();
+
+ facep->setTextureIndex(cur_tex);
+ }
+ }
+
+ tex = texture_list[0];
+ }
+ else
+ {
+ while (i != faces.end() &&
+ (LLPipeline::sTextureBindTest || (distance_sort || (*i)->getTexture() == tex)))
+ {
+ facep = *i;
+
+
+ //face has no texture index
+ facep->mDrawInfo = NULL;
+ facep->setTextureIndex(255);
+
+ if (geom_count + facep->getGeomCount() > max_vertices)
+ { //cut batches on geom count too big
+ break;
+ }
+
+ ++i;
+ index_count += facep->getIndicesCount();
+ geom_count += facep->getGeomCount();
+ }
+ }
+
+ //create/delete/resize vertex buffer if needed
+ LLVertexBuffer* buffer = NULL;
+ LLSpatialGroup::buffer_texture_map_t::iterator found_iter = group->mBufferMap[mask].find(*face_iter);
+
+ if (found_iter != group->mBufferMap[mask].end())
+ {
+ if ((U32) buffer_index < found_iter->second.size())
+ {
+ buffer = found_iter->second[buffer_index];
+ }
+ }
+
+ if (!buffer)
+ { //create new buffer if needed
+ buffer = createVertexBuffer(mask,
+ group->mBufferUsage);
+ buffer->allocateBuffer(geom_count, index_count, TRUE);
+ }
+ else
+ { //resize pre-existing buffer
+ if (LLVertexBuffer::sEnableVBOs && buffer->getUsage() != group->mBufferUsage ||
+ buffer->getTypeMask() != mask)
+ {
+ buffer = createVertexBuffer(mask,
+ group->mBufferUsage);
+ buffer->allocateBuffer(geom_count, index_count, TRUE);
+ }
+ else
+ {
+ buffer->resizeBuffer(geom_count, index_count);
+ }
+ }
+
+ buffer_map[mask][*face_iter].push_back(buffer);
+
+ //add face geometry
+
+ U32 indices_index = 0;
+ U16 index_offset = 0;
+
+ while (face_iter < i)
+ { //update face indices for new buffer
+ facep = *face_iter;
+ facep->setIndicesIndex(indices_index);
+ facep->setGeomIndex(index_offset);
+ facep->setVertexBuffer(buffer);
+
+ if (batch_textures && facep->getTextureIndex() == 255)
+ {
+ llerrs << "Invalid texture index." << llendl;
+ }
+
+ {
+ //for debugging, set last time face was updated vs moved
+ facep->updateRebuildFlags();
+
+ if (!LLPipeline::sDelayVBUpdate)
+ { //copy face geometry into vertex buffer
+ LLDrawable* drawablep = facep->getDrawable();
+ LLVOVolume* vobj = drawablep->getVOVolume();
+ LLVolume* volume = vobj->getVolume();
+
+ U32 te_idx = facep->getTEOffset();
+
+ facep->getGeometryVolume(*volume, te_idx,
+ vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), index_offset);
+ }
+ }
+
+ index_offset += facep->getGeomCount();
+ indices_index += facep->getIndicesCount();
+
+
+ //append face to appropriate render batch
+
+ BOOL force_simple = facep->getPixelArea() < FORCE_SIMPLE_RENDER_AREA;
+ BOOL fullbright = facep->isState(LLFace::FULLBRIGHT);
+ if ((mask & LLVertexBuffer::MAP_NORMAL) == 0)
+ { //paranoia check to make sure GL doesn't try to read non-existant normals
+ fullbright = TRUE;
+ }
+
+ const LLTextureEntry* te = facep->getTextureEntry();
+ tex = facep->getTexture();
+
+ BOOL is_alpha = (facep->getPoolType() == LLDrawPool::POOL_ALPHA) ? TRUE : FALSE;
+
+ if (is_alpha)
+ {
+ // can we safely treat this as an alpha mask?
+ if (facep->canRenderAsMask())
+ {
+ if (te->getFullbright() || LLPipeline::sNoAlpha)
+ {
+ registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK);
+ }
+ else
+ {
+ registerFace(group, facep, LLRenderPass::PASS_ALPHA_MASK);
+ }
+ }
+ else
+ {
+ registerFace(group, facep, LLRenderPass::PASS_ALPHA);
+ }
+
+ if (LLPipeline::sRenderDeferred)
+ {
+ registerFace(group, facep, LLRenderPass::PASS_ALPHA_SHADOW);
+ }
+ }
+ else if (gPipeline.canUseVertexShaders()
+ && group->mSpatialPartition->mPartitionType != LLViewerRegion::PARTITION_HUD
+ && LLPipeline::sRenderBump
+ && te->getShiny())
+ { //shiny
+ if (tex->getPrimaryFormat() == GL_ALPHA)
+ { //invisiprim+shiny
+ registerFace(group, facep, LLRenderPass::PASS_INVISI_SHINY);
+ registerFace(group, facep, LLRenderPass::PASS_INVISIBLE);
+ }
+ else if (LLPipeline::sRenderDeferred)
+ { //deferred rendering
+ if (te->getFullbright())
+ { //register in post deferred fullbright shiny pass
+ registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT_SHINY);
+ if (te->getBumpmap())
+ { //register in post deferred bump pass
+ registerFace(group, facep, LLRenderPass::PASS_POST_BUMP);
+ }
+ }
+ else if (te->getBumpmap())
+ { //register in deferred bump pass
+ registerFace(group, facep, LLRenderPass::PASS_BUMP);
+ }
+ else
+ { //register in deferred simple pass (deferred simple includes shiny)
+ llassert(mask & LLVertexBuffer::MAP_NORMAL);
+ registerFace(group, facep, LLRenderPass::PASS_SIMPLE);
+ }
+ }
+ else if (fullbright)
+ { //not deferred, register in standard fullbright shiny pass
+ registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT_SHINY);
+ }
+ else
+ { //not deferred or fullbright, register in standard shiny pass
+ registerFace(group, facep, LLRenderPass::PASS_SHINY);
+ }
+ }
+ else
+ { //not alpha and not shiny
+ if (!is_alpha && tex->getPrimaryFormat() == GL_ALPHA)
+ { //invisiprim
+ registerFace(group, facep, LLRenderPass::PASS_INVISIBLE);
+ }
+ else if (fullbright || bake_sunlight)
+ { //fullbright
+ registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT);
+ if (LLPipeline::sRenderDeferred && LLPipeline::sRenderBump && te->getBumpmap())
+ { //if this is the deferred render and a bump map is present, register in post deferred bump
+ registerFace(group, facep, LLRenderPass::PASS_POST_BUMP);
+ }
+ }
+ else
+ {
+ if (LLPipeline::sRenderDeferred && LLPipeline::sRenderBump && te->getBumpmap())
+ { //non-shiny or fullbright deferred bump
+ registerFace(group, facep, LLRenderPass::PASS_BUMP);
+ }
+ else
+ { //all around simple
+ llassert(mask & LLVertexBuffer::MAP_NORMAL);
+ registerFace(group, facep, LLRenderPass::PASS_SIMPLE);
+ }
+ }
+
+ //not sure why this is here -- shiny HUD attachments maybe? -- davep 5/11/2010
+ if (!is_alpha && te->getShiny() && LLPipeline::sRenderBump)
+ {
+ registerFace(group, facep, LLRenderPass::PASS_SHINY);
+ }
+ }
+
+ //not sure why this is here, and looks like it might cause bump mapped objects to get rendered redundantly -- davep 5/11/2010
+ if (!is_alpha && !LLPipeline::sRenderDeferred)
+ {
+ llassert((mask & LLVertexBuffer::MAP_NORMAL) || fullbright);
+ facep->setPoolType((fullbright) ? LLDrawPool::POOL_FULLBRIGHT : LLDrawPool::POOL_SIMPLE);
+
+ if (!force_simple && te->getBumpmap() && LLPipeline::sRenderBump)
+ {
+ registerFace(group, facep, LLRenderPass::PASS_BUMP);
+ }
+ }
+
+ if (!is_alpha && LLPipeline::sRenderGlow && te->getGlow() > 0.f)
+ {
+ registerFace(group, facep, LLRenderPass::PASS_GLOW);
+ }
+
+ ++face_iter;
+ }
+
+ buffer->setBuffer(0);
+ }
+
+ group->mBufferMap[mask].clear();
+ for (LLSpatialGroup::buffer_texture_map_t::iterator i = buffer_map[mask].begin(); i != buffer_map[mask].end(); ++i)
+ {
+ group->mBufferMap[mask][i->first] = i->second;
+ }
+}
+
+void LLGeometryManager::addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32 &index_count)
+{
+ //initialize to default usage for this partition
+ U32 usage = group->mSpatialPartition->mBufferUsage;
+
+ //clear off any old faces
+ mFaceList.clear();
+
+ //for each drawable
+ for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter)
+ {
+ LLDrawable* drawablep = *drawable_iter;
+
+ if (drawablep->isDead())
+ {
+ continue;
+ }
+
+ if (drawablep->isAnimating())
+ { //fall back to stream draw for animating verts
+ usage = GL_STREAM_DRAW_ARB;
+ }
+
+ //for each face
+ for (S32 i = 0; i < drawablep->getNumFaces(); i++)
+ {
+ //sum up face verts and indices
+ drawablep->updateFaceSize(i);
+ LLFace* facep = drawablep->getFace(i);
+ if (facep->hasGeometry() && facep->getPixelArea() > FORCE_CULL_AREA)
+ {
+ vertex_count += facep->getGeomCount();
+ index_count += facep->getIndicesCount();
+ llassert(facep->getIndicesCount() < 65536);
+ //remember face (for sorting)
+ mFaceList.push_back(facep);
+ }
+ else
+ {
+ facep->clearVertexBuffer();
+ }
+ }
+ }
+
+ group->mBufferUsage = usage;
+}
+
+LLHUDPartition::LLHUDPartition()
+{
+ mPartitionType = LLViewerRegion::PARTITION_HUD;
+ mDrawableType = LLPipeline::RENDER_TYPE_HUD;
+ mSlopRatio = 0.f;
+ mLODPeriod = 1;
+}
+
+void LLHUDPartition::shift(const LLVector4a &offset)
+{
+ //HUD objects don't shift with region crossing. That would be silly.
+}
+
+
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index fc00f0c0d0..6e9c0fbcb0 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -129,9 +129,11 @@ public: const LLMatrix4& getRelativeXform() const { return mRelativeXform; } const LLMatrix3& getRelativeXformInvTrans() const { return mRelativeXformInvTrans; } /*virtual*/ const LLMatrix4 getRenderMatrix() const; - U32 getRenderCost(std::set<LLUUID> &textures) const; + typedef std::map<LLUUID, S32> texture_cost_t; + U32 getRenderCost(texture_cost_t &textures) const; /*virtual*/ F32 getStreamingCost(S32* bytes = NULL, S32* visible_bytes = NULL); - /*virtual*/ U32 getTriangleCount(); + + /*virtual*/ U32 getTriangleCount() const; /*virtual*/ U32 getHighLODTriangleCount(); /*virtual*/ BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end, S32 face = -1, // which face to check, -1 = ALL_SIDES @@ -320,11 +322,19 @@ protected: LLFace* addFace(S32 face_index); void updateTEData(); + // stats tracking for render complexity + static S32 mRenderComplexity_last; + static S32 mRenderComplexity_current; + void requestMediaDataUpdate(bool isNew); void cleanUpMediaImpls(); void addMediaImpl(LLViewerMediaImpl* media_impl, S32 texture_index) ; void removeMediaImpl(S32 texture_index) ; public: + + static S32 getRenderComplexityMax() {return mRenderComplexity_last;} + static void updateRenderComplexity(); + LLViewerTextureAnim *mTextureAnimp; U8 mTexAnimMode; private: @@ -359,8 +369,6 @@ public: static LLPointer<LLObjectMediaDataClient> sObjectMediaClient; static LLPointer<LLObjectMediaNavigateClient> sObjectMediaNavigateClient; - static const U32 ARC_TEXTURE_COST = 5; - protected: static S32 sNumLODChanges; diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 28e6526acd..671e0f66b0 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -459,6 +459,7 @@ public: RENDER_DEBUG_PHYSICS_SHAPES = 0x1000000, RENDER_DEBUG_NORMALS = 0x2000000, RENDER_DEBUG_LOD_INFO = 0x4000000, + RENDER_DEBUG_RENDER_COMPLEXITY = 0x8000000 }; public: diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 01699955a6..994ab0a4e5 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -1287,7 +1287,7 @@ parameter="stats" /> </menu_item_check> <menu_item_check - label="Show Avatar Rendering Cost" + label="Show Draw Weight for Avatars" name="Avatar Rendering Cost"> <menu_item_check.on_check function="Advanced.CheckInfoDisplay" @@ -2435,6 +2435,16 @@ function="Advanced.ToggleInfoDisplay" parameter="raycast" /> </menu_item_check> + <menu_item_check + label="Render Complexity" + name="rendercomplexity"> + <menu_item_check.on_check + function="Advanced.CheckInfoDisplay" + parameter="rendercomplexity" /> + <menu_item_check.on_click + function="Advanced.ToggleInfoDisplay" + parameter="rendercomplexity" /> + </menu_item_check> <menu_item_check label="Sculpt" name="Sculpt"> |