aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llviewerobject.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/newview/llviewerobject.cpp
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/newview/llviewerobject.cpp')
-rw-r--r--linden/indra/newview/llviewerobject.cpp4666
1 files changed, 4666 insertions, 0 deletions
diff --git a/linden/indra/newview/llviewerobject.cpp b/linden/indra/newview/llviewerobject.cpp
new file mode 100644
index 0000000..d034aa7
--- /dev/null
+++ b/linden/indra/newview/llviewerobject.cpp
@@ -0,0 +1,4666 @@
1/**
2 * @file llviewerobject.cpp
3 * @brief Base class for viewer objects
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 "llviewerobject.h"
31
32#include "audioengine.h"
33#include "imageids.h"
34#include "indra_constants.h"
35#include "llmath.h"
36#include "llflexibleobject.h"
37#include "llviewercontrol.h"
38#include "lldatapacker.h"
39#include "llfasttimer.h"
40#include "llfontgl.h"
41#include "llframetimer.h"
42#include "llinventory.h"
43#include "llmaterialtable.h"
44#include "llmutelist.h"
45#include "llnamevalue.h"
46#include "llprimitive.h"
47#include "llquantize.h"
48#include "llregionhandle.h"
49#include "lltree_common.h"
50#include "llxfermanager.h"
51#include "message.h"
52#include "object_flags.h"
53#include "timing.h"
54
55#include "llaudiosourcevo.h"
56#include "llagent.h"
57#include "llbbox.h"
58#include "llbox.h"
59#include "llcylinder.h"
60#include "lldrawable.h"
61#include "llface.h"
62#include "llfloaterproperties.h"
63#include "llfollowcam.h"
64#include "llnetmap.h"
65#include "llselectmgr.h"
66#include "llsphere.h"
67#include "lltooldraganddrop.h"
68#include "llviewercamera.h"
69#include "llviewerimagelist.h"
70#include "llviewerinventory.h"
71#include "llviewerobjectlist.h"
72#include "llviewerparceloverlay.h"
73#include "llviewerpartsource.h"
74#include "llviewerregion.h"
75#include "llviewertextureanim.h"
76#include "llviewerwindow.h" // For getSpinAxis
77#include "llvoavatar.h"
78#include "llvoclouds.h"
79#include "llvograss.h"
80#include "llvoground.h"
81#include "llvolume.h"
82#include "llvolumemessage.h"
83#include "llvopart.h"
84#include "llvopartgroup.h"
85#include "llvosky.h"
86#include "llvostars.h"
87#include "llvosurfacepatch.h"
88#include "llvotextbubble.h"
89#include "llvotree.h"
90#include "llvotreenew.h"
91#include "llvovolume.h"
92#include "llvowater.h"
93#include "llworld.h"
94#include "llui.h"
95#include "pipeline.h"
96#include "viewer.h"
97
98//#define DEBUG_UPDATE_TYPE
99
100extern BOOL gVelocityInterpolate;
101extern BOOL gPingInterpolate;
102extern U32 gFrameCount;
103
104U32 LLViewerObject::sNumZombieObjects = 0;
105S32 LLViewerObject::sNumObjects = 0;
106BOOL LLViewerObject::sMapDebug = TRUE;
107LLColor4 LLViewerObject::sEditSelectColor( 1.0f, 1.f, 0.f, 0.3f); // Edit OK
108LLColor4 LLViewerObject::sNoEditSelectColor( 1.0f, 0.f, 0.f, 0.3f); // Can't edit
109S32 LLViewerObject::sAxisArrowLength(50);
110BOOL LLViewerObject::sPulseEnabled(FALSE);
111BOOL LLViewerObject::sUseSharedDrawables(FALSE); // TRUE
112
113// static
114LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
115{
116 LLViewerObject *res = NULL;
117 LLFastTimer t1(LLFastTimer::FTM_CREATE_OBJECT);
118
119 switch (pcode)
120 {
121 case LL_PCODE_VOLUME:
122 res = new LLVOVolume(id, pcode, regionp); break;
123 case LL_PCODE_LEGACY_AVATAR:
124 res = new LLVOAvatar(id, pcode, regionp); break;
125 case LL_PCODE_LEGACY_GRASS:
126 res = new LLVOGrass(id, pcode, regionp); break;
127 case LL_PCODE_LEGACY_PART_SYS:
128 res = new LLVOPart(id, pcode, regionp); break;
129 case LL_PCODE_LEGACY_TREE:
130 res = new LLVOTree(id, pcode, regionp); break;
131 case LL_PCODE_TREE_NEW:
132 llwarns << "Creating new tree!" << llendl;
133// res = new LLVOTree(id, pcode, regionp); break;
134// res = new LLVOTreeNew(id, pcode, regionp); break;
135 res = NULL; break;
136 case LL_PCODE_LEGACY_TEXT_BUBBLE:
137 res = new LLVOTextBubble(id, pcode, regionp); break;
138 case LL_VO_CLOUDS:
139 res = new LLVOClouds(id, pcode, regionp); break;
140 case LL_VO_SURFACE_PATCH:
141 res = new LLVOSurfacePatch(id, pcode, regionp); break;
142 case LL_VO_SKY:
143 res = new LLVOSky(id, pcode, regionp); break;
144 case LL_VO_STARS:
145 res = new LLVOStars(id, pcode, regionp); break;
146 case LL_VO_WATER:
147 res = new LLVOWater(id, pcode, regionp); break;
148 case LL_VO_GROUND:
149 res = new LLVOGround(id, pcode, regionp); break;
150 case LL_VO_PART_GROUP:
151 res = new LLVOPartGroup(id, pcode, regionp); break;
152 default:
153 llwarns << "Unknown object pcode " << (S32)pcode << llendl;
154 res = NULL; break;
155 }
156 return res;
157}
158
159LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
160: LLPrimitive(),
161 mChildList(),
162 mID(id),
163 mLocalID(0),
164 mTotalCRC(0),
165 mTEImages(NULL),
166 mGLName(0),
167 mbCanSelect(TRUE),
168 mFlags(0),
169 mDrawable(),
170 mCreateSelected(FALSE),
171 mRenderMedia(FALSE),
172 mBestUpdatePrecision(0),
173 mText(),
174 mLastInterpUpdateSecs(0.f),
175 mLastMessageUpdateSecs(0.f),
176 mData(NULL),
177 mAudioSourcep(NULL),
178 mAppAngle(0.f),
179 mPixelArea(0.f),
180 mInventory(NULL),
181 mInventorySerialNum(0),
182 mRegionp( regionp ),
183 mInventoryPending(FALSE),
184 mInventoryDirty(FALSE),
185 mDead(FALSE),
186 mOrphaned(FALSE),
187 mUserSelected(FALSE),
188 mOnActiveList(FALSE),
189 mOnMap(FALSE),
190 mStatic(FALSE),
191 mFaceIndexOffset(0),
192 mNumFaces(0),
193 mLastUpdateFrame(0),
194 mTimeDilation(1.f),
195 mRotTime(0.f),
196 mJointInfo(NULL),
197 mState(0),
198 mMedia(NULL),
199 mClickAction(0)
200{
201 llassert(mRegionp);
202
203 LLPrimitive::init(pcode);
204
205 // CP: added 12/2/2005 - this was being initialised to 0, not the current frame time
206 mLastInterpUpdateSecs = LLFrameTimer::getElapsedSeconds();
207
208 mPositionRegion = LLVector3(0.f, 0.f, 0.f);
209 mPositionAgent = mRegionp->getOriginAgent();
210
211 LLViewerObject::sNumObjects++;
212}
213
214LLViewerObject::~LLViewerObject()
215{
216 deleteTEImages();
217
218 if(mInventory)
219 {
220 mInventory->clear(); // will deref and delete entries
221 delete mInventory;
222 mInventory = NULL;
223 }
224
225 if (mJointInfo)
226 {
227 delete mJointInfo;
228 mJointInfo = NULL;
229 }
230
231 // Delete memory associated with extra parameters.
232 std::map<U16, ExtraParameter*>::iterator iter;
233 for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter)
234 {
235 delete iter->second->data;
236 delete iter->second;
237 }
238 mExtraParameterList.clear();
239
240 for_each(mNameValuePairs.begin(), mNameValuePairs.end(), DeletePairedPointer()) ;
241 mNameValuePairs.clear();
242
243 delete[] mData;
244 mData = NULL;
245
246 delete mMedia;
247 mMedia = NULL;
248
249 sNumObjects--;
250 sNumZombieObjects--;
251 llassert(mChildList.size() == 0);
252
253 clearInventoryListeners();
254}
255
256void LLViewerObject::deleteTEImages()
257{
258 delete[] mTEImages;
259 mTEImages = NULL;
260}
261
262void LLViewerObject::markDead()
263{
264 if (!mDead)
265 {
266 //llinfos << "Marking self " << mLocalID << " as dead." << llendl;
267
268 // Root object of this hierarchy unlinks itself.
269 if (getParent())
270 {
271 ((LLViewerObject *)getParent())->removeChild(this);
272 // go ahead and delete any jointinfo's that we find
273 delete mJointInfo;
274 mJointInfo = NULL;
275 }
276
277 // Mark itself as dead
278 mDead = TRUE;
279 gObjectList.cleanupReferences(this);
280
281 LLViewerObject *childp;
282 while (mChildList.size() > 0)
283 {
284 childp = mChildList[0];
285 if (childp->getPCode() != LL_PCODE_LEGACY_AVATAR)
286 {
287 //llinfos << "Marking child " << childp->getLocalID() << " as dead." << llendl;
288 childp->setParent(NULL); // LLViewerObject::markDead 1
289 childp->markDead();
290 }
291 else
292 {
293 // make sure avatar is no longer parented,
294 // so we can properly set it's position
295 childp->setDrawableParent(NULL);
296 ((LLVOAvatar*)childp)->getOffObject();
297 childp->setParent(NULL); // LLViewerObject::markDead 2
298 }
299 mChildList.erase(mChildList.begin());
300 }
301
302 if (mDrawable.notNull())
303 {
304 // Drawables are reference counted, mark as dead, then nuke the pointer.
305 mDrawable->markDead();
306 mDrawable = NULL;
307 }
308
309 if (mText)
310 {
311 mText->markDead();
312 mText = NULL;
313 }
314
315 if (mIcon)
316 {
317 mIcon->markDead();
318 mIcon = NULL;
319 }
320
321 if (mPartSourcep)
322 {
323 mPartSourcep->setDead();
324 mPartSourcep = NULL;
325 }
326
327 if (mAudioSourcep)
328 {
329 // Do some cleanup
330 if (gAudiop)
331 {
332 gAudiop->cleanupAudioSource(mAudioSourcep);
333 }
334 mAudioSourcep = NULL;
335 }
336
337 if (flagAnimSource())
338 {
339 LLVOAvatar* avatarp = gAgent.getAvatarObject();
340 if (avatarp && !avatarp->isDead())
341 {
342 // stop motions associated with this object
343 avatarp->stopMotionFromSource(mID);
344 }
345 }
346
347 if (flagCameraSource())
348 {
349 LLFollowCamMgr::removeFollowCamParams(mID);
350 }
351
352 sNumZombieObjects++;
353 }
354}
355
356void LLViewerObject::dump() const
357{
358 llinfos << "Type: " << pCodeToString(mPrimitiveCode) << llendl;
359 llinfos << "Drawable: " << (LLDrawable *)mDrawable << llendl;
360 llinfos << "Update Age: " << LLFrameTimer::getElapsedSeconds() - mLastMessageUpdateSecs << llendl;
361
362 llinfos << "Parent: " << getParent() << llendl;
363 llinfos << "ID: " << mID << llendl;
364 llinfos << "LocalID: " << mLocalID << llendl;
365 llinfos << "PositionRegion: " << getPositionRegion() << llendl;
366 llinfos << "PositionAgent: " << getPositionAgent() << llendl;
367 llinfos << "PositionGlobal: " << getPositionGlobal() << llendl;
368 llinfos << "Velocity: " << getVelocity() << llendl;
369 if (mDrawable.notNull() && mDrawable->getNumFaces())
370 {
371 LLDrawPool *poolp = mDrawable->getFace(0)->getPool();
372 llinfos << "Pool: " << poolp << llendl;
373 llinfos << "Pool reference count: " << poolp->mReferences.size() << llendl;
374 llinfos << "Pool vertex count: " << poolp->getVertexCount() << llendl;
375 }
376 //llinfos << "BoxTree Min: " << mDrawable->getBox()->getMin() << llendl;
377 //llinfos << "BoxTree Max: " << mDrawable->getBox()->getMin() << llendl;
378 /*
379 llinfos << "Velocity: " << getVelocity() << llendl;
380 llinfos << "AnyOwner: " << permAnyOwner() << " YouOwner: " << permYouOwner() << " Edit: " << mPermEdit << llendl;
381 llinfos << "UsePhysics: " << usePhysics() << " CanSelect " << mbCanSelect << " UserSelected " << mUserSelected << llendl;
382 llinfos << "AppAngle: " << mAppAngle << llendl;
383 llinfos << "PixelArea: " << mPixelArea << llendl;
384
385 char buffer[1000];
386 char *key;
387 for (key = mNameValuePairs.getFirstKey(); key; key = mNameValuePairs.getNextKey() )
388 {
389 mNameValuePairs[key]->printNameValue(buffer);
390 llinfos << buffer << llendl;
391 }
392
393 S32 i;
394
395 LLViewerObject *child;
396 for (i = 0; i < mChildList.size(); i++)
397 {
398 child = mChildList[i];
399 llinfos << " child " << child->getID() << llendl;
400 }
401 */
402}
403
404void LLViewerObject::printNameValuePairs() const
405{
406 for (name_value_map_t::const_iterator iter = mNameValuePairs.begin();
407 iter != mNameValuePairs.end(); iter++)
408 {
409 LLNameValue* nv = iter->second;
410 llinfos << nv->printNameValue() << llendl;
411 }
412}
413
414void LLViewerObject::initVOClasses()
415{
416 // Initialized shared class stuff first.
417 LLVOAvatar::initClass();
418 LLVOTree::initClass();
419 if (gNoRender)
420 {
421 // Don't init anything else in drone mode
422 return;
423 }
424 llinfos << "Viewer Object size: " << sizeof(LLViewerObject) << llendl;
425 LLVOGrass::initClass();
426 LLVOPart::initClass();
427 LLVOWater::initClass();
428 LLVOSky::initClass();
429 LLVOVolume::initClass();
430}
431
432void LLViewerObject::cleanupVOClasses()
433{
434 LLVOGrass::cleanupClass();
435 LLVOWater::cleanupClass();
436 LLVOTree::cleanupClass();
437 LLVOAvatar::cleanupClass();
438}
439
440// Replaces all name value pairs with data from \n delimited list
441// Does not update server
442void LLViewerObject::setNameValueList(const std::string& name_value_list)
443{
444 // Clear out the old
445 for_each(mNameValuePairs.begin(), mNameValuePairs.end(), DeletePairedPointer()) ;
446 mNameValuePairs.clear();
447
448 // Bring in the new
449 std::string::size_type length = name_value_list.length();
450 std::string::size_type start = 0;
451 while (start < length)
452 {
453 std::string::size_type end = name_value_list.find_first_of("\n", start);
454 if (end == std::string::npos) end = length;
455 if (end > start)
456 {
457 std::string tok = name_value_list.substr(start, end - start);
458 addNVPair(tok.c_str());
459 }
460 start = end+1;
461 }
462}
463
464
465// This method returns true if the object is over land owned by the
466// agent.
467BOOL LLViewerObject::isOverAgentOwnedLand() const
468{
469 return mRegionp
470 && mRegionp->getParcelOverlay()
471 && mRegionp->getParcelOverlay()->isOwnedSelf(getPositionRegion());
472}
473
474// This method returns true if the object is over land owned by the
475// agent.
476BOOL LLViewerObject::isOverGroupOwnedLand() const
477{
478 return mRegionp
479 && mRegionp->getParcelOverlay()
480 && mRegionp->getParcelOverlay()->isOwnedGroup(getPositionRegion());
481}
482
483void LLViewerObject::setParent(LLViewerObject* parent)
484{
485 LLPrimitive::setParent(parent);
486}
487
488void LLViewerObject::addChild(LLViewerObject *childp)
489{
490 BOOL result = TRUE;
491
492 for (child_list_t::iterator i = mChildList.begin(); i != mChildList.end(); ++i)
493 {
494 if (*i == childp)
495 { //already has child
496 return;
497 }
498 }
499
500 if (!isAvatar())
501 {
502 // propagate selection properties
503 childp->mbCanSelect = mbCanSelect;
504 }
505
506 childp->setParent(this);
507 mChildList.push_back(childp);
508
509 if (!result)
510 {
511 llwarns << "Failed to attach child " << childp->getID() << " to object " << getID() << llendl;
512 removeChild(childp);
513 if (mJointInfo)
514 {
515 delete mJointInfo;
516 mJointInfo = NULL;
517 }
518 }
519}
520
521void LLViewerObject::removeChild(LLViewerObject *childp)
522{
523 for (child_list_t::iterator i = mChildList.begin(); i != mChildList.end(); ++i)
524 {
525 if (*i == childp)
526 {
527 if (!childp->isAvatar() && mDrawable.notNull() && mDrawable->isActive() && childp->mDrawable.notNull() && !isAvatar())
528 {
529 gPipeline.markRebuild(childp->mDrawable, LLDrawable::REBUILD_VOLUME);
530 }
531
532 mChildList.erase(i);
533 childp->setParent(NULL);
534 break;
535 }
536 }
537
538 if (childp->isSelected())
539 {
540 gSelectMgr->deselectObjectAndFamily(childp);
541 BOOL add_to_end = TRUE;
542 gSelectMgr->selectObjectAndFamily(childp, add_to_end);
543 }
544}
545
546LLViewerObject::child_list_t& LLViewerObject::getChildren()
547{
548 return mChildList;
549}
550
551void LLViewerObject::addThisAndAllChildren(LLDynamicArray<LLViewerObject*>& objects)
552{
553 objects.put(this);
554 S32 count = mChildList.size();
555 for(S32 i = 0; i < count; i++)
556 {
557 if (!mChildList[i]->isAvatar())
558 {
559 (mChildList[i])->addThisAndAllChildren(objects);
560 }
561 }
562}
563
564void LLViewerObject::addThisAndNonJointChildren(LLDynamicArray<LLViewerObject*>& objects)
565{
566 objects.put(this);
567 // don't add any attachments when temporarily selecting avatar
568 if (isAvatar())
569 {
570 return;
571 }
572 S32 count = mChildList.size();
573 for(S32 i = 0; i < count; i++)
574 {
575 if ( (!mChildList[i]->isAvatar())
576 && (!mChildList[i]->isJointChild()))
577 {
578 (mChildList[i])->addThisAndNonJointChildren(objects);
579 }
580 }
581}
582
583BOOL LLViewerObject::isChild(LLViewerObject *childp) const
584{
585 S32 count = mChildList.size();
586 for(S32 i = 0; i < count; i++)
587 {
588 const LLViewerObject *testChildp = &(*mChildList[i]);
589 if (testChildp == childp) return TRUE;
590 }
591 return FALSE;
592}
593
594
595// returns TRUE if at least one avatar is sitting on this object
596BOOL LLViewerObject::isSeat() const
597{
598 S32 count = mChildList.size();
599 for(S32 i = 0; i < count; i++)
600 {
601 const LLViewerObject *childp = &(*mChildList[i]);
602 if (childp->isAvatar())
603 {
604 return TRUE;
605 }
606 }
607 return FALSE;
608
609}
610
611BOOL LLViewerObject::setDrawableParent(LLDrawable* parentp)
612{
613 if (mDrawable.isNull())
614 {
615 return FALSE;
616 }
617
618 mDrawable->mParent = parentp;
619
620 BOOL ret = mDrawable->mXform.setParent(parentp ? &parentp->mXform : NULL);
621 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE);
622 gPipeline.markMoved(mDrawable, FALSE);
623
624 return ret;
625}
626
627U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
628 void **user_data,
629 U32 block_num,
630 const EObjectUpdateType update_type,
631 LLDataPacker *dp)
632{
633 LLMemType mt(LLMemType::MTYPE_OBJECT);
634
635 U32 retval = 0x0;
636
637 // Coordinates of objects on simulators are region-local.
638 U64 region_handle;
639 mesgsys->getU64Fast(_PREHASH_RegionData, _PREHASH_RegionHandle, region_handle);
640 mRegionp = gWorldPointer->getRegionFromHandle(region_handle);
641 if (!mRegionp)
642 {
643 U32 x, y;
644 from_region_handle(region_handle, &x, &y);
645
646 llerrs << "Object has invalid region " << x << ":" << y << "!" << llendl;
647 }
648
649 U16 time_dilation16;
650 mesgsys->getU16Fast(_PREHASH_RegionData, _PREHASH_TimeDilation, time_dilation16);
651 F32 time_dilation = ((F32) time_dilation16) / 65535.f;
652 mTimeDilation = time_dilation;
653 mRegionp->setTimeDilation(time_dilation);
654
655 // this will be used to determine if we've really changed position
656 // Use getPosition, not getPositionRegion, since this is what we're comparing directly against.
657 LLVector3 test_pos_parent = getPosition();
658
659 U8 data[60+16]; // This needs to match the largest size below.
660#ifdef LL_BIG_ENDIAN
661 U16 valswizzle[4];
662#endif
663 U16 *val;
664 const F32 size = gWorldPointer->getRegionWidthInMeters();
665 const F32 MAX_HEIGHT = gWorldPointer->getRegionMaxHeight();
666 const F32 MIN_HEIGHT = gWorldPointer->getRegionMinHeight();
667 S32 length;
668 S32 count;
669 S32 this_update_precision = 32; // in bits
670
671 // Temporaries, because we need to compare w/ previous to set dirty flags...
672 LLVector3 new_pos_parent;
673 LLVector3 new_vel;
674 LLVector3 new_acc;
675 LLVector3 new_angv;
676 LLQuaternion new_rot;
677 LLVector3 new_scale;
678
679 U32 parent_id = 0;
680 U8 material = 0;
681 U8 click_action = 0;
682 U32 crc = 0;
683
684 bool old_special_hover_cursor = specialHoverCursor();
685
686 LLViewerObject *cur_parentp = (LLViewerObject *)getParent();
687
688 if (cur_parentp)
689 {
690 parent_id = cur_parentp->mLocalID;
691 }
692
693 if (!dp)
694 {
695 switch(update_type)
696 {
697 case OUT_FULL:
698 {
699#ifdef DEBUG_UPDATE_TYPE
700 llinfos << "Full:" << getID() << llendl;
701#endif
702 LLUUID audio_uuid;
703 LLUUID owner_id; // only valid if audio_uuid or particle system is not null
704 F32 gain;
705 U8 sound_flags;
706
707 mesgsys->getU32Fast( _PREHASH_ObjectData, _PREHASH_CRC, crc, block_num);
708 mesgsys->getU32Fast( _PREHASH_ObjectData, _PREHASH_ParentID, parent_id, block_num);
709 mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_Sound, audio_uuid, block_num );
710 // HACK: Owner id only valid if non-null sound id or particle system
711 mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_OwnerID, owner_id, block_num );
712 mesgsys->getF32Fast( _PREHASH_ObjectData, _PREHASH_Gain, gain, block_num );
713 mesgsys->getU8Fast( _PREHASH_ObjectData, _PREHASH_Flags, sound_flags, block_num );
714 mesgsys->getU8Fast( _PREHASH_ObjectData, _PREHASH_Material, material, block_num );
715 mesgsys->getU8Fast( _PREHASH_ObjectData, _PREHASH_ClickAction, click_action, block_num);
716 mesgsys->getVector3Fast(_PREHASH_ObjectData, _PREHASH_Scale, new_scale, block_num );
717 length = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_ObjectData);
718 mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_ObjectData, data, length, block_num);
719
720 mTotalCRC = crc;
721
722 // Owner ID used for sound muting or particle system muting
723 setAttachedSound(audio_uuid, owner_id, gain, sound_flags);
724
725 U8 old_material = getMaterial();
726 if (old_material != material)
727 {
728 setMaterial(material);
729 if (mDrawable.notNull())
730 {
731 gPipeline.markMoved(mDrawable, FALSE); // undamped
732 }
733 }
734 setClickAction(click_action);
735
736 count = 0;
737 LLVector4 collision_plane;
738
739 switch(length)
740 {
741 case (60 + 16):
742 // pull out collision normal for avatar
743 htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4));
744 ((LLVOAvatar*)this)->setFootPlane(collision_plane);
745 count += sizeof(LLVector4);
746 case 60:
747 this_update_precision = 32;
748 // this is a terse update
749 // pos
750 htonmemcpy(new_pos_parent.mV, &data[count], MVT_LLVector3, sizeof(LLVector3));
751 count += sizeof(LLVector3);
752 // vel
753 htonmemcpy((void*)getVelocity().mV, &data[count], MVT_LLVector3, sizeof(LLVector3));
754 count += sizeof(LLVector3);
755 // acc
756 htonmemcpy((void*)getAcceleration().mV, &data[count], MVT_LLVector3, sizeof(LLVector3));
757 count += sizeof(LLVector3);
758 // theta
759 {
760 LLVector3 vec;
761 htonmemcpy(vec.mV, &data[count], MVT_LLVector3, sizeof(LLVector3));
762 new_rot.unpackFromVector3(vec);
763 }
764 count += sizeof(LLVector3);
765 // omega
766 htonmemcpy((void*)new_angv.mV, &data[count], MVT_LLVector3, sizeof(LLVector3));
767 if (new_angv.isExactlyZero())
768 {
769 // reset rotation time
770 resetRot();
771 }
772 setAngularVelocity(new_angv);
773#if LL_DARWIN
774 if (length == 76)
775 {
776 setAngularVelocity(LLVector3::zero);
777 }
778#endif
779 break;
780 case(32 + 16):
781 // pull out collision normal for avatar
782 htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4));
783 ((LLVOAvatar*)this)->setFootPlane(collision_plane);
784 count += sizeof(LLVector4);
785 case 32:
786 this_update_precision = 16;
787 test_pos_parent.quantize16(-0.5f*size, 1.5f*size, MIN_HEIGHT, MAX_HEIGHT);
788
789 // This is a terse 16 update, so treat data as an array of U16's.
790#ifdef LL_BIG_ENDIAN
791 htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6);
792 val = valswizzle;
793#else
794 val = (U16 *) &data[count];
795#endif
796 count += sizeof(U16)*3;
797 new_pos_parent.mV[VX] = U16_to_F32(val[VX], -0.5f*size, 1.5f*size);
798 new_pos_parent.mV[VY] = U16_to_F32(val[VY], -0.5f*size, 1.5f*size);
799 new_pos_parent.mV[VZ] = U16_to_F32(val[VZ], MIN_HEIGHT, MAX_HEIGHT);
800
801#ifdef LL_BIG_ENDIAN
802 htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6);
803 val = valswizzle;
804#else
805 val = (U16 *) &data[count];
806#endif
807 count += sizeof(U16)*3;
808 setVelocity(LLVector3(U16_to_F32(val[VX], -size, size),
809 U16_to_F32(val[VY], -size, size),
810 U16_to_F32(val[VZ], -size, size)));
811
812#ifdef LL_BIG_ENDIAN
813 htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6);
814 val = valswizzle;
815#else
816 val = (U16 *) &data[count];
817#endif
818 count += sizeof(U16)*3;
819 setAcceleration(LLVector3(U16_to_F32(val[VX], -size, size),
820 U16_to_F32(val[VY], -size, size),
821 U16_to_F32(val[VZ], -size, size)));
822
823#ifdef LL_BIG_ENDIAN
824 htonmemcpy(valswizzle, &data[count], MVT_U16Quat, 4);
825 val = valswizzle;
826#else
827 val = (U16 *) &data[count];
828#endif
829 count += sizeof(U16)*4;
830 new_rot.mQ[VX] = U16_to_F32(val[VX], -1.f, 1.f);
831 new_rot.mQ[VY] = U16_to_F32(val[VY], -1.f, 1.f);
832 new_rot.mQ[VZ] = U16_to_F32(val[VZ], -1.f, 1.f);
833 new_rot.mQ[VW] = U16_to_F32(val[VW], -1.f, 1.f);
834
835#ifdef LL_BIG_ENDIAN
836 htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6);
837 val = valswizzle;
838#else
839 val = (U16 *) &data[count];
840#endif
841 new_angv.setVec(U16_to_F32(val[VX], -size, size),
842 U16_to_F32(val[VY], -size, size),
843 U16_to_F32(val[VZ], -size, size));
844 if (new_angv.isExactlyZero())
845 {
846 // reset rotation time
847 resetRot();
848 }
849 setAngularVelocity(new_angv);
850 break;
851
852 case 16:
853 this_update_precision = 8;
854 test_pos_parent.quantize8(-0.5f*size, 1.5f*size, MIN_HEIGHT, MAX_HEIGHT);
855 // this is a terse 8 update
856 new_pos_parent.mV[VX] = U8_to_F32(data[0], -0.5f*size, 1.5f*size);
857 new_pos_parent.mV[VY] = U8_to_F32(data[1], -0.5f*size, 1.5f*size);
858 new_pos_parent.mV[VZ] = U8_to_F32(data[2], MIN_HEIGHT, MAX_HEIGHT);
859
860 setVelocity(U8_to_F32(data[3], -size, size),
861 U8_to_F32(data[4], -size, size),
862 U8_to_F32(data[5], -size, size) );
863
864 setAcceleration(U8_to_F32(data[6], -size, size),
865 U8_to_F32(data[7], -size, size),
866 U8_to_F32(data[8], -size, size) );
867
868 new_rot.mQ[VX] = U8_to_F32(data[9], -1.f, 1.f);
869 new_rot.mQ[VY] = U8_to_F32(data[10], -1.f, 1.f);
870 new_rot.mQ[VZ] = U8_to_F32(data[11], -1.f, 1.f);
871 new_rot.mQ[VW] = U8_to_F32(data[12], -1.f, 1.f);
872
873 new_angv.setVec(U8_to_F32(data[13], -size, size),
874 U8_to_F32(data[14], -size, size),
875 U8_to_F32(data[15], -size, size) );
876 if (new_angv.isExactlyZero())
877 {
878 // reset rotation time
879 resetRot();
880 }
881 setAngularVelocity(new_angv);
882 break;
883 }
884
885 ////////////////////////////////////////////////////
886 //
887 // Here we handle data specific to the full message.
888 //
889
890 U32 flags;
891 mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, block_num);
892 // clear all but local flags
893 mFlags &= FLAGS_LOCAL;
894 mFlags |= flags;
895
896 U8 state;
897 mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_State, state, block_num );
898 mState = state;
899
900 // ...new objects that should come in selected need to be added to the selected list
901 mCreateSelected = ((flags & FLAGS_CREATE_SELECTED) != 0);
902
903 // Set the change flags for scale
904 if (new_scale != getScale())
905 {
906 setChanged(SCALED | SILHOUETTE);
907 setScale(new_scale); // Must follow setting permYouOwner()
908 }
909
910 // Set all name value pairs
911 S32 nv_size = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_NameValue);
912 if (nv_size > 0)
913 {
914 char* name_value_list = new char[nv_size];
915 mesgsys->getStringFast(_PREHASH_ObjectData, _PREHASH_NameValue, nv_size, name_value_list, block_num);
916
917 setNameValueList(name_value_list);
918
919 delete [] name_value_list;
920 }
921
922 // Clear out any existing generic data
923 if (mData)
924 {
925 delete [] mData;
926 }
927
928 // Check for appended generic data
929 S32 data_size = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_Data);
930 if (data_size == 0)
931 {
932 mData = NULL;
933 }
934 else
935 {
936 // ...has generic data
937 mData = new U8[data_size];
938 mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_Data, mData, data_size, block_num);
939 }
940
941 S32 text_size = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_Text);
942 if (text_size > 1)
943 {
944 // Setup object text
945 if (!mText)
946 {
947 mText = (LLHUDText *)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_TEXT);
948 mText->setFont(LLFontGL::sSansSerif);
949 mText->setVertAlignment(LLHUDText::ALIGN_VERT_TOP);
950 mText->setMaxLines(-1);
951 mText->setSourceObject(this);
952 mText->setOnHUDAttachment(isHUDAttachment());
953 }
954
955 char temp_string[256]; // not MAX_STRING, must hold 255 chars + \0
956 mesgsys->getStringFast(_PREHASH_ObjectData, _PREHASH_Text, 256, temp_string, block_num );
957
958 LLColor4U coloru;
959 mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_TextColor, coloru.mV, 4, block_num);
960
961 // alpha was flipped so that it zero encoded better
962 coloru.mV[3] = 255 - coloru.mV[3];
963 mText->setColor(LLColor4(coloru));
964 mText->setStringUTF8(temp_string);
965
966 if (mDrawable.notNull())
967 {
968 setChanged(MOVED | SILHOUETTE);
969 gPipeline.markMoved(mDrawable, FALSE); // undamped
970 }
971 }
972 else if (mText.notNull())
973 {
974 mText->markDead();
975 mText = NULL;
976 }
977
978 char media_url[MAX_STRING+1];
979 mesgsys->getStringFast(_PREHASH_ObjectData, _PREHASH_MediaURL, MAX_STRING+1, media_url, block_num);
980 //if (media_url[0])
981 //{
982 // llinfos << "WEBONPRIM media_url " << media_url << llendl;
983 //}
984 if (!mMedia && media_url[0] != '\0')
985 {
986 retval |= MEDIA_URL_ADDED;
987 mMedia = new LLViewerObjectMedia;
988 mMedia->mMediaURL = media_url;
989 mMedia->mMediaType = LLViewerObject::MEDIA_TYPE_WEB_PAGE;
990 mMedia->mPassedWhitelist = FALSE;
991 }
992 else if (mMedia)
993 {
994 if (media_url[0] == '\0')
995 {
996 retval |= MEDIA_URL_REMOVED;
997 delete mMedia;
998 mMedia = NULL;
999 }
1000 else if (mMedia->mMediaURL != media_url)
1001 {
1002 // We just added or changed a web page.
1003 retval |= MEDIA_URL_UPDATED;
1004 mMedia->mMediaURL = media_url;
1005 mMedia->mPassedWhitelist = FALSE;
1006 }
1007 }
1008
1009 //
1010 // Unpack particle system data
1011 //
1012 unpackParticleSource(block_num, owner_id);
1013
1014 // Mark all extra parameters not used
1015 std::map<U16, ExtraParameter*>::iterator iter;
1016 for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter)
1017 {
1018 iter->second->in_use = FALSE;
1019 }
1020
1021 // Unpack extra parameters
1022 S32 size = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_ExtraParams);
1023 if (size > 0)
1024 {
1025 U8 *buffer = new U8[size];
1026 mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_ExtraParams, buffer, size, block_num);
1027 LLDataPackerBinaryBuffer dp(buffer, size);
1028
1029 U8 num_parameters;
1030 dp.unpackU8(num_parameters, "num_params");
1031 U8 param_block[MAX_OBJECT_PARAMS_SIZE];
1032 for (U8 param=0; param<num_parameters; ++param)
1033 {
1034 U16 param_type;
1035 S32 param_size;
1036 dp.unpackU16(param_type, "param_type");
1037 dp.unpackBinaryData(param_block, param_size, "param_data");
1038 //llinfos << "Param type: " << param_type << ", Size: " << param_size << llendl;
1039 LLDataPackerBinaryBuffer dp2(param_block, param_size);
1040 unpackParameterEntry(param_type, &dp2);
1041 }
1042 delete[] buffer;
1043 }
1044
1045 for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter)
1046 {
1047 if (!iter->second->in_use)
1048 {
1049 // Send an update message in case it was formerly in use
1050 parameterChanged(iter->first, iter->second->data, FALSE, false);
1051 }
1052 }
1053
1054 U8 joint_type = 0;
1055 mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_JointType, joint_type, block_num);
1056 if (joint_type)
1057 {
1058 // create new joint info
1059 if (!mJointInfo)
1060 {
1061 mJointInfo = new LLVOJointInfo;
1062 }
1063 mJointInfo->mJointType = (EHavokJointType) joint_type;
1064 mesgsys->getVector3Fast(_PREHASH_ObjectData, _PREHASH_JointPivot, mJointInfo->mPivot, block_num);
1065 mesgsys->getVector3Fast(_PREHASH_ObjectData, _PREHASH_JointAxisOrAnchor, mJointInfo->mAxisOrAnchor, block_num);
1066 }
1067 else if (mJointInfo)
1068 {
1069 // this joint info is no longer needed
1070 delete mJointInfo;
1071 mJointInfo = NULL;
1072 }
1073
1074 break;
1075 }
1076
1077 case OUT_TERSE_IMPROVED:
1078 {
1079#ifdef DEBUG_UPDATE_TYPE
1080 llinfos << "TI:" << getID() << llendl;
1081#endif
1082 length = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_ObjectData);
1083 mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_ObjectData, data, length, block_num);
1084 count = 0;
1085 LLVector4 collision_plane;
1086
1087 switch(length)
1088 {
1089 case(60 + 16):
1090 // pull out collision normal for avatar
1091 htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4));
1092 ((LLVOAvatar*)this)->setFootPlane(collision_plane);
1093 count += sizeof(LLVector4);
1094 case 60:
1095 // this is a terse 32 update
1096 // pos
1097 this_update_precision = 32;
1098 htonmemcpy(new_pos_parent.mV, &data[count], MVT_LLVector3, sizeof(LLVector3));
1099 count += sizeof(LLVector3);
1100 // vel
1101 htonmemcpy((void*)getVelocity().mV, &data[count], MVT_LLVector3, sizeof(LLVector3));
1102 count += sizeof(LLVector3);
1103 // acc
1104 htonmemcpy((void*)getAcceleration().mV, &data[count], MVT_LLVector3, sizeof(LLVector3));
1105 count += sizeof(LLVector3);
1106 // theta
1107 {
1108 LLVector3 vec;
1109 htonmemcpy(vec.mV, &data[count], MVT_LLVector3, sizeof(LLVector3));
1110 new_rot.unpackFromVector3(vec);
1111 }
1112 count += sizeof(LLVector3);
1113 // omega
1114 htonmemcpy((void*)new_angv.mV, &data[count], MVT_LLVector3, sizeof(LLVector3));
1115 if (new_angv.isExactlyZero())
1116 {
1117 // reset rotation time
1118 resetRot();
1119 }
1120 setAngularVelocity(new_angv);
1121#if LL_DARWIN
1122 if (length == 76)
1123 {
1124 setAngularVelocity(LLVector3::zero);
1125 }
1126#endif
1127 break;
1128 case(32 + 16):
1129 // pull out collision normal for avatar
1130 htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4));
1131 ((LLVOAvatar*)this)->setFootPlane(collision_plane);
1132 count += sizeof(LLVector4);
1133 case 32:
1134 // this is a terse 16 update
1135 this_update_precision = 16;
1136 test_pos_parent.quantize16(-0.5f*size, 1.5f*size, MIN_HEIGHT, MAX_HEIGHT);
1137
1138#ifdef LL_BIG_ENDIAN
1139 htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6);
1140 val = valswizzle;
1141#else
1142 val = (U16 *) &data[count];
1143#endif
1144 count += sizeof(U16)*3;
1145 new_pos_parent.mV[VX] = U16_to_F32(val[VX], -0.5f*size, 1.5f*size);
1146 new_pos_parent.mV[VY] = U16_to_F32(val[VY], -0.5f*size, 1.5f*size);
1147 new_pos_parent.mV[VZ] = U16_to_F32(val[VZ], MIN_HEIGHT, MAX_HEIGHT);
1148
1149#ifdef LL_BIG_ENDIAN
1150 htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6);
1151 val = valswizzle;
1152#else
1153 val = (U16 *) &data[count];
1154#endif
1155 count += sizeof(U16)*3;
1156 setVelocity(U16_to_F32(val[VX], -size, size),
1157 U16_to_F32(val[VY], -size, size),
1158 U16_to_F32(val[VZ], -size, size));
1159
1160#ifdef LL_BIG_ENDIAN
1161 htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6);
1162 val = valswizzle;
1163#else
1164 val = (U16 *) &data[count];
1165#endif
1166 count += sizeof(U16)*3;
1167 setAcceleration(U16_to_F32(val[VX], -size, size),
1168 U16_to_F32(val[VY], -size, size),
1169 U16_to_F32(val[VZ], -size, size));
1170
1171#ifdef LL_BIG_ENDIAN
1172 htonmemcpy(valswizzle, &data[count], MVT_U16Quat, 8);
1173 val = valswizzle;
1174#else
1175 val = (U16 *) &data[count];
1176#endif
1177 count += sizeof(U16)*4;
1178 new_rot.mQ[VX] = U16_to_F32(val[VX], -1.f, 1.f);
1179 new_rot.mQ[VY] = U16_to_F32(val[VY], -1.f, 1.f);
1180 new_rot.mQ[VZ] = U16_to_F32(val[VZ], -1.f, 1.f);
1181 new_rot.mQ[VW] = U16_to_F32(val[VW], -1.f, 1.f);
1182
1183#ifdef LL_BIG_ENDIAN
1184 htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6);
1185 val = valswizzle;
1186#else
1187 val = (U16 *) &data[count];
1188#endif
1189 setAngularVelocity( U16_to_F32(val[VX], -size, size),
1190 U16_to_F32(val[VY], -size, size),
1191 U16_to_F32(val[VZ], -size, size));
1192 break;
1193
1194 case 16:
1195 // this is a terse 8 update
1196 this_update_precision = 8;
1197 test_pos_parent.quantize8(-0.5f*size, 1.5f*size, MIN_HEIGHT, MAX_HEIGHT);
1198 new_pos_parent.mV[VX] = U8_to_F32(data[0], -0.5f*size, 1.5f*size);
1199 new_pos_parent.mV[VY] = U8_to_F32(data[1], -0.5f*size, 1.5f*size);
1200 new_pos_parent.mV[VZ] = U8_to_F32(data[2], MIN_HEIGHT, MAX_HEIGHT);
1201
1202 setVelocity(U8_to_F32(data[3], -size, size),
1203 U8_to_F32(data[4], -size, size),
1204 U8_to_F32(data[5], -size, size) );
1205
1206 setAcceleration(U8_to_F32(data[6], -size, size),
1207 U8_to_F32(data[7], -size, size),
1208 U8_to_F32(data[8], -size, size) );
1209
1210 new_rot.mQ[VX] = U8_to_F32(data[9], -1.f, 1.f);
1211 new_rot.mQ[VY] = U8_to_F32(data[10], -1.f, 1.f);
1212 new_rot.mQ[VZ] = U8_to_F32(data[11], -1.f, 1.f);
1213 new_rot.mQ[VW] = U8_to_F32(data[12], -1.f, 1.f);
1214
1215 setAngularVelocity( U8_to_F32(data[13], -size, size),
1216 U8_to_F32(data[14], -size, size),
1217 U8_to_F32(data[15], -size, size) );
1218 break;
1219 }
1220
1221 U8 state;
1222 mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_State, state, block_num );
1223 mState = state;
1224 break;
1225 }
1226
1227 default:
1228 break;
1229
1230 }
1231 }
1232 else
1233 {
1234 // handle the compressed case
1235 LLUUID sound_uuid;
1236 LLUUID owner_id;
1237 F32 gain = 0;
1238 U8 sound_flags = 0;
1239 F32 cutoff = 0;
1240
1241 U16 val[4];
1242
1243 U8 state;
1244
1245 dp->unpackU8(state, "State");
1246 mState = state;
1247
1248 switch(update_type)
1249 {
1250 case OUT_TERSE_IMPROVED:
1251 {
1252#ifdef DEBUG_UPDATE_TYPE
1253 llinfos << "CompTI:" << getID() << llendl;
1254#endif
1255 U8 value;
1256 dp->unpackU8(value, "agent");
1257 if (value)
1258 {
1259 LLVector4 collision_plane;
1260 dp->unpackVector4(collision_plane, "Plane");
1261 ((LLVOAvatar*)this)->setFootPlane(collision_plane);
1262 }
1263 test_pos_parent = getPosition();
1264 dp->unpackVector3(new_pos_parent, "Pos");
1265 dp->unpackU16(val[VX], "VelX");
1266 dp->unpackU16(val[VY], "VelY");
1267 dp->unpackU16(val[VZ], "VelZ");
1268 setVelocity(U16_to_F32(val[VX], -128.f, 128.f),
1269 U16_to_F32(val[VY], -128.f, 128.f),
1270 U16_to_F32(val[VZ], -128.f, 128.f));
1271 dp->unpackU16(val[VX], "AccX");
1272 dp->unpackU16(val[VY], "AccY");
1273 dp->unpackU16(val[VZ], "AccZ");
1274 setAcceleration(U16_to_F32(val[VX], -64.f, 64.f),
1275 U16_to_F32(val[VY], -64.f, 64.f),
1276 U16_to_F32(val[VZ], -64.f, 64.f));
1277
1278 dp->unpackU16(val[VX], "ThetaX");
1279 dp->unpackU16(val[VY], "ThetaY");
1280 dp->unpackU16(val[VZ], "ThetaZ");
1281 dp->unpackU16(val[VS], "ThetaS");
1282 new_rot.mQ[VX] = U16_to_F32(val[VX], -1.f, 1.f);
1283 new_rot.mQ[VY] = U16_to_F32(val[VY], -1.f, 1.f);
1284 new_rot.mQ[VZ] = U16_to_F32(val[VZ], -1.f, 1.f);
1285 new_rot.mQ[VS] = U16_to_F32(val[VS], -1.f, 1.f);
1286 dp->unpackU16(val[VX], "AccX");
1287 dp->unpackU16(val[VY], "AccY");
1288 dp->unpackU16(val[VZ], "AccZ");
1289 setAngularVelocity( U16_to_F32(val[VX], -64.f, 64.f),
1290 U16_to_F32(val[VY], -64.f, 64.f),
1291 U16_to_F32(val[VZ], -64.f, 64.f));
1292 }
1293 break;
1294 case OUT_FULL_COMPRESSED:
1295 case OUT_FULL_CACHED:
1296 {
1297#ifdef DEBUG_UPDATE_TYPE
1298 llinfos << "CompFull:" << getID() << llendl;
1299#endif
1300 dp->unpackU32(crc, "CRC");
1301 mTotalCRC = crc;
1302 dp->unpackU8(material, "Material");
1303 U8 old_material = getMaterial();
1304 if (old_material != material)
1305 {
1306 setMaterial(material);
1307 if (mDrawable.notNull())
1308 {
1309 gPipeline.markMoved(mDrawable, FALSE); // undamped
1310 }
1311 }
1312 dp->unpackU8(click_action, "ClickAction");
1313 setClickAction(click_action);
1314 dp->unpackVector3(new_scale, "Scale");
1315 dp->unpackVector3(new_pos_parent, "Pos");
1316 LLVector3 vec;
1317 dp->unpackVector3(vec, "Rot");
1318 new_rot.unpackFromVector3(vec);
1319 setAcceleration(LLVector3::zero);
1320
1321 U32 value;
1322 dp->unpackU32(value, "SpecialCode");
1323
1324 dp->setPassFlags(value);
1325
1326
1327 if (value & 0x80)
1328 {
1329 dp->unpackVector3(vec, "Omega");
1330 setAngularVelocity(vec);
1331 }
1332
1333 if (value & 0x20)
1334 {
1335 dp->unpackU32(parent_id, "ParentID");
1336 }
1337 else
1338 {
1339 parent_id = 0;
1340 }
1341
1342 S32 sp_size;
1343 U32 size;
1344 if (value & 0x2)
1345 {
1346 sp_size = 1;
1347 delete [] mData;
1348 mData = new U8[1];
1349 dp->unpackU8(((U8*)mData)[0], "TreeData");
1350 }
1351 else if (value & 0x1)
1352 {
1353 dp->unpackU32(size, "ScratchPadSize");
1354 delete [] mData;
1355 mData = new U8[size];
1356 dp->unpackBinaryData((U8 *)mData, sp_size, "PartData");
1357 }
1358 else
1359 {
1360 mData = NULL;
1361 }
1362
1363 // Setup object text
1364 if (!mText)
1365 {
1366 mText = (LLHUDText *)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_TEXT);
1367 mText->setFont(LLFontGL::sSansSerif);
1368 mText->setVertAlignment(LLHUDText::ALIGN_VERT_TOP);
1369 mText->setMaxLines(-1); // Set to match current agni behavior.
1370 mText->setSourceObject(this);
1371 mText->setOnHUDAttachment(isHUDAttachment());
1372 }
1373
1374 if (value & 0x4)
1375 {
1376 std::string temp_string;
1377 dp->unpackString(temp_string, "Text");
1378 LLColor4U coloru;
1379 dp->unpackBinaryDataFixed(coloru.mV, 4, "Color");
1380 coloru.mV[3] = 255 - coloru.mV[3];
1381 mText->setColor(LLColor4(coloru));
1382 mText->setStringUTF8(temp_string);
1383
1384 setChanged(TEXTURE);
1385 }
1386 else
1387 {
1388 mText->markDead();
1389 mText = NULL;
1390 }
1391
1392 if (value & 0x200)
1393 {
1394 std::string media_url;
1395 dp->unpackString(media_url, "MediaURL");
1396 if (!mMedia)
1397 {
1398 retval |= MEDIA_URL_ADDED;
1399 mMedia = new LLViewerObjectMedia;
1400 mMedia->mMediaURL = media_url;
1401 mMedia->mMediaType = LLViewerObject::MEDIA_TYPE_WEB_PAGE;
1402 mMedia->mPassedWhitelist = FALSE;
1403 }
1404 else if (mMedia->mMediaURL != media_url)
1405 {
1406 retval |= MEDIA_URL_UPDATED;
1407 mMedia->mMediaURL = media_url;
1408 mMedia->mPassedWhitelist = FALSE;
1409 }
1410 }
1411 else if (mMedia)
1412 {
1413 retval |= MEDIA_URL_REMOVED;
1414 delete mMedia;
1415 mMedia = NULL;
1416 }
1417
1418 //
1419 // Unpack particle system data
1420 //
1421 if (value & 0x8)
1422 unpackParticleSource(*dp, owner_id);
1423
1424 // Mark all extra parameters not used
1425 std::map<U16, ExtraParameter*>::iterator iter;
1426 for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter)
1427 {
1428 iter->second->in_use = FALSE;
1429 }
1430
1431 // Unpack extra params
1432 U8 num_parameters;
1433 dp->unpackU8(num_parameters, "num_params");
1434 U8 param_block[MAX_OBJECT_PARAMS_SIZE];
1435 for (U8 param=0; param<num_parameters; ++param)
1436 {
1437 U16 param_type;
1438 S32 param_size;
1439 dp->unpackU16(param_type, "param_type");
1440 dp->unpackBinaryData(param_block, param_size, "param_data");
1441 //llinfos << "Param type: " << param_type << ", Size: " << param_size << llendl;
1442 LLDataPackerBinaryBuffer dp2(param_block, param_size);
1443 unpackParameterEntry(param_type, &dp2);
1444 }
1445
1446 for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter)
1447 {
1448 if (!iter->second->in_use)
1449 {
1450 // Send an update message in case it was formerly in use
1451 parameterChanged(iter->first, iter->second->data, FALSE, false);
1452 }
1453 }
1454
1455 if (value & 0x10)
1456 {
1457 dp->unpackUUID(sound_uuid, "SoundUUID");
1458 dp->unpackUUID(owner_id, "OwnerID");
1459 dp->unpackF32(gain, "SoundGain");
1460 dp->unpackU8(sound_flags, "SoundFlags");
1461 dp->unpackF32(cutoff, "SoundRadius");
1462 }
1463
1464 if (value & 0x100)
1465 {
1466 std::string name_value_list;
1467 dp->unpackString(name_value_list, "NV");
1468
1469 setNameValueList(name_value_list.c_str());
1470 }
1471
1472 mTotalCRC = crc;
1473
1474 setAttachedSound(sound_uuid, owner_id, gain, sound_flags);
1475
1476 // only get these flags on updates from sim, not cached ones
1477 // Preload these five flags for every object.
1478 // Finer shades require the object to be selected, and the selection manager
1479 // stores the extended permission info.
1480 U32 flags;
1481 mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, block_num);
1482 // keep local flags and overwrite remote-controlled flags
1483 mFlags = (mFlags & FLAGS_LOCAL) | flags;
1484
1485 // ...new objects that should come in selected need to be added to the selected list
1486 mCreateSelected = ((flags & FLAGS_CREATE_SELECTED) != 0);
1487
1488 // Set the change flags for scale
1489 if (new_scale != getScale())
1490 {
1491 setChanged(SCALED | SILHOUETTE);
1492 setScale(new_scale); // Must follow setting permYouOwner()
1493 }
1494
1495 }
1496 break;
1497
1498 default:
1499 break;
1500 }
1501 }
1502
1503 //
1504 // Fix object parenting.
1505 //
1506 BOOL b_changed_status = FALSE;
1507
1508 if (OUT_TERSE_IMPROVED != update_type)
1509 {
1510 // We only need to update parenting on full updates, terse updates
1511 // don't send parenting information.
1512 if (!cur_parentp)
1513 {
1514 if (parent_id == 0)
1515 {
1516 // No parent now, no parent in message -> do nothing
1517 }
1518 else
1519 {
1520 // No parent now, new parent in message -> attach to that parent if possible
1521 LLUUID parent_uuid;
1522 LLViewerObjectList::getUUIDFromLocal(parent_uuid,
1523 parent_id,
1524 mesgsys->getSenderIP(),
1525 mesgsys->getSenderPort());
1526
1527 LLViewerObject *sent_parentp = gObjectList.findObject(parent_uuid);
1528
1529 //
1530 // Check to see if we have the corresponding viewer object for the parent.
1531 //
1532 if (sent_parentp && sent_parentp->getParent() == this)
1533 {
1534 // Try to recover if we attempt to attach a parent to its child
1535 llwarns << "Attempt to attach a parent to it's child: " << this->getID() << " to " << sent_parentp->getID() << llendl;
1536 this->removeChild(sent_parentp);
1537 sent_parentp->setDrawableParent(NULL);
1538 }
1539
1540 if (sent_parentp && (sent_parentp != this) && !sent_parentp->isDead())
1541 {
1542 //
1543 // We have a viewer object for the parent, and it's not dead.
1544 // Do the actual reparenting here.
1545 //
1546
1547 // new parent is valid
1548 b_changed_status = TRUE;
1549 // ...no current parent, so don't try to remove child
1550 if (mDrawable.notNull())
1551 {
1552 if (mDrawable->isDead() || !mDrawable->getVObj())
1553 {
1554 llwarns << "Drawable is dead or no VObj!" << llendl;
1555 sent_parentp->addChild(this);
1556 }
1557 else
1558 {
1559 if (!setDrawableParent(sent_parentp->mDrawable)) // LLViewerObject::processUpdateMessage 1
1560 {
1561 // Bad, we got a cycle somehow.
1562 // Kill both the parent and the child, and
1563 // set cache misses for both of them.
1564 llwarns << "Attempting to recover from parenting cycle!" << llendl
1565 llwarns << "Killing " << sent_parentp->getID() << " and " << getID() << llendl;
1566 llwarns << "Adding to cache miss list" << llendl;
1567 setParent(NULL);
1568 sent_parentp->setParent(NULL);
1569 getRegion()->addCacheMissFull(getLocalID());
1570 getRegion()->addCacheMissFull(sent_parentp->getLocalID());
1571 gObjectList.killObject(sent_parentp);
1572 gObjectList.killObject(this);
1573 return retval;
1574 }
1575 sent_parentp->addChild(this);
1576 // make sure this object gets a non-damped update
1577 if (sent_parentp->mDrawable.notNull())
1578 {
1579 gPipeline.markMoved(sent_parentp->mDrawable, FALSE); // undamped
1580 }
1581 }
1582 }
1583 else
1584 {
1585 sent_parentp->addChild(this);
1586 }
1587
1588 setChanged(MOVED | SILHOUETTE);
1589 }
1590 else
1591 {
1592 //
1593 // No corresponding viewer object for the parent, put the various
1594 // pieces on the orphan list.
1595 //
1596
1597 //parent_id
1598 U32 ip = mesgsys->getSenderIP();
1599 U32 port = mesgsys->getSenderPort();
1600
1601 gObjectList.orphanize(this, parent_id, ip, port);
1602 }
1603 }
1604 }
1605 else
1606 {
1607 // BUG: this is a bad assumption once border crossing is alowed
1608 if ( (parent_id == cur_parentp->mLocalID)
1609 &&(update_type == OUT_TERSE_IMPROVED))
1610 {
1611 // Parent now, same parent in message -> do nothing
1612
1613 // Debugging for suspected problems with local ids.
1614 //LLUUID parent_uuid;
1615 //LLViewerObjectList::getUUIDFromLocal(parent_uuid, parent_id, mesgsys->getSenderIP(), mesgsys->getSenderPort() );
1616 //if (parent_uuid != cur_parentp->getID() )
1617 //{
1618 // llerrs << "Local ID match but UUID mismatch of viewer object" << llendl;
1619 //}
1620 }
1621 else
1622 {
1623 // Parented now, different parent in message
1624 LLViewerObject *sent_parentp;
1625 if (parent_id == 0)
1626 {
1627 //
1628 // This object is no longer parented, we sent in a zero parent ID.
1629 //
1630 sent_parentp = NULL;
1631 }
1632 else
1633 {
1634 LLUUID parent_uuid;
1635 LLViewerObjectList::getUUIDFromLocal(parent_uuid,
1636 parent_id,
1637 gMessageSystem->getSenderIP(),
1638 gMessageSystem->getSenderPort());
1639 sent_parentp = gObjectList.findObject(parent_uuid);
1640
1641 if (isAvatar())
1642 {
1643 // This logic is meant to handle the case where a sitting avatar has reached a new sim
1644 // ahead of the object she was sitting on (which is common as objects are transfered through
1645 // a slower route than agents)...
1646 // In this case, the local id for the object will not be valid, since the viewer has not received
1647 // a full update for the object from that sim yet, so we assume that the agent is still sitting
1648 // where she was originally. --RN
1649 if (!sent_parentp)
1650 {
1651 sent_parentp = cur_parentp;
1652 }
1653 }
1654 else if (!sent_parentp)
1655 {
1656 //
1657 // Switching parents, but we don't know the new parent.
1658 //
1659 U32 ip = mesgsys->getSenderIP();
1660 U32 port = mesgsys->getSenderPort();
1661
1662 // We're an orphan, flag things appropriately.
1663 gObjectList.orphanize(this, parent_id, ip, port);
1664 }
1665 }
1666
1667 // Reattach if possible.
1668 if (sent_parentp && sent_parentp != cur_parentp && sent_parentp != this)
1669 {
1670 // New parent is valid, detach and reattach
1671 b_changed_status = TRUE;
1672 if (mDrawable.notNull())
1673 {
1674 if (!setDrawableParent(sent_parentp->mDrawable)) // LLViewerObject::processUpdateMessage 2
1675 {
1676 // Bad, we got a cycle somehow.
1677 // Kill both the parent and the child, and
1678 // set cache misses for both of them.
1679 llwarns << "Attempting to recover from parenting cycle!" << llendl
1680 llwarns << "Killing " << sent_parentp->getID() << " and " << getID() << llendl;
1681 llwarns << "Adding to cache miss list" << llendl;
1682 setParent(NULL);
1683 sent_parentp->setParent(NULL);
1684 getRegion()->addCacheMissFull(getLocalID());
1685 getRegion()->addCacheMissFull(sent_parentp->getLocalID());
1686 gObjectList.killObject(sent_parentp);
1687 gObjectList.killObject(this);
1688 return retval;
1689 }
1690 // make sure this object gets a non-damped update
1691 }
1692 cur_parentp->removeChild(this);
1693 sent_parentp->addChild(this);
1694 setChanged(MOVED | SILHOUETTE);
1695 sent_parentp->setChanged(MOVED | SILHOUETTE);
1696 if (sent_parentp->mDrawable.notNull())
1697 {
1698 gPipeline.markMoved(sent_parentp->mDrawable, FALSE); // undamped
1699 }
1700 }
1701 else if (!sent_parentp)
1702 {
1703 bool remove_parent = true;
1704 // No new parent, or the parent that we sent doesn't exist on the viewer.
1705 LLViewerObject *parentp = (LLViewerObject *)getParent();
1706 if (parentp)
1707 {
1708 if (parentp->getRegion() != getRegion())
1709 {
1710 // This is probably an object flying across a region boundary, the
1711 // object probably ISN'T being reparented, but just got an object
1712 // update out of order (child update before parent).
1713 //llinfos << "Don't reparent object handoffs!" << llendl;
1714 remove_parent = false;
1715 }
1716 }
1717
1718 if (remove_parent)
1719 {
1720 b_changed_status = TRUE;
1721 if (mDrawable.notNull())
1722 {
1723 // clear parent to removeChild can put the drawable on the damped list
1724 setDrawableParent(NULL); // LLViewerObject::processUpdateMessage 3
1725 }
1726
1727 cur_parentp->removeChild(this);
1728
1729 if (mJointInfo && !parent_id)
1730 {
1731 // since this object is no longer parent-relative
1732 // we make sure we delete any joint info
1733 delete mJointInfo;
1734 mJointInfo = NULL;
1735 }
1736
1737 setChanged(MOVED | SILHOUETTE);
1738
1739 if (mDrawable.notNull())
1740 {
1741 // make sure this object gets a non-damped update
1742 gPipeline.markMoved(mDrawable, FALSE); // undamped
1743 }
1744 }
1745 }
1746 }
1747 }
1748 }
1749
1750 new_rot.normQuat();
1751
1752 if (gPingInterpolate)
1753 {
1754 LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mesgsys->getSender());
1755 F32 ping_delay = 0.5f * mTimeDilation * ( ((F32)cdp->getPingDelay()) * 0.001f + gFrameDTClamped);
1756 LLVector3 diff = getVelocity() * (0.5f*mTimeDilation*(gFrameDTClamped + ((F32)ping_delay)*0.001f));
1757 new_pos_parent += diff;
1758 }
1759
1760 //////////////////////////
1761 //
1762 // Set the generic change flags...
1763 //
1764 //
1765
1766 // first, let's see if the new position is actually a change
1767
1768 //static S32 counter = 0;
1769
1770 F32 vel_mag_sq = getVelocity().magVecSquared();
1771 F32 accel_mag_sq = getAcceleration().magVecSquared();
1772
1773 if ( ((b_changed_status)||(test_pos_parent != new_pos_parent))
1774 ||( (!isSelected())
1775 &&( (vel_mag_sq != 0.f)
1776 ||(accel_mag_sq != 0.f)
1777 ||(this_update_precision > mBestUpdatePrecision))))
1778 {
1779 mBestUpdatePrecision = this_update_precision;
1780 setPositionParent(new_pos_parent);
1781
1782 if (mParent && ((LLViewerObject*)mParent)->isAvatar())
1783 {
1784 // we have changed the position of an attachment, so we need to clamp it
1785 LLVOAvatar *avatar = (LLVOAvatar*)mParent;
1786
1787 avatar->clampAttachmentPositions();
1788 }
1789 }
1790
1791 if (new_rot != mLastRot)
1792 {
1793 // if (getAngularVelocity().isExactlyZero() ||
1794 // new_angv != getAngularVelocity())
1795 {
1796 mLastRot = new_rot;
1797 setChanged(ROTATED | SILHOUETTE);
1798 setRotation(new_rot);
1799 resetRot();
1800 }
1801 }
1802
1803
1804 if ( gShowObjectUpdates )
1805 {
1806 if (!((mPrimitiveCode == LL_PCODE_LEGACY_AVATAR) && (((LLVOAvatar *) this)->mIsSelf))
1807 && mRegionp)
1808 {
1809 LLViewerObject* object = gObjectList.createObjectViewer(LL_PCODE_LEGACY_TEXT_BUBBLE, mRegionp);
1810 LLVOTextBubble* bubble = (LLVOTextBubble*) object;
1811
1812 if (update_type == OUT_TERSE_IMPROVED)
1813 {
1814 bubble->mColor.setVec(0.f, 0.f, 1.f, 1.f);
1815 }
1816 else
1817 {
1818 bubble->mColor.setVec(1.f, 0.f, 0.f, 1.f);
1819 }
1820 object->setPositionGlobal(getPositionGlobal());
1821 gPipeline.addObject(object);
1822 }
1823 }
1824
1825 if ((0.0f == vel_mag_sq) &&
1826 (0.0f == accel_mag_sq) &&
1827 (0.0f == getAngularVelocity().magVecSquared()))
1828 {
1829 mStatic = TRUE; // This object doesn't move!
1830 }
1831 else
1832 {
1833 mStatic = FALSE;
1834 }
1835
1836// BUG: This code leads to problems during group rotate and any scale operation.
1837// Small discepencies between the simulator and viewer representations cause the
1838// selection center to creep, leading to objects moving around the wrong center.
1839//
1840// Removing this, however, means that if someone else drags an object you have
1841// selected, your selection center and dialog boxes will be wrong. It also means
1842// that higher precision information on selected objects will be ignored.
1843//
1844// I believe the group rotation problem is fixed. JNC 1.21.2002
1845//
1846 // Additionally, if any child is selected, need to update the dialogs and selection
1847 // center.
1848 BOOL needs_refresh = mUserSelected;
1849 LLViewerObject *childp;
1850 for (U32 i = 0; i < mChildList.size(); i++)
1851 {
1852 childp = mChildList[i];
1853 needs_refresh = needs_refresh || childp->mUserSelected;
1854 }
1855
1856 if (needs_refresh)
1857 {
1858 gSelectMgr->updateSelectionCenter();
1859 dialog_refresh_all();
1860 }
1861
1862
1863 // Mark update time as approx. now, with the ping delay.
1864 // Ping delay is off because it's not set for velocity interpolation, causing
1865 // much jumping and hopping around...
1866
1867// U32 ping_delay = mesgsys->mCircuitInfo.getPingDelay();
1868 mLastInterpUpdateSecs = LLFrameTimer::getElapsedSeconds();
1869 mLastMessageUpdateSecs = LLFrameTimer::getElapsedSeconds();
1870 if (mDrawable.notNull())
1871 {
1872 // Don't clear invisibility flag on update if still orphaned!
1873 if (mDrawable->isState(LLDrawable::FORCE_INVISIBLE) && !mOrphaned)
1874 {
1875// lldebugs << "Clearing force invisible: " << mID << ":" << getPCodeString() << ":" << getPositionAgent() << llendl;
1876 mDrawable->setState(LLDrawable::CLEAR_INVISIBLE);
1877 }
1878 }
1879
1880 // Update special hover cursor status
1881 bool special_hover_cursor = specialHoverCursor();
1882 if (old_special_hover_cursor != special_hover_cursor
1883 && mDrawable.notNull())
1884 {
1885 mDrawable->updateSpecialHoverCursor(special_hover_cursor);
1886 }
1887
1888 return retval;
1889}
1890
1891BOOL LLViewerObject::isActive() const
1892{
1893 return TRUE;
1894}
1895
1896BOOL LLViewerObject::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
1897{
1898 if (mDead)
1899 {
1900 // It's dead. Don't update it.
1901 return TRUE;
1902 }
1903
1904 // CRO - don't velocity interp linked objects!
1905 // Leviathan - but DO velocity interp joints
1906 if (!mStatic && gVelocityInterpolate && !isSelected())
1907 {
1908 // calculate dt from last update
1909 F32 dt_raw = (F32)(time - mLastInterpUpdateSecs);
1910 F32 dt = mTimeDilation * dt_raw;
1911
1912 if (!mUserSelected && !mJointInfo)
1913 {
1914 applyAngularVelocity(dt);
1915 }
1916
1917 LLViewerObject *parentp = (LLViewerObject *) getParent();
1918 if (mJointInfo)
1919 {
1920 if (parentp)
1921 {
1922 // do parent-relative stuff
1923 LLVector3 ang_vel = getAngularVelocity();
1924 F32 omega = ang_vel.magVecSquared();
1925 F32 angle = 0.0f;
1926 LLQuaternion dQ;
1927 if (omega > 0.00001f)
1928 {
1929 omega = sqrt(omega);
1930 angle = omega * dt;
1931 dQ.setQuat(angle, ang_vel);
1932 }
1933 LLVector3 pos = getPosition();
1934
1935 if (HJT_HINGE == mJointInfo->mJointType)
1936 {
1937 // hinge = uniform circular motion
1938 LLVector3 parent_pivot = getVelocity();
1939 LLVector3 parent_axis = getAcceleration();
1940
1941 angle = dt * (ang_vel * mJointInfo->mAxisOrAnchor); // AxisOrAnchor = axis
1942 dQ.setQuat(angle, mJointInfo->mAxisOrAnchor); // AxisOrAnchor = axis
1943 LLVector3 pivot_offset = pos - mJointInfo->mPivot; // pos in pivot-frame
1944 pivot_offset = pivot_offset * dQ; // new rotated pivot-frame pos
1945 pos = mJointInfo->mPivot + pivot_offset; // parent-frame
1946 LLViewerObject::setPosition(pos);
1947 LLQuaternion Q_PC = getRotation();
1948 setRotation(Q_PC * dQ);
1949 mLastInterpUpdateSecs = time;
1950 }
1951 else if (HJT_POINT == mJointInfo->mJointType)
1952 // || HJT_LPOINT == mJointInfo->mJointType)
1953 {
1954 // point-to-point = spin about axis and uniform circular motion
1955 // of axis about the pivot point
1956 //
1957 // NOTE: this interpolation scheme is not quite good enough to
1958 // reduce the bandwidth -- needs a gravitational correction.
1959 // Similarly for hinges with axes that deviate from vertical.
1960
1961 LLQuaternion Q_PC = getRotation();
1962 Q_PC = Q_PC * dQ;
1963 setRotation(Q_PC);
1964
1965 LLVector3 pivot_to_child = - mJointInfo->mAxisOrAnchor; // AxisOrAnchor = anchor
1966 pos = mJointInfo->mPivot + pivot_to_child * Q_PC;
1967 LLViewerObject::setPosition(pos);
1968 mLastInterpUpdateSecs = time;
1969 }
1970 /* else if (HJT_WHEEL == mJointInfo->mJointInfo)
1971 {
1972 // wheel = uniform rotation about axis, with linear
1973 // velocity interpolation (if any)
1974 LLVector3 parent_axis = getAcceleration(); // HACK -- accel stores the parent-axis (parent-frame)
1975
1976 LLQuaternion Q_PC = getRotation();
1977
1978 angle = dt * (parent_axis * ang_vel);
1979 dQ.setQuat(angle, parent_axis);
1980
1981 Q_PC = Q_PC * dQ;
1982 setRotation(Q_PC);
1983
1984 pos = getPosition() + dt * getVelocity();
1985 LLViewerObject::setPosition(pos);
1986 mLastInterpUpdateSecs = time;
1987 }*/
1988 }
1989 }
1990 else if (isAttachment())
1991 {
1992 mLastInterpUpdateSecs = time;
1993 return TRUE;
1994 }
1995 else
1996 {
1997 // linear motion
1998 // HAVOK_TIMESTEP is used below to correct for the fact that the velocity in object
1999 // updates represents the average velocity of the last timestep, rather than the final velocity.
2000 // the time dilation above should guarrantee that dt is never less than HAVOK_TIMESTEP, theoretically
2001 //
2002 // There is a problem here if dt is negative. . .
2003
2004 // *TODO: should also wrap linear accel/velocity in check
2005 // to see if object is selected, instead of explicitly
2006 // zeroing it out
2007 LLVector3 accel = getAcceleration();
2008 LLVector3 vel = getVelocity();
2009
2010 if (!(accel.isExactlyZero() && vel.isExactlyZero()))
2011 {
2012 LLVector3 pos = (vel + (0.5f * (dt-HAVOK_TIMESTEP)) * accel) * dt;
2013
2014 // region local
2015 setPositionRegion(pos + getPositionRegion());
2016 setVelocity(vel + accel*dt);
2017
2018 // for objects that are spinning but not translating, make sure to flag them as having moved
2019 setChanged(MOVED | SILHOUETTE);
2020 }
2021
2022 mLastInterpUpdateSecs = time;
2023 }
2024 }
2025
2026 if (gNoRender)
2027 {
2028 // Skip drawable stuff if not rendering.
2029 return TRUE;
2030 }
2031
2032 updateDrawable(FALSE);
2033
2034 return TRUE;
2035}
2036
2037
2038BOOL LLViewerObject::setData(const U8 *datap, const U32 data_size)
2039{
2040 LLMemType mt(LLMemType::MTYPE_OBJECT);
2041
2042 delete [] mData;
2043
2044 if (datap)
2045 {
2046 mData = new U8[data_size];
2047 if (!mData)
2048 {
2049 return FALSE;
2050 }
2051 memcpy(mData, datap, data_size);
2052 }
2053 return TRUE;
2054}
2055
2056// delete an item in the inventory, but don't tell the server. This is
2057// used internally by remove, update, and savescript.
2058// This will only delete the first item with an item_id in the list
2059void LLViewerObject::deleteInventoryItem(const LLUUID& item_id)
2060{
2061 if(mInventory)
2062 {
2063 InventoryObjectList::iterator it = mInventory->begin();
2064 InventoryObjectList::iterator end = mInventory->end();
2065 for( ; it != end; ++it )
2066 {
2067 if((*it)->getUUID() == item_id)
2068 {
2069 // This is safe only because we return immediatly.
2070 mInventory->erase(it); // will deref and delete it
2071 return;
2072 }
2073 }
2074 doInventoryCallback();
2075 }
2076}
2077
2078void LLViewerObject::doUpdateInventory(
2079 LLViewerInventoryItem* item,
2080 U8 key,
2081 bool is_new)
2082{
2083 LLMemType mt(LLMemType::MTYPE_OBJECT);
2084
2085 LLViewerInventoryItem* old_item = NULL;
2086 if(TASK_INVENTORY_ITEM_KEY == key)
2087 {
2088 old_item = (LLViewerInventoryItem*)getInventoryObject(item->getUUID());
2089 }
2090 else if(TASK_INVENTORY_ASSET_KEY == key)
2091 {
2092 old_item = getInventoryItemByAsset(item->getAssetUUID());
2093 }
2094 LLUUID item_id;
2095 LLUUID new_owner;
2096 LLUUID new_group;
2097 BOOL group_owned = FALSE;
2098 if(old_item)
2099 {
2100 item_id = old_item->getUUID();
2101 new_owner = old_item->getPermissions().getOwner();
2102 new_group = old_item->getPermissions().getGroup();
2103 group_owned = old_item->getPermissions().isGroupOwned();
2104 old_item = NULL;
2105 }
2106 else
2107 {
2108 item_id = item->getUUID();
2109 }
2110 if(!is_new && mInventory)
2111 {
2112 // Attempt to update the local inventory. If we can get the
2113 // object perm, we have perfect visibility, so we want the
2114 // serial number to match. Otherwise, take our best guess and
2115 // make sure that the serial number does not match.
2116 deleteInventoryItem(item_id);
2117 LLPermissions perm(item->getPermissions());
2118 LLPermissions* obj_perm = gSelectMgr->findObjectPermissions(this);
2119 bool is_atomic = ((S32)LLAssetType::AT_OBJECT == item->getType()) ? false : true;
2120 if(obj_perm)
2121 {
2122 perm.setOwnerAndGroup(LLUUID::null, obj_perm->getOwner(), obj_perm->getGroup(), is_atomic);
2123 }
2124 else
2125 {
2126 if(group_owned)
2127 {
2128 perm.setOwnerAndGroup(LLUUID::null, new_owner, new_group, is_atomic);
2129 }
2130 else if(!new_owner.isNull())
2131 {
2132 // The object used to be in inventory, so we can
2133 // assume the owner and group will match what they are
2134 // there.
2135 perm.setOwnerAndGroup(LLUUID::null, new_owner, new_group, is_atomic);
2136 }
2137 // *FIX: can make an even better guess by using the mPermGroup flags
2138 else if(permYouOwner())
2139 {
2140 // best guess.
2141 perm.setOwnerAndGroup(LLUUID::null, gAgent.getID(), item->getPermissions().getGroup(), is_atomic);
2142 --mInventorySerialNum;
2143 }
2144 else
2145 {
2146 // dummy it up.
2147 perm.setOwnerAndGroup(LLUUID::null, LLUUID::null, LLUUID::null, is_atomic);
2148 --mInventorySerialNum;
2149 }
2150 }
2151 LLViewerInventoryItem* new_item = new LLViewerInventoryItem(item);
2152 new_item->setPermissions(perm);
2153 mInventory->push_front(new_item);
2154 doInventoryCallback();
2155 ++mInventorySerialNum;
2156 }
2157}
2158
2159// save a script, which involves removing the old one, and rezzing
2160// in the new one. This method should be called with the asset id
2161// of the new and old script AFTER the bytecode has been saved.
2162void LLViewerObject::saveScript(
2163 const LLViewerInventoryItem* item,
2164 BOOL active,
2165 bool is_new)
2166{
2167 LLMemType mt(LLMemType::MTYPE_OBJECT);
2168
2169 /*
2170 * XXXPAM Investigate not making this copy. Seems unecessary, but I'm unsure about the
2171 * interaction with doUpdateInventory() called below.
2172 */
2173 lldebugs << "LLViewerObject::saveScript() " << item->getUUID() << " " << item->getAssetUUID() << llendl;
2174 LLPointer<LLViewerInventoryItem> task_item =
2175 new LLViewerInventoryItem(item->getUUID(), mID, item->getPermissions(),
2176 item->getAssetUUID(), item->getType(),
2177 item->getInventoryType(),
2178 item->getName(), item->getDescription(),
2179 item->getSaleInfo(), item->getFlags(),
2180 item->getCreationDate());
2181 task_item->setTransactionID(item->getTransactionID());
2182
2183 LLMessageSystem* msg = gMessageSystem;
2184 msg->newMessageFast(_PREHASH_RezScript);
2185 msg->nextBlockFast(_PREHASH_AgentData);
2186 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
2187 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
2188 msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID());
2189 msg->nextBlockFast(_PREHASH_UpdateBlock);
2190 msg->addU32Fast(_PREHASH_ObjectLocalID, (mLocalID));
2191 U8 enabled = active;
2192 msg->addBOOLFast(_PREHASH_Enabled, enabled);
2193 msg->nextBlockFast(_PREHASH_InventoryBlock);
2194 task_item->packMessage(msg);
2195 msg->sendReliable(mRegionp->getHost());
2196
2197 // do the internal logic
2198 doUpdateInventory(task_item, TASK_INVENTORY_ITEM_KEY, is_new);
2199}
2200
2201void LLViewerObject::moveInventory(const LLUUID& folder_id,
2202 const LLUUID& item_id)
2203{
2204 lldebugs << "LLViewerObject::moveInventory " << item_id << llendl;
2205 LLMessageSystem* msg = gMessageSystem;
2206 msg->newMessageFast(_PREHASH_MoveTaskInventory);
2207 msg->nextBlockFast(_PREHASH_AgentData);
2208 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
2209 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
2210 msg->addUUIDFast(_PREHASH_FolderID, folder_id);
2211 msg->nextBlockFast(_PREHASH_InventoryData);
2212 msg->addU32Fast(_PREHASH_LocalID, mLocalID);
2213 msg->addUUIDFast(_PREHASH_ItemID, item_id);
2214 msg->sendReliable(mRegionp->getHost());
2215
2216 LLInventoryObject* inv_obj = getInventoryObject(item_id);
2217 if(inv_obj)
2218 {
2219 LLViewerInventoryItem* item = (LLViewerInventoryItem*)inv_obj;
2220 if(!item->getPermissions().allowCopyBy(gAgent.getID()))
2221 {
2222 deleteInventoryItem(item_id);
2223 ++mInventorySerialNum;
2224 }
2225 }
2226}
2227
2228void LLViewerObject::dirtyInventory()
2229{
2230 // If there aren't any LLVOInventoryListeners, we won't be
2231 // able to update our mInventory when it comes back from the
2232 // simulator, so we should not clear the inventory either.
2233 if(mInventory && !mInventoryCallbacks.isEmpty())
2234 {
2235 mInventory->clear(); // will deref and delete entries
2236 delete mInventory;
2237 mInventory = NULL;
2238 mInventoryDirty = TRUE;
2239 }
2240}
2241
2242void LLViewerObject::registerInventoryListener(LLVOInventoryListener* listener, void* user_data)
2243{
2244 LLMemType mt(LLMemType::MTYPE_OBJECT);
2245
2246 LLInventoryCallbackInfo* info = new LLInventoryCallbackInfo;
2247 info->mListener = listener;
2248 info->mInventoryData = user_data;
2249 mInventoryCallbacks.addData(info);
2250}
2251
2252void LLViewerObject::removeInventoryListener(LLVOInventoryListener* listener)
2253{
2254 if (listener == NULL) return;
2255 LLInventoryCallbackInfo* info;
2256 for (info = mInventoryCallbacks.getFirstData();
2257 info;
2258 info = mInventoryCallbacks.getNextData() )
2259 {
2260 if (info->mListener == listener)
2261 {
2262 mInventoryCallbacks.deleteCurrentData();
2263 break;
2264 }
2265 }
2266}
2267
2268void LLViewerObject::clearInventoryListeners()
2269{
2270 mInventoryCallbacks.deleteAllData();
2271}
2272
2273void LLViewerObject::requestInventory()
2274{
2275 mInventoryDirty = FALSE;
2276 if(mInventory)
2277 {
2278 //mInventory->clear() // will deref and delete it
2279 //delete mInventory;
2280 //mInventory = NULL;
2281 doInventoryCallback();
2282 }
2283 // throw away duplicate requests
2284 else if (! mInventoryPending)
2285 {
2286 LLMessageSystem* msg = gMessageSystem;
2287 msg->newMessageFast(_PREHASH_RequestTaskInventory);
2288 msg->nextBlockFast(_PREHASH_AgentData);
2289 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
2290 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
2291 msg->nextBlockFast(_PREHASH_InventoryData);
2292 msg->addU32Fast(_PREHASH_LocalID, mLocalID);
2293 msg->sendReliable(mRegionp->getHost());
2294
2295 // this will get reset by dirtyInventory or doInventoryCallback
2296 mInventoryPending = TRUE;
2297 }
2298}
2299
2300struct LLFilenameAndTask
2301{
2302 LLUUID mTaskID;
2303 char mFilename[MAX_STRING]; // Just the filename, not the path
2304#ifdef _DEBUG
2305 static S32 sCount;
2306 LLFilenameAndTask()
2307 {
2308 ++sCount;
2309 lldebugs << "Constructing LLFilenameAndTask: " << sCount << llendl;
2310 }
2311 ~LLFilenameAndTask()
2312 {
2313 --sCount;
2314 lldebugs << "Destroying LLFilenameAndTask: " << sCount << llendl;
2315 }
2316private:
2317 LLFilenameAndTask(const LLFilenameAndTask& rhs);
2318 const LLFilenameAndTask& operator=(const LLFilenameAndTask& rhs) const;
2319#endif
2320};
2321
2322#ifdef _DEBUG
2323S32 LLFilenameAndTask::sCount = 0;
2324#endif
2325
2326// static
2327void LLViewerObject::processTaskInv(LLMessageSystem* msg, void** user_data)
2328{
2329 LLMemType mt(LLMemType::MTYPE_OBJECT);
2330
2331 LLUUID task_id;
2332 msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_TaskID, task_id);
2333 LLViewerObject* object = gObjectList.findObject(task_id);
2334 if(object)
2335 {
2336 msg->getS16Fast(_PREHASH_InventoryData, _PREHASH_Serial, object->mInventorySerialNum);
2337 LLFilenameAndTask* ft = new LLFilenameAndTask;
2338 ft->mTaskID = task_id;
2339 msg->getStringFast(_PREHASH_InventoryData, _PREHASH_Filename, MAX_STRING, ft->mFilename);
2340 if(!ft->mFilename[0])
2341 {
2342 lldebugs << "Task has no inventory" << llendl;
2343 // mock up some inventory to make a drop target.
2344 if(object->mInventory)
2345 {
2346 object->mInventory->clear(); // will deref and delete it
2347 }
2348 else
2349 {
2350 object->mInventory = new InventoryObjectList();
2351 }
2352 LLPointer<LLInventoryObject> obj;
2353 obj = new LLInventoryObject(object->mID, LLUUID::null,
2354 LLAssetType::AT_CATEGORY,
2355 "Contents");
2356 object->mInventory->push_front(obj);
2357 object->doInventoryCallback();
2358 delete ft;
2359 return;
2360 }
2361 gXferManager->requestFile(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ft->mFilename).c_str(),
2362 ft->mFilename, LL_PATH_CACHE,
2363 object->mRegionp->getHost(),
2364 TRUE,
2365 &LLViewerObject::processTaskInvFile,
2366 (void**)ft,
2367 LLXferManager::HIGH_PRIORITY);
2368 }
2369}
2370
2371void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code)
2372{
2373 LLFilenameAndTask* ft = (LLFilenameAndTask*)user_data;
2374 LLViewerObject* object = NULL;
2375 if(ft && (0 == error_code) &&
2376 (object = gObjectList.findObject(ft->mTaskID)))
2377 {
2378 object->loadTaskInvFile(ft->mFilename);
2379 }
2380 else
2381 {
2382 // This Occurs When to requests were made, and the first one
2383 // has already handled it.
2384 lldebugs << "Problem loading task inventory. Return code: "
2385 << error_code << llendl;
2386 }
2387 delete ft;
2388}
2389
2390void LLViewerObject::loadTaskInvFile(const char* filename)
2391{
2392 LLMemType mt(LLMemType::MTYPE_OBJECT);
2393
2394 std::string filename_and_local_path = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, filename);
2395 llifstream ifs(filename_and_local_path.c_str());
2396 if(ifs.good())
2397 {
2398 char buffer[MAX_STRING];
2399 char keyword[MAX_STRING];
2400 if(mInventory)
2401 {
2402 mInventory->clear(); // will deref and delete it
2403 }
2404 else
2405 {
2406 mInventory = new InventoryObjectList;
2407 }
2408 while(ifs.good())
2409 {
2410 ifs.getline(buffer, MAX_STRING);
2411 sscanf(buffer, " %s", keyword);
2412 if(0 == strcmp("inv_item", keyword))
2413 {
2414 LLPointer<LLInventoryObject> inv = new LLViewerInventoryItem;
2415 inv->importLegacyStream(ifs);
2416 mInventory->push_front(inv);
2417 }
2418 else if(0 == strcmp("inv_object", keyword))
2419 {
2420 LLPointer<LLInventoryObject> inv = new LLInventoryObject;
2421 inv->importLegacyStream(ifs);
2422 mInventory->push_front(inv);
2423 }
2424 else
2425 {
2426 llwarns << "Unknown token in inventory file '"
2427 << keyword << "'" << llendl;
2428 }
2429 }
2430 ifs.close();
2431 LLFile::remove(filename_and_local_path.c_str());
2432 }
2433 else
2434 {
2435 llwarns << "unable to load task inventory: " << filename_and_local_path
2436 << llendl;
2437 }
2438 doInventoryCallback();
2439}
2440
2441void LLViewerObject::doInventoryCallback()
2442{
2443 for(LLInventoryCallbackInfo* info = mInventoryCallbacks.getFirstData();
2444 info != NULL;
2445 info = mInventoryCallbacks.getNextData())
2446 {
2447 if (info->mListener != NULL)
2448 {
2449 info->mListener->inventoryChanged(this,
2450 mInventory,
2451 mInventorySerialNum,
2452 info->mInventoryData);
2453 }
2454 else
2455 {
2456 llinfos << "LLViewerObject::doInventoryCallback() deleting bad listener entry." << llendl;
2457 mInventoryCallbacks.deleteCurrentData();
2458 }
2459 }
2460 mInventoryPending = FALSE;
2461}
2462
2463void LLViewerObject::removeInventory(const LLUUID& item_id)
2464{
2465 // close any associated floater properties
2466 LLFloaterProperties::closeByID(item_id, mID);
2467
2468 LLMessageSystem* msg = gMessageSystem;
2469 msg->newMessageFast(_PREHASH_RemoveTaskInventory);
2470 msg->nextBlockFast(_PREHASH_AgentData);
2471 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
2472 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
2473 msg->nextBlockFast(_PREHASH_InventoryData);
2474 msg->addU32Fast(_PREHASH_LocalID, mLocalID);
2475 msg->addUUIDFast(_PREHASH_ItemID, item_id);
2476 msg->sendReliable(mRegionp->getHost());
2477 deleteInventoryItem(item_id);
2478 ++mInventorySerialNum;
2479
2480 // The viewer object should not refresh UI since this is a utility
2481 // function. The UI functionality that called this method should
2482 // refresh the views if necessary.
2483 //gBuildView->refresh();
2484}
2485
2486void LLViewerObject::updateInventory(
2487 LLViewerInventoryItem* item,
2488 U8 key,
2489 bool is_new)
2490{
2491 LLMemType mt(LLMemType::MTYPE_OBJECT);
2492
2493 // This slices the object into what we're concerned about on the
2494 // viewer. The simulator will take the permissions and transfer
2495 // ownership.
2496 LLPointer<LLViewerInventoryItem> task_item =
2497 new LLViewerInventoryItem(item->getUUID(), mID, item->getPermissions(),
2498 item->getAssetUUID(), item->getType(),
2499 item->getInventoryType(),
2500 item->getName(), item->getDescription(),
2501 item->getSaleInfo(),
2502 item->getFlags(),
2503 item->getCreationDate());
2504 task_item->setTransactionID(item->getTransactionID());
2505 LLMessageSystem* msg = gMessageSystem;
2506 msg->newMessageFast(_PREHASH_UpdateTaskInventory);
2507 msg->nextBlockFast(_PREHASH_AgentData);
2508 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
2509 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
2510 msg->nextBlockFast(_PREHASH_UpdateData);
2511 msg->addU32Fast(_PREHASH_LocalID, mLocalID);
2512 msg->addU8Fast(_PREHASH_Key, key);
2513 msg->nextBlockFast(_PREHASH_InventoryData);
2514 task_item->packMessage(msg);
2515 msg->sendReliable(mRegionp->getHost());
2516
2517 // do the internal logic
2518 doUpdateInventory(task_item, key, is_new);
2519}
2520
2521LLInventoryObject* LLViewerObject::getInventoryObject(const LLUUID& item_id)
2522{
2523 LLInventoryObject* rv = NULL;
2524 if(mInventory)
2525 {
2526 InventoryObjectList::iterator it = mInventory->begin();
2527 InventoryObjectList::iterator end = mInventory->end();
2528 for ( ; it != end; ++it)
2529 {
2530 if((*it)->getUUID() == item_id)
2531 {
2532 rv = *it;
2533 break;
2534 }
2535 }
2536 }
2537 return rv;
2538}
2539
2540void LLViewerObject::getInventoryContents(InventoryObjectList& objects)
2541{
2542 if(mInventory)
2543 {
2544 InventoryObjectList::iterator it = mInventory->begin();
2545 InventoryObjectList::iterator end = mInventory->end();
2546 for( ; it != end; ++it)
2547 {
2548 if ((*it)->getType() != LLAssetType::AT_CATEGORY)
2549 {
2550 objects.push_back(*it);
2551 }
2552 }
2553 }
2554}
2555
2556LLInventoryObject* LLViewerObject::getInventoryRoot()
2557{
2558 if (!mInventory || !mInventory->size())
2559 {
2560 return NULL;
2561 }
2562 return mInventory->back();
2563}
2564
2565LLViewerInventoryItem* LLViewerObject::getInventoryItemByAsset(const LLUUID& asset_id)
2566{
2567 LLViewerInventoryItem* rv = NULL;
2568 if(mInventory)
2569 {
2570 LLViewerInventoryItem* item = NULL;
2571
2572 InventoryObjectList::iterator it = mInventory->begin();
2573 InventoryObjectList::iterator end = mInventory->end();
2574 for( ; it != end; ++it)
2575 {
2576 LLInventoryObject* obj = *it;
2577 if(obj->getType() != LLAssetType::AT_CATEGORY)
2578 {
2579 // *FIX: gank-ass down cast!
2580 item = (LLViewerInventoryItem*)obj;
2581 if(item->getAssetUUID() == asset_id)
2582 {
2583 rv = item;
2584 break;
2585 }
2586 }
2587 }
2588 }
2589 return rv;
2590}
2591
2592void LLViewerObject::setPixelAreaAndAngle(LLAgent &agent)
2593{
2594 if (getVolume())
2595 { //volumes calculate pixel area and angle per face
2596 return;
2597 }
2598
2599 LLVector3 viewer_pos_agent = agent.getCameraPositionAgent();
2600 LLVector3 pos_agent = getRenderPosition();
2601
2602 F32 dx = viewer_pos_agent.mV[VX] - pos_agent.mV[VX];
2603 F32 dy = viewer_pos_agent.mV[VY] - pos_agent.mV[VY];
2604 F32 dz = viewer_pos_agent.mV[VZ] - pos_agent.mV[VZ];
2605
2606 F32 max_scale = getMaxScale();
2607 F32 mid_scale = getMidScale();
2608 F32 min_scale = getMinScale();
2609
2610 // IW: esitmate - when close to large objects, computing range based on distance from center is no good
2611 // to try to get a min distance from face, subtract min_scale/2 from the range.
2612 // This means we'll load too much detail sometimes, but that's better than not enough
2613 // I don't think there's a better way to do this without calculating distance per-poly
2614 F32 range = sqrt(dx*dx + dy*dy + dz*dz) - min_scale/2;
2615
2616 if (range < 0.001f || isHUDAttachment()) // range == zero
2617 {
2618 mAppAngle = 180.f;
2619 mPixelArea = (F32)gCamera->getScreenPixelArea();
2620 }
2621 else
2622 {
2623 mAppAngle = (F32) atan2( max_scale, range) * RAD_TO_DEG;
2624
2625 F32 pixels_per_meter = gCamera->getPixelMeterRatio() / range;
2626
2627 mPixelArea = (pixels_per_meter * max_scale) * (pixels_per_meter * mid_scale);
2628 if (mPixelArea > gCamera->getScreenPixelArea())
2629 {
2630 mAppAngle = 180.f;
2631 mPixelArea = (F32)gCamera->getScreenPixelArea();
2632 }
2633 }
2634}
2635
2636BOOL LLViewerObject::updateLOD()
2637{
2638 return FALSE;
2639}
2640
2641BOOL LLViewerObject::updateGeometry(LLDrawable *drawable)
2642{
2643 return TRUE;
2644}
2645
2646LLDrawable* LLViewerObject::createDrawable(LLPipeline *pipeline)
2647{
2648 return NULL;
2649}
2650
2651void LLViewerObject::setScale(const LLVector3 &scale, BOOL damped)
2652{
2653 LLPrimitive::setScale(scale);
2654 if (mDrawable.notNull())
2655 {
2656 //encompass completely sheared objects by taking
2657 //the most extreme point possible (<1,1,0.5>)
2658 mDrawable->setRadius(LLVector3(1,1,0.5f).scaleVec(scale).magVec());
2659 updateDrawable(damped);
2660 }
2661
2662 if( (LL_PCODE_VOLUME == getPCode()) && !isDead() )
2663 {
2664 if (permYouOwner() || (scale.magVecSquared() > (7.5f * 7.5f)) )
2665 {
2666 if (!mOnMap)
2667 {
2668 gObjectList.addToMap(this);
2669 mOnMap = TRUE;
2670 }
2671 }
2672 else
2673 {
2674 if (mOnMap)
2675 {
2676 gObjectList.removeFromMap(this);
2677 mOnMap = FALSE;
2678 }
2679 }
2680 }
2681}
2682
2683void LLViewerObject::updateSpatialExtents(LLVector3& newMin, LLVector3 &newMax)
2684{
2685 LLVector3 center = getRenderPosition();
2686 F32 sz = llmin(mDrawable->getRadius(), 256.f);
2687 LLVector3 size = LLVector3(sz,sz,sz);
2688 newMin.setVec(center-size);
2689 newMax.setVec(center+size);
2690 mDrawable->setPositionGroup((newMin + newMax) * 0.5f);
2691}
2692
2693F32 LLViewerObject::getMaxScale() const
2694{
2695 return llmax(getScale().mV[VX],getScale().mV[VY], getScale().mV[VZ]);
2696}
2697
2698F32 LLViewerObject::getMinScale() const
2699{
2700 return llmin(getScale().mV[0],getScale().mV[1],getScale().mV[2]);
2701}
2702
2703F32 LLViewerObject::getMidScale() const
2704{
2705 if (getScale().mV[VX] < getScale().mV[VY])
2706 {
2707 if (getScale().mV[VY] < getScale().mV[VZ])
2708 {
2709 return getScale().mV[VY];
2710 }
2711 else if (getScale().mV[VX] < getScale().mV[VZ])
2712 {
2713 return getScale().mV[VZ];
2714 }
2715 else
2716 {
2717 return getScale().mV[VX];
2718 }
2719 }
2720 else if (getScale().mV[VX] < getScale().mV[VZ])
2721 {
2722 return getScale().mV[VX];
2723 }
2724 else if (getScale().mV[VY] < getScale().mV[VZ])
2725 {
2726 return getScale().mV[VZ];
2727 }
2728 else
2729 {
2730 return getScale().mV[VY];
2731 }
2732}
2733
2734
2735void LLViewerObject::updateTextures(LLAgent &agent)
2736{
2737}
2738
2739void LLViewerObject::boostTexturePriority(BOOL boost_children /* = TRUE */)
2740{
2741 if (isDead())
2742 {
2743 return;
2744 }
2745
2746 S32 i;
2747 S32 tex_count = getNumTEs();
2748 for (i = 0; i < tex_count; i++)
2749 {
2750 getTEImage(i)->setBoostLevel(LLViewerImage::BOOST_SELECTED);
2751 }
2752
2753 if (boost_children)
2754 {
2755 S32 num_children = mChildList.size();
2756 for (i = 0; i < num_children; i++)
2757 {
2758 LLViewerObject *childp = mChildList[i];
2759 childp->boostTexturePriority();
2760 }
2761 }
2762}
2763
2764
2765void LLViewerObject::setLineWidthForWindowSize(S32 window_width)
2766{
2767 if (window_width < 700)
2768 {
2769 LLUI::setLineWidth(2.0f);
2770 }
2771 else if (window_width < 1100)
2772 {
2773 LLUI::setLineWidth(3.0f);
2774 }
2775 else if (window_width < 2000)
2776 {
2777 LLUI::setLineWidth(4.0f);
2778 }
2779 else
2780 {
2781 // _damn_, what a nice monitor!
2782 LLUI::setLineWidth(5.0f);
2783 }
2784}
2785
2786void LLViewerObject::increaseArrowLength()
2787{
2788/* ???
2789 if (mAxisArrowLength == 50)
2790 {
2791 mAxisArrowLength = 100;
2792 }
2793 else
2794 {
2795 mAxisArrowLength = 150;
2796 }
2797*/
2798}
2799
2800
2801void LLViewerObject::decreaseArrowLength()
2802{
2803/* ???
2804 if (mAxisArrowLength == 150)
2805 {
2806 mAxisArrowLength = 100;
2807 }
2808 else
2809 {
2810 mAxisArrowLength = 50;
2811 }
2812*/
2813}
2814
2815// Culled from newsim LLTask::addNVPair
2816void LLViewerObject::addNVPair(const std::string& data)
2817{
2818 // cout << "LLViewerObject::addNVPair() with ---" << data << "---" << endl;
2819 LLNameValue *nv = new LLNameValue(data.c_str());
2820
2821// char splat[MAX_STRING];
2822// temp->printNameValue(splat);
2823// llinfos << "addNVPair " << splat << llendl;
2824
2825 name_value_map_t::iterator iter = mNameValuePairs.find(nv->mName);
2826 if (iter != mNameValuePairs.end())
2827 {
2828 LLNameValue* foundnv = iter->second;
2829 if (foundnv->mClass != NVC_READ_ONLY)
2830 {
2831 delete foundnv;
2832 mNameValuePairs.erase(iter);
2833 }
2834 else
2835 {
2836 delete nv;
2837// llinfos << "Trying to write to Read Only NVPair " << temp->mName << " in addNVPair()" << llendl;
2838 return;
2839 }
2840 }
2841 mNameValuePairs[nv->mName] = nv;
2842}
2843
2844BOOL LLViewerObject::removeNVPair(const char *name)
2845{
2846 char* canonical_name = gNVNameTable.addString(name);
2847
2848 lldebugs << "LLViewerObject::removeNVPair(): " << name << llendl;
2849
2850 name_value_map_t::iterator iter = mNameValuePairs.find(canonical_name);
2851 if (iter != mNameValuePairs.end())
2852 {
2853 if( mRegionp )
2854 {
2855 LLNameValue* nv = iter->second;
2856/*
2857 std::string buffer = nv->printNameValue();
2858 gMessageSystem->newMessageFast(_PREHASH_RemoveNameValuePair);
2859 gMessageSystem->nextBlockFast(_PREHASH_TaskData);
2860 gMessageSystem->addUUIDFast(_PREHASH_ID, mID);
2861
2862 gMessageSystem->nextBlockFast(_PREHASH_NameValueData);
2863 gMessageSystem->addStringFast(_PREHASH_NVPair, buffer.c_str());
2864
2865 gMessageSystem->sendReliable( mRegionp->getHost() );
2866*/
2867 // Remove the NV pair from the local list.
2868 delete nv;
2869 mNameValuePairs.erase(iter);
2870 return TRUE;
2871 }
2872 else
2873 {
2874 lldebugs << "removeNVPair - No region for object" << llendl;
2875 }
2876 }
2877 return FALSE;
2878}
2879
2880
2881LLNameValue *LLViewerObject::getNVPair(const char *name) const
2882{
2883 char *canonical_name;
2884
2885 canonical_name = gNVNameTable.addString(name);
2886
2887 // If you access a map with a name that isn't in it, it will add the name and a null pointer.
2888 // So first check if the data is in the map.
2889 name_value_map_t::const_iterator iter = mNameValuePairs.find(canonical_name);
2890 if (iter != mNameValuePairs.end())
2891 {
2892 return iter->second;
2893 }
2894 else
2895 {
2896 return NULL;
2897 }
2898}
2899
2900void LLViewerObject::updatePositionCaches() const
2901{
2902 if (!isRoot())
2903 {
2904 mPositionRegion = ((LLViewerObject *)getParent())->getPositionRegion() + getPosition() * getParent()->getRotation();
2905 mPositionAgent = mRegionp->getPosAgentFromRegion(mPositionRegion);
2906 }
2907 else
2908 {
2909 mPositionRegion = getPosition();
2910 mPositionAgent = mRegionp->getPosAgentFromRegion(mPositionRegion);
2911 }
2912}
2913
2914const LLVector3d LLViewerObject::getPositionGlobal() const
2915{
2916 LLVector3d position_global = mRegionp->getPosGlobalFromRegion(getPositionRegion());;
2917
2918 if (isAttachment())
2919 {
2920 position_global = gAgent.getPosGlobalFromAgent(getRenderPosition());
2921 }
2922
2923 return position_global;
2924}
2925
2926const LLVector3 &LLViewerObject::getPositionAgent() const
2927{
2928 if (mRegionp)
2929 {
2930 if (mDrawable.notNull() && (!mDrawable->isRoot() && getParent()))
2931 {
2932 // Don't return cached position if you have a parent, recalc (until all dirtying is done correctly.
2933 LLVector3 position_region;
2934 position_region = ((LLViewerObject *)getParent())->getPositionRegion() + getPosition() * getParent()->getRotation();
2935 mPositionAgent = mRegionp->getPosAgentFromRegion(position_region);
2936 }
2937 else
2938 {
2939 mPositionAgent = mRegionp->getPosAgentFromRegion(getPosition());
2940 }
2941 }
2942 return mPositionAgent;
2943}
2944
2945const LLVector3 &LLViewerObject::getPositionRegion() const
2946{
2947 if (!isRoot())
2948 {
2949 LLViewerObject *parent = (LLViewerObject *)getParent();
2950 mPositionRegion = parent->getPositionRegion() + (getPosition() * parent->getRotation());
2951 }
2952 return mPositionRegion;
2953}
2954
2955const LLVector3 LLViewerObject::getPositionEdit() const
2956{
2957 if (isRootEdit())
2958 {
2959 return getPosition();
2960 }
2961 else
2962 {
2963 LLViewerObject *parent = (LLViewerObject *)getParent();
2964 LLVector3 position_edit = parent->getPositionEdit() + getPosition() * parent->getRotationEdit();
2965 return position_edit;
2966 }
2967}
2968
2969const LLVector3 LLViewerObject::getRenderPosition() const
2970{
2971 if (mDrawable.isNull() || mDrawable->getGeneration() < 0)
2972 {
2973 return getPositionAgent();
2974 }
2975 else
2976 {
2977 if (isAvatar())
2978 {
2979 if (isRoot())
2980 {
2981 return mDrawable->getPositionAgent();
2982 }
2983 else
2984 {
2985 return getPosition() * mDrawable->getParent()->getRenderMatrix();
2986 }
2987 }
2988
2989 return mDrawable->getPositionAgent();
2990 }
2991}
2992
2993const LLVector3 LLViewerObject::getPivotPositionAgent() const
2994{
2995 return getRenderPosition();
2996}
2997
2998const LLQuaternion LLViewerObject::getRenderRotation() const
2999{
3000 LLQuaternion ret;
3001 if (mDrawable.isNull() || mDrawable->isStatic())
3002 {
3003 ret = getRotationEdit();
3004 }
3005 else
3006 {
3007 if (!mDrawable->isRoot())
3008 {
3009 ret = getRotation() * LLQuaternion(mDrawable->getParent()->getWorldMatrix());
3010 }
3011 else
3012 {
3013 ret = LLQuaternion(mDrawable->getWorldMatrix());
3014 }
3015 }
3016
3017 return ret;
3018}
3019
3020const LLMatrix4 LLViewerObject::getRenderMatrix() const
3021{
3022 return mDrawable->getWorldMatrix();
3023}
3024
3025const LLQuaternion LLViewerObject::getRotationRegion() const
3026{
3027 LLQuaternion global_rotation = getRotation();
3028 if (!((LLXform *)this)->isRoot())
3029 {
3030 global_rotation = global_rotation * getParent()->getRotation();
3031 }
3032 return global_rotation;
3033}
3034
3035const LLQuaternion LLViewerObject::getRotationEdit() const
3036{
3037 LLQuaternion global_rotation = getRotation();
3038 if (!((LLXform *)this)->isRootEdit())
3039 {
3040 global_rotation = global_rotation * getParent()->getRotation();
3041 }
3042 return global_rotation;
3043}
3044
3045void LLViewerObject::setPositionAbsoluteGlobal( const LLVector3d &pos_global, BOOL damped )
3046{
3047 if (isAttachment())
3048 {
3049 LLVector3 new_pos = mRegionp->getPosRegionFromGlobal(pos_global);
3050 if (isRootEdit())
3051 {
3052 new_pos -= mDrawable->mXform.getParent()->getWorldPosition();
3053 LLQuaternion world_rotation = mDrawable->mXform.getParent()->getWorldRotation();
3054 new_pos = new_pos * ~world_rotation;
3055 }
3056 else
3057 {
3058 LLViewerObject* parentp = (LLViewerObject*)getParent();
3059 new_pos -= parentp->getPositionAgent();
3060 new_pos = new_pos * ~parentp->getRotationRegion();
3061 }
3062 LLViewerObject::setPosition(new_pos);
3063
3064 if (mParent && ((LLViewerObject*)mParent)->isAvatar())
3065 {
3066 // we have changed the position of an attachment, so we need to clamp it
3067 LLVOAvatar *avatar = (LLVOAvatar*)mParent;
3068
3069 avatar->clampAttachmentPositions();
3070 }
3071 }
3072 else
3073 {
3074 if( isRoot() )
3075 {
3076 setPositionRegion(mRegionp->getPosRegionFromGlobal(pos_global));
3077 }
3078 else
3079 {
3080 // the relative position with the parent is not constant
3081 LLViewerObject* parent = (LLViewerObject *)getParent();
3082 //RN: this assumes we are only calling this function from the edit tools
3083 gPipeline.updateMoveNormalAsync(parent->mDrawable);
3084
3085 LLVector3 pos_local = mRegionp->getPosRegionFromGlobal(pos_global) - parent->getPositionRegion();
3086 pos_local = pos_local * ~parent->getRotationRegion();
3087 LLViewerObject::setPosition( pos_local );
3088 }
3089 }
3090 //RN: assumes we always want to snap the object when calling this function
3091 gPipeline.updateMoveNormalAsync(mDrawable);
3092}
3093
3094void LLViewerObject::setPosition(const LLVector3 &pos, BOOL damped)
3095{
3096 if (getPosition() != pos)
3097 {
3098 setChanged(TRANSLATED | SILHOUETTE);
3099 }
3100
3101 LLXform::setPosition(pos);
3102 updateDrawable(damped);
3103 if (isRoot())
3104 {
3105 // position caches need to be up to date on root objects
3106 updatePositionCaches();
3107 }
3108}
3109
3110void LLViewerObject::setPositionGlobal(const LLVector3d &pos_global, BOOL damped)
3111{
3112 if (isAttachment())
3113 {
3114 if (isRootEdit())
3115 {
3116 LLVector3 newPos = mRegionp->getPosRegionFromGlobal(pos_global);
3117 newPos = newPos - mDrawable->mXform.getParent()->getWorldPosition();
3118
3119 LLQuaternion invWorldRotation = mDrawable->mXform.getParent()->getWorldRotation();
3120 invWorldRotation.transQuat();
3121
3122 newPos = newPos * invWorldRotation;
3123 LLViewerObject::setPosition(newPos);
3124 }
3125 else
3126 {
3127 // assumes parent is root editable (root of attachment)
3128 LLVector3 newPos = mRegionp->getPosRegionFromGlobal(pos_global);
3129 newPos = newPos - mDrawable->mXform.getParent()->getWorldPosition();
3130 LLVector3 delta_pos = newPos - getPosition();
3131
3132 LLQuaternion invRotation = mDrawable->getRotation();
3133 invRotation.transQuat();
3134
3135 delta_pos = delta_pos * invRotation;
3136
3137 // *FIX: is this right? Shouldn't we be calling the
3138 // LLViewerObject version of setPosition?
3139 LLVector3 old_pos = mDrawable->mXform.getParent()->getPosition();
3140 mDrawable->mXform.getParent()->setPosition(old_pos + delta_pos);
3141 setChanged(TRANSLATED | SILHOUETTE);
3142 }
3143 if (mParent && ((LLViewerObject*)mParent)->isAvatar())
3144 {
3145 // we have changed the position of an attachment, so we need to clamp it
3146 LLVOAvatar *avatar = (LLVOAvatar*)mParent;
3147
3148 avatar->clampAttachmentPositions();
3149 }
3150 }
3151 else
3152 {
3153 if (isRoot())
3154 {
3155 setPositionRegion(mRegionp->getPosRegionFromGlobal(pos_global));
3156 }
3157 else
3158 {
3159 // the relative position with the parent is constant, but the parent's position needs to be changed
3160 LLVector3d position_offset;
3161 position_offset.setVec(getPosition()*getParent()->getRotation());
3162 LLVector3d new_pos_global = pos_global - position_offset;
3163 ((LLViewerObject *)getParent())->setPositionGlobal(new_pos_global);
3164 }
3165 }
3166 updateDrawable(damped);
3167}
3168
3169
3170void LLViewerObject::setPositionParent(const LLVector3 &pos_parent, BOOL damped)
3171{
3172 // Set position relative to parent, if no parent, relative to region
3173 if (!isRoot())
3174 {
3175 LLViewerObject::setPosition(pos_parent);
3176 updateDrawable(damped);
3177 }
3178 else
3179 {
3180 setPositionRegion(pos_parent, damped);
3181 }
3182}
3183
3184void LLViewerObject::setPositionRegion(const LLVector3 &pos_region, BOOL damped)
3185{
3186 if (!isRootEdit())
3187 {
3188 LLViewerObject* parent = (LLViewerObject*) getParent();
3189 LLViewerObject::setPosition((pos_region-parent->getPositionRegion())*~parent->getRotationRegion());
3190 }
3191 else
3192 {
3193 LLViewerObject::setPosition(pos_region);
3194 mPositionRegion = pos_region;
3195 mPositionAgent = mRegionp->getPosAgentFromRegion(mPositionRegion);
3196 }
3197}
3198
3199void LLViewerObject::setPositionAgent(const LLVector3 &pos_agent, BOOL damped)
3200{
3201 LLVector3 pos_region = getRegion()->getPosRegionFromAgent(pos_agent);
3202 setPositionRegion(pos_region, damped);
3203}
3204
3205// identical to setPositionRegion() except it checks for child-joints
3206// and doesn't also move the joint-parent
3207// TODO -- implement similar intelligence for joint-parents toward
3208// their joint-children
3209void LLViewerObject::setPositionEdit(const LLVector3 &pos_edit, BOOL damped)
3210{
3211 if (!isRootEdit())
3212 {
3213 // the relative position with the parent is constant, but the parent's position needs to be changed
3214 LLVector3 position_offset = getPosition() * getParent()->getRotation();
3215
3216 ((LLViewerObject *)getParent())->setPositionEdit(pos_edit - position_offset);
3217 }
3218 else if (isJointChild())
3219 {
3220 // compute new parent-relative position
3221 LLViewerObject *parent = (LLViewerObject *) getParent();
3222 LLQuaternion inv_parent_rot = parent->getRotation();
3223 inv_parent_rot.transQuat();
3224 LLVector3 pos_parent = (pos_edit - parent->getPositionRegion()) * inv_parent_rot;
3225 LLViewerObject::setPosition(pos_parent);
3226 }
3227 else
3228 {
3229 LLViewerObject::setPosition(pos_edit);
3230 mPositionRegion = pos_edit;
3231 mPositionAgent = mRegionp->getPosAgentFromRegion(mPositionRegion);
3232 }
3233 updateDrawable(damped);
3234}
3235
3236
3237LLViewerObject* LLViewerObject::getRootEdit() const
3238{
3239 const LLViewerObject* root = this;
3240 while (root->mParent
3241 && !(root->mJointInfo
3242 || ((LLViewerObject*)root->mParent)->isAvatar()) )
3243 {
3244 root = (LLViewerObject*)root->mParent;
3245 }
3246 return (LLViewerObject*)root;
3247}
3248
3249U8 LLViewerObject::getMediaType() const
3250{
3251 if (mMedia)
3252 {
3253 return mMedia->mMediaType;
3254 }
3255 else
3256 {
3257 return LLViewerObject::MEDIA_TYPE_NONE;
3258 }
3259}
3260
3261void LLViewerObject::setMediaType(U8 media_type)
3262{
3263 if (!mMedia)
3264 {
3265 // JAMESDEBUG TODO what if we don't have a media pointer?
3266 }
3267 else if (mMedia->mMediaType != media_type)
3268 {
3269 mMedia->mMediaType = media_type;
3270
3271 // TODO: update materials with new image
3272 }
3273}
3274
3275const LLString& LLViewerObject::getMediaURL() const
3276{
3277 if (mMedia)
3278 {
3279 return mMedia->mMediaURL;
3280 }
3281 else
3282 {
3283 return LLString::null;
3284 }
3285}
3286
3287void LLViewerObject::setMediaURL(const LLString& media_url)
3288{
3289 LLMemType mt(LLMemType::MTYPE_OBJECT);
3290
3291 if (!mMedia)
3292 {
3293 mMedia = new LLViewerObjectMedia;
3294 mMedia->mMediaURL = media_url;
3295 mMedia->mPassedWhitelist = FALSE;
3296
3297 // TODO: update materials with new image
3298 }
3299 else if (mMedia->mMediaURL != media_url)
3300 {
3301 mMedia->mMediaURL = media_url;
3302 mMedia->mPassedWhitelist = FALSE;
3303
3304 // TODO: update materials with new image
3305 }
3306}
3307
3308BOOL LLViewerObject::getMediaPassedWhitelist() const
3309{
3310 if (mMedia)
3311 {
3312 return mMedia->mPassedWhitelist;
3313 }
3314 else
3315 {
3316 return FALSE;
3317 }
3318}
3319
3320void LLViewerObject::setMediaPassedWhitelist(BOOL passed)
3321{
3322 if (mMedia)
3323 {
3324 mMedia->mPassedWhitelist = passed;
3325 }
3326}
3327
3328BOOL LLViewerObject::setMaterial(const U8 material)
3329{
3330 BOOL res = LLPrimitive::setMaterial(material);
3331 if (res)
3332 {
3333 setChanged(TEXTURE);
3334 }
3335 return res;
3336}
3337
3338void LLViewerObject::setNumTEs(const U8 num_tes)
3339{
3340 LLMemType mt(LLMemType::MTYPE_OBJECT);
3341
3342 U32 i;
3343 if (num_tes != getNumTEs())
3344 {
3345 if (num_tes)
3346 {
3347 LLPointer<LLViewerImage> *new_images;
3348 new_images = new LLPointer<LLViewerImage>[num_tes];
3349 for (i = 0; i < num_tes; i++)
3350 {
3351 if (i < getNumTEs())
3352 {
3353 new_images[i] = mTEImages[i];
3354 }
3355 else if (getNumTEs())
3356 {
3357 new_images[i] = mTEImages[getNumTEs()-1];
3358 }
3359 else
3360 {
3361 new_images[i] = NULL;
3362 }
3363 }
3364
3365 deleteTEImages();
3366
3367 mTEImages = new_images;
3368 }
3369 else
3370 {
3371 deleteTEImages();
3372 }
3373 LLPrimitive::setNumTEs(num_tes);
3374 setChanged(TEXTURE);
3375
3376 if (mDrawable.notNull())
3377 {
3378 gPipeline.markTextured(mDrawable);
3379 }
3380 }
3381}
3382
3383void LLViewerObject::sendMaterialUpdate() const
3384{
3385 LLViewerRegion* regionp = getRegion();
3386 if(!regionp) return;
3387 gMessageSystem->newMessageFast(_PREHASH_ObjectMaterial);
3388 gMessageSystem->nextBlockFast(_PREHASH_AgentData);
3389 gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
3390 gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
3391 gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
3392 gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, mLocalID );
3393 gMessageSystem->addU8Fast(_PREHASH_Material, getMaterial() );
3394 gMessageSystem->sendReliable( regionp->getHost() );
3395
3396}
3397
3398// formerly send_object_rotation
3399void LLViewerObject::sendRotationUpdate() const
3400{
3401 LLViewerRegion* regionp = getRegion();
3402 if(!regionp) return;
3403 gMessageSystem->newMessageFast(_PREHASH_ObjectRotation);
3404 gMessageSystem->nextBlockFast(_PREHASH_AgentData);
3405 gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
3406 gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
3407 gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
3408 gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, mLocalID);
3409 gMessageSystem->addQuatFast(_PREHASH_Rotation, getRotationEdit());
3410 //llinfos << "Sent rotation " << getRotationEdit() << llendl;
3411 gMessageSystem->sendReliable( regionp->getHost() );
3412}
3413
3414// formerly send_object_position_global
3415void LLViewerObject::sendPositionUpdate() const
3416{
3417 gMessageSystem->newMessageFast(_PREHASH_ObjectPosition);
3418 gMessageSystem->nextBlockFast(_PREHASH_AgentData);
3419 gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
3420 gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
3421 gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
3422 gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, mLocalID );
3423 gMessageSystem->addVector3Fast(_PREHASH_Position, getPositionRegion());
3424 LLViewerRegion* regionp = getRegion();
3425 gMessageSystem->sendReliable(regionp->getHost());
3426}
3427
3428
3429//formerly send_object_scale
3430void LLViewerObject::sendScaleUpdate()
3431{
3432 gMessageSystem->newMessageFast(_PREHASH_ObjectScale);
3433 gMessageSystem->nextBlockFast(_PREHASH_AgentData);
3434 gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
3435 gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
3436 gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
3437 gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, mLocalID );
3438 gMessageSystem->addVector3Fast(_PREHASH_Scale, (getScale()));
3439
3440 LLViewerRegion *regionp = getRegion();
3441 gMessageSystem->sendReliable(regionp->getHost() );
3442}
3443
3444
3445//formerly send_object_shape(LLViewerObject *object)
3446void LLViewerObject::sendShapeUpdate()
3447{
3448 gMessageSystem->newMessageFast(_PREHASH_ObjectShape);
3449 gMessageSystem->nextBlockFast(_PREHASH_AgentData);
3450 gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
3451 gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
3452 gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
3453 gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, mLocalID );
3454
3455 LLVolumeMessage::packVolumeParams(&getVolume()->getParams(), gMessageSystem);
3456
3457 LLViewerRegion *regionp = getRegion();
3458 gMessageSystem->sendReliable( regionp->getHost() );
3459}
3460
3461
3462void LLViewerObject::sendTEUpdate() const
3463{
3464 LLMessageSystem* msg = gMessageSystem;
3465 msg->newMessageFast(_PREHASH_ObjectImage);
3466
3467 msg->nextBlockFast(_PREHASH_AgentData);
3468 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
3469 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
3470
3471 msg->nextBlockFast(_PREHASH_ObjectData);
3472 msg->addU32Fast(_PREHASH_ObjectLocalID, mLocalID );
3473 if (mMedia)
3474 {
3475 msg->addString("MediaURL", mMedia->mMediaURL);
3476 }
3477 else
3478 {
3479 msg->addString("MediaURL", NULL);
3480 }
3481
3482 // JAMESDEBUG TODO send media type
3483
3484 packTEMessage(msg);
3485
3486 LLViewerRegion *regionp = getRegion();
3487 msg->sendReliable( regionp->getHost() );
3488}
3489
3490void LLViewerObject::setTE(const U8 te, const LLTextureEntry &texture_entry)
3491{
3492 LLPrimitive::setTE(te, texture_entry);
3493// JAMESDEBUG This doesn't work, don't get any textures.
3494// if (mDrawable.notNull() && mDrawable->isVisible())
3495// {
3496 const LLUUID& image_id = getTE(te)->getID();
3497 mTEImages[te] = gImageList.getImage(image_id);
3498// }
3499}
3500
3501void LLViewerObject::setTEImage(const U8 te, LLViewerImage *imagep)
3502{
3503 if (mTEImages[te] != imagep)
3504 {
3505 mTEImages[te] = imagep;
3506 LLPrimitive::setTETexture(te, imagep->getID());
3507 setChanged(TEXTURE);
3508 if (mDrawable.notNull())
3509 {
3510 gPipeline.markTextured(mDrawable);
3511 }
3512 }
3513}
3514
3515
3516S32 LLViewerObject::setTETextureCore(const U8 te, const LLUUID& uuid, LLHost host)
3517{
3518 S32 retval = 0;
3519 if (uuid != getTE(te)->getID() ||
3520 uuid == LLUUID::null)
3521 {
3522 retval = LLPrimitive::setTETexture(te, uuid);
3523 mTEImages[te] = gImageList.getImageFromHost(uuid, host);
3524 setChanged(TEXTURE);
3525 if (mDrawable.notNull())
3526 {
3527 gPipeline.markTextured(mDrawable);
3528 }
3529 }
3530 return retval;
3531}
3532
3533
3534S32 LLViewerObject::setTETexture(const U8 te, const LLUUID& uuid)
3535{
3536 // Invalid host == get from the agent's sim
3537 return setTETextureCore(te, uuid, LLHost::invalid);
3538}
3539
3540
3541S32 LLViewerObject::setTEColor(const U8 te, const LLColor4 &color)
3542{
3543 S32 retval = 0;
3544 const LLTextureEntry *tep = getTE(te);
3545 if (!tep)
3546 {
3547 llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl;
3548 }
3549 else if (color != tep->getColor())
3550 {
3551 retval = LLPrimitive::setTEColor(te, color);
3552 setChanged(TEXTURE);
3553 if (mDrawable.notNull() && retval)
3554 {
3555 // These should only happen on updates which are not the initial update.
3556 gPipeline.markTextured(mDrawable);
3557 }
3558 }
3559 return retval;
3560}
3561
3562S32 LLViewerObject::setTEBumpmap(const U8 te, const U8 bump)
3563{
3564 S32 retval = 0;
3565 const LLTextureEntry *tep = getTE(te);
3566 if (!tep)
3567 {
3568 llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl;
3569 }
3570 else if (bump != tep->getBumpmap())
3571 {
3572 retval = LLPrimitive::setTEBumpmap(te, bump);
3573 setChanged(TEXTURE);
3574 if (mDrawable.notNull() && retval)
3575 {
3576 gPipeline.markTextured(mDrawable);
3577 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE);
3578 }
3579 }
3580 return retval;
3581}
3582
3583S32 LLViewerObject::setTETexGen(const U8 te, const U8 texgen)
3584{
3585 S32 retval = 0;
3586 const LLTextureEntry *tep = getTE(te);
3587 if (!tep)
3588 {
3589 llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl;
3590 }
3591 else if (texgen != tep->getTexGen())
3592 {
3593 retval = LLPrimitive::setTETexGen(te, texgen);
3594 setChanged(TEXTURE);
3595 if (mDrawable.notNull() && retval)
3596 {
3597 gPipeline.markTextured(mDrawable);
3598 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE);
3599 }
3600 }
3601 return retval;
3602}
3603
3604S32 LLViewerObject::setTEShiny(const U8 te, const U8 shiny)
3605{
3606 S32 retval = 0;
3607 const LLTextureEntry *tep = getTE(te);
3608 if (!tep)
3609 {
3610 llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl;
3611 }
3612 else if (shiny != tep->getShiny())
3613 {
3614 retval = LLPrimitive::setTEShiny(te, shiny);
3615 setChanged(TEXTURE);
3616 if (mDrawable.notNull() && retval)
3617 {
3618 gPipeline.markTextured(mDrawable);
3619 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE);
3620 }
3621 }
3622 return retval;
3623}
3624
3625S32 LLViewerObject::setTEFullbright(const U8 te, const U8 fullbright)
3626{
3627 S32 retval = 0;
3628 const LLTextureEntry *tep = getTE(te);
3629 if (!tep)
3630 {
3631 llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl;
3632 }
3633 else if (fullbright != tep->getFullbright())
3634 {
3635 retval = LLPrimitive::setTEFullbright(te, fullbright);
3636 setChanged(TEXTURE);
3637 if (mDrawable.notNull() && retval)
3638 {
3639 gPipeline.markTextured(mDrawable);
3640 }
3641 }
3642 return retval;
3643}
3644
3645
3646S32 LLViewerObject::setTEMediaFlags(const U8 te, const U8 media_flags)
3647{
3648 // JAMESDEBUG this might need work for media type
3649 S32 retval = 0;
3650 const LLTextureEntry *tep = getTE(te);
3651 if (!tep)
3652 {
3653 llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl;
3654 }
3655 else if (media_flags != tep->getMediaFlags())
3656 {
3657 retval = LLPrimitive::setTEMediaFlags(te, media_flags);
3658 setChanged(TEXTURE);
3659 if (mDrawable.notNull() && retval)
3660 {
3661 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD, TRUE);
3662 gPipeline.markTextured(mDrawable);
3663 // JC - probably only need this if changes texture coords
3664 //gPipeline.markRebuild(mDrawable);
3665 }
3666 }
3667 return retval;
3668}
3669
3670
3671S32 LLViewerObject::setTEScale(const U8 te, const F32 s, const F32 t)
3672{
3673 S32 retval = 0;
3674 retval = LLPrimitive::setTEScale(te, s, t);
3675 setChanged(TEXTURE);
3676 if (mDrawable.notNull() && retval)
3677 {
3678 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD);
3679 }
3680 return retval;
3681}
3682
3683S32 LLViewerObject::setTEScaleS(const U8 te, const F32 s)
3684{
3685 S32 retval = LLPrimitive::setTEScaleS(te, s);
3686 if (mDrawable.notNull() && retval)
3687 {
3688 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD);
3689 }
3690
3691 return retval;
3692}
3693
3694S32 LLViewerObject::setTEScaleT(const U8 te, const F32 t)
3695{
3696 S32 retval = LLPrimitive::setTEScaleT(te, t);
3697 if (mDrawable.notNull() && retval)
3698 {
3699 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD);
3700 }
3701
3702 return retval;
3703}
3704
3705S32 LLViewerObject::setTEOffset(const U8 te, const F32 s, const F32 t)
3706{
3707 S32 retval = LLPrimitive::setTEOffset(te, s, t);
3708 if (mDrawable.notNull() && retval)
3709 {
3710 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD);
3711 }
3712 return retval;
3713}
3714
3715S32 LLViewerObject::setTEOffsetS(const U8 te, const F32 s)
3716{
3717 S32 retval = LLPrimitive::setTEOffsetS(te, s);
3718 if (mDrawable.notNull() && retval)
3719 {
3720 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD);
3721 }
3722
3723 return retval;
3724}
3725
3726S32 LLViewerObject::setTEOffsetT(const U8 te, const F32 t)
3727{
3728 S32 retval = LLPrimitive::setTEOffsetT(te, t);
3729 if (mDrawable.notNull() && retval)
3730 {
3731 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD);
3732 }
3733
3734 return retval;
3735}
3736
3737S32 LLViewerObject::setTERotation(const U8 te, const F32 r)
3738{
3739 S32 retval = LLPrimitive::setTERotation(te, r);
3740 if (mDrawable.notNull() && retval)
3741 {
3742 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD);
3743 }
3744 return retval;
3745}
3746
3747
3748LLViewerImage *LLViewerObject::getTEImage(const U8 face) const
3749{
3750// llassert(mTEImages);
3751
3752 if (face < getNumTEs())
3753 {
3754 LLViewerImage* image = mTEImages[face];
3755 if (image)
3756 {
3757 return image;
3758 }
3759 else
3760 {
3761 return (LLViewerImage*)((LLImageGL*)LLViewerImage::sDefaultImagep);
3762 }
3763 }
3764
3765 llerrs << "Requested invalid face!" << llendl;
3766
3767 return NULL;
3768}
3769
3770
3771void LLViewerObject::fitFaceTexture(const U8 face)
3772{
3773 llinfos << "fitFaceTexture not implemented" << llendl;
3774}
3775
3776
3777LLBBox LLViewerObject::getBoundingBoxAgent() const
3778{
3779 LLVector3 position_agent;
3780 LLQuaternion rot;
3781 LLViewerObject* root_edit = (LLViewerObject*)getRootEdit();
3782 LLViewerObject* avatar_parent = (LLViewerObject*)root_edit->getParent();
3783 if (avatar_parent && avatar_parent->isAvatar() && root_edit->mDrawable.notNull())
3784 {
3785 LLXform* parent_xform = root_edit->mDrawable->getXform()->getParent();
3786 position_agent = (getPositionEdit() * parent_xform->getWorldRotation()) + parent_xform->getWorldPosition();
3787 rot = getRotationEdit() * parent_xform->getWorldRotation();
3788 }
3789 else
3790 {
3791 position_agent = getPositionAgent();
3792 rot = getRotationRegion();
3793 }
3794
3795 return LLBBox( position_agent, rot, getScale() * -0.5f, getScale() * 0.5f );
3796}
3797
3798U32 LLViewerObject::getNumVertices() const
3799{
3800 U32 num_vertices = 0;
3801 if (mDrawable.notNull())
3802 {
3803 S32 i, num_faces;
3804 num_faces = mDrawable->getNumFaces();
3805 for (i = 0; i < num_faces; i++)
3806 {
3807 num_vertices += mDrawable->getFace(i)->getGeomCount();
3808 }
3809 }
3810 return num_vertices;
3811}
3812
3813U32 LLViewerObject::getNumIndices() const
3814{
3815 U32 num_indices = 0;
3816 if (mDrawable.notNull())
3817 {
3818 S32 i, num_faces;
3819 num_faces = mDrawable->getNumFaces();
3820 for (i = 0; i < num_faces; i++)
3821 {
3822 num_indices += mDrawable->getFace(i)->getIndicesCount();
3823 }
3824 }
3825 return num_indices;
3826}
3827
3828// Find the number of instances of this object's inventory that are of the given type
3829S32 LLViewerObject::countInventoryContents(LLAssetType::EType type)
3830{
3831 S32 count = 0;
3832 if( mInventory )
3833 {
3834 InventoryObjectList::const_iterator it = mInventory->begin();
3835 InventoryObjectList::const_iterator end = mInventory->end();
3836 for( ; it != end ; ++it )
3837 {
3838 if( (*it)->getType() == type )
3839 {
3840 ++count;
3841 }
3842 }
3843 }
3844 return count;
3845}
3846
3847
3848void LLViewerObject::setCanSelect(BOOL canSelect)
3849{
3850 mbCanSelect = canSelect;
3851 for (U32 i = 0; i < mChildList.size(); i++)
3852 {
3853 mChildList[i]->mbCanSelect = canSelect;
3854 }
3855}
3856
3857void LLViewerObject::setDebugText(const std::string &utf8text)
3858{
3859 if (!mText)
3860 {
3861 mText = (LLHUDText *)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_TEXT);
3862 mText->setFont(LLFontGL::sSansSerif);
3863 mText->setVertAlignment(LLHUDText::ALIGN_VERT_TOP);
3864 mText->setMaxLines(-1);
3865 mText->setSourceObject(this);
3866 mText->setOnHUDAttachment(isHUDAttachment());
3867 }
3868 mText->setColor(LLColor4::white);
3869 mText->setStringUTF8(utf8text);
3870 mText->setZCompare(FALSE);
3871 mText->setDoFade(FALSE);
3872 updateText();
3873}
3874
3875void LLViewerObject::setIcon(LLViewerImage* icon_image)
3876{
3877 if (!mIcon)
3878 {
3879 mIcon = (LLHUDIcon *)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_ICON);
3880 mIcon->setSourceObject(this);
3881 mIcon->setImage(icon_image);
3882 // *TODO: make this user configurable
3883 mIcon->setScale(0.03f);
3884 }
3885 else
3886 {
3887 mIcon->restartLifeTimer();
3888 }
3889}
3890
3891void LLViewerObject::clearIcon()
3892{
3893 if (mIcon)
3894 {
3895 mIcon = NULL;
3896 }
3897}
3898
3899LLViewerObject* LLViewerObject::getSubParent()
3900{
3901 if (isJointChild())
3902 {
3903 return this;
3904 }
3905 return (LLViewerObject*) getParent();
3906}
3907
3908const LLViewerObject* LLViewerObject::getSubParent() const
3909{
3910 if (isJointChild())
3911 {
3912 return this;
3913 }
3914 return (const LLViewerObject*) getParent();
3915}
3916
3917BOOL LLViewerObject::isOnMap()
3918{
3919 return mOnMap;
3920}
3921
3922
3923void LLViewerObject::updateText()
3924{
3925 if (!isDead())
3926 {
3927 if (mText.notNull())
3928 {
3929 LLVector3 up_offset(0,0,0);
3930 up_offset.mV[2] = getScale().mV[VZ]*0.6f;
3931
3932 if (mDrawable.notNull())
3933 {
3934 mText->setPositionAgent(getRenderPosition() + up_offset);
3935 }
3936 else
3937 {
3938 mText->setPositionAgent(getPositionAgent() + up_offset);
3939 }
3940 }
3941 }
3942}
3943
3944BOOL LLViewerObject::isParticleSource() const
3945{
3946 return !mPartSourcep.isNull() && !mPartSourcep->isDead();
3947}
3948
3949void LLViewerObject::unpackParticleSource(const S32 block_num, const LLUUID& owner_id)
3950{
3951 if (!mPartSourcep.isNull() && mPartSourcep->isDead())
3952 {
3953 mPartSourcep = NULL;
3954 }
3955 if (mPartSourcep)
3956 {
3957 // If we've got one already, just update the existing source (or remove it)
3958 if (!LLViewerPartSourceScript::unpackPSS(this, mPartSourcep, block_num))
3959 {
3960 mPartSourcep->setDead();
3961 mPartSourcep = NULL;
3962 }
3963 }
3964 else
3965 {
3966 //If the owner is muted, don't create the system
3967 if(gMuteListp->isMuted(owner_id)) return;
3968 LLViewerPartSourceScript *pss = LLViewerPartSourceScript::unpackPSS(this, NULL, block_num);
3969
3970 // We need to be able to deal with a particle source that hasn't changed, but still got an update!
3971 if (pss)
3972 {
3973// llinfos << "Making particle system with owner " << owner_id << llendl;
3974 pss->setOwnerUUID(owner_id);
3975 mPartSourcep = pss;
3976 gWorldPointer->mPartSim.addPartSource(pss);
3977 }
3978 }
3979 if (mPartSourcep)
3980 {
3981 if (mPartSourcep->getImage()->getID() != mPartSourcep->mPartSysData.mPartImageID)
3982 {
3983 LLViewerImage* image;
3984 if (mPartSourcep->mPartSysData.mPartImageID == LLUUID::null)
3985 {
3986 LLUUID id(gViewerArt.getString("pixiesmall.tga"));
3987 image = gImageList.getImage(id);
3988 }
3989 else
3990 {
3991 image = gImageList.getImage(mPartSourcep->mPartSysData.mPartImageID);
3992 }
3993 mPartSourcep->setImage(image);
3994 }
3995 }
3996}
3997
3998void LLViewerObject::unpackParticleSource(LLDataPacker &dp, const LLUUID& owner_id)
3999{
4000 if (!mPartSourcep.isNull() && mPartSourcep->isDead())
4001 {
4002 mPartSourcep = NULL;
4003 }
4004 if (mPartSourcep)
4005 {
4006 // If we've got one already, just update the existing source (or remove it)
4007 if (!LLViewerPartSourceScript::unpackPSS(this, mPartSourcep, dp))
4008 {
4009 mPartSourcep->setDead();
4010 mPartSourcep = NULL;
4011 }
4012 }
4013 else
4014 {
4015 //If the owner is muted, don't create the system
4016 if(gMuteListp->isMuted(owner_id)) return;
4017 LLViewerPartSourceScript *pss = LLViewerPartSourceScript::unpackPSS(this, NULL, dp);
4018
4019 // We need to be able to deal with a particle source that hasn't changed, but still got an update!
4020 if (pss)
4021 {
4022// llinfos << "Making particle system with owner " << owner_id << llendl;
4023 pss->setOwnerUUID(owner_id);
4024 mPartSourcep = pss;
4025 gWorldPointer->mPartSim.addPartSource(pss);
4026 }
4027 }
4028 if (mPartSourcep)
4029 {
4030 if (mPartSourcep->getImage()->getID() != mPartSourcep->mPartSysData.mPartImageID)
4031 {
4032 LLViewerImage* image;
4033 if (mPartSourcep->mPartSysData.mPartImageID == LLUUID::null)
4034 {
4035 LLUUID id(gViewerArt.getString("pixiesmall.tga"));
4036 image = gImageList.getImage(id);
4037 }
4038 else
4039 {
4040 image = gImageList.getImage(mPartSourcep->mPartSysData.mPartImageID);
4041 }
4042 mPartSourcep->setImage(image);
4043 }
4044 }
4045}
4046
4047// virtual
4048void LLViewerObject::updateDrawable(BOOL force_damped)
4049{
4050 if (mDrawable.notNull() &&
4051 !mDrawable->isState(LLDrawable::ON_MOVE_LIST) &&
4052 isChanged(MOVED) &&
4053 !isAvatar())
4054 {
4055 mLastUpdateFrame = LLFrameTimer::getFrameCount();
4056 BOOL damped_motion =
4057 !isChanged(SHIFTED) && // not shifted between regions this frame and...
4058 (force_damped || // ...forced into damped motion by application logic or...
4059 (!isSelected() && // ...not selected and...
4060 (mDrawable->isRoot() || // ... is root or ...
4061 !((LLViewerObject*)getParent())->isSelected()) && // ... parent is not selected and ...
4062 getPCode() == LL_PCODE_VOLUME && // ...is a volume object and...
4063 getVelocity().isExactlyZero() && // ...is not moving physically and...
4064 mDrawable->getGeneration() != -1) // ...was not created this frame.
4065 );
4066 gPipeline.markMoved(mDrawable, damped_motion);
4067 }
4068 clearChanged(SHIFTED);
4069}
4070
4071// virtual, overridden by LLVOVolume
4072F32 LLViewerObject::getVObjRadius() const
4073{
4074 return mDrawable.notNull() ? mDrawable->getRadius() : 0.f;
4075}
4076
4077void LLViewerObject::setAttachedSound(const LLUUID &audio_uuid, const LLUUID& owner_id, const F32 gain, const U8 flags)
4078{
4079 if (!gAudiop)
4080 {
4081 return;
4082 }
4083
4084 if (audio_uuid.isNull())
4085 {
4086 if (mAudioSourcep && mAudioSourcep->isLoop() && !mAudioSourcep->hasPendingPreloads())
4087 {
4088 // We don't clear the sound if it's a loop, it'll go away on its own.
4089 // At least, this appears to be how the scripts work.
4090 // The attached sound ID is set to NULL to avoid it playing back when the
4091 // object rezzes in on non-looping sounds.
4092 //llinfos << "Clearing attached sound " << mAudioSourcep->getCurrentData()->getID() << llendl;
4093 gAudiop->cleanupAudioSource(mAudioSourcep);
4094 mAudioSourcep = NULL;
4095 }
4096 else if (mAudioSourcep)
4097 {
4098 if (mAudioSourcep->isLoop())
4099 {
4100 // Just shut off the sound
4101 mAudioSourcep->play(LLUUID::null);
4102 }
4103 }
4104 return;
4105 }
4106 if (flags & LL_SOUND_FLAG_LOOP)
4107 {
4108 if (mAudioSourcep && mAudioSourcep->isLoop() && mAudioSourcep->getCurrentData())
4109 {
4110 if (mAudioSourcep->getCurrentData()->getID() == audio_uuid)
4111 {
4112 //llinfos << "Already playing this sound on a loop, ignoring" << llendl;
4113 return;
4114 }
4115 }
4116 }
4117
4118 if ( mAudioSourcep )
4119 {
4120 gAudiop->cleanupAudioSource(mAudioSourcep);
4121 mAudioSourcep = NULL;
4122 }
4123
4124 getAudioSource(owner_id);
4125
4126 if (mAudioSourcep)
4127 {
4128 mAudioSourcep->setGain(gain);
4129 mAudioSourcep->setLoop((flags & LL_SOUND_FLAG_LOOP) ? TRUE : FALSE);
4130 mAudioSourcep->setSyncMaster((flags & LL_SOUND_FLAG_SYNC_MASTER) ? TRUE : FALSE);
4131 mAudioSourcep->setSyncSlave((flags & LL_SOUND_FLAG_SYNC_SLAVE) ? TRUE : FALSE);
4132 mAudioSourcep->setQueueSounds((flags & LL_SOUND_FLAG_QUEUE) ? TRUE : FALSE);
4133 //llinfos << "Playing attached sound " << audio_uuid << llendl;
4134 mAudioSourcep->play(audio_uuid);
4135 }
4136}
4137
4138LLAudioSource *LLViewerObject::getAudioSource(const LLUUID& owner_id)
4139{
4140 if (!mAudioSourcep)
4141 {
4142 // Arbitrary low gain for a sound that's not playing.
4143 // This is used for sound preloads, for example.
4144 LLAudioSourceVO *asvop = new LLAudioSourceVO(mID, owner_id, 0.01f, this);
4145
4146 mAudioSourcep = asvop;
4147 if(gAudiop) gAudiop->addAudioSource(asvop);
4148 }
4149
4150 return mAudioSourcep;
4151}
4152
4153void LLViewerObject::adjustAudioGain(const F32 gain)
4154{
4155 if (!gAudiop)
4156 {
4157 return;
4158 }
4159
4160 if (!mAudioSourcep)
4161 {
4162 return;
4163 }
4164 mAudioSourcep->setGain(gain);
4165}
4166
4167//----------------------------------------------------------------------------
4168
4169bool LLViewerObject::unpackParameterEntry(U16 param_type, LLDataPacker *dp)
4170{
4171 ExtraParameter* param = getExtraParameterEntryCreate(param_type);
4172 if (param)
4173 {
4174 param->data->unpack(*dp);
4175 param->in_use = TRUE;
4176 parameterChanged(param_type, param->data, TRUE, false);
4177 return true;
4178 }
4179 else
4180 {
4181 return false;
4182 }
4183}
4184
4185LLViewerObject::ExtraParameter* LLViewerObject::createNewParameterEntry(U16 param_type)
4186{
4187 LLNetworkData* new_block = NULL;
4188 switch (param_type)
4189 {
4190 case LLNetworkData::PARAMS_FLEXIBLE:
4191 {
4192 new_block = new LLFlexibleObjectData();
4193 break;
4194 }
4195 case LLNetworkData::PARAMS_LIGHT:
4196 {
4197 new_block = new LLLightParams();
4198 break;
4199 }
4200 default:
4201 {
4202 llinfos << "Unknown param type." << llendl;
4203 break;
4204 }
4205 };
4206
4207 if (new_block)
4208 {
4209 ExtraParameter* new_entry = new ExtraParameter;
4210 new_entry->data = new_block;
4211 new_entry->in_use = false; // not in use yet
4212 mExtraParameterList[param_type] = new_entry;
4213 return new_entry;
4214 }
4215 return NULL;
4216}
4217
4218LLViewerObject::ExtraParameter* LLViewerObject::getExtraParameterEntry(U16 param_type) const
4219{
4220 std::map<U16, ExtraParameter*>::const_iterator itor = mExtraParameterList.find(param_type);
4221 if (itor != mExtraParameterList.end())
4222 {
4223 return itor->second;
4224 }
4225 return NULL;
4226}
4227
4228LLViewerObject::ExtraParameter* LLViewerObject::getExtraParameterEntryCreate(U16 param_type)
4229{
4230 ExtraParameter* param = getExtraParameterEntry(param_type);
4231 if (!param)
4232 {
4233 param = createNewParameterEntry(param_type);
4234 }
4235 return param;
4236}
4237
4238LLNetworkData* LLViewerObject::getParameterEntry(U16 param_type) const
4239{
4240 ExtraParameter* param = getExtraParameterEntry(param_type);
4241 if (param)
4242 {
4243 return param->data;
4244 }
4245 else
4246 {
4247 return NULL;
4248 }
4249}
4250
4251BOOL LLViewerObject::getParameterEntryInUse(U16 param_type) const
4252{
4253 ExtraParameter* param = getExtraParameterEntry(param_type);
4254 if (param)
4255 {
4256 return param->in_use;
4257 }
4258 else
4259 {
4260 return FALSE;
4261 }
4262}
4263
4264bool LLViewerObject::setParameterEntry(U16 param_type, const LLNetworkData& new_value, bool local_origin)
4265{
4266 ExtraParameter* param = getExtraParameterEntryCreate(param_type);
4267 if (param)
4268 {
4269 if (param->in_use && new_value == *(param->data))
4270 {
4271 return false;
4272 }
4273 param->in_use = true;
4274 param->data->copy(new_value);
4275 parameterChanged(param_type, param->data, TRUE, local_origin);
4276 return true;
4277 }
4278 else
4279 {
4280 return false;
4281 }
4282}
4283
4284// Assumed to be called locally
4285// If in_use is TRUE, will crate a new extra parameter if none exists.
4286// Should always return true.
4287bool LLViewerObject::setParameterEntryInUse(U16 param_type, BOOL in_use, bool local_origin)
4288{
4289 ExtraParameter* param = getExtraParameterEntryCreate(param_type);
4290 if (param->in_use != in_use)
4291 {
4292 param->in_use = in_use;
4293 parameterChanged(param_type, param->data, in_use, local_origin);
4294 return true;
4295 }
4296 return false;
4297}
4298
4299void LLViewerObject::parameterChanged(U16 param_type, bool local_origin)
4300{
4301 ExtraParameter* param = getExtraParameterEntry(param_type);
4302 if (param)
4303 {
4304 parameterChanged(param_type, param->data, param->in_use, local_origin);
4305 }
4306}
4307
4308void LLViewerObject::parameterChanged(U16 param_type, LLNetworkData* data, BOOL in_use, bool local_origin)
4309{
4310 if (local_origin)
4311 {
4312 LLViewerRegion* regionp = getRegion();
4313 if(!regionp) return;
4314
4315 // Change happened on the viewer. Send the change up
4316 U8 tmp[MAX_OBJECT_PARAMS_SIZE];
4317 LLDataPackerBinaryBuffer dpb(tmp, MAX_OBJECT_PARAMS_SIZE);
4318 if (data->pack(dpb))
4319 {
4320 U32 datasize = (U32)dpb.getCurrentSize();
4321
4322 LLMessageSystem* msg = gMessageSystem;
4323 msg->newMessageFast(_PREHASH_ObjectExtraParams);
4324 msg->nextBlockFast(_PREHASH_AgentData);
4325 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
4326 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
4327 msg->nextBlockFast(_PREHASH_ObjectData);
4328 msg->addU32Fast(_PREHASH_ObjectLocalID, mLocalID );
4329
4330 msg->addU16Fast(_PREHASH_ParamType, param_type);
4331 msg->addBOOLFast(_PREHASH_ParamInUse, in_use);
4332
4333 msg->addU32Fast(_PREHASH_ParamSize, datasize);
4334 msg->addBinaryDataFast(_PREHASH_ParamData, tmp, datasize);
4335
4336 msg->sendReliable( regionp->getHost() );
4337 }
4338 else
4339 {
4340 llwarns << "Failed to send object extra parameters: " << param_type << llendl;
4341 }
4342 }
4343}
4344
4345void LLViewerObject::setDrawableState(U32 state, BOOL recursive)
4346{
4347 if (mDrawable)
4348 {
4349 mDrawable->setState(state);
4350 }
4351 if (recursive)
4352 {
4353 for (U32 i = 0; i < mChildList.size(); i++)
4354 {
4355 mChildList[i]->setDrawableState(state, recursive);
4356 }
4357 }
4358}
4359
4360void LLViewerObject::clearDrawableState(U32 state, BOOL recursive)
4361{
4362 if (mDrawable)
4363 {
4364 mDrawable->clearState(state);
4365 }
4366 if (recursive)
4367 {
4368 for (U32 i = 0; i < mChildList.size(); i++)
4369 {
4370 mChildList[i]->clearDrawableState(state, recursive);
4371 }
4372 }
4373}
4374
4375//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
4376// RN: these functions assume a 2-level hierarchy
4377//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
4378
4379// Owned by anyone?
4380BOOL LLViewerObject::permAnyOwner() const
4381{
4382 if (isRootEdit())
4383 {
4384 return ((mFlags & FLAGS_OBJECT_ANY_OWNER) != 0);
4385 }
4386 else
4387 {
4388 return ((LLViewerObject*)getParent())->permAnyOwner();
4389 }
4390}
4391// Owned by this viewer?
4392BOOL LLViewerObject::permYouOwner() const
4393{
4394 if (isRootEdit())
4395 {
4396#ifdef HACKED_GODLIKE_VIEWER
4397 return TRUE;
4398#else
4399# ifdef TOGGLE_HACKED_GODLIKE_VIEWER
4400 if (!gInProductionGrid && (gAgent.getGodLevel() >= GOD_MAINTENANCE))
4401 {
4402 return TRUE;
4403 }
4404# endif
4405 return ((mFlags & FLAGS_OBJECT_YOU_OWNER) != 0);
4406#endif
4407 }
4408 else
4409 {
4410 return ((LLViewerObject*)getParent())->permYouOwner();
4411 }
4412}
4413
4414// Owned by a group?
4415BOOL LLViewerObject::permGroupOwner() const
4416{
4417 if (isRootEdit())
4418 {
4419 return ((mFlags & FLAGS_OBJECT_GROUP_OWNED) != 0);
4420 }
4421 else
4422 {
4423 return ((LLViewerObject*)getParent())->permGroupOwner();
4424 }
4425}
4426
4427// Can the owner edit
4428BOOL LLViewerObject::permOwnerModify() const
4429{
4430 if (isRootEdit())
4431 {
4432#ifdef HACKED_GODLIKE_VIEWER
4433 return TRUE;
4434#else
4435# ifdef TOGGLE_HACKED_GODLIKE_VIEWER
4436 if (!gInProductionGrid && (gAgent.getGodLevel() >= GOD_MAINTENANCE))
4437 {
4438 return TRUE;
4439 }
4440# endif
4441 return ((mFlags & FLAGS_OBJECT_OWNER_MODIFY) != 0);
4442#endif
4443 }
4444 else
4445 {
4446 return ((LLViewerObject*)getParent())->permOwnerModify();
4447 }
4448}
4449
4450// Can edit
4451BOOL LLViewerObject::permModify() const
4452{
4453 if (isRootEdit())
4454 {
4455#ifdef HACKED_GODLIKE_VIEWER
4456 return TRUE;
4457#else
4458# ifdef TOGGLE_HACKED_GODLIKE_VIEWER
4459 if (!gInProductionGrid && (gAgent.getGodLevel() >= GOD_MAINTENANCE))
4460 {
4461 return TRUE;
4462 }
4463# endif
4464 return ((mFlags & FLAGS_OBJECT_MODIFY) != 0);
4465#endif
4466 }
4467 else
4468 {
4469 return ((LLViewerObject*)getParent())->permModify();
4470 }
4471}
4472
4473// Can copy
4474BOOL LLViewerObject::permCopy() const
4475{
4476 if (isRootEdit())
4477 {
4478#ifdef HACKED_GODLIKE_VIEWER
4479 return TRUE;
4480#else
4481# ifdef TOGGLE_HACKED_GODLIKE_VIEWER
4482 if (!gInProductionGrid && (gAgent.getGodLevel() >= GOD_MAINTENANCE))
4483 {
4484 return TRUE;
4485 }
4486# endif
4487 return ((mFlags & FLAGS_OBJECT_COPY) != 0);
4488#endif
4489 }
4490 else
4491 {
4492 return ((LLViewerObject*)getParent())->permCopy();
4493 }
4494}
4495
4496// Can move
4497BOOL LLViewerObject::permMove() const
4498{
4499 if (isRootEdit())
4500 {
4501#ifdef HACKED_GODLIKE_VIEWER
4502 return TRUE;
4503#else
4504# ifdef TOGGLE_HACKED_GODLIKE_VIEWER
4505 if (!gInProductionGrid && (gAgent.getGodLevel() >= GOD_MAINTENANCE))
4506 {
4507 return TRUE;
4508 }
4509# endif
4510 return ((mFlags & FLAGS_OBJECT_MOVE) != 0);
4511#endif
4512 }
4513 else
4514 {
4515 return ((LLViewerObject*)getParent())->permMove();
4516 }
4517}
4518
4519// Can be transferred
4520BOOL LLViewerObject::permTransfer() const
4521{
4522 if (isRootEdit())
4523 {
4524#ifdef HACKED_GODLIKE_VIEWER
4525 return TRUE;
4526#else
4527# ifdef TOGGLE_HACKED_GODLIKE_VIEWER
4528 if (!gInProductionGrid && (gAgent.getGodLevel() >= GOD_MAINTENANCE))
4529 {
4530 return TRUE;
4531 }
4532# endif
4533 return ((mFlags & FLAGS_OBJECT_TRANSFER) != 0);
4534#endif
4535 }
4536 else
4537 {
4538 return ((LLViewerObject*)getParent())->permTransfer();
4539 }
4540}
4541
4542// Can only open objects that you own, or that someone has
4543// given you modify rights to. JC
4544BOOL LLViewerObject::allowOpen() const
4545{
4546 return !flagInventoryEmpty() && (permYouOwner() || permModify());
4547}
4548
4549LLViewerObject::LLInventoryCallbackInfo::~LLInventoryCallbackInfo()
4550{
4551 if (mListener)
4552 {
4553 mListener->clearVOInventoryListener();
4554 }
4555}
4556
4557void LLViewerObject::updateVolume(const LLVolumeParams& volume_params)
4558{
4559 if (setVolume(volume_params, 1)) // *FIX: magic number, ack!
4560 {
4561 // Transmit the update to the simulator
4562 sendShapeUpdate();
4563 markForUpdate(TRUE);
4564 }
4565}
4566
4567void LLViewerObject::markForUpdate(BOOL priority)
4568{
4569 if (mDrawable.notNull())
4570 {
4571 gPipeline.markTextured(mDrawable);
4572 gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, priority);
4573 }
4574}
4575
4576void LLViewerObject::setRegion(LLViewerRegion *regionp)
4577{
4578 llassert(regionp);
4579 mRegionp = regionp;
4580 setChanged(MOVED | SILHOUETTE);
4581 updateDrawable(FALSE);
4582}
4583
4584bool LLViewerObject::specialHoverCursor() const
4585{
4586 return (mFlags & FLAGS_USE_PHYSICS)
4587 || (mFlags & FLAGS_HANDLE_TOUCH)
4588 || (mClickAction != 0);
4589}
4590
4591void LLViewerObject::updateFlags()
4592{
4593 LLViewerRegion* regionp = getRegion();
4594 if(!regionp) return;
4595 gMessageSystem->newMessage("ObjectFlagUpdate");
4596 gMessageSystem->nextBlockFast(_PREHASH_AgentData);
4597 gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
4598 gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
4599 gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, getLocalID() );
4600 gMessageSystem->addBOOLFast(_PREHASH_UsePhysics, usePhysics() );
4601 gMessageSystem->addBOOL("IsTemporary", flagTemporaryOnRez() );
4602 gMessageSystem->addBOOL("IsPhantom", flagPhantom() );
4603 gMessageSystem->addBOOL("CastsShadows", flagCastShadows() );
4604 gMessageSystem->sendReliable( regionp->getHost() );
4605}
4606
4607BOOL LLViewerObject::setFlags(U32 flags, BOOL state)
4608{
4609 BOOL setit = FALSE;
4610 if (state)
4611 {
4612 if ((mFlags & flags) != flags)
4613 {
4614 mFlags |= flags;
4615 setit = TRUE;
4616 }
4617 }
4618 else
4619 {
4620 if ((mFlags & flags) != 0)
4621 {
4622 mFlags &= ~flags;
4623 setit = TRUE;
4624 }
4625 }
4626
4627 // BUG: Sometimes viewer physics and simulator physics get
4628 // out of sync. To fix this, always send update to simulator.
4629// if (setit)
4630 {
4631 updateFlags();
4632 }
4633 return setit;
4634}
4635
4636BOOL LLViewerObject::lineSegmentIntersect(const LLVector3& start, LLVector3& end) const
4637{
4638 return FALSE;
4639}
4640
4641void LLViewerObject::applyAngularVelocity(F32 dt)
4642{
4643 //do target omega here
4644 mRotTime += dt;
4645 LLVector3 ang_vel = getAngularVelocity();
4646 F32 omega = ang_vel.magVecSquared();
4647 F32 angle = 0.0f;
4648 LLQuaternion dQ;
4649 if (omega > 0.00001f)
4650 {
4651 omega = sqrt(omega);
4652 angle = omega * dt;
4653
4654 ang_vel *= 1.f/omega;
4655
4656 dQ.setQuat(angle, ang_vel);
4657
4658 setRotation(getRotation()*dQ);
4659 setChanged(MOVED | SILHOUETTE);
4660 }
4661}
4662
4663void LLViewerObject::resetRot()
4664{
4665 mRotTime = 0.0f;
4666}