aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llspatialpartition.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra/newview/llspatialpartition.cpp')
-rw-r--r--linden/indra/newview/llspatialpartition.cpp2274
1 files changed, 2274 insertions, 0 deletions
diff --git a/linden/indra/newview/llspatialpartition.cpp b/linden/indra/newview/llspatialpartition.cpp
new file mode 100644
index 0000000..fd9eec0
--- /dev/null
+++ b/linden/indra/newview/llspatialpartition.cpp
@@ -0,0 +1,2274 @@
1/**
2 * @file llspatialpartition.cpp
3 * @brief LLSpatialGroup class implementation and supporting functions
4 *
5 * Copyright (c) 2003-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 "llspatialpartition.h"
31
32#include "llglheaders.h"
33
34#include "llviewerobjectlist.h"
35#include "llvovolume.h"
36#include "llviewercamera.h"
37#include "llface.h"
38#include "viewer.h"
39
40#include "llcamera.h"
41#include "pipeline.h"
42
43static BOOL sIgnoreOcclusion = TRUE;
44static GLuint sBoxList = 0;
45
46const S32 SG_LOD_SWITCH_STAGGER = 4;
47const F32 SG_MAX_OBJ_RAD = 1.f;
48const F32 SG_OCCLUSION_FUDGE = 1.1f;
49const S32 SG_MOVE_PERIOD = 32;
50const S32 SG_LOD_PERIOD = 16;
51
52#define SG_DISCARD_TOLERANCE 0.25f
53
54#if LL_OCTREE_PARANOIA_CHECK
55#define assert_octree_valid(x) x->validate()
56#else
57#define assert_octree_valid(x)
58#endif
59
60static F32 sLastMaxTexPriority = 1.f;
61static F32 sCurMaxTexPriority = 1.f;
62
63//static counter for frame to switch LOD on
64S32 LLSpatialGroup::sLODSeed = 0;
65
66void sg_assert(BOOL expr)
67{
68#if LL_OCTREE_PARANOIA_CHECK
69 if (!expr)
70 {
71 llerrs << "Octree invalid!" << llendl;
72 }
73#endif
74}
75
76#if !LL_RELEASE_FOR_DOWNLOAD
77void validate_drawable(LLDrawable* drawablep)
78{
79 F64 rad = drawablep->getBinRadius();
80 const LLVector3* ext = drawablep->getSpatialExtents();
81
82 if (rad < 0 || rad > 4096 ||
83 (ext[1]-ext[0]).magVec() > 4096)
84 {
85 llwarns << "Invalid drawable found in octree." << llendl;
86 }
87}
88#else
89#define validate_drawable(x)
90#endif
91
92BOOL earlyFail(LLCamera* camera, LLSpatialGroup* group);
93
94BOOL LLLineSegmentAABB(const LLVector3& start, const LLVector3& end, const LLVector3& center, const LLVector3& size)
95{
96 float fAWdU[3];
97 LLVector3 dir;
98 LLVector3 diff;
99
100 for (U32 i = 0; i < 3; i++)
101 {
102 dir.mV[i] = 0.5f * (end.mV[i] - start.mV[i]);
103 diff.mV[i] = (0.5f * (end.mV[i] + start.mV[i])) - center.mV[i];
104 fAWdU[i] = fabsf(dir.mV[i]);
105 if(fabsf(diff.mV[i])>size.mV[i] + fAWdU[i]) return false;
106 }
107
108 float f;
109 f = dir.mV[1] * diff.mV[2] - dir.mV[2] * diff.mV[1]; if(fabsf(f)>size.mV[1]*fAWdU[2] + size.mV[2]*fAWdU[1]) return false;
110 f = dir.mV[2] * diff.mV[0] - dir.mV[0] * diff.mV[2]; if(fabsf(f)>size.mV[0]*fAWdU[2] + size.mV[2]*fAWdU[0]) return false;
111 f = dir.mV[0] * diff.mV[1] - dir.mV[1] * diff.mV[0]; if(fabsf(f)>size.mV[0]*fAWdU[1] + size.mV[1]*fAWdU[0]) return false;
112
113 return true;
114}
115
116//returns:
117// 0 if sphere and AABB are not intersecting
118// 1 if they are
119// 2 if AABB is entirely inside sphere
120
121S32 LLSphereAABB(const LLVector3& center, const LLVector3& size, const LLVector3& pos, const F32 &rad)
122{
123 S32 ret = 2;
124
125 LLVector3 min = center - size;
126 LLVector3 max = center + size;
127 for (U32 i = 0; i < 3; i++)
128 {
129 if (min.mV[i] > pos.mV[i] + rad ||
130 max.mV[i] < pos.mV[i] - rad)
131 { //totally outside
132 return 0;
133 }
134
135 if (min.mV[i] < pos.mV[i] - rad ||
136 max.mV[i] > pos.mV[i] + rad)
137 { //intersecting
138 ret = 1;
139 }
140 }
141
142 return ret;
143}
144
145LLSpatialGroup::~LLSpatialGroup()
146{
147 LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
148 if (!safeToDelete())
149 {
150#ifdef LL_RELEASE_FOR_DOWNLOAD
151 llwarns << "Spatial Group deleted while being tracked " << ((void*) mState) << llendl;
152#else
153 llerrs << "Spatial Group deleted while being tracked " << ((void*) mState) << llendl;
154#endif
155 }
156
157#if LL_OCTREE_PARANOIA_CHECK
158 for (U32 i = 0; i < mSpatialPartition->mOccludedList.size(); i++)
159 {
160 if (mSpatialPartition->mOccludedList[i] == this)
161 {
162 llerrs << "Spatial Group deleted while being tracked STATE ERROR " << ((void*) mState) << llendl;
163 }
164 }
165#endif
166}
167
168BOOL LLSpatialGroup::safeToDelete()
169{
170 return gQuit || !isState(IN_QUEUE | ACTIVE_OCCLUSION | RESHADOW_QUEUE);
171}
172
173class LLRelightPainter : public LLSpatialGroup::OctreeTraveler
174{
175public:
176 LLVector3 mOrigin, mDir;
177 F32 mRadius;
178
179 LLRelightPainter(LLVector3 origin, LLVector3 dir, F32 radius)
180 : mOrigin(origin), mDir(dir), mRadius(radius)
181 { }
182
183 virtual void traverse(const LLSpatialGroup::TreeNode* n)
184 {
185 LLSpatialGroup::OctreeNode* node = (LLSpatialGroup::OctreeNode*) n;
186
187 LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
188 group->setState(LLSpatialGroup::RESHADOW);
189
190 for (U32 i = 0; i < node->getChildCount(); i++)
191 {
192 const LLSpatialGroup::OctreeNode* child = node->getChild(i);
193 LLSpatialGroup* group = (LLSpatialGroup*) child->getListener(0);
194
195 LLVector3 res;
196
197 LLVector3 center, size;
198
199 center = group->mBounds[0];
200 size = group->mBounds[1];
201
202 if (child->isInside(LLVector3d(mOrigin)) || LLRayAABB(center, size, mOrigin, mDir, res, mRadius))
203 {
204 traverse(child);
205 }
206 }
207 }
208
209 virtual void visit(const LLSpatialGroup::OctreeState* branch) { }
210
211};
212
213BOOL LLSpatialGroup::isVisible()
214{
215 if (sIgnoreOcclusion)
216 {
217 return !isState(CULLED);
218 }
219 else
220 {
221 return !isState(CULLED | OCCLUDED);
222 }
223}
224
225void LLSpatialGroup::validate()
226{
227#if LL_OCTREE_PARANOIA_CHECK
228
229 sg_assert(!isState(DIRTY));
230
231 LLVector3 myMin = mBounds[0] - mBounds[1];
232 LLVector3 myMax = mBounds[0] + mBounds[1];
233
234 for (U32 i = 0; i < mOctreeNode->getChildCount(); ++i)
235 {
236 LLSpatialGroup* group = (LLSpatialGroup*) mOctreeNode->getChild(i)->getListener(0);
237
238 group->validate();
239
240 //ensure all children are enclosed in this node
241 LLVector3 center = group->mBounds[0];
242 LLVector3 size = group->mBounds[1];
243
244 LLVector3 min = center - size;
245 LLVector3 max = center + size;
246
247 for (U32 j = 0; j < 3; j++)
248 {
249 sg_assert(min.mV[j] >= myMin.mV[j]-0.02f);
250 sg_assert(max.mV[j] <= myMax.mV[j]+0.02f);
251 }
252 }
253
254#endif
255}
256
257BOOL LLSpatialGroup::updateInGroup(LLDrawable *drawablep, BOOL immediate)
258{
259 LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
260
261 drawablep->updateSpatialExtents();
262 validate_drawable(drawablep);
263
264 if (mOctreeNode->isInside(drawablep) && mOctreeNode->contains(drawablep))
265 {
266 unbound();
267 setState(OBJECT_DIRTY);
268 validate_drawable(drawablep);
269 return TRUE;
270 }
271
272 return FALSE;
273}
274
275
276BOOL LLSpatialGroup::addObject(LLDrawable *drawablep, BOOL add_all, BOOL from_octree)
277{
278 LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
279 if (!from_octree)
280 {
281 mOctreeNode->insert(drawablep);
282 }
283 else
284 {
285 drawablep->setSpatialGroup(this, 0);
286 validate_drawable(drawablep);
287 }
288
289 return TRUE;
290}
291
292BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector3& minOut, LLVector3& maxOut)
293{
294 const OctreeState* node = mOctreeNode->getOctState();
295
296 if (node->getData().empty())
297 { //don't do anything if there are no objects
298 if (empty && mOctreeNode->getParent())
299 { //only root is allowed to be empty
300 OCT_ERRS << "Empty leaf found in octree." << llendl;
301 }
302 return FALSE;
303 }
304
305 LLVector3& newMin = mObjectExtents[0];
306 LLVector3& newMax = mObjectExtents[1];
307
308 if (isState(OBJECT_DIRTY))
309 { //calculate new bounding box
310 clearState(OBJECT_DIRTY);
311
312 //initialize bounding box to first element
313 OctreeState::const_element_iter i = node->getData().begin();
314 LLDrawable* drawablep = *i;
315 const LLVector3* minMax = drawablep->getSpatialExtents();
316
317 newMin.setVec(minMax[0]);
318 newMax.setVec(minMax[1]);
319
320 for (++i; i != node->getData().end(); ++i)
321 {
322 drawablep = *i;
323 minMax = drawablep->getSpatialExtents();
324
325 //bin up the object
326 for (U32 i = 0; i < 3; i++)
327 {
328 if (minMax[0].mV[i] < newMin.mV[i])
329 {
330 newMin.mV[i] = minMax[0].mV[i];
331 }
332 if (minMax[1].mV[i] > newMax.mV[i])
333 {
334 newMax.mV[i] = minMax[1].mV[i];
335 }
336 }
337 }
338
339 mObjectBounds[0] = (newMin + newMax) * 0.5f;
340 mObjectBounds[1] = (newMax - newMin) * 0.5f;
341 }
342
343 if (empty)
344 {
345 minOut = newMin;
346 maxOut = newMax;
347 }
348 else
349 {
350 for (U32 i = 0; i < 3; i++)
351 {
352 if (newMin.mV[i] < minOut.mV[i])
353 {
354 minOut.mV[i] = newMin.mV[i];
355 }
356 if (newMax.mV[i] > maxOut.mV[i])
357 {
358 maxOut.mV[i] = newMax.mV[i];
359 }
360 }
361 }
362
363 return TRUE;
364}
365
366void LLSpatialGroup::unbound()
367{
368 if (isState(DIRTY))
369 {
370 return;
371 }
372
373 setState(DIRTY);
374
375 //all the parent nodes need to rebound this child
376 if (mOctreeNode)
377 {
378 OctreeNode* parent = (OctreeNode*) mOctreeNode->getParent();
379 while (parent != NULL)
380 {
381 LLSpatialGroup* group = (LLSpatialGroup*) parent->getListener(0);
382 if (group->isState(DIRTY))
383 {
384 return;
385 }
386
387 group->setState(DIRTY);
388 parent = (OctreeNode*) parent->getParent();
389 }
390 }
391}
392
393BOOL LLSpatialGroup::removeObject(LLDrawable *drawablep, BOOL from_octree)
394{
395 LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
396 unbound();
397 if (!from_octree)
398 {
399 if (!mOctreeNode->remove(drawablep))
400 {
401 OCT_ERRS << "Could not remove drawable from spatial group" << llendl;
402 }
403 }
404 else
405 {
406 drawablep->setSpatialGroup(NULL, -1);
407 }
408 return TRUE;
409}
410
411void LLSpatialGroup::shift(const LLVector3 &offset)
412{
413 LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
414 LLVector3d offsetd(offset);
415 mOctreeNode->setCenter(mOctreeNode->getCenter()+offsetd);
416 mOctreeNode->updateMinMax();
417 mBounds[0] += offset;
418 mExtents[0] += offset;
419 mExtents[1] += offset;
420 mObjectBounds[0] += offset;
421 mObjectExtents[0] += offset;
422 mObjectExtents[1] += offset;
423}
424
425class LLSpatialSetState : public LLSpatialGroup::OctreeTraveler
426{
427public:
428 U32 mState;
429 LLSpatialSetState(U32 state) : mState(state) { }
430 virtual void visit(const LLSpatialGroup::OctreeState* branch) { ((LLSpatialGroup*) branch->getListener(0))->setState(mState); }
431};
432
433class LLSpatialSetStateDiff : public LLSpatialSetState
434{
435public:
436 LLSpatialSetStateDiff(U32 state) : LLSpatialSetState(state) { }
437
438 virtual void traverse(const LLSpatialGroup::TreeNode* n)
439 {
440 LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
441
442 if (!group->isState(mState))
443 {
444 LLSpatialGroup::OctreeTraveler::traverse(n);
445 }
446 }
447};
448
449void LLSpatialGroup::setState(U32 state, S32 mode)
450{
451 LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
452 if (mode > STATE_MODE_SINGLE)
453 {
454 if (mode == STATE_MODE_DIFF)
455 {
456 LLSpatialSetStateDiff setter(state);
457 setter.traverse(mOctreeNode);
458 }
459 else
460 {
461 LLSpatialSetState setter(state);
462 setter.traverse(mOctreeNode);
463 }
464 }
465 else
466 {
467 mState |= state;
468 }
469}
470
471class LLSpatialClearState : public LLSpatialGroup::OctreeTraveler
472{
473public:
474 U32 mState;
475 LLSpatialClearState(U32 state) : mState(state) { }
476 virtual void visit(const LLSpatialGroup::OctreeState* branch) { ((LLSpatialGroup*) branch->getListener(0))->clearState(mState); }
477};
478
479class LLSpatialClearStateDiff : public LLSpatialClearState
480{
481public:
482 LLSpatialClearStateDiff(U32 state) : LLSpatialClearState(state) { }
483
484 virtual void traverse(const LLSpatialGroup::TreeNode* n)
485 {
486 LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
487
488 if (!group->isState(mState))
489 {
490 LLSpatialGroup::OctreeTraveler::traverse(n);
491 }
492 }
493};
494
495
496void LLSpatialGroup::clearState(U32 state, S32 mode)
497{
498 LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
499 if (mode > STATE_MODE_SINGLE)
500 {
501 if (mode == STATE_MODE_DIFF)
502 {
503 LLSpatialClearStateDiff clearer(state);
504 clearer.traverse(mOctreeNode);
505 }
506 else
507 {
508 LLSpatialClearState clearer(state);
509 clearer.traverse(mOctreeNode);
510 }
511 }
512 else
513 {
514 mState &= ~state;
515 }
516
517#if LL_OCTREE_PARANOIA_CHECK
518 if (state & LLSpatialGroup::ACTIVE_OCCLUSION)
519 {
520 LLSpatialPartition* part = mSpatialPartition;
521 for (U32 i = 0; i < part->mOccludedList.size(); i++)
522 {
523 if (part->mOccludedList[i] == this)
524 {
525 llerrs << "LLSpatialGroup state error: " << mState << llendl;
526 }
527 }
528 }
529#endif
530}
531
532//======================================
533// Octree Listener Implementation
534//======================================
535
536LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part)
537: mState(0), mOctreeNode(node), mSpatialPartition(part)
538{
539 LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
540 sg_assert(mOctreeNode->getListenerCount() == 0);
541 mOctreeNode->addListener(this);
542 setState(DIRTY);
543
544 mBounds[0] = LLVector3(node->getCenter());
545 mBounds[1] = LLVector3(node->getSize());
546
547 sLODSeed = (sLODSeed+1)%SG_LOD_PERIOD;
548 mLODHash = sLODSeed;
549}
550
551BOOL LLSpatialGroup::changeLOD()
552{
553 return LLDrawable::getCurrentFrame()%SG_LOD_PERIOD == mLODHash;
554}
555
556void LLSpatialGroup::handleInsertion(const TreeNode* node, LLDrawable* drawable)
557{
558 LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
559 addObject(drawable, FALSE, TRUE);
560 unbound();
561 setState(OBJECT_DIRTY);
562}
563
564void LLSpatialGroup::handleRemoval(const TreeNode* node, LLDrawable* drawable)
565{
566 LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
567 removeObject(drawable, TRUE);
568 setState(OBJECT_DIRTY);
569}
570
571void LLSpatialGroup::handleDestruction(const TreeNode* node)
572{
573 LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
574
575 if (mOctreeNode)
576 {
577 OctreeState* state = mOctreeNode->getOctState();
578 for (OctreeState::element_iter i = state->getData().begin(); i != state->getData().end(); ++i)
579 {
580 LLDrawable* drawable = *i;
581 if (!drawable->isDead())
582 {
583 drawable->setSpatialGroup(NULL, -1);
584 }
585 }
586 }
587
588 if (safeToDelete())
589 {
590 delete this;
591 }
592 else
593 {
594 setState(DEAD);
595 mOctreeNode = NULL;
596 }
597}
598
599void LLSpatialGroup::handleStateChange(const TreeNode* node)
600{
601 //drop bounding box upon state change
602 if (mOctreeNode != node)
603 {
604 mOctreeNode = (OctreeNode*) node;
605 }
606 unbound();
607}
608
609void LLSpatialGroup::handleChildAddition(const OctreeNode* parent, OctreeNode* child)
610{
611 LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
612 if (child->getListenerCount() == 0)
613 {
614 (new LLSpatialGroup(child, mSpatialPartition))->setState(mState & SG_STATE_INHERIT_MASK);
615 }
616 else
617 {
618 OCT_ERRS << "LLSpatialGroup redundancy detected." << llendl;
619 }
620
621 unbound();
622}
623
624void LLSpatialGroup::handleChildRemoval(const OctreeNode* parent, const OctreeNode* child)
625{
626 unbound();
627}
628
629BOOL LLSpatialGroup::rebound()
630{
631 if (!isState(DIRTY))
632 { //return TRUE if we're not empty
633 return TRUE;
634 }
635
636 LLVector3 oldBounds[2];
637
638 if (isState(QUERY_OUT))
639 { //a query has been issued, if our bounding box changes significantly
640 //we need to discard the issued query
641 oldBounds[0] = mBounds[0];
642 oldBounds[1] = mBounds[1];
643 }
644
645 if (mOctreeNode->getChildCount() == 1 && mOctreeNode->getElementCount() == 0)
646 {
647 LLSpatialGroup* group = (LLSpatialGroup*) mOctreeNode->getChild(0)->getListener(0);
648 group->rebound();
649
650 //copy single child's bounding box
651 mBounds[0] = group->mBounds[0];
652 mBounds[1] = group->mBounds[1];
653 mExtents[0] = group->mExtents[0];
654 mExtents[1] = group->mExtents[1];
655
656 group->setState(SKIP_FRUSTUM_CHECK);
657 }
658 else if (mOctreeNode->hasLeafState())
659 { //copy object bounding box if this is a leaf
660 boundObjects(TRUE, mExtents[0], mExtents[1]);
661 mBounds[0] = mObjectBounds[0];
662 mBounds[1] = mObjectBounds[1];
663 }
664 else
665 {
666 LLVector3& newMin = mExtents[0];
667 LLVector3& newMax = mExtents[1];
668 LLSpatialGroup* group = (LLSpatialGroup*) mOctreeNode->getChild(0)->getListener(0);
669 group->clearState(SKIP_FRUSTUM_CHECK);
670 group->rebound();
671 //initialize to first child
672 newMin = group->mExtents[0];
673 newMax = group->mExtents[1];
674
675 //first, rebound children
676 for (U32 i = 1; i < mOctreeNode->getChildCount(); i++)
677 {
678 group = (LLSpatialGroup*) mOctreeNode->getChild(i)->getListener(0);
679 group->clearState(SKIP_FRUSTUM_CHECK);
680 group->rebound();
681 const LLVector3& max = group->mExtents[1];
682 const LLVector3& min = group->mExtents[0];
683
684 for (U32 j = 0; j < 3; j++)
685 {
686 if (max.mV[j] > newMax.mV[j])
687 {
688 newMax.mV[j] = max.mV[j];
689 }
690 if (min.mV[j] < newMin.mV[j])
691 {
692 newMin.mV[j] = min.mV[j];
693 }
694 }
695 }
696
697 boundObjects(FALSE, newMin, newMax);
698
699 mBounds[0] = (newMin + newMax)*0.5f;
700 mBounds[1] = (newMax - newMin)*0.5f;
701 }
702
703 if (isState(QUERY_OUT))
704 {
705 for (U32 i = 0; i < 3 && !isState(DISCARD_QUERY); i++)
706 {
707 if (fabsf(mBounds[0].mV[i]-oldBounds[0].mV[i]) > SG_DISCARD_TOLERANCE ||
708 fabsf(mBounds[1].mV[i]-oldBounds[1].mV[i]) > SG_DISCARD_TOLERANCE)
709 { //bounding box changed significantly, discard last issued
710 //occlusion query
711 setState(DISCARD_QUERY);
712 }
713 }
714 }
715
716 clearState(DIRTY);
717
718 return TRUE;
719}
720
721//==============================================
722
723LLSpatialPartition::LLSpatialPartition()
724{
725 LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
726 mOctree = new LLSpatialGroup::OctreeNode(LLVector3d(0,0,0),
727 LLVector3d(1,1,1),
728 new LLSpatialGroup::OctreeRoot(), NULL);
729 new LLSpatialGroup(mOctree, this);
730}
731
732
733LLSpatialPartition::~LLSpatialPartition()
734{
735 LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
736 delete mOctree;
737 mOctree = NULL;
738}
739
740
741LLSpatialGroup *LLSpatialPartition::put(LLDrawable *drawablep)
742{
743 LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
744 const F32 MAX_MAG = 1000000.f*1000000.f; // 1 million
745
746 if (drawablep->getPositionGroup().magVecSquared() > MAX_MAG)
747 {
748#ifndef LL_RELEASE_FOR_DOWNLOAD
749 llwarns << "LLSpatialPartition::put Object out of range!" << llendl;
750 llinfos << drawablep->getPositionGroup() << llendl;
751
752 if (drawablep->getVObj())
753 {
754 llwarns << "Dumping debugging info: " << llendl;
755 drawablep->getVObj()->dump();
756 }
757#endif
758 return NULL;
759 }
760
761 drawablep->updateSpatialExtents();
762 validate_drawable(drawablep);
763
764 //keep drawable from being garbage collected
765 LLPointer<LLDrawable> ptr = drawablep;
766
767 assert_octree_valid(mOctree);
768 mOctree->insert(drawablep);
769 assert_octree_valid(mOctree);
770
771 LLSpatialGroup::OctreeNode* node = mOctree->getNodeAt(drawablep);
772
773 return (LLSpatialGroup*) node->getListener(0);
774}
775
776BOOL LLSpatialPartition::remove(LLDrawable *drawablep, LLSpatialGroup *curp)
777{
778 LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
779
780 drawablep->setSpatialGroup(NULL, -1);
781
782 if (!curp->removeObject(drawablep))
783 {
784 OCT_ERRS << "Failed to remove drawable from octree!" << llendl;
785 }
786
787 assert_octree_valid(mOctree);
788
789 return TRUE;
790}
791
792void LLSpatialPartition::move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL immediate)
793{
794 LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
795 LLFastTimer t(LLFastTimer::FTM_UPDATE_MOVE);
796
797 if (curp && curp->mSpatialPartition != this)
798 {
799 //keep drawable from being garbage collected
800 LLPointer<LLDrawable> ptr = drawablep;
801 if (curp->mSpatialPartition->remove(drawablep, curp))
802 {
803 put(drawablep);
804 return;
805 }
806 else
807 {
808 OCT_ERRS << "Drawable lost between spatial partitions on outbound transition." << llendl;
809 }
810 }
811
812 if (curp && curp->updateInGroup(drawablep, immediate))
813 {
814 // Already updated, don't need to do anything
815 assert_octree_valid(mOctree);
816 return;
817 }
818
819 //keep drawable from being garbage collected
820 LLPointer<LLDrawable> ptr = drawablep;
821 if (curp && !remove(drawablep, curp))
822 {
823 OCT_ERRS << "Move couldn't find existing spatial group!" << llendl;
824 }
825
826 put(drawablep);
827}
828
829class LLSpatialShift : public LLSpatialGroup::OctreeTraveler
830{
831public:
832 LLSpatialShift(LLVector3 offset) : mOffset(offset) { }
833 virtual void visit(const LLSpatialGroup::OctreeState* branch)
834 {
835 ((LLSpatialGroup*) branch->getListener(0))->shift(mOffset);
836 }
837
838 LLVector3 mOffset;
839};
840
841void LLSpatialPartition::shift(const LLVector3 &offset)
842{
843 LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
844 llinfos << "Shifting octree: " << offset << llendl;
845 LLSpatialShift shifter(offset);
846 shifter.traverse(mOctree);
847}
848
849BOOL LLSpatialPartition::checkOcclusion(LLSpatialGroup* group, LLCamera* camera)
850{
851 if (sIgnoreOcclusion)
852 {
853 return FALSE;
854 }
855
856 if (!group->isState(LLSpatialGroup::ACTIVE_OCCLUSION | LLSpatialGroup::OCCLUDED) &&
857 !earlyFail(camera, group))
858 {
859 group->setState(LLSpatialGroup::ACTIVE_OCCLUSION);
860 mQueryQueue.push(group);
861 return TRUE;
862 }
863
864 return FALSE;
865}
866
867class LLOctreeCull : public LLSpatialGroup::OctreeTraveler
868{
869public:
870 LLOctreeCull(LLCamera* camera)
871 : mCamera(camera), mRes(0) { }
872
873 virtual bool earlyFail(const LLSpatialGroup* group)
874 {
875 if (mRes && //never occlusion cull the root node
876 !sIgnoreOcclusion && //never occlusion cull selection
877 group->isState(LLSpatialGroup::OCCLUDED))
878 {
879 return true;
880 }
881
882 return false;
883 }
884
885 virtual void traverse(const LLSpatialGroup::TreeNode* n)
886 {
887 LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
888
889 if (earlyFail(group))
890 {
891 return;
892 }
893
894 if (mRes == 2 ||
895 (mRes && group->isState(LLSpatialGroup::SKIP_FRUSTUM_CHECK)))
896 { //fully in, just add everything
897 LLSpatialGroup::OctreeTraveler::traverse(n);
898 }
899 else
900 {
901 mRes = mCamera->AABBInFrustum(group->mBounds[0], group->mBounds[1]);
902
903 if (mRes)
904 { //at least partially in, run on down
905 LLSpatialGroup::OctreeTraveler::traverse(n);
906 }
907 else
908 {
909 lateFail(group);
910 }
911 mRes = 0;
912 }
913 }
914
915 virtual void lateFail(LLSpatialGroup* group)
916 {
917 if (!group->isState(LLSpatialGroup::CULLED))
918 { //totally culled, so are all its children
919 group->setState(LLSpatialGroup::CULLED, LLSpatialGroup::STATE_MODE_DIFF);
920 }
921 }
922
923 virtual bool checkObjects(const LLSpatialGroup::OctreeState* branch, const LLSpatialGroup* group)
924 {
925
926 if (branch->getElementCount() == 0) //no elements
927 {
928 return false;
929 }
930 else if (branch->getChildCount() == 0) //leaf state, already checked tightest bounding box
931 {
932 return true;
933 }
934 else if (mRes == 1 && !mCamera->AABBInFrustum(group->mObjectBounds[0], group->mObjectBounds[1])) //no objects in frustum
935 {
936 return false;
937 }
938
939 return true;
940 }
941
942 virtual void preprocess(LLSpatialGroup* group)
943 {
944 if (group->isState(LLSpatialGroup::CULLED))
945 { //this is the first frame this node is visible
946 group->clearState(LLSpatialGroup::CULLED);
947 if (group->mOctreeNode->hasLeafState())
948 { //if it's a leaf, force it onto the active occlusion list to prevent
949 //massive frame stutters
950 group->mSpatialPartition->checkOcclusion(group, mCamera);
951 }
952 }
953 }
954
955 virtual void processDrawable(LLDrawable* drawable)
956 {
957 if (!drawable->isDead())
958 {
959 const LLVector3* extents = drawable->getSpatialExtents();
960
961 F32 objRad = drawable->getRadius();
962 objRad *= objRad;
963 F32 distSqr = ((extents[0]+extents[1])*0.5f - mCamera->getOrigin()).magVecSquared();
964 if (objRad/distSqr > SG_MIN_DIST_RATIO)
965 {
966 gPipeline.markNotCulled(drawable, *mCamera);
967 }
968 }
969 }
970
971 virtual void visit(const LLSpatialGroup::OctreeState* branch)
972 {
973 LLSpatialGroup* group = (LLSpatialGroup*) branch->getListener(0);
974
975 preprocess(group);
976
977 if (checkObjects(branch, group))
978 {
979 for (LLSpatialGroup::OctreeState::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i)
980 {
981 processDrawable(*i);
982 }
983 }
984 }
985
986 LLCamera *mCamera;
987 S32 mRes;
988};
989
990
991class LLOctreeSelect : public LLOctreeCull
992{
993public:
994 LLOctreeSelect(LLCamera* camera, std::vector<LLDrawable*>* results)
995 : LLOctreeCull(camera), mResults(results) { }
996
997 virtual bool earlyFail(const LLSpatialGroup* group) { return false; }
998 virtual void lateFail(LLSpatialGroup* group) { }
999 virtual void preprocess(LLSpatialGroup* group) { }
1000
1001 virtual void processDrawable(LLDrawable* drawable)
1002 {
1003 if (!drawable->isDead())
1004 {
1005 if (drawable->isSpatialBridge())
1006 {
1007 drawable->setVisible(*mCamera, mResults, TRUE);
1008 }
1009 else
1010 {
1011 mResults->push_back(drawable);
1012 }
1013 }
1014 }
1015
1016 std::vector<LLDrawable*>* mResults;
1017};
1018
1019
1020void drawBox(const LLVector3& c, const LLVector3& r)
1021{
1022 glPushMatrix();
1023 glTranslatef(c.mV[0], c.mV[1], c.mV[2]);
1024 glScalef(r.mV[0], r.mV[1], r.mV[2]);
1025 glCallList(sBoxList);
1026 glPopMatrix();
1027}
1028
1029void genBoxList()
1030{
1031 if (sBoxList != 0)
1032 {
1033 return;
1034 }
1035
1036 sBoxList = glGenLists(1);
1037 glNewList(sBoxList, GL_COMPILE);
1038
1039 LLVector3 c,r;
1040 c = LLVector3(0,0,0);
1041 r = LLVector3(1,1,1);
1042
1043 glBegin(GL_TRIANGLE_STRIP);
1044 //left front
1045 glVertex3fv((c+r.scaledVec(LLVector3(-1,1,-1))).mV);
1046 glVertex3fv((c+r.scaledVec(LLVector3(-1,1,1))).mV);
1047 //right front
1048 glVertex3fv((c+r.scaledVec(LLVector3(1,1,-1))).mV);
1049 glVertex3fv((c+r.scaledVec(LLVector3(1,1,1))).mV);
1050 //right back
1051 glVertex3fv((c+r.scaledVec(LLVector3(1,-1,-1))).mV);
1052 glVertex3fv((c+r.scaledVec(LLVector3(1,-1,1))).mV);
1053 //left back
1054 glVertex3fv((c+r.scaledVec(LLVector3(-1,-1,-1))).mV);
1055 glVertex3fv((c+r.scaledVec(LLVector3(-1,-1,1))).mV);
1056 //left front
1057 glVertex3fv((c+r.scaledVec(LLVector3(-1,1,-1))).mV);
1058 glVertex3fv((c+r.scaledVec(LLVector3(-1,1,1))).mV);
1059 glEnd();
1060
1061 //bottom
1062 glBegin(GL_TRIANGLE_STRIP);
1063 glVertex3fv((c+r.scaledVec(LLVector3(1,1,-1))).mV);
1064 glVertex3fv((c+r.scaledVec(LLVector3(1,-1,-1))).mV);
1065 glVertex3fv((c+r.scaledVec(LLVector3(-1,1,-1))).mV);
1066 glVertex3fv((c+r.scaledVec(LLVector3(-1,-1,-1))).mV);
1067 glEnd();
1068
1069 //top
1070 glBegin(GL_TRIANGLE_STRIP);
1071 glVertex3fv((c+r.scaledVec(LLVector3(1,1,1))).mV);
1072 glVertex3fv((c+r.scaledVec(LLVector3(-1,1,1))).mV);
1073 glVertex3fv((c+r.scaledVec(LLVector3(1,-1,1))).mV);
1074 glVertex3fv((c+r.scaledVec(LLVector3(-1,-1,1))).mV);
1075 glEnd();
1076
1077 glEndList();
1078}
1079
1080void LLSpatialPartition::restoreGL()
1081{
1082 LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
1083 mOcclusionQueries.clear();
1084 sBoxList = 0;
1085
1086 //generate query ids
1087 while (mOcclusionQueries.size() < mOccludedList.size())
1088 {
1089 GLuint id;
1090 glGenQueriesARB(1, &id);
1091 mOcclusionQueries.push_back(id);
1092 }
1093
1094 for (U32 i = 0; i < mOccludedList.size(); i++)
1095 { //previously issued queries are now invalid
1096 mOccludedList[i]->setState(LLSpatialGroup::DISCARD_QUERY);
1097 }
1098
1099 genBoxList();
1100}
1101
1102S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* results, BOOL for_select)
1103{
1104 LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
1105 {
1106 LLFastTimer ftm(LLFastTimer::FTM_CULL_REBOUND);
1107 LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0);
1108 group->rebound();
1109 }
1110
1111 if (for_select)
1112 {
1113 LLOctreeSelect selecter(&camera, results);
1114 selecter.traverse(mOctree);
1115 }
1116 else
1117 {
1118 LLOctreeCull culler(&camera);
1119 culler.traverse(mOctree);
1120 }
1121
1122 sIgnoreOcclusion = !(gSavedSettings.getBOOL("UseOcclusion") && gGLManager.mHasOcclusionQuery);
1123 return 0;
1124}
1125
1126class LLOctreeClearOccludedNotActive : public LLSpatialGroup::OctreeTraveler
1127{
1128public:
1129 LLOctreeClearOccludedNotActive() { }
1130
1131 virtual void traverse(const LLSpatialGroup::TreeNode* n)
1132 {
1133 LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
1134 if ((!group->isState(LLSpatialGroup::ACTIVE_OCCLUSION)) //|| group->isState(LLSpatialGroup::QUERY_PENDING)
1135 || group->isState(LLSpatialGroup::DEACTIVATE_OCCLUSION))
1136 { //the children are all occluded or culled as well
1137 group->clearState(LLSpatialGroup::OCCLUDED);
1138 for (U32 i = 0; i < group->mOctreeNode->getChildCount(); i++)
1139 {
1140 traverse(group->mOctreeNode->getChild(i));
1141 }
1142 }
1143 }
1144
1145 virtual void visit(const LLSpatialGroup::OctreeState* branch) { }
1146};
1147
1148class LLQueueNonCulled : public LLSpatialGroup::OctreeTraveler
1149{
1150public:
1151 std::queue<LLSpatialGroup*>* mQueue;
1152 LLQueueNonCulled(std::queue<LLSpatialGroup*> *queue) : mQueue(queue) { }
1153
1154 virtual void traverse(const LLSpatialGroup::TreeNode* n)
1155 {
1156 LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
1157 if (group->isState(LLSpatialGroup::OCCLUDED | LLSpatialGroup::CULLED))
1158 { //the children are all occluded or culled as well
1159 return;
1160 }
1161
1162 if (!group->isState(LLSpatialGroup::IN_QUEUE))
1163 {
1164 group->setState(LLSpatialGroup::IN_QUEUE);
1165 mQueue->push(group);
1166 }
1167
1168 LLSpatialGroup::OctreeTraveler::traverse(n);
1169 }
1170
1171 virtual void visit(const LLSpatialGroup::OctreeState* branch) { }
1172};
1173
1174BOOL earlyFail(LLCamera* camera, LLSpatialGroup* group)
1175{
1176 LLVector3 c = group->mBounds[0];
1177 LLVector3 r = group->mBounds[1] * (SG_OCCLUSION_FUDGE*2.f) + LLVector3(0.01f,0.01f,0.01f);
1178
1179 if (group->isState(LLSpatialGroup::CULLED) || !camera->AABBInFrustum(c, r))
1180 {
1181 return TRUE;
1182 }
1183
1184 LLVector3 e = camera->getOrigin();
1185
1186 LLVector3 min = c - r;
1187 LLVector3 max = c + r;
1188
1189 for (U32 j = 0; j < 3; j++)
1190 {
1191 if (e.mV[j] < min.mV[j] || e.mV[j] > max.mV[j])
1192 {
1193 return FALSE;
1194 }
1195 }
1196
1197 return TRUE;
1198}
1199
1200void LLSpatialPartition::processOcclusion(LLCamera* camera)
1201{
1202 LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
1203 LLSpatialGroup* rootGroup = (LLSpatialGroup*) mOctree->getListener(0);
1204 {
1205 LLFastTimer ftm(LLFastTimer::FTM_CULL_REBOUND);
1206 rootGroup->rebound();
1207 }
1208
1209 //update potentials
1210 if (!rootGroup->isState(LLSpatialGroup::IN_QUEUE))
1211 {
1212 rootGroup->setState(LLSpatialGroup::IN_QUEUE);
1213 mOcclusionQueue.push(rootGroup);
1214 }
1215
1216 const U32 MAX_PULLED = 32;
1217 const U32 MAX_PUSHED = mOcclusionQueue.size();
1218 U32 count = 0;
1219 U32 pcount = 0;
1220
1221 while (pcount < MAX_PUSHED && count < MAX_PULLED && !mOcclusionQueue.empty())
1222 {
1223 LLFastTimer t(LLFastTimer::FTM_OCCLUSION);
1224
1225 LLSpatialGroup* group = mOcclusionQueue.front();
1226 if (!group->isState(LLSpatialGroup::IN_QUEUE))
1227 {
1228 OCT_ERRS << "Spatial Group State Error. Group in queue not tagged as such." << llendl;
1229 }
1230
1231 mOcclusionQueue.pop();
1232 group->clearState(LLSpatialGroup::IN_QUEUE);
1233
1234 if (group->isDead())
1235 {
1236 if (group->safeToDelete())
1237 {
1238 delete group;
1239 }
1240 continue;
1241 }
1242
1243 if (group->isState(LLSpatialGroup::CULLED | LLSpatialGroup::OCCLUDED))
1244 { //already culled, skip it
1245 continue;
1246 }
1247
1248 //before we process, enqueue this group's children
1249 for (U32 i = 0; i < group->mOctreeNode->getChildCount(); i++)
1250 {
1251 LLSpatialGroup* child = (LLSpatialGroup*) group->mOctreeNode->getChild(i)->getListener(0);
1252
1253 if (!child->isState(LLSpatialGroup::OCCLUDED | LLSpatialGroup::CULLED)
1254 && !child->isState(LLSpatialGroup::IN_QUEUE | LLSpatialGroup::ACTIVE_OCCLUSION))
1255 {
1256 child->setState(LLSpatialGroup::IN_QUEUE);
1257 mOcclusionQueue.push(child);
1258 }
1259 }
1260
1261 /*if (group->isState(LLSpatialGroup::QUERY_PENDING))
1262 { //already on the pending group, put it back
1263 group->setState(LLSpatialGroup::IN_QUEUE);
1264 mOcclusionQueue.push(group);
1265 pcount++;
1266 continue;
1267 }*/
1268
1269 if (earlyFail(camera, group))
1270 {
1271 sg_assert(!group->isState(LLSpatialGroup::OCCLUDED));
1272 group->setState(LLSpatialGroup::IN_QUEUE);
1273 mOcclusionQueue.push(group);
1274 pcount++;
1275 continue;
1276 }
1277
1278 //add to pending queue
1279 if (!group->isState(LLSpatialGroup::ACTIVE_OCCLUSION))
1280 {
1281#if LL_OCTREE_PARANOIA_CHECK
1282 for (U32 i = 0; i < mOccludedList.size(); ++i)
1283 {
1284 sg_assert(mOccludedList[i] != group);
1285 }
1286#endif
1287 //group->setState(LLSpatialGroup::QUERY_PENDING);
1288 group->setState(LLSpatialGroup::ACTIVE_OCCLUSION);
1289 mQueryQueue.push(group);
1290 count++;
1291 }
1292 }
1293
1294 //read back results from last frame
1295 for (U32 i = 0; i < mOccludedList.size(); i++)
1296 {
1297 LLFastTimer t(LLFastTimer::FTM_OCCLUSION_READBACK);
1298
1299 if (mOccludedList[i]->isDead() || !mOccludedList[i]->isState(LLSpatialGroup::ACTIVE_OCCLUSION))
1300 {
1301 continue;
1302 }
1303 GLuint res = 0;
1304
1305 if (mOccludedList[i]->isState(LLSpatialGroup::EARLY_FAIL | LLSpatialGroup::DISCARD_QUERY) ||
1306 !mOccludedList[i]->isState(LLSpatialGroup::QUERY_OUT))
1307 {
1308 mOccludedList[i]->clearState(LLSpatialGroup::EARLY_FAIL);
1309 mOccludedList[i]->clearState(LLSpatialGroup::DISCARD_QUERY);
1310 res = 1;
1311 }
1312 else
1313 {
1314 glGetQueryObjectuivARB(mOcclusionQueries[i], GL_QUERY_RESULT_ARB, &res);
1315 stop_glerror();
1316 }
1317
1318 if (res) //NOT OCCLUDED
1319 {
1320 if (mOccludedList[i]->isState(LLSpatialGroup::OCCLUDED))
1321 { //this node was occluded last frame
1322 LLSpatialGroup::OctreeNode* node = mOccludedList[i]->mOctreeNode;
1323 //add any immediate children to the queue that are not already there
1324 for (U32 j = 0; j < node->getChildCount(); j++)
1325 {
1326 LLSpatialGroup* group = (LLSpatialGroup*) node->getChild(j)->getListener(0);
1327 checkOcclusion(group, camera);
1328 }
1329 }
1330
1331 //clear occlusion status for everything not on the active list
1332 LLOctreeClearOccludedNotActive clear_occluded;
1333 mOccludedList[i]->setState(LLSpatialGroup::DEACTIVATE_OCCLUSION);
1334 mOccludedList[i]->clearState(LLSpatialGroup::OCCLUDED);
1335 mOccludedList[i]->clearState(LLSpatialGroup::OCCLUDING);
1336 clear_occluded.traverse(mOccludedList[i]->mOctreeNode);
1337 }
1338 else
1339 { //OCCLUDED
1340 if (mOccludedList[i]->isState(LLSpatialGroup::OCCLUDING))
1341 {
1342 if (!mOccludedList[i]->isState(LLSpatialGroup::OCCLUDED))
1343 {
1344 LLSpatialGroup::OctreeNode* oct_parent = (LLSpatialGroup::OctreeNode*) mOccludedList[i]->mOctreeNode->getParent();
1345 if (oct_parent)
1346 {
1347 LLSpatialGroup* parent = (LLSpatialGroup*) oct_parent->getListener(0);
1348
1349 if (checkOcclusion(parent, camera))
1350 { //force a guess on the parent and siblings
1351
1352 for (U32 i = 0; i < parent->mOctreeNode->getChildCount(); i++)
1353 {
1354 LLSpatialGroup* child = (LLSpatialGroup*) parent->mOctreeNode->getChild(i)->getListener(0);
1355 checkOcclusion(child, camera);
1356 }
1357 }
1358 }
1359 }
1360 mOccludedList[i]->setState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
1361 }
1362 else
1363 {
1364 //take children off the active list
1365 mOccludedList[i]->setState(LLSpatialGroup::DEACTIVATE_OCCLUSION, LLSpatialGroup::STATE_MODE_DIFF);
1366
1367 //keep this node on the active list
1368 mOccludedList[i]->clearState(LLSpatialGroup::DEACTIVATE_OCCLUSION);
1369
1370 //this node is a top level occluder
1371 mOccludedList[i]->setState(LLSpatialGroup::OCCLUDING);
1372 }
1373 }
1374
1375 mOccludedList[i]->clearState(LLSpatialGroup::QUERY_OUT);
1376 }
1377
1378 //remove non-occluded groups from occluded list
1379 for (U32 i = 0; i < mOccludedList.size(); )
1380 {
1381 if (mOccludedList[i]->isDead() || //needs to be deleted
1382 !mOccludedList[i]->isState(LLSpatialGroup::OCCLUDING) || //is not occluding
1383 mOccludedList[i]->isState(LLSpatialGroup::DEACTIVATE_OCCLUSION)) //parent is occluded
1384 {
1385 LLSpatialGroup* groupp = mOccludedList[i];
1386 mOccludedList.erase(mOccludedList.begin()+i);
1387 groupp->clearState(LLSpatialGroup::ACTIVE_OCCLUSION);
1388 groupp->clearState(LLSpatialGroup::DEACTIVATE_OCCLUSION);
1389 groupp->clearState(LLSpatialGroup::OCCLUDING);
1390
1391 if (groupp->isDead() && groupp->safeToDelete())
1392 {
1393 delete groupp;
1394 }
1395 }
1396 else
1397 {
1398 i++;
1399 }
1400 }
1401
1402 //pump some non-culled items onto the occlusion list
1403 //count = MAX_PULLED;
1404 while (!mQueryQueue.empty())
1405 {
1406 LLSpatialGroup* group = mQueryQueue.front();
1407 mQueryQueue.pop();
1408 //group->clearState(LLSpatialGroup::QUERY_PENDING);
1409 mOccludedList.push_back(group);
1410 }
1411
1412 //generate query ids
1413 while (mOcclusionQueries.size() < mOccludedList.size())
1414 {
1415 GLuint id;
1416 glGenQueriesARB(1, &id);
1417 mOcclusionQueries.push_back(id);
1418 }
1419}
1420
1421void LLSpatialPartition::doOcclusion(LLCamera* camera)
1422{
1423 LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
1424
1425 sIgnoreOcclusion = gUseWireframe;
1426 LLFastTimer t(LLFastTimer::FTM_RENDER_OCCLUSION);
1427
1428#if LL_OCTREE_PARANOIA_CHECK
1429 LLSpatialGroup* check = (LLSpatialGroup*) mOctree->getListener(0);
1430 check->validate();
1431#endif
1432
1433 stop_glerror();
1434
1435 //actually perform the occlusion queries
1436 LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
1437 glDisable(GL_TEXTURE_2D);
1438 gPipeline.disableLights();
1439 LLGLEnable cull_face(GL_CULL_FACE);
1440 LLGLDisable blend(GL_BLEND);
1441 LLGLDisable alpha_test(GL_ALPHA_TEST);
1442 LLGLDisable fog(GL_FOG);
1443 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
1444 glColor4f(1,1,1,1);
1445
1446 //sort occlusion queries front to back
1447 /*for (U32 i = 0; i < mOccludedList.size(); i++)
1448 {
1449 LLSpatialGroup* group = mOccludedList[i];
1450
1451 LLVector3 v = group->mOctreeNode->getCenter()-camera->getOrigin();
1452 group->mDistance = v*v;
1453 }
1454
1455 std::sort(mOccludedList.begin(), mOccludedList.end(), dist_greater());
1456
1457 glClearStencil(0);
1458 glClear(GL_STENCIL_BUFFER_BIT);
1459 LLGLEnable stencil(GL_STENCIL_TEST);
1460 glStencilFunc(GL_GREATER, 1, 0xFFFFFFFF);
1461 glStencilOp(GL_KEEP, GL_SET, GL_KEEP);*/
1462
1463 genBoxList();
1464
1465 for (U32 i = 0; i < mOccludedList.size(); i++)
1466 {
1467#if LL_OCTREE_PARANOIA_CHECK
1468 for (U32 j = i+1; j < mOccludedList.size(); j++)
1469 {
1470 sg_assert(mOccludedList[i] != mOccludedList[j]);
1471 }
1472#endif
1473 LLSpatialGroup* group = mOccludedList[i];
1474 if (group->isDead())
1475 {
1476 continue;
1477 }
1478
1479 if (earlyFail(camera, group))
1480 {
1481 group->setState(LLSpatialGroup::EARLY_FAIL);
1482 }
1483 else
1484 { //early rejection criteria passed, send some geometry to the query
1485 LLVector3 c;
1486 LLVector3 r;
1487
1488 sg_assert(!group->isState(LLSpatialGroup::DIRTY));
1489
1490 c = group->mBounds[0];
1491 r = group->mBounds[1]*SG_OCCLUSION_FUDGE + LLVector3(0.01f,0.01f,0.01f);
1492 for (U32 k = 0; k < 3; k++)
1493 {
1494 r.mV[k] = llmin(group->mBounds[1].mV[k]+0.25f, r.mV[k]);
1495 }
1496
1497#if LL_OCTREE_PARANOIA_CHECK
1498 LLVector3 e = camera->getOrigin();
1499 LLVector3 min = c - r;
1500 LLVector3 max = c + r;
1501 BOOL outside = FALSE;
1502 for (U32 j = 0; j < 3; j++)
1503 {
1504 outside = outside || (e.mV[j] < min.mV[j] || e.mV[j] > max.mV[j]);
1505 }
1506 sg_assert(outside);
1507#endif
1508
1509 glBeginQueryARB(GL_SAMPLES_PASSED_ARB, mOcclusionQueries[i]);
1510 drawBox(c,r);
1511 glEndQueryARB(GL_SAMPLES_PASSED_ARB);
1512
1513 group->setState(LLSpatialGroup::QUERY_OUT);
1514 group->clearState(LLSpatialGroup::DISCARD_QUERY);
1515 }
1516 }
1517 stop_glerror();
1518
1519 glFlush();
1520
1521 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1522 glEnable(GL_TEXTURE_2D);
1523}
1524
1525class LLOctreeGet : public LLSpatialGroup::OctreeTraveler
1526{
1527public:
1528 LLOctreeGet(LLVector3 pos, F32 rad, LLDrawable::drawable_set_t* results, BOOL lights)
1529 : mPosition(pos), mRad(rad), mResults(results), mLights(lights), mRes(0)
1530 {
1531
1532 }
1533
1534 virtual void traverse(const LLSpatialGroup::TreeNode* n)
1535 {
1536 LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
1537
1538 if (mRes == 2)
1539 { //fully in, just add everything
1540 LLSpatialGroup::OctreeTraveler::traverse(n);
1541 }
1542 else
1543 {
1544 LLVector3 center, size;
1545
1546 center = group->mBounds[0];
1547 size = group->mBounds[1];
1548
1549 mRes = LLSphereAABB(center, size, mPosition, mRad);
1550 if (mRes > 0)
1551 {
1552 LLSpatialGroup::OctreeTraveler::traverse(n);
1553 }
1554 mRes = 0;
1555 }
1556 }
1557
1558 static BOOL skip(LLDrawable* drawable, BOOL get_lights)
1559 {
1560 if (get_lights != drawable->isLight())
1561 {
1562 return TRUE;
1563 }
1564 if (get_lights && drawable->getVObj()->isHUDAttachment())
1565 {
1566 return TRUE; // no lighting from HUD objects
1567 }
1568 if (get_lights && drawable->isState(LLDrawable::ACTIVE))
1569 {
1570 return TRUE; // ignore active lights
1571 }
1572 return FALSE;
1573 }
1574
1575 virtual void visit(const LLSpatialGroup::OctreeState* branch)
1576 {
1577 for (LLSpatialGroup::OctreeState::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i)
1578 {
1579 LLDrawable* drawable = *i;
1580 if (!skip(drawable, mLights))
1581 {
1582 if (mRes == 2)
1583 {
1584 mResults->insert(drawable);
1585 }
1586 else
1587 {
1588 LLVector3 v = LLVector3(drawable->getPositionGroup())-mPosition;
1589 float dsq = v.magVecSquared();
1590 float maxd = mRad + drawable->getVisibilityRadius();
1591 if (dsq <= maxd*maxd)
1592 {
1593 mResults->insert(drawable);
1594 }
1595 }
1596 }
1597 }
1598 }
1599
1600 LLVector3 mPosition;
1601 F32 mRad;
1602 LLDrawable::drawable_set_t* mResults;
1603 BOOL mLights;
1604 U32 mRes;
1605};
1606
1607S32 LLSpatialPartition::getDrawables(const LLVector3& pos, F32 rad,
1608 LLDrawable::drawable_set_t &results,
1609 BOOL get_lights)
1610{
1611 LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
1612
1613 LLOctreeGet getter(pos, rad, &results, get_lights);
1614 getter.traverse(mOctree);
1615
1616 return results.size();
1617}
1618
1619S32 LLSpatialPartition::getObjects(const LLVector3& pos, F32 rad, LLDrawable::drawable_set_t &results)
1620{
1621 return getDrawables(pos, rad, results, FALSE);
1622}
1623
1624S32 LLSpatialPartition::getLights(const LLVector3& pos, F32 rad, LLDrawable::drawable_set_t &results)
1625{
1626 return getDrawables(pos, rad, results, TRUE);
1627}
1628
1629class LLOctreeRenderNonOccluded : public LLOctreeTraveler<LLDrawable>
1630{
1631public:
1632 LLOctreeRenderNonOccluded() {}
1633
1634 virtual void traverse(const LLSpatialGroup::OctreeNode* node)
1635 {
1636 const LLSpatialGroup::OctreeState* state = node->getOctState();
1637 LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
1638
1639 if (!group->isState(LLSpatialGroup::OCCLUDED | LLSpatialGroup::CULLED))
1640 {
1641 state->accept(this);
1642
1643 for (U32 i = 0; i < state->getChildCount(); i++)
1644 {
1645 traverse(state->getChild(i));
1646 }
1647
1648 /*if (state->getElementCount() == 0)
1649 {
1650 return;
1651 }*/
1652
1653 //draw tight fit bounding box for spatial group
1654 if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCTREE))
1655 {
1656 if (node->getElementCount() == 0)
1657 {
1658 return;
1659 }
1660
1661 if (node->hasLeafState())
1662 {
1663 glColor4f(1,1,1,1);
1664 }
1665 else
1666 {
1667 glColor4f(0,1,1,1);
1668 }
1669
1670
1671 LLVector3 pos;
1672 LLVector3 size;
1673
1674 pos = group->mObjectBounds[0];
1675 size = group->mObjectBounds[1];
1676
1677 LLVector3 v1 = size.scaledVec(LLVector3( 1, 1,1));
1678 LLVector3 v2 = size.scaledVec(LLVector3(-1, 1,1));
1679 LLVector3 v3 = size.scaledVec(LLVector3(-1,-1,1));
1680 LLVector3 v4 = size.scaledVec(LLVector3( 1,-1,1));
1681
1682 glBegin(GL_LINE_LOOP); //top
1683 glVertex3fv((pos+v1).mV);
1684 glVertex3fv((pos+v2).mV);
1685 glVertex3fv((pos+v3).mV);
1686 glVertex3fv((pos+v4).mV);
1687 glEnd();
1688
1689 glBegin(GL_LINE_LOOP); //bottom
1690 glVertex3fv((pos-v1).mV);
1691 glVertex3fv((pos-v2).mV);
1692 glVertex3fv((pos-v3).mV);
1693 glVertex3fv((pos-v4).mV);
1694 glEnd();
1695
1696
1697 glBegin(GL_LINES);
1698
1699 //right
1700 glVertex3fv((pos+v1).mV);
1701 glVertex3fv((pos-v3).mV);
1702
1703 glVertex3fv((pos+v4).mV);
1704 glVertex3fv((pos-v2).mV);
1705
1706 //left
1707 glVertex3fv((pos+v2).mV);
1708 glVertex3fv((pos-v4).mV);
1709
1710 glVertex3fv((pos+v3).mV);
1711 glVertex3fv((pos-v1).mV);
1712
1713 glEnd();
1714
1715 LLVector3 nc = LLVector3(node->getCenter());
1716 LLVector3 ns = LLVector3(node->getSize());
1717
1718 LLVector3 nv1 = ns.scaledVec(LLVector3( 1, 1,1));
1719 LLVector3 nv2 = ns.scaledVec(LLVector3(-1, 1,1));
1720 LLVector3 nv3 = ns.scaledVec(LLVector3(-1,-1,1));
1721 LLVector3 nv4 = ns.scaledVec(LLVector3( 1,-1,1));
1722
1723
1724
1725 /*if (node->getElementCount() > 0)
1726 {
1727 //spokes
1728 glColor4f(1,1,0,1);
1729 glVertex3fv(pos.mV);
1730 glColor4f(1,1,0,0);
1731 glVertex3fv(nc.mV);
1732
1733 glColor4f(1,1,0,1); glVertex3fv((pos+v1).mV); glColor4f(1,1,0,0); glVertex3fv(pos.mV);
1734 glColor4f(1,1,0,1); glVertex3fv((pos-v1).mV); glColor4f(1,1,0,0); glVertex3fv(pos.mV);
1735 glColor4f(1,1,0,1); glVertex3fv((pos+v2).mV); glColor4f(1,1,0,0); glVertex3fv(pos.mV);
1736 glColor4f(1,1,0,1); glVertex3fv((pos-v2).mV); glColor4f(1,1,0,0); glVertex3fv(pos.mV);
1737 glColor4f(1,1,0,1); glVertex3fv((pos+v3).mV); glColor4f(1,1,0,0); glVertex3fv(pos.mV);
1738 glColor4f(1,1,0,1); glVertex3fv((pos-v3).mV); glColor4f(1,1,0,0); glVertex3fv(pos.mV);
1739 glColor4f(1,1,0,1); glVertex3fv((pos+v4).mV); glColor4f(1,1,0,0); glVertex3fv(pos.mV);
1740 glColor4f(1,1,0,1); glVertex3fv((pos-v4).mV); glColor4f(1,1,0,0); glVertex3fv(pos.mV);
1741 }*/
1742
1743
1744
1745 /*glColor4f(0,1,0,1);
1746 glBegin(GL_LINE_LOOP); //top
1747 glVertex3fv((nc+nv1).mV);
1748 glVertex3fv((nc+nv2).mV);
1749 glVertex3fv((nc+nv3).mV);
1750 glVertex3fv((nc+nv4).mV);
1751 glEnd();
1752
1753 glBegin(GL_LINE_LOOP); //bottom
1754 glVertex3fv((nc-nv1).mV);
1755 glVertex3fv((nc-nv2).mV);
1756 glVertex3fv((nc-nv3).mV);
1757 glVertex3fv((nc-nv4).mV);
1758 glEnd();
1759
1760
1761 glBegin(GL_LINES);
1762
1763 //right
1764 glVertex3fv((nc+nv1).mV);
1765 glVertex3fv((nc-nv3).mV);
1766
1767 glVertex3fv((nc+nv4).mV);
1768 glVertex3fv((nc-nv2).mV);
1769
1770 //left
1771 glVertex3fv((nc+nv2).mV);
1772 glVertex3fv((nc-nv4).mV);
1773
1774 glVertex3fv((nc+nv3).mV);
1775 glVertex3fv((nc-nv1).mV);
1776 glEnd();*/
1777
1778 glLineWidth(1);
1779
1780 glDepthMask(GL_FALSE);
1781 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
1782 glColor4f(0.1f,0.1f,1,0.1f);
1783 drawBox(group->mObjectBounds[0], group->mObjectBounds[1]*1.01f+LLVector3(0.001f, 0.001f, 0.001f));
1784 glDepthMask(GL_TRUE);
1785 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1786 }
1787 }
1788 /*else
1789 {
1790 //occlusion paranoia check
1791 const LLSpatialGroup::OctreeNode* parent = node;
1792 while (parent != NULL)
1793 {
1794 LLSpatialGroup* grp = (LLSpatialGroup*) parent->getListener(0);
1795 if (grp->isState(LLSpatialGroup::ACTIVE_OCCLUSION))
1796 {
1797 return;
1798 }
1799 parent = (const LLSpatialGroup::OctreeNode*) parent->getParent();
1800 }
1801
1802 glColor4f(1,0,1,1);
1803 drawBox(group->mBounds[0], group->mBounds[1]);
1804 }*/
1805 }
1806
1807 virtual void visit(const LLSpatialGroup::OctreeState* branch)
1808 {
1809 LLSpatialGroup* group = (LLSpatialGroup*) branch->getListener(0);
1810
1811 if (group->isState(LLSpatialGroup::CULLED | LLSpatialGroup::OCCLUDED))
1812 {
1813 return;
1814 }
1815
1816 LLVector3 nodeCenter = group->mBounds[0];
1817 LLVector3 octCenter = LLVector3(group->mOctreeNode->getCenter());
1818
1819 if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCTREE))
1820 {
1821 glBegin(GL_LINES);
1822 glColor4f(1,0.5f,0,1);
1823 glVertex3fv(nodeCenter.mV);
1824 glColor4f(0,1,1,0);
1825 glVertex3fv(octCenter.mV);
1826 glEnd();
1827 }
1828
1829 for (LLSpatialGroup::OctreeState::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i)
1830 {
1831 LLDrawable* drawable = *i;
1832
1833 if (drawable->isSpatialBridge())
1834 {
1835 LLSpatialBridge* bridge = (LLSpatialBridge*) drawable;
1836 glPushMatrix();
1837 glMultMatrixf((F32*)bridge->mDrawable->getWorldMatrix().mMatrix);
1838 traverse(bridge->mOctree);
1839 glPopMatrix();
1840 }
1841
1842 if (!drawable->isVisible())
1843 {
1844 continue;
1845 }
1846
1847 if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BBOXES))
1848 {
1849 if (drawable->isSpatialBridge())
1850 {
1851 glColor4f(1,0.5f,0,1);
1852 }
1853 else if (drawable->getVOVolume())
1854 {
1855 if (drawable->isRoot())
1856 {
1857 glColor4f(1,1,0,1);
1858 }
1859 else
1860 {
1861 glColor4f(0,1,0,1);
1862 }
1863 }
1864 else if (drawable->getVObj())
1865 {
1866 switch (drawable->getVObj()->getPCode())
1867 {
1868 case LLViewerObject::LL_VO_SURFACE_PATCH:
1869 glColor4f(0,1,1,1);
1870 break;
1871 case LLViewerObject::LL_VO_CLOUDS:
1872 glColor4f(0.5f,0.5f,0.5f,1.0f);
1873 break;
1874 case LLViewerObject::LL_VO_PART_GROUP:
1875 glColor4f(0,0,1,1);
1876 break;
1877 case LLViewerObject::LL_VO_WATER:
1878 glColor4f(0,0.5f,1,1);
1879 break;
1880 case LL_PCODE_LEGACY_TREE:
1881 glColor4f(0,0.5f,0,1);
1882 default:
1883 glColor4f(1,0,1,1);
1884 break;
1885 }
1886 }
1887 else
1888 {
1889 glColor4f(1,0,0,1);
1890 }
1891
1892
1893 const LLVector3* ext = drawable->getSpatialExtents();
1894
1895 LLVector3 pos = (ext[0] + ext[1]) * 0.5f;
1896 LLVector3 size = (ext[1] - ext[0]) * 0.5f;
1897
1898 LLVector3 v1 = size.scaledVec(LLVector3( 1, 1,1));
1899 LLVector3 v2 = size.scaledVec(LLVector3(-1, 1,1));
1900 LLVector3 v3 = size.scaledVec(LLVector3(-1,-1,1));
1901 LLVector3 v4 = size.scaledVec(LLVector3( 1,-1,1));
1902
1903 glBegin(GL_LINE_LOOP); //top
1904 glVertex3fv((pos+v1).mV);
1905 glVertex3fv((pos+v2).mV);
1906 glVertex3fv((pos+v3).mV);
1907 glVertex3fv((pos+v4).mV);
1908 glEnd();
1909
1910 glBegin(GL_LINE_LOOP); //bottom
1911 glVertex3fv((pos-v1).mV);
1912 glVertex3fv((pos-v2).mV);
1913 glVertex3fv((pos-v3).mV);
1914 glVertex3fv((pos-v4).mV);
1915 glEnd();
1916
1917
1918 glBegin(GL_LINES);
1919
1920 //right
1921 glVertex3fv((pos+v1).mV);
1922 glVertex3fv((pos-v3).mV);
1923
1924 glVertex3fv((pos+v4).mV);
1925 glVertex3fv((pos-v2).mV);
1926
1927 //left
1928 glVertex3fv((pos+v2).mV);
1929 glVertex3fv((pos-v4).mV);
1930
1931 glVertex3fv((pos+v3).mV);
1932 glVertex3fv((pos-v1).mV);
1933
1934 glEnd();
1935
1936 //render space partition trace
1937 glBegin(GL_LINE_STRIP);
1938 glColor4f(1,0,0,1);
1939 glVertex3fv(pos.mV);
1940 glColor4f(0,1,0,1);
1941 glVertex3dv(drawable->getPositionGroup().mdV);
1942 glColor4f(0,0,1,1);
1943 glVertex3fv(nodeCenter.mV);
1944 glColor4f(1,1,0,1);
1945 glVertex3fv(octCenter.mV);
1946 glEnd();
1947 }
1948
1949 if (drawable->getVOVolume() && gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_FACE_CHAINS | LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY))
1950 {
1951 glLineWidth(3);
1952
1953 for (int face=0; face<drawable->getNumFaces(); ++face)
1954 {
1955 LLFace *facep = drawable->getFace(face);
1956
1957 if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_FACE_CHAINS))
1958 {
1959 LLGLDepthTest depth(GL_FALSE);
1960 if (facep->mNextFace)
1961 {
1962 glBegin(GL_LINE_STRIP);
1963
1964 if (facep->isState(LLFace::GLOBAL))
1965 {
1966 glColor4f(0,1,0,1);
1967 }
1968 else
1969 {
1970 glColor4f(1,0.5f,0.25f,1);
1971 }
1972
1973 if (drawable->isActive())
1974 {
1975 glVertex3fv(facep->mCenterLocal.mV);
1976 glVertex3fv(facep->mNextFace->mCenterLocal.mV);
1977 }
1978 else
1979 {
1980 glVertex3fv(facep->mCenterAgent.mV);
1981 glVertex3fv(facep->mNextFace->mCenterAgent.mV);
1982 }
1983
1984 glEnd();
1985 }
1986 else
1987 {
1988 glPointSize(5);
1989 glBegin(GL_POINTS);
1990
1991 if (!facep->isState(LLFace::GLOBAL))
1992 {
1993 glColor4f(1,0.75f,0,1);
1994 glVertex3fv(facep->mCenterLocal.mV);
1995 }
1996 else
1997 {
1998 glColor4f(0,0.75f,1,1);
1999 glVertex3fv(facep->mCenterAgent.mV);
2000 }
2001
2002 glEnd();
2003 glPointSize(1);
2004 }
2005 }
2006
2007 if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY))
2008 {
2009 LLVector4 cold(0,0,0.25f);
2010 LLVector4 hot(1,0.25f,0.25f);
2011
2012 LLVector4 boost_cold(0,0,0,0);
2013 LLVector4 boost_hot(0,1,0,1);
2014
2015 LLGLDisable blend(GL_BLEND);
2016
2017 LLViewerImage* imagep = facep->getTexture();
2018 if (imagep)
2019 {
2020
2021 //F32 vsize = LLVOVolume::getTextureVirtualSize(facep);
2022 F32 vsize = imagep->mMaxVirtualSize;
2023
2024 if (vsize > sCurMaxTexPriority)
2025 {
2026 sCurMaxTexPriority = vsize;
2027 }
2028
2029 F32 t = vsize/sLastMaxTexPriority;
2030
2031 LLVector4 col = lerp(cold, hot, t);
2032 glColor4fv(col.mV);
2033 }
2034 else
2035 {
2036 glColor4f(1,0,1,1);
2037 }
2038
2039 LLVector3 center = (facep->mExtents[1]+facep->mExtents[0])*0.5f;
2040 LLVector3 size = (facep->mExtents[1]-facep->mExtents[0])*0.5f + LLVector3(0.01f, 0.01f, 0.01f);
2041 drawBox(center, size);
2042
2043 S32 boost = imagep->getBoostLevel();
2044 if (boost)
2045 {
2046 F32 t = (F32) boost / (F32) (LLViewerImage::BOOST_MAX_LEVEL-1);
2047 LLVector4 col = lerp(boost_cold, boost_hot, t);
2048 LLGLEnable blend_on(GL_BLEND);
2049 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
2050 glColor4fv(col.mV);
2051 drawBox(center, size);
2052 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2053 }
2054
2055 }
2056 }
2057 }
2058
2059 if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_POINTS))
2060 {
2061 glPointSize(4);
2062 glColor4f(1,1,1,1);
2063 glBegin(GL_POINTS);
2064 S32 num_faces = drawable->getNumFaces();
2065 for (S32 i = 0; i < num_faces; i++)
2066 {
2067 LLStrider<LLVector3> vertices;
2068 drawable->getFace(i)->getVertices(vertices);
2069
2070 LLFace* face = drawable->getFace(i);
2071
2072 for (S32 v = 0; v < (S32)drawable->getFace(i)->getGeomCount(); v++)
2073 {
2074 if (!face->getDrawable()->isActive())
2075 {
2076 //glVertex3fv(vertices[v].mV);
2077 }
2078 else
2079 {
2080 glVertex3fv((vertices[v]*face->getRenderMatrix()).mV);
2081 }
2082 }
2083 }
2084 glEnd();
2085 glPointSize(1);
2086 }
2087
2088 glLineWidth(1);
2089 }
2090 }
2091};
2092
2093void LLSpatialPartition::renderDebug()
2094{
2095 if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCTREE |
2096 LLPipeline::RENDER_DEBUG_OCCLUSION |
2097 LLPipeline::RENDER_DEBUG_BBOXES |
2098 LLPipeline::RENDER_DEBUG_POINTS |
2099 LLPipeline::RENDER_DEBUG_FACE_CHAINS |
2100 LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY))
2101 {
2102 return;
2103 }
2104
2105 if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY))
2106 {
2107 //sLastMaxTexPriority = lerp(sLastMaxTexPriority, sCurMaxTexPriority, gFrameIntervalSeconds);
2108 sLastMaxTexPriority = sCurMaxTexPriority;
2109 sCurMaxTexPriority = 0.f;
2110 }
2111
2112 LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
2113
2114 LLGLDisable cullface(GL_CULL_FACE);
2115 LLGLEnable blend(GL_BLEND);
2116 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2117 LLGLDisable tex(GL_TEXTURE_2D);
2118 gPipeline.disableLights();
2119
2120 LLOctreeRenderNonOccluded render_debug;
2121 render_debug.traverse(mOctree);
2122
2123 LLGLDisable cull_face(GL_CULL_FACE);
2124
2125 {
2126 LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
2127
2128 //draw frustum
2129 glColor4f(0,0,1,0.5f);
2130 glBegin(GL_QUADS);
2131 //glVertex3fv(gCamera->mAgentFrustum[0].mV);
2132 //glVertex3fv(gCamera->mAgentFrustum[1].mV);
2133 //glVertex3fv(gCamera->mAgentFrustum[2].mV);
2134 //glVertex3fv(gCamera->mAgentFrustum[3].mV);
2135
2136 //glVertex3fv(gCamera->mAgentFrustum[4].mV);
2137 //glVertex3fv(gCamera->mAgentFrustum[5].mV);
2138 //glVertex3fv(gCamera->mAgentFrustum[6].mV);
2139 //glVertex3fv(gCamera->mAgentFrustum[7].mV);
2140
2141 glVertex3fv(gCamera->mAgentFrustum[0].mV);
2142 glVertex3fv(gCamera->mAgentFrustum[1].mV);
2143 glVertex3fv(gCamera->mAgentFrustum[5].mV);
2144 glVertex3fv(gCamera->mAgentFrustum[4].mV);
2145
2146 glVertex3fv(gCamera->mAgentFrustum[1].mV);
2147 glVertex3fv(gCamera->mAgentFrustum[2].mV);
2148 glVertex3fv(gCamera->mAgentFrustum[6].mV);
2149 glVertex3fv(gCamera->mAgentFrustum[5].mV);
2150
2151 glVertex3fv(gCamera->mAgentFrustum[2].mV);
2152 glVertex3fv(gCamera->mAgentFrustum[3].mV);
2153 glVertex3fv(gCamera->mAgentFrustum[7].mV);
2154 glVertex3fv(gCamera->mAgentFrustum[6].mV);
2155
2156 glVertex3fv(gCamera->mAgentFrustum[3].mV);
2157 glVertex3fv(gCamera->mAgentFrustum[0].mV);
2158 glVertex3fv(gCamera->mAgentFrustum[4].mV);
2159 glVertex3fv(gCamera->mAgentFrustum[7].mV);
2160
2161 glEnd();
2162 }
2163
2164 if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION))
2165 {
2166 LLGLDisable fog(GL_FOG);
2167 LLGLDepthTest gls_depth(GL_FALSE);
2168 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
2169
2170 for (std::vector<LLSpatialGroup*>::iterator i = mOccludedList.begin(); i != mOccludedList.end(); ++i)
2171 { //draw occluded nodes
2172 LLSpatialGroup* node = *i;
2173 if (node->isDead())
2174 {
2175 continue;
2176 }
2177 if (!node->isState(LLSpatialGroup::OCCLUDED))
2178 {
2179 continue;
2180 }
2181 else
2182 {
2183 glColor4f(0.25f,0.125f,0.1f,0.125f);
2184 }
2185 LLVector3 c;
2186 LLVector3 r;
2187
2188 c = node->mBounds[0];
2189 r = node->mBounds[1]*SG_OCCLUSION_FUDGE + LLVector3(0.01f,0.01f,0.01f);;
2190
2191 drawBox(c,r);
2192 }
2193 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2194 }
2195}
2196
2197
2198BOOL LLSpatialPartition::isVisible(const LLVector3& v)
2199{
2200 if (!gCamera->sphereInFrustum(v, 4.0f))
2201 {
2202 return FALSE;
2203 }
2204
2205 return TRUE;
2206}
2207
2208class LLOctreePick : public LLSpatialGroup::OctreeTraveler
2209{
2210public:
2211 LLVector3 mStart;
2212 LLVector3 mEnd;
2213 LLDrawable* mRet;
2214
2215 LLOctreePick(LLVector3 start, LLVector3 end)
2216 : mStart(start), mEnd(end)
2217 {
2218 mRet = NULL;
2219 }
2220
2221 virtual LLDrawable* check(const LLSpatialGroup::OctreeNode* node)
2222 {
2223 const LLSpatialGroup::OctreeState* state = node->getOctState();
2224 state->accept(this);
2225
2226 for (U32 i = 0; i < node->getChildCount(); i++)
2227 {
2228 const LLSpatialGroup::OctreeNode* child = node->getChild(i);
2229 LLVector3 res;
2230
2231 LLSpatialGroup* group = (LLSpatialGroup*) child->getListener(0);
2232
2233 LLVector3 size;
2234 LLVector3 center;
2235
2236 size = group->mBounds[1];
2237 center = group->mBounds[0];
2238
2239 if (LLLineSegmentAABB(mStart, mEnd, center, size))
2240 {
2241 check(child);
2242 }
2243 }
2244
2245 return mRet;
2246 }
2247
2248 virtual void visit(const LLSpatialGroup::OctreeState* branch)
2249 {
2250 for (LLSpatialGroup::OctreeState::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i)
2251 {
2252 check(*i);
2253 }
2254 }
2255
2256 virtual bool check(LLDrawable* drawable)
2257 {
2258 LLViewerObject* vobj = drawable->getVObj();
2259 if (vobj->lineSegmentIntersect(mStart, mEnd))
2260 {
2261 mRet = vobj->mDrawable;
2262 }
2263
2264 return false;
2265 }
2266};
2267
2268LLDrawable* LLSpatialPartition::pickDrawable(const LLVector3& start, const LLVector3& end, LLVector3& collision)
2269{
2270 LLOctreePick pick(start, end);
2271 LLDrawable* ret = pick.check(mOctree);
2272 collision.setVec(pick.mEnd);
2273 return ret;
2274}