diff options
Diffstat (limited to 'linden/indra/newview/llspatialpartition.cpp')
-rw-r--r-- | linden/indra/newview/llspatialpartition.cpp | 2274 |
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 | |||
43 | static BOOL sIgnoreOcclusion = TRUE; | ||
44 | static GLuint sBoxList = 0; | ||
45 | |||
46 | const S32 SG_LOD_SWITCH_STAGGER = 4; | ||
47 | const F32 SG_MAX_OBJ_RAD = 1.f; | ||
48 | const F32 SG_OCCLUSION_FUDGE = 1.1f; | ||
49 | const S32 SG_MOVE_PERIOD = 32; | ||
50 | const 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 | |||
60 | static F32 sLastMaxTexPriority = 1.f; | ||
61 | static F32 sCurMaxTexPriority = 1.f; | ||
62 | |||
63 | //static counter for frame to switch LOD on | ||
64 | S32 LLSpatialGroup::sLODSeed = 0; | ||
65 | |||
66 | void 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 | ||
77 | void 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 | |||
92 | BOOL earlyFail(LLCamera* camera, LLSpatialGroup* group); | ||
93 | |||
94 | BOOL 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 | |||
121 | S32 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 | |||
145 | LLSpatialGroup::~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 | |||
168 | BOOL LLSpatialGroup::safeToDelete() | ||
169 | { | ||
170 | return gQuit || !isState(IN_QUEUE | ACTIVE_OCCLUSION | RESHADOW_QUEUE); | ||
171 | } | ||
172 | |||
173 | class LLRelightPainter : public LLSpatialGroup::OctreeTraveler | ||
174 | { | ||
175 | public: | ||
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 | |||
213 | BOOL LLSpatialGroup::isVisible() | ||
214 | { | ||
215 | if (sIgnoreOcclusion) | ||
216 | { | ||
217 | return !isState(CULLED); | ||
218 | } | ||
219 | else | ||
220 | { | ||
221 | return !isState(CULLED | OCCLUDED); | ||
222 | } | ||
223 | } | ||
224 | |||
225 | void 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 | |||
257 | BOOL 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 | |||
276 | BOOL 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 | |||
292 | BOOL 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 | |||
366 | void 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 | |||
393 | BOOL 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 | |||
411 | void 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 | |||
425 | class LLSpatialSetState : public LLSpatialGroup::OctreeTraveler | ||
426 | { | ||
427 | public: | ||
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 | |||
433 | class LLSpatialSetStateDiff : public LLSpatialSetState | ||
434 | { | ||
435 | public: | ||
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 | |||
449 | void 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 | |||
471 | class LLSpatialClearState : public LLSpatialGroup::OctreeTraveler | ||
472 | { | ||
473 | public: | ||
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 | |||
479 | class LLSpatialClearStateDiff : public LLSpatialClearState | ||
480 | { | ||
481 | public: | ||
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 | |||
496 | void 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 | |||
536 | LLSpatialGroup::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 | |||
551 | BOOL LLSpatialGroup::changeLOD() | ||
552 | { | ||
553 | return LLDrawable::getCurrentFrame()%SG_LOD_PERIOD == mLODHash; | ||
554 | } | ||
555 | |||
556 | void 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 | |||
564 | void 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 | |||
571 | void 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 | |||
599 | void 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 | |||
609 | void 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 | |||
624 | void LLSpatialGroup::handleChildRemoval(const OctreeNode* parent, const OctreeNode* child) | ||
625 | { | ||
626 | unbound(); | ||
627 | } | ||
628 | |||
629 | BOOL 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 | |||
723 | LLSpatialPartition::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 | |||
733 | LLSpatialPartition::~LLSpatialPartition() | ||
734 | { | ||
735 | LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); | ||
736 | delete mOctree; | ||
737 | mOctree = NULL; | ||
738 | } | ||
739 | |||
740 | |||
741 | LLSpatialGroup *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 | |||
776 | BOOL 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 | |||
792 | void 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 | |||
829 | class LLSpatialShift : public LLSpatialGroup::OctreeTraveler | ||
830 | { | ||
831 | public: | ||
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 | |||
841 | void 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 | |||
849 | BOOL 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 | |||
867 | class LLOctreeCull : public LLSpatialGroup::OctreeTraveler | ||
868 | { | ||
869 | public: | ||
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 | |||
991 | class LLOctreeSelect : public LLOctreeCull | ||
992 | { | ||
993 | public: | ||
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 | |||
1020 | void 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 | |||
1029 | void 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 | |||
1080 | void 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 | |||
1102 | S32 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 | |||
1126 | class LLOctreeClearOccludedNotActive : public LLSpatialGroup::OctreeTraveler | ||
1127 | { | ||
1128 | public: | ||
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 | |||
1148 | class LLQueueNonCulled : public LLSpatialGroup::OctreeTraveler | ||
1149 | { | ||
1150 | public: | ||
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 | |||
1174 | BOOL 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 | |||
1200 | void 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 | |||
1421 | void 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 | |||
1525 | class LLOctreeGet : public LLSpatialGroup::OctreeTraveler | ||
1526 | { | ||
1527 | public: | ||
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 | |||
1607 | S32 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 | |||
1619 | S32 LLSpatialPartition::getObjects(const LLVector3& pos, F32 rad, LLDrawable::drawable_set_t &results) | ||
1620 | { | ||
1621 | return getDrawables(pos, rad, results, FALSE); | ||
1622 | } | ||
1623 | |||
1624 | S32 LLSpatialPartition::getLights(const LLVector3& pos, F32 rad, LLDrawable::drawable_set_t &results) | ||
1625 | { | ||
1626 | return getDrawables(pos, rad, results, TRUE); | ||
1627 | } | ||
1628 | |||
1629 | class LLOctreeRenderNonOccluded : public LLOctreeTraveler<LLDrawable> | ||
1630 | { | ||
1631 | public: | ||
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 | |||
2093 | void 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 | |||
2198 | BOOL LLSpatialPartition::isVisible(const LLVector3& v) | ||
2199 | { | ||
2200 | if (!gCamera->sphereInFrustum(v, 4.0f)) | ||
2201 | { | ||
2202 | return FALSE; | ||
2203 | } | ||
2204 | |||
2205 | return TRUE; | ||
2206 | } | ||
2207 | |||
2208 | class LLOctreePick : public LLSpatialGroup::OctreeTraveler | ||
2209 | { | ||
2210 | public: | ||
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 | |||
2268 | LLDrawable* 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 | } | ||