lldrawable.cpp

Go to the documentation of this file.
00001 
00032 #include "llviewerprecompiledheaders.h"
00033 
00034 #include "lldrawable.h"
00035 
00036 // library includes
00037 #include "material_codes.h"
00038 
00039 // viewer includes
00040 #include "llcriticaldamp.h"
00041 #include "llface.h"
00042 #include "lllightconstants.h"
00043 #include "llsky.h"
00044 #include "llsurfacepatch.h"
00045 #include "llviewercamera.h"
00046 #include "llviewerregion.h"
00047 #include "llvolume.h"
00048 #include "llvoavatar.h"
00049 #include "llvovolume.h"
00050 #include "llvosurfacepatch.h" // for debugging
00051 #include "llworld.h"
00052 #include "pipeline.h"
00053 #include "llspatialpartition.h"
00054 #include "llviewerobjectlist.h"
00055 #include "llviewerwindow.h"
00056 
00057 const F32 MIN_INTERPOLATE_DISTANCE_SQUARED = 0.001f * 0.001f;
00058 const F32 MAX_INTERPOLATE_DISTANCE_SQUARED = 10.f * 10.f;
00059 const F32 OBJECT_DAMPING_TIME_CONSTANT = 0.06f;
00060 const F32 MIN_SHADOW_CASTER_RADIUS = 2.0f;
00061 
00063 //
00064 // Inline implementations.
00065 //
00066 //
00067 
00068 
00069 
00071 //
00072 // Drawable code
00073 //
00074 //
00075 
00076 // static
00077 U32 LLDrawable::sCurVisible = 0;
00078 U32 LLDrawable::sNumZombieDrawables = 0;
00079 F32 LLDrawable::sCurPixelAngle = 0;
00080 LLDynamicArrayPtr<LLPointer<LLDrawable> > LLDrawable::sDeadList;
00081 
00082 #define FORCE_INVISIBLE_AREA 16.f
00083 
00084 // static
00085 void LLDrawable::incrementVisible() 
00086 {
00087         sCurVisible++;
00088         sCurPixelAngle = (F32) gViewerWindow->getWindowDisplayHeight()/gCamera->getView();
00089 }
00090 void LLDrawable::init()
00091 {
00092         // mXform
00093         mParent = NULL;
00094         mRenderType = 0;
00095         mCurrentScale = LLVector3(1,1,1);
00096         mDistanceWRTCamera = 0.0f;
00097         // mUVRect
00098         mUVZ = 0.f;
00099         // mLightSet
00100         // mBlockSet
00101         // mSavePos
00102         mQuietCount = 0;
00103 
00104         mState     = 0;
00105         mVObjp   = NULL;
00106         // mFaces
00107         mSpatialGroupp = NULL;
00108         mVisible = 0;
00109         mRadius = 0.f;
00110         mSunShadowFactor = 1.f;
00111         
00112         mGeneration = -1;
00113         mBinRadius = 1.f;
00114         mSpatialBridge = NULL;
00115 }
00116 
00117 // static
00118 void LLDrawable::initClass()
00119 {
00120 }
00121 
00122 
00123 void LLDrawable::destroy()
00124 {
00125         if (isDead())
00126         {
00127                 sNumZombieDrawables--;
00128         }
00129 
00130         std::for_each(mFaces.begin(), mFaces.end(), DeletePointer());
00131         mFaces.clear();
00132                 
00133         
00134         /*if (!(sNumZombieDrawables % 10))
00135         {
00136                 llinfos << "- Zombie drawables: " << sNumZombieDrawables << llendl;
00137         }*/     
00138 }
00139 
00140 void LLDrawable::markDead()
00141 {
00142         if (isDead())
00143         {
00144                 llwarns << "Warning!  Marking dead multiple times!" << llendl;
00145                 return;
00146         }
00147 
00148         if (mSpatialBridge)
00149         {
00150                 mSpatialBridge->markDead();
00151                 mSpatialBridge = NULL;
00152         }
00153 
00154         sNumZombieDrawables++;
00155 
00156         // We're dead.  Free up all of our references to other objects
00157         setState(DEAD);
00158         cleanupReferences();
00159 //      sDeadList.put(this);
00160 }
00161 
00162 LLVOVolume* LLDrawable::getVOVolume() const
00163 {
00164         LLViewerObject* objectp = mVObjp;
00165         if ( !isDead() && objectp && (objectp->getPCode() == LL_PCODE_VOLUME))
00166         {
00167                 return ((LLVOVolume*)objectp);
00168         }
00169         else
00170         {
00171                 return NULL;
00172         }
00173 }
00174 
00175 BOOL LLDrawable::isLight() const
00176 {
00177         LLViewerObject* objectp = mVObjp;
00178         if ( objectp && (objectp->getPCode() == LL_PCODE_VOLUME) && !isDead())
00179         {
00180                 return ((LLVOVolume*)objectp)->getIsLight();
00181         }
00182         else
00183         {
00184                 return FALSE;
00185         }
00186 }
00187 
00188 void LLDrawable::clearLightSet()
00189 {
00190         // Remove this object from any object which has it as a light
00191         for (drawable_set_t::iterator iter = mLightSet.begin(); iter != mLightSet.end(); iter++)
00192         {
00193                 LLDrawable *targetp = *iter;
00194                 if (targetp != this && !targetp->isDead())
00195                 {
00196                         targetp->mLightSet.erase(this);
00197                         gPipeline.markRelight(targetp);
00198                 }
00199         }
00200         mLightSet.clear();
00201 }
00202 
00203 void LLDrawable::cleanupReferences()
00204 {
00205         LLFastTimer t(LLFastTimer::FTM_PIPELINE);
00206         
00207         std::for_each(mFaces.begin(), mFaces.end(), DeletePointer());
00208         mFaces.clear();
00209 
00210         clearLightSet();
00211 
00212         gObjectList.removeDrawable(this);
00213         
00214         mBlockSet.clear();
00215 
00216         gPipeline.unlinkDrawable(this);
00217         
00218         // Cleanup references to other objects
00219         mVObjp = NULL;
00220         mParent = NULL;
00221 }
00222 
00223 void LLDrawable::cleanupDeadDrawables()
00224 {
00225         /*
00226         S32 i;
00227         for (i = 0; i < sDeadList.count(); i++)
00228         {
00229                 if (sDeadList[i]->getNumRefs() > 1)
00230                 {
00231                         llwarns << "Dead drawable has " << sDeadList[i]->getNumRefs() << " remaining refs" << llendl;
00232                         gPipeline.findReferences(sDeadList[i]);
00233                 }
00234         }
00235         */
00236         sDeadList.reset();
00237 }
00238 
00239 S32 LLDrawable::findReferences(LLDrawable *drawablep)
00240 {
00241         S32 count = 0;
00242         if (mLightSet.count(drawablep) > 0)
00243         {
00244                 llinfos << this << ": lightset reference" << llendl;
00245                 count++;
00246         }
00247         if (mBlockSet.count(drawablep) > 0)
00248         {
00249                 llinfos << this << ": blockset reference" << llendl;
00250                 count++;
00251         }
00252         if (mParent == drawablep)
00253         {
00254                 llinfos << this << ": parent reference" << llendl;
00255                 count++;
00256         }
00257         return count;
00258 }
00259 
00260 #if 0
00261 // SJB: This is SLOW, so we don't want to allow it (we don't currently use it)
00262 void LLDrawable::removeFace(const S32 i)
00263 {
00264         LLFace *face= mFaces[i];
00265 
00266         if (face)
00267         {
00268                 mFaces.erase(mFaces.begin() + i);
00269                 delete face;
00270         }
00271 }
00272 #endif
00273 
00274 LLFace* LLDrawable::addFace(LLFacePool *poolp, LLViewerImage *texturep)
00275 {
00276         LLMemType mt(LLMemType::MTYPE_DRAWABLE);
00277         
00278         LLFace *face = new LLFace(this, mVObjp);
00279         if (!face) llerrs << "Allocating new Face: " << mFaces.size() << llendl;
00280         
00281         if (face)
00282         {
00283                 mFaces.push_back(face);
00284 
00285                 if (poolp)
00286                 {
00287                         face->setPool(poolp, texturep);
00288                 }
00289 
00290                 if (isState(UNLIT))
00291                 {
00292                         face->setState(LLFace::FULLBRIGHT);
00293                 }
00294         }
00295         return face;
00296 }
00297 
00298 LLFace* LLDrawable::addFace(const LLTextureEntry *te, LLViewerImage *texturep)
00299 {
00300         LLMemType mt(LLMemType::MTYPE_DRAWABLE);
00301         
00302         LLFace *face = new LLFace(this, mVObjp);
00303 
00304         face->setTEOffset(mFaces.size());
00305         face->setTexture(texturep);
00306         face->setPoolType(gPipeline.getPoolTypeFromTE(te, texturep));
00307         mFaces.push_back(face);
00308 
00309         if (isState(UNLIT))
00310         {
00311                 face->setState(LLFace::FULLBRIGHT);
00312         }
00313 
00314         return face;
00315 
00316 }
00317 
00318 void LLDrawable::setNumFaces(const S32 newFaces, LLFacePool *poolp, LLViewerImage *texturep)
00319 {
00320         if (newFaces == (S32)mFaces.size())
00321         {
00322                 return;
00323         }
00324         else if (newFaces < (S32)mFaces.size())
00325         {
00326                 std::for_each(mFaces.begin() + newFaces, mFaces.end(), DeletePointer());
00327                 mFaces.erase(mFaces.begin() + newFaces, mFaces.end());
00328         }
00329         else // (newFaces > mFaces.size())
00330         {
00331                 mFaces.reserve(newFaces);
00332                 for (int i = mFaces.size(); i<newFaces; i++)
00333                 {
00334                         addFace(poolp, texturep);
00335                 }
00336         }
00337 }
00338 
00339 void LLDrawable::setNumFacesFast(const S32 newFaces, LLFacePool *poolp, LLViewerImage *texturep)
00340 {
00341         if (newFaces <= (S32)mFaces.size() && newFaces >= (S32)mFaces.size()/2)
00342         {
00343                 return;
00344         }
00345         else if (newFaces < (S32)mFaces.size())
00346         {
00347                 std::for_each(mFaces.begin() + newFaces, mFaces.end(), DeletePointer());
00348                 mFaces.erase(mFaces.begin() + newFaces, mFaces.end());
00349         }
00350         else // (newFaces > mFaces.size())
00351         {
00352                 mFaces.reserve(newFaces);
00353                 for (int i = mFaces.size(); i<newFaces; i++)
00354                 {
00355                         addFace(poolp, texturep);
00356                 }
00357         }
00358 }
00359 
00360 void LLDrawable::mergeFaces(LLDrawable* src)
00361 {
00362         U32 face_count = mFaces.size() + src->mFaces.size();
00363 
00364         mFaces.reserve(face_count);
00365         for (U32 i = 0; i < src->mFaces.size(); i++)
00366         {
00367                 LLFace* facep = src->mFaces[i];
00368                 facep->setDrawable(this);
00369                 mFaces.push_back(facep);
00370         }
00371         src->mFaces.clear();
00372 }
00373 
00374 void LLDrawable::deleteFaces(S32 offset, S32 count)
00375 {
00376         face_list_t::iterator face_begin = mFaces.begin() + offset;
00377         face_list_t::iterator face_end = face_begin + count;
00378         std::for_each(face_begin, face_end, DeletePointer());
00379         mFaces.erase(face_begin, face_end);
00380 }
00381 
00382 void LLDrawable::update()
00383 {
00384         llerrs << "Shouldn't be called!" << llendl;
00385 }
00386 
00387 
00388 void LLDrawable::updateMaterial()
00389 {
00390 }
00391 
00392 void LLDrawable::makeActive()
00393 {               
00394 #if !LL_RELEASE_FOR_DOWNLOAD
00395         if (mVObjp.notNull())
00396         {
00397                 U32 pcode = mVObjp->getPCode();
00398                 if (pcode == LLViewerObject::LL_VO_WATER ||
00399                         pcode == LLViewerObject::LL_VO_SURFACE_PATCH ||
00400                         pcode == LLViewerObject::LL_VO_PART_GROUP ||
00401                         pcode == LLViewerObject::LL_VO_CLOUDS ||
00402                         pcode == LLViewerObject::LL_VO_STARS ||
00403                         pcode == LLViewerObject::LL_VO_GROUND ||
00404                         pcode == LLViewerObject::LL_VO_SKY)
00405                 {
00406                         llerrs << "Static viewer object has active drawable!" << llendl;
00407                 }
00408         }
00409 #endif
00410 
00411         if (!isState(ACTIVE)) // && mGeneration > 0)
00412         {
00413                 setState(ACTIVE);
00414                 
00415                 //parent must be made active first
00416                 if (!isRoot() && !mParent->isActive())
00417                 {
00418                         mParent->makeActive();
00419                 }
00420 
00421                 gPipeline.setActive(this, TRUE);
00422 
00423                 //all child objects must also be active
00424                 for (U32 i = 0; i < getChildCount(); i++)
00425                 {
00426                         LLDrawable* drawable = getChild(i);
00427                         if (drawable)
00428                         {
00429                                 drawable->makeActive();
00430                         }
00431                 }
00432                         
00433                 if (mVObjp->getPCode() == LL_PCODE_VOLUME)
00434                 {
00435                         if (mVObjp->getVolume()->getPathType() == LL_PCODE_PATH_FLEXIBLE)
00436                         {
00437                                 return;
00438                         }
00439                 }
00440         
00441                 clearState(LLDrawable::LIGHTING_BUILT);
00442                 if (mVObjp->getPCode() == LL_PCODE_VOLUME)
00443                 {
00444                         gPipeline.markRebuild(this, LLDrawable::REBUILD_VOLUME, TRUE);
00445                 }
00446         }
00447         updatePartition();
00448         if (isRoot())
00449         {
00450                 mQuietCount = 0;
00451         }
00452         else
00453         {
00454                 getParent()->mQuietCount = 0;
00455         }
00456 }
00457 
00458 
00459 void LLDrawable::makeStatic()
00460 {
00461         if (isState(ACTIVE))
00462         {
00463                 clearState(ACTIVE);
00464                 gPipeline.setActive(this, FALSE);
00465 
00466                 if (mParent.notNull() && mParent->isActive())
00467                 {
00468                         llwarns << "Drawable becamse static with active parent!" << llendl;
00469                 }
00470                 
00471                 S32 child_count = mVObjp->mChildList.size();
00472                 for (S32 child_num = 0; child_num < child_count; child_num++)
00473                 {
00474                         LLDrawable* child_drawable = mVObjp->mChildList[child_num]->mDrawable;
00475                         if (child_drawable)
00476                         {
00477                                 if (child_drawable->getParent() != this)
00478                                 {
00479                                         llwarns << "Child drawable has unknown parent." << llendl;
00480                                 }
00481                                 child_drawable->makeStatic();
00482                         }
00483                 }
00484                 
00485                 gPipeline.markRelight(this);
00486                 if (mVObjp->getPCode() == LL_PCODE_VOLUME)
00487                 {
00488                         gPipeline.markRebuild(this, LLDrawable::REBUILD_VOLUME, TRUE);
00489                 }               
00490                 
00491                 if (mSpatialBridge)
00492                 {
00493                         mSpatialBridge->markDead();
00494                         setSpatialBridge(NULL);
00495                 }
00496         }
00497         updatePartition();
00498 }
00499 
00500 // Returns "distance" between target destination and resulting xfrom
00501 F32 LLDrawable::updateXform(BOOL undamped)
00502 {
00503         BOOL damped = !undamped;
00504 
00505         // Position
00506         LLVector3 old_pos(mXform.getPosition());
00507         LLVector3 target_pos;
00508         if (mXform.isRoot())
00509         {
00510                 // get root position in your agent's region
00511                 target_pos = mVObjp->getPositionAgent();
00512         }
00513         else
00514         {
00515                 // parent-relative position
00516                 target_pos = mVObjp->getPosition();
00517         }
00518         
00519         // Rotation
00520         LLQuaternion old_rot(mXform.getRotation());
00521         LLQuaternion target_rot = mVObjp->getRotation();
00522         //scaling
00523         LLVector3 target_scale = mVObjp->getScale();
00524         LLVector3 old_scale = mCurrentScale;
00525         LLVector3 dest_scale = target_scale;
00526         
00527         // Damping
00528         F32 dist_squared = 0.f;
00529         F32 scaled = 0.f;
00530         
00531         if (damped && mDistanceWRTCamera > 0.0f)
00532         {
00533                 F32 lerp_amt = llclamp(LLCriticalDamp::getInterpolant(OBJECT_DAMPING_TIME_CONSTANT), 0.f, 1.f);
00534                 LLVector3 new_pos = lerp(old_pos, target_pos, lerp_amt);
00535                 dist_squared = dist_vec_squared(new_pos, target_pos);
00536 
00537                 LLQuaternion new_rot = nlerp(lerp_amt, old_rot, target_rot);
00538                 dist_squared += (1.f - dot(new_rot, target_rot)) * 10.f;
00539 
00540                 LLVector3 new_scale = lerp(old_scale, target_scale, lerp_amt);
00541                 scaled = dist_vec_squared(new_scale, target_scale);
00542 
00543                 dist_squared += scaled;
00544                 F32 camdist2 = (mDistanceWRTCamera * mDistanceWRTCamera);
00545                 if ((dist_squared >= MIN_INTERPOLATE_DISTANCE_SQUARED * camdist2) &&
00546                         (dist_squared <= MAX_INTERPOLATE_DISTANCE_SQUARED))
00547                 {
00548                         // interpolate
00549                         target_pos = new_pos;
00550                         target_rot = new_rot;
00551                         target_scale = new_scale;
00552                         
00553                         if (scaled >= MIN_INTERPOLATE_DISTANCE_SQUARED)
00554                         {               
00555                                 //scaling requires an immediate rebuild
00556                                 gPipeline.markRebuild(this, LLDrawable::REBUILD_POSITION, TRUE);
00557                         }
00558                 }
00559                 else
00560                 {
00561                         // snap to final position
00562                         dist_squared = 0.0f;
00563                 }
00564         }
00565                 
00566         // Update
00567         mXform.setPosition(target_pos);
00568         mXform.setRotation(target_rot);
00569         mXform.setScale(LLVector3(1,1,1)); //no scale in drawable transforms (IT'S A RULE!)
00570         mXform.updateMatrix();
00571         
00572         mCurrentScale = target_scale;
00573         
00574         return dist_squared;
00575 }
00576 
00577 void LLDrawable::setRadius(F32 radius)
00578 {
00579         if (mRadius != radius)
00580         {
00581                 mRadius = radius;
00582         }
00583 }
00584 
00585 void LLDrawable::moveUpdatePipeline(BOOL moved)
00586 {
00587         makeActive();
00588         
00589         // Update the face centers.
00590         for (S32 i = 0; i < getNumFaces(); i++)
00591         {
00592                 getFace(i)->updateCenterAgent();
00593         }
00594 
00595         if (moved || !isState(LLDrawable::BUILT)) // moved since last frame
00596         {
00597                 LLVector3 tmp = mSavePos - mXform.getPositionW();
00598                 F32 dist = tmp.magVecSquared(); // moved since last _update_
00599 
00600                 if (dist > 1.0f || !isState(LLDrawable::BUILT) || isLight())
00601                 {
00602                         mSavePos = mXform.getPositionW();
00603                         gPipeline.markRelight(this);
00604                 }
00605         }
00606 }
00607 
00608 void LLDrawable::movePartition()
00609 {
00610         LLSpatialPartition* part = getSpatialPartition();
00611         if (part)
00612         {
00613                 part->move(this, getSpatialGroup());
00614         }
00615 }
00616 
00617 BOOL LLDrawable::updateMove()
00618 {
00619         if (isDead())
00620         {
00621                 llwarns << "Update move on dead drawable!" << llendl;
00622                 return TRUE;
00623         }
00624         
00625         if (mVObjp.isNull())
00626         {
00627                 return FALSE;
00628         }
00629         
00630         makeActive();
00631         
00632         BOOL done;
00633 
00634         if (isState(MOVE_UNDAMPED))
00635         {
00636                 done = updateMoveUndamped();
00637         }
00638         else
00639         {
00640                 done = updateMoveDamped();
00641         }
00642         return done;
00643 }
00644 
00645 BOOL LLDrawable::updateMoveUndamped()
00646 {
00647         F32 dist_squared = updateXform(TRUE);
00648 
00649         mGeneration++;
00650 
00651         if (!isState(LLDrawable::INVISIBLE))
00652         {
00653                 BOOL moved = (dist_squared > 0.001f && dist_squared < 255.99f); 
00654                 moveUpdatePipeline(moved);
00655                 mVObjp->updateText();
00656         }
00657 
00658         mVObjp->clearChanged(LLXform::MOVED);
00659         
00660         return TRUE;
00661 }
00662 
00663 void LLDrawable::updatePartition()
00664 {
00665         if (!getVOVolume())
00666         {
00667                 movePartition();
00668         }
00669         else if (mSpatialBridge)
00670         {
00671                 gPipeline.markMoved(mSpatialBridge, FALSE);
00672         }
00673         else
00674         {
00675                 //a child prim moved and needs its verts regenerated
00676                 gPipeline.markRebuild(this, LLDrawable::REBUILD_POSITION, TRUE);
00677         }
00678 }
00679 
00680 BOOL LLDrawable::updateMoveDamped()
00681 {
00682         F32 dist_squared = updateXform(FALSE);
00683 
00684         mGeneration++;
00685 
00686         if (!isState(LLDrawable::INVISIBLE))
00687         {
00688                 BOOL moved = (dist_squared > 0.001f && dist_squared < 128.0f);
00689                 moveUpdatePipeline(moved);
00690                 mVObjp->updateText();
00691         }
00692 
00693         BOOL done_moving = (dist_squared == 0.0f) ? TRUE : FALSE;
00694 
00695         if (done_moving)
00696         {
00697                 mVObjp->clearChanged(LLXform::MOVED);
00698         }
00699         
00700         return done_moving;
00701 }
00702 
00703 void LLDrawable::updateDistance(LLCamera& camera)
00704 {
00705         //switch LOD with the spatial group to avoid artifacts
00706         LLSpatialGroup* sg = getSpatialGroup();
00707 
00708         LLVector3 pos;
00709 
00710         if (!sg || sg->changeLOD())
00711         {
00712                 LLVOVolume* volume = getVOVolume();
00713                 if (volume)
00714                 {
00715                         volume->updateRelativeXform();
00716                         pos = LLVector3(0,0,0) * volume->getRelativeXform();
00717 
00718                         for (S32 i = 0; i < getNumFaces(); i++)
00719                         {
00720                                 LLFace* facep = getFace(i);
00721                                 if (facep->getPoolType() == LLDrawPool::POOL_ALPHA)
00722                                 {
00723                                         LLVector3 box = (facep->mExtents[1] - facep->mExtents[0]) * 0.25f;
00724                                         LLVector3 v = (facep->mCenterLocal-camera.getOrigin());
00725                                         LLVector3 at = camera.getAtAxis();
00726                                         for (U32 j = 0; j < 3; j++)
00727                                         {
00728                                                 v.mV[j] -= box.mV[j] * at.mV[j];
00729                                         }
00730                                         facep->mDistance = v * camera.getAtAxis();
00731                                 }
00732                         }
00733                 }
00734                 else
00735                 {
00736                         pos = LLVector3(getPositionGroup());
00737                 }
00738 
00739                 pos -= camera.getOrigin();      
00740                 mDistanceWRTCamera = llround(pos.magVec(), 0.01f);
00741                 mVObjp->updateLOD();
00742         }
00743 }
00744 
00745 void LLDrawable::updateTexture()
00746 {
00747         LLMemType mt(LLMemType::MTYPE_DRAWABLE);
00748         
00749         if (isDead())
00750         {
00751                 llwarns << "Dead drawable updating texture!" << llendl;
00752                 return;
00753         }
00754         
00755         if (getNumFaces() != mVObjp->getNumTEs())
00756         { //drawable is transitioning its face count
00757                 return;
00758         }
00759 
00760         if (getVOVolume())
00761         {
00762                 if (!isActive())
00763                 {
00764                         gPipeline.markMoved(this);
00765                 }
00766                 else
00767                 {
00768                         if (isRoot())
00769                         {
00770                                 mQuietCount = 0;
00771                         }
00772                         else
00773                         {
00774                                 getParent()->mQuietCount = 0;
00775                         }
00776                 }
00777                                 
00778                 gPipeline.markRebuild(this, LLDrawable::REBUILD_MATERIAL, TRUE);
00779         }
00780 }
00781 
00782 BOOL LLDrawable::updateGeometry(BOOL priority)
00783 {
00784         llassert(mVObjp.notNull());
00785         BOOL res = mVObjp->updateGeometry(this);
00786         if (isState(REBUILD_LIGHTING))
00787         {
00788                 updateLighting(priority ? FALSE : TRUE); // only do actual lighting for non priority updates
00789                 if (priority)
00790                 {
00791                         gPipeline.markRelight(this); // schedule non priority update
00792                 }
00793                 else
00794                 {
00795                         clearState(REBUILD_LIGHTING);
00796                 }
00797         }
00798         return res;
00799 }
00800 
00801 void LLDrawable::shiftPos(const LLVector3 &shift_vector)
00802 {
00803         if (isDead())
00804         {
00805                 llwarns << "Shifting dead drawable" << llendl;
00806                 return;
00807         }
00808 
00809         if (mParent)
00810         {
00811                 mXform.setPosition(mVObjp->getPosition());
00812         }
00813         else
00814         {
00815                 mXform.setPosition(mVObjp->getPositionAgent());
00816         }
00817 
00818         mXform.setRotation(mVObjp->getRotation());
00819         mXform.setScale(1,1,1);
00820         mXform.updateMatrix();
00821 
00822         if (isStatic())
00823         {
00824                 gPipeline.markRebuild(this, LLDrawable::REBUILD_GEOMETRY, TRUE);
00825 
00826                 for (S32 i = 0; i < getNumFaces(); i++)
00827                 {
00828                         LLFace *facep = getFace(i);
00829                         facep->mCenterAgent += shift_vector;
00830                         facep->mExtents[0] += shift_vector;
00831                         facep->mExtents[1] += shift_vector;
00832                         
00833                         if (facep->hasGeometry())
00834                         {
00835                                 facep->mVertexBuffer = NULL;
00836                                 facep->mLastVertexBuffer = NULL;
00837                         }
00838                 }
00839                 
00840                 mExtents[0] += shift_vector;
00841                 mExtents[1] += shift_vector;
00842                 mPositionGroup += LLVector3d(shift_vector);
00843         }
00844         else if (mSpatialBridge)
00845         {
00846                 mSpatialBridge->shiftPos(shift_vector);
00847         }
00848         
00849         mSavePos = mXform.getPositionW();
00850 
00851         mVObjp->onShift(shift_vector);
00852 }
00853 
00854 const LLVector3& LLDrawable::getBounds(LLVector3& min, LLVector3& max) const
00855 {
00856         mXform.getMinMax(min,max);
00857         return mXform.getPositionW();
00858 }
00859 
00860 const LLVector3* LLDrawable::getSpatialExtents() const
00861 {
00862         return mExtents;
00863 }
00864 
00865 void LLDrawable::setSpatialExtents(LLVector3 min, LLVector3 max)
00866 { 
00867         LLVector3 size = max - min;
00868         mExtents[0] = min; 
00869         mExtents[1] = max; 
00870 }
00871 
00872 void LLDrawable::setPositionGroup(const LLVector3d& pos)
00873 {
00874         mPositionGroup.setVec(pos);
00875 }
00876 
00877 void LLDrawable::updateSpatialExtents()
00878 {
00879         if (mVObjp)
00880         {
00881                 mVObjp->updateSpatialExtents(mExtents[0], mExtents[1]);
00882         }
00883         
00884         updateBinRadius();
00885         
00886         if (mSpatialBridge.notNull())
00887         {
00888                 mPositionGroup.setVec(0,0,0);
00889         }
00890 }
00891 
00892 
00893 void LLDrawable::updateBinRadius()
00894 {
00895         if (mVObjp.notNull())
00896         {
00897                 mBinRadius = mVObjp->getBinRadius();
00898         }
00899         else
00900         {
00901                 mBinRadius = getRadius()*4.f;
00902         }
00903 }
00904 
00905 void LLDrawable::updateLightSet()
00906 {
00907         if (isDead())
00908         {
00909                 llwarns << "Updating light set for dead drawable!" << llendl;
00910                 return;
00911         }
00912 
00913         LLSpatialPartition* part = gPipeline.getSpatialPartition(LLPipeline::PARTITION_VOLUME);
00914         LLVOVolume* light = getVOVolume();
00915         if (isLight() && light)
00916         {
00917                 // mLightSet points to lit objects
00918                 for (drawable_set_t::iterator iter = mLightSet.begin(); iter != mLightSet.end(); iter++)
00919                 {
00920                         gPipeline.markRelight(*iter);
00921                 }
00922                 mLightSet.clear();
00923                 part->getObjects(getPositionAgent(), light->getLightRadius(), mLightSet);
00924                 for (drawable_set_t::iterator iter = mLightSet.begin(); iter != mLightSet.end(); iter++)
00925                 {
00926                         gPipeline.markRelight(*iter);
00927                 }
00928         }
00929         else
00930         {
00931                 // mLightSet points to nearby lights
00932                 mLightSet.clear();
00933                 part->getLights(getPositionAgent(), getRadius(), mLightSet);
00934                 const drawable_set_t::size_type MAX_LIGHTS = 16;
00935                 if (mLightSet.size() > MAX_LIGHTS)
00936                 {
00937                         typedef std::set<std::pair<F32,LLPointer<LLDrawable> > > sorted_pair_set_t;
00938                         sorted_pair_set_t sorted_set;
00939                         for (drawable_set_t::iterator iter = mLightSet.begin(); iter != mLightSet.end(); iter++)
00940                         {
00941                                 LLDrawable* drawable = *iter;
00942                                 LLVector3 dvec = drawable->getPositionAgent() - getPositionAgent();
00943                                 F32 dist2 = dvec.magVecSquared();
00944                                 sorted_set.insert(std::make_pair(dist2, drawable));
00945                         }
00946                         mLightSet.clear();
00947                         S32 count = 0;
00948                         for (sorted_pair_set_t::iterator iter = sorted_set.begin(); iter != sorted_set.end(); iter++)
00949                         {
00950                                 if (++count > 16)
00951                                         break;
00952                                 mLightSet.insert((*iter).second);
00953                         }
00954                 }
00955         }
00956 }
00957 
00958 void LLDrawable::updateSpecialHoverCursor(BOOL enabled)
00959 {
00960         // TODO: maintain a list of objects that have special
00961         // hover cursors, then use that list for per-frame
00962         // hover cursor selection. JC
00963 }
00964 
00965 BOOL LLDrawable::updateLighting(BOOL do_lighting)
00966 {
00967         if (do_lighting)
00968         {
00969                 if (gPipeline.getLightingDetail() >= 2 && (getLit() || isLight()))
00970                 {
00971                         LLFastTimer t(LLFastTimer::FTM_UPDATE_LIGHTS);
00972                         updateLightSet();
00973                         do_lighting = isLight() ? FALSE : TRUE;
00974                 }
00975                 else
00976                 {
00977                         do_lighting = FALSE;
00978                 }
00979         }
00980         if (gPipeline.getLightingDetail() >= 2)
00981         {
00982                 LLFastTimer t(LLFastTimer::FTM_GEO_LIGHT);
00983                 if (mVObjp->updateLighting(do_lighting))
00984                 {
00985                         setState(LIGHTING_BUILT);
00986                 }
00987         }
00988 
00989         return TRUE;
00990 }
00991 
00992 void LLDrawable::applyLightsAsPoint(LLColor4& result)
00993 {
00994         LLMemType mt1(LLMemType::MTYPE_DRAWABLE);
00995 
00996         LLVector3 point_agent(getPositionAgent());
00997         LLVector3 normal(-gCamera->getXAxis()); // make point agent face camera
00998         
00999         F32 sun_int = normal * gPipeline.mSunDir;
01000         LLColor4 color(gSky.getTotalAmbientColor());
01001         color += gPipeline.mSunDiffuse * sun_int;
01002         
01003         for (drawable_set_t::iterator iter = mLightSet.begin();
01004                  iter != mLightSet.end(); ++iter)
01005         {
01006                 LLDrawable* drawable = *iter;
01007                 LLVOVolume* light = drawable->getVOVolume();
01008                 if (!light)
01009                 {
01010                         continue;
01011                 }
01012                 LLColor4 light_color;
01013                 light->calcLightAtPoint(point_agent, normal, light_color);
01014                 color += light_color;
01015         }
01016         
01017         // Clamp the color...
01018         color.mV[0] = llmax(color.mV[0], 0.f);
01019         color.mV[1] = llmax(color.mV[1], 0.f);
01020         color.mV[2] = llmax(color.mV[2], 0.f);
01021 
01022         F32 max_color = llmax(color.mV[0], color.mV[1], color.mV[2]);
01023         if (max_color > 1.f)
01024         {
01025                 color *= 1.f/max_color;
01026         }
01027 
01028         result = color;
01029 }
01030 
01031 F32 LLDrawable::getVisibilityRadius() const
01032 {
01033         if (isDead())
01034         {
01035                 return 0.f;
01036         }
01037         else if (isLight())
01038         {
01039                 return llmax(getRadius(), getVOVolume()->getLightRadius());
01040         }
01041         else
01042         {
01043                 return getRadius();
01044         }
01045 }
01046 
01047 void LLDrawable::updateUVMinMax()
01048 {
01049 }
01050 
01051 void LLDrawable::setSpatialGroup(LLSpatialGroup *groupp)
01052 {
01053         if (mSpatialGroupp && (groupp != mSpatialGroupp))
01054         {
01055                 mSpatialGroupp->setState(LLSpatialGroup::GEOM_DIRTY);
01056         }
01057         mSpatialGroupp = groupp;
01058 }
01059 
01060 LLSpatialPartition* LLDrawable::getSpatialPartition()
01061 { 
01062         LLSpatialPartition* retval = NULL;
01063         
01064         if (!mVObjp || 
01065                 !getVOVolume() ||
01066                 isStatic())
01067         {
01068                 retval = gPipeline.getSpatialPartition((LLViewerObject*) mVObjp);
01069         }
01070         else if (isRoot())
01071         {       //must be an active volume
01072                 if (!mSpatialBridge)
01073                 {
01074                         if (mVObjp->isHUDAttachment())
01075                         {
01076                                 setSpatialBridge(new LLHUDBridge(this));
01077                         }
01078                         else
01079                         {
01080                                 setSpatialBridge(new LLVolumeBridge(this));
01081                         }
01082                 }
01083                 return mSpatialBridge->asPartition();
01084         }
01085         else 
01086         {
01087                 retval = getParent()->getSpatialPartition();
01088         }
01089         
01090         if (retval && mSpatialBridge.notNull())
01091         {
01092                 mSpatialBridge->markDead();
01093                 setSpatialBridge(NULL);
01094         }
01095         
01096         return retval;
01097 }
01098 
01099 
01100 BOOL LLDrawable::isVisible() const
01101 {
01102         if (mVisible == sCurVisible)
01103         {
01104                 return TRUE;
01105         }
01106         
01107         if (isActive())
01108         {
01109                 if (isRoot())
01110                 {
01111                         LLSpatialGroup* group = mSpatialBridge.notNull() ? mSpatialBridge->getSpatialGroup() :
01112                                                                         getSpatialGroup();
01113                         if (!group || group->isVisible())
01114                         {
01115                                 mVisible = sCurVisible;
01116                                 return TRUE;
01117                         }
01118                 }
01119                 else
01120                 {
01121                         if (getParent()->isVisible())
01122                         {
01123                                 mVisible = sCurVisible;
01124                                 return TRUE;
01125                         }
01126                 }
01127         }
01128         else
01129         {
01130                 LLSpatialGroup* group = getSpatialGroup();
01131                 if (!group || group->isVisible())
01132                 {
01133                         mVisible = sCurVisible;
01134                         return TRUE;
01135                 }
01136         }
01137 
01138         return FALSE;
01139 }
01140 
01141 //=======================================
01142 // Spatial Partition Bridging Drawable
01143 //=======================================
01144 
01145 LLSpatialBridge::LLSpatialBridge(LLDrawable* root, U32 data_mask)
01146 : LLSpatialPartition(data_mask, FALSE)
01147 {
01148         mDrawable = root;
01149         root->setSpatialBridge(this);
01150         
01151         mRenderType = mDrawable->mRenderType;
01152         mDrawableType = mDrawable->mRenderType;
01153         
01154         mPartitionType = LLPipeline::PARTITION_VOLUME;
01155         
01156         mOctree->balance();
01157         
01158         gPipeline.getSpatialPartition(mPartitionType)->put(this);
01159 }
01160 
01161 LLSpatialBridge::~LLSpatialBridge()
01162 {       
01163         if (getSpatialGroup())
01164         {
01165                 gPipeline.getSpatialPartition(mPartitionType)->remove(this, getSpatialGroup());
01166         }
01167 }
01168 
01169 void LLSpatialBridge::updateSpatialExtents()
01170 {
01171         LLSpatialGroup* root = (LLSpatialGroup*) mOctree->getListener(0);
01172         
01173         {
01174                 LLFastTimer ftm(LLFastTimer::FTM_CULL_REBOUND);
01175                 root->rebound();
01176         }
01177         
01178         LLXformMatrix* mat = mDrawable->getXform();
01179         
01180         LLVector3 offset = root->mBounds[0];
01181         LLVector3 size = root->mBounds[1];
01182                 
01183         LLVector3 center = LLVector3(0,0,0) * mat->getWorldMatrix();
01184         LLQuaternion rotation = LLQuaternion(mat->getWorldMatrix());
01185         
01186         offset *= rotation;
01187         center += offset;
01188         
01189         LLVector3 v[4];
01190         //get 4 corners of bounding box
01191         v[0] = (size * rotation);
01192         v[1] = (LLVector3(-size.mV[0], -size.mV[1], size.mV[2]) * rotation);
01193         v[2] = (LLVector3(size.mV[0], -size.mV[1], -size.mV[2]) * rotation);
01194         v[3] = (LLVector3(-size.mV[0], size.mV[1], -size.mV[2]) * rotation);
01195 
01196         LLVector3& newMin = mExtents[0];
01197         LLVector3& newMax = mExtents[1];
01198         
01199         newMin = newMax = center;
01200         
01201         for (U32 i = 0; i < 4; i++)
01202         {
01203                 for (U32 j = 0; j < 3; j++)
01204                 {
01205                         F32 delta = fabsf(v[i].mV[j]);
01206                         F32 min = center.mV[j] - delta;
01207                         F32 max = center.mV[j] + delta;
01208                         
01209                         if (min < newMin.mV[j])
01210                         {
01211                                 newMin.mV[j] = min;
01212                         }
01213                         
01214                         if (max > newMax.mV[j])
01215                         {
01216                                 newMax.mV[j] = max;
01217                         }
01218                 }
01219         }
01220 
01221         LLVector3 diagonal = newMax - newMin;
01222         mRadius = diagonal.magVec() * 0.5f;
01223         
01224         mPositionGroup.setVec((newMin + newMax) * 0.5f);
01225         updateBinRadius();
01226 }
01227 
01228 void LLSpatialBridge::updateBinRadius()
01229 {
01230         mBinRadius = llmin((F32) mOctree->getSize().mdV[0]*0.5f, 256.f);
01231 }
01232 
01233 LLCamera LLSpatialBridge::transformCamera(LLCamera& camera)
01234 {
01235         LLCamera ret = camera;
01236         LLXformMatrix* mat = mDrawable->getXform();
01237         LLVector3 center = LLVector3(0,0,0) * mat->getWorldMatrix();
01238         LLQuaternion rotation = LLQuaternion(mat->getWorldMatrix());
01239 
01240         LLVector3 delta = ret.getOrigin() - center;
01241         LLQuaternion rot = ~mat->getRotation();
01242 
01243         delta *= rot;
01244         LLVector3 lookAt = ret.getAtAxis();
01245         LLVector3 up_axis = ret.getUpAxis();
01246         LLVector3 left_axis = ret.getLeftAxis();
01247 
01248         lookAt *= rot;
01249         up_axis *= rot;
01250         left_axis *= rot;
01251 
01252         ret.setOrigin(delta);
01253         ret.setAxes(lookAt, left_axis, up_axis);
01254                 
01255         return ret;
01256 }
01257 
01258 void LLDrawable::setVisible(LLCamera& camera, std::vector<LLDrawable*>* results, BOOL for_select)
01259 {
01260         mVisible = sCurVisible;
01261         
01262 #if 0 && !LL_RELEASE_FOR_DOWNLOAD
01263         //crazy paranoid rules checking
01264         if (getVOVolume())
01265         {
01266                 if (!isRoot())
01267                 {
01268                         if (isActive() && !mParent->isActive())
01269                         {
01270                                 llerrs << "Active drawable has static parent!" << llendl;
01271                         }
01272                         
01273                         if (isStatic() && !mParent->isStatic())
01274                         {
01275                                 llerrs << "Static drawable has active parent!" << llendl;
01276                         }
01277                         
01278                         if (mSpatialBridge)
01279                         {
01280                                 llerrs << "Child drawable has spatial bridge!" << llendl;
01281                         }
01282                 }
01283                 else if (isActive() && !mSpatialBridge)
01284                 {
01285                         llerrs << "Active root drawable has no spatial bridge!" << llendl;
01286                 }
01287                 else if (isStatic() && mSpatialBridge.notNull())
01288                 {
01289                         llerrs << "Static drawable has spatial bridge!" << llendl;
01290                 }
01291         }
01292 #endif
01293 }
01294 
01295 class LLOctreeMarkNotCulled: public LLOctreeTraveler<LLDrawable>
01296 {
01297 public:
01298         LLCamera* mCamera;
01299         
01300         LLOctreeMarkNotCulled(LLCamera* camera_in) : mCamera(camera_in) { }
01301         
01302         virtual void traverse(const LLOctreeNode<LLDrawable>* node)
01303         {
01304                 LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
01305                 group->clearState(LLSpatialGroup::OCCLUDED | LLSpatialGroup::CULLED);
01306                 LLOctreeTraveler<LLDrawable>::traverse(node);
01307         }
01308         
01309         void visit(const LLOctreeState<LLDrawable>* branch)
01310         {
01311                 gPipeline.markNotCulled((LLSpatialGroup*) branch->getListener(0), *mCamera, TRUE);
01312         }
01313 };
01314 
01315 void LLSpatialBridge::setVisible(LLCamera& camera_in, std::vector<LLDrawable*>* results, BOOL for_select)
01316 {
01317         if (!gPipeline.hasRenderType(mDrawableType))
01318         {
01319                 return;
01320         }
01321 
01322         LLViewerObject *vobj = mDrawable->getVObj();
01323         if (vobj && vobj->isAttachment() && !vobj->isHUDAttachment())
01324         {
01325                 LLVOAvatar* av;
01326                 LLDrawable* parent = mDrawable->getParent();
01327 
01328                 if (parent)
01329                 {
01330                         av = (LLVOAvatar*) parent->getVObj().get();
01331                 
01332                         if (!av->isVisible())
01333                         {
01334                                 return;
01335                         }
01336                 }
01337         }
01338         
01339 
01340         LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0);
01341         group->rebound();
01342         
01343         LLVector3 center = (mExtents[0] + mExtents[1]) * 0.5f;
01344         LLVector3 size = (mExtents[1]-mExtents[0]) * 0.5f;
01345 
01346         if (camera_in.AABBInFrustum(center, size))
01347         {
01348                 if (LLPipeline::calcPixelArea(center, size, camera_in) < FORCE_INVISIBLE_AREA)
01349                 {
01350                         return;
01351                 }
01352 
01353                 LLDrawable::setVisible(camera_in);
01354                 
01355                 if (for_select)
01356                 {
01357                         results->push_back(mDrawable);
01358                         for (U32 i = 0; i < mDrawable->getChildCount(); i++)
01359                         {
01360                                 results->push_back(mDrawable->getChild(i));
01361                         }
01362                 }
01363                 else 
01364                 {
01365                         LLCamera trans_camera = transformCamera(camera_in);
01366                         LLOctreeMarkNotCulled culler(&trans_camera);
01367                         culler.traverse(mOctree);
01368                 }               
01369         }
01370 }
01371 
01372 void LLSpatialBridge::updateDistance(LLCamera& camera_in)
01373 {
01374         if (mDrawable == NULL)
01375         {
01376                 markDead();
01377                 return;
01378         }
01379 
01380         LLCamera camera = transformCamera(camera_in);
01381         
01382         mDrawable->updateDistance(camera);
01383         
01384         for (U32 i = 0; i < mDrawable->getChildCount(); ++i)
01385         {
01386                 LLDrawable* child = mDrawable->getChild(i);
01387                 if (!child)
01388                 {
01389                         llwarns << "Corrupt drawable found while updating spatial bridge distance." << llendl;
01390                         continue;
01391                 }
01392                 child->updateDistance(camera);
01393         }
01394 }
01395 
01396 void LLSpatialBridge::makeActive()
01397 { //it is an error to make a spatial bridge active (it's already active)
01398         llerrs << "makeActive called on spatial bridge" << llendl;
01399 }
01400 
01401 void LLSpatialBridge::makeStatic()
01402 {
01403         llerrs << "makeStatic called on spatial bridge" << llendl;
01404 }
01405 
01406 void LLSpatialBridge::move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL immediate)
01407 {
01408         LLSpatialPartition::move(drawablep, curp, immediate);
01409         gPipeline.markMoved(this, FALSE);
01410 }
01411 
01412 BOOL LLSpatialBridge::updateMove()
01413 {
01414         mOctree->balance();
01415         gPipeline.getSpatialPartition(mPartitionType)->move(this, getSpatialGroup(), TRUE);
01416         return TRUE;
01417 }
01418 
01419 void LLSpatialBridge::shiftPos(const LLVector3& vec)
01420 {
01421         mExtents[0] += vec;
01422         mExtents[1] += vec;
01423         mPositionGroup += LLVector3d(vec);
01424 }
01425 
01426 void LLSpatialBridge::cleanupReferences()
01427 {       
01428         LLDrawable::cleanupReferences();
01429         if (mDrawable)
01430         {
01431                 mDrawable->setSpatialGroup(NULL);
01432                 for (U32 i = 0; i < mDrawable->getChildCount(); i++)
01433                 {
01434                         LLDrawable* drawable = mDrawable->getChild(i);
01435                         if (drawable)
01436                         {
01437                                 drawable->setSpatialGroup(NULL);
01438                         }
01439                 }
01440 
01441                 LLDrawable* drawablep = mDrawable;
01442                 mDrawable = NULL;
01443                 drawablep->setSpatialBridge(NULL);
01444         }
01445 }
01446 
01447 const LLVector3 LLDrawable::getPositionAgent() const
01448 {
01449         if (getVOVolume())
01450         {
01451                 if (isActive())
01452                 {
01453                         if (isRoot())
01454                         {
01455                                 return LLVector3(0,0,0) * getWorldMatrix();
01456                         }
01457                         else
01458                         {
01459                                 return mVObjp->getPosition() * getParent()->getWorldMatrix();
01460                         }
01461                 }
01462                 else
01463                 {
01464                         return mVObjp->getPositionAgent();
01465                 }
01466         }
01467         else
01468         {
01469                 return getWorldPosition();
01470         }
01471 }
01472 
01473 BOOL LLDrawable::isAnimating() const
01474 {
01475         if (!getVObj())
01476         {
01477                 return TRUE;
01478         }
01479 
01480         if (getScale() != mVObjp->getScale())
01481         {
01482                 return TRUE;
01483         }
01484 
01485         if (mVObjp->isFlexible())
01486         {
01487                 return TRUE;
01488         }
01489 
01490         if (mVObjp->getPCode() == LLViewerObject::LL_VO_PART_GROUP)
01491         {
01492                 return TRUE;
01493         }
01494 
01495         if (mVObjp->getPCode() == LLViewerObject::LL_VO_CLOUDS)
01496         {
01497                 return TRUE;
01498         }
01499 
01500         LLVOVolume* vol = getVOVolume();
01501         if (vol && vol->mTextureAnimp)
01502         {
01503                 return TRUE;
01504         }
01505 
01506         if (!isRoot() && !mVObjp->getAngularVelocity().isExactlyZero())
01507         {
01508                 return TRUE;
01509         }
01510 
01511         return FALSE;
01512 }
01513 
01514 void LLDrawable::updateFaceSize(S32 idx)
01515 {
01516         if (mVObjp.notNull())
01517         {
01518                 mVObjp->updateFaceSize(idx);
01519         }
01520 }
01521 
01522 LLBridgePartition::LLBridgePartition()
01523 : LLSpatialPartition(0, TRUE) 
01524 { 
01525         mRenderByGroup = FALSE; 
01526         mDrawableType = LLPipeline::RENDER_TYPE_AVATAR; 
01527         mPartitionType = LLPipeline::PARTITION_BRIDGE;
01528         mLODPeriod = 1;
01529         mSlopRatio = 0.f;
01530 }
01531 
01532 LLHUDBridge::LLHUDBridge(LLDrawable* drawablep)
01533 : LLVolumeBridge(drawablep)
01534 {
01535         mDrawableType = LLPipeline::RENDER_TYPE_HUD;
01536         mPartitionType = LLPipeline::PARTITION_HUD;
01537         mSlopRatio = 0.0f;
01538 }
01539 
01540 F32 LLHUDBridge::calcPixelArea(LLSpatialGroup* group, LLCamera& camera)
01541 {
01542         return 1024.f;
01543 }
01544 
01545 
01546 void LLHUDBridge::shiftPos(const LLVector3& vec)
01547 {
01548         //don't shift hud bridges on region crossing
01549 }
01550 

Generated on Thu Jul 1 06:08:25 2010 for Second Life Viewer by  doxygen 1.4.7