aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/lldrawable.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/newview/lldrawable.cpp
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/newview/lldrawable.cpp')
-rw-r--r--linden/indra/newview/lldrawable.cpp1340
1 files changed, 1340 insertions, 0 deletions
diff --git a/linden/indra/newview/lldrawable.cpp b/linden/indra/newview/lldrawable.cpp
new file mode 100644
index 0000000..af4f205
--- /dev/null
+++ b/linden/indra/newview/lldrawable.cpp
@@ -0,0 +1,1340 @@
1/**
2 * @file lldrawable.cpp
3 * @brief LLDrawable class implementation
4 *
5 * Copyright (c) 2002-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "llviewerprecompiledheaders.h"
29
30#include "lldrawable.h"
31
32// library includes
33#include "material_codes.h"
34
35// viewer includes
36#include "llagparray.h"
37#include "llagparray.inl"
38#include "llcriticaldamp.h"
39#include "llface.h"
40#include "lllightconstants.h"
41#include "llsky.h"
42#include "llsurfacepatch.h"
43#include "llviewercamera.h"
44#include "llviewerregion.h"
45#include "llvolume.h"
46#include "llvoavatar.h"
47#include "llvovolume.h"
48#include "llvosurfacepatch.h" // for debugging
49#include "llworld.h"
50#include "pipeline.h"
51#include "llspatialpartition.h"
52#include "llviewerobjectlist.h"
53#include "llviewerwindow.h"
54
55const F32 MIN_INTERPOLATE_DISTANCE_SQUARED = 0.001f * 0.001f;
56const F32 MAX_INTERPOLATE_DISTANCE_SQUARED = 10.f * 10.f;
57const F32 OBJECT_DAMPING_TIME_CONSTANT = 0.06f;
58const F32 MIN_SHADOW_CASTER_RADIUS = 2.0f;
59
60////////////////////////
61//
62// Inline implementations.
63//
64//
65
66
67
68//////////////////////////////
69//
70// Drawable code
71//
72//
73
74// static
75U32 LLDrawable::sCurVisible = 0;
76U32 LLDrawable::sNumZombieDrawables = 0;
77F32 LLDrawable::sCurPixelAngle = 0;
78LLDynamicArrayPtr<LLPointer<LLDrawable> > LLDrawable::sDeadList;
79
80// static
81void LLDrawable::incrementVisible()
82{
83 sCurVisible++;
84 sCurPixelAngle = (F32) gViewerWindow->getWindowDisplayHeight()/gCamera->getView();
85}
86void LLDrawable::init()
87{
88 // mXform
89 mParent = NULL;
90 mRenderType = 0;
91 mCurrentScale = LLVector3(1,1,1);
92 mDistanceWRTCamera = 0.0f;
93 // mUVRect
94 mUVZ = 0.f;
95 // mLightSet
96 // mBlockSet
97 // mSavePos
98 mQuietCount = 0;
99
100 mState = 0;
101 mVObjp = NULL;
102 // mFaces
103 mSpatialGroupp = NULL;
104 mSpatialGroupOffset = -1;
105 mVisible = 0;
106 mRadius = 0.f;
107 mSunShadowFactor = 1.f;
108
109 mGeneration = -1;
110 mBinRadius = 1.f;
111 mSpatialBridge = NULL;
112}
113
114// static
115void LLDrawable::initClass()
116{
117}
118
119
120void LLDrawable::destroy()
121{
122 if (isDead())
123 {
124 sNumZombieDrawables--;
125 }
126
127 std::for_each(mFaces.begin(), mFaces.end(), DeletePointer());
128 mFaces.clear();
129
130 /*
131 if (!(sNumZombieDrawables % 10))
132 {
133 llinfos << "- Zombie drawables: " << sNumZombieDrawables << llendl;
134 }
135 */
136}
137
138void LLDrawable::markDead()
139{
140 if (isDead())
141 {
142 llwarns << "Warning! Marking dead multiple times!" << llendl;
143 return;
144 }
145
146 if (mSpatialBridge)
147 {
148 mSpatialBridge->markDead();
149 mSpatialBridge = NULL;
150 }
151
152 sNumZombieDrawables++;
153
154 // We're dead. Free up all of our references to other objects
155 setState(DEAD);
156 cleanupReferences();
157// sDeadList.put(this);
158}
159
160LLVOVolume* LLDrawable::getVOVolume() const
161{
162 LLViewerObject* objectp = mVObjp;
163 if ( !isDead() && objectp && (objectp->getPCode() == LL_PCODE_VOLUME))
164 {
165 return ((LLVOVolume*)objectp);
166 }
167 else
168 {
169 return NULL;
170 }
171}
172
173BOOL LLDrawable::isLight() const
174{
175 LLViewerObject* objectp = mVObjp;
176 if ( objectp && (objectp->getPCode() == LL_PCODE_VOLUME) && !isDead())
177 {
178 return ((LLVOVolume*)objectp)->getIsLight();
179 }
180 else
181 {
182 return FALSE;
183 }
184}
185
186void LLDrawable::clearLightSet()
187{
188 // Remove this object from any object which has it as a light
189 for (drawable_set_t::iterator iter = mLightSet.begin(); iter != mLightSet.end(); iter++)
190 {
191 LLDrawable *targetp = *iter;
192 if (targetp != this && !targetp->isDead())
193 {
194 targetp->mLightSet.erase(this);
195 gPipeline.markRelight(targetp);
196 }
197 }
198 mLightSet.clear();
199}
200
201void LLDrawable::cleanupReferences()
202{
203 LLFastTimer t(LLFastTimer::FTM_PIPELINE);
204
205 std::for_each(mFaces.begin(), mFaces.end(), DeletePointer());
206 mFaces.clear();
207
208 clearLightSet();
209
210 gObjectList.removeDrawable(this);
211
212 mBlockSet.clear();
213
214 gPipeline.unlinkDrawable(this);
215
216 // Cleanup references to other objects
217 mVObjp = NULL;
218 mParent = NULL;
219}
220
221void LLDrawable::cleanupDeadDrawables()
222{
223 /*
224 S32 i;
225 for (i = 0; i < sDeadList.count(); i++)
226 {
227 if (sDeadList[i]->getNumRefs() > 1)
228 {
229 llwarns << "Dead drawable has " << sDeadList[i]->getNumRefs() << " remaining refs" << llendl;
230 gPipeline.findReferences(sDeadList[i]);
231 }
232 }
233 */
234 sDeadList.reset();
235}
236
237S32 LLDrawable::findReferences(LLDrawable *drawablep)
238{
239 S32 count = 0;
240 if (mLightSet.count(drawablep) > 0)
241 {
242 llinfos << this << ": lightset reference" << llendl;
243 count++;
244 }
245 if (mBlockSet.count(drawablep) > 0)
246 {
247 llinfos << this << ": blockset reference" << llendl;
248 count++;
249 }
250 if (mParent == drawablep)
251 {
252 llinfos << this << ": parent reference" << llendl;
253 count++;
254 }
255 return count;
256}
257
258#if 0
259// SJB: This is SLOW, so we don't want to allow it (we don't currently use it)
260void LLDrawable::removeFace(const S32 i)
261{
262 LLFace *face= mFaces[i];
263
264 if (face)
265 {
266 mFaces.erase(mFaces.begin() + i);
267 delete face;
268 }
269}
270#endif
271
272LLFace* LLDrawable::addFace(LLDrawPool *poolp, LLViewerImage *texturep, const BOOL shared_geom)
273{
274 LLMemType mt(LLMemType::MTYPE_DRAWABLE);
275
276 LLFace *face = new LLFace(this, mVObjp);
277
278 if (face)
279 {
280 mFaces.push_back(face);
281 face->setPool(poolp, texturep);
282
283 if (shared_geom)
284 {
285 face->setState(LLFace::SHARED_GEOM);
286 }
287 else if (!isVisible())
288 {
289 face->setState(LLFace::BACKLIST);
290 }
291 if (isState(UNLIT))
292 {
293 face->setState(LLFace::FULLBRIGHT);
294 }
295 }
296 return face;
297}
298
299void LLDrawable::setNumFaces(const S32 newFaces, LLDrawPool *poolp, LLViewerImage *texturep)
300{
301 if (newFaces == (S32)mFaces.size())
302 {
303 return;
304 }
305 else if (newFaces < (S32)mFaces.size())
306 {
307 std::for_each(mFaces.begin() + newFaces, mFaces.end(), DeletePointer());
308 mFaces.erase(mFaces.begin() + newFaces, mFaces.end());
309 }
310 else // (newFaces > mFaces.size())
311 {
312 mFaces.reserve(newFaces);
313 for (int i = mFaces.size(); i<newFaces; i++)
314 {
315 addFace(poolp, texturep);
316 }
317 }
318}
319
320void LLDrawable::setNumFacesFast(const S32 newFaces, LLDrawPool *poolp, LLViewerImage *texturep)
321{
322 if (newFaces <= (S32)mFaces.size() && newFaces >= (S32)mFaces.size()/2)
323 {
324 return;
325 }
326 else if (newFaces < (S32)mFaces.size())
327 {
328 std::for_each(mFaces.begin() + newFaces, mFaces.end(), DeletePointer());
329 mFaces.erase(mFaces.begin() + newFaces, mFaces.end());
330 }
331 else // (newFaces > mFaces.size())
332 {
333 mFaces.reserve(newFaces);
334 for (int i = mFaces.size(); i<newFaces; i++)
335 {
336 addFace(poolp, texturep);
337 }
338 }
339}
340
341void LLDrawable::mergeFaces(LLDrawable* src)
342{
343 U32 face_count = mFaces.size() + src->mFaces.size();
344
345 mFaces.reserve(face_count);
346 for (U32 i = 0; i < src->mFaces.size(); i++)
347 {
348 LLFace* facep = src->mFaces[i];
349 facep->setDrawable(this);
350 mFaces.push_back(facep);
351 }
352 src->mFaces.clear();
353}
354
355void LLDrawable::deleteFaces(S32 offset, S32 count)
356{
357 face_list_t::iterator face_begin = mFaces.begin() + offset;
358 face_list_t::iterator face_end = face_begin + count;
359 std::for_each(face_begin, face_end, DeletePointer());
360 mFaces.erase(face_begin, face_end);
361}
362
363void LLDrawable::update()
364{
365 llerrs << "Shouldn't be called!" << llendl;
366}
367
368
369void LLDrawable::updateMaterial()
370{
371}
372
373void LLDrawable::makeActive()
374{
375 if (!isState(ACTIVE)) // && mGeneration > 0)
376 {
377 setState(ACTIVE);
378
379 if (!isRoot() && !mParent->isActive())
380 {
381 mParent->makeActive();
382 }
383
384 gPipeline.setActive(this, TRUE);
385
386 //all child objects must also be active
387 for (U32 i = 0; i < getChildCount(); i++)
388 {
389 getChild(i)->makeActive();
390 }
391
392 if (mVObjp->getPCode() == LL_PCODE_VOLUME)
393 {
394 if (mVObjp->getVolume()->getPathType() == LL_PCODE_PATH_FLEXIBLE)
395 {
396 return;
397 }
398 }
399
400 clearState(LLDrawable::LIGHTING_BUILT);
401 if (mVObjp->getPCode() == LL_PCODE_VOLUME)
402 {
403 gPipeline.markRebuild(this, LLDrawable::REBUILD_VOLUME, TRUE);
404 }
405 }
406 mQuietCount = 0;
407}
408
409
410void LLDrawable::makeStatic()
411{
412 if (isState(ACTIVE))
413 {
414 clearState(ACTIVE);
415 gPipeline.setActive(this, FALSE);
416
417 if (mParent.notNull() && mParent->isActive())
418 {
419 llerrs << "Drawable became static with active parent!" << llendl;
420 }
421
422 S32 child_count = mVObjp->mChildList.size();
423 for (S32 child_num = 0; child_num < child_count; child_num++)
424 {
425 LLDrawable* child_drawable = mVObjp->mChildList[child_num]->mDrawable;
426 if (child_drawable)
427 {
428 child_drawable->makeStatic();
429 }
430 }
431
432 gPipeline.markRelight(this);
433 if (mVObjp->getPCode() == LL_PCODE_VOLUME)
434 {
435 gPipeline.markRebuild(this, LLDrawable::REBUILD_VOLUME, TRUE);
436 }
437
438 if (mSpatialBridge)
439 {
440 mSpatialBridge->markDead();
441 setSpatialBridge(NULL);
442 }
443 }
444}
445
446// Returns "distance" between target destination and resulting xfrom
447F32 LLDrawable::updateXform(BOOL undamped)
448{
449 BOOL damped = !undamped;
450
451 // Position
452 LLVector3 old_pos(mXform.getPosition());
453 LLVector3 target_pos;
454 if (mXform.isRoot())
455 {
456 // get root position in your agent's region
457 target_pos = mVObjp->getPositionAgent();
458 }
459 else
460 {
461 // parent-relative position
462 target_pos = mVObjp->getPosition();
463 }
464
465 // Rotation
466 LLQuaternion old_rot(mXform.getRotation());
467 LLQuaternion target_rot = mVObjp->getRotation();
468 //scaling
469 LLVector3 target_scale = mVObjp->getScale();
470 LLVector3 old_scale = mCurrentScale;
471 LLVector3 dest_scale = target_scale;
472
473 // Damping
474 F32 dist_squared = 0.f;
475 F32 scaled = 0.f;
476
477 if (damped && mDistanceWRTCamera > 0.0f)
478 {
479 F32 lerp_amt = llclamp(LLCriticalDamp::getInterpolant(OBJECT_DAMPING_TIME_CONSTANT), 0.f, 1.f);
480 LLVector3 new_pos = lerp(old_pos, target_pos, lerp_amt);
481 dist_squared = dist_vec_squared(new_pos, target_pos);
482
483 LLQuaternion new_rot = nlerp(lerp_amt, old_rot, target_rot);
484 dist_squared += (1.f - dot(new_rot, target_rot)) * 10.f;
485
486 LLVector3 new_scale = lerp(old_scale, target_scale, lerp_amt);
487 scaled = dist_vec_squared(new_scale, target_scale);
488
489 dist_squared += scaled;
490 F32 camdist2 = (mDistanceWRTCamera * mDistanceWRTCamera);
491 if ((dist_squared >= MIN_INTERPOLATE_DISTANCE_SQUARED * camdist2) &&
492 (dist_squared <= MAX_INTERPOLATE_DISTANCE_SQUARED))
493 {
494 // interpolate
495 target_pos = new_pos;
496 target_rot = new_rot;
497 target_scale = new_scale;
498
499 if (scaled >= MIN_INTERPOLATE_DISTANCE_SQUARED)
500 {
501 //scaling requires an immediate rebuild
502 gPipeline.markRebuild(this, LLDrawable::REBUILD_VOLUME, TRUE);
503 }
504
505 }
506 else
507 {
508 // snap to final position
509 dist_squared = 0.0f;
510 }
511 }
512
513 // Update
514 mXform.setPosition(target_pos);
515 mXform.setRotation(target_rot);
516 mXform.setScale(LLVector3(1,1,1)); //no scale in drawable transforms (IT'S A RULE!)
517 mXform.updateMatrix();
518
519 mCurrentScale = target_scale;
520
521 if (!getVOVolume())
522 {
523 movePartition();
524 }
525 else if (mSpatialBridge)
526 {
527 gPipeline.markMoved(mSpatialBridge, FALSE);
528 }
529 else
530 {
531 //a child prim moved and needs its verts regenerated
532 gPipeline.markRebuild(this, LLDrawable::REBUILD_VOLUME, TRUE);
533 }
534
535 return dist_squared;
536}
537
538void LLDrawable::setRadius(F32 radius)
539{
540 if (mRadius != radius)
541 {
542 mRadius = radius;
543 updateBinRadius();
544 if (!getVOVolume())
545 {
546 movePartition();
547 }
548 }
549}
550
551void LLDrawable::moveUpdatePipeline(BOOL moved)
552{
553 makeActive();
554
555 // Update the face centers.
556 for (S32 i = 0; i < getNumFaces(); i++)
557 {
558 getFace(i)->updateCenterAgent();
559 }
560
561 if (moved || !isState(LLDrawable::BUILT)) // moved since last frame
562 {
563 LLVector3 tmp = mSavePos - mXform.getPositionW();
564 F32 dist = tmp.magVecSquared(); // moved since last _update_
565
566 if (dist > 1.0f || !isState(LLDrawable::BUILT) || isLight())
567 {
568 mSavePos = mXform.getPositionW();
569 gPipeline.markRelight(this);
570 }
571 }
572}
573
574void LLDrawable::movePartition()
575{
576 if (getSpatialGroup() || getVOVolume())
577 {
578 LLSpatialPartition* part = getSpatialPartition();
579 if (part)
580 {
581 part->move(this, getSpatialGroup());
582 }
583 }
584}
585
586BOOL LLDrawable::updateMove()
587{
588 if (isDead())
589 {
590 llwarns << "Update move on dead drawable!" << llendl;
591 return TRUE;
592 }
593
594 if (mVObjp.isNull())
595 {
596 return FALSE;
597 }
598
599 makeActive();
600
601 BOOL done;
602
603 if (isState(MOVE_UNDAMPED))
604 {
605 done = updateMoveUndamped();
606 }
607 else
608 {
609 done = updateMoveDamped();
610 }
611 return done;
612}
613
614BOOL LLDrawable::updateMoveUndamped()
615{
616 F32 dist_squared = updateXform(TRUE);
617
618 mGeneration++;
619
620 if (!isState(LLDrawable::INVISIBLE))
621 {
622 BOOL moved = (dist_squared > 0.001f && dist_squared < 255.99f);
623 moveUpdatePipeline(moved);
624 mVObjp->updateText();
625 }
626
627 mVObjp->clearChanged(LLXform::MOVED);
628
629 return TRUE;
630}
631
632BOOL LLDrawable::updateMoveDamped()
633{
634 F32 dist_squared = updateXform(FALSE);
635
636 mGeneration++;
637
638 if (!isState(LLDrawable::INVISIBLE))
639 {
640 BOOL moved = (dist_squared > 0.001f && dist_squared < 128.0f);
641 moveUpdatePipeline(moved);
642 mVObjp->updateText();
643 }
644
645 BOOL done_moving = (dist_squared == 0.0f) ? TRUE : FALSE;
646
647 if (done_moving)
648 {
649 mVObjp->clearChanged(LLXform::MOVED);
650 }
651
652 return done_moving;
653}
654
655void LLDrawable::updateDistance(LLCamera& camera)
656{
657 if (mVObjp->isHUDAttachment())
658 {
659 mDistanceWRTCamera = 1.0f;
660 if (sCurVisible % 16 == 0)
661 {
662 mVObjp->updateLOD();
663 }
664 return;
665 }
666
667 LLVector3 pos(getPositionGroup());
668
669 pos -= camera.getOrigin();
670 mDistanceWRTCamera = pos.magVec();
671
672 //switch LOD with the spatial group to avoid artifacts
673 LLSpatialGroup* sg = getSpatialGroup();
674 if (!sg || sg->changeLOD())
675 {
676 mVObjp->updateLOD();
677 }
678}
679
680void LLDrawable::updateTexture()
681{
682 LLMemType mt(LLMemType::MTYPE_DRAWABLE);
683
684 if (isDead())
685 {
686 llwarns << "Dead drawable updating texture!" << llendl;
687 return;
688 }
689
690 // *FIX: this updates textures on all faces in this drawable, not
691 // just the viewer object we care about
692 if (mVObjp->getNumTEs())
693 {
694 // For each face in this drawable, change the drawpool if necessary.
695 for (S32 i = 0; i < getNumFaces(); i++)
696 {
697 LLFace *facep = mFaces[i];
698 U32 pool_type = facep->getPool()->getType();
699
700 if ((pool_type == LLDrawPool::POOL_SIMPLE) ||
701 (pool_type == LLDrawPool::POOL_ALPHA) ||
702 (pool_type == LLDrawPool::POOL_HUD) ||
703 (pool_type == LLDrawPool::POOL_MEDIA) ||
704 (pool_type == LLDrawPool::POOL_BUMP))
705 {
706 LLViewerObject* objp = facep->getViewerObject();
707 S32 te_offset = facep->getTEOffset();
708
709 if (te_offset >= objp->getNumTEs()) // Shouldn't happen
710 {
711 llwarns << "TE offsets don't match!" << llendl;
712 facep->setTEOffset(-1);
713 continue;
714 }
715
716 LLDrawPool* poolp = NULL;
717 LLViewerImage* imagep = (te_offset >= 0) ? objp->getTEImage(te_offset) : facep->getTexture();
718 if (facep->isState(LLFace::HUD_RENDER))
719 {
720 poolp = gPipeline.getPool(LLDrawPool::POOL_HUD);
721 }
722 else if (te_offset >= 0)
723 {
724 // This face actually uses texture entries...
725 const LLTextureEntry* te = facep->getTextureEntry();
726 poolp = LLPipeline::getPoolFromTE(te, imagep);
727 }
728 else
729 {
730 // No texture entry for this face.
731 if (!imagep)
732 {
733 poolp = gPipeline.getPool(LLDrawPool::POOL_SIMPLE, NULL);
734 }
735 else if ((imagep->getComponents() == 4) || (imagep->getComponents() == 2))
736 {
737 poolp = gPipeline.getPool(LLDrawPool::POOL_ALPHA);
738 }
739 else
740 {
741 poolp = gPipeline.getPool(LLDrawPool::POOL_SIMPLE, imagep);
742 }
743 }
744 facep->setPool(poolp, imagep);
745 }
746 }
747 }
748}
749
750
751BOOL LLDrawable::updateGeometry(BOOL priority)
752{
753 llassert(mVObjp.notNull());
754 BOOL res = mVObjp->updateGeometry(this);
755 if (isState(REBUILD_LIGHTING))
756 {
757 updateLighting(priority ? FALSE : TRUE); // only do actual lighting for non priority updates
758 if (priority)
759 {
760 gPipeline.markRelight(this); // schedule non priority update
761 }
762 else
763 {
764 clearState(REBUILD_LIGHTING);
765 }
766 }
767 return res;
768}
769
770void LLDrawable::shiftPos(const LLVector3 &shift_vector)
771{
772 if (isDead())
773 {
774 llwarns << "Shifting dead drawable" << llendl;
775 return;
776 }
777
778 if (mParent)
779 {
780 mXform.setPosition(mVObjp->getPosition());
781 }
782 else
783 {
784 mXform.setPosition(mVObjp->getPositionAgent());
785 }
786
787 mXform.setRotation(mVObjp->getRotation());
788 mXform.setScale(1,1,1);
789 mXform.updateMatrix();
790
791 if (isStatic() || // *FIX: don't know why this is happening, but
792 // some terrain patches are becoming active
793 // (earth quake, maybe?) DP
794 getRenderType() == LLPipeline::RENDER_TYPE_TERRAIN)
795 {
796 LLStrider<LLVector3> verticesp;
797
798 for (S32 i = 0; i < getNumFaces(); i++)
799 {
800 LLFace *facep = getFace(i);
801 facep->mCenterAgent += shift_vector;
802 facep->mExtents[0] += shift_vector;
803 facep->mExtents[1] += shift_vector;
804
805 if (facep->hasGeometry() && !facep->isState(LLFace::SHARED_GEOM))
806 {
807 S32 index = facep->getVertices(verticesp);
808 if (index >= 0)
809 {
810 S32 vertex_count = facep->getGeomCount();
811 for (S32 j = 0; j < vertex_count; j++)
812 {
813 *verticesp += shift_vector;
814 verticesp++;
815 }
816 }
817 }
818 }
819 }
820 else
821 {
822 // Update the face centers.
823 for (S32 i = 0; i < getNumFaces(); i++)
824 {
825 LLFace *facep = getFace(i);
826 facep->mCenterAgent += shift_vector;
827 }
828 }
829
830 //update spatial extents
831 if (!getVOVolume() || isStatic())
832 {
833 mExtents[0] += shift_vector;
834 mExtents[1] += shift_vector;
835 mPositionGroup += LLVector3d(shift_vector);
836 }
837 else if (mSpatialBridge)
838 {
839 mSpatialBridge->shiftPos(shift_vector);
840 }
841
842 mSavePos = mXform.getPositionW();
843
844 mVObjp->onShift(shift_vector);
845}
846
847const LLVector3& LLDrawable::getBounds(LLVector3& min, LLVector3& max) const
848{
849 mXform.getMinMax(min,max);
850 return mXform.getPositionW();
851}
852
853const LLVector3* LLDrawable::getSpatialExtents() const
854{
855 return mExtents;
856}
857
858void LLDrawable::setSpatialExtents(LLVector3 min, LLVector3 max)
859{
860 LLVector3 size = max - min;
861 mExtents[0] = min;
862 mExtents[1] = max;
863}
864
865void LLDrawable::setPositionGroup(const LLVector3d& pos)
866{
867 mPositionGroup.setVec(pos);
868}
869
870void LLDrawable::updateSpatialExtents()
871{
872 if (mVObjp)
873 {
874 mVObjp->updateSpatialExtents(mExtents[0], mExtents[1]);
875 }
876
877 if (mSpatialBridge.notNull())
878 {
879 mPositionGroup.setVec(0,0,0);
880 }
881}
882
883
884void LLDrawable::updateBinRadius()
885{
886 S32 binLOD = mVObjp ? mVObjp->getLOD() : 2;
887 static F64 detail_bins[] = { 8, 4, 2, 1 };
888 F32 radius = getVOVolume() && isStatic() ?
889 (mExtents[1]-mExtents[0]).magVec() : getRadius();
890 mBinRadius = detail_bins[binLOD] * llmax((F64) radius, (3-binLOD)*0.25);
891}
892
893void LLDrawable::updateLightSet()
894{
895 if (isDead())
896 {
897 llwarns << "Updating light set for dead drawable!" << llendl;
898 return;
899 }
900
901 LLVOVolume* light = getVOVolume();
902 if (isLight() && light)
903 {
904 // mLightSet points to lit objects
905 for (drawable_set_t::iterator iter = mLightSet.begin(); iter != mLightSet.end(); iter++)
906 {
907 gPipeline.markRelight(*iter);
908 }
909 mLightSet.clear();
910 gPipeline.mObjectPartition->getObjects(getPositionAgent(), light->getLightRadius(), mLightSet);
911 for (drawable_set_t::iterator iter = mLightSet.begin(); iter != mLightSet.end(); iter++)
912 {
913 gPipeline.markRelight(*iter);
914 }
915 }
916 else
917 {
918 // mLightSet points to nearby lights
919 mLightSet.clear();
920 gPipeline.mObjectPartition->getLights(getPositionAgent(), getRadius(), mLightSet);
921 const U32 max_lights = 16;
922 if (mLightSet.size() > max_lights)
923 {
924 typedef std::set<std::pair<F32,LLPointer<LLDrawable> > > sorted_pair_set_t;
925 sorted_pair_set_t sorted_set;
926 for (drawable_set_t::iterator iter = mLightSet.begin(); iter != mLightSet.end(); iter++)
927 {
928 LLDrawable* drawable = *iter;
929 LLVector3 dvec = drawable->getPositionAgent() - getPositionAgent();
930 F32 dist2 = dvec.magVecSquared();
931 sorted_set.insert(std::make_pair(dist2, drawable));
932 }
933 mLightSet.clear();
934 S32 count = 0;
935 for (sorted_pair_set_t::iterator iter = sorted_set.begin(); iter != sorted_set.end(); iter++)
936 {
937 if (++count > 16)
938 break;
939 mLightSet.insert((*iter).second);
940 }
941 }
942 }
943}
944
945void LLDrawable::updateSpecialHoverCursor(BOOL enabled)
946{
947 // TODO: maintain a list of objects that have special
948 // hover cursors, then use that list for per-frame
949 // hover cursor selection. JC
950}
951
952BOOL LLDrawable::updateLighting(BOOL do_lighting)
953{
954 if (do_lighting)
955 {
956 if (gPipeline.getLightingDetail() >= 2 && (getLit() || isLight()))
957 {
958 LLFastTimer t(LLFastTimer::FTM_UPDATE_LIGHTS);
959 updateLightSet();
960 do_lighting = isLight() ? FALSE : TRUE;
961 }
962 else
963 {
964 do_lighting = FALSE;
965 }
966 }
967 if (gPipeline.getLightingDetail() >= 2)
968 {
969 LLFastTimer t(LLFastTimer::FTM_GEO_LIGHT);
970 if (mVObjp->updateLighting(do_lighting))
971 {
972 setState(LIGHTING_BUILT);
973 }
974 }
975
976 return TRUE;
977}
978
979void LLDrawable::applyLightsAsPoint(LLColor4& result)
980{
981 LLMemType mt1(LLMemType::MTYPE_DRAWABLE);
982
983 LLVector3 point_agent(getPositionAgent());
984 LLVector3 normal(-gCamera->getXAxis()); // make point agent face camera
985
986 F32 sun_int = normal * gPipeline.mSunDir;
987 LLColor4 color(gSky.getTotalAmbientColor());
988 color += gPipeline.mSunDiffuse * sun_int;
989
990 for (drawable_set_t::iterator iter = mLightSet.begin();
991 iter != mLightSet.end(); ++iter)
992 {
993 LLDrawable* drawable = *iter;
994 LLVOVolume* light = drawable->getVOVolume();
995 if (!light)
996 {
997 continue;
998 }
999 LLColor4 light_color;
1000 light->calcLightAtPoint(point_agent, normal, light_color);
1001 color += light_color;
1002 }
1003
1004 // Clamp the color...
1005 color.mV[0] = llmax(color.mV[0], 0.f);
1006 color.mV[1] = llmax(color.mV[1], 0.f);
1007 color.mV[2] = llmax(color.mV[2], 0.f);
1008
1009 F32 max_color = llmax(color.mV[0], color.mV[1], color.mV[2]);
1010 if (max_color > 1.f)
1011 {
1012 color *= 1.f/max_color;
1013 }
1014
1015 result = color;
1016}
1017
1018F32 LLDrawable::getVisibilityRadius() const
1019{
1020 if (isDead())
1021 {
1022 return 0.f;
1023 }
1024 else if (isLight())
1025 {
1026 return llmax(getRadius(), getVOVolume()->getLightRadius());
1027 }
1028 else
1029 {
1030 return getRadius();
1031 }
1032}
1033
1034void LLDrawable::updateUVMinMax()
1035{
1036}
1037
1038void LLDrawable::setSpatialGroup(LLSpatialGroup *groupp, const S32 offset)
1039{
1040 mSpatialGroupp = groupp;
1041
1042 if (mSpatialGroupp)
1043 {
1044 mSpatialGroupOffset = offset;
1045 }
1046 else
1047 {
1048 mSpatialGroupOffset = -1;
1049 }
1050}
1051
1052LLSpatialPartition* LLDrawable::getSpatialPartition()
1053{
1054 LLSpatialPartition* retval = NULL;
1055
1056 if (mVObjp->isHUDAttachment())
1057 { //HUD attachments don't get space partitioned
1058 return NULL;
1059 }
1060
1061 if (!mVObjp ||
1062 !getVOVolume() ||
1063 isStatic())
1064 {
1065 retval = gPipeline.mObjectPartition;
1066 }
1067
1068 //must be an active volume
1069 if (!retval && isRoot())
1070 {
1071 if (!mSpatialBridge)
1072 {
1073 setSpatialBridge(new LLSpatialBridge(this));
1074 }
1075 return mSpatialBridge->asPartition();
1076 }
1077 else if (!retval)
1078 {
1079 retval = getParent()->getSpatialPartition();
1080 }
1081
1082 if (retval && mSpatialBridge.notNull())
1083 {
1084 mSpatialBridge->markDead();
1085 setSpatialBridge(NULL);
1086 }
1087
1088 return retval;
1089}
1090
1091//=======================================
1092// Spatial Partition Bridging Drawable
1093//=======================================
1094
1095LLSpatialBridge::LLSpatialBridge(LLDrawable* root)
1096{
1097 mDrawable = root;
1098 root->setSpatialBridge(this);
1099
1100 mRenderType = mDrawable->mRenderType; //w00! magic!
1101
1102 mOctree->balance();
1103
1104 gPipeline.mObjectPartition->put(this);
1105}
1106
1107LLSpatialBridge::~LLSpatialBridge()
1108{
1109 if (getSpatialGroup())
1110 {
1111 gPipeline.mObjectPartition->remove(this, getSpatialGroup());
1112 }
1113}
1114
1115void LLSpatialBridge::updateSpatialExtents()
1116{
1117 LLSpatialGroup* root = (LLSpatialGroup*) mOctree->getListener(0);
1118
1119 if (mOctree->getChildCount() > 0)
1120 {
1121 LLFastTimer ftm(LLFastTimer::FTM_CULL_REBOUND);
1122 root->rebound();
1123 }
1124
1125 LLXformMatrix* mat = mDrawable->getXform();
1126
1127 LLVector3 offset = root->mBounds[0];
1128 LLVector3 size = root->mBounds[1];
1129
1130 LLVector3 center = LLVector3(0,0,0) * mat->getWorldMatrix();
1131 LLQuaternion rotation = LLQuaternion(mat->getWorldMatrix());
1132
1133 offset *= rotation;
1134 center += offset;
1135
1136 LLVector3 v[4];
1137 //get 4 corners of bounding box
1138 v[0] = (size * rotation);
1139 v[1] = (LLVector3(-size.mV[0], -size.mV[1], size.mV[2]) * rotation);
1140 v[2] = (LLVector3(size.mV[0], -size.mV[1], -size.mV[2]) * rotation);
1141 v[3] = (LLVector3(-size.mV[0], size.mV[1], -size.mV[2]) * rotation);
1142
1143 LLVector3& newMin = mExtents[0];
1144 LLVector3& newMax = mExtents[1];
1145
1146 newMin = newMax = center;
1147
1148 for (U32 i = 0; i < 4; i++)
1149 {
1150 for (U32 j = 0; j < 3; j++)
1151 {
1152 F32 delta = fabsf(v[i].mV[j]);
1153 F32 min = center.mV[j] - delta;
1154 F32 max = center.mV[j] + delta;
1155
1156 if (min < newMin.mV[j])
1157 {
1158 newMin.mV[j] = min;
1159 }
1160
1161 if (max > newMax.mV[j])
1162 {
1163 newMax.mV[j] = max;
1164 }
1165 }
1166 }
1167
1168 mPositionGroup.setVec((newMin + newMax) * 0.5f);
1169 updateBinRadius();
1170}
1171
1172void LLSpatialBridge::updateBinRadius()
1173{
1174 F32 rad = ((mExtents[1]-mExtents[0])*0.5f).magVec();
1175 mBinRadius = llmax(rad, 2.f);
1176 mRadius = rad;
1177}
1178
1179LLCamera LLSpatialBridge::transformCamera(LLCamera& camera)
1180{
1181 LLCamera ret = camera;
1182 LLXformMatrix* mat = mDrawable->getXform();
1183 LLVector3 center = LLVector3(0,0,0) * mat->getWorldMatrix();
1184 //LLQuaternion rotation = LLQuaternion(mat->getWorldMatrix());
1185
1186 //ret.rotate(~mat->getRotation());
1187 LLVector3 delta = ret.getOrigin() - center;
1188 delta *= ~mat->getRotation();
1189 ret.setOrigin(delta);
1190
1191 return ret;
1192}
1193
1194void LLDrawable::setVisible(LLCamera& camera, std::vector<LLDrawable*>* results, BOOL for_select)
1195{
1196 mVisible = sCurVisible;
1197}
1198
1199void LLSpatialBridge::setVisible(LLCamera& camera_in, std::vector<LLDrawable*>* results, BOOL for_select)
1200{
1201 LLVector3 center = (mExtents[0] + mExtents[1]) * 0.5f;
1202 LLVector3 size = (mExtents[1]-mExtents[0]) * 0.5f;
1203
1204 if (camera_in.AABBInFrustum(center, size))
1205 {
1206 LLVector3 lookAt = center - camera_in.getOrigin();
1207 F32 distSqr = lookAt.magVecSquared();
1208 F32 objRad = size.magVecSquared();
1209
1210 if (objRad/distSqr < SG_MIN_DIST_RATIO*4)
1211 {
1212 return;
1213 }
1214
1215 LLDrawable::setVisible(camera_in);
1216
1217 if (for_select)
1218 {
1219 results->push_back(mDrawable);
1220 for (U32 i = 0; i < mDrawable->getChildCount(); i++)
1221 {
1222 results->push_back(mDrawable->getChild(i));
1223 }
1224 }
1225 else
1226 {
1227 const LLVector3* extents = mDrawable->getSpatialExtents();
1228 objRad = mDrawable->getRadius();
1229 objRad *= objRad;
1230
1231 if (objRad/distSqr > SG_MIN_DIST_RATIO)
1232 {
1233 gPipeline.markNotCulled(mDrawable, camera_in);
1234 }
1235
1236 for (U32 i = 0; i < mDrawable->getChildCount(); i++)
1237 {
1238 LLDrawable* child = mDrawable->getChild(i);
1239 extents = child->getSpatialExtents();
1240 objRad = child->getRadius();
1241 objRad *= objRad;
1242
1243 if (objRad/distSqr > SG_MIN_DIST_RATIO)
1244 {
1245 gPipeline.markNotCulled(mDrawable->getChild(i), camera_in);
1246 }
1247 }
1248 }
1249 }
1250}
1251
1252void LLSpatialBridge::updateDistance(LLCamera& camera_in)
1253{
1254 LLCamera camera = transformCamera(camera_in);
1255
1256 mDrawable->updateDistance(camera);
1257
1258 for (U32 i = 0; i < mDrawable->getChildCount(); ++i)
1259 {
1260 mDrawable->getChild(i)->updateDistance(camera);
1261 }
1262}
1263
1264void LLSpatialBridge::makeActive()
1265{ //it is an error to make a spatial bridge active (it's already active)
1266 llerrs << "makeActive called on spatial bridge" << llendl;
1267}
1268
1269void LLSpatialBridge::makeStatic()
1270{
1271 llerrs << "makeStatic called on spatial bridge" << llendl;
1272}
1273
1274void LLSpatialBridge::move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL immediate)
1275{
1276 LLSpatialPartition::move(drawablep, curp, immediate);
1277 gPipeline.markMoved(this, FALSE);
1278}
1279
1280BOOL LLSpatialBridge::updateMove()
1281{
1282 mOctree->balance();
1283 gPipeline.mObjectPartition->move(this, getSpatialGroup(), TRUE);
1284 return TRUE;
1285}
1286
1287void LLSpatialBridge::shiftPos(const LLVector3& vec)
1288{
1289 mExtents[0] += vec;
1290 mExtents[1] += vec;
1291 mPositionGroup += LLVector3d(vec);
1292}
1293
1294void LLSpatialBridge::cleanupReferences()
1295{
1296 LLDrawable::cleanupReferences();
1297 if (mDrawable)
1298 {
1299 mDrawable->setSpatialGroup(NULL, -1);
1300 for (U32 i = 0; i < mDrawable->getChildCount(); i++)
1301 {
1302 LLDrawable* drawable = mDrawable->getChild(i);
1303 if (drawable && drawable->getVOVolume())
1304 {
1305 drawable->setSpatialGroup(NULL, -1);
1306 }
1307 }
1308
1309 LLDrawable* drawablep = mDrawable;
1310 mDrawable = NULL;
1311 drawablep->setSpatialBridge(NULL);
1312 }
1313}
1314
1315const LLVector3 LLDrawable::getPositionAgent() const
1316{
1317 if (getVOVolume())
1318 {
1319 if (isActive())
1320 {
1321 if (isRoot())
1322 {
1323 return LLVector3(0,0,0) * getWorldMatrix();
1324 }
1325 else
1326 {
1327 return mVObjp->getPosition() * getParent()->getWorldMatrix();
1328 }
1329 }
1330 else
1331 {
1332 return mVObjp->getPositionAgent();
1333 }
1334 }
1335 else
1336 {
1337 return getWorldPosition();
1338 }
1339}
1340