diff options
author | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 |
---|---|---|
committer | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 19:04:52 +0200 |
commit | 1b67dd855c41f5a0cda7ec2a68d98071986ca703 (patch) | |
tree | ab243607f74f78200787bba5b9b88f07ef1b966f /indra/newview/lldrawable.cpp | |
parent | 6d6eabca44d08d5b97bfe3e941d2b9687c2246ea (diff) | |
parent | e1623bb276f83a43ce7a197e388720c05bdefe61 (diff) |
Merge remote-tracking branch 'origin/main' into DRTVWR-600-maint-A
# Conflicts:
# autobuild.xml
# indra/cmake/CMakeLists.txt
# indra/cmake/GoogleMock.cmake
# indra/llaudio/llaudioengine_fmodstudio.cpp
# indra/llaudio/llaudioengine_fmodstudio.h
# indra/llaudio/lllistener_fmodstudio.cpp
# indra/llaudio/lllistener_fmodstudio.h
# indra/llaudio/llstreamingaudio_fmodstudio.cpp
# indra/llaudio/llstreamingaudio_fmodstudio.h
# indra/llcharacter/llmultigesture.cpp
# indra/llcharacter/llmultigesture.h
# indra/llimage/llimage.cpp
# indra/llimage/llimagepng.cpp
# indra/llimage/llimageworker.cpp
# indra/llimage/tests/llimageworker_test.cpp
# indra/llmessage/tests/llmockhttpclient.h
# indra/llprimitive/llgltfmaterial.h
# indra/llrender/llfontfreetype.cpp
# indra/llui/llcombobox.cpp
# indra/llui/llfolderview.cpp
# indra/llui/llfolderviewmodel.h
# indra/llui/lllineeditor.cpp
# indra/llui/lllineeditor.h
# indra/llui/lltextbase.cpp
# indra/llui/lltextbase.h
# indra/llui/lltexteditor.cpp
# indra/llui/lltextvalidate.cpp
# indra/llui/lltextvalidate.h
# indra/llui/lluictrl.h
# indra/llui/llview.cpp
# indra/llwindow/llwindowmacosx.cpp
# indra/newview/app_settings/settings.xml
# indra/newview/llappearancemgr.cpp
# indra/newview/llappearancemgr.h
# indra/newview/llavatarpropertiesprocessor.cpp
# indra/newview/llavatarpropertiesprocessor.h
# indra/newview/llbreadcrumbview.cpp
# indra/newview/llbreadcrumbview.h
# indra/newview/llbreastmotion.cpp
# indra/newview/llbreastmotion.h
# indra/newview/llconversationmodel.h
# indra/newview/lldensityctrl.cpp
# indra/newview/lldensityctrl.h
# indra/newview/llface.inl
# indra/newview/llfloatereditsky.cpp
# indra/newview/llfloatereditwater.cpp
# indra/newview/llfloateremojipicker.h
# indra/newview/llfloaterimsessiontab.cpp
# indra/newview/llfloaterprofiletexture.cpp
# indra/newview/llfloaterprofiletexture.h
# indra/newview/llgesturemgr.cpp
# indra/newview/llgesturemgr.h
# indra/newview/llimpanel.cpp
# indra/newview/llimpanel.h
# indra/newview/llinventorybridge.cpp
# indra/newview/llinventorybridge.h
# indra/newview/llinventoryclipboard.cpp
# indra/newview/llinventoryclipboard.h
# indra/newview/llinventoryfunctions.cpp
# indra/newview/llinventoryfunctions.h
# indra/newview/llinventorygallery.cpp
# indra/newview/lllistbrowser.cpp
# indra/newview/lllistbrowser.h
# indra/newview/llpanelobjectinventory.cpp
# indra/newview/llpanelprofile.cpp
# indra/newview/llpanelprofile.h
# indra/newview/llpreviewgesture.cpp
# indra/newview/llsavedsettingsglue.cpp
# indra/newview/llsavedsettingsglue.h
# indra/newview/lltooldraganddrop.cpp
# indra/newview/llurllineeditorctrl.cpp
# indra/newview/llvectorperfoptions.cpp
# indra/newview/llvectorperfoptions.h
# indra/newview/llviewerparceloverlay.cpp
# indra/newview/llviewertexlayer.cpp
# indra/newview/llviewertexturelist.cpp
# indra/newview/macmain.h
# indra/test/test.cpp
Diffstat (limited to 'indra/newview/lldrawable.cpp')
-rw-r--r-- | indra/newview/lldrawable.cpp | 3590 |
1 files changed, 1795 insertions, 1795 deletions
diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp index 99494c96b8..1becd02ae7 100644 --- a/indra/newview/lldrawable.cpp +++ b/indra/newview/lldrawable.cpp @@ -1,1795 +1,1795 @@ -/** - * @file lldrawable.cpp - * @brief LLDrawable class implementation - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "lldrawable.h" - -// library includes -#include "material_codes.h" - -// viewer includes -#include "llagent.h" -#include "llcriticaldamp.h" -#include "llface.h" -#include "lllightconstants.h" -#include "llmatrix4a.h" -#include "llsky.h" -#include "llsurfacepatch.h" -#include "llviewercamera.h" -#include "llviewerregion.h" -#include "llvolume.h" -#include "llvoavatar.h" -#include "llvovolume.h" -#include "llvosurfacepatch.h" // for debugging -#include "llworld.h" -#include "pipeline.h" -#include "llspatialpartition.h" -#include "llviewerobjectlist.h" -#include "llviewerwindow.h" -#include "llvocache.h" -#include "llcontrolavatar.h" -#include "lldrawpoolavatar.h" - -const F32 MIN_INTERPOLATE_DISTANCE_SQUARED = 0.001f * 0.001f; -const F32 MAX_INTERPOLATE_DISTANCE_SQUARED = 10.f * 10.f; -const F32 OBJECT_DAMPING_TIME_CONSTANT = 0.06f; - -extern bool gShiftFrame; - - -//////////////////////// -// -// Inline implementations. -// -// - - - -////////////////////////////// -// -// Drawable code -// -// - -// static -U32 LLDrawable::sNumZombieDrawables = 0; -F32 LLDrawable::sCurPixelAngle = 0; -std::vector<LLPointer<LLDrawable> > LLDrawable::sDeadList; - -#define FORCE_INVISIBLE_AREA 16.f - -// static -void LLDrawable::incrementVisible() -{ - LLViewerOctreeEntryData::incrementVisible(); - sCurPixelAngle = (F32) gViewerWindow->getWindowHeightRaw()/LLViewerCamera::getInstance()->getView(); -} - -LLDrawable::LLDrawable(LLViewerObject *vobj, bool new_entry) -: LLViewerOctreeEntryData(LLViewerOctreeEntry::LLDRAWABLE), - mVObjp(vobj) -{ - init(new_entry); -} - -void LLDrawable::init(bool new_entry) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE - - // mXform - mParent = NULL; - mRenderType = 0; - mCurrentScale = LLVector3(1,1,1); - mDistanceWRTCamera = 0.0f; - mState = 0; - - // mFaces - mRadius = 0.f; - mGeneration = -1; - mSpatialBridge = NULL; - - LLViewerOctreeEntry* entry = NULL; - LLVOCacheEntry* vo_entry = NULL; - if(!new_entry && mVObjp && getRegion() != NULL) - { - vo_entry = getRegion()->getCacheEntryForOctree(mVObjp->getLocalID()); - if(vo_entry) - { - entry = vo_entry->getEntry(); - } - } - setOctreeEntry(entry); - if(vo_entry) - { - if(!entry) - { - vo_entry->setOctreeEntry(mEntry); - } - - getRegion()->addActiveCacheEntry(vo_entry); - - if(vo_entry->getNumOfChildren() > 0) - { - getRegion()->addVisibleChildCacheEntry(vo_entry, NULL); //to load all children. - } - - llassert(!vo_entry->getGroup()); //not in the object cache octree. - } - - llassert(!vo_entry || vo_entry->getEntry() == mEntry); - - initVisible(sCurVisible - 2);//invisible for the current frame and the last frame. -} - -void LLDrawable::unload() -{ - LLVOVolume *pVVol = getVOVolume(); - pVVol->setNoLOD(); - pVVol->markForUpdate(); -} - -// static -void LLDrawable::initClass() -{ -} - - -void LLDrawable::destroy() -{ - if (gDebugGL) - { - gPipeline.checkReferences(this); - } - - if (isDead()) - { - sNumZombieDrawables--; - } - - // Attempt to catch violations of this in debug, - // knowing that some false alarms may result - // - llassert(!LLSpatialGroup::sNoDelete); - - /* cannot be guaranteed and causes crashes on false alarms - if (LLSpatialGroup::sNoDelete) - { - LL_ERRS() << "Illegal deletion of LLDrawable!" << LL_ENDL; - }*/ - - std::for_each(mFaces.begin(), mFaces.end(), DeletePointer()); - mFaces.clear(); - - - /*if (!(sNumZombieDrawables % 10)) - { - LL_INFOS() << "- Zombie drawables: " << sNumZombieDrawables << LL_ENDL; - }*/ - -} - -void LLDrawable::markDead() -{ - if (isDead()) - { - LL_WARNS() << "Warning! Marking dead multiple times!" << LL_ENDL; - return; - } - setState(DEAD); - - if (mSpatialBridge) - { - mSpatialBridge->markDead(); - mSpatialBridge = NULL; - } - - sNumZombieDrawables++; - - // We're dead. Free up all of our references to other objects - cleanupReferences(); -// sDeadList.push_back(this); -} - -LLVOVolume* LLDrawable::getVOVolume() const -{ - LLViewerObject* objectp = mVObjp; - if ( !isDead() && objectp && (objectp->getPCode() == LL_PCODE_VOLUME)) - { - return ((LLVOVolume*)objectp); - } - else - { - return NULL; - } -} - -const LLMatrix4& LLDrawable::getRenderMatrix() const -{ - return isRoot() ? getWorldMatrix() : getParent()->getWorldMatrix(); -} - -bool LLDrawable::isLight() const -{ - LLViewerObject* objectp = mVObjp; - if ( objectp && (objectp->getPCode() == LL_PCODE_VOLUME) && !isDead()) - { - return ((LLVOVolume*)objectp)->getIsLight(); - } - else - { - return false; - } -} - -void LLDrawable::cleanupReferences() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE; - - std::for_each(mFaces.begin(), mFaces.end(), DeletePointer()); - mFaces.clear(); - - gPipeline.unlinkDrawable(this); - - removeFromOctree(); - - // Cleanup references to other objects - mVObjp = NULL; - mParent = NULL; -} - -void LLDrawable::removeFromOctree() -{ - if(!mEntry) - { - return; - } - - mEntry->removeData(this); - if(mEntry->hasVOCacheEntry()) - { - getRegion()->removeActiveCacheEntry((LLVOCacheEntry*)mEntry->getVOCacheEntry(), this); - } - mEntry = NULL; -} - -void LLDrawable::cleanupDeadDrawables() -{ - /* - S32 i; - for (i = 0; i < sDeadList.size(); i++) - { - if (sDeadList[i]->getNumRefs() > 1) - { - LL_WARNS() << "Dead drawable has " << sDeadList[i]->getNumRefs() << " remaining refs" << LL_ENDL; - gPipeline.findReferences(sDeadList[i]); - } - } - */ - sDeadList.clear(); -} - -S32 LLDrawable::findReferences(LLDrawable *drawablep) -{ - S32 count = 0; - if (mParent == drawablep) - { - LL_INFOS() << this << ": parent reference" << LL_ENDL; - count++; - } - return count; -} - -LLFace* LLDrawable::addFace(LLFacePool *poolp, LLViewerTexture *texturep) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE - - LLFace *face; - { - face = new LLFace(this, mVObjp); - } - - if (!face) LL_ERRS() << "Allocating new Face: " << mFaces.size() << LL_ENDL; - - if (face) - { - mFaces.push_back(face); - - if (poolp) - { - face->setPool(poolp, texturep); - } - - if (isState(UNLIT)) - { - face->setState(LLFace::FULLBRIGHT); - } - } - return face; -} - -LLFace* LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE - - LLFace *face; - - face = new LLFace(this, mVObjp); - - face->setTEOffset(mFaces.size()); - face->setTexture(texturep); - face->setPoolType(gPipeline.getPoolTypeFromTE(te, texturep)); - - mFaces.push_back(face); - - if (isState(UNLIT)) - { - face->setState(LLFace::FULLBRIGHT); - } - - return face; - -} - -LLFace* LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep, LLViewerTexture *normalp) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE - - LLFace *face; - face = new LLFace(this, mVObjp); - - face->setTEOffset(mFaces.size()); - face->setTexture(texturep); - face->setNormalMap(normalp); - face->setPoolType(gPipeline.getPoolTypeFromTE(te, texturep)); - - mFaces.push_back(face); - - if (isState(UNLIT)) - { - face->setState(LLFace::FULLBRIGHT); - } - - return face; - -} - -LLFace* LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep, LLViewerTexture *normalp, LLViewerTexture *specularp) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE - - LLFace *face; - face = new LLFace(this, mVObjp); - - face->setTEOffset(mFaces.size()); - face->setTexture(texturep); - face->setNormalMap(normalp); - face->setSpecularMap(specularp); - face->setPoolType(gPipeline.getPoolTypeFromTE(te, texturep)); - - mFaces.push_back(face); - - if (isState(UNLIT)) - { - face->setState(LLFace::FULLBRIGHT); - } - - return face; - -} - -void LLDrawable::setNumFaces(const S32 newFaces, LLFacePool *poolp, LLViewerTexture *texturep) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE - - if (newFaces == (S32)mFaces.size()) - { - return; - } - else if (newFaces < (S32)mFaces.size()) - { - std::for_each(mFaces.begin() + newFaces, mFaces.end(), DeletePointer()); - mFaces.erase(mFaces.begin() + newFaces, mFaces.end()); - } - else // (newFaces > mFaces.size()) - { - mFaces.reserve(newFaces); - for (int i = mFaces.size(); i<newFaces; i++) - { - addFace(poolp, texturep); - } - } - - llassert_always(mFaces.size() == newFaces); -} - -void LLDrawable::setNumFacesFast(const S32 newFaces, LLFacePool *poolp, LLViewerTexture *texturep) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE - - if (newFaces <= (S32)mFaces.size() && newFaces >= (S32)mFaces.size()/2) - { - return; - } - else if (newFaces < (S32)mFaces.size()) - { - std::for_each(mFaces.begin() + newFaces, mFaces.end(), DeletePointer()); - mFaces.erase(mFaces.begin() + newFaces, mFaces.end()); - } - else // (newFaces > mFaces.size()) - { - mFaces.reserve(newFaces); - for (int i = mFaces.size(); i<newFaces; i++) - { - addFace(poolp, texturep); - } - } - - llassert_always(mFaces.size() == newFaces) ; -} - -void LLDrawable::mergeFaces(LLDrawable* src) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE - - U32 face_count = mFaces.size() + src->mFaces.size(); - - mFaces.reserve(face_count); - for (U32 i = 0; i < src->mFaces.size(); i++) - { - LLFace* facep = src->mFaces[i]; - facep->setDrawable(this); - mFaces.push_back(facep); - } - src->mFaces.clear(); -} - -void LLDrawable::deleteFaces(S32 offset, S32 count) -{ - face_list_t::iterator face_begin = mFaces.begin() + offset; - face_list_t::iterator face_end = face_begin + count; - - std::for_each(face_begin, face_end, DeletePointer()); - mFaces.erase(face_begin, face_end); -} - -void LLDrawable::update() -{ - LL_ERRS() << "Shouldn't be called!" << LL_ENDL; -} - - -void LLDrawable::updateMaterial() -{ -} - -void LLDrawable::makeActive() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE - -#if !LL_RELEASE_FOR_DOWNLOAD - if (mVObjp.notNull()) - { - U32 pcode = mVObjp->getPCode(); - if (pcode == LLViewerObject::LL_VO_WATER || - pcode == LLViewerObject::LL_VO_VOID_WATER || - pcode == LLViewerObject::LL_VO_SURFACE_PATCH || - pcode == LLViewerObject::LL_VO_PART_GROUP || - pcode == LLViewerObject::LL_VO_HUD_PART_GROUP || - pcode == LLViewerObject::LL_VO_SKY) - { - LL_ERRS() << "Static viewer object has active drawable!" << LL_ENDL; - } - } -#endif - - if (!isState(ACTIVE)) // && mGeneration > 0) - { - setState(ACTIVE); - - //parent must be made active first - if (!isRoot() && !mParent->isActive()) - { - mParent->makeActive(); - //NOTE: linked set will now NEVER become static - mParent->setState(LLDrawable::ACTIVE_CHILD); - } - - //all child objects must also be active - llassert_always(mVObjp); - - LLViewerObject::const_child_list_t& child_list = mVObjp->getChildren(); - for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); - iter != child_list.end(); iter++) - { - LLViewerObject* child = *iter; - LLDrawable* drawable = child->mDrawable; - if (drawable) - { - drawable->makeActive(); - } - } - - if (mVObjp->getPCode() == LL_PCODE_VOLUME) - { - gPipeline.markRebuild(this, LLDrawable::REBUILD_VOLUME); - } - updatePartition(); - } - else if (!isRoot() && !mParent->isActive()) //this should not happen, but occasionally it does... - { - mParent->makeActive(); - //NOTE: linked set will now NEVER become static - mParent->setState(LLDrawable::ACTIVE_CHILD); - } - - llassert(isAvatar() || isRoot() || mParent->isActive()); -} - - -void LLDrawable::makeStatic(bool warning_enabled) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE - - if (isState(ACTIVE) && - !isState(ACTIVE_CHILD) && - !mVObjp->isAttachment() && - !mVObjp->isFlexible() && - !mVObjp->isAnimatedObject()) - { - clearState(ACTIVE | ANIMATED_CHILD); - - //drawable became static with active parent, not acceptable - llassert(mParent.isNull() || !mParent->isActive() || !warning_enabled); - - LLViewerObject::const_child_list_t& child_list = mVObjp->getChildren(); - for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); - iter != child_list.end(); iter++) - { - LLViewerObject* child = *iter; - LLDrawable* child_drawable = child->mDrawable; - if (child_drawable) - { - if (child_drawable->getParent() != this) - { - LL_WARNS() << "Child drawable has unknown parent." << LL_ENDL; - } - child_drawable->makeStatic(warning_enabled); - } - } - - if (mVObjp->getPCode() == LL_PCODE_VOLUME) - { - gPipeline.markRebuild(this, LLDrawable::REBUILD_VOLUME); - } - - if (mSpatialBridge) - { - mSpatialBridge->markDead(); - setSpatialBridge(NULL); - } - updatePartition(); - } - - llassert(isAvatar() || isRoot() || mParent->isStatic()); -} - -// Returns "distance" between target destination and resulting xfrom -F32 LLDrawable::updateXform(bool undamped) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE - - bool damped = !undamped; - - // Position - const LLVector3 old_pos(mXform.getPosition()); - LLVector3 target_pos; - if (mXform.isRoot()) - { - // get root position in your agent's region - target_pos = mVObjp->getPositionAgent(); - } - else - { - // parent-relative position - target_pos = mVObjp->getPosition(); - } - - // Rotation - const LLQuaternion old_rot(mXform.getRotation()); - LLQuaternion target_rot = mVObjp->getRotation(); - //scaling - LLVector3 target_scale = mVObjp->getScale(); - LLVector3 old_scale = mCurrentScale; - - // Damping - F32 dist_squared = 0.f; - F32 camdist2 = (mDistanceWRTCamera * mDistanceWRTCamera); - - if (damped && isVisible()) - { - F32 lerp_amt = llclamp(LLSmoothInterpolation::getInterpolant(OBJECT_DAMPING_TIME_CONSTANT), 0.f, 1.f); - LLVector3 new_pos = lerp(old_pos, target_pos, lerp_amt); - dist_squared = dist_vec_squared(new_pos, target_pos); - - LLQuaternion new_rot = nlerp(lerp_amt, old_rot, target_rot); - // FIXME: This can be negative! It is be possible for some rots to 'cancel out' pos or size changes. - dist_squared += (1.f - dot(new_rot, target_rot)) * 10.f; - - LLVector3 new_scale = lerp(old_scale, target_scale, lerp_amt); - dist_squared += dist_vec_squared(new_scale, target_scale); - - if ((dist_squared >= MIN_INTERPOLATE_DISTANCE_SQUARED * camdist2) && - (dist_squared <= MAX_INTERPOLATE_DISTANCE_SQUARED)) - { - // interpolate - target_pos = new_pos; - target_rot = new_rot; - target_scale = new_scale; - } - else if (mVObjp->getAngularVelocity().isExactlyZero()) - { - // snap to final position (only if no target omega is applied) - dist_squared = 0.0f; - //set target scale here, because of dist_squared = 0.0f remove object from move list - mCurrentScale = target_scale; - - if (getVOVolume() && !isRoot()) - { //child prim snapping to some position, needs a rebuild - gPipeline.markRebuild(this, LLDrawable::REBUILD_POSITION); - } - } - } - else - { - // The following fixes MAINT-1742 but breaks vehicles similar to MAINT-2275 - // dist_squared = dist_vec_squared(old_pos, target_pos); - - // The following fixes MAINT-2247 but causes MAINT-2275 - //dist_squared += (1.f - dot(old_rot, target_rot)) * 10.f; - //dist_squared += dist_vec_squared(old_scale, target_scale); - } - - const LLVector3 vec = mCurrentScale-target_scale; - - //It's a very important on each cycle on Drawable::update form(), when object remained in move - //, list update the CurrentScale member, because if do not do that, it remained in this list forever - //or when the delta time between two frames a become a sufficiently large (due to interpolation) - //for overcome the MIN_INTERPOLATE_DISTANCE_SQUARED. - mCurrentScale = target_scale; - - if (vec*vec > MIN_INTERPOLATE_DISTANCE_SQUARED) - { //scale change requires immediate rebuild - gPipeline.markRebuild(this, LLDrawable::REBUILD_POSITION); - } - else if (!isRoot() && - (!mVObjp->getAngularVelocity().isExactlyZero() || - dist_squared > 0.f)) - { //child prim moving relative to parent, tag as needing to be rendered atomically and rebuild - dist_squared = 1.f; //keep this object on the move list - if (!isState(LLDrawable::ANIMATED_CHILD)) - { - setState(LLDrawable::ANIMATED_CHILD); - gPipeline.markRebuild(this, LLDrawable::REBUILD_ALL); - mVObjp->dirtySpatialGroup(); - } - } - else if (!isRoot() && - ((dist_vec_squared(old_pos, target_pos) > 0.f) - || (1.f - dot(old_rot, target_rot)) > 0.f)) - { //fix for BUG-840, MAINT-2275, MAINT-1742, MAINT-2247 - mVObjp->shrinkWrap(); - gPipeline.markRebuild(this, LLDrawable::REBUILD_POSITION); - } - else if (!getVOVolume() && !isAvatar()) - { - movePartition(); - } - - // Update - mXform.setPosition(target_pos); - mXform.setRotation(target_rot); - mXform.setScale(LLVector3(1,1,1)); //no scale in drawable transforms (IT'S A RULE!) - mXform.updateMatrix(); - if (isRoot() && mVObjp->isAnimatedObject() && mVObjp->getControlAvatar()) - { - mVObjp->getControlAvatar()->matchVolumeTransform(); - } - - if (mSpatialBridge) - { - gPipeline.markMoved(mSpatialBridge, false); - } - return dist_squared; -} - -void LLDrawable::setRadius(F32 radius) -{ - if (mRadius != radius) - { - mRadius = radius; - } -} - -void LLDrawable::moveUpdatePipeline(bool moved) -{ - if (moved) - { - makeActive(); - } - - // Update the face centers. - for (S32 i = 0; i < getNumFaces(); i++) - { - LLFace* face = getFace(i); - if (face) - { - face->updateCenterAgent(); - } - } -} - -void LLDrawable::movePartition() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE - - LLSpatialPartition* part = getSpatialPartition(); - if (part) - { - part->move(this, getSpatialGroup()); - } -} - -bool LLDrawable::updateMove() -{ - if (isDead()) - { - LL_WARNS() << "Update move on dead drawable!" << LL_ENDL; - return true; - } - - if (mVObjp.isNull()) - { - return false; - } - - makeActive(); - - return isState(MOVE_UNDAMPED) ? updateMoveUndamped() : updateMoveDamped(); -} - -bool LLDrawable::updateMoveUndamped() -{ - F32 dist_squared = updateXform(true); - - mGeneration++; - - if (!isState(LLDrawable::INVISIBLE)) - { - bool moved = (dist_squared > 0.001f && dist_squared < 255.99f); - moveUpdatePipeline(moved); - mVObjp->updateText(); - } - - mVObjp->clearChanged(LLXform::MOVED); - return true; -} - -void LLDrawable::updatePartition() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE - - if (!getVOVolume()) - { - movePartition(); - } - else if (mSpatialBridge) - { - gPipeline.markMoved(mSpatialBridge, false); - } - else - { - //a child prim moved and needs its verts regenerated - gPipeline.markRebuild(this, LLDrawable::REBUILD_POSITION); - } -} - -bool LLDrawable::updateMoveDamped() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE - - F32 dist_squared = updateXform(false); - - mGeneration++; - - if (!isState(LLDrawable::INVISIBLE)) - { - bool moved = (dist_squared > 0.001f && dist_squared < 128.0f); - moveUpdatePipeline(moved); - mVObjp->updateText(); - } - - bool done_moving = dist_squared == 0.0f; - - if (done_moving) - { - mVObjp->clearChanged(LLXform::MOVED); - } - - return done_moving; -} - -void LLDrawable::updateDistance(LLCamera& camera, bool force_update) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE - - if (LLViewerCamera::sCurCameraID != LLViewerCamera::CAMERA_WORLD) - { - LL_WARNS() << "Attempted to update distance for non-world camera." << LL_ENDL; - return; - } - - if (gShiftFrame) - { - return; - } - - //switch LOD with the spatial group to avoid artifacts - //LLSpatialGroup* sg = getSpatialGroup(); - - LLVector3 pos; - - //if (!sg || sg->changeLOD()) - { - LLVOVolume* volume = getVOVolume(); - if (volume) - { - if (getGroup()) - { - pos.set(getPositionGroup().getF32ptr()); - } - else - { - pos = getPositionAgent(); - } - - if (isState(LLDrawable::HAS_ALPHA)) - { - for (S32 i = 0; i < getNumFaces(); i++) - { - LLFace* facep = getFace(i); - if (facep && - (force_update || facep->isInAlphaPool())) - { - LLVector4a box; - box.setSub(facep->mExtents[1], facep->mExtents[0]); - box.mul(0.25f); - LLVector3 v = (facep->mCenterLocal-camera.getOrigin()); - const LLVector3& at = camera.getAtAxis(); - for (U32 j = 0; j < 3; j++) - { - v.mV[j] -= box[j] * at.mV[j]; - } - facep->mDistance = v * camera.getAtAxis(); - } - } - } - - - // MAINT-7926 Handle volumes in an animated object as a special case - // SL-937: add dynamic box handling for rigged mesh on regular avatars. - //if (volume->getAvatar() && volume->getAvatar()->isControlAvatar()) - if (volume->getAvatar()) - { - const LLVector3* av_box = volume->getAvatar()->getLastAnimExtents(); - LLVector3 cam_pos_from_agent = LLViewerCamera::getInstance()->getOrigin(); - LLVector3 cam_to_box_offset = point_to_box_offset(cam_pos_from_agent, av_box); - mDistanceWRTCamera = llmax(0.01f, ll_round(cam_to_box_offset.magVec(), 0.01f)); - mVObjp->updateLOD(); - return; - } - } - else - { - pos = LLVector3(getPositionGroup().getF32ptr()); - } - - pos -= camera.getOrigin(); - mDistanceWRTCamera = ll_round(pos.magVec(), 0.01f); - mVObjp->updateLOD(); - } -} - -void LLDrawable::updateTexture() -{ - if (isDead()) - { - LL_WARNS() << "Dead drawable updating texture!" << LL_ENDL; - return; - } - - if (getNumFaces() != mVObjp->getNumTEs()) - { //drawable is transitioning its face count - return; - } - - if (getVOVolume()) - { - gPipeline.markRebuild(this, LLDrawable::REBUILD_MATERIAL); - } -} - -bool LLDrawable::updateGeometry() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE - - llassert(mVObjp.notNull()); - bool res = mVObjp && mVObjp->updateGeometry(this); - return res; -} - -void LLDrawable::shiftPos(const LLVector4a &shift_vector) -{ - if (isDead()) - { - LL_WARNS() << "Shifting dead drawable" << LL_ENDL; - return; - } - - if (mParent) - { - mXform.setPosition(mVObjp->getPosition()); - } - else - { - mXform.setPosition(mVObjp->getPositionAgent()); - } - - mXform.updateMatrix(); - - if (isStatic()) - { - LLVOVolume* volume = getVOVolume(); - - bool rebuild = (!volume && - getRenderType() != LLPipeline::RENDER_TYPE_TREE && - getRenderType() != LLPipeline::RENDER_TYPE_TERRAIN && - getRenderType() != LLPipeline::RENDER_TYPE_SKY); - - if (rebuild) - { - gPipeline.markRebuild(this, LLDrawable::REBUILD_ALL); - } - - for (S32 i = 0; i < getNumFaces(); i++) - { - LLFace *facep = getFace(i); - if (facep) - { - facep->mCenterAgent += LLVector3(shift_vector.getF32ptr()); - facep->mExtents[0].add(shift_vector); - facep->mExtents[1].add(shift_vector); - - if (rebuild && facep->hasGeometry()) - { - facep->clearVertexBuffer(); - } - } - } - - shift(shift_vector); - } - else if (mSpatialBridge) - { - mSpatialBridge->shiftPos(shift_vector); - } - else if (isAvatar()) - { - shift(shift_vector); - } - - mVObjp->onShift(shift_vector); -} - -const LLVector3& LLDrawable::getBounds(LLVector3& min, LLVector3& max) const -{ - mXform.getMinMax(min,max); - return mXform.getPositionW(); -} - -void LLDrawable::updateSpatialExtents() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE - - if (mVObjp) - { - const LLVector4a* exts = getSpatialExtents(); - LLVector4a extents[2] = { exts[0], exts[1] }; - - mVObjp->updateSpatialExtents(extents[0], extents[1]); - setSpatialExtents(extents[0], extents[1]); - } - - updateBinRadius(); - - if (mSpatialBridge.notNull()) - { - getGroupPosition().splat(0.f); - } -} - - -void LLDrawable::updateBinRadius() -{ - if (mVObjp.notNull()) - { - setBinRadius(llmin(mVObjp->getBinRadius(), 256.f)); - } - else - { - setBinRadius(llmin(getRadius()*4.f, 256.f)); - } -} - -void LLDrawable::updateSpecialHoverCursor(bool enabled) -{ - // TODO: maintain a list of objects that have special - // hover cursors, then use that list for per-frame - // hover cursor selection. JC -} - -F32 LLDrawable::getVisibilityRadius() const -{ - if (isDead()) - { - return 0.f; - } - else if (isLight()) - { - const LLVOVolume *vov = getVOVolume(); - if (vov) - { - return llmax(getRadius(), vov->getLightRadius()); - } else { - // LL_WARNS() ? - } - } - return getRadius(); -} - -void LLDrawable::updateUVMinMax() -{ -} - -//virtual -bool LLDrawable::isVisible() const -{ - if (LLViewerOctreeEntryData::isVisible()) - { - return true; - } - - { - LLViewerOctreeGroup* group = mEntry->getGroup(); - if (group && group->isVisible()) - { - LLViewerOctreeEntryData::setVisible(); - return true; - } - } - - return false; -} - -//virtual -bool LLDrawable::isRecentlyVisible() const -{ - //currently visible or visible in the previous frame. - bool vis = LLViewerOctreeEntryData::isRecentlyVisible(); - - if(!vis) - { - const U32 MIN_VIS_FRAME_RANGE = 2 ; //two frames:the current one and the last one. - vis = (sCurVisible - getVisible() < MIN_VIS_FRAME_RANGE); - } - - return vis ; -} - -void LLDrawable::setGroup(LLViewerOctreeGroup *groupp) - { - LLSpatialGroup* cur_groupp = (LLSpatialGroup*)getGroup(); - - //precondition: mGroupp MUST be null or DEAD or mGroupp MUST NOT contain this - //llassert(!cur_groupp || cur_groupp->isDead() || !cur_groupp->hasElement(this)); - - //precondition: groupp MUST be null or groupp MUST contain this - llassert(!groupp || (LLSpatialGroup*)groupp->hasElement(this)); - - if (cur_groupp != groupp && getVOVolume()) - { - //NULL out vertex buffer references for volumes on spatial group change to maintain - //requirement that every face vertex buffer is either NULL or points to a vertex buffer - //contained by its drawable's spatial group - for (S32 i = 0; i < getNumFaces(); ++i) - { - LLFace* facep = getFace(i); - if (facep) - { - facep->clearVertexBuffer(); - } - } - } - - //postcondition: if next group is NULL, previous group must be dead OR NULL OR binIndex must be -1 - //postcondition: if next group is NOT NULL, binIndex must not be -1 - //llassert(groupp == NULL ? (cur_groupp == NULL || cur_groupp->isDead()) || (!getEntry() || getEntry()->getBinIndex() == -1) : - // (getEntry() && getEntry()->getBinIndex() != -1)); - - LLViewerOctreeEntryData::setGroup(groupp); -} - -/* -* Get the SpatialPartition this Drawable should use. -* Checks current SpatialPartition assignment and corrects if it is invalid. -*/ -LLSpatialPartition* LLDrawable::getSpatialPartition() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE - - LLSpatialPartition* retval = NULL; - - if (!mVObjp || - !getVOVolume() || - isStatic()) - { - retval = gPipeline.getSpatialPartition((LLViewerObject*)mVObjp); - } - else if (isRoot()) - { - // determine if the spatial bridge has changed - if (mSpatialBridge) - { - U32 partition_type = mSpatialBridge->asPartition()->mPartitionType; - bool is_hud = mVObjp->isHUDAttachment(); - bool is_animesh = mVObjp->isAnimatedObject() && mVObjp->getControlAvatar() != NULL; - bool is_attachment = mVObjp->isAttachment() && !is_hud && !is_animesh; - if ((partition_type == LLViewerRegion::PARTITION_HUD) != is_hud) - { - // Was/became HUD - // remove obsolete bridge - mSpatialBridge->markDead(); - setSpatialBridge(NULL); - } - else if ((partition_type == LLViewerRegion::PARTITION_CONTROL_AV) != is_animesh) - { - // Was/became part of animesh - // remove obsolete bridge - mSpatialBridge->markDead(); - setSpatialBridge(NULL); - } - else if ((partition_type == LLViewerRegion::PARTITION_AVATAR) != is_attachment) - { - // Was/became part of avatar - // remove obsolete bridge - mSpatialBridge->markDead(); - setSpatialBridge(NULL); - } - } - //must be an active volume - if (!mSpatialBridge) - { - if (mVObjp->isHUDAttachment()) - { - setSpatialBridge(new LLHUDBridge(this, getRegion())); - } - else if (mVObjp->isAnimatedObject() && mVObjp->getControlAvatar()) - { - setSpatialBridge(new LLControlAVBridge(this, getRegion())); - mVObjp->getControlAvatar()->mControlAVBridge = (LLControlAVBridge*)getSpatialBridge(); - } - // check HUD first, because HUD is also attachment - else if (mVObjp->isAttachment()) - { - // Attachment - // Use AvatarBridge of root object in attachment linkset - setSpatialBridge(new LLAvatarBridge(this, getRegion())); - } - else - { - // Moving linkset, use VolumeBridge of root object in linkset - setSpatialBridge(new LLVolumeBridge(this, getRegion())); - } - } - return mSpatialBridge->asPartition(); - } - else - { - retval = getParent()->getSpatialPartition(); - } - - if (retval && mSpatialBridge.notNull()) - { - mSpatialBridge->markDead(); - setSpatialBridge(NULL); - } - - return retval; -} - -//======================================= -// Spatial Partition Bridging Drawable -//======================================= - -LLSpatialBridge::LLSpatialBridge(LLDrawable* root, bool render_by_group, U32 data_mask, LLViewerRegion* regionp) : - LLDrawable(root->getVObj(), true), - LLSpatialPartition(data_mask, render_by_group, regionp) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE; - mOcclusionEnabled = false; - mBridge = this; - mDrawable = root; - root->setSpatialBridge(this); - - mRenderType = mDrawable->mRenderType; - mDrawableType = mDrawable->mRenderType; - - mPartitionType = LLViewerRegion::PARTITION_VOLUME; - - mOctree->balance(); - - llassert(mDrawable); - llassert(mDrawable->getRegion()); - LLSpatialPartition *part = mDrawable->getRegion()->getSpatialPartition(mPartitionType); - llassert(part); - - if (part) - { - part->put(this); - } -} - -LLSpatialBridge::~LLSpatialBridge() -{ - if(mEntry) - { - LLSpatialGroup* group = getSpatialGroup(); - if (group) - { - group->getSpatialPartition()->remove(this, group); - } - } - - //delete octree here so listeners will still be able to access bridge specific state - destroyTree(); -} - -void LLSpatialBridge::destroyTree() -{ - delete mOctree; - mOctree = NULL; -} - -void LLSpatialBridge::updateSpatialExtents() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE - - LLSpatialGroup* root = (LLSpatialGroup*) mOctree->getListener(0); - - root->rebound(); - - const LLVector4a* root_bounds = root->getBounds(); - LLVector4a offset; - LLVector4a size = root_bounds[1]; - - //VECTORIZE THIS - LLMatrix4a mat; - mat.loadu(mDrawable->getXform()->getWorldMatrix()); - - LLVector4a t; - t.splat(0.f); - - LLVector4a center; - mat.affineTransform(t, center); - - mat.rotate(root_bounds[0], offset); - center.add(offset); - - LLVector4a v[4]; - - //get 4 corners of bounding box - mat.rotate(size,v[0]); - - LLVector4a scale; - - scale.set(-1.f, -1.f, 1.f); - scale.mul(size); - mat.rotate(scale, v[1]); - - scale.set(1.f, -1.f, -1.f); - scale.mul(size); - mat.rotate(scale, v[2]); - - scale.set(-1.f, 1.f, -1.f); - scale.mul(size); - mat.rotate(scale, v[3]); - - LLVector4a newMin; - LLVector4a newMax; - newMin = newMax = center; - for (U32 i = 0; i < 4; i++) - { - LLVector4a delta; - delta.setAbs(v[i]); - LLVector4a min; - min.setSub(center, delta); - LLVector4a max; - max.setAdd(center, delta); - - newMin.setMin(newMin, min); - newMax.setMax(newMax, max); - } - setSpatialExtents(newMin, newMax); - - LLVector4a diagonal; - diagonal.setSub(newMax, newMin); - mRadius = diagonal.getLength3().getF32() * 0.5f; - - LLVector4a& pos = getGroupPosition(); - pos.setAdd(newMin,newMax); - pos.mul(0.5f); - updateBinRadius(); -} - -void LLSpatialBridge::updateBinRadius() -{ - setBinRadius(llmin( mOctree->getSize()[0]*0.5f, 256.f)); -} - -LLCamera LLSpatialBridge::transformCamera(LLCamera& camera) -{ - LLCamera ret = camera; - LLXformMatrix* mat = mDrawable->getXform(); - LLVector3 center = LLVector3(0,0,0) * mat->getWorldMatrix(); - - LLVector3 delta = ret.getOrigin() - center; - LLQuaternion rot = ~mat->getRotation(); - - delta *= rot; - LLVector3 lookAt = ret.getAtAxis(); - LLVector3 up_axis = ret.getUpAxis(); - LLVector3 left_axis = ret.getLeftAxis(); - - lookAt *= rot; - up_axis *= rot; - left_axis *= rot; - - if (!delta.isFinite()) - { - delta.clearVec(); - } - - ret.setOrigin(delta); - ret.setAxes(lookAt, left_axis, up_axis); - - return ret; -} - -void LLSpatialBridge::transformExtents(const LLVector4a* src, LLVector4a* dst) -{ - LLMatrix4 mat = mDrawable->getXform()->getWorldMatrix(); - mat.invert(); - - LLMatrix4a world_to_bridge(mat); - - matMulBoundBox(world_to_bridge, src, dst); -} - - -void LLDrawable::setVisible(LLCamera& camera, std::vector<LLDrawable*>* results, bool for_select) -{ - LLViewerOctreeEntryData::setVisible(); - -#if 0 && !LL_RELEASE_FOR_DOWNLOAD - //crazy paranoid rules checking - if (getVOVolume()) - { - if (!isRoot()) - { - if (isActive() && !mParent->isActive()) - { - LL_ERRS() << "Active drawable has static parent!" << LL_ENDL; - } - - if (isStatic() && !mParent->isStatic()) - { - LL_ERRS() << "Static drawable has active parent!" << LL_ENDL; - } - - if (mSpatialBridge) - { - LL_ERRS() << "Child drawable has spatial bridge!" << LL_ENDL; - } - } - else if (isActive() && !mSpatialBridge) - { - LL_ERRS() << "Active root drawable has no spatial bridge!" << LL_ENDL; - } - else if (isStatic() && mSpatialBridge.notNull()) - { - LL_ERRS() << "Static drawable has spatial bridge!" << LL_ENDL; - } - } -#endif -} - -class LLOctreeMarkNotCulled: public OctreeTraveler -{ -public: - LLCamera* mCamera; - - LLOctreeMarkNotCulled(LLCamera* camera_in) : mCamera(camera_in) { } - - virtual void traverse(const OctreeNode* node) - { - LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0); - group->setVisible(); - OctreeTraveler::traverse(node); - } - - void visit(const OctreeNode* branch) - { - gPipeline.markNotCulled((LLSpatialGroup*) branch->getListener(0), *mCamera); - } -}; - -void LLSpatialBridge::setVisible(LLCamera& camera_in, std::vector<LLDrawable*>* results, bool for_select) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE - - if (!gPipeline.hasRenderType(mDrawableType)) - { - return; - } - - - //HACK don't draw attachments for avatars that haven't been visible in more than a frame - LLViewerObject *vobj = mDrawable->getVObj(); - if (vobj && vobj->isAttachment() && !vobj->isHUDAttachment()) - { - LLDrawable* av; - LLDrawable* parent = mDrawable->getParent(); - - if (parent) - { - LLViewerObject* objparent = parent->getVObj(); - av = objparent->mDrawable; - LLSpatialGroup* group = av->getSpatialGroup(); - - bool impostor = false; - bool loaded = false; - if (objparent->isAvatar()) - { - LLVOAvatar* avatarp = (LLVOAvatar*) objparent; - if (avatarp->isVisible()) - { - impostor = objparent->isAvatar() && !LLPipeline::sImpostorRender && ((LLVOAvatar*) objparent)->isImpostor(); - loaded = objparent->isAvatar() && ((LLVOAvatar*) objparent)->isFullyLoaded(); - } - else - { - return; - } - } - - if (!group || - LLDrawable::getCurrentFrame() - av->getVisible() > 1 || - impostor || - !loaded) - { - return; - } - } - } - - - LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0); - group->rebound(); - - LLVector4a center; - const LLVector4a* exts = getSpatialExtents(); - center.setAdd(exts[0], exts[1]); - center.mul(0.5f); - LLVector4a size; - size.setSub(exts[1], exts[0]); - size.mul(0.5f); - - if ((LLPipeline::sShadowRender && camera_in.AABBInFrustum(center, size)) || - LLPipeline::sImpostorRender || - (camera_in.AABBInFrustumNoFarClip(center, size) && - AABBSphereIntersect(exts[0], exts[1], camera_in.getOrigin(), camera_in.mFrustumCornerDist))) - { - if (!LLPipeline::sImpostorRender && - !LLPipeline::sShadowRender && - LLPipeline::calcPixelArea(center, size, camera_in) < FORCE_INVISIBLE_AREA) - { - return; - } - - LLDrawable::setVisible(camera_in); - - if (for_select) - { - results->push_back(mDrawable); - if (mDrawable->getVObj()) - { - LLViewerObject::const_child_list_t& child_list = mDrawable->getVObj()->getChildren(); - for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); - iter != child_list.end(); iter++) - { - LLViewerObject* child = *iter; - LLDrawable* drawable = child->mDrawable; - results->push_back(drawable); - } - } - } - else - { - LLCamera trans_camera = transformCamera(camera_in); - LLOctreeMarkNotCulled culler(&trans_camera); - culler.traverse(mOctree); - } - } -} - -void LLSpatialBridge::updateDistance(LLCamera& camera_in, bool force_update) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE - - if (mDrawable == NULL) - { - markDead(); - return; - } - - if (gShiftFrame) - { - return; - } - - if (mDrawable->getVObj()) - { - // Don't update if we are part of impostor, unles it's an impostor pass - if (!LLPipeline::sImpostorRender && mDrawable->getVObj()->isAttachment()) - { - LLDrawable* parent = mDrawable->getParent(); - if (parent && parent->getVObj()) - { - LLVOAvatar* av = parent->getVObj()->asAvatar(); - if (av && av->isImpostor()) - { - return; - } - } - } - - LLCamera camera = transformCamera(camera_in); - - mDrawable->updateDistance(camera, force_update); - - LLViewerObject::const_child_list_t& child_list = mDrawable->getVObj()->getChildren(); - for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); - iter != child_list.end(); iter++) - { - LLViewerObject* child = *iter; - LLDrawable* drawable = child->mDrawable; - if (!drawable) - { - continue; - } - - if (!drawable->isAvatar()) - { - drawable->updateDistance(camera, force_update); - } - } - } -} - -void LLSpatialBridge::makeActive() -{ //it is an error to make a spatial bridge active (it's already active) - LL_ERRS() << "makeActive called on spatial bridge" << LL_ENDL; -} - -void LLSpatialBridge::move(LLDrawable *drawablep, LLSpatialGroup *curp, bool immediate) -{ - LLSpatialPartition::move(drawablep, curp, immediate); - gPipeline.markMoved(this, false); -} - -bool LLSpatialBridge::updateMove() -{ - llassert_always(mDrawable); - llassert_always(mDrawable->mVObjp); - llassert_always(mDrawable->getRegion()); - LLSpatialPartition* part = mDrawable->getRegion()->getSpatialPartition(mPartitionType); - llassert_always(part); - - mOctree->balance(); - if (part) - { - part->move(this, getSpatialGroup(), true); - } - return true; -} - -void LLSpatialBridge::shiftPos(const LLVector4a& vec) -{ - LLDrawable::shift(vec); -} - -void LLSpatialBridge::cleanupReferences() -{ - LLDrawable::cleanupReferences(); - if (mDrawable) - { - mDrawable->setGroup(NULL); - - if (mDrawable->getVObj()) - { - LLViewerObject::const_child_list_t& child_list = mDrawable->getVObj()->getChildren(); - for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); - iter != child_list.end(); iter++) - { - LLViewerObject* child = *iter; - LLDrawable* drawable = child->mDrawable; - if (drawable) - { - drawable->setGroup(NULL); - } - } - } - - LLDrawable* drawablep = mDrawable; - mDrawable = NULL; - drawablep->setSpatialBridge(NULL); - } -} - -const LLVector3 LLDrawable::getPositionAgent() const -{ - if (getVOVolume()) - { - if (isActive()) - { - LLVector3 pos(0,0,0); - if (!isRoot()) - { - pos = mVObjp->getPosition(); - } - return pos * getRenderMatrix(); - } - else - { - return mVObjp->getPositionAgent(); - } - } - else - { - return getWorldPosition(); - } -} - -bool LLDrawable::isAnimating() const -{ - if (!getVObj()) - { - return true; - } - - if (getScale() != mVObjp->getScale()) - { - return true; - } - - if (mVObjp->getPCode() == LLViewerObject::LL_VO_PART_GROUP) - { - return true; - } - if (mVObjp->getPCode() == LLViewerObject::LL_VO_HUD_PART_GROUP) - { - return true; - } - - /*if (!isRoot() && !mVObjp->getAngularVelocity().isExactlyZero()) - { //target omega - return true; - }*/ - - return false; -} - -void LLDrawable::updateFaceSize(S32 idx) -{ - if (mVObjp.notNull()) - { - mVObjp->updateFaceSize(idx); - } -} - -LLDrawable* LLDrawable::getRoot() -{ - LLDrawable* ret = this; - while (!ret->isRoot()) - { - ret = ret->getParent(); - } - - return ret; -} - -LLBridgePartition::LLBridgePartition(LLViewerRegion* regionp) -: LLSpatialPartition(0, false, regionp) -{ - mDrawableType = LLPipeline::RENDER_TYPE_VOLUME; - mPartitionType = LLViewerRegion::PARTITION_BRIDGE; - mLODPeriod = 16; - mSlopRatio = 0.25f; -} - -LLAvatarPartition::LLAvatarPartition(LLViewerRegion* regionp) - : LLBridgePartition(regionp) -{ - mDrawableType = LLPipeline::RENDER_TYPE_AVATAR; - mPartitionType = LLViewerRegion::PARTITION_AVATAR; -} - -LLControlAVPartition::LLControlAVPartition(LLViewerRegion* regionp) - : LLBridgePartition(regionp) -{ - mDrawableType = LLPipeline::RENDER_TYPE_CONTROL_AV; - mPartitionType = LLViewerRegion::PARTITION_CONTROL_AV; -} - -LLHUDBridge::LLHUDBridge(LLDrawable* drawablep, LLViewerRegion* regionp) -: LLVolumeBridge(drawablep, regionp) -{ - mDrawableType = LLPipeline::RENDER_TYPE_HUD; - mPartitionType = LLViewerRegion::PARTITION_HUD; - mSlopRatio = 0.0f; -} - -F32 LLHUDBridge::calcPixelArea(LLSpatialGroup* group, LLCamera& camera) -{ - return 1024.f; -} - - -void LLHUDBridge::shiftPos(const LLVector4a& vec) -{ - //don't shift hud bridges on region crossing -} - +/**
+ * @file lldrawable.cpp
+ * @brief LLDrawable class implementation
+ *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "lldrawable.h"
+
+// library includes
+#include "material_codes.h"
+
+// viewer includes
+#include "llagent.h"
+#include "llcriticaldamp.h"
+#include "llface.h"
+#include "lllightconstants.h"
+#include "llmatrix4a.h"
+#include "llsky.h"
+#include "llsurfacepatch.h"
+#include "llviewercamera.h"
+#include "llviewerregion.h"
+#include "llvolume.h"
+#include "llvoavatar.h"
+#include "llvovolume.h"
+#include "llvosurfacepatch.h" // for debugging
+#include "llworld.h"
+#include "pipeline.h"
+#include "llspatialpartition.h"
+#include "llviewerobjectlist.h"
+#include "llviewerwindow.h"
+#include "llvocache.h"
+#include "llcontrolavatar.h"
+#include "lldrawpoolavatar.h"
+
+const F32 MIN_INTERPOLATE_DISTANCE_SQUARED = 0.001f * 0.001f;
+const F32 MAX_INTERPOLATE_DISTANCE_SQUARED = 10.f * 10.f;
+const F32 OBJECT_DAMPING_TIME_CONSTANT = 0.06f;
+
+extern bool gShiftFrame;
+
+
+////////////////////////
+//
+// Inline implementations.
+//
+//
+
+
+
+//////////////////////////////
+//
+// Drawable code
+//
+//
+
+// static
+U32 LLDrawable::sNumZombieDrawables = 0;
+F32 LLDrawable::sCurPixelAngle = 0;
+std::vector<LLPointer<LLDrawable> > LLDrawable::sDeadList;
+
+#define FORCE_INVISIBLE_AREA 16.f
+
+// static
+void LLDrawable::incrementVisible()
+{
+ LLViewerOctreeEntryData::incrementVisible();
+ sCurPixelAngle = (F32) gViewerWindow->getWindowHeightRaw()/LLViewerCamera::getInstance()->getView();
+}
+
+LLDrawable::LLDrawable(LLViewerObject *vobj, bool new_entry)
+: LLViewerOctreeEntryData(LLViewerOctreeEntry::LLDRAWABLE),
+ mVObjp(vobj)
+{
+ init(new_entry);
+}
+
+void LLDrawable::init(bool new_entry)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
+ // mXform
+ mParent = NULL;
+ mRenderType = 0;
+ mCurrentScale = LLVector3(1,1,1);
+ mDistanceWRTCamera = 0.0f;
+ mState = 0;
+
+ // mFaces
+ mRadius = 0.f;
+ mGeneration = -1;
+ mSpatialBridge = NULL;
+
+ LLViewerOctreeEntry* entry = NULL;
+ LLVOCacheEntry* vo_entry = NULL;
+ if(!new_entry && mVObjp && getRegion() != NULL)
+ {
+ vo_entry = getRegion()->getCacheEntryForOctree(mVObjp->getLocalID());
+ if(vo_entry)
+ {
+ entry = vo_entry->getEntry();
+ }
+ }
+ setOctreeEntry(entry);
+ if(vo_entry)
+ {
+ if(!entry)
+ {
+ vo_entry->setOctreeEntry(mEntry);
+ }
+
+ getRegion()->addActiveCacheEntry(vo_entry);
+
+ if(vo_entry->getNumOfChildren() > 0)
+ {
+ getRegion()->addVisibleChildCacheEntry(vo_entry, NULL); //to load all children.
+ }
+
+ llassert(!vo_entry->getGroup()); //not in the object cache octree.
+ }
+
+ llassert(!vo_entry || vo_entry->getEntry() == mEntry);
+
+ initVisible(sCurVisible - 2);//invisible for the current frame and the last frame.
+}
+
+void LLDrawable::unload()
+{
+ LLVOVolume *pVVol = getVOVolume();
+ pVVol->setNoLOD();
+ pVVol->markForUpdate();
+}
+
+// static
+void LLDrawable::initClass()
+{
+}
+
+
+void LLDrawable::destroy()
+{
+ if (gDebugGL)
+ {
+ gPipeline.checkReferences(this);
+ }
+
+ if (isDead())
+ {
+ sNumZombieDrawables--;
+ }
+
+ // Attempt to catch violations of this in debug,
+ // knowing that some false alarms may result
+ //
+ llassert(!LLSpatialGroup::sNoDelete);
+
+ /* cannot be guaranteed and causes crashes on false alarms
+ if (LLSpatialGroup::sNoDelete)
+ {
+ LL_ERRS() << "Illegal deletion of LLDrawable!" << LL_ENDL;
+ }*/
+
+ std::for_each(mFaces.begin(), mFaces.end(), DeletePointer());
+ mFaces.clear();
+
+
+ /*if (!(sNumZombieDrawables % 10))
+ {
+ LL_INFOS() << "- Zombie drawables: " << sNumZombieDrawables << LL_ENDL;
+ }*/
+
+}
+
+void LLDrawable::markDead()
+{
+ if (isDead())
+ {
+ LL_WARNS() << "Warning! Marking dead multiple times!" << LL_ENDL;
+ return;
+ }
+ setState(DEAD);
+
+ if (mSpatialBridge)
+ {
+ mSpatialBridge->markDead();
+ mSpatialBridge = NULL;
+ }
+
+ sNumZombieDrawables++;
+
+ // We're dead. Free up all of our references to other objects
+ cleanupReferences();
+// sDeadList.push_back(this);
+}
+
+LLVOVolume* LLDrawable::getVOVolume() const
+{
+ LLViewerObject* objectp = mVObjp;
+ if ( !isDead() && objectp && (objectp->getPCode() == LL_PCODE_VOLUME))
+ {
+ return ((LLVOVolume*)objectp);
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+const LLMatrix4& LLDrawable::getRenderMatrix() const
+{
+ return isRoot() ? getWorldMatrix() : getParent()->getWorldMatrix();
+}
+
+bool LLDrawable::isLight() const
+{
+ LLViewerObject* objectp = mVObjp;
+ if ( objectp && (objectp->getPCode() == LL_PCODE_VOLUME) && !isDead())
+ {
+ return ((LLVOVolume*)objectp)->getIsLight();
+ }
+ else
+ {
+ return false;
+ }
+}
+
+void LLDrawable::cleanupReferences()
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE;
+
+ std::for_each(mFaces.begin(), mFaces.end(), DeletePointer());
+ mFaces.clear();
+
+ gPipeline.unlinkDrawable(this);
+
+ removeFromOctree();
+
+ // Cleanup references to other objects
+ mVObjp = NULL;
+ mParent = NULL;
+}
+
+void LLDrawable::removeFromOctree()
+{
+ if(!mEntry)
+ {
+ return;
+ }
+
+ mEntry->removeData(this);
+ if(mEntry->hasVOCacheEntry())
+ {
+ getRegion()->removeActiveCacheEntry((LLVOCacheEntry*)mEntry->getVOCacheEntry(), this);
+ }
+ mEntry = NULL;
+}
+
+void LLDrawable::cleanupDeadDrawables()
+{
+ /*
+ S32 i;
+ for (i = 0; i < sDeadList.size(); i++)
+ {
+ if (sDeadList[i]->getNumRefs() > 1)
+ {
+ LL_WARNS() << "Dead drawable has " << sDeadList[i]->getNumRefs() << " remaining refs" << LL_ENDL;
+ gPipeline.findReferences(sDeadList[i]);
+ }
+ }
+ */
+ sDeadList.clear();
+}
+
+S32 LLDrawable::findReferences(LLDrawable *drawablep)
+{
+ S32 count = 0;
+ if (mParent == drawablep)
+ {
+ LL_INFOS() << this << ": parent reference" << LL_ENDL;
+ count++;
+ }
+ return count;
+}
+
+LLFace* LLDrawable::addFace(LLFacePool *poolp, LLViewerTexture *texturep)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
+ LLFace *face;
+ {
+ face = new LLFace(this, mVObjp);
+ }
+
+ if (!face) LL_ERRS() << "Allocating new Face: " << mFaces.size() << LL_ENDL;
+
+ if (face)
+ {
+ mFaces.push_back(face);
+
+ if (poolp)
+ {
+ face->setPool(poolp, texturep);
+ }
+
+ if (isState(UNLIT))
+ {
+ face->setState(LLFace::FULLBRIGHT);
+ }
+ }
+ return face;
+}
+
+LLFace* LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
+ LLFace *face;
+
+ face = new LLFace(this, mVObjp);
+
+ face->setTEOffset(mFaces.size());
+ face->setTexture(texturep);
+ face->setPoolType(gPipeline.getPoolTypeFromTE(te, texturep));
+
+ mFaces.push_back(face);
+
+ if (isState(UNLIT))
+ {
+ face->setState(LLFace::FULLBRIGHT);
+ }
+
+ return face;
+
+}
+
+LLFace* LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep, LLViewerTexture *normalp)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
+ LLFace *face;
+ face = new LLFace(this, mVObjp);
+
+ face->setTEOffset(mFaces.size());
+ face->setTexture(texturep);
+ face->setNormalMap(normalp);
+ face->setPoolType(gPipeline.getPoolTypeFromTE(te, texturep));
+
+ mFaces.push_back(face);
+
+ if (isState(UNLIT))
+ {
+ face->setState(LLFace::FULLBRIGHT);
+ }
+
+ return face;
+
+}
+
+LLFace* LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep, LLViewerTexture *normalp, LLViewerTexture *specularp)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
+ LLFace *face;
+ face = new LLFace(this, mVObjp);
+
+ face->setTEOffset(mFaces.size());
+ face->setTexture(texturep);
+ face->setNormalMap(normalp);
+ face->setSpecularMap(specularp);
+ face->setPoolType(gPipeline.getPoolTypeFromTE(te, texturep));
+
+ mFaces.push_back(face);
+
+ if (isState(UNLIT))
+ {
+ face->setState(LLFace::FULLBRIGHT);
+ }
+
+ return face;
+
+}
+
+void LLDrawable::setNumFaces(const S32 newFaces, LLFacePool *poolp, LLViewerTexture *texturep)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
+ if (newFaces == (S32)mFaces.size())
+ {
+ return;
+ }
+ else if (newFaces < (S32)mFaces.size())
+ {
+ std::for_each(mFaces.begin() + newFaces, mFaces.end(), DeletePointer());
+ mFaces.erase(mFaces.begin() + newFaces, mFaces.end());
+ }
+ else // (newFaces > mFaces.size())
+ {
+ mFaces.reserve(newFaces);
+ for (int i = mFaces.size(); i<newFaces; i++)
+ {
+ addFace(poolp, texturep);
+ }
+ }
+
+ llassert_always(mFaces.size() == newFaces);
+}
+
+void LLDrawable::setNumFacesFast(const S32 newFaces, LLFacePool *poolp, LLViewerTexture *texturep)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
+ if (newFaces <= (S32)mFaces.size() && newFaces >= (S32)mFaces.size()/2)
+ {
+ return;
+ }
+ else if (newFaces < (S32)mFaces.size())
+ {
+ std::for_each(mFaces.begin() + newFaces, mFaces.end(), DeletePointer());
+ mFaces.erase(mFaces.begin() + newFaces, mFaces.end());
+ }
+ else // (newFaces > mFaces.size())
+ {
+ mFaces.reserve(newFaces);
+ for (int i = mFaces.size(); i<newFaces; i++)
+ {
+ addFace(poolp, texturep);
+ }
+ }
+
+ llassert_always(mFaces.size() == newFaces) ;
+}
+
+void LLDrawable::mergeFaces(LLDrawable* src)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
+ U32 face_count = mFaces.size() + src->mFaces.size();
+
+ mFaces.reserve(face_count);
+ for (U32 i = 0; i < src->mFaces.size(); i++)
+ {
+ LLFace* facep = src->mFaces[i];
+ facep->setDrawable(this);
+ mFaces.push_back(facep);
+ }
+ src->mFaces.clear();
+}
+
+void LLDrawable::deleteFaces(S32 offset, S32 count)
+{
+ face_list_t::iterator face_begin = mFaces.begin() + offset;
+ face_list_t::iterator face_end = face_begin + count;
+
+ std::for_each(face_begin, face_end, DeletePointer());
+ mFaces.erase(face_begin, face_end);
+}
+
+void LLDrawable::update()
+{
+ LL_ERRS() << "Shouldn't be called!" << LL_ENDL;
+}
+
+
+void LLDrawable::updateMaterial()
+{
+}
+
+void LLDrawable::makeActive()
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
+#if !LL_RELEASE_FOR_DOWNLOAD
+ if (mVObjp.notNull())
+ {
+ U32 pcode = mVObjp->getPCode();
+ if (pcode == LLViewerObject::LL_VO_WATER ||
+ pcode == LLViewerObject::LL_VO_VOID_WATER ||
+ pcode == LLViewerObject::LL_VO_SURFACE_PATCH ||
+ pcode == LLViewerObject::LL_VO_PART_GROUP ||
+ pcode == LLViewerObject::LL_VO_HUD_PART_GROUP ||
+ pcode == LLViewerObject::LL_VO_SKY)
+ {
+ LL_ERRS() << "Static viewer object has active drawable!" << LL_ENDL;
+ }
+ }
+#endif
+
+ if (!isState(ACTIVE)) // && mGeneration > 0)
+ {
+ setState(ACTIVE);
+
+ //parent must be made active first
+ if (!isRoot() && !mParent->isActive())
+ {
+ mParent->makeActive();
+ //NOTE: linked set will now NEVER become static
+ mParent->setState(LLDrawable::ACTIVE_CHILD);
+ }
+
+ //all child objects must also be active
+ llassert_always(mVObjp);
+
+ LLViewerObject::const_child_list_t& child_list = mVObjp->getChildren();
+ for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
+ iter != child_list.end(); iter++)
+ {
+ LLViewerObject* child = *iter;
+ LLDrawable* drawable = child->mDrawable;
+ if (drawable)
+ {
+ drawable->makeActive();
+ }
+ }
+
+ if (mVObjp->getPCode() == LL_PCODE_VOLUME)
+ {
+ gPipeline.markRebuild(this, LLDrawable::REBUILD_VOLUME);
+ }
+ updatePartition();
+ }
+ else if (!isRoot() && !mParent->isActive()) //this should not happen, but occasionally it does...
+ {
+ mParent->makeActive();
+ //NOTE: linked set will now NEVER become static
+ mParent->setState(LLDrawable::ACTIVE_CHILD);
+ }
+
+ llassert(isAvatar() || isRoot() || mParent->isActive());
+}
+
+
+void LLDrawable::makeStatic(bool warning_enabled)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
+ if (isState(ACTIVE) &&
+ !isState(ACTIVE_CHILD) &&
+ !mVObjp->isAttachment() &&
+ !mVObjp->isFlexible() &&
+ !mVObjp->isAnimatedObject())
+ {
+ clearState(ACTIVE | ANIMATED_CHILD);
+
+ //drawable became static with active parent, not acceptable
+ llassert(mParent.isNull() || !mParent->isActive() || !warning_enabled);
+
+ LLViewerObject::const_child_list_t& child_list = mVObjp->getChildren();
+ for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
+ iter != child_list.end(); iter++)
+ {
+ LLViewerObject* child = *iter;
+ LLDrawable* child_drawable = child->mDrawable;
+ if (child_drawable)
+ {
+ if (child_drawable->getParent() != this)
+ {
+ LL_WARNS() << "Child drawable has unknown parent." << LL_ENDL;
+ }
+ child_drawable->makeStatic(warning_enabled);
+ }
+ }
+
+ if (mVObjp->getPCode() == LL_PCODE_VOLUME)
+ {
+ gPipeline.markRebuild(this, LLDrawable::REBUILD_VOLUME);
+ }
+
+ if (mSpatialBridge)
+ {
+ mSpatialBridge->markDead();
+ setSpatialBridge(NULL);
+ }
+ updatePartition();
+ }
+
+ llassert(isAvatar() || isRoot() || mParent->isStatic());
+}
+
+// Returns "distance" between target destination and resulting xfrom
+F32 LLDrawable::updateXform(bool undamped)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
+ bool damped = !undamped;
+
+ // Position
+ const LLVector3 old_pos(mXform.getPosition());
+ LLVector3 target_pos;
+ if (mXform.isRoot())
+ {
+ // get root position in your agent's region
+ target_pos = mVObjp->getPositionAgent();
+ }
+ else
+ {
+ // parent-relative position
+ target_pos = mVObjp->getPosition();
+ }
+
+ // Rotation
+ const LLQuaternion old_rot(mXform.getRotation());
+ LLQuaternion target_rot = mVObjp->getRotation();
+ //scaling
+ LLVector3 target_scale = mVObjp->getScale();
+ LLVector3 old_scale = mCurrentScale;
+
+ // Damping
+ F32 dist_squared = 0.f;
+ F32 camdist2 = (mDistanceWRTCamera * mDistanceWRTCamera);
+
+ if (damped && isVisible())
+ {
+ F32 lerp_amt = llclamp(LLSmoothInterpolation::getInterpolant(OBJECT_DAMPING_TIME_CONSTANT), 0.f, 1.f);
+ LLVector3 new_pos = lerp(old_pos, target_pos, lerp_amt);
+ dist_squared = dist_vec_squared(new_pos, target_pos);
+
+ LLQuaternion new_rot = nlerp(lerp_amt, old_rot, target_rot);
+ // FIXME: This can be negative! It is be possible for some rots to 'cancel out' pos or size changes.
+ dist_squared += (1.f - dot(new_rot, target_rot)) * 10.f;
+
+ LLVector3 new_scale = lerp(old_scale, target_scale, lerp_amt);
+ dist_squared += dist_vec_squared(new_scale, target_scale);
+
+ if ((dist_squared >= MIN_INTERPOLATE_DISTANCE_SQUARED * camdist2) &&
+ (dist_squared <= MAX_INTERPOLATE_DISTANCE_SQUARED))
+ {
+ // interpolate
+ target_pos = new_pos;
+ target_rot = new_rot;
+ target_scale = new_scale;
+ }
+ else if (mVObjp->getAngularVelocity().isExactlyZero())
+ {
+ // snap to final position (only if no target omega is applied)
+ dist_squared = 0.0f;
+ //set target scale here, because of dist_squared = 0.0f remove object from move list
+ mCurrentScale = target_scale;
+
+ if (getVOVolume() && !isRoot())
+ { //child prim snapping to some position, needs a rebuild
+ gPipeline.markRebuild(this, LLDrawable::REBUILD_POSITION);
+ }
+ }
+ }
+ else
+ {
+ // The following fixes MAINT-1742 but breaks vehicles similar to MAINT-2275
+ // dist_squared = dist_vec_squared(old_pos, target_pos);
+
+ // The following fixes MAINT-2247 but causes MAINT-2275
+ //dist_squared += (1.f - dot(old_rot, target_rot)) * 10.f;
+ //dist_squared += dist_vec_squared(old_scale, target_scale);
+ }
+
+ const LLVector3 vec = mCurrentScale-target_scale;
+
+ //It's a very important on each cycle on Drawable::update form(), when object remained in move
+ //, list update the CurrentScale member, because if do not do that, it remained in this list forever
+ //or when the delta time between two frames a become a sufficiently large (due to interpolation)
+ //for overcome the MIN_INTERPOLATE_DISTANCE_SQUARED.
+ mCurrentScale = target_scale;
+
+ if (vec*vec > MIN_INTERPOLATE_DISTANCE_SQUARED)
+ { //scale change requires immediate rebuild
+ gPipeline.markRebuild(this, LLDrawable::REBUILD_POSITION);
+ }
+ else if (!isRoot() &&
+ (!mVObjp->getAngularVelocity().isExactlyZero() ||
+ dist_squared > 0.f))
+ { //child prim moving relative to parent, tag as needing to be rendered atomically and rebuild
+ dist_squared = 1.f; //keep this object on the move list
+ if (!isState(LLDrawable::ANIMATED_CHILD))
+ {
+ setState(LLDrawable::ANIMATED_CHILD);
+ gPipeline.markRebuild(this, LLDrawable::REBUILD_ALL);
+ mVObjp->dirtySpatialGroup();
+ }
+ }
+ else if (!isRoot() &&
+ ((dist_vec_squared(old_pos, target_pos) > 0.f)
+ || (1.f - dot(old_rot, target_rot)) > 0.f))
+ { //fix for BUG-840, MAINT-2275, MAINT-1742, MAINT-2247
+ mVObjp->shrinkWrap();
+ gPipeline.markRebuild(this, LLDrawable::REBUILD_POSITION);
+ }
+ else if (!getVOVolume() && !isAvatar())
+ {
+ movePartition();
+ }
+
+ // Update
+ mXform.setPosition(target_pos);
+ mXform.setRotation(target_rot);
+ mXform.setScale(LLVector3(1,1,1)); //no scale in drawable transforms (IT'S A RULE!)
+ mXform.updateMatrix();
+ if (isRoot() && mVObjp->isAnimatedObject() && mVObjp->getControlAvatar())
+ {
+ mVObjp->getControlAvatar()->matchVolumeTransform();
+ }
+
+ if (mSpatialBridge)
+ {
+ gPipeline.markMoved(mSpatialBridge, false);
+ }
+ return dist_squared;
+}
+
+void LLDrawable::setRadius(F32 radius)
+{
+ if (mRadius != radius)
+ {
+ mRadius = radius;
+ }
+}
+
+void LLDrawable::moveUpdatePipeline(bool moved)
+{
+ if (moved)
+ {
+ makeActive();
+ }
+
+ // Update the face centers.
+ for (S32 i = 0; i < getNumFaces(); i++)
+ {
+ LLFace* face = getFace(i);
+ if (face)
+ {
+ face->updateCenterAgent();
+ }
+ }
+}
+
+void LLDrawable::movePartition()
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
+ LLSpatialPartition* part = getSpatialPartition();
+ if (part)
+ {
+ part->move(this, getSpatialGroup());
+ }
+}
+
+bool LLDrawable::updateMove()
+{
+ if (isDead())
+ {
+ LL_WARNS() << "Update move on dead drawable!" << LL_ENDL;
+ return true;
+ }
+
+ if (mVObjp.isNull())
+ {
+ return false;
+ }
+
+ makeActive();
+
+ return isState(MOVE_UNDAMPED) ? updateMoveUndamped() : updateMoveDamped();
+}
+
+bool LLDrawable::updateMoveUndamped()
+{
+ F32 dist_squared = updateXform(true);
+
+ mGeneration++;
+
+ if (!isState(LLDrawable::INVISIBLE))
+ {
+ bool moved = (dist_squared > 0.001f && dist_squared < 255.99f);
+ moveUpdatePipeline(moved);
+ mVObjp->updateText();
+ }
+
+ mVObjp->clearChanged(LLXform::MOVED);
+ return true;
+}
+
+void LLDrawable::updatePartition()
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
+ if (!getVOVolume())
+ {
+ movePartition();
+ }
+ else if (mSpatialBridge)
+ {
+ gPipeline.markMoved(mSpatialBridge, false);
+ }
+ else
+ {
+ //a child prim moved and needs its verts regenerated
+ gPipeline.markRebuild(this, LLDrawable::REBUILD_POSITION);
+ }
+}
+
+bool LLDrawable::updateMoveDamped()
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
+ F32 dist_squared = updateXform(false);
+
+ mGeneration++;
+
+ if (!isState(LLDrawable::INVISIBLE))
+ {
+ bool moved = (dist_squared > 0.001f && dist_squared < 128.0f);
+ moveUpdatePipeline(moved);
+ mVObjp->updateText();
+ }
+
+ bool done_moving = dist_squared == 0.0f;
+
+ if (done_moving)
+ {
+ mVObjp->clearChanged(LLXform::MOVED);
+ }
+
+ return done_moving;
+}
+
+void LLDrawable::updateDistance(LLCamera& camera, bool force_update)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
+ if (LLViewerCamera::sCurCameraID != LLViewerCamera::CAMERA_WORLD)
+ {
+ LL_WARNS() << "Attempted to update distance for non-world camera." << LL_ENDL;
+ return;
+ }
+
+ if (gShiftFrame)
+ {
+ return;
+ }
+
+ //switch LOD with the spatial group to avoid artifacts
+ //LLSpatialGroup* sg = getSpatialGroup();
+
+ LLVector3 pos;
+
+ //if (!sg || sg->changeLOD())
+ {
+ LLVOVolume* volume = getVOVolume();
+ if (volume)
+ {
+ if (getGroup())
+ {
+ pos.set(getPositionGroup().getF32ptr());
+ }
+ else
+ {
+ pos = getPositionAgent();
+ }
+
+ if (isState(LLDrawable::HAS_ALPHA))
+ {
+ for (S32 i = 0; i < getNumFaces(); i++)
+ {
+ LLFace* facep = getFace(i);
+ if (facep &&
+ (force_update || facep->isInAlphaPool()))
+ {
+ LLVector4a box;
+ box.setSub(facep->mExtents[1], facep->mExtents[0]);
+ box.mul(0.25f);
+ LLVector3 v = (facep->mCenterLocal-camera.getOrigin());
+ const LLVector3& at = camera.getAtAxis();
+ for (U32 j = 0; j < 3; j++)
+ {
+ v.mV[j] -= box[j] * at.mV[j];
+ }
+ facep->mDistance = v * camera.getAtAxis();
+ }
+ }
+ }
+
+
+ // MAINT-7926 Handle volumes in an animated object as a special case
+ // SL-937: add dynamic box handling for rigged mesh on regular avatars.
+ //if (volume->getAvatar() && volume->getAvatar()->isControlAvatar())
+ if (volume->getAvatar())
+ {
+ const LLVector3* av_box = volume->getAvatar()->getLastAnimExtents();
+ LLVector3 cam_pos_from_agent = LLViewerCamera::getInstance()->getOrigin();
+ LLVector3 cam_to_box_offset = point_to_box_offset(cam_pos_from_agent, av_box);
+ mDistanceWRTCamera = llmax(0.01f, ll_round(cam_to_box_offset.magVec(), 0.01f));
+ mVObjp->updateLOD();
+ return;
+ }
+ }
+ else
+ {
+ pos = LLVector3(getPositionGroup().getF32ptr());
+ }
+
+ pos -= camera.getOrigin();
+ mDistanceWRTCamera = ll_round(pos.magVec(), 0.01f);
+ mVObjp->updateLOD();
+ }
+}
+
+void LLDrawable::updateTexture()
+{
+ if (isDead())
+ {
+ LL_WARNS() << "Dead drawable updating texture!" << LL_ENDL;
+ return;
+ }
+
+ if (getNumFaces() != mVObjp->getNumTEs())
+ { //drawable is transitioning its face count
+ return;
+ }
+
+ if (getVOVolume())
+ {
+ gPipeline.markRebuild(this, LLDrawable::REBUILD_MATERIAL);
+ }
+}
+
+bool LLDrawable::updateGeometry()
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
+ llassert(mVObjp.notNull());
+ bool res = mVObjp && mVObjp->updateGeometry(this);
+ return res;
+}
+
+void LLDrawable::shiftPos(const LLVector4a &shift_vector)
+{
+ if (isDead())
+ {
+ LL_WARNS() << "Shifting dead drawable" << LL_ENDL;
+ return;
+ }
+
+ if (mParent)
+ {
+ mXform.setPosition(mVObjp->getPosition());
+ }
+ else
+ {
+ mXform.setPosition(mVObjp->getPositionAgent());
+ }
+
+ mXform.updateMatrix();
+
+ if (isStatic())
+ {
+ LLVOVolume* volume = getVOVolume();
+
+ bool rebuild = (!volume &&
+ getRenderType() != LLPipeline::RENDER_TYPE_TREE &&
+ getRenderType() != LLPipeline::RENDER_TYPE_TERRAIN &&
+ getRenderType() != LLPipeline::RENDER_TYPE_SKY);
+
+ if (rebuild)
+ {
+ gPipeline.markRebuild(this, LLDrawable::REBUILD_ALL);
+ }
+
+ for (S32 i = 0; i < getNumFaces(); i++)
+ {
+ LLFace *facep = getFace(i);
+ if (facep)
+ {
+ facep->mCenterAgent += LLVector3(shift_vector.getF32ptr());
+ facep->mExtents[0].add(shift_vector);
+ facep->mExtents[1].add(shift_vector);
+
+ if (rebuild && facep->hasGeometry())
+ {
+ facep->clearVertexBuffer();
+ }
+ }
+ }
+
+ shift(shift_vector);
+ }
+ else if (mSpatialBridge)
+ {
+ mSpatialBridge->shiftPos(shift_vector);
+ }
+ else if (isAvatar())
+ {
+ shift(shift_vector);
+ }
+
+ mVObjp->onShift(shift_vector);
+}
+
+const LLVector3& LLDrawable::getBounds(LLVector3& min, LLVector3& max) const
+{
+ mXform.getMinMax(min,max);
+ return mXform.getPositionW();
+}
+
+void LLDrawable::updateSpatialExtents()
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
+ if (mVObjp)
+ {
+ const LLVector4a* exts = getSpatialExtents();
+ LLVector4a extents[2] = { exts[0], exts[1] };
+
+ mVObjp->updateSpatialExtents(extents[0], extents[1]);
+ setSpatialExtents(extents[0], extents[1]);
+ }
+
+ updateBinRadius();
+
+ if (mSpatialBridge.notNull())
+ {
+ getGroupPosition().splat(0.f);
+ }
+}
+
+
+void LLDrawable::updateBinRadius()
+{
+ if (mVObjp.notNull())
+ {
+ setBinRadius(llmin(mVObjp->getBinRadius(), 256.f));
+ }
+ else
+ {
+ setBinRadius(llmin(getRadius()*4.f, 256.f));
+ }
+}
+
+void LLDrawable::updateSpecialHoverCursor(bool enabled)
+{
+ // TODO: maintain a list of objects that have special
+ // hover cursors, then use that list for per-frame
+ // hover cursor selection. JC
+}
+
+F32 LLDrawable::getVisibilityRadius() const
+{
+ if (isDead())
+ {
+ return 0.f;
+ }
+ else if (isLight())
+ {
+ const LLVOVolume *vov = getVOVolume();
+ if (vov)
+ {
+ return llmax(getRadius(), vov->getLightRadius());
+ } else {
+ // LL_WARNS() ?
+ }
+ }
+ return getRadius();
+}
+
+void LLDrawable::updateUVMinMax()
+{
+}
+
+//virtual
+bool LLDrawable::isVisible() const
+{
+ if (LLViewerOctreeEntryData::isVisible())
+ {
+ return true;
+ }
+
+ {
+ LLViewerOctreeGroup* group = mEntry->getGroup();
+ if (group && group->isVisible())
+ {
+ LLViewerOctreeEntryData::setVisible();
+ return true;
+ }
+ }
+
+ return false;
+}
+
+//virtual
+bool LLDrawable::isRecentlyVisible() const
+{
+ //currently visible or visible in the previous frame.
+ bool vis = LLViewerOctreeEntryData::isRecentlyVisible();
+
+ if(!vis)
+ {
+ const U32 MIN_VIS_FRAME_RANGE = 2 ; //two frames:the current one and the last one.
+ vis = (sCurVisible - getVisible() < MIN_VIS_FRAME_RANGE);
+ }
+
+ return vis ;
+}
+
+void LLDrawable::setGroup(LLViewerOctreeGroup *groupp)
+ {
+ LLSpatialGroup* cur_groupp = (LLSpatialGroup*)getGroup();
+
+ //precondition: mGroupp MUST be null or DEAD or mGroupp MUST NOT contain this
+ //llassert(!cur_groupp || cur_groupp->isDead() || !cur_groupp->hasElement(this));
+
+ //precondition: groupp MUST be null or groupp MUST contain this
+ llassert(!groupp || (LLSpatialGroup*)groupp->hasElement(this));
+
+ if (cur_groupp != groupp && getVOVolume())
+ {
+ //NULL out vertex buffer references for volumes on spatial group change to maintain
+ //requirement that every face vertex buffer is either NULL or points to a vertex buffer
+ //contained by its drawable's spatial group
+ for (S32 i = 0; i < getNumFaces(); ++i)
+ {
+ LLFace* facep = getFace(i);
+ if (facep)
+ {
+ facep->clearVertexBuffer();
+ }
+ }
+ }
+
+ //postcondition: if next group is NULL, previous group must be dead OR NULL OR binIndex must be -1
+ //postcondition: if next group is NOT NULL, binIndex must not be -1
+ //llassert(groupp == NULL ? (cur_groupp == NULL || cur_groupp->isDead()) || (!getEntry() || getEntry()->getBinIndex() == -1) :
+ // (getEntry() && getEntry()->getBinIndex() != -1));
+
+ LLViewerOctreeEntryData::setGroup(groupp);
+}
+
+/*
+* Get the SpatialPartition this Drawable should use.
+* Checks current SpatialPartition assignment and corrects if it is invalid.
+*/
+LLSpatialPartition* LLDrawable::getSpatialPartition()
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
+ LLSpatialPartition* retval = NULL;
+
+ if (!mVObjp ||
+ !getVOVolume() ||
+ isStatic())
+ {
+ retval = gPipeline.getSpatialPartition((LLViewerObject*)mVObjp);
+ }
+ else if (isRoot())
+ {
+ // determine if the spatial bridge has changed
+ if (mSpatialBridge)
+ {
+ U32 partition_type = mSpatialBridge->asPartition()->mPartitionType;
+ bool is_hud = mVObjp->isHUDAttachment();
+ bool is_animesh = mVObjp->isAnimatedObject() && mVObjp->getControlAvatar() != NULL;
+ bool is_attachment = mVObjp->isAttachment() && !is_hud && !is_animesh;
+ if ((partition_type == LLViewerRegion::PARTITION_HUD) != is_hud)
+ {
+ // Was/became HUD
+ // remove obsolete bridge
+ mSpatialBridge->markDead();
+ setSpatialBridge(NULL);
+ }
+ else if ((partition_type == LLViewerRegion::PARTITION_CONTROL_AV) != is_animesh)
+ {
+ // Was/became part of animesh
+ // remove obsolete bridge
+ mSpatialBridge->markDead();
+ setSpatialBridge(NULL);
+ }
+ else if ((partition_type == LLViewerRegion::PARTITION_AVATAR) != is_attachment)
+ {
+ // Was/became part of avatar
+ // remove obsolete bridge
+ mSpatialBridge->markDead();
+ setSpatialBridge(NULL);
+ }
+ }
+ //must be an active volume
+ if (!mSpatialBridge)
+ {
+ if (mVObjp->isHUDAttachment())
+ {
+ setSpatialBridge(new LLHUDBridge(this, getRegion()));
+ }
+ else if (mVObjp->isAnimatedObject() && mVObjp->getControlAvatar())
+ {
+ setSpatialBridge(new LLControlAVBridge(this, getRegion()));
+ mVObjp->getControlAvatar()->mControlAVBridge = (LLControlAVBridge*)getSpatialBridge();
+ }
+ // check HUD first, because HUD is also attachment
+ else if (mVObjp->isAttachment())
+ {
+ // Attachment
+ // Use AvatarBridge of root object in attachment linkset
+ setSpatialBridge(new LLAvatarBridge(this, getRegion()));
+ }
+ else
+ {
+ // Moving linkset, use VolumeBridge of root object in linkset
+ setSpatialBridge(new LLVolumeBridge(this, getRegion()));
+ }
+ }
+ return mSpatialBridge->asPartition();
+ }
+ else
+ {
+ retval = getParent()->getSpatialPartition();
+ }
+
+ if (retval && mSpatialBridge.notNull())
+ {
+ mSpatialBridge->markDead();
+ setSpatialBridge(NULL);
+ }
+
+ return retval;
+}
+
+//=======================================
+// Spatial Partition Bridging Drawable
+//=======================================
+
+LLSpatialBridge::LLSpatialBridge(LLDrawable* root, bool render_by_group, U32 data_mask, LLViewerRegion* regionp) :
+ LLDrawable(root->getVObj(), true),
+ LLSpatialPartition(data_mask, render_by_group, regionp)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE;
+ mOcclusionEnabled = false;
+ mBridge = this;
+ mDrawable = root;
+ root->setSpatialBridge(this);
+
+ mRenderType = mDrawable->mRenderType;
+ mDrawableType = mDrawable->mRenderType;
+
+ mPartitionType = LLViewerRegion::PARTITION_VOLUME;
+
+ mOctree->balance();
+
+ llassert(mDrawable);
+ llassert(mDrawable->getRegion());
+ LLSpatialPartition *part = mDrawable->getRegion()->getSpatialPartition(mPartitionType);
+ llassert(part);
+
+ if (part)
+ {
+ part->put(this);
+ }
+}
+
+LLSpatialBridge::~LLSpatialBridge()
+{
+ if(mEntry)
+ {
+ LLSpatialGroup* group = getSpatialGroup();
+ if (group)
+ {
+ group->getSpatialPartition()->remove(this, group);
+ }
+ }
+
+ //delete octree here so listeners will still be able to access bridge specific state
+ destroyTree();
+}
+
+void LLSpatialBridge::destroyTree()
+{
+ delete mOctree;
+ mOctree = NULL;
+}
+
+void LLSpatialBridge::updateSpatialExtents()
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
+ LLSpatialGroup* root = (LLSpatialGroup*) mOctree->getListener(0);
+
+ root->rebound();
+
+ const LLVector4a* root_bounds = root->getBounds();
+ LLVector4a offset;
+ LLVector4a size = root_bounds[1];
+
+ //VECTORIZE THIS
+ LLMatrix4a mat;
+ mat.loadu(mDrawable->getXform()->getWorldMatrix());
+
+ LLVector4a t;
+ t.splat(0.f);
+
+ LLVector4a center;
+ mat.affineTransform(t, center);
+
+ mat.rotate(root_bounds[0], offset);
+ center.add(offset);
+
+ LLVector4a v[4];
+
+ //get 4 corners of bounding box
+ mat.rotate(size,v[0]);
+
+ LLVector4a scale;
+
+ scale.set(-1.f, -1.f, 1.f);
+ scale.mul(size);
+ mat.rotate(scale, v[1]);
+
+ scale.set(1.f, -1.f, -1.f);
+ scale.mul(size);
+ mat.rotate(scale, v[2]);
+
+ scale.set(-1.f, 1.f, -1.f);
+ scale.mul(size);
+ mat.rotate(scale, v[3]);
+
+ LLVector4a newMin;
+ LLVector4a newMax;
+ newMin = newMax = center;
+ for (U32 i = 0; i < 4; i++)
+ {
+ LLVector4a delta;
+ delta.setAbs(v[i]);
+ LLVector4a min;
+ min.setSub(center, delta);
+ LLVector4a max;
+ max.setAdd(center, delta);
+
+ newMin.setMin(newMin, min);
+ newMax.setMax(newMax, max);
+ }
+ setSpatialExtents(newMin, newMax);
+
+ LLVector4a diagonal;
+ diagonal.setSub(newMax, newMin);
+ mRadius = diagonal.getLength3().getF32() * 0.5f;
+
+ LLVector4a& pos = getGroupPosition();
+ pos.setAdd(newMin,newMax);
+ pos.mul(0.5f);
+ updateBinRadius();
+}
+
+void LLSpatialBridge::updateBinRadius()
+{
+ setBinRadius(llmin( mOctree->getSize()[0]*0.5f, 256.f));
+}
+
+LLCamera LLSpatialBridge::transformCamera(LLCamera& camera)
+{
+ LLCamera ret = camera;
+ LLXformMatrix* mat = mDrawable->getXform();
+ LLVector3 center = LLVector3(0,0,0) * mat->getWorldMatrix();
+
+ LLVector3 delta = ret.getOrigin() - center;
+ LLQuaternion rot = ~mat->getRotation();
+
+ delta *= rot;
+ LLVector3 lookAt = ret.getAtAxis();
+ LLVector3 up_axis = ret.getUpAxis();
+ LLVector3 left_axis = ret.getLeftAxis();
+
+ lookAt *= rot;
+ up_axis *= rot;
+ left_axis *= rot;
+
+ if (!delta.isFinite())
+ {
+ delta.clearVec();
+ }
+
+ ret.setOrigin(delta);
+ ret.setAxes(lookAt, left_axis, up_axis);
+
+ return ret;
+}
+
+void LLSpatialBridge::transformExtents(const LLVector4a* src, LLVector4a* dst)
+{
+ LLMatrix4 mat = mDrawable->getXform()->getWorldMatrix();
+ mat.invert();
+
+ LLMatrix4a world_to_bridge(mat);
+
+ matMulBoundBox(world_to_bridge, src, dst);
+}
+
+
+void LLDrawable::setVisible(LLCamera& camera, std::vector<LLDrawable*>* results, bool for_select)
+{
+ LLViewerOctreeEntryData::setVisible();
+
+#if 0 && !LL_RELEASE_FOR_DOWNLOAD
+ //crazy paranoid rules checking
+ if (getVOVolume())
+ {
+ if (!isRoot())
+ {
+ if (isActive() && !mParent->isActive())
+ {
+ LL_ERRS() << "Active drawable has static parent!" << LL_ENDL;
+ }
+
+ if (isStatic() && !mParent->isStatic())
+ {
+ LL_ERRS() << "Static drawable has active parent!" << LL_ENDL;
+ }
+
+ if (mSpatialBridge)
+ {
+ LL_ERRS() << "Child drawable has spatial bridge!" << LL_ENDL;
+ }
+ }
+ else if (isActive() && !mSpatialBridge)
+ {
+ LL_ERRS() << "Active root drawable has no spatial bridge!" << LL_ENDL;
+ }
+ else if (isStatic() && mSpatialBridge.notNull())
+ {
+ LL_ERRS() << "Static drawable has spatial bridge!" << LL_ENDL;
+ }
+ }
+#endif
+}
+
+class LLOctreeMarkNotCulled: public OctreeTraveler
+{
+public:
+ LLCamera* mCamera;
+
+ LLOctreeMarkNotCulled(LLCamera* camera_in) : mCamera(camera_in) { }
+
+ virtual void traverse(const OctreeNode* node)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
+ group->setVisible();
+ OctreeTraveler::traverse(node);
+ }
+
+ void visit(const OctreeNode* branch)
+ {
+ gPipeline.markNotCulled((LLSpatialGroup*) branch->getListener(0), *mCamera);
+ }
+};
+
+void LLSpatialBridge::setVisible(LLCamera& camera_in, std::vector<LLDrawable*>* results, bool for_select)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
+ if (!gPipeline.hasRenderType(mDrawableType))
+ {
+ return;
+ }
+
+
+ //HACK don't draw attachments for avatars that haven't been visible in more than a frame
+ LLViewerObject *vobj = mDrawable->getVObj();
+ if (vobj && vobj->isAttachment() && !vobj->isHUDAttachment())
+ {
+ LLDrawable* av;
+ LLDrawable* parent = mDrawable->getParent();
+
+ if (parent)
+ {
+ LLViewerObject* objparent = parent->getVObj();
+ av = objparent->mDrawable;
+ LLSpatialGroup* group = av->getSpatialGroup();
+
+ bool impostor = false;
+ bool loaded = false;
+ if (objparent->isAvatar())
+ {
+ LLVOAvatar* avatarp = (LLVOAvatar*) objparent;
+ if (avatarp->isVisible())
+ {
+ impostor = objparent->isAvatar() && !LLPipeline::sImpostorRender && ((LLVOAvatar*) objparent)->isImpostor();
+ loaded = objparent->isAvatar() && ((LLVOAvatar*) objparent)->isFullyLoaded();
+ }
+ else
+ {
+ return;
+ }
+ }
+
+ if (!group ||
+ LLDrawable::getCurrentFrame() - av->getVisible() > 1 ||
+ impostor ||
+ !loaded)
+ {
+ return;
+ }
+ }
+ }
+
+
+ LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0);
+ group->rebound();
+
+ LLVector4a center;
+ const LLVector4a* exts = getSpatialExtents();
+ center.setAdd(exts[0], exts[1]);
+ center.mul(0.5f);
+ LLVector4a size;
+ size.setSub(exts[1], exts[0]);
+ size.mul(0.5f);
+
+ if ((LLPipeline::sShadowRender && camera_in.AABBInFrustum(center, size)) ||
+ LLPipeline::sImpostorRender ||
+ (camera_in.AABBInFrustumNoFarClip(center, size) &&
+ AABBSphereIntersect(exts[0], exts[1], camera_in.getOrigin(), camera_in.mFrustumCornerDist)))
+ {
+ if (!LLPipeline::sImpostorRender &&
+ !LLPipeline::sShadowRender &&
+ LLPipeline::calcPixelArea(center, size, camera_in) < FORCE_INVISIBLE_AREA)
+ {
+ return;
+ }
+
+ LLDrawable::setVisible(camera_in);
+
+ if (for_select)
+ {
+ results->push_back(mDrawable);
+ if (mDrawable->getVObj())
+ {
+ LLViewerObject::const_child_list_t& child_list = mDrawable->getVObj()->getChildren();
+ for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
+ iter != child_list.end(); iter++)
+ {
+ LLViewerObject* child = *iter;
+ LLDrawable* drawable = child->mDrawable;
+ results->push_back(drawable);
+ }
+ }
+ }
+ else
+ {
+ LLCamera trans_camera = transformCamera(camera_in);
+ LLOctreeMarkNotCulled culler(&trans_camera);
+ culler.traverse(mOctree);
+ }
+ }
+}
+
+void LLSpatialBridge::updateDistance(LLCamera& camera_in, bool force_update)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
+
+ if (mDrawable == NULL)
+ {
+ markDead();
+ return;
+ }
+
+ if (gShiftFrame)
+ {
+ return;
+ }
+
+ if (mDrawable->getVObj())
+ {
+ // Don't update if we are part of impostor, unles it's an impostor pass
+ if (!LLPipeline::sImpostorRender && mDrawable->getVObj()->isAttachment())
+ {
+ LLDrawable* parent = mDrawable->getParent();
+ if (parent && parent->getVObj())
+ {
+ LLVOAvatar* av = parent->getVObj()->asAvatar();
+ if (av && av->isImpostor())
+ {
+ return;
+ }
+ }
+ }
+
+ LLCamera camera = transformCamera(camera_in);
+
+ mDrawable->updateDistance(camera, force_update);
+
+ LLViewerObject::const_child_list_t& child_list = mDrawable->getVObj()->getChildren();
+ for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
+ iter != child_list.end(); iter++)
+ {
+ LLViewerObject* child = *iter;
+ LLDrawable* drawable = child->mDrawable;
+ if (!drawable)
+ {
+ continue;
+ }
+
+ if (!drawable->isAvatar())
+ {
+ drawable->updateDistance(camera, force_update);
+ }
+ }
+ }
+}
+
+void LLSpatialBridge::makeActive()
+{ //it is an error to make a spatial bridge active (it's already active)
+ LL_ERRS() << "makeActive called on spatial bridge" << LL_ENDL;
+}
+
+void LLSpatialBridge::move(LLDrawable *drawablep, LLSpatialGroup *curp, bool immediate)
+{
+ LLSpatialPartition::move(drawablep, curp, immediate);
+ gPipeline.markMoved(this, false);
+}
+
+bool LLSpatialBridge::updateMove()
+{
+ llassert_always(mDrawable);
+ llassert_always(mDrawable->mVObjp);
+ llassert_always(mDrawable->getRegion());
+ LLSpatialPartition* part = mDrawable->getRegion()->getSpatialPartition(mPartitionType);
+ llassert_always(part);
+
+ mOctree->balance();
+ if (part)
+ {
+ part->move(this, getSpatialGroup(), true);
+ }
+ return true;
+}
+
+void LLSpatialBridge::shiftPos(const LLVector4a& vec)
+{
+ LLDrawable::shift(vec);
+}
+
+void LLSpatialBridge::cleanupReferences()
+{
+ LLDrawable::cleanupReferences();
+ if (mDrawable)
+ {
+ mDrawable->setGroup(NULL);
+
+ if (mDrawable->getVObj())
+ {
+ LLViewerObject::const_child_list_t& child_list = mDrawable->getVObj()->getChildren();
+ for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
+ iter != child_list.end(); iter++)
+ {
+ LLViewerObject* child = *iter;
+ LLDrawable* drawable = child->mDrawable;
+ if (drawable)
+ {
+ drawable->setGroup(NULL);
+ }
+ }
+ }
+
+ LLDrawable* drawablep = mDrawable;
+ mDrawable = NULL;
+ drawablep->setSpatialBridge(NULL);
+ }
+}
+
+const LLVector3 LLDrawable::getPositionAgent() const
+{
+ if (getVOVolume())
+ {
+ if (isActive())
+ {
+ LLVector3 pos(0,0,0);
+ if (!isRoot())
+ {
+ pos = mVObjp->getPosition();
+ }
+ return pos * getRenderMatrix();
+ }
+ else
+ {
+ return mVObjp->getPositionAgent();
+ }
+ }
+ else
+ {
+ return getWorldPosition();
+ }
+}
+
+bool LLDrawable::isAnimating() const
+{
+ if (!getVObj())
+ {
+ return true;
+ }
+
+ if (getScale() != mVObjp->getScale())
+ {
+ return true;
+ }
+
+ if (mVObjp->getPCode() == LLViewerObject::LL_VO_PART_GROUP)
+ {
+ return true;
+ }
+ if (mVObjp->getPCode() == LLViewerObject::LL_VO_HUD_PART_GROUP)
+ {
+ return true;
+ }
+
+ /*if (!isRoot() && !mVObjp->getAngularVelocity().isExactlyZero())
+ { //target omega
+ return true;
+ }*/
+
+ return false;
+}
+
+void LLDrawable::updateFaceSize(S32 idx)
+{
+ if (mVObjp.notNull())
+ {
+ mVObjp->updateFaceSize(idx);
+ }
+}
+
+LLDrawable* LLDrawable::getRoot()
+{
+ LLDrawable* ret = this;
+ while (!ret->isRoot())
+ {
+ ret = ret->getParent();
+ }
+
+ return ret;
+}
+
+LLBridgePartition::LLBridgePartition(LLViewerRegion* regionp)
+: LLSpatialPartition(0, false, regionp)
+{
+ mDrawableType = LLPipeline::RENDER_TYPE_VOLUME;
+ mPartitionType = LLViewerRegion::PARTITION_BRIDGE;
+ mLODPeriod = 16;
+ mSlopRatio = 0.25f;
+}
+
+LLAvatarPartition::LLAvatarPartition(LLViewerRegion* regionp)
+ : LLBridgePartition(regionp)
+{
+ mDrawableType = LLPipeline::RENDER_TYPE_AVATAR;
+ mPartitionType = LLViewerRegion::PARTITION_AVATAR;
+}
+
+LLControlAVPartition::LLControlAVPartition(LLViewerRegion* regionp)
+ : LLBridgePartition(regionp)
+{
+ mDrawableType = LLPipeline::RENDER_TYPE_CONTROL_AV;
+ mPartitionType = LLViewerRegion::PARTITION_CONTROL_AV;
+}
+
+LLHUDBridge::LLHUDBridge(LLDrawable* drawablep, LLViewerRegion* regionp)
+: LLVolumeBridge(drawablep, regionp)
+{
+ mDrawableType = LLPipeline::RENDER_TYPE_HUD;
+ mPartitionType = LLViewerRegion::PARTITION_HUD;
+ mSlopRatio = 0.0f;
+}
+
+F32 LLHUDBridge::calcPixelArea(LLSpatialGroup* group, LLCamera& camera)
+{
+ return 1024.f;
+}
+
+
+void LLHUDBridge::shiftPos(const LLVector4a& vec)
+{
+ //don't shift hud bridges on region crossing
+}
+
|