diff options
Diffstat (limited to 'indra/newview/llcontrolavatar.cpp')
-rw-r--r-- | indra/newview/llcontrolavatar.cpp | 366 |
1 files changed, 366 insertions, 0 deletions
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; +} |