diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/newview/llviewerobjectlist.cpp | |
parent | README.txt (diff) | |
download | meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2 meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz |
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/newview/llviewerobjectlist.cpp')
-rw-r--r-- | linden/indra/newview/llviewerobjectlist.cpp | 1472 |
1 files changed, 1472 insertions, 0 deletions
diff --git a/linden/indra/newview/llviewerobjectlist.cpp b/linden/indra/newview/llviewerobjectlist.cpp new file mode 100644 index 0000000..49f2aae --- /dev/null +++ b/linden/indra/newview/llviewerobjectlist.cpp | |||
@@ -0,0 +1,1472 @@ | |||
1 | /** | ||
2 | * @file llviewerobjectlist.cpp | ||
3 | * @brief Implementation of LLViewerObjectList class. | ||
4 | * | ||
5 | * Copyright (c) 2001-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 "llviewerobjectlist.h" | ||
31 | |||
32 | #include "message.h" | ||
33 | #include "timing.h" | ||
34 | #include "llfasttimer.h" | ||
35 | |||
36 | #include "llviewercontrol.h" | ||
37 | #include "llface.h" | ||
38 | #include "llvoavatar.h" | ||
39 | #include "llviewerobject.h" | ||
40 | #include "llviewerwindow.h" | ||
41 | #include "viewer.h" | ||
42 | #include "llnetmap.h" | ||
43 | #include "llagent.h" | ||
44 | #include "pipeline.h" | ||
45 | #include "llhoverview.h" | ||
46 | #include "llworld.h" | ||
47 | #include "llstring.h" | ||
48 | #include "llhudtext.h" | ||
49 | #include "lldrawable.h" | ||
50 | #include "xform.h" | ||
51 | #include "llsky.h" | ||
52 | #include "llviewercamera.h" | ||
53 | #include "llselectmgr.h" | ||
54 | #include "llresmgr.h" | ||
55 | #include "llviewerregion.h" | ||
56 | #include "llviewerstats.h" | ||
57 | #include "lltoolmgr.h" | ||
58 | #include "lltoolpie.h" | ||
59 | #include "llkeyboard.h" | ||
60 | #include "u64.h" | ||
61 | #include "llviewerimagelist.h" | ||
62 | #include "lldatapacker.h" | ||
63 | #include <zlib/zlib.h> | ||
64 | #include "object_flags.h" | ||
65 | |||
66 | extern BOOL gVelocityInterpolate; | ||
67 | extern BOOL gPingInterpolate; | ||
68 | extern F32 gMinObjectDistance; | ||
69 | extern U32 gFrameCount; | ||
70 | extern LLTimer gRenderStartTime; | ||
71 | extern BOOL gAnimateTextures; | ||
72 | |||
73 | void dialog_refresh_all(); | ||
74 | |||
75 | #define CULL_VIS | ||
76 | //#define ORPHAN_SPAM | ||
77 | //#define IGNORE_DEAD | ||
78 | |||
79 | // Global lists of objects - should go away soon. | ||
80 | LLViewerObjectList gObjectList; | ||
81 | |||
82 | extern LLPipeline gPipeline; | ||
83 | |||
84 | // Statics for object lookup tables. | ||
85 | U32 LLViewerObjectList::sSimulatorMachineIndex = 1; // Not zero deliberately, to speed up index check. | ||
86 | LLMap<U64, U32> LLViewerObjectList::sIPAndPortToIndex; | ||
87 | std::map<U64, LLUUID> LLViewerObjectList::sIndexAndLocalIDToUUID; | ||
88 | |||
89 | LLViewerObjectList::LLViewerObjectList() | ||
90 | { | ||
91 | mNumVisCulled = 0; | ||
92 | mNumSizeCulled = 0; | ||
93 | mCurLazyUpdateIndex = 0; | ||
94 | mCurBin = 0; | ||
95 | mNumDeadObjects = 0; | ||
96 | mNumOrphans = 0; | ||
97 | mNumNewObjects = 0; | ||
98 | mWasPaused = FALSE; | ||
99 | mNumDeadObjectUpdates = 0; | ||
100 | mNumUnknownKills = 0; | ||
101 | mNumUnknownUpdates = 0; | ||
102 | } | ||
103 | |||
104 | LLViewerObjectList::~LLViewerObjectList() | ||
105 | { | ||
106 | destroy(); | ||
107 | } | ||
108 | |||
109 | void LLViewerObjectList::destroy() | ||
110 | { | ||
111 | killAllObjects(); | ||
112 | |||
113 | resetObjectBeacons(); | ||
114 | mActiveObjects.clear(); | ||
115 | mDeadObjects.clear(); | ||
116 | mMapObjects.clear(); | ||
117 | mUUIDObjectMap.clear(); | ||
118 | } | ||
119 | |||
120 | |||
121 | void LLViewerObjectList::getUUIDFromLocal(LLUUID &id, | ||
122 | const U32 local_id, | ||
123 | const U32 ip, | ||
124 | const U32 port) | ||
125 | { | ||
126 | U64 ipport = (((U64)ip) << 32) | (U64)port; | ||
127 | |||
128 | U32 index = sIPAndPortToIndex[ipport]; | ||
129 | |||
130 | if (!index) | ||
131 | { | ||
132 | index = sSimulatorMachineIndex++; | ||
133 | sIPAndPortToIndex[ipport] = index; | ||
134 | } | ||
135 | |||
136 | U64 indexid = (((U64)index) << 32) | (U64)local_id; | ||
137 | |||
138 | id = get_if_there(sIndexAndLocalIDToUUID, indexid, LLUUID::null); | ||
139 | } | ||
140 | |||
141 | U64 LLViewerObjectList::getIndex(const U32 local_id, | ||
142 | const U32 ip, | ||
143 | const U32 port) | ||
144 | { | ||
145 | U64 ipport = (((U64)ip) << 32) | (U64)port; | ||
146 | |||
147 | U32 index = sIPAndPortToIndex[ipport]; | ||
148 | |||
149 | if (!index) | ||
150 | { | ||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | return (((U64)index) << 32) | (U64)local_id; | ||
155 | } | ||
156 | |||
157 | BOOL LLViewerObjectList::removeFromLocalIDTable(const LLViewerObject &object) | ||
158 | { | ||
159 | U32 local_id = object.mLocalID; | ||
160 | LLHost region_host = object.getRegion()->getHost(); | ||
161 | U32 ip = region_host.getAddress(); | ||
162 | U32 port = region_host.getPort(); | ||
163 | U64 ipport = (((U64)ip) << 32) | (U64)port; | ||
164 | U32 index = sIPAndPortToIndex[ipport]; | ||
165 | |||
166 | U64 indexid = (((U64)index) << 32) | (U64)local_id; | ||
167 | return sIndexAndLocalIDToUUID.erase(indexid) > 0 ? TRUE : FALSE; | ||
168 | } | ||
169 | |||
170 | void LLViewerObjectList::setUUIDAndLocal(const LLUUID &id, | ||
171 | const U32 local_id, | ||
172 | const U32 ip, | ||
173 | const U32 port) | ||
174 | { | ||
175 | U64 ipport = (((U64)ip) << 32) | (U64)port; | ||
176 | |||
177 | U32 index = sIPAndPortToIndex[ipport]; | ||
178 | |||
179 | if (!index) | ||
180 | { | ||
181 | index = sSimulatorMachineIndex++; | ||
182 | sIPAndPortToIndex[ipport] = index; | ||
183 | } | ||
184 | |||
185 | U64 indexid = (((U64)index) << 32) | (U64)local_id; | ||
186 | |||
187 | sIndexAndLocalIDToUUID[indexid] = id; | ||
188 | } | ||
189 | |||
190 | S32 gFullObjectUpdates = 0; | ||
191 | S32 gTerseObjectUpdates = 0; | ||
192 | |||
193 | void LLViewerObjectList::processUpdateCore(LLViewerObject* objectp, | ||
194 | void** user_data, | ||
195 | U32 i, | ||
196 | const EObjectUpdateType update_type, | ||
197 | LLDataPacker* dpp, | ||
198 | BOOL just_created) | ||
199 | { | ||
200 | LLMessageSystem* msg = gMessageSystem; | ||
201 | |||
202 | // ignore returned flags | ||
203 | objectp->processUpdateMessage(msg, user_data, i, update_type, dpp); | ||
204 | |||
205 | if (objectp->isDead()) | ||
206 | { | ||
207 | // The update failed | ||
208 | return; | ||
209 | } | ||
210 | updateActive(objectp); | ||
211 | |||
212 | // Also sets the approx. pixel area | ||
213 | objectp->setPixelAreaAndAngle(gAgent); | ||
214 | |||
215 | // Update the image levels of textures for this object. | ||
216 | objectp->updateTextures(gAgent); | ||
217 | |||
218 | if (just_created) | ||
219 | { | ||
220 | gPipeline.addObject(objectp); | ||
221 | } | ||
222 | |||
223 | // RN: this must be called after we have a drawable | ||
224 | // (from gPipeline.addObject) | ||
225 | // so that the drawable parent is set properly | ||
226 | findOrphans(objectp, msg->getSenderIP(), msg->getSenderPort()); | ||
227 | |||
228 | // If we're just wandering around, don't create new objects selected. | ||
229 | if (just_created | ||
230 | && update_type != OUT_TERSE_IMPROVED | ||
231 | && objectp->mCreateSelected) | ||
232 | { | ||
233 | if ( gToolMgr->getCurrentTool( gKeyboard->currentMask(TRUE) ) != gToolPie ) | ||
234 | { | ||
235 | //llinfos << "DEBUG selecting " << objectp->mID << " " | ||
236 | // << objectp->mLocalID << llendl; | ||
237 | gSelectMgr->selectObjectAndFamily(objectp); | ||
238 | dialog_refresh_all(); | ||
239 | } | ||
240 | |||
241 | objectp->mCreateSelected = false; | ||
242 | gViewerWindow->getWindow()->decBusyCount(); | ||
243 | gViewerWindow->getWindow()->setCursor( UI_CURSOR_ARROW ); | ||
244 | } | ||
245 | } | ||
246 | |||
247 | void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, | ||
248 | void **user_data, | ||
249 | const EObjectUpdateType update_type, | ||
250 | bool cached, bool compressed) | ||
251 | { | ||
252 | LLFastTimer t(LLFastTimer::FTM_PROCESS_OBJECTS); | ||
253 | |||
254 | LLVector3d camera_global = gAgent.getCameraPositionGlobal(); | ||
255 | LLViewerObject *objectp; | ||
256 | S32 num_objects; | ||
257 | U32 local_id; | ||
258 | LLPCode pcode = 0; | ||
259 | LLUUID fullid; | ||
260 | S32 i; | ||
261 | |||
262 | // figure out which simulator these are from and get it's index | ||
263 | // Coordinates in simulators are region-local | ||
264 | // Until we get region-locality working on viewer we | ||
265 | // have to transform to absolute coordinates. | ||
266 | num_objects = mesgsys->getNumberOfBlocksFast(_PREHASH_ObjectData); | ||
267 | |||
268 | if (!cached && !compressed && update_type != OUT_FULL) | ||
269 | { | ||
270 | gTerseObjectUpdates += num_objects; | ||
271 | S32 size; | ||
272 | if (mesgsys->getReceiveCompressedSize()) | ||
273 | { | ||
274 | size = mesgsys->getReceiveCompressedSize(); | ||
275 | } | ||
276 | else | ||
277 | { | ||
278 | size = mesgsys->getReceiveSize(); | ||
279 | } | ||
280 | // llinfos << "Received terse " << num_objects << " in " << size << " byte (" << size/num_objects << ")" << llendl; | ||
281 | } | ||
282 | else | ||
283 | { | ||
284 | S32 size; | ||
285 | if (mesgsys->getReceiveCompressedSize()) | ||
286 | { | ||
287 | size = mesgsys->getReceiveCompressedSize(); | ||
288 | } | ||
289 | else | ||
290 | { | ||
291 | size = mesgsys->getReceiveSize(); | ||
292 | } | ||
293 | |||
294 | // llinfos << "Received " << num_objects << " in " << size << " byte (" << size/num_objects << ")" << llendl; | ||
295 | gFullObjectUpdates += num_objects; | ||
296 | } | ||
297 | |||
298 | U64 region_handle; | ||
299 | mesgsys->getU64Fast(_PREHASH_RegionData, _PREHASH_RegionHandle, region_handle); | ||
300 | LLViewerRegion *regionp = gWorldPointer->getRegionFromHandle(region_handle); | ||
301 | |||
302 | if (!regionp) | ||
303 | { | ||
304 | llwarns << "Object update from unknown region!" << llendl; | ||
305 | return; | ||
306 | } | ||
307 | |||
308 | U8 compressed_dpbuffer[2048]; | ||
309 | LLDataPackerBinaryBuffer compressed_dp(compressed_dpbuffer, 2048); | ||
310 | LLDataPacker *cached_dpp = NULL; | ||
311 | |||
312 | for (i = 0; i < num_objects; i++) | ||
313 | { | ||
314 | LLTimer update_timer; | ||
315 | BOOL justCreated = FALSE; | ||
316 | |||
317 | if (cached) | ||
318 | { | ||
319 | U32 id; | ||
320 | U32 crc; | ||
321 | mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, id, i); | ||
322 | mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_CRC, crc, i); | ||
323 | |||
324 | // Lookup data packer and add this id to cache miss lists if necessary. | ||
325 | cached_dpp = regionp->getDP(id, crc); | ||
326 | if (cached_dpp) | ||
327 | { | ||
328 | cached_dpp->reset(); | ||
329 | cached_dpp->unpackUUID(fullid, "ID"); | ||
330 | cached_dpp->unpackU32(local_id, "LocalID"); | ||
331 | cached_dpp->unpackU8(pcode, "PCode"); | ||
332 | } | ||
333 | else | ||
334 | { | ||
335 | continue; // no data packer, skip this object | ||
336 | } | ||
337 | } | ||
338 | else if (compressed) | ||
339 | { | ||
340 | U8 compbuffer[2048]; | ||
341 | S32 uncompressed_length = 2048; | ||
342 | S32 compressed_length; | ||
343 | |||
344 | compressed_dp.reset(); | ||
345 | |||
346 | U32 flags = 0; | ||
347 | if (update_type != OUT_TERSE_IMPROVED) | ||
348 | { | ||
349 | mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, i); | ||
350 | } | ||
351 | |||
352 | if (flags & FLAGS_ZLIB_COMPRESSED) | ||
353 | { | ||
354 | compressed_length = mesgsys->getSizeFast(_PREHASH_ObjectData, i, _PREHASH_Data); | ||
355 | mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_Data, compbuffer, 0, i); | ||
356 | uncompressed_length = 2048; | ||
357 | uncompress(compressed_dpbuffer, (unsigned long *)&uncompressed_length, | ||
358 | compbuffer, compressed_length); | ||
359 | compressed_dp.assignBuffer(compressed_dpbuffer, uncompressed_length); | ||
360 | } | ||
361 | else | ||
362 | { | ||
363 | uncompressed_length = mesgsys->getSizeFast(_PREHASH_ObjectData, i, _PREHASH_Data); | ||
364 | mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_Data, compressed_dpbuffer, 0, i); | ||
365 | compressed_dp.assignBuffer(compressed_dpbuffer, uncompressed_length); | ||
366 | } | ||
367 | |||
368 | |||
369 | if (update_type != OUT_TERSE_IMPROVED) | ||
370 | { | ||
371 | compressed_dp.unpackUUID(fullid, "ID"); | ||
372 | compressed_dp.unpackU32(local_id, "LocalID"); | ||
373 | compressed_dp.unpackU8(pcode, "PCode"); | ||
374 | } | ||
375 | else | ||
376 | { | ||
377 | compressed_dp.unpackU32(local_id, "LocalID"); | ||
378 | getUUIDFromLocal(fullid, | ||
379 | local_id, | ||
380 | gMessageSystem->getSenderIP(), | ||
381 | gMessageSystem->getSenderPort()); | ||
382 | if (fullid.isNull()) | ||
383 | { | ||
384 | //llwarns << "update for unknown localid " << local_id << " host " << gMessageSystem->getSender() << llendl; | ||
385 | mNumUnknownUpdates++; | ||
386 | } | ||
387 | } | ||
388 | } | ||
389 | else if (update_type != OUT_FULL) | ||
390 | { | ||
391 | mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, local_id, i); | ||
392 | getUUIDFromLocal(fullid, | ||
393 | local_id, | ||
394 | gMessageSystem->getSenderIP(), | ||
395 | gMessageSystem->getSenderPort()); | ||
396 | if (fullid.isNull()) | ||
397 | { | ||
398 | //llwarns << "update for unknown localid " << local_id << " host " << gMessageSystem->getSender() << llendl; | ||
399 | mNumUnknownUpdates++; | ||
400 | } | ||
401 | } | ||
402 | else | ||
403 | { | ||
404 | mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_FullID, fullid, i); | ||
405 | mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, local_id, i); | ||
406 | // llinfos << "Full Update, obj " << local_id << ", global ID" << fullid << "from " << mesgsys->getSender() << llendl; | ||
407 | } | ||
408 | objectp = findObject(fullid); | ||
409 | |||
410 | // This looks like it will break if the local_id of the object doesn't change | ||
411 | // upon boundary crossing, but we check for region id matching later... | ||
412 | if (objectp && (objectp->mLocalID != local_id)) | ||
413 | { | ||
414 | removeFromLocalIDTable(*objectp); | ||
415 | setUUIDAndLocal(fullid, | ||
416 | local_id, | ||
417 | gMessageSystem->getSenderIP(), | ||
418 | gMessageSystem->getSenderPort()); | ||
419 | } | ||
420 | |||
421 | if (!objectp) | ||
422 | { | ||
423 | if (compressed) | ||
424 | { | ||
425 | if (update_type == OUT_TERSE_IMPROVED) | ||
426 | { | ||
427 | // llinfos << "terse update for an unknown object:" << fullid << llendl; | ||
428 | continue; | ||
429 | } | ||
430 | } | ||
431 | else if (cached) | ||
432 | { | ||
433 | } | ||
434 | else | ||
435 | { | ||
436 | if (update_type != OUT_FULL) | ||
437 | { | ||
438 | // llinfos << "terse update for an unknown object:" << fullid << llendl; | ||
439 | continue; | ||
440 | } | ||
441 | |||
442 | mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_PCode, pcode, i); | ||
443 | } | ||
444 | #ifdef IGNORE_DEAD | ||
445 | if (mDeadObjects.find(fullid) != mDeadObjects.end()) | ||
446 | { | ||
447 | mNumDeadObjectUpdates++; | ||
448 | //llinfos << "update for a dead object:" << fullid << llendl; | ||
449 | continue; | ||
450 | } | ||
451 | #endif | ||
452 | |||
453 | objectp = createObject(pcode, regionp, fullid, local_id, gMessageSystem->getSender()); | ||
454 | if (!objectp) | ||
455 | { | ||
456 | continue; | ||
457 | } | ||
458 | justCreated = TRUE; | ||
459 | mNumNewObjects++; | ||
460 | } | ||
461 | else | ||
462 | { | ||
463 | if (objectp->getRegion() != regionp) | ||
464 | { | ||
465 | // Object has changed region! Update lookup tables, set region pointer. | ||
466 | removeFromLocalIDTable(*objectp); | ||
467 | setUUIDAndLocal(fullid, | ||
468 | local_id, | ||
469 | gMessageSystem->getSenderIP(), | ||
470 | gMessageSystem->getSenderPort()); | ||
471 | objectp->setRegion(regionp); | ||
472 | } | ||
473 | objectp->updateRegion(regionp); // for LLVOAvatar | ||
474 | } | ||
475 | |||
476 | |||
477 | if (objectp->isDead()) | ||
478 | { | ||
479 | llwarns << "Dead object " << objectp->mID << " in UUID map 1!" << llendl; | ||
480 | } | ||
481 | |||
482 | if (compressed) | ||
483 | { | ||
484 | if (update_type != OUT_TERSE_IMPROVED) | ||
485 | { | ||
486 | objectp->mLocalID = local_id; | ||
487 | } | ||
488 | processUpdateCore(objectp, user_data, i, update_type, &compressed_dp, justCreated); | ||
489 | if (update_type != OUT_TERSE_IMPROVED) | ||
490 | { | ||
491 | objectp->mRegionp->cacheFullUpdate(objectp, compressed_dp); | ||
492 | } | ||
493 | } | ||
494 | else if (cached) | ||
495 | { | ||
496 | objectp->mLocalID = local_id; | ||
497 | processUpdateCore(objectp, user_data, i, update_type, cached_dpp, justCreated); | ||
498 | } | ||
499 | else | ||
500 | { | ||
501 | if (update_type == OUT_FULL) | ||
502 | { | ||
503 | objectp->mLocalID = local_id; | ||
504 | } | ||
505 | processUpdateCore(objectp, user_data, i, update_type, NULL, justCreated); | ||
506 | } | ||
507 | } | ||
508 | |||
509 | LLVOAvatar::cullAvatarsByPixelArea(); | ||
510 | } | ||
511 | |||
512 | void LLViewerObjectList::processCompressedObjectUpdate(LLMessageSystem *mesgsys, | ||
513 | void **user_data, | ||
514 | const EObjectUpdateType update_type) | ||
515 | { | ||
516 | processObjectUpdate(mesgsys, user_data, update_type, false, true); | ||
517 | } | ||
518 | |||
519 | void LLViewerObjectList::processCachedObjectUpdate(LLMessageSystem *mesgsys, | ||
520 | void **user_data, | ||
521 | const EObjectUpdateType update_type) | ||
522 | { | ||
523 | processObjectUpdate(mesgsys, user_data, update_type, true, false); | ||
524 | } | ||
525 | |||
526 | void LLViewerObjectList::relightAllObjects() | ||
527 | { | ||
528 | for (S32 i = 0; i < mObjects.count(); i++) | ||
529 | { | ||
530 | LLDrawable *drawable = mObjects[i]->mDrawable; | ||
531 | if (drawable) | ||
532 | { | ||
533 | gPipeline.markRelight(drawable); | ||
534 | } | ||
535 | } | ||
536 | } | ||
537 | |||
538 | void LLViewerObjectList::dirtyAllObjectInventory() | ||
539 | { | ||
540 | S32 count = mObjects.count(); | ||
541 | for(S32 i = 0; i < count; ++i) | ||
542 | { | ||
543 | mObjects[i]->dirtyInventory(); | ||
544 | } | ||
545 | } | ||
546 | |||
547 | void LLViewerObjectList::updateApparentAngles(LLAgent &agent) | ||
548 | { | ||
549 | S32 i; | ||
550 | S32 num_objects = 0; | ||
551 | LLViewerObject *objectp; | ||
552 | |||
553 | S32 num_updates, max_value; | ||
554 | if (NUM_BINS - 1 == mCurBin) | ||
555 | { | ||
556 | num_updates = mObjects.count() - mCurLazyUpdateIndex; | ||
557 | max_value = mObjects.count(); | ||
558 | gImageList.setUpdateStats(TRUE); | ||
559 | } | ||
560 | else | ||
561 | { | ||
562 | num_updates = (mObjects.count() / NUM_BINS) + 1; | ||
563 | max_value = llmin(mObjects.count(), mCurLazyUpdateIndex + num_updates); | ||
564 | } | ||
565 | |||
566 | |||
567 | if (!gNoRender) | ||
568 | { | ||
569 | // Slam priorities for textures that we care about (hovered, selected, and focused) | ||
570 | // Hovered | ||
571 | // Assumes only one level deep of parenting | ||
572 | objectp = gHoverView->getLastHoverObject(); | ||
573 | if (objectp) | ||
574 | { | ||
575 | objectp->boostTexturePriority(); | ||
576 | } | ||
577 | } | ||
578 | |||
579 | // Focused | ||
580 | objectp = gAgent.getFocusObject(); | ||
581 | if (objectp) | ||
582 | { | ||
583 | objectp->boostTexturePriority(); | ||
584 | } | ||
585 | |||
586 | // Selected | ||
587 | for (objectp = gSelectMgr->getFirstRootObject(); objectp; objectp = gSelectMgr->getNextRootObject()) | ||
588 | { | ||
589 | objectp->boostTexturePriority(); | ||
590 | } | ||
591 | |||
592 | |||
593 | // Iterate through some of the objects and lazy update their texture priorities | ||
594 | for (i = mCurLazyUpdateIndex; i < max_value; i++) | ||
595 | { | ||
596 | objectp = mObjects[i]; | ||
597 | if (!objectp->isDead()) | ||
598 | { | ||
599 | num_objects++; | ||
600 | |||
601 | // Update distance & gpw | ||
602 | objectp->setPixelAreaAndAngle(agent); // Also sets the approx. pixel area | ||
603 | objectp->updateTextures(agent); // Update the image levels of textures for this object. | ||
604 | } | ||
605 | } | ||
606 | |||
607 | mCurLazyUpdateIndex = max_value; | ||
608 | if (mCurLazyUpdateIndex == mObjects.count()) | ||
609 | { | ||
610 | mCurLazyUpdateIndex = 0; | ||
611 | } | ||
612 | |||
613 | mCurBin = (++mCurBin) % NUM_BINS; | ||
614 | |||
615 | LLVOAvatar::cullAvatarsByPixelArea(); | ||
616 | } | ||
617 | |||
618 | |||
619 | void LLViewerObjectList::update(LLAgent &agent, LLWorld &world) | ||
620 | { | ||
621 | LLMemType mt(LLMemType::MTYPE_OBJECT); | ||
622 | // Update globals | ||
623 | gVelocityInterpolate = gSavedSettings.getBOOL("VelocityInterpolate"); | ||
624 | gPingInterpolate = gSavedSettings.getBOOL("PingInterpolate"); | ||
625 | gAnimateTextures = gSavedSettings.getBOOL("AnimateTextures"); | ||
626 | |||
627 | // update global timer | ||
628 | F32 last_time = gFrameTimeSeconds; | ||
629 | U64 time = totalTime(); // this will become the new gFrameTime when the update is done | ||
630 | // Time _can_ go backwards, for example if the user changes the system clock. | ||
631 | // It doesn't cause any fatal problems (just some oddness with stats), so we shouldn't assert here. | ||
632 | // llassert(time > gFrameTime); | ||
633 | F64 time_diff = U64_to_F64(time - gFrameTime)/(F64)SEC_TO_MICROSEC; | ||
634 | gFrameTime = time; | ||
635 | F64 time_since_start = U64_to_F64(gFrameTime - gStartTime)/(F64)SEC_TO_MICROSEC; | ||
636 | gFrameTimeSeconds = (F32)time_since_start; | ||
637 | |||
638 | gFrameIntervalSeconds = gFrameTimeSeconds - last_time; | ||
639 | if (gFrameIntervalSeconds < 0.f) | ||
640 | { | ||
641 | gFrameIntervalSeconds = 0.f; | ||
642 | } | ||
643 | |||
644 | //clear avatar LOD change counter | ||
645 | LLVOAvatar::sNumLODChangesThisFrame = 0; | ||
646 | |||
647 | const F64 frame_time = LLFrameTimer::getElapsedSeconds(); | ||
648 | |||
649 | std::vector<LLViewerObject*> kill_list; | ||
650 | S32 num_active_objects = 0; | ||
651 | |||
652 | if (gSavedSettings.getBOOL("FreezeTime")) | ||
653 | { | ||
654 | for (std::set<LLPointer<LLViewerObject> >::iterator iter = mActiveObjects.begin(); | ||
655 | iter != mActiveObjects.end(); iter++) | ||
656 | { | ||
657 | LLViewerObject *objectp = *iter; | ||
658 | if (objectp->getPCode() == LLViewerObject::LL_VO_CLOUDS || | ||
659 | objectp->isAvatar()) | ||
660 | { | ||
661 | objectp->idleUpdate(agent, world, frame_time); | ||
662 | } | ||
663 | } | ||
664 | } | ||
665 | else | ||
666 | { | ||
667 | for (std::set<LLPointer<LLViewerObject> >::iterator iter = mActiveObjects.begin(); | ||
668 | iter != mActiveObjects.end(); iter++) | ||
669 | { | ||
670 | LLViewerObject *objectp = *iter; | ||
671 | if (!objectp->idleUpdate(agent, world, frame_time)) | ||
672 | { | ||
673 | // If Idle Update returns false, kill object! | ||
674 | kill_list.push_back(objectp); | ||
675 | } | ||
676 | else | ||
677 | { | ||
678 | num_active_objects++; | ||
679 | } | ||
680 | } | ||
681 | for (std::vector<LLViewerObject*>::iterator iter = kill_list.begin(); | ||
682 | iter != kill_list.end(); iter++) | ||
683 | { | ||
684 | LLViewerObject *objectp = *iter; | ||
685 | killObject(objectp); | ||
686 | } | ||
687 | } | ||
688 | |||
689 | mNumSizeCulled = 0; | ||
690 | mNumVisCulled = 0; | ||
691 | |||
692 | // compute all sorts of time-based stats | ||
693 | // don't factor frames that were paused into the stats | ||
694 | if (! mWasPaused) | ||
695 | { | ||
696 | gViewerStats->updateFrameStats(time_diff); | ||
697 | } | ||
698 | |||
699 | /* | ||
700 | // Debugging code for viewing orphans, and orphaned parents | ||
701 | LLUUID id; | ||
702 | char id_str[UUID_STR_LENGTH + 20]; | ||
703 | for (i = 0; i < mOrphanParents.count(); i++) | ||
704 | { | ||
705 | id = sIndexAndLocalIDToUUID[mOrphanParents[i]]; | ||
706 | LLViewerObject *objectp = findObject(id); | ||
707 | if (objectp) | ||
708 | { | ||
709 | sprintf(id_str, "Par: "); | ||
710 | objectp->mID.toString(id_str + 5); | ||
711 | addDebugBeacon(objectp->getPositionAgent(), | ||
712 | id_str, | ||
713 | LLColor4(1.f,0.f,0.f,1.f), | ||
714 | LLColor4(1.f,1.f,1.f,1.f)); | ||
715 | } | ||
716 | } | ||
717 | |||
718 | LLColor4 text_color; | ||
719 | for (i = 0; i < mOrphanChildren.count(); i++) | ||
720 | { | ||
721 | OrphanInfo oi = mOrphanChildren[i]; | ||
722 | LLViewerObject *objectp = findObject(oi.mChildInfo); | ||
723 | if (objectp) | ||
724 | { | ||
725 | if (objectp->getParent()) | ||
726 | { | ||
727 | sprintf(id_str, "ChP: "); | ||
728 | text_color = LLColor4(0.f, 1.f, 0.f, 1.f); | ||
729 | } | ||
730 | else | ||
731 | { | ||
732 | sprintf(id_str, "ChNoP: "); | ||
733 | text_color = LLColor4(1.f, 0.f, 0.f, 1.f); | ||
734 | } | ||
735 | id = sIndexAndLocalIDToUUID[oi.mParentInfo]; | ||
736 | objectp->mID.toString(id_str + 8); | ||
737 | addDebugBeacon(objectp->getPositionAgent() + LLVector3(0.f, 0.f, -0.25f), | ||
738 | id_str, | ||
739 | LLColor4(0.25f,0.25f,0.25f,1.f), | ||
740 | text_color); | ||
741 | } | ||
742 | i++; | ||
743 | } | ||
744 | */ | ||
745 | |||
746 | mNumObjectsStat.addValue(mObjects.count()); | ||
747 | mNumActiveObjectsStat.addValue(num_active_objects); | ||
748 | mNumSizeCulledStat.addValue(mNumSizeCulled); | ||
749 | mNumVisCulledStat.addValue(mNumVisCulled); | ||
750 | } | ||
751 | |||
752 | void LLViewerObjectList::cleanupReferences(LLViewerObject *objectp) | ||
753 | { | ||
754 | LLMemType mt(LLMemType::MTYPE_OBJECT); | ||
755 | if (mDeadObjects.count(objectp->mID)) | ||
756 | { | ||
757 | llinfos << "Object " << objectp->mID << " already on dead list, ignoring cleanup!" << llendl; | ||
758 | return; | ||
759 | } | ||
760 | |||
761 | mDeadObjects.insert(std::pair<LLUUID, LLPointer<LLViewerObject> >(objectp->mID, objectp)); | ||
762 | |||
763 | // Cleanup any references we have to this object | ||
764 | // Remove from object map so noone can look it up. | ||
765 | |||
766 | mUUIDObjectMap.erase(objectp->mID); | ||
767 | removeFromLocalIDTable(*objectp); | ||
768 | |||
769 | if (objectp->onActiveList()) | ||
770 | { | ||
771 | //llinfos << "Removing " << objectp->mID << " " << objectp->getPCodeString() << " from active list in cleanupReferences." << llendl; | ||
772 | objectp->setOnActiveList(FALSE); | ||
773 | mActiveObjects.erase(objectp); | ||
774 | } | ||
775 | |||
776 | if (objectp->isOnMap()) | ||
777 | { | ||
778 | mMapObjects.removeObj(objectp); | ||
779 | } | ||
780 | |||
781 | // Don't clean up mObject references, these will be cleaned up more efficiently later! | ||
782 | // Also, not cleaned up | ||
783 | removeDrawable(objectp->mDrawable); | ||
784 | |||
785 | mNumDeadObjects++; | ||
786 | } | ||
787 | |||
788 | void LLViewerObjectList::removeDrawable(LLDrawable* drawablep) | ||
789 | { | ||
790 | if (!drawablep) | ||
791 | { | ||
792 | return; | ||
793 | } | ||
794 | |||
795 | for (S32 i = 0; i < drawablep->getNumFaces(); i++) | ||
796 | { | ||
797 | LLViewerObject* objectp = drawablep->getFace(i)->getViewerObject(); | ||
798 | mSelectPickList.erase(objectp); | ||
799 | } | ||
800 | } | ||
801 | |||
802 | BOOL LLViewerObjectList::killObject(LLViewerObject *objectp) | ||
803 | { | ||
804 | // When we're killing objects, all we do is mark them as dead. | ||
805 | // We clean up the dead objects later. | ||
806 | |||
807 | if (objectp) | ||
808 | { | ||
809 | if (objectp->isDead()) | ||
810 | { | ||
811 | // This object is already dead. Don't need to do more. | ||
812 | return TRUE; | ||
813 | } | ||
814 | else | ||
815 | { | ||
816 | objectp->markDead(); | ||
817 | } | ||
818 | |||
819 | return TRUE; | ||
820 | } | ||
821 | return FALSE; | ||
822 | } | ||
823 | |||
824 | void LLViewerObjectList::killObjects(LLViewerRegion *regionp) | ||
825 | { | ||
826 | LLViewerObject *objectp; | ||
827 | |||
828 | S32 i; | ||
829 | for (i = 0; i < mObjects.count(); i++) | ||
830 | { | ||
831 | objectp = mObjects[i]; | ||
832 | |||
833 | if (objectp->mRegionp == regionp) | ||
834 | { | ||
835 | killObject(objectp); | ||
836 | } | ||
837 | } | ||
838 | |||
839 | // Have to clean right away because the region is becoming invalid. | ||
840 | cleanDeadObjects(FALSE); | ||
841 | } | ||
842 | |||
843 | void LLViewerObjectList::killAllObjects() | ||
844 | { | ||
845 | // Used only on global destruction. | ||
846 | LLViewerObject *objectp; | ||
847 | |||
848 | for (S32 i = 0; i < mObjects.count(); i++) | ||
849 | { | ||
850 | objectp = mObjects[i]; | ||
851 | |||
852 | killObject(objectp); | ||
853 | llassert(objectp->isDead()); | ||
854 | } | ||
855 | |||
856 | cleanDeadObjects(FALSE); | ||
857 | |||
858 | if(!mObjects.empty()) | ||
859 | { | ||
860 | llwarns << "LLViewerObjectList::killAllObjects still has entries in mObjects: " << mObjects.count() << llendl; | ||
861 | mObjects.clear(); | ||
862 | } | ||
863 | |||
864 | if (!mActiveObjects.empty()) | ||
865 | { | ||
866 | llwarns << "Some objects still on active object list!" << llendl; | ||
867 | mActiveObjects.clear(); | ||
868 | } | ||
869 | |||
870 | if (!mMapObjects.empty()) | ||
871 | { | ||
872 | llwarns << "Some objects still on map object list!" << llendl; | ||
873 | mActiveObjects.clear(); | ||
874 | } | ||
875 | } | ||
876 | |||
877 | void LLViewerObjectList::cleanDeadObjects(BOOL use_timer) | ||
878 | { | ||
879 | if (!mNumDeadObjects) | ||
880 | { | ||
881 | // No dead objects, don't need to scan object list. | ||
882 | return; | ||
883 | } | ||
884 | |||
885 | S32 i = 0; | ||
886 | S32 num_removed = 0; | ||
887 | LLViewerObject *objectp; | ||
888 | while (i < mObjects.count()) | ||
889 | { | ||
890 | // Scan for all of the dead objects and remove any "global" references to them. | ||
891 | objectp = mObjects[i]; | ||
892 | if (objectp->isDead()) | ||
893 | { | ||
894 | mObjects.remove(i); | ||
895 | num_removed++; | ||
896 | |||
897 | if (num_removed == mNumDeadObjects) | ||
898 | { | ||
899 | // We've cleaned up all of the dead objects. | ||
900 | break; | ||
901 | } | ||
902 | } | ||
903 | else | ||
904 | { | ||
905 | // iterate, this isn't a dead object. | ||
906 | i++; | ||
907 | } | ||
908 | } | ||
909 | |||
910 | // We've cleaned the global object list, now let's do some paranoia testing on objects | ||
911 | // before blowing away the dead list. | ||
912 | mDeadObjects.clear(); | ||
913 | mNumDeadObjects = 0; | ||
914 | } | ||
915 | |||
916 | void LLViewerObjectList::updateActive(LLViewerObject *objectp) | ||
917 | { | ||
918 | LLMemType mt(LLMemType::MTYPE_OBJECT); | ||
919 | if (objectp->isDead()) | ||
920 | { | ||
921 | return; // We don't update dead objects! | ||
922 | } | ||
923 | |||
924 | BOOL active = objectp->isActive(); | ||
925 | if (active != objectp->onActiveList()) | ||
926 | { | ||
927 | if (active) | ||
928 | { | ||
929 | //llinfos << "Adding " << objectp->mID << " " << objectp->getPCodeString() << " to active list." << llendl; | ||
930 | mActiveObjects.insert(objectp); | ||
931 | objectp->setOnActiveList(TRUE); | ||
932 | } | ||
933 | else | ||
934 | { | ||
935 | //llinfos << "Removing " << objectp->mID << " " << objectp->getPCodeString() << " from active list." << llendl; | ||
936 | mActiveObjects.erase(objectp); | ||
937 | objectp->setOnActiveList(FALSE); | ||
938 | } | ||
939 | } | ||
940 | } | ||
941 | |||
942 | |||
943 | |||
944 | void LLViewerObjectList::shiftObjects(const LLVector3 &offset) | ||
945 | { | ||
946 | // This is called when we shift our origin when we cross region boundaries... | ||
947 | // We need to update many object caches, I'll document this more as I dig through the code | ||
948 | // cleaning things out... | ||
949 | |||
950 | if (gNoRender || 0 == offset.magVecSquared()) | ||
951 | { | ||
952 | return; | ||
953 | } | ||
954 | |||
955 | LLViewerObject *objectp; | ||
956 | S32 i; | ||
957 | for (i = 0; i < mObjects.count(); i++) | ||
958 | { | ||
959 | objectp = getObject(i); | ||
960 | // There could be dead objects on the object list, so don't update stuff if the object is dead. | ||
961 | if (objectp) | ||
962 | { | ||
963 | objectp->updatePositionCaches(); | ||
964 | |||
965 | if (objectp->mDrawable.notNull() && !objectp->mDrawable->isDead()) | ||
966 | { | ||
967 | gPipeline.markShift(objectp->mDrawable); | ||
968 | } | ||
969 | } | ||
970 | } | ||
971 | |||
972 | gPipeline.shiftObjects(offset); | ||
973 | gWorldPointer->mPartSim.shift(offset); | ||
974 | } | ||
975 | |||
976 | void LLViewerObjectList::renderObjectsForMap(LLNetMap &netmap) | ||
977 | { | ||
978 | LLColor4 above_water_color = gColors.getColor( "NetMapOtherOwnAboveWater" ); | ||
979 | LLColor4 below_water_color = gColors.getColor( "NetMapOtherOwnBelowWater" ); | ||
980 | LLColor4 you_own_above_water_color = | ||
981 | gColors.getColor( "NetMapYouOwnAboveWater" ); | ||
982 | LLColor4 you_own_below_water_color = | ||
983 | gColors.getColor( "NetMapYouOwnBelowWater" ); | ||
984 | LLColor4 group_own_above_water_color = | ||
985 | gColors.getColor( "NetMapGroupOwnAboveWater" ); | ||
986 | LLColor4 group_own_below_water_color = | ||
987 | gColors.getColor( "NetMapGroupOwnBelowWater" ); | ||
988 | |||
989 | |||
990 | for (S32 i = 0; i < mMapObjects.count(); i++) | ||
991 | { | ||
992 | LLViewerObject* objectp = mMapObjects[i]; | ||
993 | if (objectp->isOrphaned() || objectp->isAttachment()) | ||
994 | { | ||
995 | continue; | ||
996 | } | ||
997 | const LLVector3& scale = objectp->getScale(); | ||
998 | const LLVector3d pos = objectp->getPositionGlobal(); | ||
999 | const F64 water_height = F64( objectp->getRegion()->getWaterHeight() ); | ||
1000 | // gWorldPointer->getWaterHeight(); | ||
1001 | |||
1002 | F32 approx_radius = (scale.mV[VX] + scale.mV[VY]) * 0.5f * 0.5f * 1.3f; // 1.3 is a fudge | ||
1003 | |||
1004 | LLColor4U color = above_water_color; | ||
1005 | if( objectp->permYouOwner() ) | ||
1006 | { | ||
1007 | const F32 MIN_RADIUS_FOR_OWNED_OBJECTS = 2.f; | ||
1008 | if( approx_radius < MIN_RADIUS_FOR_OWNED_OBJECTS ) | ||
1009 | { | ||
1010 | approx_radius = MIN_RADIUS_FOR_OWNED_OBJECTS; | ||
1011 | } | ||
1012 | |||
1013 | if( pos.mdV[VZ] >= water_height ) | ||
1014 | { | ||
1015 | if ( objectp->permGroupOwner() ) | ||
1016 | { | ||
1017 | color = group_own_above_water_color; | ||
1018 | } | ||
1019 | else | ||
1020 | { | ||
1021 | color = you_own_above_water_color; | ||
1022 | } | ||
1023 | } | ||
1024 | else | ||
1025 | { | ||
1026 | if ( objectp->permGroupOwner() ) | ||
1027 | { | ||
1028 | color = group_own_below_water_color; | ||
1029 | } | ||
1030 | else | ||
1031 | { | ||
1032 | color = you_own_below_water_color; | ||
1033 | } | ||
1034 | } | ||
1035 | } | ||
1036 | else | ||
1037 | if( pos.mdV[VZ] < water_height ) | ||
1038 | { | ||
1039 | color = below_water_color; | ||
1040 | } | ||
1041 | |||
1042 | netmap.renderScaledPointGlobal( | ||
1043 | pos, | ||
1044 | color, | ||
1045 | approx_radius ); | ||
1046 | } | ||
1047 | } | ||
1048 | |||
1049 | void LLViewerObjectList::renderObjectBounds(const LLVector3 ¢er) | ||
1050 | { | ||
1051 | } | ||
1052 | |||
1053 | |||
1054 | U32 LLViewerObjectList::renderObjectsForSelect(LLCamera &camera, BOOL pick_parcel_wall, BOOL keep_pick_list) | ||
1055 | { | ||
1056 | gRenderForSelect = TRUE; | ||
1057 | |||
1058 | // LLTimer pick_timer; | ||
1059 | if (!keep_pick_list) | ||
1060 | { | ||
1061 | LLViewerObject *objectp; | ||
1062 | S32 i; | ||
1063 | // Reset all of the GL names to zero. | ||
1064 | for (i = 0; i < mObjects.count(); i++) | ||
1065 | { | ||
1066 | objectp = mObjects[i]; | ||
1067 | objectp->mGLName = 0; | ||
1068 | } | ||
1069 | |||
1070 | mSelectPickList.clear(); | ||
1071 | |||
1072 | std::vector<LLDrawable*> pick_drawables; | ||
1073 | gPipeline.mObjectPartition->cull(camera, &pick_drawables, TRUE); | ||
1074 | |||
1075 | for (std::vector<LLDrawable*>::iterator iter = pick_drawables.begin(); | ||
1076 | iter != pick_drawables.end(); iter++) | ||
1077 | { | ||
1078 | LLDrawable* drawablep = *iter; | ||
1079 | |||
1080 | LLViewerObject* last_objectp = NULL; | ||
1081 | for (S32 face_num = 0; face_num < drawablep->getNumFaces(); face_num++) | ||
1082 | { | ||
1083 | LLViewerObject* objectp = drawablep->getFace(face_num)->getViewerObject(); | ||
1084 | |||
1085 | if (objectp && objectp != last_objectp) | ||
1086 | { | ||
1087 | mSelectPickList.insert(objectp); | ||
1088 | last_objectp = objectp; | ||
1089 | } | ||
1090 | } | ||
1091 | } | ||
1092 | |||
1093 | LLHUDText::addPickable(mSelectPickList); | ||
1094 | |||
1095 | for (objectp = (LLVOAvatar*)LLCharacter::sInstances.getFirstData(); | ||
1096 | objectp; | ||
1097 | objectp = (LLVOAvatar*)LLCharacter::sInstances.getNextData()) | ||
1098 | { | ||
1099 | if (!objectp->isDead()) | ||
1100 | { | ||
1101 | if (objectp->mDrawable.notNull() && objectp->mDrawable->isVisible()) | ||
1102 | { | ||
1103 | mSelectPickList.insert(objectp); | ||
1104 | } | ||
1105 | } | ||
1106 | } | ||
1107 | |||
1108 | // add all hud objects to pick list | ||
1109 | LLVOAvatar* avatarp = gAgent.getAvatarObject(); | ||
1110 | if (avatarp) | ||
1111 | { | ||
1112 | LLViewerJointAttachment* attachmentp; | ||
1113 | for (attachmentp = avatarp->mAttachmentPoints.getFirstData(); | ||
1114 | attachmentp; | ||
1115 | attachmentp = avatarp->mAttachmentPoints.getNextData()) | ||
1116 | { | ||
1117 | if (attachmentp->getIsHUDAttachment()) | ||
1118 | { | ||
1119 | LLViewerObject* objectp = attachmentp->getObject(0); | ||
1120 | if (objectp) | ||
1121 | { | ||
1122 | mSelectPickList.insert(objectp); | ||
1123 | for (U32 i = 0; i < objectp->mChildList.size(); i++) | ||
1124 | { | ||
1125 | LLViewerObject* childp = objectp->mChildList[i]; | ||
1126 | if (childp) | ||
1127 | { | ||
1128 | mSelectPickList.insert(childp); | ||
1129 | } | ||
1130 | } | ||
1131 | } | ||
1132 | } | ||
1133 | } | ||
1134 | } | ||
1135 | |||
1136 | S32 num_pickables = (S32)mSelectPickList.size() + LLHUDIcon::getNumInstances(); | ||
1137 | |||
1138 | S32 step = (0x000fffff - GL_NAME_INDEX_OFFSET) / num_pickables; | ||
1139 | |||
1140 | std::set<LLViewerObject*>::iterator pick_it; | ||
1141 | i = 0; | ||
1142 | for (pick_it = mSelectPickList.begin(); pick_it != mSelectPickList.end();) | ||
1143 | { | ||
1144 | LLViewerObject* objp = (*pick_it); | ||
1145 | if (!objp || objp->isDead() || !objp->mbCanSelect) | ||
1146 | { | ||
1147 | mSelectPickList.erase(pick_it++); | ||
1148 | continue; | ||
1149 | } | ||
1150 | |||
1151 | objp->mGLName = (i * step) + GL_NAME_INDEX_OFFSET; | ||
1152 | i++; | ||
1153 | ++pick_it; | ||
1154 | } | ||
1155 | |||
1156 | LLHUDIcon::generatePickIDs(i * step, step); | ||
1157 | } | ||
1158 | |||
1159 | // At this point, we should only have live drawables/viewer objects | ||
1160 | gPipeline.renderForSelect(); | ||
1161 | // | ||
1162 | // Render pass for selected objects | ||
1163 | // | ||
1164 | gViewerWindow->renderSelections( TRUE, pick_parcel_wall, FALSE ); | ||
1165 | |||
1166 | // render pickable ui elements, like names, etc. | ||
1167 | LLHUDObject::renderAllForSelect(); | ||
1168 | |||
1169 | gRenderForSelect = FALSE; | ||
1170 | |||
1171 | //llinfos << "Rendered " << count << " for select" << llendl; | ||
1172 | //llinfos << "Took " << pick_timer.getElapsedTimeF32()*1000.f << "ms to pick" << llendl; | ||
1173 | return 0; | ||
1174 | } | ||
1175 | |||
1176 | LLViewerObject *LLViewerObjectList::getSelectedObject(const U32 object_id) | ||
1177 | { | ||
1178 | std::set<LLViewerObject*>::iterator pick_it; | ||
1179 | for (pick_it = mSelectPickList.begin(); pick_it != mSelectPickList.end(); ++pick_it) | ||
1180 | { | ||
1181 | if ((*pick_it)->mGLName == object_id) | ||
1182 | { | ||
1183 | return (*pick_it); | ||
1184 | } | ||
1185 | } | ||
1186 | return NULL; | ||
1187 | } | ||
1188 | |||
1189 | void LLViewerObjectList::addDebugBeacon(const LLVector3 &pos_agent, | ||
1190 | const LLString &string, | ||
1191 | const LLColor4 &color, | ||
1192 | const LLColor4 &text_color, | ||
1193 | S32 line_width) | ||
1194 | { | ||
1195 | LLDebugBeacon *beaconp = mDebugBeacons.reserve_block(1); | ||
1196 | beaconp->mPositionAgent = pos_agent; | ||
1197 | beaconp->mString = string; | ||
1198 | beaconp->mColor = color; | ||
1199 | beaconp->mTextColor = text_color; | ||
1200 | beaconp->mLineWidth = line_width; | ||
1201 | } | ||
1202 | |||
1203 | void LLViewerObjectList::resetObjectBeacons() | ||
1204 | { | ||
1205 | mDebugBeacons.reset(); | ||
1206 | } | ||
1207 | |||
1208 | LLViewerObject *LLViewerObjectList::createObjectViewer(const LLPCode pcode, LLViewerRegion *regionp) | ||
1209 | { | ||
1210 | LLMemType mt(LLMemType::MTYPE_OBJECT); | ||
1211 | LLUUID fullid; | ||
1212 | fullid.generate(); | ||
1213 | |||
1214 | LLViewerObject *objectp = LLViewerObject::createObject(fullid, pcode, regionp); | ||
1215 | if (!objectp) | ||
1216 | { | ||
1217 | llwarns << "Couldn't create object of type " << LLPrimitive::pCodeToString(pcode) << llendl; | ||
1218 | return NULL; | ||
1219 | } | ||
1220 | |||
1221 | mUUIDObjectMap[fullid] = objectp; | ||
1222 | |||
1223 | mObjects.put(objectp); | ||
1224 | |||
1225 | updateActive(objectp); | ||
1226 | |||
1227 | return objectp; | ||
1228 | } | ||
1229 | |||
1230 | |||
1231 | |||
1232 | LLViewerObject *LLViewerObjectList::createObject(const LLPCode pcode, LLViewerRegion *regionp, | ||
1233 | const LLUUID &uuid, const U32 local_id, const LLHost &sender) | ||
1234 | { | ||
1235 | LLMemType mt(LLMemType::MTYPE_OBJECT); | ||
1236 | LLFastTimer t(LLFastTimer::FTM_CREATE_OBJECT); | ||
1237 | |||
1238 | LLUUID fullid; | ||
1239 | if (uuid == LLUUID::null) | ||
1240 | { | ||
1241 | fullid.generate(); | ||
1242 | } | ||
1243 | else | ||
1244 | { | ||
1245 | fullid = uuid; | ||
1246 | } | ||
1247 | |||
1248 | LLViewerObject *objectp = LLViewerObject::createObject(fullid, pcode, regionp); | ||
1249 | if (!objectp) | ||
1250 | { | ||
1251 | llwarns << "Couldn't create object of type " << LLPrimitive::pCodeToString(pcode) << " id:" << fullid << llendl; | ||
1252 | return NULL; | ||
1253 | } | ||
1254 | |||
1255 | mUUIDObjectMap[fullid] = objectp; | ||
1256 | setUUIDAndLocal(fullid, | ||
1257 | local_id, | ||
1258 | gMessageSystem->getSenderIP(), | ||
1259 | gMessageSystem->getSenderPort()); | ||
1260 | |||
1261 | mObjects.put(objectp); | ||
1262 | |||
1263 | updateActive(objectp); | ||
1264 | |||
1265 | return objectp; | ||
1266 | } | ||
1267 | |||
1268 | LLViewerObject *LLViewerObjectList::replaceObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) | ||
1269 | { | ||
1270 | LLViewerObject *old_instance = findObject(id); | ||
1271 | if (old_instance) | ||
1272 | { | ||
1273 | cleanupReferences(old_instance); | ||
1274 | old_instance->markDead(); | ||
1275 | |||
1276 | return createObject(pcode, regionp, id, old_instance->getLocalID(), LLHost()); | ||
1277 | } | ||
1278 | return NULL; | ||
1279 | } | ||
1280 | |||
1281 | S32 LLViewerObjectList::findReferences(LLDrawable *drawablep) const | ||
1282 | { | ||
1283 | LLViewerObject *objectp; | ||
1284 | S32 i; | ||
1285 | S32 num_refs = 0; | ||
1286 | for (i = 0; i < mObjects.count(); i++) | ||
1287 | { | ||
1288 | objectp = mObjects[i]; | ||
1289 | if (objectp->mDrawable.notNull()) | ||
1290 | { | ||
1291 | num_refs += objectp->mDrawable->findReferences(drawablep); | ||
1292 | } | ||
1293 | } | ||
1294 | return num_refs; | ||
1295 | } | ||
1296 | |||
1297 | |||
1298 | void LLViewerObjectList::orphanize(LLViewerObject *childp, U32 parent_id, U32 ip, U32 port) | ||
1299 | { | ||
1300 | LLMemType mt(LLMemType::MTYPE_OBJECT); | ||
1301 | #ifdef ORPHAN_SPAM | ||
1302 | llinfos << "Orphaning object " << childp->getID() << " with parent " << parent_id << llendl; | ||
1303 | #endif | ||
1304 | |||
1305 | // We're an orphan, flag things appropriately. | ||
1306 | childp->mOrphaned = TRUE; | ||
1307 | if (childp->mDrawable.notNull()) | ||
1308 | { | ||
1309 | bool make_invisible = true; | ||
1310 | LLViewerObject *parentp = (LLViewerObject *)childp->getParent(); | ||
1311 | if (parentp) | ||
1312 | { | ||
1313 | if (parentp->getRegion() != childp->getRegion()) | ||
1314 | { | ||
1315 | // This is probably an object flying across a region boundary, the | ||
1316 | // object probably ISN'T being reparented, but just got an object | ||
1317 | // update out of order (child update before parent). | ||
1318 | make_invisible = false; | ||
1319 | //llinfos << "Don't make object handoffs invisible!" << llendl; | ||
1320 | } | ||
1321 | } | ||
1322 | |||
1323 | if (make_invisible) | ||
1324 | { | ||
1325 | // Make sure that this object becomes invisible if it's an orphan | ||
1326 | childp->mDrawable->setState(LLDrawable::FORCE_INVISIBLE); | ||
1327 | } | ||
1328 | } | ||
1329 | |||
1330 | // Unknown parent, add to orpaned child list | ||
1331 | U64 parent_info = getIndex(parent_id, ip, port); | ||
1332 | |||
1333 | if (-1 == mOrphanParents.find(parent_info)) | ||
1334 | { | ||
1335 | mOrphanParents.put(parent_info); | ||
1336 | } | ||
1337 | |||
1338 | LLViewerObjectList::OrphanInfo oi(parent_info, childp->mID); | ||
1339 | if (-1 == mOrphanChildren.find(oi)) | ||
1340 | { | ||
1341 | mOrphanChildren.put(oi); | ||
1342 | mNumOrphans++; | ||
1343 | } | ||
1344 | } | ||
1345 | |||
1346 | |||
1347 | void LLViewerObjectList::findOrphans(LLViewerObject* objectp, U32 ip, U32 port) | ||
1348 | { | ||
1349 | if (gNoRender) | ||
1350 | { | ||
1351 | return; | ||
1352 | } | ||
1353 | |||
1354 | if (objectp->isDead()) | ||
1355 | { | ||
1356 | llwarns << "Trying to find orphans for dead obj " << objectp->mID | ||
1357 | << ":" << objectp->getPCodeString() << llendl; | ||
1358 | return; | ||
1359 | } | ||
1360 | |||
1361 | // See if we are a parent of an orphan. | ||
1362 | // Note: This code is fairly inefficient but it should happen very rarely. | ||
1363 | // It can be sped up if this is somehow a performance issue... | ||
1364 | if (0 == mOrphanParents.count()) | ||
1365 | { | ||
1366 | // no known orphan parents | ||
1367 | return; | ||
1368 | } | ||
1369 | if (-1 == mOrphanParents.find(getIndex(objectp->mLocalID, ip, port))) | ||
1370 | { | ||
1371 | // did not find objectp in OrphanParent list | ||
1372 | return; | ||
1373 | } | ||
1374 | |||
1375 | S32 i; | ||
1376 | U64 parent_info = getIndex(objectp->mLocalID, ip, port); | ||
1377 | BOOL orphans_found = FALSE; | ||
1378 | // Iterate through the orphan list, and set parents of matching children. | ||
1379 | for (i = 0; i < mOrphanChildren.count(); i++) | ||
1380 | { | ||
1381 | if (mOrphanChildren[i].mParentInfo != parent_info) | ||
1382 | { | ||
1383 | continue; | ||
1384 | } | ||
1385 | LLViewerObject *childp = findObject(mOrphanChildren[i].mChildInfo); | ||
1386 | if (childp) | ||
1387 | { | ||
1388 | if (childp == objectp) | ||
1389 | { | ||
1390 | llwarns << objectp->mID << " has self as parent, skipping!" | ||
1391 | << llendl; | ||
1392 | continue; | ||
1393 | } | ||
1394 | |||
1395 | #ifdef ORPHAN_SPAM | ||
1396 | llinfos << "Reunited parent " << objectp->mID | ||
1397 | << " with child " << childp->mID << llendl; | ||
1398 | llinfos << "Glob: " << objectp->getPositionGlobal() << llendl; | ||
1399 | llinfos << "Agent: " << objectp->getPositionAgent() << llendl; | ||
1400 | addDebugBeacon(objectp->getPositionAgent(),""); | ||
1401 | #endif | ||
1402 | gPipeline.markMoved(objectp->mDrawable); | ||
1403 | objectp->setChanged(LLXform::MOVED | LLXform::SILHOUETTE); | ||
1404 | |||
1405 | // Flag the object as no longer orphaned | ||
1406 | childp->mOrphaned = FALSE; | ||
1407 | if (childp->mDrawable.notNull()) | ||
1408 | { | ||
1409 | // Make the drawable visible again and set the drawable parent | ||
1410 | childp->mDrawable->setState(LLDrawable::CLEAR_INVISIBLE); | ||
1411 | childp->setDrawableParent(objectp->mDrawable); // LLViewerObjectList::findOrphans() | ||
1412 | } | ||
1413 | objectp->addChild(childp); | ||
1414 | orphans_found = TRUE; | ||
1415 | } | ||
1416 | else | ||
1417 | { | ||
1418 | llinfos << "Missing orphan child, removing from list" << llendl; | ||
1419 | mOrphanChildren.remove(i); | ||
1420 | i--; | ||
1421 | } | ||
1422 | } | ||
1423 | |||
1424 | // Remove orphan parent and children from lists now that they've been found | ||
1425 | mOrphanParents.remove(mOrphanParents.find(parent_info)); | ||
1426 | |||
1427 | i = 0; | ||
1428 | while (i < mOrphanChildren.count()) | ||
1429 | { | ||
1430 | if (mOrphanChildren[i].mParentInfo == parent_info) | ||
1431 | { | ||
1432 | mOrphanChildren.remove(i); | ||
1433 | mNumOrphans--; | ||
1434 | } | ||
1435 | else | ||
1436 | { | ||
1437 | i++; | ||
1438 | } | ||
1439 | } | ||
1440 | |||
1441 | if (orphans_found && objectp->isSelected()) | ||
1442 | { | ||
1443 | LLSelectNode* nodep = gSelectMgr->findSelectNode(objectp); | ||
1444 | if (nodep && !nodep->mIndividualSelection) | ||
1445 | { | ||
1446 | // rebuild selection with orphans | ||
1447 | gSelectMgr->deselectObjectAndFamily(objectp); | ||
1448 | gSelectMgr->selectObjectAndFamily(objectp); | ||
1449 | } | ||
1450 | } | ||
1451 | } | ||
1452 | |||
1453 | |||
1454 | LLViewerObjectList::OrphanInfo::OrphanInfo() | ||
1455 | { | ||
1456 | } | ||
1457 | |||
1458 | LLViewerObjectList::OrphanInfo::OrphanInfo(const U64 parent_info, const LLUUID child_info) | ||
1459 | : mParentInfo(parent_info), mChildInfo(child_info) | ||
1460 | { | ||
1461 | } | ||
1462 | |||
1463 | bool LLViewerObjectList::OrphanInfo::operator==(const OrphanInfo &rhs) const | ||
1464 | { | ||
1465 | return (mParentInfo == rhs.mParentInfo) && (mChildInfo == rhs.mChildInfo); | ||
1466 | } | ||
1467 | |||
1468 | bool LLViewerObjectList::OrphanInfo::operator!=(const OrphanInfo &rhs) const | ||
1469 | { | ||
1470 | return !operator==(rhs); | ||
1471 | } | ||
1472 | |||