diff options
| author | James Cook <james@lindenlab.com> | 2007-01-02 08:33:20 +0000 |
|---|---|---|
| committer | James Cook <james@lindenlab.com> | 2007-01-02 08:33:20 +0000 |
| commit | 420b91db29485df39fd6e724e782c449158811cb (patch) | |
| tree | b471a94563af914d3ed3edd3e856d21cb1b69945 /indra/newview/lldrawable.cpp | |
Print done when done.
Diffstat (limited to 'indra/newview/lldrawable.cpp')
| -rw-r--r-- | indra/newview/lldrawable.cpp | 1320 |
1 files changed, 1320 insertions, 0 deletions
diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp new file mode 100644 index 0000000000..a198886d37 --- /dev/null +++ b/indra/newview/lldrawable.cpp @@ -0,0 +1,1320 @@ +/** + * @file lldrawable.cpp + * @brief LLDrawable class implementation + * + * Copyright (c) 2002-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "lldrawable.h" + +// library includes +#include "material_codes.h" + +// viewer includes +#include "llagparray.h" +#include "llagparray.inl" +#include "llcriticaldamp.h" +#include "llface.h" +#include "lllightconstants.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" + +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; +const F32 MIN_SHADOW_CASTER_RADIUS = 2.0f; + +//////////////////////// +// +// Inline implementations. +// +// + + + +////////////////////////////// +// +// Drawable code +// +// + +// static +U32 LLDrawable::sCurVisible = 0; +U32 LLDrawable::sNumZombieDrawables = 0; +F32 LLDrawable::sCurPixelAngle = 0; +LLDynamicArrayPtr<LLPointer<LLDrawable> > LLDrawable::sDeadList; + +// static +void LLDrawable::incrementVisible() +{ + sCurVisible++; + sCurPixelAngle = (F32) gViewerWindow->getWindowDisplayHeight()/gCamera->getView(); +} +void LLDrawable::init() +{ + // mXform + mParent = NULL; + mRenderType = 0; + mCurrentScale = LLVector3(1,1,1); + mDistanceWRTCamera = 0.0f; + // mUVRect + mUVZ = 0.f; + // mLightSet + // mBlockSet + // mSavePos + mQuietCount = 0; + + mState = 0; + mVObjp = NULL; + // mFaces + mSpatialGroupp = NULL; + mSpatialGroupOffset = -1; + mVisible = 0; + mRadius = 0.f; + mSunShadowFactor = 1.f; + + mGeneration = -1; + mBinRadius = 1.f; + mSpatialBridge = NULL; +} + +// static +void LLDrawable::initClass() +{ +} + + +void LLDrawable::destroy() +{ + if (isDead()) + { + sNumZombieDrawables--; + } + + std::for_each(mFaces.begin(), mFaces.end(), DeletePointer()); + mFaces.clear(); + + /* + if (!(sNumZombieDrawables % 10)) + { + llinfos << "- Zombie drawables: " << sNumZombieDrawables << llendl; + } + */ +} + +void LLDrawable::markDead() +{ + if (isDead()) + { + llwarns << "Warning! Marking dead multiple times!" << llendl; + return; + } + + if (mSpatialBridge) + { + mSpatialBridge->markDead(); + mSpatialBridge = NULL; + } + + sNumZombieDrawables++; + + // We're dead. Free up all of our references to other objects + setState(DEAD); + cleanupReferences(); +// sDeadList.put(this); +} + +LLVOVolume* LLDrawable::getVOVolume() const +{ + LLViewerObject* objectp = mVObjp; + if ( !isDead() && objectp && (objectp->getPCode() == LL_PCODE_VOLUME)) + { + return ((LLVOVolume*)objectp); + } + else + { + return NULL; + } +} + +BOOL LLDrawable::isLight() const +{ + LLViewerObject* objectp = mVObjp; + if ( objectp && (objectp->getPCode() == LL_PCODE_VOLUME) && !isDead()) + { + return ((LLVOVolume*)objectp)->getIsLight(); + } + else + { + return FALSE; + } +} + +void LLDrawable::clearLightSet() +{ + // Remove this object from any object which has it as a light + for (drawable_set_t::iterator iter = mLightSet.begin(); iter != mLightSet.end(); iter++) + { + LLDrawable *targetp = *iter; + if (targetp != this && !targetp->isDead()) + { + targetp->mLightSet.erase(this); + gPipeline.markRelight(targetp); + } + } + mLightSet.clear(); +} + +void LLDrawable::cleanupReferences() +{ + LLFastTimer t(LLFastTimer::FTM_PIPELINE); + + std::for_each(mFaces.begin(), mFaces.end(), DeletePointer()); + mFaces.clear(); + + clearLightSet(); + + gObjectList.removeDrawable(this); + + mBlockSet.clear(); + + gPipeline.unlinkDrawable(this); + + // Cleanup references to other objects + mVObjp = NULL; + mParent = NULL; +} + +void LLDrawable::cleanupDeadDrawables() +{ + /* + S32 i; + for (i = 0; i < sDeadList.count(); i++) + { + if (sDeadList[i]->getNumRefs() > 1) + { + llwarns << "Dead drawable has " << sDeadList[i]->getNumRefs() << " remaining refs" << llendl; + gPipeline.findReferences(sDeadList[i]); + } + } + */ + sDeadList.reset(); +} + +S32 LLDrawable::findReferences(LLDrawable *drawablep) +{ + S32 count = 0; + if (mLightSet.count(drawablep) > 0) + { + llinfos << this << ": lightset reference" << llendl; + count++; + } + if (mBlockSet.count(drawablep) > 0) + { + llinfos << this << ": blockset reference" << llendl; + count++; + } + if (mParent == drawablep) + { + llinfos << this << ": parent reference" << llendl; + count++; + } + return count; +} + +#if 0 +// SJB: This is SLOW, so we don't want to allow it (we don't currently use it) +void LLDrawable::removeFace(const S32 i) +{ + LLFace *face= mFaces[i]; + + if (face) + { + mFaces.erase(mFaces.begin() + i); + delete face; + } +} +#endif + +LLFace* LLDrawable::addFace(LLDrawPool *poolp, LLViewerImage *texturep, const BOOL shared_geom) +{ + LLMemType mt(LLMemType::MTYPE_DRAWABLE); + + LLFace *face = new LLFace(this, mVObjp); + + if (face) + { + mFaces.push_back(face); + face->setPool(poolp, texturep); + + if (shared_geom) + { + face->setState(LLFace::SHARED_GEOM); + } + else if (!isVisible()) + { + face->setState(LLFace::BACKLIST); + } + if (isState(UNLIT)) + { + face->setState(LLFace::FULLBRIGHT); + } + } + return face; +} + +void LLDrawable::setNumFaces(const S32 newFaces, LLDrawPool *poolp, LLViewerImage *texturep) +{ + 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); + } + } +} + +void LLDrawable::setNumFacesFast(const S32 newFaces, LLDrawPool *poolp, LLViewerImage *texturep) +{ + 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); + } + } +} + +void LLDrawable::mergeFaces(LLDrawable* src) +{ + 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() +{ + llerrs << "Shouldn't be called!" << llendl; +} + + +void LLDrawable::updateMaterial() +{ +} + +void LLDrawable::makeActive() +{ + if (!isState(ACTIVE)) // && mGeneration > 0) + { + setState(ACTIVE); + + if (!isRoot() && !mParent->isActive()) + { + mParent->makeActive(); + } + + gPipeline.setActive(this, TRUE); + + //all child objects must also be active + for (U32 i = 0; i < getChildCount(); i++) + { + getChild(i)->makeActive(); + } + + if (mVObjp->getPCode() == LL_PCODE_VOLUME) + { + if (mVObjp->getVolume()->getPathType() == LL_PCODE_PATH_FLEXIBLE) + { + return; + } + } + + clearState(LLDrawable::LIGHTING_BUILT); + if (mVObjp->getPCode() == LL_PCODE_VOLUME) + { + gPipeline.markRebuild(this, LLDrawable::REBUILD_VOLUME, TRUE); + } + } + mQuietCount = 0; +} + + +void LLDrawable::makeStatic() +{ + if (isState(ACTIVE)) + { + clearState(ACTIVE); + gPipeline.setActive(this, FALSE); + + if (mParent.notNull() && mParent->isActive()) + { + llerrs << "Drawable became static with active parent!" << llendl; + } + + S32 child_count = mVObjp->mChildList.size(); + for (S32 child_num = 0; child_num < child_count; child_num++) + { + LLDrawable* child_drawable = mVObjp->mChildList[child_num]->mDrawable; + if (child_drawable) + { + child_drawable->makeStatic(); + } + } + + gPipeline.markRelight(this); + if (mVObjp->getPCode() == LL_PCODE_VOLUME) + { + gPipeline.markRebuild(this, LLDrawable::REBUILD_VOLUME, TRUE); + } + + if (mSpatialBridge) + { + mSpatialBridge->markDead(); + setSpatialBridge(NULL); + } + } +} + +// Returns "distance" between target destination and resulting xfrom +F32 LLDrawable::updateXform(BOOL undamped) +{ + BOOL damped = !undamped; + + // Position + 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 + LLQuaternion old_rot(mXform.getRotation()); + LLQuaternion target_rot = mVObjp->getRotation(); + //scaling + LLVector3 target_scale = mVObjp->getScale(); + LLVector3 old_scale = mCurrentScale; + LLVector3 dest_scale = target_scale; + + // Damping + F32 dist_squared = 0.f; + F32 scaled = 0.f; + + if (damped && mDistanceWRTCamera > 0.0f) + { + F32 lerp_amt = llclamp(LLCriticalDamp::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); + dist_squared += (1.f - dot(new_rot, target_rot)) * 10.f; + + LLVector3 new_scale = lerp(old_scale, target_scale, lerp_amt); + scaled = dist_vec_squared(new_scale, target_scale); + + dist_squared += scaled; + F32 camdist2 = (mDistanceWRTCamera * mDistanceWRTCamera); + 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; + + if (scaled >= MIN_INTERPOLATE_DISTANCE_SQUARED) + { + //scaling requires an immediate rebuild + gPipeline.markRebuild(this, LLDrawable::REBUILD_VOLUME, TRUE); + } + + } + else + { + // snap to final position + dist_squared = 0.0f; + } + } + + // 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(); + + mCurrentScale = target_scale; + + 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_VOLUME, TRUE); + } + + return dist_squared; +} + +void LLDrawable::setRadius(F32 radius) +{ + if (mRadius != radius) + { + mRadius = radius; + updateBinRadius(); + if (!getVOVolume()) + { + movePartition(); + } + } +} + +void LLDrawable::moveUpdatePipeline(BOOL moved) +{ + makeActive(); + + // Update the face centers. + for (S32 i = 0; i < getNumFaces(); i++) + { + getFace(i)->updateCenterAgent(); + } + + if (moved || !isState(LLDrawable::BUILT)) // moved since last frame + { + LLVector3 tmp = mSavePos - mXform.getPositionW(); + F32 dist = tmp.magVecSquared(); // moved since last _update_ + + if (dist > 1.0f || !isState(LLDrawable::BUILT) || isLight()) + { + mSavePos = mXform.getPositionW(); + gPipeline.markRelight(this); + } + } +} + +void LLDrawable::movePartition() +{ + if (getSpatialGroup() || getVOVolume()) + { + LLSpatialPartition* part = getSpatialPartition(); + if (part) + { + part->move(this, getSpatialGroup()); + } + } +} + +BOOL LLDrawable::updateMove() +{ + if (isDead()) + { + llwarns << "Update move on dead drawable!" << llendl; + return TRUE; + } + + if (mVObjp.isNull()) + { + return FALSE; + } + + makeActive(); + + BOOL done; + + if (isState(MOVE_UNDAMPED)) + { + done = updateMoveUndamped(); + } + else + { + done = updateMoveDamped(); + } + return done; +} + +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; +} + +BOOL LLDrawable::updateMoveDamped() +{ + 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) ? TRUE : FALSE; + + if (done_moving) + { + mVObjp->clearChanged(LLXform::MOVED); + } + + return done_moving; +} + +void LLDrawable::updateDistance(LLCamera& camera) +{ + if (mVObjp->isHUDAttachment()) + { + mDistanceWRTCamera = 1.0f; + if (sCurVisible % 16 == 0) + { + mVObjp->updateLOD(); + } + return; + } + + LLVector3 pos(getPositionGroup()); + + pos -= camera.getOrigin(); + mDistanceWRTCamera = pos.magVec(); + + //switch LOD with the spatial group to avoid artifacts + LLSpatialGroup* sg = getSpatialGroup(); + if (!sg || sg->changeLOD()) + { + mVObjp->updateLOD(); + } +} + +void LLDrawable::updateTexture() +{ + LLMemType mt(LLMemType::MTYPE_DRAWABLE); + + if (isDead()) + { + llwarns << "Dead drawable updating texture!" << llendl; + return; + } + + //FIXME: this updates textures on all faces in this drawable, not just the viewer object we care about + if (mVObjp->getNumTEs()) + { + // For each face in this drawable, change the drawpool if necessary. + for (S32 i = 0; i < getNumFaces(); i++) + { + LLFace *facep = mFaces[i]; + U32 pool_type = facep->getPool()->getType(); + + if ((pool_type == LLDrawPool::POOL_SIMPLE) || + (pool_type == LLDrawPool::POOL_ALPHA) || + (pool_type == LLDrawPool::POOL_HUD) || + (pool_type == LLDrawPool::POOL_MEDIA) || + (pool_type == LLDrawPool::POOL_BUMP)) + { + LLViewerObject* objp = facep->getViewerObject(); + S32 te_offset = facep->getTEOffset(); + + if (te_offset >= objp->getNumTEs()) // Shouldn't happen + { + llwarns << "TE offsets don't match!" << llendl; + facep->setTEOffset(-1); + continue; + } + + LLDrawPool* poolp = NULL; + LLViewerImage* imagep = (te_offset >= 0) ? objp->getTEImage(te_offset) : facep->getTexture(); + if (facep->isState(LLFace::HUD_RENDER)) + { + poolp = gPipeline.getPool(LLDrawPool::POOL_HUD); + } + else if (te_offset >= 0) + { + // This face actually uses texture entries... + const LLTextureEntry* te = facep->getTextureEntry(); + poolp = LLPipeline::getPoolFromTE(te, imagep); + } + else + { + // No texture entry for this face. + if (!imagep) + { + poolp = gPipeline.getPool(LLDrawPool::POOL_SIMPLE, NULL); + } + else if ((imagep->getComponents() == 4) || (imagep->getComponents() == 2)) + { + poolp = gPipeline.getPool(LLDrawPool::POOL_ALPHA); + } + else + { + poolp = gPipeline.getPool(LLDrawPool::POOL_SIMPLE, imagep); + } + } + facep->setPool(poolp, imagep); + } + } + } +} + + +BOOL LLDrawable::updateGeometry(BOOL priority) +{ + llassert(mVObjp.notNull()); + BOOL res = mVObjp->updateGeometry(this); + if (isState(REBUILD_LIGHTING)) + { + updateLighting(priority ? FALSE : TRUE); // only do actual lighting for non priority updates + if (priority) + { + gPipeline.markRelight(this); // schedule non priority update + } + else + { + clearState(REBUILD_LIGHTING); + } + } + return res; +} + +void LLDrawable::shiftPos(const LLVector3 &shift_vector) +{ + if (isDead()) + { + llwarns << "Shifting dead drawable" << llendl; + return; + } + + if (mParent) + { + mXform.setPosition(mVObjp->getPosition()); + } + else + { + mXform.setPosition(mVObjp->getPositionAgent()); + } + + mXform.setRotation(mVObjp->getRotation()); + mXform.setScale(1,1,1); + mXform.updateMatrix(); + + if (isStatic() || //DP FIXME: don't know why this is happening, but + //some terrain patches are becoming active + //(earth quake, maybe?) + getRenderType() == LLPipeline::RENDER_TYPE_TERRAIN) + { + LLStrider<LLVector3> verticesp; + + for (S32 i = 0; i < getNumFaces(); i++) + { + LLFace *facep = getFace(i); + facep->mCenterAgent += shift_vector; + facep->mExtents[0] += shift_vector; + facep->mExtents[1] += shift_vector; + + if (facep->hasGeometry() && !facep->isState(LLFace::SHARED_GEOM)) + { + S32 index = facep->getVertices(verticesp); + if (index >= 0) + { + S32 vertex_count = facep->getGeomCount(); + for (S32 j = 0; j < vertex_count; j++) + { + *verticesp += shift_vector; + verticesp++; + } + } + } + } + } + else + { + // Update the face centers. + for (S32 i = 0; i < getNumFaces(); i++) + { + LLFace *facep = getFace(i); + facep->mCenterAgent += shift_vector; + } + } + + //update spatial extents + if (!getVOVolume() || isStatic()) + { + mExtents[0] += shift_vector; + mExtents[1] += shift_vector; + mPositionGroup += LLVector3d(shift_vector); + } + else if (mSpatialBridge) + { + mSpatialBridge->shiftPos(shift_vector); + } + + mSavePos = mXform.getPositionW(); + + mVObjp->onShift(shift_vector); +} + +const LLVector3& LLDrawable::getBounds(LLVector3& min, LLVector3& max) const +{ + mXform.getMinMax(min,max); + return mXform.getPositionW(); +} + +const LLVector3* LLDrawable::getSpatialExtents() const +{ + return mExtents; +} + +void LLDrawable::setSpatialExtents(LLVector3 min, LLVector3 max) +{ + LLVector3 size = max - min; + mExtents[0] = min; + mExtents[1] = max; +} + +void LLDrawable::setPositionGroup(const LLVector3d& pos) +{ + mPositionGroup.setVec(pos); +} + +void LLDrawable::updateSpatialExtents() +{ + if (mVObjp) + { + mVObjp->updateSpatialExtents(mExtents[0], mExtents[1]); + } + + if (mSpatialBridge.notNull()) + { + mPositionGroup.setVec(0,0,0); + } +} + + +void LLDrawable::updateBinRadius() +{ + S32 binLOD = mVObjp ? mVObjp->getLOD() : 2; + static F64 detail_bins[] = { 8, 4, 2, 1 }; + F32 radius = getVOVolume() && isStatic() ? + (mExtents[1]-mExtents[0]).magVec() : getRadius(); + mBinRadius = detail_bins[binLOD] * llmax((F64) radius, (3-binLOD)*0.25); +} + +void LLDrawable::updateLightSet() +{ + if (isDead()) + { + llwarns << "Updating light set for dead drawable!" << llendl; + return; + } + + LLVOVolume* light = getVOVolume(); + if (isLight() && light) + { + // mLightSet points to lit objects + for (drawable_set_t::iterator iter = mLightSet.begin(); iter != mLightSet.end(); iter++) + { + gPipeline.markRelight(*iter); + } + mLightSet.clear(); + gPipeline.mObjectPartition->getObjects(getPositionAgent(), light->getLightRadius(), mLightSet); + for (drawable_set_t::iterator iter = mLightSet.begin(); iter != mLightSet.end(); iter++) + { + gPipeline.markRelight(*iter); + } + } + else + { + // mLightSet points to nearby lights + mLightSet.clear(); + gPipeline.mObjectPartition->getLights(getPositionAgent(), getRadius(), mLightSet); + const U32 max_lights = 16; + if (mLightSet.size() > max_lights) + { + typedef std::set<std::pair<F32,LLPointer<LLDrawable> > > sorted_pair_set_t; + sorted_pair_set_t sorted_set; + for (drawable_set_t::iterator iter = mLightSet.begin(); iter != mLightSet.end(); iter++) + { + LLDrawable* drawable = *iter; + LLVector3 dvec = drawable->getPositionAgent() - getPositionAgent(); + F32 dist2 = dvec.magVecSquared(); + sorted_set.insert(std::make_pair(dist2, drawable)); + } + mLightSet.clear(); + S32 count = 0; + for (sorted_pair_set_t::iterator iter = sorted_set.begin(); iter != sorted_set.end(); iter++) + { + if (++count > 16) + break; + mLightSet.insert((*iter).second); + } + } + } +} + +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 +} + +BOOL LLDrawable::updateLighting(BOOL do_lighting) +{ + if (do_lighting) + { + if (gPipeline.getLightingDetail() >= 2 && (getLit() || isLight())) + { + LLFastTimer t(LLFastTimer::FTM_UPDATE_LIGHTS); + updateLightSet(); + do_lighting = isLight() ? FALSE : TRUE; + } + else + { + do_lighting = FALSE; + } + } + if (gPipeline.getLightingDetail() >= 2) + { + LLFastTimer t(LLFastTimer::FTM_GEO_LIGHT); + if (mVObjp->updateLighting(do_lighting)) + { + setState(LIGHTING_BUILT); + } + } + + return TRUE; +} + +void LLDrawable::applyLightsAsPoint(LLColor4& result) +{ + LLMemType mt1(LLMemType::MTYPE_DRAWABLE); + + LLVector3 point_agent(getPositionAgent()); + LLVector3 normal(-gCamera->getXAxis()); // make point agent face camera + + F32 sun_int = normal * gPipeline.mSunDir; + LLColor4 color(gSky.getTotalAmbientColor()); + color += gPipeline.mSunDiffuse * sun_int; + + for (drawable_set_t::iterator iter = mLightSet.begin(); + iter != mLightSet.end(); ++iter) + { + LLDrawable* drawable = *iter; + LLVOVolume* light = drawable->getVOVolume(); + if (!light) + { + continue; + } + LLColor4 light_color; + light->calcLightAtPoint(point_agent, normal, light_color); + color += light_color; + } + + // Clamp the color... + color.mV[0] = llmax(color.mV[0], 0.f); + color.mV[1] = llmax(color.mV[1], 0.f); + color.mV[2] = llmax(color.mV[2], 0.f); + + F32 max_color = llmax(color.mV[0], color.mV[1], color.mV[2]); + if (max_color > 1.f) + { + color *= 1.f/max_color; + } + + result = color; +} + +F32 LLDrawable::getVisibilityRadius() const +{ + if (isDead()) + { + return 0.f; + } + else if (isLight()) + { + return llmax(getRadius(), getVOVolume()->getLightRadius()); + } + else + { + return getRadius(); + } +} + +void LLDrawable::updateUVMinMax() +{ +} + +void LLDrawable::setSpatialGroup(LLSpatialGroup *groupp, const S32 offset) +{ + mSpatialGroupp = groupp; + + if (mSpatialGroupp) + { + mSpatialGroupOffset = offset; + } + else + { + mSpatialGroupOffset = -1; + } +} + +LLSpatialPartition* LLDrawable::getSpatialPartition() +{ + LLSpatialPartition* retval = NULL; + + if (mVObjp->isHUDAttachment()) + { //HUD attachments don't get space partitioned + return NULL; + } + + if (!mVObjp || + !getVOVolume() || + isStatic()) + { + retval = gPipeline.mObjectPartition; + } + + //must be an active volume + if (!retval && isRoot()) + { + if (!mSpatialBridge) + { + setSpatialBridge(new LLSpatialBridge(this)); + } + return mSpatialBridge->asPartition(); + } + else if (!retval) + { + retval = getParent()->getSpatialPartition(); + } + + if (retval && mSpatialBridge.notNull()) + { + mSpatialBridge->markDead(); + setSpatialBridge(NULL); + } + + return retval; +} + +//======================================= +// Spatial Partition Bridging Drawable +//======================================= + +LLSpatialBridge::LLSpatialBridge(LLDrawable* root) +{ + mDrawable = root; + root->setSpatialBridge(this); + + mRenderType = mDrawable->mRenderType; //w00! magic! + + mOctree->balance(); + + gPipeline.mObjectPartition->put(this); +} + +LLSpatialBridge::~LLSpatialBridge() +{ + if (getSpatialGroup()) + { + gPipeline.mObjectPartition->remove(this, getSpatialGroup()); + } +} + +void LLSpatialBridge::updateSpatialExtents() +{ + LLSpatialGroup* root = (LLSpatialGroup*) mOctree->getListener(0); + + if (mOctree->getChildCount() > 0) + { + LLFastTimer ftm(LLFastTimer::FTM_CULL_REBOUND); + root->rebound(); + } + + LLXformMatrix* mat = mDrawable->getXform(); + + LLVector3 offset = root->mBounds[0]; + LLVector3 size = root->mBounds[1]; + + LLVector3 center = LLVector3(0,0,0) * mat->getWorldMatrix(); + LLQuaternion rotation = LLQuaternion(mat->getWorldMatrix()); + + offset *= rotation; + center += offset; + + LLVector3 v[4]; + //get 4 corners of bounding box + v[0] = (size * rotation); + v[1] = (LLVector3(-size.mV[0], -size.mV[1], size.mV[2]) * rotation); + v[2] = (LLVector3(size.mV[0], -size.mV[1], -size.mV[2]) * rotation); + v[3] = (LLVector3(-size.mV[0], size.mV[1], -size.mV[2]) * rotation); + + LLVector3& newMin = mExtents[0]; + LLVector3& newMax = mExtents[1]; + + newMin = newMax = center; + + for (U32 i = 0; i < 4; i++) + { + for (U32 j = 0; j < 3; j++) + { + F32 delta = fabsf(v[i].mV[j]); + F32 min = center.mV[j] - delta; + F32 max = center.mV[j] + delta; + + if (min < newMin.mV[j]) + { + newMin.mV[j] = min; + } + + if (max > newMax.mV[j]) + { + newMax.mV[j] = max; + } + } + } + + mPositionGroup.setVec((newMin + newMax) * 0.5f); + updateBinRadius(); +} + +void LLSpatialBridge::updateBinRadius() +{ + F32 rad = ((mExtents[1]-mExtents[0])*0.5f).magVec(); + mBinRadius = llmax(rad, 2.f); + mRadius = rad; +} + +LLCamera LLSpatialBridge::transformCamera(LLCamera& camera) +{ + LLCamera ret = camera; + LLXformMatrix* mat = mDrawable->getXform(); + LLVector3 center = LLVector3(0,0,0) * mat->getWorldMatrix(); + //LLQuaternion rotation = LLQuaternion(mat->getWorldMatrix()); + + //ret.rotate(~mat->getRotation()); + LLVector3 delta = ret.getOrigin() - center; + delta *= ~mat->getRotation(); + ret.setOrigin(delta); + + return ret; +} + +void LLDrawable::setVisible(LLCamera& camera, std::vector<LLDrawable*>* results, BOOL for_select) +{ + mVisible = sCurVisible; +} + +void LLSpatialBridge::setVisible(LLCamera& camera_in, std::vector<LLDrawable*>* results, BOOL for_select) +{ + LLVector3 center = (mExtents[0] + mExtents[1]) * 0.5f; + LLVector3 size = (mExtents[1]-mExtents[0]) * 0.5f; + + if (camera_in.AABBInFrustum(center, size)) + { + LLVector3 lookAt = center - camera_in.getOrigin(); + F32 distSqr = lookAt.magVecSquared(); + F32 objRad = size.magVecSquared(); + + if (objRad/distSqr < SG_MIN_DIST_RATIO*4) + { + return; + } + + LLDrawable::setVisible(camera_in); + + if (for_select) + { + results->push_back(mDrawable); + for (U32 i = 0; i < mDrawable->getChildCount(); i++) + { + results->push_back(mDrawable->getChild(i)); + } + } + else + { + const LLVector3* extents = mDrawable->getSpatialExtents(); + objRad = mDrawable->getRadius(); + objRad *= objRad; + + if (objRad/distSqr > SG_MIN_DIST_RATIO) + { + gPipeline.markNotCulled(mDrawable, camera_in); + } + + for (U32 i = 0; i < mDrawable->getChildCount(); i++) + { + LLDrawable* child = mDrawable->getChild(i); + extents = child->getSpatialExtents(); + objRad = child->getRadius(); + objRad *= objRad; + + if (objRad/distSqr > SG_MIN_DIST_RATIO) + { + gPipeline.markNotCulled(mDrawable->getChild(i), camera_in); + } + } + } + } +} + +void LLSpatialBridge::updateDistance(LLCamera& camera_in) +{ + LLCamera camera = transformCamera(camera_in); + + mDrawable->updateDistance(camera); + + for (U32 i = 0; i < mDrawable->getChildCount(); ++i) + { + mDrawable->getChild(i)->updateDistance(camera); + } +} + +void LLSpatialBridge::makeActive() +{ //it is an error to make a spatial bridge active (it's already active) + llerrs << "makeActive called on spatial bridge" << llendl; +} + +void LLSpatialBridge::makeStatic() +{ + llerrs << "makeStatic called on spatial bridge" << llendl; +} + +void LLSpatialBridge::move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL immediate) +{ + LLSpatialPartition::move(drawablep, curp, immediate); + gPipeline.markMoved(this, FALSE); +} + +BOOL LLSpatialBridge::updateMove() +{ + mOctree->balance(); + gPipeline.mObjectPartition->move(this, getSpatialGroup(), TRUE); + return TRUE; +} + +void LLSpatialBridge::shiftPos(const LLVector3& vec) +{ + mExtents[0] += vec; + mExtents[1] += vec; + mPositionGroup += LLVector3d(vec); +} + +void LLSpatialBridge::cleanupReferences() +{ + LLDrawable::cleanupReferences(); + if (mDrawable) + { + mDrawable->setSpatialGroup(NULL, -1); + for (U32 i = 0; i < mDrawable->getChildCount(); i++) + { + LLDrawable* drawable = mDrawable->getChild(i); + if (drawable && drawable->getVOVolume()) + { + drawable->setSpatialGroup(NULL, -1); + } + } + + LLDrawable* drawablep = mDrawable; + mDrawable = NULL; + drawablep->setSpatialBridge(NULL); + } +} + +const LLVector3 LLDrawable::getPositionAgent() const +{ + if (getVOVolume()) + { + if (isActive()) + { + if (isRoot()) + { + return LLVector3(0,0,0) * getWorldMatrix(); + } + else + { + return mVObjp->getPosition() * getParent()->getWorldMatrix(); + } + } + else + { + return mVObjp->getPositionAgent(); + } + } + else + { + return getWorldPosition(); + } +} + |
