summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xetc/message.xml8
-rw-r--r--indra/llcharacter/lljoint.cpp2
-rw-r--r--indra/llcharacter/llmotioncontroller.h3
-rw-r--r--indra/llmath/llvolume.cpp1
-rw-r--r--indra/llmessage/message_prehash.cpp1
-rw-r--r--indra/llmessage/message_prehash.h1
-rw-r--r--indra/llprimitive/llprimitive.cpp66
-rw-r--r--indra/llprimitive/llprimitive.h22
-rw-r--r--indra/newview/CMakeLists.txt2
-rw-r--r--indra/newview/app_settings/logcontrol.xml1
-rw-r--r--indra/newview/app_settings/settings.xml22
-rw-r--r--indra/newview/llappearancemgr.cpp5
-rw-r--r--indra/newview/llappviewer.cpp1
-rw-r--r--indra/newview/llcontrolavatar.cpp366
-rw-r--r--indra/newview/llcontrolavatar.h81
-rw-r--r--indra/newview/lldrawable.cpp9
-rw-r--r--indra/newview/lldrawpoolavatar.cpp1
-rw-r--r--indra/newview/llpanelvolume.cpp49
-rw-r--r--indra/newview/llpanelvolume.h1
-rw-r--r--indra/newview/llselectmgr.cpp70
-rw-r--r--indra/newview/llselectmgr.h4
-rw-r--r--indra/newview/llstartup.cpp1
-rw-r--r--indra/newview/lltoolpie.cpp3
-rw-r--r--indra/newview/llviewercontrol.cpp7
-rw-r--r--indra/newview/llviewermenu.cpp6
-rw-r--r--indra/newview/llviewermessage.cpp71
-rw-r--r--indra/newview/llviewermessage.h1
-rw-r--r--indra/newview/llviewerobject.cpp103
-rw-r--r--indra/newview/llviewerobject.h24
-rw-r--r--indra/newview/llviewerobjectlist.cpp4
-rw-r--r--indra/newview/llviewerobjectlist.h2
-rw-r--r--indra/newview/llviewerregion.cpp1
-rw-r--r--indra/newview/llvoavatar.cpp243
-rw-r--r--indra/newview/llvoavatar.h18
-rw-r--r--indra/newview/llvoavatarself.cpp2
-rw-r--r--indra/newview/llvograss.cpp3
-rw-r--r--indra/newview/llvovolume.cpp294
-rw-r--r--indra/newview/llvovolume.h17
-rw-r--r--indra/newview/pipeline.h9
-rw-r--r--indra/newview/skins/default/xui/en/floater_tools.xml18
-rw-r--r--indra/newview/skins/default/xui/en/menu_viewer.xml10
-rw-r--r--indra/test/test.cpp2
-rwxr-xr-xscripts/messages/message_template.msg26
-rwxr-xr-xscripts/messages/message_template.msg.sha12
-rw-r--r--scripts/testing/lsl/axon_test_region_driver.lsl54
-rw-r--r--scripts/testing/lsl/cycle_object_animations.lsl118
-rw-r--r--scripts/testing/lsl/move_in_circle_using_llSetRegionPos.lsl90
47 files changed, 1687 insertions, 158 deletions
diff --git a/etc/message.xml b/etc/message.xml
index 6d8160abb5..b444fe6c11 100755
--- a/etc/message.xml
+++ b/etc/message.xml
@@ -236,6 +236,14 @@
<boolean>false</boolean>
</map>
+ <key>ObjectAnimation</key>
+ <map>
+ <key>flavor</key>
+ <string>template</string>
+ <key>trusted-sender</key>
+ <boolean>false</boolean>
+ </map>
+
<key>AvatarAppearance</key>
<map>
<key>flavor</key>
diff --git a/indra/llcharacter/lljoint.cpp b/indra/llcharacter/lljoint.cpp
index a3d5679f65..89335a20f5 100644
--- a/indra/llcharacter/lljoint.cpp
+++ b/indra/llcharacter/lljoint.cpp
@@ -881,7 +881,7 @@ void LLJoint::setWorldRotation( const LLQuaternion& rot )
//--------------------------------------------------------------------
const LLVector3& LLJoint::getScale()
{
- return mXform.getScale();
+ return mXform.getScale();
}
//--------------------------------------------------------------------
diff --git a/indra/llcharacter/llmotioncontroller.h b/indra/llcharacter/llmotioncontroller.h
index 72de331694..22357a2c6b 100644
--- a/indra/llcharacter/llmotioncontroller.h
+++ b/indra/llcharacter/llmotioncontroller.h
@@ -150,10 +150,13 @@ public:
BOOL isPaused() const { return mPaused; }
void setTimeStep(F32 step);
+ F32 getTimeStep() const { return mTimeStep; }
void setTimeFactor(F32 time_factor);
F32 getTimeFactor() const { return mTimeFactor; }
+ F32 getAnimTime() const { return mAnimTime; }
+
motion_list_t& getActiveMotions() { return mActiveMotions; }
void incMotionCounts(S32& num_motions, S32& num_loading_motions, S32& num_loaded_motions, S32& num_active_motions, S32& num_deprecated_motions);
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index 7a54d83b3f..8c27ef9961 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -1,5 +1,4 @@
/**
-
* @file llvolume.cpp
*
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
diff --git a/indra/llmessage/message_prehash.cpp b/indra/llmessage/message_prehash.cpp
index 1ae8a6ac15..f8e11e324e 100644
--- a/indra/llmessage/message_prehash.cpp
+++ b/indra/llmessage/message_prehash.cpp
@@ -818,6 +818,7 @@ char const* const _PREHASH_StateSave = LLMessageStringTable::getInstance()->getS
char const* const _PREHASH_RoleData = LLMessageStringTable::getInstance()->getString("RoleData");
char const* const _PREHASH_AgentAnimation = LLMessageStringTable::getInstance()->getString("AgentAnimation");
char const* const _PREHASH_AvatarAnimation = LLMessageStringTable::getInstance()->getString("AvatarAnimation");
+char const* const _PREHASH_ObjectAnimation = LLMessageStringTable::getInstance()->getString("ObjectAnimation");
char const* const _PREHASH_LogDwellTime = LLMessageStringTable::getInstance()->getString("LogDwellTime");
char const* const _PREHASH_ParcelGodMarkAsContent = LLMessageStringTable::getInstance()->getString("ParcelGodMarkAsContent");
char const* const _PREHASH_UsePhysics = LLMessageStringTable::getInstance()->getString("UsePhysics");
diff --git a/indra/llmessage/message_prehash.h b/indra/llmessage/message_prehash.h
index 7910fde305..334236fb25 100644
--- a/indra/llmessage/message_prehash.h
+++ b/indra/llmessage/message_prehash.h
@@ -818,6 +818,7 @@ extern char const* const _PREHASH_StateSave;
extern char const* const _PREHASH_RoleData;
extern char const* const _PREHASH_AgentAnimation;
extern char const* const _PREHASH_AvatarAnimation;
+extern char const* const _PREHASH_ObjectAnimation;
extern char const* const _PREHASH_LogDwellTime;
extern char const* const _PREHASH_ParcelGodMarkAsContent;
extern char const* const _PREHASH_UsePhysics;
diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp
index bfa65666b5..c847cf653f 100644
--- a/indra/llprimitive/llprimitive.cpp
+++ b/indra/llprimitive/llprimitive.cpp
@@ -1599,6 +1599,8 @@ BOOL LLNetworkData::isValid(U16 param_type, U32 size)
return (size == 17);
case PARAMS_LIGHT_IMAGE:
return (size == 28);
+ case PARAMS_EXTENDED_MESH:
+ return (size == 4);
}
return FALSE;
@@ -2026,3 +2028,67 @@ bool LLLightImageParams::fromLLSD(LLSD& sd)
return false;
}
+
+//============================================================================
+
+LLExtendedMeshParams::LLExtendedMeshParams()
+{
+ mType = PARAMS_EXTENDED_MESH;
+ mFlags = 0;
+}
+
+BOOL LLExtendedMeshParams::pack(LLDataPacker &dp) const
+{
+ dp.packU32(mFlags, "flags");
+
+ return TRUE;
+}
+
+BOOL LLExtendedMeshParams::unpack(LLDataPacker &dp)
+{
+ dp.unpackU32(mFlags, "flags");
+
+ return TRUE;
+}
+
+bool LLExtendedMeshParams::operator==(const LLNetworkData& data) const
+{
+ if (data.mType != PARAMS_EXTENDED_MESH)
+ {
+ return false;
+ }
+
+ const LLExtendedMeshParams *param = (const LLExtendedMeshParams*)&data;
+ if ( (param->mFlags != mFlags) )
+ {
+ return false;
+ }
+
+ return true;
+}
+
+void LLExtendedMeshParams::copy(const LLNetworkData& data)
+{
+ const LLExtendedMeshParams *param = (LLExtendedMeshParams*)&data;
+ mFlags = param->mFlags;
+}
+
+LLSD LLExtendedMeshParams::asLLSD() const
+{
+ LLSD sd;
+
+ sd["flags"] = LLSD::Integer(mFlags);
+
+ return sd;
+}
+
+bool LLExtendedMeshParams::fromLLSD(LLSD& sd)
+{
+ if (sd.has("flags"))
+ {
+ setFlags( sd["flags"].asInteger());
+ return true;
+ }
+
+ return false;
+}
diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h
index 19d9d52817..9216c04229 100644
--- a/indra/llprimitive/llprimitive.h
+++ b/indra/llprimitive/llprimitive.h
@@ -106,6 +106,7 @@ public:
PARAMS_LIGHT_IMAGE = 0x40,
PARAMS_RESERVED = 0x50, // Used on server-side
PARAMS_MESH = 0x60,
+ PARAMS_EXTENDED_MESH = 0x70,
};
public:
@@ -288,6 +289,27 @@ public:
};
+class LLExtendedMeshParams : public LLNetworkData
+{
+protected:
+ U32 mFlags;
+
+public:
+ static const U32 ANIMATED_MESH_ENABLED_FLAG = 0x1 << 0;
+
+ LLExtendedMeshParams();
+ /*virtual*/ BOOL pack(LLDataPacker &dp) const;
+ /*virtual*/ BOOL unpack(LLDataPacker &dp);
+ /*virtual*/ bool operator==(const LLNetworkData& data) const;
+ /*virtual*/ void copy(const LLNetworkData& data);
+ LLSD asLLSD() const;
+ operator LLSD() const { return asLLSD(); }
+ bool fromLLSD(LLSD& sd);
+
+ void setFlags(const U32& flags) { mFlags = flags; }
+ U32 getFlags() const { return mFlags; }
+
+};
// This code is not naming-standards compliant. Leaving it like this for
// now to make the connection to code in
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index b4e930d062..3787a25a9b 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -149,6 +149,7 @@ set(viewer_SOURCE_FILES
llcommunicationchannel.cpp
llcompilequeue.cpp
llconfirmationmanager.cpp
+ llcontrolavatar.cpp
llconversationlog.cpp
llconversationloglist.cpp
llconversationloglistitem.cpp
@@ -769,6 +770,7 @@ set(viewer_HEADER_FILES
llcommunicationchannel.h
llcompilequeue.h
llconfirmationmanager.h
+ llcontrolavatar.h
llconversationlog.h
llconversationloglist.h
llconversationloglistitem.h
diff --git a/indra/newview/app_settings/logcontrol.xml b/indra/newview/app_settings/logcontrol.xml
index ecd7c4bc36..ddd07dba80 100644
--- a/indra/newview/app_settings/logcontrol.xml
+++ b/indra/newview/app_settings/logcontrol.xml
@@ -50,6 +50,7 @@
</array>
<key>tags</key>
<array>
+ <string>AXON</string>
<!-- sample entry for debugging specific items
<string>Avatar</string>
<string>Inventory</string>
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index c544205df0..3e06e7094d 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -2171,6 +2171,17 @@
<key>Value</key>
<string />
</map>
+ <key>DebugAnimatedObjects</key>
+ <map>
+ <key>Comment</key>
+ <string>Show info related to animated objects</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
<key>DebugAvatarAppearanceMessage</key>
<map>
<key>Comment</key>
@@ -10382,6 +10393,17 @@
<key>Value</key>
<integer>0</integer>
</map>
+ <key>RenderForceVolumeLOD</key>
+ <map>
+ <key>Comment</key>
+ <string>Override for all volume LODs</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>-1</integer>
+ </map>
<key>RenderVolumeLODFactor</key>
<map>
<key>Comment</key>
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index c928cf0601..d58d03d68d 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -880,7 +880,10 @@ void LLWearableHoldingPattern::onAllComplete()
++it)
{
LLViewerObject *objectp = *it;
- gAgentAvatarp->addAttachmentOverridesForObject(objectp);
+ if (!objectp->isAnimatedObject())
+ {
+ gAgentAvatarp->addAttachmentOverridesForObject(objectp);
+ }
}
// Add new attachments to match those requested.
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 37340a42b6..4ab19b714f 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -594,6 +594,7 @@ static void settings_to_globals()
LLVertexBuffer::sUseVAO = gSavedSettings.getBOOL("RenderUseVAO");
LLImageGL::sGlobalUseAnisotropic = gSavedSettings.getBOOL("RenderAnisotropic");
LLImageGL::sCompressTextures = gSavedSettings.getBOOL("RenderCompressTextures");
+ LLVOVolume::sForceLOD = gSavedSettings.getS32("RenderForceVolumeLOD");
LLVOVolume::sLODFactor = gSavedSettings.getF32("RenderVolumeLODFactor");
LLVOVolume::sDistanceFactor = 1.f-LLVOVolume::sLODFactor * 0.1f;
LLVolumeImplFlexible::sUpdateFactor = gSavedSettings.getF32("RenderFlexTimeFactor");
diff --git a/indra/newview/llcontrolavatar.cpp b/indra/newview/llcontrolavatar.cpp
new file mode 100644
index 0000000000..d458e2951b
--- /dev/null
+++ b/indra/newview/llcontrolavatar.cpp
@@ -0,0 +1,366 @@
+/**
+ * @file llcontrolavatar.cpp
+ * @brief Implementation for special dummy avatar used to drive rigged meshes.
+ *
+ * $LicenseInfo:firstyear=2017&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2017, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llcontrolavatar.h"
+#include "llagent.h" // Get state values from here
+#include "llviewerobjectlist.h"
+#include "pipeline.h"
+#include "llanimationstates.h"
+#include "llviewercontrol.h"
+#include "llmeshrepository.h"
+
+LLControlAvatar::LLControlAvatar(const LLUUID& id, const LLPCode pcode, LLViewerRegion* regionp) :
+ LLVOAvatar(id, pcode, regionp),
+ mPlaying(false),
+ mGlobalScale(1.0f),
+ mMarkedForDeath(false)
+{
+ mIsControlAvatar = true;
+ mEnableDefaultMotions = false;
+}
+
+// virtual
+LLControlAvatar::~LLControlAvatar()
+{
+}
+
+void LLControlAvatar::matchVolumeTransform()
+{
+ {
+ LLVolume *volume = mRootVolp->getVolume();
+ if (volume)
+ {
+ LLUUID mesh_id = volume->getParams().getSculptID();
+ const LLMeshSkinInfo* skin = gMeshRepo.getSkinInfo(mesh_id, mRootVolp);
+ if (skin)
+ {
+ LLMatrix4 bind_shape = skin->mBindShapeMatrix;
+ LL_INFOS("AXON") << "bind_shape is " << bind_shape << LL_ENDL;
+ }
+ }
+ }
+
+ setPositionAgent(mRootVolp->getRenderPosition());
+ //slamPosition();
+
+ LLQuaternion fix_axes_rot(-F_PI_BY_TWO, LLVector3(0,0,1));
+ LLQuaternion obj_rot = mRootVolp->getRotation();
+ LLQuaternion result_rot = fix_axes_rot * obj_rot;
+ setRotation(result_rot);
+ mRoot->setWorldRotation(result_rot);
+ mRoot->setPosition(mRootVolp->getRenderPosition());
+}
+
+void LLControlAvatar::setGlobalScale(F32 scale)
+{
+ if (scale <= 0.0)
+ {
+ LL_WARNS() << "invalid global scale " << scale << LL_ENDL;
+ return;
+ }
+ if (scale != mGlobalScale)
+ {
+ F32 adjust_scale = scale/mGlobalScale;
+ LL_INFOS() << "scale " << scale << " adjustment " << adjust_scale << LL_ENDL;
+ // AXON - should we be scaling from the pelvis or the root?
+ recursiveScaleJoint(mPelvisp,adjust_scale);
+ mGlobalScale = scale;
+ }
+}
+
+void LLControlAvatar::recursiveScaleJoint(LLJoint* joint, F32 factor)
+{
+ joint->setScale(factor * joint->getScale());
+
+ for (LLJoint::child_list_t::iterator iter = joint->mChildren.begin();
+ iter != joint->mChildren.end(); ++iter)
+ {
+ LLJoint* child = *iter;
+ recursiveScaleJoint(child, factor);
+ }
+}
+
+// Based on LLViewerJointAttachment::setupDrawable(), without the attaching part.
+void LLControlAvatar::updateVolumeGeom()
+{
+ if (!mRootVolp->mDrawable)
+ return;
+ if (mRootVolp->mDrawable->isActive())
+ {
+ mRootVolp->mDrawable->makeStatic(FALSE);
+ }
+ mRootVolp->mDrawable->makeActive();
+ gPipeline.markMoved(mRootVolp->mDrawable);
+ gPipeline.markTextured(mRootVolp->mDrawable); // face may need to change draw pool to/from POOL_HUD
+ mRootVolp->mDrawable->setState(LLDrawable::USE_BACKLIGHT);
+
+ LLViewerObject::const_child_list_t& child_list = mRootVolp->getChildren();
+ for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
+ iter != child_list.end(); ++iter)
+ {
+ LLViewerObject* childp = *iter;
+ if (childp && childp->mDrawable.notNull())
+ {
+ childp->mDrawable->setState(LLDrawable::USE_BACKLIGHT);
+ gPipeline.markTextured(childp->mDrawable); // face may need to change draw pool to/from POOL_HUD
+ gPipeline.markMoved(childp->mDrawable);
+ }
+ }
+
+ gPipeline.markRebuild(mRootVolp->mDrawable, LLDrawable::REBUILD_ALL, TRUE);
+ mRootVolp->markForUpdate(TRUE);
+
+ // Note that attachment overrides aren't needed here, have already
+ // been applied at the time the mControlAvatar was created, in
+ // llvovolume.cpp.
+
+ matchVolumeTransform();
+
+ // AXON testing scale
+
+ // What should the scale be? What we really want is the ratio
+ // between the scale at which the object was originally designed
+ // and rigged, and the scale to which it has been subsequently
+ // modified - for example, if the object has been scaled down by a
+ // factor of 2 then we should use 0.5 as the global scale. But we
+ // don't have the original scale stored anywhere, just the current
+ // scale. Possibilities - 1) remember the original scale
+ // somewhere, 2) add another field to let the user specify the
+ // global scale, 3) approximate the original scale by looking at
+ // the proportions of the skeleton after joint positions have
+ // been applied
+
+ //LLVector3 obj_scale = obj->getScale();
+ //F32 obj_scale_z = llmax(obj_scale[2],0.1f);
+ //setGlobalScale(obj_scale_z/2.0f); // roughly fit avatar height range (2m) into object height
+}
+
+LLControlAvatar *LLControlAvatar::createControlAvatar(LLVOVolume *obj)
+{
+ // AXON Lifted from LLPreviewAnimation
+ LLControlAvatar *cav = (LLControlAvatar*)gObjectList.createObjectViewer(LL_PCODE_LEGACY_AVATAR, gAgent.getRegion(), CO_FLAG_CONTROL_AVATAR);
+
+ cav->mRootVolp = obj;
+
+ cav->createDrawable(&gPipeline);
+ cav->mIsDummy = TRUE;
+ cav->mSpecialRenderMode = 1;
+ cav->updateJointLODs();
+ cav->updateGeometry(cav->mDrawable);
+ cav->hideSkirt();
+
+ // Sync up position/rotation with object
+ cav->matchVolumeTransform();
+
+ return cav;
+}
+
+void LLControlAvatar::markForDeath()
+{
+ mMarkedForDeath = true;
+}
+
+// static
+void LLControlAvatar::idleUpdate(LLAgent &agent, const F64 &time)
+{
+ if (mMarkedForDeath)
+ {
+ markDead();
+ mMarkedForDeath = false;
+ }
+ else
+ {
+ LLVOAvatar::idleUpdate(agent,time);
+ }
+}
+
+//virtual
+void LLControlAvatar::updateDebugText()
+{
+ if (gSavedSettings.getBOOL("DebugAnimatedObjects"))
+ {
+ S32 total_linkset_count = 0;
+ if (mRootVolp)
+ {
+ total_linkset_count = 1 + mRootVolp->getChildren().size();
+ }
+ std::vector<LLVOVolume*> volumes;
+ getAnimatedVolumes(volumes);
+ S32 animated_volume_count = volumes.size();
+ std::string active_string;
+ std::string lod_string;
+ S32 total_tris = 0;
+ S32 total_verts = 0;
+ for (std::vector<LLVOVolume*>::iterator it = volumes.begin();
+ it != volumes.end(); ++it)
+ {
+ LLVOVolume *volp = *it;
+ S32 verts = 0;
+ total_tris += volp->getTriangleCount(&verts);
+ total_verts += verts;
+ lod_string += llformat("%d",volp->getLOD());
+ if (volp && volp->mDrawable)
+ {
+ if (volp->mDrawable->isActive())
+ {
+ active_string += "A";
+ }
+ else
+ {
+ active_string += "S";
+ }
+ }
+ else
+ {
+ active_string += "-";
+ }
+ }
+ addDebugText(llformat("CAV obj %d anim %d active %s",
+ total_linkset_count, animated_volume_count, active_string.c_str()));
+
+#if 0
+ // AXON - detailed rigged mesh info
+ for (std::vector<LLVOVolume*>::iterator it = volumes.begin();
+ it != volumes.end(); ++it)
+ {
+ LLRiggedVolume *rig_vol = (*it)->getRiggedVolume();
+ if (rig_vol)
+ {
+ addDebugText(rig_vol->mExtraDebugText);
+ }
+ }
+#endif
+
+ addDebugText(llformat("lod %s",lod_string.c_str()));
+ addDebugText(llformat("tris %d verts %d", total_tris, total_verts));
+ //addDebugText(llformat("anim time %.1f (step %f factor %f)",
+ // mMotionController.getAnimTime(),
+ // mMotionController.getTimeStep(),
+ // mMotionController.getTimeFactor()));
+
+ }
+
+ LLVOAvatar::updateDebugText();
+}
+
+void LLControlAvatar::getAnimatedVolumes(std::vector<LLVOVolume*>& volumes)
+{
+ if (!mRootVolp)
+ {
+ return;
+ }
+
+ volumes.push_back(mRootVolp);
+
+ LLViewerObject::const_child_list_t& child_list = mRootVolp->getChildren();
+ for (LLViewerObject::const_child_list_t::const_iterator iter = child_list.begin();
+ iter != child_list.end(); ++iter)
+ {
+ LLViewerObject* childp = *iter;
+ LLVOVolume *child_volp = dynamic_cast<LLVOVolume*>(childp);
+ if (child_volp && child_volp->isAnimatedObject())
+ {
+ volumes.push_back(child_volp);
+ }
+ }
+}
+
+// This is called after an associated object receives an animation
+// message. Combine the signaled animations for all associated objects
+// and process any resulting state changes.
+void LLControlAvatar::updateAnimations()
+{
+ if (!mRootVolp)
+ {
+ LL_WARNS("AXON") << "No root vol" << LL_ENDL;
+ return;
+ }
+
+ std::vector<LLVOVolume*> volumes;
+ getAnimatedVolumes(volumes);
+
+ // Rebuild mSignaledAnimations from the associated volumes.
+ std::map<LLUUID, S32> anims;
+ for (std::vector<LLVOVolume*>::iterator vol_it = volumes.begin(); vol_it != volumes.end(); ++vol_it)
+ {
+ LLVOVolume *volp = *vol_it;
+ for (std::map<LLUUID,S32>::iterator anim_it = volp->mObjectSignaledAnimations.begin();
+ anim_it != volp->mObjectSignaledAnimations.end();
+ ++anim_it)
+ {
+ std::map<LLUUID,S32>::iterator found_anim_it = anims.find(anim_it->first);
+ if (found_anim_it != anims.end())
+ {
+ // Animation already present, use the larger sequence id
+ anims[anim_it->first] = llmax(found_anim_it->second, anim_it->second);
+ }
+ else
+ {
+ // Animation not already present, use this sequence id.
+ anims[anim_it->first] = anim_it->second;
+ }
+ }
+ }
+ mSignaledAnimations = anims;
+
+ LL_DEBUGS("AXON") << "process animation state changes here" << LL_ENDL;
+ processAnimationStateChanges();
+}
+
+// virtual
+LLViewerObject* LLControlAvatar::lineSegmentIntersectRiggedAttachments(const LLVector4a& start, const LLVector4a& end,
+ S32 face,
+ BOOL pick_transparent,
+ BOOL pick_rigged,
+ S32* face_hit,
+ LLVector4a* intersection,
+ LLVector2* tex_coord,
+ LLVector4a* normal,
+ LLVector4a* tangent)
+{
+ LLViewerObject* hit = NULL;
+
+ if (lineSegmentBoundingBox(start, end))
+ {
+ LLVector4a local_end = end;
+ LLVector4a local_intersection;
+
+ if (mRootVolp &&
+ mRootVolp->lineSegmentIntersect(start, local_end, face, pick_transparent, pick_rigged, face_hit, &local_intersection, tex_coord, normal, tangent))
+ {
+ local_end = local_intersection;
+ if (intersection)
+ {
+ *intersection = local_intersection;
+ }
+
+ hit = mRootVolp;
+ }
+ }
+
+ return hit;
+}
diff --git a/indra/newview/llcontrolavatar.h b/indra/newview/llcontrolavatar.h
new file mode 100644
index 0000000000..a6b77b73ba
--- /dev/null
+++ b/indra/newview/llcontrolavatar.h
@@ -0,0 +1,81 @@
+/**
+ * @file llcontrolavatar.h
+ * @brief Special dummy avatar used to drive rigged meshes.
+ *
+ * $LicenseInfo:firstyear=2017&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2017, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_CONTROLAVATAR_H
+#define LL_CONTROLAVATAR_H
+
+#include "llvoavatar.h"
+#include "llvovolume.h"
+
+class LLControlAvatar:
+ public LLVOAvatar
+{
+ LOG_CLASS(LLControlAvatar);
+
+public:
+ LLControlAvatar(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp);
+ virtual ~LLControlAvatar();
+
+ void matchVolumeTransform();
+ void updateVolumeGeom();
+
+ void setGlobalScale(F32 scale);
+ void recursiveScaleJoint(LLJoint *joint, F32 factor);
+ static LLControlAvatar *createControlAvatar(LLVOVolume *obj);
+
+ // Delayed kill so we don't make graphics pipeline unhappy calling
+ // markDead() inside other graphics pipeline operations.
+ void markForDeath();
+
+ virtual void idleUpdate(LLAgent &agent, const F64 &time);
+
+ void getAnimatedVolumes(std::vector<LLVOVolume*>& volumes);
+ void updateAnimations();
+
+ virtual LLViewerObject* lineSegmentIntersectRiggedAttachments(
+ const LLVector4a& start, const LLVector4a& end,
+ S32 face = -1, // which face to check, -1 = ALL_SIDES
+ BOOL pick_transparent = FALSE,
+ BOOL pick_rigged = FALSE,
+ S32* face_hit = NULL, // which face was hit
+ LLVector4a* intersection = NULL, // return the intersection point
+ LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point
+ LLVector4a* normal = NULL, // return the surface normal at the intersection point
+ LLVector4a* tangent = NULL); // return the surface tangent at the intersection point
+
+ virtual void updateDebugText();
+
+ bool mPlaying;
+
+ F32 mGlobalScale;
+
+ LLVOVolume *mRootVolp;
+
+ bool mMarkedForDeath;
+
+};
+
+#endif //LL_CONTROLAVATAR_H
diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index f956023358..8001486b53 100644
--- a/indra/newview/lldrawable.cpp
+++ b/indra/newview/lldrawable.cpp
@@ -50,6 +50,7 @@
#include "llviewerobjectlist.h"
#include "llviewerwindow.h"
#include "llvocache.h"
+#include "llcontrolavatar.h"
const F32 MIN_INTERPOLATE_DISTANCE_SQUARED = 0.001f * 0.001f;
const F32 MAX_INTERPOLATE_DISTANCE_SQUARED = 10.f * 10.f;
@@ -550,7 +551,8 @@ void LLDrawable::makeStatic(BOOL warning_enabled)
if (isState(ACTIVE) &&
!isState(ACTIVE_CHILD) &&
!mVObjp->isAttachment() &&
- !mVObjp->isFlexible())
+ !mVObjp->isFlexible() &&
+ !mVObjp->isAnimatedObject())
{
clearState(ACTIVE | ANIMATED_CHILD);
@@ -696,6 +698,11 @@ F32 LLDrawable::updateXform(BOOL undamped)
mXform.setScale(LLVector3(1,1,1)); //no scale in drawable transforms (IT'S A RULE!)
mXform.updateMatrix();
+ if (mVObjp && mVObjp->isRootEdit() && mVObjp->getControlAvatar())
+ {
+ mVObjp->getControlAvatar()->matchVolumeTransform();
+ }
+
if (mSpatialBridge)
{
gPipeline.markMoved(mSpatialBridge, FALSE);
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index b221221f16..869e37e08c 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -467,6 +467,7 @@ void LLDrawPoolAvatar::renderShadow(S32 pass)
}
LLVOAvatar *avatarp = (LLVOAvatar *)facep->getDrawable()->getVObj().get();
+// AXON fix
if (avatarp->isDead() || avatarp->mIsDummy || avatarp->mDrawable.isNull())
{
return;
diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp
index c9f8683e0e..c5fbc1f71b 100644
--- a/indra/newview/llpanelvolume.cpp
+++ b/indra/newview/llpanelvolume.cpp
@@ -86,6 +86,7 @@ BOOL LLPanelVolume::postBuild()
{
// Flexible Objects Parameters
{
+ childSetCommitCallback("Animated Mesh Checkbox Ctrl", boost::bind(&LLPanelVolume::onCommitAnimatedMeshCheckbox, this, _1, _2), NULL);
childSetCommitCallback("Flexible1D Checkbox Ctrl", boost::bind(&LLPanelVolume::onCommitIsFlexible, this, _1, _2), NULL);
childSetCommitCallback("FlexNumSections",onCommitFlexible,this);
getChild<LLUICtrl>("FlexNumSections")->setValidateBeforeCommit(precommitValidate);
@@ -237,6 +238,11 @@ void LLPanelVolume::getState( )
{
volobjp = (LLVOVolume *)objectp;
}
+ LLVOVolume *root_volobjp = NULL;
+ if (root_objectp && (root_objectp->getPCode() == LL_PCODE_VOLUME))
+ {
+ root_volobjp = (LLVOVolume *)root_objectp;
+ }
if( !objectp )
{
@@ -260,6 +266,8 @@ void LLPanelVolume::getState( )
BOOL editable = root_objectp->permModify() && !root_objectp->isPermanentEnforced();
BOOL single_volume = LLSelectMgr::getInstance()->selectionAllPCode( LL_PCODE_VOLUME )
&& LLSelectMgr::getInstance()->getSelection()->getObjectCount() == 1;
+ BOOL single_root_volume = LLSelectMgr::getInstance()->selectionAllPCode( LL_PCODE_VOLUME ) &&
+ LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() == 1;
// Select Single Message
if (single_volume)
@@ -347,7 +355,20 @@ void LLPanelVolume::getState( )
getChildView("Light Focus")->setEnabled(false);
getChildView("Light Ambiance")->setEnabled(false);
}
-
+
+ // Animated Mesh
+ BOOL is_animated_mesh = single_root_volume && root_volobjp && root_volobjp->isAnimatedObject();
+ getChild<LLUICtrl>("Animated Mesh Checkbox Ctrl")->setValue(is_animated_mesh);
+ // AXON FIXME CHECK FOR SKIN INFO ALSO
+ // WHAT ABOUT isPermanentEnforced?
+ // What about linksets with some skinned objects?
+ BOOL enabled_animated_object_box = FALSE;
+ if (root_volobjp && root_volobjp == volobjp)
+ {
+ enabled_animated_object_box = single_root_volume && root_volobjp && root_volobjp->canBeAnimatedObject() && editable;
+ }
+ getChildView("Animated Mesh Checkbox Ctrl")->setEnabled(enabled_animated_object_box);
+
// Flexible properties
BOOL is_flexible = volobjp && volobjp->isFlexible();
getChild<LLUICtrl>("Flexible1D Checkbox Ctrl")->setValue(is_flexible);
@@ -587,6 +608,7 @@ void LLPanelVolume::clearCtrls()
getChildView("Light Radius")->setEnabled(false);
getChildView("Light Falloff")->setEnabled(false);
+ getChildView("Animated Mesh Checkbox Ctrl")->setEnabled(false);
getChildView("Flexible1D Checkbox Ctrl")->setEnabled(false);
getChildView("FlexNumSections")->setEnabled(false);
getChildView("FlexGravity")->setEnabled(false);
@@ -899,6 +921,31 @@ void LLPanelVolume::onCommitFlexible( LLUICtrl* ctrl, void* userdata )
self->refresh();
}
+void LLPanelVolume::onCommitAnimatedMeshCheckbox(LLUICtrl *, void*)
+{
+ LLViewerObject* objectp = mObject;
+ if (!objectp || (objectp->getPCode() != LL_PCODE_VOLUME))
+ {
+ return;
+ }
+ LLVOVolume *volobjp = (LLVOVolume *)objectp;
+ BOOL animated_mesh = getChild<LLUICtrl>("Animated Mesh Checkbox Ctrl")->getValue();
+ U32 flags = volobjp->getExtendedMeshFlags();
+ U32 new_flags = flags;
+ if (animated_mesh)
+ {
+ new_flags |= LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG;
+ }
+ else
+ {
+ new_flags &= ~LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG;
+ }
+ if (new_flags != flags)
+ {
+ volobjp->setExtendedMeshFlags(new_flags);
+ }
+}
+
void LLPanelVolume::onCommitIsFlexible(LLUICtrl *, void*)
{
if (mObject->flagObjectPermanent())
diff --git a/indra/newview/llpanelvolume.h b/indra/newview/llpanelvolume.h
index deb6b6f2a6..d85df69b19 100644
--- a/indra/newview/llpanelvolume.h
+++ b/indra/newview/llpanelvolume.h
@@ -63,6 +63,7 @@ public:
static void onCommitLight( LLUICtrl* ctrl, void* userdata);
void onCommitIsFlexible( LLUICtrl* ctrl, void* userdata);
static void onCommitFlexible( LLUICtrl* ctrl, void* userdata);
+ void onCommitAnimatedMeshCheckbox(LLUICtrl* ctrl, void* userdata);
static void onCommitPhysicsParam( LLUICtrl* ctrl, void* userdata);
static void onCommitMaterial( LLUICtrl* ctrl, void* userdata);
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index 983a7ca1ae..3e8d8883e0 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -46,6 +46,7 @@
#include "llundo.h"
#include "lluuid.h"
#include "llvolume.h"
+#include "llcontrolavatar.h"
#include "message.h"
#include "object_flags.h"
#include "llquaternion.h"
@@ -6628,7 +6629,10 @@ S32 get_family_count(LLViewerObject *parent)
//-----------------------------------------------------------------------------
// updateSelectionCenter
-//-----------------------------------------------------------------------------
+//
+// FIXME this is a grab bag of functionality only some of which has to do
+// with the selection center
+// -----------------------------------------------------------------------------
void LLSelectMgr::updateSelectionCenter()
{
const F32 MOVE_SELECTION_THRESHOLD = 1.f; // Movement threshold in meters for updating selection
@@ -6646,23 +6650,12 @@ void LLSelectMgr::updateSelectionCenter()
mSelectionCenterGlobal.clearVec();
mShowSelection = FALSE;
mSelectionBBox = LLBBox();
- mPauseRequest = NULL;
resetAgentHUDZoom();
-
}
else
{
mSelectedObjects->mSelectType = getSelectTypeForObject(object);
- if (mSelectedObjects->mSelectType == SELECT_TYPE_ATTACHMENT && isAgentAvatarValid() && object->getParent() != NULL)
- {
- mPauseRequest = gAgentAvatarp->requestPause();
- }
- else
- {
- mPauseRequest = NULL;
- }
-
if (mSelectedObjects->mSelectType != SELECT_TYPE_HUD && isAgentAvatarValid())
{
// reset hud ZOOM
@@ -6739,6 +6732,59 @@ void LLSelectMgr::updateSelectionCenter()
{
gEditMenuHandler = NULL;
}
+
+ pauseAssociatedAvatars();
+}
+
+//-----------------------------------------------------------------------------
+// pauseAssociatedAvatars
+//
+// If the selection includes an attachment or an animated object, the
+// associated avatars should pause their animations until they are no
+// longer selected.
+//-----------------------------------------------------------------------------
+void LLSelectMgr::pauseAssociatedAvatars()
+{
+ mPauseRequests.clear();
+
+ for (LLObjectSelection::iterator iter = mSelectedObjects->begin();
+ iter != mSelectedObjects->end(); iter++)
+ {
+ LLSelectNode* node = *iter;
+ LLViewerObject* object = node->getObject();
+ if (!object)
+ continue;
+
+ mSelectedObjects->mSelectType = getSelectTypeForObject(object);
+
+ if (mSelectedObjects->mSelectType == SELECT_TYPE_ATTACHMENT &&
+ isAgentAvatarValid() && object->getParent() != NULL)
+ {
+ if (object->isAnimatedObject())
+ {
+ // Is an animated object attachment.
+ // Pause both the control avatar and the avatar it's attached to.
+ if (object->getControlAvatar())
+ {
+ mPauseRequests.push_back(object->getControlAvatar()->requestPause());
+ }
+ mPauseRequests.push_back(gAgentAvatarp->requestPause());
+ }
+ else
+ {
+ // Is a regular attachment. Pause the avatar it's attached to.
+ mPauseRequests.push_back(gAgentAvatarp->requestPause());
+ }
+ }
+ else
+ {
+ if (object && object->isAnimatedObject() && object->getControlAvatar())
+ {
+ // Is a non-attached animated object. Pause the control avatar.
+ mPauseRequests.push_back(object->getControlAvatar()->requestPause());
+ }
+ }
+ }
}
void LLSelectMgr::updatePointAt()
diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h
index 7ef0032645..fc4b920c51 100644
--- a/indra/newview/llselectmgr.h
+++ b/indra/newview/llselectmgr.h
@@ -742,6 +742,8 @@ public:
LLVector3d getSelectionCenterGlobal() const { return mSelectionCenterGlobal; }
void updateSelectionCenter();
+ void pauseAssociatedAvatars();
+
void resetAgentHUDZoom();
void setAgentHUDZoom(F32 target_zoom, F32 current_zoom);
void getAgentHUDZoom(F32 &target_zoom, F32 &current_zoom) const;
@@ -843,7 +845,7 @@ private:
LLFrameTimer mEffectsTimer;
BOOL mForceSelection;
- LLAnimPauseRequest mPauseRequest;
+ std::vector<LLAnimPauseRequest> mPauseRequests;
};
// *DEPRECATED: For callbacks or observers, use
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 1a480b1838..dc184e2538 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -2386,6 +2386,7 @@ void register_viewer_callbacks(LLMessageSystem* msg)
msg->setHandlerFuncFast(_PREHASH_NameValuePair, process_name_value);
msg->setHandlerFuncFast(_PREHASH_RemoveNameValuePair, process_remove_name_value);
msg->setHandlerFuncFast(_PREHASH_AvatarAnimation, process_avatar_animation);
+ msg->setHandlerFuncFast(_PREHASH_ObjectAnimation, process_object_animation);
msg->setHandlerFuncFast(_PREHASH_AvatarAppearance, process_avatar_appearance);
msg->setHandlerFuncFast(_PREHASH_CameraConstraint, process_camera_constraint);
msg->setHandlerFuncFast(_PREHASH_AvatarSitResponse, process_avatar_sit_response);
diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp
index fc052ae3aa..a06aeb5631 100644
--- a/indra/newview/lltoolpie.cpp
+++ b/indra/newview/lltoolpie.cpp
@@ -1750,8 +1750,7 @@ BOOL LLToolPie::handleRightClickPick()
gMenuHolder->setObjectSelection(LLSelectMgr::getInstance()->getSelection());
bool is_other_attachment = (object->isAttachment() && !object->isHUDAttachment() && !object->permYouOwner());
- if (object->isAvatar()
- || is_other_attachment)
+ if (object->isAvatar() || is_other_attachment)
{
// Find the attachment's avatar
while( object && object->isAttachment())
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index 7c1921b143..66f5bf3c37 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -208,6 +208,12 @@ static bool handleAnisotropicChanged(const LLSD& newvalue)
return true;
}
+static bool handleForceLODChanged(const LLSD& newvalue)
+{
+ LLVOVolume::sForceLOD = (F32) newvalue.asReal();
+ return true;
+}
+
static bool handleVolumeLODChanged(const LLSD& newvalue)
{
LLVOVolume::sLODFactor = (F32) newvalue.asReal();
@@ -626,6 +632,7 @@ void settings_setup_listeners()
gSavedSettings.getControl("RenderAvatarCloth")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
gSavedSettings.getControl("WindLightUseAtmosShaders")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
gSavedSettings.getControl("RenderGammaFull")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
+ gSavedSettings.getControl("RenderForceVolumeLOD")->getSignal()->connect(boost::bind(&handleForceLODChanged, _2));
gSavedSettings.getControl("RenderVolumeLODFactor")->getSignal()->connect(boost::bind(&handleVolumeLODChanged, _2));
gSavedSettings.getControl("RenderAvatarLODFactor")->getSignal()->connect(boost::bind(&handleAvatarLODChanged, _2));
gSavedSettings.getControl("RenderAvatarPhysicsLODFactor")->getSignal()->connect(boost::bind(&handleAvatarPhysicsLODChanged, _2));
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index c68f6b8a15..f01c67e499 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -1076,6 +1076,10 @@ U32 info_display_from_string(std::string info_display)
{
return LLPipeline::RENDER_DEBUG_TEXEL_DENSITY;
}
+ else if ("triangle count" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_TRIANGLE_COUNT;
+ }
else
{
LL_WARNS() << "unrecognized feature name '" << info_display << "'" << LL_ENDL;
@@ -6907,7 +6911,7 @@ class LLAttachmentEnableDrop : public view_listener_t
// Do not enable drop if all faces of object are not enabled
if (object && LLSelectMgr::getInstance()->getSelection()->contains(object,SELECT_ALL_TES ))
{
- S32 attachmentID = ATTACHMENT_ID_FROM_STATE(object->getState());
+ S32 attachmentID = ATTACHMENT_ID_FROM_STATE(object->getAttachmentState());
attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, attachmentID, (LLViewerJointAttachment*)NULL);
if (attachment)
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 06f868dc08..14846d898f 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -55,6 +55,7 @@
#include "llagentcamera.h"
#include "llcallingcard.h"
#include "llbuycurrencyhtml.h"
+#include "llcontrolavatar.h"
#include "llfirstuse.h"
#include "llfloaterbump.h"
#include "llfloaterbuyland.h"
@@ -103,6 +104,7 @@
#include "llviewerwindow.h"
#include "llvlmanager.h"
#include "llvoavatarself.h"
+#include "llvovolume.h"
#include "llworld.h"
#include "pipeline.h"
#include "llfloaterworldmap.h"
@@ -4982,12 +4984,15 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data)
LLUUID animation_id;
LLUUID uuid;
S32 anim_sequence_id;
- LLVOAvatar *avatarp;
+ LLVOAvatar *avatarp = NULL;
mesgsys->getUUIDFast(_PREHASH_Sender, _PREHASH_ID, uuid);
- //clear animation flags
- avatarp = (LLVOAvatar *)gObjectList.findObject(uuid);
+ LLViewerObject *objp = gObjectList.findObject(uuid);
+ if (objp)
+ {
+ avatarp = objp->asAvatar();
+ }
if (!avatarp)
{
@@ -4999,6 +5004,7 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data)
S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationList);
S32 num_source_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationSourceList);
+ //clear animation flags
avatarp->mSignaledAnimations.clear();
if (avatarp->isSelf())
@@ -5069,6 +5075,65 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data)
}
}
+void process_object_animation(LLMessageSystem *mesgsys, void **user_data)
+{
+ LLUUID animation_id;
+ LLUUID uuid;
+ S32 anim_sequence_id;
+
+ mesgsys->getUUIDFast(_PREHASH_Sender, _PREHASH_ID, uuid);
+
+ LLViewerObject *objp = gObjectList.findObject(uuid);
+ if (!objp)
+ {
+ LL_WARNS("Messaging") << "AXON Received animation state for unknown object" << uuid << LL_ENDL;
+ return;
+ }
+
+ LLVOVolume *volp = dynamic_cast<LLVOVolume*>(objp);
+ if (!volp)
+ {
+ LL_WARNS("Messaging") << "AXON Received animation state for non-volume object" << uuid << LL_ENDL;
+ return;
+ }
+
+ if (!volp->isAnimatedObject())
+ {
+ LL_WARNS("Messaging") << "AXON Received animation state for non-animated object" << uuid << LL_ENDL;
+ return;
+ }
+
+ LLControlAvatar *avatarp = volp->getControlAvatar();
+ if (!avatarp)
+ {
+ LL_WARNS() << "AXON no control avatar, ignoring" << LL_ENDL;
+ return;
+ }
+
+ S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationList);
+ LL_DEBUGS("AXON") << "handle object animation here, num_blocks " << num_blocks << LL_ENDL;
+
+ if (!avatarp->mPlaying)
+ {
+ avatarp->mPlaying = true;
+ avatarp->updateVolumeGeom();
+ }
+
+ volp->mObjectSignaledAnimations.clear();
+
+ for( S32 i = 0; i < num_blocks; i++ )
+ {
+ mesgsys->getUUIDFast(_PREHASH_AnimationList, _PREHASH_AnimID, animation_id, i);
+ mesgsys->getS32Fast(_PREHASH_AnimationList, _PREHASH_AnimSequenceID, anim_sequence_id, i);
+ volp->mObjectSignaledAnimations[animation_id] = anim_sequence_id;
+ LL_DEBUGS("AXON") << "got object animation request for object "
+ << uuid << " animation id " << animation_id << LL_ENDL;
+ }
+
+ avatarp->updateAnimations();
+}
+
+
void process_avatar_appearance(LLMessageSystem *mesgsys, void **user_data)
{
LLUUID uuid;
diff --git a/indra/newview/llviewermessage.h b/indra/newview/llviewermessage.h
index b0eaa37541..cef6f79812 100644
--- a/indra/newview/llviewermessage.h
+++ b/indra/newview/llviewermessage.h
@@ -95,6 +95,7 @@ void process_health_message(LLMessageSystem *mesgsys, void **user_data);
void process_sim_stats(LLMessageSystem *mesgsys, void **user_data);
void process_shooter_agent_hit(LLMessageSystem* msg, void** user_data);
void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data);
+void process_object_animation(LLMessageSystem *mesgsys, void **user_data);
void process_avatar_appearance(LLMessageSystem *mesgsys, void **user_data);
void process_camera_constraint(LLMessageSystem *mesgsys, void **user_data);
void process_avatar_sit_response(LLMessageSystem *mesgsys, void **user_data);
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 1d6daed9cc..e2fbac023a 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -60,6 +60,7 @@
#include "llbbox.h"
#include "llbox.h"
#include "llcylinder.h"
+#include "llcontrolavatar.h"
#include "lldrawable.h"
#include "llface.h"
#include "llfloaterproperties.h"
@@ -138,7 +139,7 @@ const F32 PHYSICS_TIMESTEP = 1.f / 45.f;
static LLTrace::BlockTimerStatHandle FTM_CREATE_OBJECT("Create Object");
// static
-LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
+LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp, S32 flags)
{
LLViewerObject *res = NULL;
LL_RECORD_BLOCK_TIME(FTM_CREATE_OBJECT);
@@ -166,6 +167,12 @@ LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pco
}
res = gAgentAvatarp;
}
+ else if (flags & CO_FLAG_CONTROL_AVATAR)
+ {
+ LLControlAvatar *avatar = new LLControlAvatar(id, pcode, regionp);
+ avatar->initInstance();
+ res = avatar;
+ }
else
{
LLVOAvatar *avatar = new LLVOAvatar(id, pcode, regionp);
@@ -235,6 +242,7 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe
mText(),
mHudText(""),
mHudTextColor(LLColor4::white),
+ mControlAvatar(NULL),
mLastInterpUpdateSecs(0.f),
mLastMessageUpdateSecs(0.f),
mLatestRecvPacketID(0),
@@ -259,7 +267,7 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe
mRotTime(0.f),
mAngularVelocityRot(),
mPreviousRotation(),
- mState(0),
+ mAttachmentState(0),
mMedia(NULL),
mClickAction(0),
mObjectCost(0),
@@ -363,17 +371,23 @@ void LLViewerObject::markDead()
//LL_INFOS() << "Marking self " << mLocalID << " as dead." << LL_ENDL;
// Root object of this hierarchy unlinks itself.
- LLVOAvatar *av = getAvatarAncestor();
if (getParent())
{
((LLViewerObject *)getParent())->removeChild(this);
}
LLUUID mesh_id;
- if (av && LLVOAvatar::getRiggedMeshID(this,mesh_id))
- {
- // This case is needed for indirectly attached mesh objects.
- av->resetJointsOnDetach(mesh_id);
- }
+ {
+ LLVOAvatar *av = getAvatar();
+ if (av && LLVOAvatar::getRiggedMeshID(this,mesh_id))
+ {
+ // This case is needed for indirectly attached mesh objects.
+ av->removeAttachmentOverridesForObject(mesh_id);
+ }
+ }
+ if (getControlAvatar())
+ {
+ unlinkControlAvatar();
+ }
// Mark itself as dead
mDead = TRUE;
@@ -1378,7 +1392,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
U8 state;
mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_State, state, block_num );
- mState = state;
+ mAttachmentState = state;
// ...new objects that should come in selected need to be added to the selected list
mCreateSelected = ((flags & FLAGS_CREATE_SELECTED) != 0);
@@ -1648,7 +1662,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
U8 state;
mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_State, state, block_num );
- mState = state;
+ mAttachmentState = state;
break;
}
@@ -1671,7 +1685,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
U8 state;
dp->unpackU8(state, "State");
- mState = state;
+ mAttachmentState = state;
switch(update_type)
{
@@ -2902,6 +2916,61 @@ void LLViewerObject::fetchInventoryFromServer()
}
}
+LLControlAvatar *LLViewerObject::getControlAvatar()
+{
+ return getRootEdit()->mControlAvatar.get();
+}
+
+LLControlAvatar *LLViewerObject::getControlAvatar() const
+{
+ return getRootEdit()->mControlAvatar.get();
+}
+
+void LLViewerObject::linkControlAvatar()
+{
+ if (!getControlAvatar() && isRootEdit())
+ {
+ LLVOVolume *volp = dynamic_cast<LLVOVolume*>(this);
+ if (!volp)
+ {
+ LL_WARNS() << "called with null or non-volume object" << LL_ENDL;
+ return;
+ }
+ mControlAvatar = LLControlAvatar::createControlAvatar(volp);
+ }
+ if (getControlAvatar())
+ {
+ getControlAvatar()->addAttachmentOverridesForObject(this);
+ }
+ else
+ {
+ LL_WARNS() << "no control avatar found!" << LL_ENDL;
+ }
+}
+
+void LLViewerObject::unlinkControlAvatar()
+{
+ if (getControlAvatar())
+ {
+ getControlAvatar()->removeAttachmentOverridesForObject(this);
+ }
+ if (isRootEdit())
+ {
+ // This will remove the entire linkset from the control avatar
+ LLControlAvatar *av = mControlAvatar;
+ mControlAvatar = NULL;
+ av->markForDeath();
+ }
+ // For non-root prims, removing from the linkset will
+ // automatically remove the control avatar connection.
+}
+
+// virtual
+bool LLViewerObject::isAnimatedObject() const
+{
+ return false;
+}
+
struct LLFilenameAndTask
{
LLUUID mTaskID;
@@ -3857,7 +3926,7 @@ const LLVector3 LLViewerObject::getRenderPosition() const
if (mDrawable.notNull() && mDrawable->isState(LLDrawable::RIGGED))
{
LLVOAvatar* avatar = getAvatar();
- if (avatar)
+ if (avatar && !getControlAvatar())
{
return avatar->getPositionAgent();
}
@@ -5122,6 +5191,7 @@ LLVOAvatar* LLViewerObject::asAvatar()
// If this object is directly or indirectly parented by an avatar, return it.
LLVOAvatar* LLViewerObject::getAvatarAncestor()
{
+ LL_ERRS("AXON") << "this method has been targetted for termination. Use getAvatar()." << LL_ENDL;
LLViewerObject *pobj = (LLViewerObject*) getParent();
while (pobj)
{
@@ -5458,6 +5528,11 @@ LLViewerObject::ExtraParameter* LLViewerObject::createNewParameterEntry(U16 para
new_block = new LLLightImageParams();
break;
}
+ case LLNetworkData::PARAMS_EXTENDED_MESH:
+ {
+ new_block = new LLExtendedMeshParams();
+ break;
+ }
default:
{
LL_INFOS() << "Unknown param type." << LL_ENDL;
@@ -6353,6 +6428,10 @@ const std::string& LLViewerObject::getAttachmentItemName() const
//virtual
LLVOAvatar* LLViewerObject::getAvatar() const
{
+ if (getControlAvatar())
+ {
+ return getControlAvatar();
+ }
if (isAttachment())
{
LLViewerObject* vobj = (LLViewerObject*) getParent();
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index 24fcf0517e..c79ff7bb74 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -47,6 +47,7 @@ class LLAgent; // TODO: Get rid of this.
class LLAudioSource;
class LLAudioSourceVO;
class LLColor4;
+class LLControlAvatar;
class LLDataPacker;
class LLDataPackerBinaryBuffer;
class LLDrawable;
@@ -374,7 +375,7 @@ public:
void sendShapeUpdate();
- U8 getState() { return mState; }
+ U8 getAttachmentState() { return mAttachmentState; }
F32 getAppAngle() const { return mAppAngle; }
F32 getPixelArea() const { return mPixelArea; }
@@ -683,6 +684,21 @@ public:
static BOOL sUseSharedDrawables;
+public:
+ // Returns mControlAvatar for the edit root prim of this linkset
+ LLControlAvatar *getControlAvatar();
+ LLControlAvatar *getControlAvatar() const;
+
+ // Create or connect to an existing control av as applicable
+ void linkControlAvatar();
+ // Remove any reference to control av for this prim
+ void unlinkControlAvatar();
+
+ virtual bool isAnimatedObject() const;
+
+protected:
+ LLPointer<LLControlAvatar> mControlAvatar;
+
protected:
// delete an item in the inventory, but don't tell the
// server. This is used internally by remove, update, and
@@ -693,8 +709,10 @@ protected:
// updateInventory.
void doUpdateInventory(LLPointer<LLViewerInventoryItem>& item, U8 key, bool is_new);
+ // Flags for createObject
+ static const S32 CO_FLAG_CONTROL_AVATAR = 1 << 1;
- static LLViewerObject *createObject(const LLUUID &id, LLPCode pcode, LLViewerRegion *regionp);
+ static LLViewerObject *createObject(const LLUUID &id, LLPCode pcode, LLViewerRegion *regionp, S32 flags = 0);
BOOL setData(const U8 *datap, const U32 data_size);
@@ -782,7 +800,7 @@ protected:
LLQuaternion mAngularVelocityRot; // accumulated rotation from the angular velocity computations
LLQuaternion mPreviousRotation;
- U8 mState; // legacy
+ U8 mAttachmentState; // this encodes the attachment id in a somewhat complex way. 0 if not an attachment.
LLViewerObjectMedia* mMedia; // NULL if no media associated
U8 mClickAction;
F32 mObjectCost; //resource cost of this object or -1 if unknown
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index 8f98d66c0c..1f99119d82 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -1942,12 +1942,12 @@ void LLViewerObjectList::resetObjectBeacons()
mDebugBeacons.clear();
}
-LLViewerObject *LLViewerObjectList::createObjectViewer(const LLPCode pcode, LLViewerRegion *regionp)
+LLViewerObject *LLViewerObjectList::createObjectViewer(const LLPCode pcode, LLViewerRegion *regionp, S32 flags)
{
LLUUID fullid;
fullid.generate();
- LLViewerObject *objectp = LLViewerObject::createObject(fullid, pcode, regionp);
+ LLViewerObject *objectp = LLViewerObject::createObject(fullid, pcode, regionp, flags);
if (!objectp)
{
// LL_WARNS() << "Couldn't create object of type " << LLPrimitive::pCodeToString(pcode) << LL_ENDL;
diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h
index 94c751acc6..72b2b99004 100644
--- a/indra/newview/llviewerobjectlist.h
+++ b/indra/newview/llviewerobjectlist.h
@@ -67,7 +67,7 @@ public:
inline LLViewerObject *getObject(const S32 index);
inline LLViewerObject *findObject(const LLUUID &id);
- LLViewerObject *createObjectViewer(const LLPCode pcode, LLViewerRegion *regionp); // Create a viewer-side object
+ LLViewerObject *createObjectViewer(const LLPCode pcode, LLViewerRegion *regionp, S32 flags = 0); // Create a viewer-side object
LLViewerObject *createObjectFromCache(const LLPCode pcode, LLViewerRegion *regionp, const LLUUID &uuid, const U32 local_id);
LLViewerObject *createObject(const LLPCode pcode, LLViewerRegion *regionp,
const LLUUID &uuid, const U32 local_id, const LLHost &sender);
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index eb37613c95..02ac0a0d34 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -2857,6 +2857,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
capabilityNames.append("MeshUploadFlag");
capabilityNames.append("NavMeshGenerationStatus");
capabilityNames.append("NewFileAgentInventory");
+ capabilityNames.append("ObjectAnimation");
capabilityNames.append("ObjectMedia");
capabilityNames.append("ObjectMediaNavigate");
capabilityNames.append("ObjectNavMeshProperties");
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 80c6805ead..eab5206828 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -44,6 +44,7 @@
#include "llavatarnamecache.h"
#include "llavatarpropertiesprocessor.h"
#include "llavatarrendernotifier.h"
+#include "llcontrolavatar.h"
#include "llexperiencecache.h"
#include "llphysicsmotion.h"
#include "llviewercontrol.h"
@@ -663,7 +664,9 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
mLastUpdateRequestCOFVersion(-1),
mLastUpdateReceivedCOFVersion(-1),
mCachedMuteListUpdateTime(0),
- mCachedInMuteList(false)
+ mCachedInMuteList(false),
+ mIsControlAvatar(false),
+ mEnableDefaultMotions(true)
{
LL_DEBUGS("AvatarRender") << "LLVOAvatar Constructor (0x" << this << ") id:" << mID << LL_ENDL;
@@ -718,6 +721,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
mCurrentGesticulationLevel = 0;
+
mRuthTimer.reset();
mRuthDebugTimer.reset();
mDebugExistenceTimer.reset();
@@ -1222,8 +1226,6 @@ const LLVector3 LLVOAvatar::getRenderPosition() const
{
return getPosition() * mDrawable->getParent()->getRenderMatrix();
}
-
-
}
void LLVOAvatar::updateDrawable(BOOL force_damped)
@@ -1240,6 +1242,10 @@ void LLVOAvatar::onShift(const LLVector4a& shift_vector)
void LLVOAvatar::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax)
{
+ if (mDrawable.isNull())
+ {
+ return;
+ }
if (isImpostor() && !needsImpostorUpdate())
{
LLVector3 delta = getRenderPosition() -
@@ -1404,13 +1410,29 @@ void LLVOAvatar::renderCollisionVolumes()
static F32 sphere_scale = 1.0f;
static F32 center_dot_scale = 0.05f;
- static LLVector3 CV_COLOR_OCCLUDED(0.0f, 0.0f, 1.0f);
- static LLVector3 CV_COLOR_VISIBLE(0.5f, 0.5f, 1.0f);
- static LLVector3 DOT_COLOR_OCCLUDED(1.0f, 1.0f, 1.0f);
- static LLVector3 DOT_COLOR_VISIBLE(1.0f, 1.0f, 1.0f);
+ static LLVector3 BLUE(0.0f, 0.0f, 1.0f);
+ static LLVector3 PASTEL_BLUE(0.5f, 0.5f, 1.0f);
+ static LLVector3 RED(1.0f, 0.0f, 0.0f);
+ static LLVector3 PASTEL_RED(1.0f, 0.5f, 0.5f);
+ static LLVector3 WHITE(1.0f, 1.0f, 1.0f);
+
- render_sphere_and_line(begin_pos, end_pos, sphere_scale, CV_COLOR_OCCLUDED, CV_COLOR_VISIBLE);
- render_sphere_and_line(begin_pos, end_pos, center_dot_scale, DOT_COLOR_OCCLUDED, DOT_COLOR_VISIBLE);
+ LLVector3 cv_color_occluded;
+ LLVector3 cv_color_visible;
+ LLVector3 dot_color_occluded(WHITE);
+ LLVector3 dot_color_visible(WHITE);
+ if (isControlAvatar())
+ {
+ cv_color_occluded = RED;
+ cv_color_visible = PASTEL_RED;
+ }
+ else
+ {
+ cv_color_occluded = BLUE;
+ cv_color_visible = PASTEL_BLUE;
+ }
+ render_sphere_and_line(begin_pos, end_pos, sphere_scale, cv_color_occluded, cv_color_visible);
+ render_sphere_and_line(begin_pos, end_pos, center_dot_scale, dot_color_occluded, dot_color_visible);
gGL.popMatrix();
}
@@ -1422,9 +1444,6 @@ void LLVOAvatar::renderCollisionVolumes()
mNameText->lineSegmentIntersect(unused, unused, unused, TRUE);
}
-
- mDebugText.clear();
- addDebugText(ostr.str());
}
void LLVOAvatar::renderBones()
@@ -1595,6 +1614,11 @@ BOOL LLVOAvatar::lineSegmentIntersect(const LLVector4a& start, const LLVector4a&
return FALSE;
}
+ if (isControlAvatar())
+ {
+ return FALSE;
+ }
+
if (lineSegmentBoundingBox(start, end))
{
for (S32 i = 0; i < mNumCollisionVolumes; ++i)
@@ -1680,6 +1704,7 @@ BOOL LLVOAvatar::lineSegmentIntersect(const LLVector4a& start, const LLVector4a&
return FALSE;
}
+// virtual
LLViewerObject* LLVOAvatar::lineSegmentIntersectRiggedAttachments(const LLVector4a& start, const LLVector4a& end,
S32 face,
BOOL pick_transparent,
@@ -1796,7 +1821,11 @@ void LLVOAvatar::buildCharacter()
mAahMorph = getVisualParam( "Express_Open_Mouth" );
}
- startDefaultMotions();
+ // Currently disabled for control avatars (animated objects), enabled for all others.
+ if (mEnableDefaultMotions)
+ {
+ startDefaultMotions();
+ }
//-------------------------------------------------------------------------
// restart any currently active motions
@@ -1942,6 +1971,8 @@ void LLVOAvatar::resetSkeleton(bool reset_animations)
//-----------------------------------------------------------------------------
void LLVOAvatar::releaseMeshData()
{
+ // AXON what should we be doing here for control avs? Why are
+ // dummies treated differently in the first place?
if (sInstances.size() < AVATAR_RELEASE_THRESHOLD || mIsDummy)
{
return;
@@ -1962,15 +1993,15 @@ void LLVOAvatar::releaseMeshData()
LLFace* facep = mDrawable->getFace(0);
if (facep)
{
- facep->setSize(0, 0);
- for(S32 i = mNumInitFaces ; i < mDrawable->getNumFaces(); i++)
- {
- facep = mDrawable->getFace(i);
+ facep->setSize(0, 0);
+ for(S32 i = mNumInitFaces ; i < mDrawable->getNumFaces(); i++)
+ {
+ facep = mDrawable->getFace(i);
if (facep)
{
- facep->setSize(0, 0);
- }
- }
+ facep->setSize(0, 0);
+ }
+ }
}
}
@@ -1994,6 +2025,10 @@ void LLVOAvatar::releaseMeshData()
void LLVOAvatar::restoreMeshData()
{
llassert(!isSelf());
+ if (mDrawable.isNull())
+ {
+ return;
+ }
//LL_INFOS() << "Restoring" << LL_ENDL;
mMeshValid = TRUE;
@@ -2571,13 +2606,16 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update)
}
}
- mDrawable->movePartition();
-
- //force a move if sitting on an active object
- if (getParent() && ((LLViewerObject*) getParent())->mDrawable->isActive())
- {
- gPipeline.markMoved(mDrawable, TRUE);
- }
+ if (mDrawable.notNull())
+ {
+ mDrawable->movePartition();
+
+ //force a move if sitting on an active object
+ if (getParent() && ((LLViewerObject*) getParent())->mDrawable->isActive())
+ {
+ gPipeline.markMoved(mDrawable, TRUE);
+ }
+ }
}
void LLVOAvatar::idleUpdateAppearanceAnimation()
@@ -2738,7 +2776,8 @@ void LLVOAvatar::idleUpdateLoadingEffect()
LLPartData::LL_PART_EMISSIVE_MASK | // LLPartData::LL_PART_FOLLOW_SRC_MASK |
LLPartData::LL_PART_TARGET_POS_MASK );
- if (!isTooComplex()) // do not generate particles for overly-complex avatars
+ // AXON skip cloud effects for dummy avs as well
+ if (!mIsDummy && !isTooComplex()) // do not generate particles for overly-complex avatars
{
setParticleSource(particle_parameters, getID());
}
@@ -3338,8 +3377,7 @@ bool LLVOAvatar::isInMuteList()
void LLVOAvatar::updateDebugText()
{
- // clear debug text
- mDebugText.clear();
+ // Leave mDebugText uncleared here, in case a derived class has added some state first
if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
{
@@ -3406,6 +3444,7 @@ void LLVOAvatar::updateDebugText()
addDebugText(mBakedTextureDebugText);
}
+ // Develop -> Avatar -> Animation Info
if (LLVOAvatar::sShowAnimationDebug)
{
for (LLMotionController::motion_list_t::iterator iter = mMotionController.getActiveMotions().begin();
@@ -3415,8 +3454,27 @@ void LLVOAvatar::updateDebugText()
if (motionp->getMinPixelArea() < getPixelArea())
{
std::string output;
- if (motionp->getName().empty())
+ std::string motion_name = motionp->getName();
+ if (motion_name.empty())
{
+ if (isControlAvatar())
+ {
+ LLControlAvatar *control_av = dynamic_cast<LLControlAvatar*>(this);
+ // Try to get name from inventory of associated object
+ LLVOVolume *volp = control_av->mRootVolp;
+ if (volp)
+ {
+ volp->requestInventory(); // AXON should be a no-op if already requested or fetched?
+ LLViewerInventoryItem* item = volp->getInventoryItemByAsset(motionp->getID());
+ if (item)
+ {
+ motion_name = item->getName();
+ }
+ }
+ }
+ }
+ if (motion_name.empty())
+ {
output = llformat("%s - %d",
gAgent.isGodlikeWithoutAdminMenuFakery() ?
motionp->getID().asString().c_str() :
@@ -3426,8 +3484,8 @@ void LLVOAvatar::updateDebugText()
else
{
output = llformat("%s - %d",
- motionp->getName().c_str(),
- (U32)motionp->getPriority());
+ motion_name.c_str(),
+ (U32)motionp->getPriority());
}
addDebugText(output);
}
@@ -3443,8 +3501,7 @@ void LLVOAvatar::updateDebugText()
{
setDebugText(mDebugText);
}
- mDebugText.clear();
-
+ mDebugText.clear();
}
//------------------------------------------------------------------------
@@ -3474,7 +3531,9 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
//--------------------------------------------------------------------
bool visually_muted = isVisuallyMuted();
- if (visible && (!isSelf() || visually_muted) && !mIsDummy && sUseImpostors && !mNeedsAnimUpdate && !sFreezeCounter)
+ // AXON FIXME this expression is a crawling horror
+ if (mDrawable.notNull() && visible && (!isSelf() || visually_muted) &&
+ !mIsDummy && sUseImpostors && !mNeedsAnimUpdate && !sFreezeCounter)
{
const LLVector4a* ext = mDrawable->getSpatialExtents();
LLVector4a size;
@@ -3530,7 +3589,9 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
}
// change animation time quanta based on avatar render load
- if (!isSelf() && !mIsDummy)
+ // AXON how should control avs be handled here?
+ bool is_pure_dummy = mIsDummy && !isControlAvatar();
+ if (!isSelf() && !is_pure_dummy)
{
F32 time_quantum = clamp_rescale((F32)sInstances.size(), 10.f, 35.f, 0.f, 0.25f);
F32 pixel_area_scale = clamp_rescale(mPixelArea, 100, 5000, 1.f, 0.f);
@@ -3652,7 +3713,8 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
//--------------------------------------------------------------------
// Propagate viewer object rotation to root of avatar
//--------------------------------------------------------------------
- if (!isAnyAnimationSignaled(AGENT_NO_ROTATE_ANIMS, NUM_AGENT_NO_ROTATE_ANIMS))
+ // AXON - also skip for control avatars
+ if (!isControlAvatar() && !isAnyAnimationSignaled(AGENT_NO_ROTATE_ANIMS, NUM_AGENT_NO_ROTATE_ANIMS))
{
LLQuaternion iQ;
LLVector3 upDir( 0.0f, 0.0f, 1.0f );
@@ -4041,7 +4103,7 @@ void LLVOAvatar::updateVisibility()
if (mIsDummy)
{
- visible = TRUE;
+ visible = FALSE;
}
else if (mDrawable.isNull())
{
@@ -4190,6 +4252,11 @@ U32 LLVOAvatar::renderSkinned()
return num_indices;
}
+ if (mDrawable.isNull())
+ {
+ return num_indices;
+ }
+
LLFace* face = mDrawable->getFace(0);
bool needs_rebuild = !face || !face->getVertexBuffer() || mDrawable->isState(LLDrawable::REBUILD_GEOMETRY);
@@ -4352,11 +4419,12 @@ U32 LLVOAvatar::renderSkinned()
}
BOOL first_pass = TRUE;
+ bool is_pure_dummy = mIsDummy && !isControlAvatar();
if (!LLDrawPoolAvatar::sSkipOpaque)
{
if (!isSelf() || gAgent.needsRenderHead() || LLPipeline::sShadowRender)
{
- if (isTextureVisible(TEX_HEAD_BAKED) || mIsDummy)
+ if (isTextureVisible(TEX_HEAD_BAKED) || is_pure_dummy)
{
LLViewerJoint* head_mesh = getViewerJoint(MESH_ID_HEAD);
if (head_mesh)
@@ -4366,7 +4434,7 @@ U32 LLVOAvatar::renderSkinned()
first_pass = FALSE;
}
}
- if (isTextureVisible(TEX_UPPER_BAKED) || mIsDummy)
+ if (isTextureVisible(TEX_UPPER_BAKED) || is_pure_dummy)
{
LLViewerJoint* upper_mesh = getViewerJoint(MESH_ID_UPPER_BODY);
if (upper_mesh)
@@ -4376,7 +4444,7 @@ U32 LLVOAvatar::renderSkinned()
first_pass = FALSE;
}
- if (isTextureVisible(TEX_LOWER_BAKED) || mIsDummy)
+ if (isTextureVisible(TEX_LOWER_BAKED) || is_pure_dummy)
{
LLViewerJoint* lower_mesh = getViewerJoint(MESH_ID_LOWER_BODY);
if (lower_mesh)
@@ -4433,18 +4501,15 @@ U32 LLVOAvatar::renderTransparent(BOOL first_pass)
}
first_pass = FALSE;
}
- // Can't test for baked hair being defined, since that won't always be the case (not all viewers send baked hair)
- // TODO: 1.25 will be able to switch this logic back to calling isTextureVisible();
- if ( (getImage(TEX_HAIR_BAKED, 0) && getImage(TEX_HAIR_BAKED, 0)->getID() != IMG_INVISIBLE)
- || LLDrawPoolAlpha::sShowDebugAlpha)
- {
- LLViewerJoint* hair_mesh = getViewerJoint(MESH_ID_HAIR);
- if (hair_mesh)
- {
- num_indices += hair_mesh->render(mAdjustedPixelArea, first_pass, mIsDummy);
- }
- first_pass = FALSE;
- }
+ if (isTextureVisible(TEX_HAIR_BAKED))
+ {
+ LLViewerJoint* hair_mesh = getViewerJoint(MESH_ID_HAIR);
+ if (hair_mesh)
+ {
+ num_indices += hair_mesh->render(mAdjustedPixelArea, first_pass, mIsDummy);
+ }
+ first_pass = FALSE;
+ }
if (LLPipeline::sImpostorRender)
{
gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
@@ -4484,7 +4549,9 @@ U32 LLVOAvatar::renderRigid()
gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f);
}
- if (isTextureVisible(TEX_EYES_BAKED) || mIsDummy)
+ bool is_pure_dummy = mIsDummy && !isControlAvatar();
+
+ if (isTextureVisible(TEX_EYES_BAKED) || is_pure_dummy)
{
LLViewerJoint* eyeball_left = getViewerJoint(MESH_ID_EYEBALL_LEFT);
LLViewerJoint* eyeball_right = getViewerJoint(MESH_ID_EYEBALL_RIGHT);
@@ -5034,7 +5101,10 @@ void LLVOAvatar::processAnimationStateChanges()
else if (mInAir && !mIsSitting)
{
stopMotion(ANIM_AGENT_WALK_ADJUST);
- startMotion(ANIM_AGENT_FLY_ADJUST);
+ if (mEnableDefaultMotions)
+ {
+ startMotion(ANIM_AGENT_FLY_ADJUST);
+ }
}
else
{
@@ -5044,13 +5114,19 @@ void LLVOAvatar::processAnimationStateChanges()
if ( isAnyAnimationSignaled(AGENT_GUN_AIM_ANIMS, NUM_AGENT_GUN_AIM_ANIMS) )
{
- startMotion(ANIM_AGENT_TARGET);
+ if (mEnableDefaultMotions)
+ {
+ startMotion(ANIM_AGENT_TARGET);
+ }
stopMotion(ANIM_AGENT_BODY_NOISE);
}
else
{
stopMotion(ANIM_AGENT_TARGET);
- startMotion(ANIM_AGENT_BODY_NOISE);
+ if (mEnableDefaultMotions)
+ {
+ startMotion(ANIM_AGENT_BODY_NOISE);
+ }
}
// clear all current animations
@@ -5521,14 +5597,13 @@ void LLVOAvatar::rebuildAttachmentOverrides()
//-----------------------------------------------------------------------------
void LLVOAvatar::addAttachmentOverridesForObject(LLViewerObject *vo)
{
- LLVOAvatar *av = vo->getAvatarAncestor();
- if (!av || (av != this))
- {
+ if (vo->getAvatar() != this)
+ {
LL_WARNS("Avatar") << "called with invalid avatar" << LL_ENDL;
return;
- }
+ }
- LLScopedContextString str("addAttachmentOverridesForObject " + av->getFullname());
+ LLScopedContextString str("addAttachmentOverridesForObject " + vo->getAvatar()->getFullname());
// Process all children
LLViewerObject::const_child_list_t& children = vo->getChildren();
@@ -5554,7 +5629,7 @@ void LLVOAvatar::addAttachmentOverridesForObject(LLViewerObject *vo)
LLUUID currentId = vobj->getVolume()->getParams().getSculptID();
const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( currentId, vobj );
- if ( vobj && vobj->isAttachment() && vobj->isMesh() && pSkinData )
+ if ( vobj && vobj->isMesh() && pSkinData )
{
const int bindCnt = pSkinData->mAlternateBindMatrix.size();
const int jointCnt = pSkinData->mJointNames.size();
@@ -5736,14 +5811,15 @@ void LLVOAvatar::showAttachmentOverrides(bool verbose) const
}
//-----------------------------------------------------------------------------
-// resetJointsOnDetach
+// removeAttachmentOverridesForObject
//-----------------------------------------------------------------------------
-void LLVOAvatar::resetJointsOnDetach(LLViewerObject *vo)
+// AXON handle NPC case
+void LLVOAvatar::removeAttachmentOverridesForObject(LLViewerObject *vo)
{
- LLVOAvatar *av = vo->getAvatarAncestor();
- if (!av || (av != this))
+ if (vo->getAvatar() != this)
{
LL_WARNS("Avatar") << "called with invalid avatar" << LL_ENDL;
+ return;
}
// Process all children
@@ -5752,21 +5828,22 @@ void LLVOAvatar::resetJointsOnDetach(LLViewerObject *vo)
it != children.end(); ++it)
{
LLViewerObject *childp = *it;
- resetJointsOnDetach(childp);
+ removeAttachmentOverridesForObject(childp);
}
// Process self.
LLUUID mesh_id;
if (getRiggedMeshID(vo,mesh_id))
{
- resetJointsOnDetach(mesh_id);
+ removeAttachmentOverridesForObject(mesh_id);
}
}
//-----------------------------------------------------------------------------
-// resetJointsOnDetach
+// removeAttachmentOverridesForObject
//-----------------------------------------------------------------------------
-void LLVOAvatar::resetJointsOnDetach(const LLUUID& mesh_id)
+// AXON handle NPC case
+void LLVOAvatar::removeAttachmentOverridesForObject(const LLUUID& mesh_id)
{
//Subsequent joints are relative to pelvis
avatar_joint_list_t::iterator iter = mSkeleton.begin();
@@ -5844,6 +5921,7 @@ void LLVOAvatar::getGround(const LLVector3 &in_pos_agent, LLVector3 &out_pos_age
LLVector3d z_vec(0.0f, 0.0f, 1.0f);
LLVector3d p0_global, p1_global;
+ // AXON update for control avs?
if (mIsDummy)
{
outNorm.setVec(z_vec);
@@ -5873,6 +5951,7 @@ F32 LLVOAvatar::getTimeDilation()
//-----------------------------------------------------------------------------
F32 LLVOAvatar::getPixelArea() const
{
+ // AXON update for control avatars
if (mIsDummy)
{
return 100000.f;
@@ -6288,7 +6367,7 @@ void LLVOAvatar::removeChild(LLViewerObject *childp)
LLViewerJointAttachment* LLVOAvatar::getTargetAttachmentPoint(LLViewerObject* viewer_object)
{
- S32 attachmentID = ATTACHMENT_ID_FROM_STATE(viewer_object->getState());
+ S32 attachmentID = ATTACHMENT_ID_FROM_STATE(viewer_object->getAttachmentState());
// This should never happen unless the server didn't process the attachment point
// correctly, but putting this check in here to be safe.
@@ -6483,7 +6562,7 @@ void LLVOAvatar::cleanupAttachedMesh( LLViewerObject* pVO )
LLUUID mesh_id;
if (getRiggedMeshID(pVO, mesh_id))
{
- resetJointsOnDetach(mesh_id);
+ removeAttachmentOverridesForObject(mesh_id);
if ( gAgentCamera.cameraCustomizeAvatar() )
{
gAgent.unpauseAnimation();
@@ -6644,7 +6723,10 @@ void LLVOAvatar::getOffObject()
mRoot->setRotation(cur_rotation_world);
mRoot->getXform()->update();
- startMotion(ANIM_AGENT_BODY_NOISE);
+ if (mEnableDefaultMotions)
+ {
+ startMotion(ANIM_AGENT_BODY_NOISE);
+ }
if (isSelf())
{
@@ -6804,6 +6886,7 @@ void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color)
BOOL LLVOAvatar::isVisible() const
{
+ // AXON should we flag control avs as invisible?
return mDrawable.notNull()
&& (!mOrphaned || isSelf())
&& (mDrawable->isVisible() || mIsDummy);
@@ -6812,6 +6895,11 @@ BOOL LLVOAvatar::isVisible() const
// Determine if we have enough avatar data to render
bool LLVOAvatar::getIsCloud() const
{
+ if (mIsDummy)
+ {
+ return false;
+ }
+
return ( ((const_cast<LLVOAvatar*>(this))->visualParamWeightsAreDefault())// Do we have a shape?
|| ( !isTextureDefined(TEX_LOWER_BAKED)
|| !isTextureDefined(TEX_UPPER_BAKED)
@@ -8776,6 +8864,11 @@ void LLVOAvatar::updateFreezeCounter(S32 counter)
BOOL LLVOAvatar::updateLOD()
{
+ if (mDrawable.isNull())
+ {
+ return FALSE;
+ }
+
if (isImpostor() && 0 != mDrawable->getNumFaces() && mDrawable->getFace(0)->hasGeometry())
{
return TRUE;
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index bd89d4ef23..8b22024e0a 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -169,7 +169,8 @@ public:
LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point
LLVector4a* normal = NULL, // return the surface normal at the intersection point
LLVector4a* tangent = NULL); // return the surface tangent at the intersection point
- LLViewerObject* lineSegmentIntersectRiggedAttachments(const LLVector4a& start, const LLVector4a& end,
+ virtual LLViewerObject* lineSegmentIntersectRiggedAttachments(
+ const LLVector4a& start, const LLVector4a& end,
S32 face = -1, // which face to check, -1 = ALL_SIDES
BOOL pick_transparent = FALSE,
BOOL pick_rigged = FALSE,
@@ -202,8 +203,8 @@ public:
LLJoint* getJoint(S32 num);
void addAttachmentOverridesForObject(LLViewerObject *vo);
- void resetJointsOnDetach(const LLUUID& mesh_id);
- void resetJointsOnDetach(LLViewerObject *vo);
+ void removeAttachmentOverridesForObject(const LLUUID& mesh_id);
+ void removeAttachmentOverridesForObject(LLViewerObject *vo);
bool jointIsRiggedTo(const std::string& joint_name);
bool jointIsRiggedTo(const std::string& joint_name, const LLViewerObject *vo);
void clearAttachmentOverrides();
@@ -233,6 +234,8 @@ public:
public:
virtual bool isSelf() const { return false; } // True if this avatar is for this viewer's agent
+ virtual bool isControlAvatar() const { return mIsControlAvatar; } // True if this avatar is a control av (no associated user)
+
private: //aligned members
LL_ALIGN_16(LLVector4a mImpostorExtents[2]);
@@ -240,7 +243,7 @@ private: //aligned members
// Updates
//--------------------------------------------------------------------
public:
- void updateDebugText();
+ virtual void updateDebugText();
virtual BOOL updateCharacter(LLAgent &agent);
void idleUpdateVoiceVisualizer(bool voice_enabled);
void idleUpdateMisc(bool detailed_update);
@@ -441,6 +444,13 @@ public:
VisualMuteSettings mVisuallyMuteSetting; // Always or never visually mute this AV
//--------------------------------------------------------------------
+ // animated object status
+ //--------------------------------------------------------------------
+public:
+ bool mIsControlAvatar;
+ bool mEnableDefaultMotions;
+
+ //--------------------------------------------------------------------
// Morph masks
//--------------------------------------------------------------------
public:
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index d62862dfb8..658000987b 100644
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -2791,7 +2791,7 @@ BOOL LLVOAvatarSelf::needsRenderBeam()
// don't render selection beam on hud objects
is_touching_or_grabbing = FALSE;
}
- return is_touching_or_grabbing || (mState & AGENT_STATE_EDITING && LLSelectMgr::getInstance()->shouldShowSelection());
+ return is_touching_or_grabbing || (getAttachmentState() & AGENT_STATE_EDITING && LLSelectMgr::getInstance()->shouldShowSelection());
}
// static
diff --git a/indra/newview/llvograss.cpp b/indra/newview/llvograss.cpp
index de63a3963c..337f969f3d 100644
--- a/indra/newview/llvograss.cpp
+++ b/indra/newview/llvograss.cpp
@@ -92,7 +92,8 @@ LLVOGrass::~LLVOGrass()
void LLVOGrass::updateSpecies()
{
- mSpecies = mState;
+ // AXON is grass still even supported? This use of state seems odd.
+ mSpecies = getAttachmentState();
if (!sSpeciesTable.count(mSpecies))
{
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 90ba814a15..403bff5a9e 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -76,8 +76,13 @@
#include "lldatapacker.h"
#include "llviewershadermgr.h"
#include "llvoavatar.h"
+#include "llcontrolavatar.h"
+#include "llvoavatarself.h"
#include "llvocache.h"
#include "llmaterialmgr.h"
+#include "llanimationstates.h"
+#include "llinventorytype.h"
+#include "llviewerinventory.h"
const F32 FORCE_SIMPLE_RENDER_AREA = 512.f;
const F32 FORCE_CULL_AREA = 8.f;
@@ -86,6 +91,8 @@ U32 JOINT_COUNT_REQUIRED_FOR_FULLRIG = 1;
BOOL gAnimateTextures = TRUE;
//extern BOOL gHideSelectedObjects;
+// AXON TEMP
+S32 LLVOVolume::sForceLOD = -1;
F32 LLVOVolume::sLODFactor = 1.f;
F32 LLVOVolume::sLODSlopDistanceFactor = 0.5f; //Changing this to zero, effectively disables the LOD transition slop
F32 LLVOVolume::sDistanceFactor = 1.0f;
@@ -1217,16 +1224,24 @@ void LLVOVolume::sculpt()
S32 LLVOVolume::computeLODDetail(F32 distance, F32 radius)
{
S32 cur_detail;
- if (LLPipeline::sDynamicLOD)
- {
- // We've got LOD in the profile, and in the twist. Use radius.
- F32 tan_angle = (LLVOVolume::sLODFactor*radius)/distance;
- cur_detail = LLVolumeLODGroup::getDetailFromTan(ll_round(tan_angle, 0.01f));
- }
- else
- {
- cur_detail = llclamp((S32) (sqrtf(radius)*LLVOVolume::sLODFactor*4.f), 0, 3);
- }
+ // AXON TEMP
+ if (LLVOVolume::sForceLOD>=0 && LLVOVolume::sForceLOD<=3)
+ {
+ cur_detail = LLVOVolume::sForceLOD;
+ }
+ else
+ {
+ if (LLPipeline::sDynamicLOD)
+ {
+ // We've got LOD in the profile, and in the twist. Use radius.
+ F32 tan_angle = (LLVOVolume::sLODFactor*radius)/distance;
+ cur_detail = LLVolumeLODGroup::getDetailFromTan(ll_round(tan_angle, 0.01f));
+ }
+ else
+ {
+ cur_detail = llclamp((S32) (sqrtf(radius)*LLVOVolume::sLODFactor*4.f), 0, 3);
+ }
+ }
return cur_detail;
}
@@ -1280,15 +1295,38 @@ BOOL LLVOVolume::calcLOD()
distance *= F_PI/3.f;
cur_detail = computeLODDetail(ll_round(distance, 0.01f),
- ll_round(radius, 0.01f));
+ ll_round(radius, 0.01f));
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TRIANGLE_COUNT) && mDrawable->getFace(0))
+ {
+ if (isRootEdit() && getChildren().size()>0)
+ {
+ S32 total_tris = getTriangleCount();
+ LLViewerObject::const_child_list_t& child_list = getChildren();
+ for (LLViewerObject::const_child_list_t::const_iterator iter = child_list.begin();
+ iter != child_list.end(); ++iter)
+ {
+ LLViewerObject* childp = *iter;
+ LLVOVolume *child_volp = dynamic_cast<LLVOVolume*>(childp);
+ if (child_volp)
+ {
+ total_tris += child_volp->getTriangleCount();
+ }
+ }
+ setDebugText(llformat("TRIS %d TOTAL %d", getTriangleCount(), total_tris));
+ }
+ else
+ {
+ setDebugText(llformat("TRIS %d", getTriangleCount()));
+ }
+
+ }
if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_LOD_INFO) &&
mDrawable->getFace(0))
{
- //setDebugText(llformat("%.2f:%.2f, %d", mDrawable->mDistanceWRTCamera, radius, cur_detail));
-
- setDebugText(llformat("%d", mDrawable->getFace(0)->getTextureIndex()));
+ // This is a debug display for LODs. Please don't put the texture index here.
+ setDebugText(llformat("%d", cur_detail));
}
if (cur_detail != mLOD)
@@ -1386,7 +1424,8 @@ void LLVOVolume::updateFaceFlags()
BOOL LLVOVolume::setParent(LLViewerObject* parent)
{
BOOL ret = FALSE ;
- if (parent != getParent())
+ LLViewerObject *old_parent = (LLViewerObject*) getParent();
+ if (parent != old_parent)
{
ret = LLViewerObject::setParent(parent);
if (ret && mDrawable)
@@ -1394,6 +1433,7 @@ BOOL LLVOVolume::setParent(LLViewerObject* parent)
gPipeline.markMoved(mDrawable);
gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE);
}
+ updateAnimatedObjectState(old_parent, parent);
}
return ret ;
@@ -3270,6 +3310,176 @@ BOOL LLVOVolume::setIsFlexible(BOOL is_flexible)
}
//----------------------------------------------------------------------------
+// AXON - methods related to extended mesh flags
+
+U32 LLVOVolume::getExtendedMeshFlags() const
+{
+ const LLExtendedMeshParams *param_block =
+ (const LLExtendedMeshParams *)getParameterEntry(LLNetworkData::PARAMS_EXTENDED_MESH);
+ if (param_block)
+ {
+ return param_block->getFlags();
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+void LLVOVolume::setExtendedMeshFlags(U32 flags)
+{
+ U32 curr_flags = getExtendedMeshFlags();
+ if (curr_flags != flags)
+ {
+ bool in_use = (flags != 0);
+ setParameterEntryInUse(LLNetworkData::PARAMS_EXTENDED_MESH, in_use, true);
+ LLExtendedMeshParams *param_block =
+ (LLExtendedMeshParams *)getParameterEntry(LLNetworkData::PARAMS_EXTENDED_MESH);
+ if (param_block)
+ {
+ param_block->setFlags(flags);
+ }
+ parameterChanged(LLNetworkData::PARAMS_EXTENDED_MESH, true);
+ }
+}
+
+bool LLVOVolume::canBeAnimatedObject() const
+{
+ if (!isMesh())
+ {
+ return false;
+ }
+// AXON remove this check if animated object attachments are allowed
+#if 0
+ if (isAttachment())
+ {
+ return false;
+ }
+#endif
+ if (!getVolume())
+ {
+ return false;
+ }
+ const LLMeshSkinInfo* skin = gMeshRepo.getSkinInfo(getVolume()->getParams().getSculptID(), this);
+ if (!skin)
+ {
+ return false;
+ }
+ return true;
+}
+
+bool LLVOVolume::isAnimatedObject() const
+{
+ LLVOVolume *root_vol = (LLVOVolume*)getRootEdit();
+ bool can_be_animated = canBeAnimatedObject();
+ bool root_can_be_animated = root_vol->canBeAnimatedObject();
+ bool root_is_animated = root_vol->getExtendedMeshFlags() & LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG;
+ if (can_be_animated && root_can_be_animated && root_is_animated)
+ {
+ return true;
+ }
+ return false;
+}
+
+// Make sure animated objects in a linkset are consistent. The rules are:
+// Only the root of a linkset can have the animated object flag set
+// Only the root of a linkset can have a control avatar (iff the animated object flag is set)
+// Only skinned mesh volumes can have the animated object flag set, or a control avatar
+bool LLVOVolume::isAnimatedObjectStateConsistent() const
+{
+ if (!canBeAnimatedObject())
+ {
+ if ((getExtendedMeshFlags() & LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG) ||
+ mControlAvatar.notNull())
+ {
+ LL_WARNS("AXON") << "Non animatable object has mesh enabled flag or mControlAvatar. Flags "
+ << getExtendedMeshFlags() << " cav " << mControlAvatar.get() << LL_ENDL;
+ return false;
+ }
+ }
+ if (!isRootEdit())
+ {
+ if ((getExtendedMeshFlags() & LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG) ||
+ mControlAvatar.notNull())
+ {
+ LL_WARNS("AXON") << "Non root object has mesh enabled flag or mControlAvatar. Flags "
+ << getExtendedMeshFlags() << " cav " << mControlAvatar.get() << LL_ENDL;
+ return false;
+ }
+ }
+ // If we get here, we have a potentially animatable root volume.
+ bool is_animation_enabled = getExtendedMeshFlags() & LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG;
+ bool has_control_avatar = (mControlAvatar.notNull());
+ if (is_animation_enabled != has_control_avatar)
+ {
+ LL_WARNS("AXON") << "Inconsistent state: animation enabled " << is_animation_enabled
+ << " has control avatar " << has_control_avatar
+ << " flags " << getExtendedMeshFlags() << " cav " << mControlAvatar.get() << LL_ENDL;
+ return false;
+ }
+ return true;
+}
+
+// Called any time parenting changes for a volume. Update flags and
+// control av accordingly. This is called after parent has been
+// changed to new_parent.
+void LLVOVolume::updateAnimatedObjectState(LLViewerObject *old_parent, LLViewerObject *new_parent)
+{
+ LLVOVolume *old_volp = dynamic_cast<LLVOVolume*>(old_parent);
+ LLVOVolume *new_volp = dynamic_cast<LLVOVolume*>(new_parent);
+
+ // AXON - depending on whether animated objects can be attached,
+ // we may want to include or remove the isAvatar() check.
+ if (new_parent && !new_parent->isAvatar())
+ {
+ // Object should inherit control avatar and animated mesh flag
+ // from parent, so clear them out from our own state
+ if (getExtendedMeshFlags() & LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG)
+ {
+ setExtendedMeshFlags(getExtendedMeshFlags() & ~LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG);
+ }
+ if (mControlAvatar.notNull())
+ {
+ LLControlAvatar *av = mControlAvatar;
+ mControlAvatar = NULL;
+ av->markForDeath();
+ }
+ // If this succeeds now, it's because the new_parent is an animated object
+ if (isAnimatedObject() && getControlAvatar())
+ {
+ getControlAvatar()->addAttachmentOverridesForObject(this);
+ }
+ }
+ if (old_volp && old_volp->isAnimatedObject())
+ {
+ if (old_volp->getControlAvatar())
+ {
+ // We have been removed from an animated object, need to do cleanup.
+ old_volp->getControlAvatar()->removeAttachmentOverridesForObject(this);
+ }
+ }
+
+ if (old_volp)
+ {
+ if (!old_volp->isAnimatedObjectStateConsistent())
+ {
+ LL_WARNS("AXON") << "old_volp failed consistency check" << LL_ENDL;
+ }
+ }
+ if (new_volp)
+ {
+ if (!new_volp->isAnimatedObjectStateConsistent())
+ {
+ LL_WARNS("AXON") << "new_volp failed consistency check" << LL_ENDL;
+ }
+ }
+ if (!isAnimatedObjectStateConsistent())
+ {
+ LL_WARNS("AXON") << "child object failed consistency check" << LL_ENDL;
+ }
+}
+
+//----------------------------------------------------------------------------
void LLVOVolume::generateSilhouette(LLSelectNode* nodep, const LLVector3& view_point)
{
@@ -3330,7 +3540,7 @@ void LLVOVolume::updateRadius()
BOOL LLVOVolume::isAttachment() const
{
- return mState != 0 ;
+ return mAttachmentState != 0 ;
}
BOOL LLVOVolume::isHUDAttachment() const
@@ -3338,7 +3548,7 @@ BOOL LLVOVolume::isHUDAttachment() const
// *NOTE: we assume hud attachment points are in defined range
// since this range is constant for backwards compatibility
// reasons this is probably a reasonable assumption to make
- S32 attachment_id = ATTACHMENT_ID_FROM_STATE(mState);
+ S32 attachment_id = ATTACHMENT_ID_FROM_STATE(mAttachmentState);
return ( attachment_id >= 31 && attachment_id <= 38 );
}
@@ -4092,9 +4302,9 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a&
bool LLVOVolume::treatAsRigged()
{
return isSelected() &&
- isAttachment() &&
- mDrawable.notNull() &&
- mDrawable->isState(LLDrawable::RIGGED);
+ (isAttachment() || isAnimatedObject()) &&
+ mDrawable.notNull() &&
+ mDrawable->isState(LLDrawable::RIGGED);
}
LLRiggedVolume* LLVOVolume::getRiggedVolume()
@@ -4187,6 +4397,9 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
U32 maxJoints = LLSkinningUtil::getMeshJointCount(skin);
LLSkinningUtil::initSkinningMatrixPalette((LLMatrix4*)mat, maxJoints, skin, avatar);
+ S32 rigged_vert_count = 0;
+ S32 rigged_face_count = 0;
+ LLVector4a box_min, box_max;
for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
{
const LLVolumeFace& vol_face = volume->getVolumeFace(i);
@@ -4208,6 +4421,8 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
LL_RECORD_BLOCK_TIME(FTM_SKIN_RIGGED);
U32 max_joints = LLSkinningUtil::getMaxJointCount();
+ rigged_vert_count += dst_face.mNumVertices;
+ rigged_face_count++;
for (U32 j = 0; j < dst_face.mNumVertices; ++j)
{
LLMatrix4a final_mat;
@@ -4227,12 +4442,19 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
min = pos[0];
max = pos[1];
+ if (i==0)
+ {
+ box_min = min;
+ box_max = max;
+ }
for (U32 j = 1; j < dst_face.mNumVertices; ++j)
{
min.setMin(min, pos[j]);
max.setMax(max, pos[j]);
}
+ box_min.setMin(min,box_min);
+ box_max.setMax(max,box_max);
dst_face.mCenter->setAdd(dst_face.mExtents[0], dst_face.mExtents[1]);
dst_face.mCenter->mul(0.5f);
@@ -4252,6 +4474,10 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
}
}
}
+ mExtraDebugText = llformat("rigged %d/%d - box (%f %f %f) (%f %f %f)",
+ rigged_face_count, rigged_vert_count,
+ box_min[0], box_min[1], box_min[2],
+ box_max[0], box_max[1], box_max[2]);
}
U32 LLVOVolume::getPartitionType() const
@@ -4772,11 +4998,35 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
vobj->isMesh() &&
gMeshRepo.getSkinInfo(vobj->getVolume()->getParams().getSculptID(), vobj);
+ if (vobj->isAnimatedObject())
+ {
+ if (!vobj->getControlAvatar())
+ {
+ vobj->linkControlAvatar();
+ }
+ if (vobj->getControlAvatar())
+ {
+ pAvatarVO = vobj->getControlAvatar();
+ }
+ }
+ else
+ {
+ // Not animated but has a control avatar - probably
+ // the checkbox has changed since the last rebuild.
+ if (vobj->getControlAvatar())
+ {
+ vobj->unlinkControlAvatar();
+ }
+ }
+
bool bake_sunlight = LLPipeline::sBakeSunlight && drawablep->isStatic();
+ // AXON why this variable? Only different from rigged if
+ // there are no LLFaces associated with the drawable.
bool is_rigged = false;
- if (rigged && pAvatarVO)
+ // AXON handle NPC case
+ if (rigged && pAvatarVO && !vobj->isAnimatedObject())
{
pAvatarVO->addAttachmentOverridesForObject(vobj);
if (!LLApp::isExiting() && pAvatarVO->isSelf() && debugLoggingEnabled("AvatarAttachments"))
@@ -4802,7 +5052,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
//sum up face verts and indices
drawablep->updateFaceSize(i);
- if (rigged)
+ if (rigged || (vobj->getControlAvatar() && vobj->getControlAvatar()->mPlaying))
{
if (!facep->isState(LLFace::RIGGED))
{ //completely reset vertex buffer
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index a331908320..c972d7770e 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -62,6 +62,8 @@ public:
}
void update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, const LLVolume* src_volume);
+
+ std::string mExtraDebugText;
};
// Base class for implementations of the volume - Primitive, Flexible Object, etc.
@@ -261,10 +263,24 @@ public:
virtual BOOL isMesh() const;
virtual BOOL hasLightTexture() const;
+
BOOL isVolumeGlobal() const;
BOOL canBeFlexible() const;
BOOL setIsFlexible(BOOL is_flexible);
+ // Extended Mesh Properties
+ U32 getExtendedMeshFlags() const;
+ void setExtendedMeshFlags(U32 flags);
+ bool canBeAnimatedObject() const;
+ bool isAnimatedObject() const;
+ bool isAnimatedObjectStateConsistent() const;
+ void updateAnimatedObjectState(LLViewerObject *old_parent, LLViewerObject *new_parent);
+
+ // AXON For animated objects, we need to track animations requested
+ // per-object, then reconcile those to manage the control avatar
+ // animation state.
+ std::map<LLUUID, S32> mObjectSignaledAnimations; // requested state of Animation name/value
+
// Functions that deal with media, or media navigation
// Update this object's media data with the given media data array
@@ -379,6 +395,7 @@ private:
public:
static F32 sLODSlopDistanceFactor;// Changing this to zero, effectively disables the LOD transition slop
static F32 sLODFactor; // LOD scale factor
+ static S32 sForceLOD; // LOD override
static F32 sDistanceFactor; // LOD distance factor
static LLPointer<LLObjectMediaDataClient> sObjectMediaClient;
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index bba36351d9..4cc4b821bf 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -513,11 +513,11 @@ public:
RENDER_DEBUG_TEXTURE_AREA = 0x00000100,
RENDER_DEBUG_FACE_AREA = 0x00000200,
RENDER_DEBUG_PARTICLES = 0x00000400,
- RENDER_DEBUG_GLOW = 0x00000800,
+ RENDER_DEBUG_GLOW = 0x00000800, // not used
RENDER_DEBUG_TEXTURE_ANIM = 0x00001000,
RENDER_DEBUG_LIGHTS = 0x00002000,
RENDER_DEBUG_BATCH_SIZE = 0x00004000,
- RENDER_DEBUG_ALPHA_BINS = 0x00008000,
+ RENDER_DEBUG_ALPHA_BINS = 0x00008000, // not used
RENDER_DEBUG_RAYCAST = 0x00010000,
RENDER_DEBUG_AVATAR_DRAW_INFO = 0x00020000,
RENDER_DEBUG_SHADOW_FRUSTA = 0x00040000,
@@ -531,8 +531,9 @@ public:
RENDER_DEBUG_NORMALS = 0x04000000,
RENDER_DEBUG_LOD_INFO = 0x08000000,
RENDER_DEBUG_RENDER_COMPLEXITY = 0x10000000,
- RENDER_DEBUG_ATTACHMENT_BYTES = 0x20000000,
- RENDER_DEBUG_TEXEL_DENSITY = 0x40000000
+ RENDER_DEBUG_ATTACHMENT_BYTES = 0x20000000, // not used
+ RENDER_DEBUG_TEXEL_DENSITY = 0x40000000,
+ RENDER_DEBUG_TRIANGLE_COUNT = 0x80000000
};
public:
diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml
index ed3cc26851..63e2ed4bb9 100644
--- a/indra/newview/skins/default/xui/en/floater_tools.xml
+++ b/indra/newview/skins/default/xui/en/floater_tools.xml
@@ -2,7 +2,7 @@
<floater
positioning="cascading"
legacy_header_height="18"
- height="590"
+ height="600"
layout="topleft"
bg_opaque_image="Window_NoTitle_Foreground"
bg_alpha_image="Window_NoTitle_Background"
@@ -2131,7 +2131,7 @@ even though the user gets a free copy.
<panel
border="false"
follows="all"
- height="367"
+ height="387"
label="Features"
layout="topleft"
left_delta="0"
@@ -2169,13 +2169,23 @@ even though the user gets a free copy.
Edit object features:
</text>
<check_box
- height="19"
+ height="15"
+ label="Animated Mesh"
+ layout="topleft"
+ left="10"
+ name="Animated Mesh Checkbox Ctrl"
+ tool_tip="Allows rigged mesh objects to be animated independently"
+ top_pad="10"
+ width="121" />
+ <check_box
+ height="10"
label="Flexible Path"
+ follows="left|top"
layout="topleft"
left="10"
name="Flexible1D Checkbox Ctrl"
tool_tip="Allows object to flex about the Z axis (Client-side only)"
- top_pad="20"
+ top_pad="15"
width="121" />
<spinner
follows="left|top"
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 697d27907d..f8b4948697 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -2654,6 +2654,16 @@
parameter="lod info" />
</menu_item_check>
<menu_item_check
+ label="Triangle Count"
+ name="Triangle Count">
+ <menu_item_check.on_check
+ function="Advanced.CheckInfoDisplay"
+ parameter="triangle count" />
+ <menu_item_check.on_click
+ function="Advanced.ToggleInfoDisplay"
+ parameter="triangle count" />
+ </menu_item_check>
+ <menu_item_check
label="Build Queue"
name="Build Queue">
<menu_item_check.on_check
diff --git a/indra/test/test.cpp b/indra/test/test.cpp
index 630af2b73b..e42374d56b 100644
--- a/indra/test/test.cpp
+++ b/indra/test/test.cpp
@@ -34,7 +34,6 @@
*
*/
-
#include "linden_common.h"
#include "llerrorcontrol.h"
#include "lltut.h"
@@ -685,5 +684,4 @@ int main(int argc, char **argv)
return retval;
//delete mycallback;
-
}
diff --git a/scripts/messages/message_template.msg b/scripts/messages/message_template.msg
index c56eaae6fe..18264ee59c 100755
--- a/scripts/messages/message_template.msg
+++ b/scripts/messages/message_template.msg
@@ -8,7 +8,7 @@ version 2.0
// for each type is listed below:
// Low: 423
// Medium: 18
-// High: 29
+// High: 30
// PLEASE UPDATE THIS WHEN YOU ADD A NEW MESSAGE!
@@ -3571,7 +3571,6 @@ version 2.0
}
}
-
// AvatarAppearance - Update visual params
{
AvatarAppearance Low 158 Trusted Zerocoded
@@ -7286,6 +7285,29 @@ version 2.0
// *************************************************************************
+// Object animation messages
+// *************************************************************************
+
+// Note this is basically identical to AvatarAnimation.
+// Needs to be a different message because existing viewers
+// have insufficiently smart handler functions.
+
+// ObjectAnimation - Update animation state
+// simulator --> viewer
+{
+ ObjectAnimation High 30 Trusted Unencoded
+ {
+ Sender Single
+ { ID LLUUID }
+ }
+ {
+ AnimationList Variable
+ { AnimID LLUUID }
+ { AnimSequenceID S32 }
+ }
+}
+
+// *************************************************************************
// Asset storage messages
// *************************************************************************
diff --git a/scripts/messages/message_template.msg.sha1 b/scripts/messages/message_template.msg.sha1
index 5bc06ec042..db87ad5e77 100755
--- a/scripts/messages/message_template.msg.sha1
+++ b/scripts/messages/message_template.msg.sha1
@@ -1 +1 @@
-337f351910b0c8821cb3d447bc6578516a043c80 \ No newline at end of file
+55df2c7135733c5da64ef8f01859b83a433a3a09 \ No newline at end of file
diff --git a/scripts/testing/lsl/axon_test_region_driver.lsl b/scripts/testing/lsl/axon_test_region_driver.lsl
new file mode 100644
index 0000000000..dcf146a9cf
--- /dev/null
+++ b/scripts/testing/lsl/axon_test_region_driver.lsl
@@ -0,0 +1,54 @@
+list buttons = ["anim start", "anim stop", "step", "verbose on", "verbose off", " "];
+string dialogInfo = "\nPlease make a choice.";
+
+key ToucherID;
+integer dialogChannel;
+integer listenHandle;
+integer commandChannel;
+
+default
+{
+ state_entry()
+ {
+ dialogChannel = -1 - (integer)("0x" + llGetSubString( (string)llGetKey(), -7, -1) );
+ commandChannel = -2001;
+ }
+
+ touch_start(integer num_detected)
+ {
+ ToucherID = llDetectedKey(0);
+ llListenRemove(listenHandle);
+ listenHandle = llListen(dialogChannel, "", ToucherID, "");
+ llDialog(ToucherID, dialogInfo, buttons, dialogChannel);
+ //llSetTimerEvent(60.0); // Here we set a time limit for responses
+ }
+
+ listen(integer channel, string name, key id, string message)
+ {
+ if (message == "-")
+ {
+ llDialog(ToucherID, dialogInfo, buttons, dialogChannel);
+ return;
+ }
+
+ llListenRemove(listenHandle);
+ // stop timer since the menu was clicked
+ llSetTimerEvent(0);
+
+ //llOwnerSay("Sending message " + message + " on channel " + (string)commandChannel);
+ llRegionSay(commandChannel, message);
+ }
+
+ timer()
+ {
+ // stop timer
+ llSetTimerEvent(0);
+
+ llListenRemove(listenHandle);
+ //llWhisper(0, "Sorry. You snooze; you lose.");
+ }
+}
+
+// Local Variables:
+// shadow-file-name: "$SW_HOME/axon/scripts/testing/lsl/axon_test_region_driver.lsl"
+// End:
diff --git a/scripts/testing/lsl/cycle_object_animations.lsl b/scripts/testing/lsl/cycle_object_animations.lsl
new file mode 100644
index 0000000000..e7a378889a
--- /dev/null
+++ b/scripts/testing/lsl/cycle_object_animations.lsl
@@ -0,0 +1,118 @@
+integer listenHandle;
+integer verbose;
+integer current_animation_number;
+string NowPlaying;
+
+say_if_verbose(integer channel, string message)
+{
+ if (verbose)
+ {
+ llSay(0, message);
+ }
+}
+
+stop_all_animations()
+{
+ integer count = llGetInventoryNumber(INVENTORY_ANIMATION);
+ string ItemName;
+ string NowPlaying;
+ while (count--)
+ {
+ ItemName = llGetInventoryName(INVENTORY_ANIMATION, count);
+ say_if_verbose(0, "Stopping " + ItemName);
+ llStopObjectAnimation(ItemName);
+ }
+}
+
+start_cycle_animations()
+{
+ current_animation_number = llGetInventoryNumber(INVENTORY_ANIMATION);
+ next_animation(); // Do first iteration without waiting for timer
+ llSetTimerEvent(5.0);
+}
+
+next_animation()
+{
+ string ItemName;
+ if (NowPlaying != "")
+ {
+ say_if_verbose(0, "Stopping " + NowPlaying);
+ llStopObjectAnimation(NowPlaying);
+ }
+ if (current_animation_number--)
+ {
+ ItemName = llGetInventoryName(INVENTORY_ANIMATION, current_animation_number);
+ say_if_verbose(0, "Starting " + ItemName);
+ llStartObjectAnimation(ItemName);
+ NowPlaying = ItemName;
+ }
+ else
+ {
+ // Start again at the top
+ current_animation_number = llGetInventoryNumber(INVENTORY_ANIMATION);
+ }
+}
+
+stop_cycle_animations()
+{
+ llSetTimerEvent(0);
+}
+
+default
+{
+ state_entry()
+ {
+ say_if_verbose(0, "Animated Object here");
+ listenHandle = llListen(-2001,"","","");
+ verbose = 0;
+
+ stop_all_animations();
+ }
+
+ listen(integer channel, string name, key id, string message)
+ {
+ llOwnerSay("got message " + name + " " + (string) id + " " + message);
+ list words = llParseString2List(message,[" "],[]);
+ string command = llList2String(words,0);
+ string option = llList2String(words,1);
+ if (command=="anim")
+ {
+ stop_all_animations();
+ if (option=="start")
+ {
+ start_cycle_animations();
+ }
+ else if (option=="stop")
+ {
+ stop_cycle_animations();
+ }
+ }
+ if (command=="verbose")
+ {
+ if (option=="on")
+ {
+ verbose = 1;
+ }
+ else if (option=="off")
+ {
+ verbose = 0;
+ }
+ }
+ }
+
+ timer()
+ {
+ say_if_verbose(0, "timer triggered");
+ next_animation();
+ }
+
+ touch_start(integer total_number)
+ {
+ say_if_verbose(0, "Touch started.");
+ start_cycle_animations();
+ }
+}
+
+// Local Variables:
+// shadow-file-name: "$SW_HOME/axon/scripts/testing/lsl/cycle_object_animations.lsl"
+// End:
diff --git a/scripts/testing/lsl/move_in_circle_using_llSetRegionPos.lsl b/scripts/testing/lsl/move_in_circle_using_llSetRegionPos.lsl
new file mode 100644
index 0000000000..cc5b899b67
--- /dev/null
+++ b/scripts/testing/lsl/move_in_circle_using_llSetRegionPos.lsl
@@ -0,0 +1,90 @@
+integer listenHandle;
+integer verbose;
+integer num_steps = 12;
+float circle_time = 5.0;
+integer circle_step;
+vector circle_pos;
+vector circle_center;
+float circle_radius;
+
+start_circle(vector center, float radius)
+{
+ vector currentPosition = llGetPos();
+ circle_center = center;
+ circle_radius = radius;
+ circle_step = 0;
+ llSetTimerEvent(circle_time/num_steps);
+ llTargetOmega(<0.0, 0.0, 1.0>, TWO_PI/circle_time, 1.0);
+}
+
+stop_circle()
+{
+ llSetTimerEvent(0);
+ llTargetOmega(<0.0, 0.0, 1.0>, TWO_PI/circle_time, 0.0);
+ llSetRegionPos(circle_center);
+}
+
+next_circle()
+{
+ float rad = (circle_step * TWO_PI)/num_steps;
+ float x = circle_center.x + llCos(rad)*circle_radius;
+ float y = circle_center.y + llSin(rad)*circle_radius;
+ float z = circle_center.z;
+ llSetRegionPos(<x,y,z>);
+ circle_step = (circle_step+1)%num_steps;
+}
+
+default
+{
+ state_entry()
+ {
+ //llSay(0, "Hello, Avatar!");
+ listenHandle = llListen(-2001,"","","");
+ verbose = 0;
+ circle_center = llGetPos();
+ }
+
+ listen(integer channel, string name, key id, string message)
+ {
+ //llOwnerSay("got message " + name + " " + (string) id + " " + message);
+ list words = llParseString2List(message,[" "],[]);
+ string command = llList2String(words,0);
+ string option = llList2String(words,1);
+ if (command=="anim")
+ {
+ if (option=="start")
+ {
+ start_circle(llGetPos(), 3.0);
+ }
+ else if (option=="stop")
+ {
+ stop_circle();
+ }
+ }
+ if (command=="verbose")
+ {
+ if (option=="on")
+ {
+ verbose = 1;
+ }
+ else if (option=="off")
+ {
+ verbose = 0;
+ }
+ }
+ if (command=="step")
+ {
+ llSetTimerEvent(0);
+ next_circle();
+ }
+ }
+
+ timer()
+ {
+ next_circle();
+ }
+}
+
+// Local Variables:
+// shadow-file-name: "$SW_HOME/axon/scripts/testing/lsl/move_in_circle_using_llSetRegionPos.lsl"
+// End: