From 2dff12433cc5d42acc8a44e0338e49a9f80c6084 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Thu, 28 Apr 2011 10:09:11 -0500 Subject: [PATCH] Avatar Physics innital commit. No edit panel. SavedSettings not plugged in yet. --- indra/newview/CMakeLists.txt | 2 + indra/newview/character/avatar_lad.xml | 693 +++++++++++++++- indra/newview/llagent.cpp | 5 +- indra/newview/llassetconverter.cpp | 2 +- indra/newview/lldriverparam.h | 2 + indra/newview/llfilepicker.cpp | 10 + indra/newview/llfilepicker.h | 1 + indra/newview/llfloatercustomize.cpp | 12 +- indra/newview/llinventoryactions.cpp | 6 +- indra/newview/llinventorybackup.cpp | 2 + indra/newview/llinventorybridge.cpp | 5 + indra/newview/llinventorybridge.h | 2 + indra/newview/llinventoryview.cpp | 3 + indra/newview/llphysicsmotion.cpp | 747 ++++++++++++++++++ indra/newview/llphysicsmotion.h | 124 +++ indra/newview/llpolymesh.cpp | 118 ++- indra/newview/llpolymorph.cpp | 56 +- indra/newview/llpolymorph.h | 1 + indra/newview/llviewermenu.cpp | 9 + indra/newview/llvoavatar.cpp | 15 +- indra/newview/llvoavatar.h | 2 + indra/newview/llwearable.cpp | 3 + indra/newview/llwearable.h | 3 +- indra/newview/rlvhandler.cpp | 2 +- .../default/textures/inv_item_physics.png | Bin 0 -> 539 bytes .../default/xui/en-us/floater_inventory.xml | 4 + .../default/xui/en-us/menu_inventory.xml | 4 + .../skins/default/xui/en-us/menu_pie_self.xml | 5 + .../skins/default/xui/en-us/menu_viewer.xml | 7 +- 29 files changed, 1821 insertions(+), 24 deletions(-) create mode 100644 indra/newview/llphysicsmotion.cpp create mode 100644 indra/newview/llphysicsmotion.h create mode 100644 indra/newview/skins/default/textures/inv_item_physics.png diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index cc73ffc32..bd7a541fc 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -348,6 +348,7 @@ set(viewer_SOURCE_FILES llpanelweb.cpp llparcelselection.cpp llpatchvertexarray.cpp + llphysicsmotion.cpp llpolymesh.cpp llpolymorph.cpp llprefschat.cpp @@ -822,6 +823,7 @@ set(viewer_HEADER_FILES llpanelweb.h llparcelselection.h llpatchvertexarray.h + llphysicsmotion.h llpolymesh.h llpolymorph.h llprefschat.h diff --git a/indra/newview/character/avatar_lad.xml b/indra/newview/character/avatar_lad.xml index 7c320eceb..b2f3aea4c 100755 --- a/indra/newview/character/avatar_lad.xml +++ b/indra/newview/character/avatar_lad.xml @@ -2923,6 +2923,8 @@ id="40" group="1" name="Male_Head" + wearable="shape" + edit_group="driven" value_min="0" value_max="1"> @@ -3508,6 +3510,8 @@ id="104" group="1" name="Big_Belly_Torso" + wearable="shape" + edit_group="driven" value_min="0" value_max="1"> @@ -3824,6 +3828,8 @@ id="855" group="1" name="Love_Handles" + wearable="shape" + edit_group="driven" value_default="0" value_min="-1" value_max="2"> @@ -3879,6 +3885,8 @@ id="100" group="1" name="Male_Torso" + wearable="shape" + edit_group="driven" label_min="Male_Torso" value_min="0" value_max="1"> @@ -4047,9 +4055,66 @@ - + + + + + + + + + + + + + + + + + + + @@ -4537,15 +4607,62 @@ id="153" group="1" name="Male_Legs" + wearable="shape" + edit_group="driven" value_min="0" value_max="1"> - - + + + + + + + + + + + + + + + + + @@ -4828,6 +4946,8 @@ id="852" group="1" name="skirt_bigbutt" + wearable="skirt" + edit_group="driven" label="bigbutt skirt" label_min="less" label_max="more" @@ -4840,6 +4960,8 @@ id="849" group="1" name="skirt_belly" + wearable="skirt" + edit_group="driven" label="big belly skirt" value_min="0" value_max="1"> @@ -4849,6 +4971,8 @@ @@ -4859,6 +4983,8 @@ id="851" group="1" name="skirt_chubby" + wearable="skirt" + edit_group="driven" label_min="less" label_max="more" value_min="0" @@ -4871,6 +4997,8 @@ id="856" group="1" name="skirt_lovehandles" + wearable="skirt" + edit_group="driven" label_min="less" label_max="more" value_min="-1" @@ -4888,11 +5016,32 @@ id="857" group="1" name="skirt_male" + wearable="skirt" + edit_group="driven" value_min="0" value_max="1"> - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 5917d402f..39da9489f 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -7306,7 +7306,8 @@ void LLAgent::createStandardWearables(BOOL female) TRUE, //WT_UNDERPANTS FALSE, //WT_SKIRT FALSE, //WT_ALPHA - FALSE //WT_TATTOO + FALSE, //WT_TATTOO + FALSE, //WT_PHYSICS }; for( S32 i=0; i < WT_COUNT; i++ ) @@ -7918,6 +7919,7 @@ void LLAgent::setWearableOutfit( wearables_to_remove[WT_SKIRT] = remove && gRlvWearableLocks.canRemove(WT_SKIRT); wearables_to_remove[WT_ALPHA] = remove && gRlvWearableLocks.canRemove(WT_ALPHA); wearables_to_remove[WT_TATTOO] = remove && gRlvWearableLocks.canRemove(WT_TATTOO); + wearables_to_remove[WT_PHYSICS] = remove && gRlvWearableLocks.canRemove(WT_PHYSICS); // [/RLVa:KB] S32 count = wearables.count(); @@ -8199,6 +8201,7 @@ void LLAgent::userRemoveAllClothesStep2( BOOL proceed, void* userdata ) gAgent.removeWearable( WT_SKIRT ); gAgent.removeWearable( WT_ALPHA ); gAgent.removeWearable( WT_TATTOO ); + gAgent.removeWearable( WT_PHYSICS ); } } diff --git a/indra/newview/llassetconverter.cpp b/indra/newview/llassetconverter.cpp index 53c56a49c..73da5cd26 100644 --- a/indra/newview/llassetconverter.cpp +++ b/indra/newview/llassetconverter.cpp @@ -144,7 +144,7 @@ LLAssetType::EType LLAssetConverter::convert(std::string src_filename, std::stri return LLAssetType::AT_NONE; } } - else if(exten == "eyes" || exten == "gloves" || exten == "hair" || exten == "jacket" || exten == "pants" || exten == "shape" || exten == "shirt" || exten == "shoes" || exten == "skin" || exten == "skirt" || exten == "socks" || exten == "underpants" || exten == "undershirt" || exten == "bodypart" || exten == "clothing") + else if(exten == "eyes" || exten == "gloves" || exten == "hair" || exten == "jacket" || exten == "pants" || exten == "shape" || exten == "shirt" || exten == "shoes" || exten == "skin" || exten == "skirt" || exten == "socks" || exten == "underpants" || exten == "undershirt" || exten == "bodypart" || exten == "clothing" || exten == "physics") { asset_type = LLAssetType::AT_CLOTHING; if(!copyFile(src_filename, filename)) diff --git a/indra/newview/lldriverparam.h b/indra/newview/lldriverparam.h index 7bc0c1544..2e53ce563 100644 --- a/indra/newview/lldriverparam.h +++ b/indra/newview/lldriverparam.h @@ -35,6 +35,7 @@ #include "llviewervisualparam.h" +class LLPhysicsMotion; class LLVOAvatar; //----------------------------------------------------------------------------- @@ -78,6 +79,7 @@ protected: class LLDriverParam : public LLViewerVisualParam { + friend class LLPhysicsMotion; // physics motion needs to access driven params directly. public: LLDriverParam(LLVOAvatar *avatarp); ~LLDriverParam(); diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index 8648eef7c..5cea197ca 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -693,6 +693,16 @@ BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename) L"Asset Blacklists (*.blacklist)\0*.blacklist\0" \ L"\0"; break; + case FFSAVE_PHYSICS: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.phy", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"phy"; + mOFN.lpstrFilter = + L"Landmarks (*.phy)\0*.phy\0" \ + L"\0"; + break; // default: return FALSE; diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h index ea1e61fc2..feba53423 100644 --- a/indra/newview/llfilepicker.h +++ b/indra/newview/llfilepicker.h @@ -139,6 +139,7 @@ public: FFSAVE_LANDMARK = 34, FFSAVE_AO = 35, FFSAVE_BLACKLIST = 36, + FFSAVE_PHYSICS = 37, // }; diff --git a/indra/newview/llfloatercustomize.cpp b/indra/newview/llfloatercustomize.cpp index 39d3ce5ab..2cc35f404 100644 --- a/indra/newview/llfloatercustomize.cpp +++ b/indra/newview/llfloatercustomize.cpp @@ -405,7 +405,14 @@ enum ESubpart { SUBPART_UNDERPANTS, SUBPART_SKIRT, SUBPART_ALPHA, - SUBPART_TATTOO + SUBPART_TATTOO, + SUBPART_PHYSICS_BREASTS_UPDOWN, + SUBPART_PHYSICS_BREASTS_INOUT, + SUBPART_PHYSICS_BREASTS_LEFTRIGHT, + SUBPART_PHYSICS_BELLY_UPDOWN, + SUBPART_PHYSICS_BUTT_UPDOWN, + SUBPART_PHYSICS_BUTT_LEFTRIGHT, + SUBPART_PHYSICS_ADVANCED }; struct LLSubpart @@ -926,6 +933,7 @@ ESubpart LLPanelEditWearable::getDefaultSubpart() case WT_SKIRT: return SUBPART_SKIRT; case WT_ALPHA: return SUBPART_ALPHA; case WT_TATTOO: return SUBPART_TATTOO; + case WT_PHYSICS: return SUBPART_PHYSICS_BELLY_UPDOWN; default: llassert(0); return SUBPART_SHAPE_WHOLE; } @@ -1708,6 +1716,7 @@ LLFloaterCustomize::LLFloaterCustomize() factory_map["Skirt"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, WT_SKIRT) ) ); factory_map["Alpha"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, WT_ALPHA))); factory_map["Tattoo"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, WT_TATTOO))); + factory_map["Physics"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, WT_PHYSICS))); LLUICtrlFactory::getInstance()->buildFloater(this, "floater_customize.xml", &factory_map); } @@ -1741,6 +1750,7 @@ BOOL LLFloaterCustomize::postBuild() childSetTabChangeCallback("customize tab container", "Skirt", onTabChanged, (void*)WT_SKIRT, onTabPrecommit ); childSetTabChangeCallback("customize tab container", "Alpha", onTabChanged, (void*)WT_ALPHA, onTabPrecommit); childSetTabChangeCallback("customize tab container", "Tattoo", onTabChanged, (void*)WT_TATTOO, onTabPrecommit); + childSetTabChangeCallback("customize tab container", "Physics", onTabChanged, (void*)WT_PHYSICS, onTabPrecommit); // Remove underwear panels for teens if (gAgent.isTeen()) diff --git a/indra/newview/llinventoryactions.cpp b/indra/newview/llinventoryactions.cpp index 4c41ddb66..b770a531d 100644 --- a/indra/newview/llinventoryactions.cpp +++ b/indra/newview/llinventoryactions.cpp @@ -462,7 +462,11 @@ void do_create(LLInventoryModel *model, LLInventoryPanel *ptr, std::string type, LLUUID parent_id = self ? self->getUUID() : gInventory.findCategoryUUIDForType(LLAssetType::AT_BODYPART); LLFolderBridge::createWearable(parent_id, WT_EYES); } - + else if ("physics" == type) + { + LLUUID parent_id = self ? self->getUUID() : gInventory.findCategoryUUIDForType(LLAssetType::AT_CLOTHING); + LLFolderBridge::createWearable(parent_id, WT_PHYSICS); + } ptr->getRootFolder()->setNeedsAutoRename(TRUE); } diff --git a/indra/newview/llinventorybackup.cpp b/indra/newview/llinventorybackup.cpp index 4ad9e79bb..a5ce38e59 100644 --- a/indra/newview/llinventorybackup.cpp +++ b/indra/newview/llinventorybackup.cpp @@ -209,6 +209,8 @@ LLFilePicker::ESaveFilter LLInventoryBackup::getSaveFilter(LLInventoryItem* item return LLFilePicker::FFSAVE_UNDERPANTS; case WT_UNDERSHIRT: return LLFilePicker::FFSAVE_UNDERSHIRT; + case WT_PHYSICS: + return LLFilePicker::FFSAVE_PHYSICS; default: return LLFilePicker::FFSAVE_ALL; } diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 3ac7342ae..3455caf19 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -186,6 +186,7 @@ std::string ICON_NAME[ICON_NAME_COUNT] = "inv_item_skirt.tga", "inv_item_alpha.tga", "inv_item_tattoo.tga", + "inv_item_physics.png", "inv_item_animation.tga", "inv_item_gesture.tga", @@ -2712,6 +2713,10 @@ void LLFolderBridge::createNewEyes(void* user_data) LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_EYES); } +void LLFolderBridge::createNewPhysics(void* user_data) +{ + LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_PHYSICS); +} // static void LLFolderBridge::createWearable(LLFolderBridge* bridge, EWearableType type) { diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index e9f131f68..dcadc2781 100755 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -72,6 +72,7 @@ enum EInventoryIcon CLOTHING_SKIRT_ICON_NAME, CLOTHING_ALPHA_ICON_NAME, CLOTHING_TATTOO_ICON_NAME, + CLOTHING_PHYSICS_ICON_NAME, ANIMATION_ICON_NAME, GESTURE_ICON_NAME, @@ -375,6 +376,7 @@ protected: static void createNewSkin(void* user_data); static void createNewHair(void* user_data); static void createNewEyes(void* user_data); + static void createNewPhysics(void* user_data); BOOL checkFolderForContentsOfType(LLInventoryModel* model, LLInventoryCollectFunctor& typeToCheck); diff --git a/indra/newview/llinventoryview.cpp b/indra/newview/llinventoryview.cpp index 1e9ce663a..1d89872c9 100644 --- a/indra/newview/llinventoryview.cpp +++ b/indra/newview/llinventoryview.cpp @@ -1521,6 +1521,9 @@ std::string get_item_icon_name(LLAssetType::EType asset_type, case WT_TATTOO: idx = CLOTHING_TATTOO_ICON_NAME; break; + case WT_PHYSICS: + idx = CLOTHING_PHYSICS_ICON_NAME; + break; default: // no-op, go with choice above break; diff --git a/indra/newview/llphysicsmotion.cpp b/indra/newview/llphysicsmotion.cpp new file mode 100644 index 000000000..59434a1f1 --- /dev/null +++ b/indra/newview/llphysicsmotion.cpp @@ -0,0 +1,747 @@ +/** + * @file llphysicsmotion.cpp + * @brief Implementation of LLPhysicsMotion class. + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +//----------------------------------------------------------------------------- +// Header Files +//----------------------------------------------------------------------------- +#include "llviewerprecompiledheaders.h" +#include "linden_common.h" + +#include "m3math.h" +#include "v3dmath.h" + +#include "llphysicsmotion.h" +#include "llagent.h" +#include "llcharacter.h" +#include "llviewercontrol.h" +#include "llviewervisualparam.h" +#include "llvoavatar.h" +#include "lldriverparam.h" + +typedef std::map controller_map_t; +typedef std::map default_controller_map_t; + +#define MIN_REQUIRED_PIXEL_AREA_AVATAR_PHYSICS_MOTION 0.f +#define TIME_ITERATION_STEP 0.1f + +inline F64 llsgn(const F64 a) +{ + if (a >= 0) + return 1; + return -1; +} + +/* + At a high level, this works by setting temporary parameters that are not stored + in the avatar's list of params, and are not conveyed to other users. We accomplish + this by creating some new temporary driven params inside avatar_lad that are then driven + by the actual params that the user sees and sets. For example, in the old system, + the user sets a param called breast bouyancy, which controls the Z value of the breasts. + In our new system, the user still sets the breast bouyancy, but that param is redefined + as a driver param so that affects a new temporary driven param that the bounce is applied + to. +*/ + +class LLPhysicsMotion +{ +public: + /* + param_driver_name: The param that controls the params that are being affected by the physics. + joint_name: The joint that the body part is attached to. The joint is + used to determine the orientation (rotation) of the body part. + + character: The avatar that this physics affects. + + motion_direction_vec: The direction (in world coordinates) that determines the + motion. For example, (0,0,1) is up-down, and means that up-down motion is what + determines how this joint moves. + + controllers: The various settings (e.g. spring force, mass) that determine how + the body part behaves. + */ + LLPhysicsMotion(const std::string ¶m_driver_name, + const std::string &joint_name, + LLCharacter *character, + const LLVector3 &motion_direction_vec, + const controller_map_t &controllers) : + mParamDriverName(param_driver_name), + mJointName(joint_name), + mMotionDirectionVec(motion_direction_vec), + mParamDriver(NULL), + mParamControllers(controllers), + mCharacter(character), + mLastTime(0), + mPosition_local(0), + mVelocityJoint_local(0), + mPositionLastUpdate_local(0) + { + mJointState = new LLJointState; + } + + BOOL initialize(); + + ~LLPhysicsMotion() {} + + BOOL onUpdate(F32 time, bool &bHandled); + + LLPointer getJointState() + { + return mJointState; + } +protected: + F32 getParamValue(const std::string& controller_key) + { + const controller_map_t::const_iterator& entry = mParamControllers.find(controller_key); + if (entry == mParamControllers.end()) + { + return sDefaultController[controller_key]; + } + const std::string& param_name = (*entry).second.c_str(); + return mCharacter->getVisualParamWeight(param_name.c_str()); + } + void setParamValue(LLViewerVisualParam *param, + const F32 new_value_local, + F32 behavior_maxeffect); + + F32 toLocal(const LLVector3 &world); + F32 calculateVelocity_local(); + F32 calculateAcceleration_local(F32 velocity_local); +private: + const std::string mParamDriverName; + const std::string mParamControllerName; + const LLVector3 mMotionDirectionVec; + const std::string mJointName; + + F32 mPosition_local; + F32 mVelocityJoint_local; // How fast the joint is moving + F32 mAccelerationJoint_local; // Acceleration on the joint + + F32 mVelocity_local; // How fast the param is moving + F32 mPositionLastUpdate_local; + LLVector3 mPosition_world; + + LLViewerVisualParam *mParamDriver; + const controller_map_t mParamControllers; + + LLPointer mJointState; + LLCharacter *mCharacter; + + F32 mLastTime; + + static default_controller_map_t sDefaultController; +}; + +default_controller_map_t initDefaultController() +{ + default_controller_map_t controller; + controller["Mass"] = 0.2f; + controller["Gravity"] = 0.0f; + controller["Damping"] = .05f; + controller["Drag"] = 0.15f; + controller["MaxEffect"] = 0.1f; + controller["Spring"] = 0.1f; + controller["Gain"] = 10.0f; + return controller; +} + +default_controller_map_t LLPhysicsMotion::sDefaultController = initDefaultController(); + +BOOL LLPhysicsMotion::initialize() +{ + if (!mJointState->setJoint(mCharacter->getJoint(mJointName.c_str()))) + return FALSE; + mJointState->setUsage(LLJointState::ROT); + + mParamDriver = (LLViewerVisualParam*)mCharacter->getVisualParam(mParamDriverName.c_str()); + if (mParamDriver == NULL) + { + llinfos << "Failure reading in [ " << mParamDriverName << " ]" << llendl; + return FALSE; + } + + return TRUE; +} + +LLPhysicsMotionController::LLPhysicsMotionController(const LLUUID &id) : + LLMotion(id), + mCharacter(NULL) +{ + mName = "breast_motion"; +} + +LLPhysicsMotionController::~LLPhysicsMotionController() +{ + for (motion_vec_t::iterator iter = mMotions.begin(); + iter != mMotions.end(); + ++iter) + { + delete (*iter); + } +} + +BOOL LLPhysicsMotionController::onActivate() +{ + return TRUE; +} + +void LLPhysicsMotionController::onDeactivate() +{ +} + +LLMotion::LLMotionInitStatus LLPhysicsMotionController::onInitialize(LLCharacter *character) +{ + mCharacter = character; + + mMotions.clear(); + + // Breast Cleavage + { + controller_map_t controller; + controller["Mass"] = "Breast_Physics_Mass"; + controller["Gravity"] = "Breast_Physics_Gravity"; + controller["Drag"] = "Breast_Physics_Drag"; + controller["Damping"] = "Breast_Physics_InOut_Damping"; + controller["MaxEffect"] = "Breast_Physics_InOut_Max_Effect"; + controller["Spring"] = "Breast_Physics_InOut_Spring"; + controller["Gain"] = "Breast_Physics_InOut_Gain"; + LLPhysicsMotion *motion = new LLPhysicsMotion("Breast_Physics_InOut_Controller", + "mChest", + character, + LLVector3(-1,0,0), + controller); + if (!motion->initialize()) + { + llassert_always(FALSE); + return STATUS_FAILURE; + } + addMotion(motion); + } + + // Breast Bounce + { + controller_map_t controller; + controller["Mass"] = "Breast_Physics_Mass"; + controller["Gravity"] = "Breast_Physics_Gravity"; + controller["Drag"] = "Breast_Physics_Drag"; + controller["Damping"] = "Breast_Physics_UpDown_Damping"; + controller["MaxEffect"] = "Breast_Physics_UpDown_Max_Effect"; + controller["Spring"] = "Breast_Physics_UpDown_Spring"; + controller["Gain"] = "Breast_Physics_UpDown_Gain"; + LLPhysicsMotion *motion = new LLPhysicsMotion("Breast_Physics_UpDown_Controller", + "mChest", + character, + LLVector3(0,0,1), + controller); + if (!motion->initialize()) + { + llassert_always(FALSE); + return STATUS_FAILURE; + } + addMotion(motion); + } + + // Breast Sway + { + controller_map_t controller; + controller["Mass"] = "Breast_Physics_Mass"; + controller["Gravity"] = "Breast_Physics_Gravity"; + controller["Drag"] = "Breast_Physics_Drag"; + controller["Damping"] = "Breast_Physics_LeftRight_Damping"; + controller["MaxEffect"] = "Breast_Physics_LeftRight_Max_Effect"; + controller["Spring"] = "Breast_Physics_LeftRight_Spring"; + controller["Gain"] = "Breast_Physics_LeftRight_Gain"; + LLPhysicsMotion *motion = new LLPhysicsMotion("Breast_Physics_LeftRight_Controller", + "mChest", + character, + LLVector3(0,-1,0), + controller); + if (!motion->initialize()) + { + llassert_always(FALSE); + return STATUS_FAILURE; + } + addMotion(motion); + } + // Butt Bounce + { + controller_map_t controller; + controller["Mass"] = "Butt_Physics_Mass"; + controller["Gravity"] = "Butt_Physics_Gravity"; + controller["Drag"] = "Butt_Physics_Drag"; + controller["Damping"] = "Butt_Physics_UpDown_Damping"; + controller["MaxEffect"] = "Butt_Physics_UpDown_Max_Effect"; + controller["Spring"] = "Butt_Physics_UpDown_Spring"; + controller["Gain"] = "Butt_Physics_UpDown_Gain"; + LLPhysicsMotion *motion = new LLPhysicsMotion("Butt_Physics_UpDown_Controller", + "mPelvis", + character, + LLVector3(0,0,-1), + controller); + if (!motion->initialize()) + { + llassert_always(FALSE); + return STATUS_FAILURE; + } + addMotion(motion); + } + + // Butt LeftRight + { + controller_map_t controller; + controller["Mass"] = "Butt_Physics_Mass"; + controller["Gravity"] = "Butt_Physics_Gravity"; + controller["Drag"] = "Butt_Physics_Drag"; + controller["Damping"] = "Butt_Physics_LeftRight_Damping"; + controller["MaxEffect"] = "Butt_Physics_LeftRight_Max_Effect"; + controller["Spring"] = "Butt_Physics_LeftRight_Spring"; + controller["Gain"] = "Butt_Physics_LeftRight_Gain"; + LLPhysicsMotion *motion = new LLPhysicsMotion("Butt_Physics_LeftRight_Controller", + "mPelvis", + character, + LLVector3(0,-1,0), + controller); + if (!motion->initialize()) + { + llassert_always(FALSE); + return STATUS_FAILURE; + } + addMotion(motion); + } + + // Belly Bounce + { + controller_map_t controller; + controller["Mass"] = "Belly_Physics_Mass"; + controller["Gravity"] = "Belly_Physics_Gravity"; + controller["Drag"] = "Belly_Physics_Drag"; + controller["Damping"] = "Belly_Physics_UpDown_Damping"; + controller["MaxEffect"] = "Belly_Physics_UpDown_Max_Effect"; + controller["Spring"] = "Belly_Physics_UpDown_Spring"; + controller["Gain"] = "Belly_Physics_UpDown_Gain"; + LLPhysicsMotion *motion = new LLPhysicsMotion("Belly_Physics_UpDown_Controller", + "mPelvis", + character, + LLVector3(0,0,-1), + controller); + if (!motion->initialize()) + { + llassert_always(FALSE); + return STATUS_FAILURE; + } + addMotion(motion); + } + + return STATUS_SUCCESS; +} + +void LLPhysicsMotionController::addMotion(LLPhysicsMotion *motion) +{ + addJointState(motion->getJointState()); + mMotions.push_back(motion); +} + +F32 LLPhysicsMotionController::getMinPixelArea() +{ + return MIN_REQUIRED_PIXEL_AREA_AVATAR_PHYSICS_MOTION; +} + +// Local space means "parameter space". +F32 LLPhysicsMotion::toLocal(const LLVector3 &world) +{ + LLJoint *joint = mJointState->getJoint(); + const LLQuaternion rotation_world = joint->getWorldRotation(); + + LLVector3 dir_world = mMotionDirectionVec * rotation_world; + dir_world.normalize(); + return world * dir_world; +} + +F32 LLPhysicsMotion::calculateVelocity_local() +{ + const F32 world_to_model_scale = 100.0f; + LLJoint *joint = mJointState->getJoint(); + const LLVector3 position_world = joint->getWorldPosition(); + const LLQuaternion rotation_world = joint->getWorldRotation(); + const LLVector3 last_position_world = mPosition_world; + const LLVector3 positionchange_world = (position_world-last_position_world) * world_to_model_scale; + const LLVector3 velocity_world = positionchange_world; + const F32 velocity_local = toLocal(velocity_world); + return velocity_local; +} + +F32 LLPhysicsMotion::calculateAcceleration_local(const F32 velocity_local) +{ +// const F32 smoothing = getParamValue("Smoothing"); + static const F32 smoothing = 3.0f; // Removed smoothing param since it's probably not necessary + const F32 acceleration_local = velocity_local - mVelocityJoint_local; + + const F32 smoothed_acceleration_local = + acceleration_local * 1.0/smoothing + + mAccelerationJoint_local * (smoothing-1.0)/smoothing; + + return smoothed_acceleration_local; +} + +BOOL LLPhysicsMotionController::onUpdate(F32 time, U8* joint_mask) +{ + // Skip if disabled globally. + /*if (!gSavedSettings.getBOOL("AvatarPhysics")) + { + return TRUE; + }*/ + + BOOL update_visuals = FALSE; + bool physics_handled = false; + for (motion_vec_t::iterator iter = mMotions.begin(); + iter != mMotions.end(); + ++iter) + { + LLPhysicsMotion *motion = (*iter); + bool bHandled; + update_visuals |= motion->onUpdate(time,bHandled); + physics_handled |= bHandled; + } + + if (update_visuals) + mCharacter->updateVisualParams(); + + if(!physics_handled && mCharacter) //If absolutely nothing was done, and it wasn't due to timers/lod + ((LLVOAvatar*)mCharacter)->idleUpdateBoobEffect(); + return TRUE; +} + + +// Return TRUE if character has to update visual params. +BOOL LLPhysicsMotion::onUpdate(F32 time, bool &bHandled) +{ + bHandled = false; + // static FILE *mFileWrite = fopen("c:\\temp\\avatar_data.txt","w"); + + if (!mParamDriver) + return FALSE; + + if (!mLastTime) + { + mLastTime = time; + return FALSE; + } + + //////////////////////////////////////////////////////////////////////////////// + // Get all parameters and settings + // + + const F32 time_delta = time - mLastTime; + + bHandled = true; + // Don't update too frequently, to avoid precision errors from small time slices. + if (time_delta <= .01) + { + return FALSE; + } + + // If less than 1FPS, we don't want to be spending time updating physics at all. + if (time_delta > 1.0) + { + mLastTime = time; + return FALSE; + } + + // Higher LOD is better. This controls the granularity + // and frequency of updates for the motions. + const F32 lod_factor = LLVOAvatar::sPhysicsLODFactor; + if (lod_factor == 0) + { + return TRUE; + } + + LLJoint *joint = mJointState->getJoint(); + + const F32 behavior_mass = getParamValue("Mass"); + const F32 behavior_gravity = getParamValue("Gravity"); + const F32 behavior_spring = getParamValue("Spring"); + const F32 behavior_gain = getParamValue("Gain"); + const F32 behavior_damping = getParamValue("Damping"); + const F32 behavior_drag = getParamValue("Drag"); + const BOOL physics_test = FALSE; // Enable this to simulate bouncing on all parts. + + F32 behavior_maxeffect = getParamValue("MaxEffect"); + if (physics_test) + behavior_maxeffect = 1.0f; + + // Normalize the param position to be from [0,1]. + // We have to use normalized values because there may be more than one driven param, + // and each of these driven params may have its own range. + // This means we'll do all our calculations in normalized [0,1] local coordinates. + const F32 position_user_local = (mParamDriver->getWeight() - mParamDriver->getMinWeight()) / (mParamDriver->getMaxWeight() - mParamDriver->getMinWeight()); + + // + // End parameters and settings + //////////////////////////////////////////////////////////////////////////////// + + + //////////////////////////////////////////////////////////////////////////////// + // Calculate velocity and acceleration in parameter space. + // + + //const F32 velocity_joint_local = calculateVelocity_local(time_iteration_step); + const F32 velocity_joint_local = calculateVelocity_local(); + const F32 acceleration_joint_local = calculateAcceleration_local(velocity_joint_local); + + // + // End velocity and acceleration + //////////////////////////////////////////////////////////////////////////////// + + BOOL update_visuals = FALSE; + + // Break up the physics into a bunch of iterations so that differing framerates will show + // roughly the same behavior. + for (F32 time_iteration = 0; time_iteration <= time_delta; time_iteration += TIME_ITERATION_STEP) + { + F32 time_iteration_step = TIME_ITERATION_STEP; + if (time_iteration + TIME_ITERATION_STEP > time_delta) + { + time_iteration_step = time_delta-time_iteration; + } + + // mPositon_local should be in normalized 0,1 range already. Just making sure... + const F32 position_current_local = llclamp(mPosition_local, + 0.0f, + 1.0f); + // If the effect is turned off then don't process unless we need one more update + // to set the position to the default (i.e. user) position. + if ((behavior_maxeffect == 0) && (position_current_local == position_user_local)) + { + bHandled = false; //Let emerald boob stuff do its thing, possibly. + return update_visuals; + } + + //////////////////////////////////////////////////////////////////////////////// + // Calculate the total force + // + + // Spring force is a restoring force towards the original user-set breast position. + // F = kx + const F32 spring_length = position_current_local - position_user_local; + const F32 force_spring = -spring_length * behavior_spring; + + // Acceleration is the force that comes from the change in velocity of the torso. + // F = ma + const F32 force_accel = behavior_gain * (acceleration_joint_local * behavior_mass); + + // Gravity always points downward in world space. + // F = mg + const LLVector3 gravity_world(0,0,1); + const F32 force_gravity = (toLocal(gravity_world) * behavior_gravity * behavior_mass); + + // Damping is a restoring force that opposes the current velocity. + // F = -kv + const F32 force_damping = -behavior_damping * mVelocity_local; + + // Drag is a force imparted by velocity (intuitively it is similar to wind resistance) + // F = .5kv^2 + const F32 force_drag = .5*behavior_drag*velocity_joint_local*velocity_joint_local*llsgn(velocity_joint_local); + + const F32 force_net = (force_accel + + force_gravity + + force_spring + + force_damping + + force_drag); + + // + // End total force + //////////////////////////////////////////////////////////////////////////////// + + + //////////////////////////////////////////////////////////////////////////////// + // Calculate new params + // + + // Calculate the new acceleration based on the net force. + // a = F/m + const F32 acceleration_new_local = force_net / behavior_mass; + static const F32 max_velocity = 100.0f; // magic number, used to be customizable. + F32 velocity_new_local = mVelocity_local + acceleration_new_local*time_iteration_step; + velocity_new_local = llclamp(velocity_new_local, + -max_velocity, max_velocity); + + // Temporary debugging setting to cause all avatars to move, for profiling purposes. + if (physics_test) + { + velocity_new_local = sin(time*4.0); + } + // Calculate the new parameters, or remain unchanged if max speed is 0. + F32 position_new_local = position_current_local + velocity_new_local*time_iteration_step; + if (behavior_maxeffect == 0) + position_new_local = position_user_local; + + // Zero out the velocity if the param is being pushed beyond its limits. + if ((position_new_local < 0 && velocity_new_local < 0) || + (position_new_local > 1 && velocity_new_local > 0)) + { + velocity_new_local = 0; + } + + // Check for NaN values. A NaN value is detected if the variables doesn't equal itself. + // If NaN, then reset everything. + if ((mPosition_local != mPosition_local) || + (mVelocity_local != mVelocity_local) || + (position_new_local != position_new_local)) + { + position_new_local = 0; + mVelocity_local = 0; + mVelocityJoint_local = 0; + mAccelerationJoint_local = 0; + mPosition_local = 0; + mPosition_world = LLVector3(0,0,0); + } + + const F32 position_new_local_clamped = llclamp(position_new_local, + 0.0f, + 1.0f); + + LLDriverParam *driver_param = dynamic_cast(mParamDriver); + llassert_always(driver_param); + if (driver_param) + { + // If this is one of our "hidden" driver params, then make sure it's + // the default value. + if ((driver_param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) && + (driver_param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT)) + { + mCharacter->setVisualParamWeight(driver_param, + 0, + FALSE); + } + for (LLDriverParam::entry_list_t::iterator iter = driver_param->mDriven.begin(); + iter != driver_param->mDriven.end(); + ++iter) + { + LLDrivenEntry &entry = (*iter); + LLViewerVisualParam *driven_param = entry.mParam; + setParamValue(driven_param,position_new_local_clamped, behavior_maxeffect); + } + } + + // + // End calculate new params + //////////////////////////////////////////////////////////////////////////////// + + //////////////////////////////////////////////////////////////////////////////// + // Conditionally update the visual params + // + + // Updating the visual params (i.e. what the user sees) is fairly expensive. + // So only update if the params have changed enough, and also take into account + // the graphics LOD settings. + + // For non-self, if the avatar is small enough visually, then don't update. + const F32 area_for_max_settings = 0.0; + const F32 area_for_min_settings = 1400.0; + const F32 area_for_this_setting = area_for_max_settings + (area_for_min_settings-area_for_max_settings)*(1.0-lod_factor); + const F32 pixel_area = fsqrtf(mCharacter->getPixelArea()); + + const BOOL is_self = (dynamic_cast(mCharacter) != NULL && ((LLVOAvatar*)mCharacter)->isSelf()); + if ((pixel_area > area_for_this_setting) || is_self) + { + const F32 position_diff_local = llabs(mPositionLastUpdate_local-position_new_local_clamped); + const F32 min_delta = (1.0001f-lod_factor)*0.4f; + if (llabs(position_diff_local) > min_delta) + { + update_visuals = TRUE; + mPositionLastUpdate_local = position_new_local; + } + } + + // + // End update visual params + //////////////////////////////////////////////////////////////////////////////// + + mVelocity_local = velocity_new_local; + mAccelerationJoint_local = acceleration_joint_local; + mPosition_local = position_new_local; + } + mLastTime = time; + mPosition_world = joint->getWorldPosition(); + mVelocityJoint_local = velocity_joint_local; + + + /* + // Write out debugging info into a spreadsheet. + if (mFileWrite != NULL && is_self) + { + fprintf(mFileWrite,"%f\t%f\t%f \t\t%f \t\t%f\t%f\t%f\t \t\t%f\t%f\t%f\t%f\t%f \t\t%f\t%f\t%f\n", + position_new_local, + velocity_new_local, + acceleration_new_local, + + time_delta, + + mPosition_world[0], + mPosition_world[1], + mPosition_world[2], + + force_net, + force_spring, + force_accel, + force_damping, + force_drag, + + spring_length, + velocity_joint_local, + acceleration_joint_local + ); + } + */ + + return update_visuals; +} + +// Range of new_value_local is assumed to be [0 , 1] normalized. +void LLPhysicsMotion::setParamValue(LLViewerVisualParam *param, + F32 new_value_normalized, + F32 behavior_maxeffect) +{ + const F32 value_min_local = param->getMinWeight(); + const F32 value_max_local = param->getMaxWeight(); + const F32 min_val = 0.5f-behavior_maxeffect/2.0; + const F32 max_val = 0.5f+behavior_maxeffect/2.0; + + // Scale from [0,1] to [min_val,max_val] + const F32 new_value_rescaled = min_val + (max_val-min_val) * new_value_normalized; + + // Scale from [0,1] to [value_min_local,value_max_local] + const F32 new_value_local = value_min_local + (value_max_local-value_min_local) * new_value_rescaled; + + mCharacter->setVisualParamWeight(param, + new_value_local, + FALSE); +} diff --git a/indra/newview/llphysicsmotion.h b/indra/newview/llphysicsmotion.h new file mode 100644 index 000000000..657698e4f --- /dev/null +++ b/indra/newview/llphysicsmotion.h @@ -0,0 +1,124 @@ +/** + * @file llphysicsmotion.h + * @brief Implementation of LLPhysicsMotion class. + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLPHYSICSMOTIONCONTROLLER_H +#define LL_LLPHYSICSMOTIONCONTROLLER_H + +//----------------------------------------------------------------------------- +// Header files +//----------------------------------------------------------------------------- +#include "llmotion.h" +#include "llframetimer.h" + +#define PHYSICS_MOTION_FADEIN_TIME 1.0f +#define PHYSICS_MOTION_FADEOUT_TIME 1.0f + +class LLPhysicsMotion; + +//----------------------------------------------------------------------------- +// class LLPhysicsMotion +//----------------------------------------------------------------------------- +class LLPhysicsMotionController : + public LLMotion +{ +public: + // Constructor + LLPhysicsMotionController(const LLUUID &id); + + // Destructor + virtual ~LLPhysicsMotionController(); + +public: + //------------------------------------------------------------------------- + // functions to support MotionController and MotionRegistry + //------------------------------------------------------------------------- + + // static constructor + // all subclasses must implement such a function and register it + static LLMotion *create(const LLUUID &id) { return new LLPhysicsMotionController(id); } + +public: + //------------------------------------------------------------------------- + // animation callbacks to be implemented by subclasses + //------------------------------------------------------------------------- + + // motions must specify whether or not they loop + virtual BOOL getLoop() { return TRUE; } + + // motions must report their total duration + virtual F32 getDuration() { return 0.0; } + + // motions must report their "ease in" duration + virtual F32 getEaseInDuration() { return PHYSICS_MOTION_FADEIN_TIME; } + + // motions must report their "ease out" duration. + virtual F32 getEaseOutDuration() { return PHYSICS_MOTION_FADEOUT_TIME; } + + // called to determine when a motion should be activated/deactivated based on avatar pixel coverage + virtual F32 getMinPixelArea(); + + // motions must report their priority + virtual LLJoint::JointPriority getPriority() { return LLJoint::MEDIUM_PRIORITY; } + + virtual LLMotionBlendType getBlendType() { return ADDITIVE_BLEND; } + + // run-time (post constructor) initialization, + // called after parameters have been set + // must return true to indicate success and be available for activation + virtual LLMotionInitStatus onInitialize(LLCharacter *character); + + // called when a motion is activated + // must return TRUE to indicate success, or else + // it will be deactivated + virtual BOOL onActivate(); + + // called per time step + // must return TRUE while it is active, and + // must return FALSE when the motion is completed. + virtual BOOL onUpdate(F32 time, U8* joint_mask); + + // called when a motion is deactivated + virtual void onDeactivate(); + + LLCharacter* getCharacter() { return mCharacter; } + +protected: + void addMotion(LLPhysicsMotion *motion); +private: + LLCharacter* mCharacter; + + typedef std::vector motion_vec_t; + motion_vec_t mMotions; +}; + +#endif // LL_LLPHYSICSMOTION_H + diff --git a/indra/newview/llpolymesh.cpp b/indra/newview/llpolymesh.cpp index dbe6079ed..a23c199c9 100644 --- a/indra/newview/llpolymesh.cpp +++ b/indra/newview/llpolymesh.cpp @@ -49,7 +49,16 @@ #define HEADER_ASCII "Linden Mesh 1.0" #define HEADER_BINARY "Linden Binary Mesh 1.0" -extern LLControlGroup gSavedSettings; // read only +extern LLControlGroup gSavedSettings; // read only + +LLPolyMorphData *clone_morph_param_duplicate(const LLPolyMorphData *src_data, + const std::string &name); +LLPolyMorphData *clone_morph_param_direction(const LLPolyMorphData *src_data, + const LLVector3 &direction, + const std::string &name); +LLPolyMorphData *clone_morph_param_cleavage(const LLPolyMorphData *src_data, + F32 scale, + const std::string &name); //----------------------------------------------------------------------------- // Global table of loaded LLPolyMeshes @@ -606,8 +615,60 @@ BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName ) continue; } - mMorphData.insert(morph_data); - } + mMorphData.insert(morph_data); + + if (!strcmp(morphName, "Breast_Female_Cleavage")) + { + mMorphData.insert(clone_morph_param_cleavage(morph_data, + .75f, + "Breast_Physics_LeftRight_Driven")); + } + + if (!strcmp(morphName, "Breast_Female_Cleavage")) + { + mMorphData.insert(clone_morph_param_duplicate(morph_data, + "Breast_Physics_InOut_Driven")); + } + if (!strcmp(morphName, "Breast_Gravity")) + { + mMorphData.insert(clone_morph_param_duplicate(morph_data, + "Breast_Physics_UpDown_Driven")); + } + + if (!strcmp(morphName, "Big_Belly_Torso")) + { + mMorphData.insert(clone_morph_param_direction(morph_data, + LLVector3(0,0,0.05f), + "Belly_Physics_Torso_UpDown_Driven")); + } + + if (!strcmp(morphName, "Big_Belly_Legs")) + { + mMorphData.insert(clone_morph_param_direction(morph_data, + LLVector3(0,0,0.05f), + "Belly_Physics_Legs_UpDown_Driven")); + } + + if (!strcmp(morphName, "skirt_belly")) + { + mMorphData.insert(clone_morph_param_direction(morph_data, + LLVector3(0,0,0.05f), + "Belly_Physics_Skirt_UpDown_Driven")); + } + + if (!strcmp(morphName, "Small_Butt")) + { + mMorphData.insert(clone_morph_param_direction(morph_data, + LLVector3(0,0,0.05f), + "Butt_Physics_UpDown_Driven")); + } + if (!strcmp(morphName, "Small_Butt")) + { + mMorphData.insert(clone_morph_param_direction(morph_data, + LLVector3(0,0.03f,0), + "Butt_Physics_LeftRight_Driven")); + } + } S32 numRemaps; if (fread(&numRemaps, sizeof(S32), 1, fp) == 1) @@ -1156,4 +1217,55 @@ void LLPolySkeletalDistortion::apply( ESex avatar_sex ) mLastWeight = mCurWeight; } + +LLPolyMorphData *clone_morph_param_duplicate(const LLPolyMorphData *src_data, + const std::string &name) +{ + LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data); + cloned_morph_data->mName = name; + for (U32 v=0; v < cloned_morph_data->mNumIndices; v++) + { + cloned_morph_data->mCoords[v] = src_data->mCoords[v]; + cloned_morph_data->mNormals[v] = src_data->mNormals[v]; + cloned_morph_data->mBinormals[v] = src_data->mBinormals[v]; + } + return cloned_morph_data; +} + +LLPolyMorphData *clone_morph_param_direction(const LLPolyMorphData *src_data, + const LLVector3 &direction, + const std::string &name) +{ + LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data); + cloned_morph_data->mName = name; + for (U32 v=0; v < cloned_morph_data->mNumIndices; v++) + { + cloned_morph_data->mCoords[v] = direction; + cloned_morph_data->mNormals[v] = LLVector3(0,0,0); + cloned_morph_data->mBinormals[v] = LLVector3(0,0,0); + } + return cloned_morph_data; +} + +LLPolyMorphData *clone_morph_param_cleavage(const LLPolyMorphData *src_data, + F32 scale, + const std::string &name) +{ + LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data); + cloned_morph_data->mName = name; + for (U32 v=0; v < cloned_morph_data->mNumIndices; v++) + { + cloned_morph_data->mCoords[v] = src_data->mCoords[v]*scale; + cloned_morph_data->mNormals[v] = src_data->mNormals[v]*scale; + cloned_morph_data->mBinormals[v] = src_data->mBinormals[v]*scale; + if (cloned_morph_data->mCoords[v][1] < 0) + { + cloned_morph_data->mCoords[v][1] *= -1; + cloned_morph_data->mNormals[v][1] *= -1; + cloned_morph_data->mBinormals[v][1] *= -1; + } + } + return cloned_morph_data; +} + // End diff --git a/indra/newview/llpolymorph.cpp b/indra/newview/llpolymorph.cpp index 3a57b6f9f..72a332440 100644 --- a/indra/newview/llpolymorph.cpp +++ b/indra/newview/llpolymorph.cpp @@ -64,6 +64,36 @@ LLPolyMorphData::LLPolyMorphData(const std::string& morph_name) mMesh = NULL; } +LLPolyMorphData::LLPolyMorphData(const LLPolyMorphData &rhs) : + mName(rhs.mName), + mNumIndices(rhs.mNumIndices), + mTotalDistortion(rhs.mTotalDistortion), + mAvgDistortion(rhs.mAvgDistortion), + mMaxDistortion(rhs.mMaxDistortion), + mVertexIndices(NULL), + mCoords(NULL), + mNormals(NULL), + mBinormals(NULL), + mTexCoords(NULL) +{ + const S32 numVertices = mNumIndices; + + mCoords = new LLVector3[numVertices]; + mNormals = new LLVector3[numVertices]; + mBinormals = new LLVector3[numVertices]; + mTexCoords = new LLVector2[numVertices]; + mVertexIndices = new U32[numVertices]; + + for (S32 v=0; v < numVertices; v++) + { + mCoords[v] = rhs.mCoords[v]; + mNormals[v] = rhs.mNormals[v]; + mBinormals[v] = rhs.mBinormals[v]; + mTexCoords[v] = rhs.mTexCoords[v]; + mVertexIndices[v] = rhs.mVertexIndices[v]; + } +} + //----------------------------------------------------------------------------- // ~LLPolyMorphData() //----------------------------------------------------------------------------- @@ -292,10 +322,22 @@ BOOL LLPolyMorphTarget::setInfo(LLPolyMorphTargetInfo* info) } } - mMorphData = mMesh->getMorphData(getInfo()->mMorphName); + std::string morph_param_name = getInfo()->mMorphName; + + mMorphData = mMesh->getMorphData(morph_param_name); if (!mMorphData) { - llwarns << "No morph target named " << getInfo()->mMorphName << " found in mesh." << llendl; + const std::string driven_tag = "_Driven"; + U32 pos = morph_param_name.find(driven_tag); + if (pos > 0) + { + morph_param_name = morph_param_name.substr(0,pos); + mMorphData = mMesh->getMorphData(morph_param_name); + } + } + if (!mMorphData) + { + llwarns << "No morph target named " << morph_param_name << " found in mesh." << llendl; return FALSE; // Continue, ignoring this tag } return TRUE; @@ -445,6 +487,16 @@ void LLPolyMorphTarget::apply( ESex avatar_sex ) mLastSex = avatar_sex; + // Check for NaN condition (NaN is detected if a variable doesn't equal itself. + if (mCurWeight != mCurWeight) + { + mCurWeight = 0.0; + } + if (mLastWeight != mLastWeight) + { + mLastWeight = mCurWeight+.001; + } + // perform differential update of morph F32 delta_weight = ( getSex() & avatar_sex ) ? (mCurWeight - mLastWeight) : (getDefaultWeight() - mLastWeight); // store last weight diff --git a/indra/newview/llpolymorph.h b/indra/newview/llpolymorph.h index f8dd52ca3..3fdaf3785 100644 --- a/indra/newview/llpolymorph.h +++ b/indra/newview/llpolymorph.h @@ -51,6 +51,7 @@ class LLPolyMorphData public: LLPolyMorphData(const std::string& morph_name); ~LLPolyMorphData(); + LLPolyMorphData(const LLPolyMorphData &rhs); BOOL loadBinary(LLFILE* fp, LLPolyMeshSharedData *mesh); const std::string& getName() { return mName; } diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 956e31502..b75c3345e 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -3913,6 +3913,7 @@ class LLEditEnableCustomizeAvatar : public view_listener_t } }; + class LLEditEnableChangeDisplayname : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) @@ -8894,6 +8895,10 @@ class LLEditEnableTakeOff : public view_listener_t { new_value = LLAgent::selfHasWearable((void *)WT_TATTOO); } + if (clothing == "physics") + { + new_value = LLAgent::selfHasWearable((void *)WT_PHYSICS); + } // [RLVa:KB] - Checked: 2009-07-07 (RLVa-1.1.3b) | Modified: RLVa-1.1.3b | OK // Why aren't they using LLWearable::typeNameToType()? *confuzzled* @@ -8957,6 +8962,10 @@ class LLEditTakeOff : public view_listener_t { LLAgent::userRemoveWearable((void*)WT_TATTOO); } + else if (clothing == "physics") + { + LLAgent::userRemoveWearable((void*)WT_PHYSICS); + } else if (clothing == "all") { LLAgent::userRemoveAllClothes(NULL); diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 5f1749ddd..c1d9f11a9 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -103,6 +103,8 @@ #include "llavatarname.h" #include "llavatarnamecache.h" +#include "llphysicsmotion.h" + // [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) #include "rlvhandler.h" // [/RLVa:KB] @@ -128,6 +130,7 @@ const LLUUID ANIM_AGENT_HEAD_ROT = LLUUID("e6e8d1dd-e643-fff7-b238-c6b4b056a68d" const LLUUID ANIM_AGENT_PELVIS_FIX = LLUUID("0c5dd2a2-514d-8893-d44d-05beffad208b"); //"pelvis_fix" const LLUUID ANIM_AGENT_TARGET = LLUUID("0e4896cb-fba4-926c-f355-8720189d5b55"); //"target" const LLUUID ANIM_AGENT_WALK_ADJUST = LLUUID("829bc85b-02fc-ec41-be2e-74cc6dd7215d"); //"walk_adjust" +const LLUUID ANIM_AGENT_PHYSICS_MOTION = LLUUID("7360e029-3cb8-ebc4-863e-212df440d987"); //"physics_motion" //----------------------------------------------------------------------------- @@ -720,6 +723,7 @@ BOOL LLVOAvatar::sShowAnimationDebug = FALSE; BOOL LLVOAvatar::sShowFootPlane = FALSE; BOOL LLVOAvatar::sVisibleInFirstPerson = FALSE; F32 LLVOAvatar::sLODFactor = 1.f; +F32 LLVOAvatar::sPhysicsLODFactor = 1.f; BOOL LLVOAvatar::sUseImpostors = FALSE; BOOL LLVOAvatar::sJointDebug = FALSE; @@ -1016,6 +1020,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, // motions without a start/stop bit registerMotion( ANIM_AGENT_BODY_NOISE, LLBodyNoiseMotion::create ); registerMotion( ANIM_AGENT_BREATHE_ROT, LLBreatheMotionRot::create ); + registerMotion( ANIM_AGENT_PHYSICS_MOTION, LLPhysicsMotionController::create ); registerMotion( ANIM_AGENT_EDITING, LLEditingMotion::create ); registerMotion( ANIM_AGENT_EYE, LLEyeMotion::create ); registerMotion( ANIM_AGENT_FLY_ADJUST, LLFlyAdjustMotion::create ); @@ -1970,6 +1975,7 @@ void LLVOAvatar::startDefaultMotions() startMotion( ANIM_AGENT_EYE ); startMotion( ANIM_AGENT_BODY_NOISE ); startMotion( ANIM_AGENT_BREATHE_ROT ); + startMotion( ANIM_AGENT_PHYSICS_MOTION ); startMotion( ANIM_AGENT_HAND_MOTION ); startMotion( ANIM_AGENT_PELVIS_FIX ); @@ -2791,7 +2797,7 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) idleUpdateAppearanceAnimation(); if (detailed_update) { - idleUpdateBoobEffect(); + //idleUpdateBoobEffect(); idleUpdateLipSync( voice_enabled ); idleUpdateLoadingEffect(); idleUpdateBelowWater(); // wind effect uses this @@ -9151,6 +9157,13 @@ void LLVOAvatar::wearableUpdated(EWearableType type, BOOL upload_result) } } } + + // Physics type has no associated baked textures, but change of params needs to be sent to + // other avatars. + if (isSelf() && type == WT_PHYSICS) + { + gAgent.sendAgentSetAppearance(); + } } diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 4bedcbb10..0ea151b12 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -55,6 +55,7 @@ extern const LLUUID ANIM_AGENT_BODY_NOISE; extern const LLUUID ANIM_AGENT_BREATHE_ROT; +extern const LLUUID ANIM_AGENT_PHYSICS_MOTION; extern const LLUUID ANIM_AGENT_EDITING; extern const LLUUID ANIM_AGENT_EYE; extern const LLUUID ANIM_AGENT_FLY_ADJUST; @@ -629,6 +630,7 @@ public: static BOOL sDebugInvisible; static BOOL sShowAttachmentPoints; static F32 sLODFactor; // user-settable LOD factor + static F32 sPhysicsLODFactor; // user-settable physics LOD factor static BOOL sJointDebug; // output total number of joints being touched for each avatar static BOOL sDebugAvatarRotation; static F32 sAvMorphTime; diff --git a/indra/newview/llwearable.cpp b/indra/newview/llwearable.cpp index 14c6220c5..e85726166 100644 --- a/indra/newview/llwearable.cpp +++ b/indra/newview/llwearable.cpp @@ -72,6 +72,7 @@ const std::string LLWearable::sTypeName[ WT_COUNT+1 ] = "skirt", "alpha", "tattoo", + "physics", "invalid" }; @@ -93,6 +94,7 @@ const std::string LLWearable::sTypeLabel[ WT_COUNT+1 ] = "Skirt", "Alpha", "Tattoo", + "Physics", "invalid" }; @@ -118,6 +120,7 @@ LLAssetType::EType LLWearable::typeToAssetType(EWearableType wearable_type) case WT_SKIRT: case WT_ALPHA: case WT_TATTOO: + case WT_PHYSICS: return LLAssetType::AT_CLOTHING; default: return LLAssetType::AT_NONE; diff --git a/indra/newview/llwearable.h b/indra/newview/llwearable.h index 253ae97b0..72d876359 100644 --- a/indra/newview/llwearable.h +++ b/indra/newview/llwearable.h @@ -58,7 +58,8 @@ enum EWearableType // If you change this, update LLWearable::getTypeName(), get WT_SKIRT = 12, WT_ALPHA = 13, WT_TATTOO = 14, - WT_COUNT = 15, + WT_PHYSICS = 15, + WT_COUNT = 16, WT_INVALID = 255 }; diff --git a/indra/newview/rlvhandler.cpp b/indra/newview/rlvhandler.cpp index 8fb992e0c..94b88fb0c 100644 --- a/indra/newview/rlvhandler.cpp +++ b/indra/newview/rlvhandler.cpp @@ -1993,7 +1993,7 @@ ERlvCmdRet RlvHandler::onGetOutfit(const RlvCommand& rlvCmd, std::string& strRep const EWearableType wtRlvTypes[] = { WT_GLOVES, WT_JACKET, WT_PANTS, WT_SHIRT, WT_SHOES, WT_SKIRT, WT_SOCKS, - WT_UNDERPANTS, WT_UNDERSHIRT, WT_SKIN, WT_EYES, WT_HAIR, WT_SHAPE, WT_ALPHA, WT_TATTOO + WT_UNDERPANTS, WT_UNDERSHIRT, WT_SKIN, WT_EYES, WT_HAIR, WT_SHAPE, WT_ALPHA, WT_TATTOO, WT_PHYSICS }; for (int idxType = 0, cntType = sizeof(wtRlvTypes) / sizeof(EWearableType); idxType < cntType; idxType++) diff --git a/indra/newview/skins/default/textures/inv_item_physics.png b/indra/newview/skins/default/textures/inv_item_physics.png new file mode 100644 index 0000000000000000000000000000000000000000..360baec46d291923ec07f574df9022178f7c640a GIT binary patch literal 539 zcmV+$0_6RPP)tQ^=kX}?XQ5E zUwyfAyd5kj$?~5V7kKgfc=nx#hlfF5Umq;M_4B10&|vNV;<}A6L+}NnHBiG$#&^-8 zOwa!?Faq)KXTL>(^c6vNyn*%ih=BN46fS@fFArphg*xq2F#D*oPhlj3CXT48Ise7=AOr>Hoih z^e-U)H-pT}4f~~}q?~{TtoqBu=D@1yC5GWykRfXS5_^zr_kg(oiur&BgyT#H$C#Ed z0&Oma2|oGwJM!zVf4Beq`+xT1kH3$fe*EnS6n>1&0C+5b41uw?U;hZAUIB485N`nD z*QP-M$8fp;3%G(t;{+H6G_Jb@O0J$Dc72fEC#Y~bP+SIx`G|1=DAR!aupP=j3dA6d d{7^X*008*3-Imx&5t;x1002ovPDHLkV1h7h@8tjh literal 0 HcmV?d00001 diff --git a/indra/newview/skins/default/xui/en-us/floater_inventory.xml b/indra/newview/skins/default/xui/en-us/floater_inventory.xml index 4832c5132..d42d855d6 100644 --- a/indra/newview/skins/default/xui/en-us/floater_inventory.xml +++ b/indra/newview/skins/default/xui/en-us/floater_inventory.xml @@ -160,6 +160,10 @@ mouse_opaque="true" name="New Alpha" width="125"> + + + diff --git a/indra/newview/skins/default/xui/en-us/menu_inventory.xml b/indra/newview/skins/default/xui/en-us/menu_inventory.xml index 64f294599..9265e688a 100644 --- a/indra/newview/skins/default/xui/en-us/menu_inventory.xml +++ b/indra/newview/skins/default/xui/en-us/menu_inventory.xml @@ -96,6 +96,10 @@ mouse_opaque="true" name="New Alpha" width="128"> + + + + + + + diff --git a/indra/newview/skins/default/xui/en-us/menu_viewer.xml b/indra/newview/skins/default/xui/en-us/menu_viewer.xml index a73400803..aa3f5b756 100644 --- a/indra/newview/skins/default/xui/en-us/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en-us/menu_viewer.xml @@ -196,7 +196,12 @@ - + + + +