diff options
author | Oz Linden <oz@lindenlab.com> | 2011-01-13 11:14:13 -0500 |
---|---|---|
committer | Oz Linden <oz@lindenlab.com> | 2011-01-13 11:14:13 -0500 |
commit | b01ca1293b7890ee1e2671f4a9e7b1a77a559a44 (patch) | |
tree | 45316409d91dd5cb72e31ae9b53154469380cb99 /indra | |
parent | 55322713fc071a3e171fd4cfbea989945dc8d084 (diff) | |
parent | 433ad05ae9580027641c8bd5e1fe175f96669a66 (diff) |
merge up to latest viewer-development
Diffstat (limited to 'indra')
47 files changed, 1288 insertions, 99 deletions
diff --git a/indra/llmath/v3math.cpp b/indra/llmath/v3math.cpp index fd08df02d8..18b15e08c4 100644 --- a/indra/llmath/v3math.cpp +++ b/indra/llmath/v3math.cpp @@ -134,6 +134,21 @@ BOOL LLVector3::clampLength( F32 length_limit ) return changed; } +BOOL LLVector3::clamp(const LLVector3 &min_vec, const LLVector3 &max_vec) +{ + BOOL ret = FALSE; + + if (mV[0] < min_vec[0]) { mV[0] = min_vec[0]; ret = TRUE; } + if (mV[1] < min_vec[1]) { mV[1] = min_vec[1]; ret = TRUE; } + if (mV[2] < min_vec[2]) { mV[2] = min_vec[2]; ret = TRUE; } + + if (mV[0] > max_vec[0]) { mV[0] = max_vec[0]; ret = TRUE; } + if (mV[1] > max_vec[1]) { mV[1] = max_vec[1]; ret = TRUE; } + if (mV[2] > max_vec[2]) { mV[2] = max_vec[2]; ret = TRUE; } + + return ret; +} + // Sets all values to absolute value of their original values // Returns TRUE if data changed diff --git a/indra/llmath/v3math.h b/indra/llmath/v3math.h index dbd38c1c3f..d3fc6fcb2f 100644 --- a/indra/llmath/v3math.h +++ b/indra/llmath/v3math.h @@ -69,6 +69,7 @@ class LLVector3 inline BOOL isFinite() const; // checks to see if all values of LLVector3 are finite BOOL clamp(F32 min, F32 max); // Clamps all values to (min,max), returns TRUE if data changed + BOOL clamp(const LLVector3 &min_vec, const LLVector3 &max_vec); // Scales vector by another vector BOOL clampLength( F32 length_limit ); // Scales vector to limit length to a value void quantize16(F32 lowerxy, F32 upperxy, F32 lowerz, F32 upperz); // changes the vector to reflect quatization diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index a61c35abd2..39aa3a1c8d 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -96,6 +96,7 @@ set(viewer_SOURCE_FILES llbottomtray.cpp llbox.cpp llbreadcrumbview.cpp + llbreastmotion.cpp llbrowsernotification.cpp llbuycurrencyhtml.cpp llcallbacklist.cpp @@ -634,6 +635,7 @@ set(viewer_HEADER_FILES llbottomtray.h llbox.h llbreadcrumbview.h + llbreastmotion.h llbuycurrencyhtml.h llcallbacklist.h llcallfloater.h diff --git a/indra/newview/app_settings/high_graphics.xml b/indra/newview/app_settings/high_graphics.xml index 4da2b0fd00..4e137d971a 100644 --- a/indra/newview/app_settings/high_graphics.xml +++ b/indra/newview/app_settings/high_graphics.xml @@ -4,6 +4,8 @@ <RenderAvatarCloth value="FALSE"/> <!--Default for now--> <RenderAvatarLODFactor value="1.0"/> + <!--Default for now--> + <RenderAvatarPhysicsLODFactor value="0.9"/> <!--NO SHADERS--> <RenderAvatarVP value="TRUE"/> <!--Short Range--> diff --git a/indra/newview/app_settings/low_graphics.xml b/indra/newview/app_settings/low_graphics.xml index 136087f69b..79463b475c 100644 --- a/indra/newview/app_settings/low_graphics.xml +++ b/indra/newview/app_settings/low_graphics.xml @@ -5,6 +5,8 @@ <!--Default for now--> <RenderAvatarLODFactor value="0.5"/> <!--Default for now--> + <RenderAvatarPhysicsLODFactor value="0.0"/> + <!--Default for now--> <RenderAvatarMaxVisible value="3"/> <!--NO SHADERS--> <RenderAvatarVP value="FALSE"/> diff --git a/indra/newview/app_settings/mid_graphics.xml b/indra/newview/app_settings/mid_graphics.xml index c150a87cdf..ab1e2a2e1c 100644 --- a/indra/newview/app_settings/mid_graphics.xml +++ b/indra/newview/app_settings/mid_graphics.xml @@ -4,6 +4,8 @@ <RenderAvatarCloth value="FALSE"/> <!--Default for now--> <RenderAvatarLODFactor value="0.5"/> + <!--Default for now--> + <RenderAvatarPhysicsLODFactor value="0.75"/> <!--NO SHADERS--> <RenderAvatarVP value="TRUE"/> <!--Short Range--> diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index ef6f8fd3ee..dc2ff09830 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -641,7 +641,28 @@ <key>Value</key> <integer>10</integer> </map> - + <key>AvatarPhysics</key> + <map> + <key>Comment</key> + <string>Enable avatar physics.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>AvatarPhysicsTest</key> + <map> + <key>Comment</key> + <string>Simulate continuous physics behavior on all nearby avatars.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> <key>AvatarSex</key> <map> <key>Comment</key> @@ -653,6 +674,7 @@ <key>Value</key> <integer>0</integer> </map> + <key>BackgroundYieldTime</key> <map> <key>Comment</key> @@ -6833,6 +6855,17 @@ <key>Value</key> <integer>12</integer> </map> + <key>RenderAvatarPhysicsLODFactor</key> + <map> + <key>Comment</key> + <string>Controls level of detail of avatar physics (such as breast physics).</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <integer>1.0</integer> + </map> <key>RenderAvatarVP</key> <map> <key>Comment</key> diff --git a/indra/newview/app_settings/ultra_graphics.xml b/indra/newview/app_settings/ultra_graphics.xml index e7dce3b989..e1f3ca5769 100644 --- a/indra/newview/app_settings/ultra_graphics.xml +++ b/indra/newview/app_settings/ultra_graphics.xml @@ -4,6 +4,8 @@ <RenderAvatarCloth value="TRUE"/> <!--Default for now--> <RenderAvatarLODFactor value="1.0"/> + <!--Default for now--> + <RenderAvatarPhysicsLODFactor value="1.0"/> <!--NO SHADERS--> <RenderAvatarVP value="TRUE"/> <!--Short Range--> diff --git a/indra/newview/character/avatar_lad.xml b/indra/newview/character/avatar_lad.xml index a9b4ff02c5..453ed1baf7 100644 --- a/indra/newview/character/avatar_lad.xml +++ b/indra/newview/character/avatar_lad.xml @@ -612,7 +612,7 @@ id="36" group="0" name="Shoulders" - label="Shoulders" + label="Shoulders" wearable="shape" edit_group="shape_torso" edit_group_order="4" @@ -4044,14 +4044,13 @@ </param> <param - id="507" + id="1087" group="0" sex="female" name="Breast_Gravity" label="Breast Buoyancy" wearable="shape" - edit_group="shape_torso" - edit_group_order="7" + edit_group="driven" label_min="Less Gravity" label_max="More Gravity" value_default="0" @@ -4063,6 +4062,24 @@ </param> <param + id="1088" + group="0" + sex="female" + name="Breast_Female_Cleavage" + label="Breast Cleavage" + wearable="shape" + edit_group="driven" + label_min="Separate" + label_max="Join" + value_default="0" + value_min="-.3" + value_max="1.3" + camera_elevation=".3" + camera_distance=".8"> + <param_morph /> + </param> + + <param id="628" group="1" name="Displace_Loose_Upperbody" @@ -4113,25 +4130,6 @@ </param> <param - id="684" - group="0" - sex="female" - name="Breast_Female_Cleavage" - label="Breast Cleavage" - wearable="shape" - edit_group="shape_torso" - edit_group_order="8" - label_min="Separate" - label_max="Join" - value_default="0" - value_min="-.3" - value_max="1.3" - camera_elevation=".3" - camera_distance=".8"> - <param_morph /> - </param> - - <param id="685" group="0" sex="male" @@ -9074,12 +9072,292 @@ render_pass="bump"> <!-- =========================================================== --> <driver_parameters> + + <param + id="1074" + group="0" + sex="female" + name="Breast_Physics_Mass" + label="Breast Physics Mass" + wearable="physics" + edit_group="physics" + label_min="Less" + label_max="More" + value_default="2" + value_min="1" + value_max="5" + camera_elevation=".3" + camera_distance=".8"> + <param_driver /> + </param> + + <param + id="1075" + group="0" + sex="female" + name="Breast_Physics_Smoothing" + label="Breast Physics Smoothing" + wearable="physics" + edit_group="physics" + label_min="Less" + label_max="More" + value_default="2" + value_min="1" + value_max="10" + camera_elevation=".3" + camera_distance=".8"> + <param_driver /> + </param> + + <param + id="1076" + group="0" + sex="female" + name="Breast_Physics_Gravity" + label="Breast Physics Gravity" + wearable="physics" + edit_group="physics" + label_min="Less" + label_max="More" + value_default="0" + value_min="0" + value_max="1" + camera_elevation=".3" + camera_distance=".8"> + <param_driver /> + </param> + + <param + id="1077" + group="0" + sex="female" + name="Breast_Physics_Side_Spring" + label="Breast Physics Side Spring" + wearable="physics" + edit_group="physics" + label_min="Less" + label_max="More" + value_default="3" + value_min="0" + value_max="10" + camera_elevation=".3" + camera_distance=".8"> + <param_driver /> + </param> + + <param + id="1078" + group="0" + sex="female" + name="Breast_Physics_Side_Gain" + label="Breast Physics Side Gain" + wearable="physics" + edit_group="physics" + label_min="Less" + label_max="More" + value_default="10" + value_min="1" + value_max="100" + camera_elevation=".3" + camera_distance=".8"> + <param_driver /> + </param> + + <param + id="1079" + group="0" + sex="female" + name="Breast_Physics_Side_Damping" + label="Breast Physics Side Damping" + wearable="physics" + edit_group="physics" + label_min="Less" + label_max="More" + value_default=".5" + value_min="0" + value_max="1" + camera_elevation=".3" + camera_distance=".8"> + <param_driver /> + </param> + + <param + id="1080" + group="0" + sex="female" + name="Breast_Physics_Side_Drag" + label="Breast Physics Side Drag" + wearable="physics" + edit_group="physics" + label_min="Less" + label_max="More" + value_default=".1" + value_min="0" + value_max="1" + camera_elevation=".3" + camera_distance=".8"> + <param_driver /> + </param> + + <param + id="1081" + group="0" + sex="female" + name="Breast_Physics_Side_Max_Velocity" + label="Breast Physics Side Max Speed" + wearable="physics" + edit_group="physics" + label_min="Less" + label_max="More" + value_default="0" + value_min="0" + value_max="10" + camera_elevation=".3" + camera_distance=".8"> + <param_driver /> + </param> + + + <param + id="1082" + group="0" + sex="female" + name="Breast_Physics_UpDown_Spring" + label="Breast Physics UpDown Spring" + wearable="physics" + edit_group="physics" + label_min="Less" + label_max="More" + value_default="1.5" + value_min="0" + value_max="10" + camera_elevation=".3" + camera_distance=".8"> + <param_driver /> + </param> + + <param + id="1083" + group="0" + sex="female" + name="Breast_Physics_UpDown_Gain" + label="Breast Physics UpDown Gain" + wearable="physics" + edit_group="physics" + label_min="Less" + label_max="More" + value_default="50" + value_min="1" + value_max="100" + camera_elevation=".3" + camera_distance=".8"> + <param_driver /> + </param> + + <param + id="1084" + group="0" + sex="female" + name="Breast_Physics_UpDown_Damping" + label="Breast Physics UpDown Damping" + wearable="physics" + edit_group="physics" + label_min="Less" + label_max="More" + value_default=".1" + value_min="0" + value_max="1" + camera_elevation=".3" + camera_distance=".8"> + <param_driver /> + </param> + + <param + id="1085" + group="0" + sex="female" + name="Breast_Physics_UpDown_Drag" + label="Breast Physics UpDown Drag" + wearable="physics" + edit_group="physics" + label_min="Less" + label_max="More" + value_default=".1" + value_min="0" + value_max="1" + camera_elevation=".3" + camera_distance=".8"> + <param_driver /> + </param> + + <param + id="1086" + group="0" + sex="female" + name="Breast_Physics_UpDown_Max_Velocity" + label="Breast Physics UpDown Max Speed" + wearable="physics" + edit_group="physics" + label_min="Less" + label_max="More" + value_default="1" + value_min="0" + value_max="10" + camera_elevation=".3" + camera_distance=".8"> + <param_driver /> + </param> + + <param + id="507" + group="0" + sex="female" + name="Breast_Gravity_Driver" + label="Breast Buoyancy" + wearable="shape" + edit_group="shape_torso" + edit_group_order="7" + label_min="Less" + label_max="More" + value_default="10" + value_min="-1.5" + value_max="2" + camera_elevation=".3" + camera_distance=".8"> + <param_driver> + <driven + id="1087" /> + </param_driver> + </param> + + <param + id="684" + group="0" + sex="female" + name="Breast_Female_Cleavage_Driver" + label="Breast Cleavage" + wearable="shape" + edit_group="shape_torso" + edit_group_order="8" + label_min="Less" + label_max="More" + value_default="10" + value_min="-.3" + value_max="1.3" + camera_elevation=".3" + camera_distance=".8"> + <param_driver> + <driven + id="1088" /> + </param_driver> + </param> + <param id="828" group="0" name="Loose Upper Clothing" label="Shirt Fit" - show_simple="true" + show_simple="true" wearable="shirt" edit_group="shirt" edit_group_order="4" diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt index a82c3da4c5..15ad330418 100644 --- a/indra/newview/featuretable.txt +++ b/indra/newview/featuretable.txt @@ -26,6 +26,7 @@ list all RenderAnisotropic 1 1 RenderAvatarCloth 1 1 RenderAvatarLODFactor 1 1.0 +RenderAvatarPhysicsLODFactor 1 1.0 RenderAvatarMaxVisible 1 12 RenderAvatarVP 1 1 RenderCubeMap 1 1 @@ -71,6 +72,7 @@ list Low RenderAnisotropic 1 0 RenderAvatarCloth 1 0 RenderAvatarLODFactor 1 0 +RenderAvatarPhysicsLODFactor 1 0 RenderAvatarMaxVisible 1 3 RenderAvatarVP 1 0 RenderFarClip 1 64 @@ -101,6 +103,7 @@ list Mid RenderAnisotropic 1 0 RenderAvatarCloth 1 0 RenderAvatarLODFactor 1 0.5 +RenderAvatarPhysicsLODFactor 1 0.75 RenderAvatarVP 1 1 RenderFarClip 1 96 RenderFlexTimeFactor 1 1.0 @@ -129,6 +132,7 @@ list High RenderAnisotropic 1 1 RenderAvatarCloth 1 0 RenderAvatarLODFactor 1 1.0 +RenderAvatarPhysicsLODFactor 1 0.9 RenderAvatarVP 1 1 RenderFarClip 1 128 RenderFlexTimeFactor 1 1.0 diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp index f01d5ff1f5..4118b1df98 100644 --- a/indra/newview/llagentcamera.cpp +++ b/indra/newview/llagentcamera.cpp @@ -277,6 +277,7 @@ LLAgentCamera::~LLAgentCamera() //----------------------------------------------------------------------------- void LLAgentCamera::resetView(BOOL reset_camera, BOOL change_camera) { + if (TRUE) return; // Disabling reset for avatar physics demo-ing. if (gAgent.getAutoPilot()) { gAgent.stopAutoPilot(TRUE); diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index 055be4cae2..d426afb17c 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -821,7 +821,7 @@ void LLAgentWearables::popWearable(const LLWearableType::EType type, U32 index) } } -U32 LLAgentWearables::getWearableIndex(LLWearable *wearable) +U32 LLAgentWearables::getWearableIndex(const LLWearable *wearable) const { if (wearable == NULL) { @@ -2045,8 +2045,9 @@ void LLAgentWearables::editWearable(const LLUUID& item_id) return; } + const BOOL disable_camera_switch = LLWearableType::getDisableCameraSwitch(wearable->getType()); LLPanel* panel = LLSideTray::getInstance()->getPanel("sidepanel_appearance"); - LLSidepanelAppearance::editWearable(wearable, panel); + LLSidepanelAppearance::editWearable(wearable, panel, disable_camera_switch); } // Request editing the item after it gets worn. diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h index d7e77a5a5b..3ef50f14da 100644 --- a/indra/newview/llagentwearables.h +++ b/indra/newview/llagentwearables.h @@ -124,7 +124,7 @@ public: void setWearableOutfit(const LLInventoryItem::item_array_t& items, const LLDynamicArray< LLWearable* >& wearables, BOOL remove); void setWearableName(const LLUUID& item_id, const std::string& new_name); void addLocalTextureObject(const LLWearableType::EType wearable_type, const LLVOAvatarDefines::ETextureIndex texture_type, U32 wearable_index); - U32 getWearableIndex(LLWearable *wearable); + U32 getWearableIndex(const LLWearable *wearable) const; protected: void setWearableFinal(LLInventoryItem* new_item, LLWearable* new_wearable, bool do_append = false); diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index f0711db3bd..f393cf1206 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -458,6 +458,7 @@ static void settings_to_globals() LLVolumeImplFlexible::sUpdateFactor = gSavedSettings.getF32("RenderFlexTimeFactor"); LLVOTree::sTreeFactor = gSavedSettings.getF32("RenderTreeLODFactor"); LLVOAvatar::sLODFactor = gSavedSettings.getF32("RenderAvatarLODFactor"); + LLVOAvatar::sPhysicsLODFactor = gSavedSettings.getF32("RenderAvatarPhysicsLODFactor"); LLVOAvatar::sMaxVisible = (U32)gSavedSettings.getS32("RenderAvatarMaxVisible"); LLVOAvatar::sVisibleInFirstPerson = gSavedSettings.getBOOL("FirstPersonAvatarVisible"); // clamp auto-open time to some minimum usable value diff --git a/indra/newview/llbreastmotion.cpp b/indra/newview/llbreastmotion.cpp new file mode 100644 index 0000000000..7c205a8b9f --- /dev/null +++ b/indra/newview/llbreastmotion.cpp @@ -0,0 +1,402 @@ +/** + * @file llbreastmotion.cpp + * @brief Implementation of LLBreastMotion 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 "llbreastmotion.h" +#include "llcharacter.h" +#include "llviewercontrol.h" +#include "llviewervisualparam.h" +#include "llvoavatarself.h" + +#define MIN_REQUIRED_PIXEL_AREA_BREAST_MOTION 0.f; + +#define N_PARAMS 2 + +// User-set params +static const std::string breast_param_names_user[N_PARAMS] = +{ + "Breast_Female_Cleavage_Driver", + "Breast_Gravity_Driver" +}; + +// Params driven by this algorithm +static const std::string breast_param_names_driven[N_PARAMS] = +{ + "Breast_Female_Cleavage", + "Breast_Gravity" +}; + + + +LLBreastMotion::LLBreastMotion(const LLUUID &id) : + LLMotion(id), + mCharacter(NULL) +{ + mName = "breast_motion"; + mChestState = new LLJointState; + + mBreastMassParam = (F32)1.0; + mBreastDragParam = LLVector3((F32)0.1, (F32)0.1, (F32)0.1); + mBreastSmoothingParam = (U32)2; + mBreastGravityParam = (F32)0.0; + + mBreastSpringParam = LLVector3((F32)3.0, (F32)0.0, (F32)3.0); + mBreastGainParam = LLVector3((F32)50.0, (F32)0.0, (F32)50.0); + mBreastDampingParam = LLVector3((F32)0.3, (F32)0.0, (F32)0.3); + mBreastMaxVelocityParam = LLVector3((F32)10.0, (F32)0.0, (F32)10.0); + + mBreastParamsUser[0] = mBreastParamsUser[1] = mBreastParamsUser[2] = NULL; + mBreastParamsDriven[0] = mBreastParamsDriven[1] = mBreastParamsDriven[2] = NULL; + + mCharLastPosition_world_pt = LLVector3(0,0,0); + mCharLastVelocity_local_vec = LLVector3(0,0,0); + mCharLastAcceleration_local_vec = LLVector3(0,0,0); + mBreastLastPosition_local_pt = LLVector3(0,0,0); + mBreastLastUpdatePosition_local_pt = LLVector3(0,0,0); + mBreastVelocity_local_vec = LLVector3(0,0,0); +} + +LLBreastMotion::~LLBreastMotion() +{ +} + +BOOL LLBreastMotion::onActivate() +{ + return TRUE; +} + +void LLBreastMotion::onDeactivate() +{ +} + +LLMotion::LLMotionInitStatus LLBreastMotion::onInitialize(LLCharacter *character) +{ + mCharacter = character; + + if (!mChestState->setJoint(character->getJoint("mChest"))) + { + return STATUS_FAILURE; + } + + mChestState->setUsage(LLJointState::ROT); + addJointState( mChestState ); + + for (U32 i=0; i < N_PARAMS; i++) + { + mBreastParamsUser[i] = NULL; + mBreastParamsDriven[i] = NULL; + mBreastParamsMin[i] = 0; + mBreastParamsMax[i] = 0; + if (breast_param_names_user[i] != "" && breast_param_names_driven[i] != "") + { + mBreastParamsUser[i] = (LLViewerVisualParam*)mCharacter->getVisualParam(breast_param_names_user[i].c_str()); + mBreastParamsDriven[i] = (LLViewerVisualParam*)mCharacter->getVisualParam(breast_param_names_driven[i].c_str()); + if (mBreastParamsDriven[i]) + { + mBreastParamsMin[i] = mBreastParamsDriven[i]->getMinWeight(); + mBreastParamsMax[i] = mBreastParamsDriven[i]->getMaxWeight(); + } + } + } + + mTimer.reset(); + return STATUS_SUCCESS; +} + +F32 LLBreastMotion::getMinPixelArea() +{ + return MIN_REQUIRED_PIXEL_AREA_BREAST_MOTION; +} + + +F32 LLBreastMotion::calculateTimeDelta() +{ + const F32 time = mTimer.getElapsedTimeF32(); + const F32 time_delta = time - mLastTime; + mLastTime = time; + return time_delta; +} + +// Local space means "parameter space". +LLVector3 LLBreastMotion::toLocal(const LLVector3 &world_vector) +{ + LLVector3 local_vec(0,0,0); + + LLJoint *chest_joint = mChestState->getJoint(); + const LLQuaternion world_rot = chest_joint->getWorldRotation(); + + // Cleavage + LLVector3 breast_dir_world_vec = LLVector3(-1,0,0) * world_rot; // -1 b/c cleavage param changes opposite to direction + breast_dir_world_vec.normalize(); + local_vec[0] = world_vector * breast_dir_world_vec; + + // Up-Down Bounce + LLVector3 breast_up_dir_world_vec = LLVector3(0,0,1) * world_rot; + breast_up_dir_world_vec.normalize(); + local_vec[1] = world_vector * breast_up_dir_world_vec; + + return local_vec; +} + +LLVector3 LLBreastMotion::calculateVelocity_local(const F32 time_delta) +{ + LLJoint *chest_joint = mChestState->getJoint(); + const LLVector3 world_pos_pt = chest_joint->getWorldPosition(); + const LLQuaternion world_rot = chest_joint->getWorldRotation(); + const LLVector3 last_world_pos_pt = mCharLastPosition_world_pt; + const LLVector3 char_velocity_world_vec = (world_pos_pt-last_world_pos_pt) / time_delta; + const LLVector3 char_velocity_local_vec = toLocal(char_velocity_world_vec); + + return char_velocity_local_vec; +} + +LLVector3 LLBreastMotion::calculateAcceleration_local(const LLVector3 &new_char_velocity_local_vec, + const F32 time_delta) +{ + LLVector3 char_acceleration_local_vec = new_char_velocity_local_vec - mCharLastVelocity_local_vec; + + char_acceleration_local_vec = + char_acceleration_local_vec * 1.0/mBreastSmoothingParam + + mCharLastAcceleration_local_vec * (mBreastSmoothingParam-1.0)/mBreastSmoothingParam; + + mCharLastAcceleration_local_vec = char_acceleration_local_vec; + + return char_acceleration_local_vec; +} + +BOOL LLBreastMotion::onUpdate(F32 time, U8* joint_mask) +{ + // Skip if disabled globally. + if (!gSavedSettings.getBOOL("AvatarPhysics")) + { + return TRUE; + } + + // 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; + } + + if (mCharacter->getSex() != SEX_FEMALE) return TRUE; + const F32 time_delta = calculateTimeDelta(); + if (time_delta < .01 || time_delta > 10.0) return TRUE; + + + //////////////////////////////////////////////////////////////////////////////// + // Get all parameters and settings + // + + mBreastMassParam = mCharacter->getVisualParamWeight("Breast_Physics_Mass"); + mBreastSmoothingParam = (U32)(mCharacter->getVisualParamWeight("Breast_Physics_Smoothing")); + mBreastGravityParam = mCharacter->getVisualParamWeight("Breast_Physics_Gravity"); + + mBreastSpringParam[0] = mCharacter->getVisualParamWeight("Breast_Physics_Side_Spring"); + mBreastGainParam[0] = mCharacter->getVisualParamWeight("Breast_Physics_Side_Gain"); + mBreastDampingParam[0] = mCharacter->getVisualParamWeight("Breast_Physics_Side_Damping"); + mBreastMaxVelocityParam[0] = mCharacter->getVisualParamWeight("Breast_Physics_Side_Max_Velocity"); + mBreastDragParam[0] = mCharacter->getVisualParamWeight("Breast_Physics_Side_Drag"); + + mBreastSpringParam[1] = mCharacter->getVisualParamWeight("Breast_Physics_UpDown_Spring"); + mBreastGainParam[1] = mCharacter->getVisualParamWeight("Breast_Physics_UpDown_Gain"); + mBreastDampingParam[1] = mCharacter->getVisualParamWeight("Breast_Physics_UpDown_Damping"); + mBreastMaxVelocityParam[1] = mCharacter->getVisualParamWeight("Breast_Physics_UpDown_Max_Velocity"); + mBreastDragParam[1] = mCharacter->getVisualParamWeight("Breast_Physics_UpDown_Drag"); + + + // Get the current morph parameters. + LLVector3 breast_user_local_pt(0,0,0); + for (U32 i=0; i < N_PARAMS; i++) + { + if (mBreastParamsUser[i] != NULL) + { + breast_user_local_pt[i] = mBreastParamsUser[i]->getWeight(); + } + } + + LLVector3 breast_current_local_pt = mBreastLastPosition_local_pt; + + // + // End parameters and settings + //////////////////////////////////////////////////////////////////////////////// + + + //////////////////////////////////////////////////////////////////////////////// + // Calculate velocity and acceleration in parameter space. + // + + const LLVector3 char_velocity_local_vec = calculateVelocity_local(time_delta); + const LLVector3 char_acceleration_local_vec = calculateAcceleration_local(char_velocity_local_vec, time_delta); + mCharLastVelocity_local_vec = char_velocity_local_vec; + + LLJoint *chest_joint = mChestState->getJoint(); + mCharLastPosition_world_pt = chest_joint->getWorldPosition(); + + // + // End velocity and acceleration + //////////////////////////////////////////////////////////////////////////////// + + + //////////////////////////////////////////////////////////////////////////////// + // Calculate the total force + // + + // Spring force is a restoring force towards the original user-set breast position. + // F = kx + const LLVector3 spring_length_local = breast_current_local_pt-breast_user_local_pt; + LLVector3 force_spring_local_vec = -spring_length_local; force_spring_local_vec *= mBreastSpringParam; + + // Acceleration is the force that comes from the change in velocity of the torso. + // F = ma + mg + LLVector3 force_accel_local_vec = char_acceleration_local_vec * mBreastMassParam; + const LLVector3 force_gravity_local_vec = toLocal(LLVector3(0,0,1))* mBreastGravityParam * mBreastMassParam; + force_accel_local_vec += force_gravity_local_vec; + force_accel_local_vec *= mBreastGainParam; + + // Damping is a restoring force that opposes the current velocity. + // F = -kv + LLVector3 force_damping_local_vec = -mBreastDampingParam; + force_damping_local_vec *= mBreastVelocity_local_vec; + + // Drag is a force imparted by velocity, intuitively it is similar to wind resistance. + // F = .5v*v + LLVector3 force_drag_local_vec = .5*char_velocity_local_vec; + force_drag_local_vec *= char_velocity_local_vec; + force_drag_local_vec *= mBreastDragParam[0]; + + LLVector3 force_net_local_vec = + force_accel_local_vec + + force_gravity_local_vec + + force_spring_local_vec + + force_damping_local_vec + + force_drag_local_vec; + + // + // End total force + //////////////////////////////////////////////////////////////////////////////// + + + //////////////////////////////////////////////////////////////////////////////// + // Calculate new params + // + + // Calculate the new acceleration based on the net force. + // a = F/m + LLVector3 acceleration_local_vec = force_net_local_vec / mBreastMassParam; + mBreastVelocity_local_vec += acceleration_local_vec; + mBreastVelocity_local_vec.clamp(-mBreastMaxVelocityParam*100.0, mBreastMaxVelocityParam*100.0); + + // Temporary debugging setting to cause all avatars to move, for profiling purposes. + if (gSavedSettings.getBOOL("AvatarPhysicsTest")) + { + mBreastVelocity_local_vec[0] = sin(mTimer.getElapsedTimeF32()*4.0)*5.0; + mBreastVelocity_local_vec[1] = sin(mTimer.getElapsedTimeF32()*3.0)*5.0; + } + // Calculate the new parameters and clamp them to the min/max ranges. + LLVector3 new_local_pt = breast_current_local_pt + mBreastVelocity_local_vec*time_delta; + new_local_pt.clamp(mBreastParamsMin,mBreastParamsMax); + + // Set the new parameters. + for (U32 i=0; i < 3; i++) + { + // If the param is disabled, just set the param to the user value. + if (mBreastMaxVelocityParam[i] == 0) + { + new_local_pt[i] = breast_user_local_pt[i]; + } + if (mBreastParamsDriven[i]) + { + mCharacter->setVisualParamWeight(mBreastParamsDriven[i], + new_local_pt[i], + FALSE); + } + } + + mBreastLastPosition_local_pt = new_local_pt; + + // + // 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 BOOL is_self = (dynamic_cast<LLVOAvatarSelf *>(this) != NULL); + if (!is_self) + { + 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()); + if (pixel_area < area_for_this_setting) + { + return TRUE; + } + } + + // If the parameter hasn't changed enough, then don't update. + LLVector3 position_diff = mBreastLastUpdatePosition_local_pt-new_local_pt; + for (U32 i=0; i < 3; i++) + { + const F32 min_delta = (1.0-lod_factor)*(mBreastParamsMax[i]-mBreastParamsMin[i])/2.0; + if (llabs(position_diff[i]) > min_delta) + { + mCharacter->updateVisualParams(); + mBreastLastUpdatePosition_local_pt = new_local_pt; + return TRUE; + } + } + + // + // End update visual params + //////////////////////////////////////////////////////////////////////////////// + + return TRUE; +} diff --git a/indra/newview/llbreastmotion.h b/indra/newview/llbreastmotion.h new file mode 100644 index 0000000000..8578d4ad1a --- /dev/null +++ b/indra/newview/llbreastmotion.h @@ -0,0 +1,160 @@ +/** + * @file llbreastmotion.h + * @brief Implementation of LLBreastMotion 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_LLBREASTMOTION_H +#define LL_LLBREASTMOTION_H + +//----------------------------------------------------------------------------- +// Header files +//----------------------------------------------------------------------------- +#include "llmotion.h" +#include "llframetimer.h" + +#define BREAST_MOTION_FADEIN_TIME 1.0f +#define BREAST_MOTION_FADEOUT_TIME 1.0f + +class LLViewerVisualParam; + +//----------------------------------------------------------------------------- +// class LLBreastMotion +//----------------------------------------------------------------------------- +class LLBreastMotion : + public LLMotion +{ +public: + // Constructor + LLBreastMotion(const LLUUID &id); + + // Destructor + virtual ~LLBreastMotion(); + +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 LLBreastMotion(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 BREAST_MOTION_FADEIN_TIME; } + + // motions must report their "ease out" duration. + virtual F32 getEaseOutDuration() { return BREAST_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(); + +protected: + LLVector3 toLocal(const LLVector3 &world_vector); + LLVector3 calculateVelocity_local(const F32 time_delta); + LLVector3 calculateAcceleration_local(const LLVector3 &new_char_velocity_local_vec, + const F32 time_delta); + F32 calculateTimeDelta(); +private: + //------------------------------------------------------------------------- + // joint states to be animated + //------------------------------------------------------------------------- + LLPointer<LLJointState> mChestState; + LLCharacter* mCharacter; + + + //------------------------------------------------------------------------- + // miscellaneous parameters + //------------------------------------------------------------------------- + LLViewerVisualParam *mBreastParamsUser[3]; + LLViewerVisualParam *mBreastParamsDriven[3]; + LLVector3 mBreastParamsMin; + LLVector3 mBreastParamsMax; + + LLVector3 mCharLastPosition_world_pt; // Last position of the avatar + LLVector3 mCharLastVelocity_local_vec; // How fast the character is moving + LLVector3 mCharLastAcceleration_local_vec; // Change in character velocity + + LLVector3 mBreastLastPosition_local_pt; // Last parameters for breast + LLVector3 mBreastVelocity_local_vec; // How fast the breast params are moving + LLVector3 mBreastLastUpdatePosition_local_pt; // Last parameters when visual update was sent + + + F32 mBreastMassParam; + F32 mBreastGravityParam; + U32 mBreastSmoothingParam; + + LLVector3 mBreastSpringParam; + LLVector3 mBreastDampingParam; + LLVector3 mBreastGainParam; + LLVector3 mBreastMaxVelocityParam; + LLVector3 mBreastDragParam; + + LLFrameTimer mTimer; + F32 mLastTime; + + U32 mFileTicks; +}; + +#endif // LL_LLBREASTMOTION_H + diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 8c9dfe435a..b0387083d7 100755 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -1200,6 +1200,7 @@ void LLFloaterPreference::refresh() updateSliderText(getChild<LLSliderCtrl>("FlexibleMeshDetail", true), getChild<LLTextBox>("FlexibleMeshDetailText", true)); updateSliderText(getChild<LLSliderCtrl>("TreeMeshDetail", true), getChild<LLTextBox>("TreeMeshDetailText", true)); updateSliderText(getChild<LLSliderCtrl>("AvatarMeshDetail", true), getChild<LLTextBox>("AvatarMeshDetailText", true)); + updateSliderText(getChild<LLSliderCtrl>("AvatarPhysicsDetail", true), getChild<LLTextBox>("AvatarPhysicsDetailText", true)); updateSliderText(getChild<LLSliderCtrl>("TerrainMeshDetail", true), getChild<LLTextBox>("TerrainMeshDetailText", true)); updateSliderText(getChild<LLSliderCtrl>("RenderPostProcess", true), getChild<LLTextBox>("PostProcessText", true)); updateSliderText(getChild<LLSliderCtrl>("SkyMeshDetail", true), getChild<LLTextBox>("SkyMeshDetailText", true)); diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 5108f68592..b9e9a83f42 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -4671,10 +4671,18 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags) else { items.push_back(std::string("Wearable And Object Wear")); - items.push_back(std::string("Wearable Add")); disabled_items.push_back(std::string("Take Off")); disabled_items.push_back(std::string("Wearable Edit")); } + + if (LLWearableType::getAllowMultiwear(mWearableType)) + { + items.push_back(std::string("Wearable Add")); + if (gAgentWearables.getWearableCount(mWearableType) > 0) + { + disabled_items.push_back(std::string("Wearable Add")); + } + } break; default: break; diff --git a/indra/newview/llinventoryicon.cpp b/indra/newview/llinventoryicon.cpp index 3f4f33e88d..95dea219a8 100644 --- a/indra/newview/llinventoryicon.cpp +++ b/indra/newview/llinventoryicon.cpp @@ -82,6 +82,8 @@ LLIconDictionary::LLIconDictionary() addEntry(LLInventoryIcon::ICONNAME_ANIMATION, new IconEntry("Inv_Animation")); addEntry(LLInventoryIcon::ICONNAME_GESTURE, new IconEntry("Inv_Gesture")); + addEntry(LLInventoryIcon::ICONNAME_CLOTHING_PHYSICS, new IconEntry("Inv_Physics")); + addEntry(LLInventoryIcon::ICONNAME_LINKITEM, new IconEntry("Inv_LinkItem")); addEntry(LLInventoryIcon::ICONNAME_LINKFOLDER, new IconEntry("Inv_LinkFolder")); diff --git a/indra/newview/llinventoryicon.h b/indra/newview/llinventoryicon.h index 9a2cc08095..694b56d572 100644 --- a/indra/newview/llinventoryicon.h +++ b/indra/newview/llinventoryicon.h @@ -66,9 +66,11 @@ public: ICONNAME_CLOTHING_SKIRT, ICONNAME_CLOTHING_ALPHA, ICONNAME_CLOTHING_TATTOO, - + ICONNAME_ANIMATION, ICONNAME_GESTURE, + + ICONNAME_CLOTHING_PHYSICS, ICONNAME_LINKITEM, ICONNAME_LINKFOLDER, diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp index 90ed8b9e58..baccb9a807 100644 --- a/indra/newview/llpaneleditwearable.cpp +++ b/indra/newview/llpaneleditwearable.cpp @@ -94,7 +94,8 @@ enum ESubpart { SUBPART_UNDERPANTS, SUBPART_SKIRT, SUBPART_ALPHA, - SUBPART_TATTOO + SUBPART_TATTOO, + SUBPART_PHYSICS }; using namespace LLVOAvatarDefines; @@ -218,7 +219,7 @@ LLEditWearableDictionary::Wearables::Wearables() // note the subpart that is listed first is treated as "default", regardless of what order is in enum. // Please match the order presented in XUI. -Nyx // this will affect what camera angle is shown when first editing a wearable - addEntry(LLWearableType::WT_SHAPE, new WearableEntry(LLWearableType::WT_SHAPE,"edit_shape_title","shape_desc_text",0,0,9, SUBPART_SHAPE_WHOLE, SUBPART_SHAPE_HEAD, SUBPART_SHAPE_EYES, SUBPART_SHAPE_EARS, SUBPART_SHAPE_NOSE, SUBPART_SHAPE_MOUTH, SUBPART_SHAPE_CHIN, SUBPART_SHAPE_TORSO, SUBPART_SHAPE_LEGS )); + addEntry(LLWearableType::WT_SHAPE, new WearableEntry(LLWearableType::WT_SHAPE,"edit_shape_title","shape_desc_text",0,0,9, SUBPART_SHAPE_WHOLE, SUBPART_SHAPE_HEAD, SUBPART_SHAPE_EYES, SUBPART_SHAPE_EARS, SUBPART_SHAPE_NOSE, SUBPART_SHAPE_MOUTH, SUBPART_SHAPE_CHIN, SUBPART_SHAPE_TORSO, SUBPART_SHAPE_LEGS)); addEntry(LLWearableType::WT_SKIN, new WearableEntry(LLWearableType::WT_SKIN,"edit_skin_title","skin_desc_text",0,3,4, TEX_HEAD_BODYPAINT, TEX_UPPER_BODYPAINT, TEX_LOWER_BODYPAINT, SUBPART_SKIN_COLOR, SUBPART_SKIN_FACEDETAIL, SUBPART_SKIN_MAKEUP, SUBPART_SKIN_BODYDETAIL)); addEntry(LLWearableType::WT_HAIR, new WearableEntry(LLWearableType::WT_HAIR,"edit_hair_title","hair_desc_text",0,1,4, TEX_HAIR, SUBPART_HAIR_COLOR, SUBPART_HAIR_STYLE, SUBPART_HAIR_EYEBROWS, SUBPART_HAIR_FACIAL)); addEntry(LLWearableType::WT_EYES, new WearableEntry(LLWearableType::WT_EYES,"edit_eyes_title","eyes_desc_text",0,1,1, TEX_EYES_IRIS, SUBPART_EYES)); @@ -233,6 +234,7 @@ LLEditWearableDictionary::Wearables::Wearables() addEntry(LLWearableType::WT_SKIRT, new WearableEntry(LLWearableType::WT_SKIRT,"edit_skirt_title","skirt_desc_text",1,1,1, TEX_SKIRT, TEX_SKIRT, SUBPART_SKIRT)); addEntry(LLWearableType::WT_ALPHA, new WearableEntry(LLWearableType::WT_ALPHA,"edit_alpha_title","alpha_desc_text",0,5,1, TEX_LOWER_ALPHA, TEX_UPPER_ALPHA, TEX_HEAD_ALPHA, TEX_EYES_ALPHA, TEX_HAIR_ALPHA, SUBPART_ALPHA)); addEntry(LLWearableType::WT_TATTOO, new WearableEntry(LLWearableType::WT_TATTOO,"edit_tattoo_title","tattoo_desc_text",1,3,1, TEX_HEAD_TATTOO, TEX_LOWER_TATTOO, TEX_UPPER_TATTOO, TEX_HEAD_TATTOO, SUBPART_TATTOO)); + addEntry(LLWearableType::WT_PHYSICS, new WearableEntry(LLWearableType::WT_PHYSICS,"edit_physics_title","physics_desc_text",0,0,1, SUBPART_PHYSICS)); } LLEditWearableDictionary::WearableEntry::WearableEntry(LLWearableType::EType type, @@ -303,6 +305,7 @@ LLEditWearableDictionary::Subparts::Subparts() addEntry(SUBPART_UNDERPANTS, new SubpartEntry(SUBPART_UNDERPANTS, "mPelvis", "underpants", "underpants_main_param_list", "underpants_main_tab", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f),SEX_BOTH)); addEntry(SUBPART_ALPHA, new SubpartEntry(SUBPART_ALPHA, "mPelvis", "alpha", "alpha_main_param_list", "alpha_main_tab", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f),SEX_BOTH)); addEntry(SUBPART_TATTOO, new SubpartEntry(SUBPART_TATTOO, "mPelvis", "tattoo", "tattoo_main_param_list", "tattoo_main_tab", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f),SEX_BOTH)); + addEntry(SUBPART_PHYSICS, new SubpartEntry(SUBPART_PHYSICS, "mTorso", "physics", "physics_main_param_list", "physics_main_tab", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(-1.f, 0.15f, 0.3f),SEX_FEMALE)); } LLEditWearableDictionary::SubpartEntry::SubpartEntry(ESubpart part, @@ -739,6 +742,7 @@ BOOL LLPanelEditWearable::postBuild() mPanelSkirt = getChild<LLPanel>("edit_skirt_panel"); mPanelAlpha = getChild<LLPanel>("edit_alpha_panel"); mPanelTattoo = getChild<LLPanel>("edit_tattoo_panel"); + mPanelPhysics = getChild<LLPanel>("edit_physics_panel"); mTxtAvatarHeight = mPanelShape->getChild<LLTextBox>("avatar_height"); @@ -847,11 +851,11 @@ void LLPanelEditWearable::setVisible(BOOL visible) LLPanel::setVisible(visible); } -void LLPanelEditWearable::setWearable(LLWearable *wearable) +void LLPanelEditWearable::setWearable(LLWearable *wearable, BOOL disable_camera_switch) { - showWearable(mWearablePtr, FALSE); + showWearable(mWearablePtr, FALSE, disable_camera_switch); mWearablePtr = wearable; - showWearable(mWearablePtr, TRUE); + showWearable(mWearablePtr, TRUE, disable_camera_switch); } @@ -1051,7 +1055,7 @@ void LLPanelEditWearable::revertChanges() gAgentAvatarp->wearableUpdated(mWearablePtr->getType(), FALSE); } -void LLPanelEditWearable::showWearable(LLWearable* wearable, BOOL show) +void LLPanelEditWearable::showWearable(LLWearable* wearable, BOOL show, BOOL disable_camera_switch) { if (!wearable) { @@ -1146,7 +1150,10 @@ void LLPanelEditWearable::showWearable(LLWearable* wearable, BOOL show) updateScrollingPanelUI(); } - showDefaultSubpart(); + if (!disable_camera_switch) + { + showDefaultSubpart(); + } updateVerbs(); } @@ -1154,7 +1161,7 @@ void LLPanelEditWearable::showWearable(LLWearable* wearable, BOOL show) void LLPanelEditWearable::showDefaultSubpart() { - changeCamera(0); + changeCamera(3); } void LLPanelEditWearable::onTabExpandedCollapsed(const LLSD& param, U8 index) @@ -1355,6 +1362,11 @@ LLPanel* LLPanelEditWearable::getPanel(LLWearableType::EType type) case LLWearableType::WT_TATTOO: return mPanelTattoo; break; + + case LLWearableType::WT_PHYSICS: + return mPanelPhysics; + break; + default: break; } diff --git a/indra/newview/llpaneleditwearable.h b/indra/newview/llpaneleditwearable.h index 43513d8ab3..692a7ce90f 100644 --- a/indra/newview/llpaneleditwearable.h +++ b/indra/newview/llpaneleditwearable.h @@ -55,8 +55,11 @@ public: /*virtual*/ BOOL isDirty() const; // LLUICtrl /*virtual*/ void draw(); + // changes camera angle to default for selected subpart + void changeCamera(U8 subpart); + LLWearable* getWearable() { return mWearablePtr; } - void setWearable(LLWearable *wearable); + void setWearable(LLWearable *wearable, BOOL disable_camera_switch = FALSE); void saveChanges(bool force_save_as = false); void revertChanges(); @@ -77,7 +80,7 @@ public: private: typedef std::map<F32, LLViewerVisualParam*> value_map_t; - void showWearable(LLWearable* wearable, BOOL show); + void showWearable(LLWearable* wearable, BOOL show, BOOL disable_camera_switch = FALSE); void updateScrollingPanelUI(); LLPanel* getPanel(LLWearableType::EType type); void getSortedParams(value_map_t &sorted_params, const std::string &edit_group); @@ -91,9 +94,6 @@ private: void toggleTypeSpecificControls(LLWearableType::EType type); void updateTypeSpecificControls(LLWearableType::EType type); - // changes camera angle to default for selected subpart - void changeCamera(U8 subpart); - //alpha mask checkboxes void configureAlphaCheckbox(LLVOAvatarDefines::ETextureIndex te, const std::string& name); void onInvisibilityCommit(LLCheckBoxCtrl* checkbox_ctrl, LLVOAvatarDefines::ETextureIndex te); @@ -163,6 +163,7 @@ private: LLPanel *mPanelSkirt; LLPanel *mPanelAlpha; LLPanel *mPanelTattoo; + LLPanel *mPanelPhysics; typedef std::map<std::string, LLVOAvatarDefines::ETextureIndex> string_texture_index_map_t; string_texture_index_map_t mAlphaCheckbox2Index; diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp index c10c21683b..08d781cb47 100644 --- a/indra/newview/llpaneloutfitedit.cpp +++ b/indra/newview/llpaneloutfitedit.cpp @@ -466,6 +466,7 @@ BOOL LLPanelOutfitEdit::postBuild() mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("skirt"), new LLFindActualWearablesOfType(LLWearableType::WT_SKIRT))); mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("alpha"), new LLFindActualWearablesOfType(LLWearableType::WT_ALPHA))); mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("tattoo"), new LLFindActualWearablesOfType(LLWearableType::WT_TATTOO))); + mListViewItemTypes.push_back(new LLFilterItem(LLTrans::getString("physics"), new LLFindActualWearablesOfType(LLWearableType::WT_PHYSICS))); mCurrentOutfitName = getChild<LLTextBox>("curr_outfit_name"); mStatus = getChild<LLTextBox>("status"); diff --git a/indra/newview/llpaneloutfitedit.h b/indra/newview/llpaneloutfitedit.h index fd366e9cbc..5d4b8d4644 100644 --- a/indra/newview/llpaneloutfitedit.h +++ b/indra/newview/llpaneloutfitedit.h @@ -97,6 +97,7 @@ public: LVIT_SKIRT, LVIT_ALPHA, LVIT_TATTOO, + LVIT_PHYSICS, NUM_LIST_VIEW_ITEM_TYPES } EListViewItemType; diff --git a/indra/newview/llpolymesh.cpp b/indra/newview/llpolymesh.cpp index 363b0b8e9d..2942f4befb 100644 --- a/indra/newview/llpolymesh.cpp +++ b/indra/newview/llpolymesh.cpp @@ -602,6 +602,12 @@ BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName ) } mMorphData.insert(morph_data); + /* + if (std::string(morphName) == "Breast_Gravity") + { + LLPolyMorphData *morph_data_clone = new LLPolyMorphData(std::string(morphName)); + } + */ } S32 numRemaps; diff --git a/indra/newview/llpolymorph.cpp b/indra/newview/llpolymorph.cpp index 0ffe1c635f..ec41ef08f5 100644 --- a/indra/newview/llpolymorph.cpp +++ b/indra/newview/llpolymorph.cpp @@ -287,10 +287,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) + { + 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 " << getInfo()->mMorphName << " found in mesh." << llendl; + llwarns << "No morph target named " << morph_param_name << " found in mesh." << llendl; return FALSE; // Continue, ignoring this tag } return TRUE; diff --git a/indra/newview/llsidepanelappearance.cpp b/indra/newview/llsidepanelappearance.cpp index b316171604..eed59e4705 100644 --- a/indra/newview/llsidepanelappearance.cpp +++ b/indra/newview/llsidepanelappearance.cpp @@ -193,18 +193,26 @@ void LLSidepanelAppearance::updateToVisibility(const LLSD &new_visibility) { if (new_visibility["visible"].asBoolean()) { - bool is_outfit_edit_visible = mOutfitEdit && mOutfitEdit->getVisible(); - bool is_wearable_edit_visible = mEditWearable && mEditWearable->getVisible(); + const BOOL is_outfit_edit_visible = mOutfitEdit && mOutfitEdit->getVisible(); + const BOOL is_wearable_edit_visible = mEditWearable && mEditWearable->getVisible(); if (is_outfit_edit_visible || is_wearable_edit_visible) { - if (!gAgentCamera.cameraCustomizeAvatar() && gSavedSettings.getBOOL("AppearanceCameraMovement")) + const LLWearable *wearable_ptr = mEditWearable->getWearable(); + if (!wearable_ptr) + { + llwarns << "Visibility change to invalid wearable" << llendl; + return; + } + const BOOL disable_camera_motion = LLWearableType::getDisableCameraSwitch(wearable_ptr->getType()); + if (!gAgentCamera.cameraCustomizeAvatar() && + !disable_camera_motion && + gSavedSettings.getBOOL("AppearanceCameraMovement")) { gAgentCamera.changeCameraToCustomizeAvatar(); } if (is_wearable_edit_visible) { - LLWearable *wearable_ptr = mEditWearable->getWearable(); if (gAgentWearables.getWearableIndex(wearable_ptr) == LLAgentWearables::MAX_CLOTHING_PER_TYPE) { // we're no longer wearing the wearable we were last editing, switch back to outfit editor @@ -289,7 +297,7 @@ void LLSidepanelAppearance::showOutfitsInventoryPanel() { toggleWearableEditPanel(FALSE); toggleOutfitEditPanel(FALSE); - togglMyOutfitsPanel(TRUE); + toggleMyOutfitsPanel(TRUE); } void LLSidepanelAppearance::showOutfitEditPanel() @@ -305,19 +313,19 @@ void LLSidepanelAppearance::showOutfitEditPanel() mOutfitEdit->resetAccordionState(); } - togglMyOutfitsPanel(FALSE); + toggleMyOutfitsPanel(FALSE); toggleWearableEditPanel(FALSE, NULL, TRUE); // don't switch out of edit appearance mode toggleOutfitEditPanel(TRUE); } -void LLSidepanelAppearance::showWearableEditPanel(LLWearable *wearable /* = NULL*/) +void LLSidepanelAppearance::showWearableEditPanel(LLWearable *wearable /* = NULL*/, BOOL disable_camera_switch) { - togglMyOutfitsPanel(FALSE); + toggleMyOutfitsPanel(FALSE); toggleOutfitEditPanel(FALSE, TRUE); // don't switch out of edit appearance mode - toggleWearableEditPanel(TRUE, wearable); + toggleWearableEditPanel(TRUE, wearable, disable_camera_switch); } -void LLSidepanelAppearance::togglMyOutfitsPanel(BOOL visible) +void LLSidepanelAppearance::toggleMyOutfitsPanel(BOOL visible) { if (!mPanelOutfitsInventory || mPanelOutfitsInventory->getVisible() == visible) { @@ -390,7 +398,7 @@ void LLSidepanelAppearance::toggleWearableEditPanel(BOOL visible, LLWearable *we { gAgentCamera.changeCameraToCustomizeAvatar(); } - mEditWearable->setWearable(wearable); + mEditWearable->setWearable(wearable, disable_camera_switch); mEditWearable->onOpen(LLSD()); // currently no-op, just for consistency } else @@ -434,14 +442,14 @@ void LLSidepanelAppearance::refreshCurrentOutfitName(const std::string& name) } //static -void LLSidepanelAppearance::editWearable(LLWearable *wearable, LLView *data) +void LLSidepanelAppearance::editWearable(LLWearable *wearable, LLView *data, BOOL disable_camera_switch) { LLSideTray::getInstance()->showPanel("sidepanel_appearance"); LLSidepanelAppearance *panel = dynamic_cast<LLSidepanelAppearance*>(data); if (panel) { - panel->showWearableEditPanel(wearable); + panel->showWearableEditPanel(wearable, disable_camera_switch); } } diff --git a/indra/newview/llsidepanelappearance.h b/indra/newview/llsidepanelappearance.h index 2a83dfbc9d..6dd3520266 100644 --- a/indra/newview/llsidepanelappearance.h +++ b/indra/newview/llsidepanelappearance.h @@ -51,7 +51,7 @@ public: void refreshCurrentOutfitName(const std::string& name = ""); - static void editWearable(LLWearable *wearable, LLView *data); + static void editWearable(LLWearable *wearable, LLView *data, BOOL disable_camera_switch = FALSE); void fetchInventory(); void inventoryFetched(); @@ -59,7 +59,7 @@ public: void showOutfitsInventoryPanel(); void showOutfitEditPanel(); - void showWearableEditPanel(LLWearable *wearable = NULL); + void showWearableEditPanel(LLWearable *wearable = NULL, BOOL disable_camera_switch = FALSE); void setWearablesLoading(bool val); void showDefaultSubpart(); void updateScrollingPanelList(); @@ -72,7 +72,7 @@ private: void onOpenOutfitButtonClicked(); void onEditAppearanceButtonClicked(); - void togglMyOutfitsPanel(BOOL visible); + void toggleMyOutfitsPanel(BOOL visible); void toggleOutfitEditPanel(BOOL visible, BOOL disable_camera_switch = FALSE); void toggleWearableEditPanel(BOOL visible, LLWearable* wearable = NULL, BOOL disable_camera_switch = FALSE); diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 8c5a52c187..5d0fea2704 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -164,6 +164,12 @@ static bool handleAvatarLODChanged(const LLSD& newvalue) return true; } +static bool handleAvatarPhysicsLODChanged(const LLSD& newvalue) +{ + LLVOAvatar::sPhysicsLODFactor = (F32) newvalue.asReal(); + return true; +} + static bool handleAvatarMaxVisibleChanged(const LLSD& newvalue) { LLVOAvatar::sMaxVisible = (U32) newvalue.asInteger(); @@ -543,6 +549,7 @@ void settings_setup_listeners() gSavedSettings.getControl("RenderAvatarMaxVisible")->getSignal()->connect(boost::bind(&handleAvatarMaxVisibleChanged, _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)); gSavedSettings.getControl("RenderTerrainLODFactor")->getSignal()->connect(boost::bind(&handleTerrainLODChanged, _2)); gSavedSettings.getControl("RenderTreeLODFactor")->getSignal()->connect(boost::bind(&handleTreeLODChanged, _2)); gSavedSettings.getControl("RenderFlexTimeFactor")->getSignal()->connect(boost::bind(&handleFlexLODChanged, _2)); diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index b3642a2c1e..a9312e9c40 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -89,6 +89,7 @@ public: mInventoryItemsDict["New Skirt"] = LLTrans::getString("New Skirt"); mInventoryItemsDict["New Alpha"] = LLTrans::getString("New Alpha"); mInventoryItemsDict["New Tattoo"] = LLTrans::getString("New Tattoo"); + mInventoryItemsDict["New Physics"] = LLTrans::getString("New Physics"); mInventoryItemsDict["Invalid Wearable"] = LLTrans::getString("Invalid Wearable"); mInventoryItemsDict["New Gesture"] = LLTrans::getString("New Gesture"); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 60b118284b..6b50fda433 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -3616,6 +3616,15 @@ class LLEnableEditShape : public view_listener_t } }; +class LLEnableEditPhysics : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + //return gAgentWearables.isWearableModifiable(LLWearableType::WT_SHAPE, 0); + return TRUE; + } +}; + bool is_object_sittable() { LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); @@ -5606,6 +5615,11 @@ void handle_edit_shape() LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD().with("type", "edit_shape")); } +void handle_edit_physics() +{ + LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD().with("type", "edit_physics")); +} + void handle_report_abuse() { // Prevent menu from appearing in screen shot. @@ -7831,9 +7845,11 @@ void initialize_menus() view_listener_t::addMenu(new LLEditEnableTakeOff(), "Edit.EnableTakeOff"); view_listener_t::addMenu(new LLEditEnableCustomizeAvatar(), "Edit.EnableCustomizeAvatar"); view_listener_t::addMenu(new LLEnableEditShape(), "Edit.EnableEditShape"); + view_listener_t::addMenu(new LLEnableEditPhysics(), "Edit.EnableEditPhysics"); commit.add("CustomizeAvatar", boost::bind(&handle_customize_avatar)); commit.add("EditOutfit", boost::bind(&handle_edit_outfit)); commit.add("EditShape", boost::bind(&handle_edit_shape)); + commit.add("EditPhysics", boost::bind(&handle_edit_physics)); // View menu view_listener_t::addMenu(new LLViewMouselook(), "View.Mouselook"); diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index fd89044995..116dd73cb9 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -48,6 +48,7 @@ #include "llanimationstates.h" #include "llavatarnamecache.h" #include "llavatarpropertiesprocessor.h" +#include "llbreastmotion.h" #include "llviewercontrol.h" #include "llcallingcard.h" // IDEVO for LLAvatarTracker #include "lldrawpoolavatar.h" @@ -108,6 +109,8 @@ extern F32 ANIM_SPEED_MIN; #include <boost/lexical_cast.hpp> +// #define OUTPUT_BREAST_DATA + using namespace LLVOAvatarDefines; //----------------------------------------------------------------------------- @@ -123,6 +126,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_BREAST_MOTION = LLUUID("7360e029-3cb8-ebc4-863e-212df440d987"); //"breast_motion" //----------------------------------------------------------------------------- @@ -620,6 +624,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; @@ -1144,6 +1149,7 @@ void LLVOAvatar::initClass() gAnimLibrary.animStateSetString(ANIM_AGENT_BODY_NOISE,"body_noise"); gAnimLibrary.animStateSetString(ANIM_AGENT_BREATHE_ROT,"breathe_rot"); + gAnimLibrary.animStateSetString(ANIM_AGENT_BREAST_MOTION,"breast_motion"); gAnimLibrary.animStateSetString(ANIM_AGENT_EDITING,"editing"); gAnimLibrary.animStateSetString(ANIM_AGENT_EYE,"eye"); gAnimLibrary.animStateSetString(ANIM_AGENT_FLY_ADJUST,"fly_adjust"); @@ -1282,6 +1288,7 @@ void LLVOAvatar::initInstance(void) // motions without a start/stop bit registerMotion( ANIM_AGENT_BODY_NOISE, LLBodyNoiseMotion::create ); registerMotion( ANIM_AGENT_BREATHE_ROT, LLBreatheMotionRot::create ); + registerMotion( ANIM_AGENT_BREAST_MOTION, LLBreastMotion::create ); registerMotion( ANIM_AGENT_EDITING, LLEditingMotion::create ); registerMotion( ANIM_AGENT_EYE, LLEyeMotion::create ); registerMotion( ANIM_AGENT_FEMALE_WALK, LLKeyframeWalkMotion::create ); @@ -1695,6 +1702,7 @@ void LLVOAvatar::startDefaultMotions() startMotion( ANIM_AGENT_EYE ); startMotion( ANIM_AGENT_BODY_NOISE ); startMotion( ANIM_AGENT_BREATHE_ROT ); + startMotion( ANIM_AGENT_BREAST_MOTION ); startMotion( ANIM_AGENT_HAND_MOTION ); startMotion( ANIM_AGENT_PELVIS_FIX ); @@ -6211,11 +6219,9 @@ void LLVOAvatar::updateMeshTextures() // When an avatar is changing clothes and not in Appearance mode, // use the last-known good baked texture until it finish the first // render of the new layerset. - const BOOL layerset_invalid = mBakedTextureDatas[i].mTexLayerSet && ( !mBakedTextureDatas[i].mTexLayerSet->getComposite()->isInitialized() || !mBakedTextureDatas[i].mTexLayerSet->isLocalTextureDataAvailable() ); - use_lkg_baked_layer[i] = (!is_layer_baked[i] && (mBakedTextureDatas[i].mLastTextureIndex != IMG_DEFAULT_AVATAR) && layerset_invalid); diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index a779a1735c..f5f90b2912 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -50,6 +50,7 @@ extern const LLUUID ANIM_AGENT_BODY_NOISE; extern const LLUUID ANIM_AGENT_BREATHE_ROT; +extern const LLUUID ANIM_AGENT_BREAST_MOTION; extern const LLUUID ANIM_AGENT_EDITING; extern const LLUUID ANIM_AGENT_EYE; extern const LLUUID ANIM_AGENT_FLY_ADJUST; @@ -240,6 +241,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; diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp index a49dc1b59d..4373eec02a 100644 --- a/indra/newview/llwearableitemslist.cpp +++ b/indra/newview/llwearableitemslist.cpp @@ -443,6 +443,7 @@ clothing_to_string_map_t init_clothing_string_map() w_map.insert(std::make_pair(LLWearableType::WT_SKIRT, "skirt_not_worn")); w_map.insert(std::make_pair(LLWearableType::WT_ALPHA, "alpha_not_worn")); w_map.insert(std::make_pair(LLWearableType::WT_TATTOO, "tattoo_not_worn")); + w_map.insert(std::make_pair(LLWearableType::WT_PHYSICS, "physics_not_worn")); return w_map; } @@ -888,6 +889,7 @@ void LLWearableItemsList::ContextMenu::updateItemsVisibility(LLContextMenu* menu setMenuItemVisible(menu, "edit", !standalone && mask & (MASK_CLOTHING|MASK_BODYPART) && n_worn == n_items && n_worn == 1); setMenuItemEnabled(menu, "edit", n_editable == 1 && n_worn == 1 && n_items == 1); setMenuItemVisible(menu, "create_new", mask & (MASK_CLOTHING|MASK_BODYPART) && n_items == 1); + setMenuItemEnabled(menu, "create_new", canAddWearables(ids)); setMenuItemVisible(menu, "show_original", !standalone); setMenuItemEnabled(menu, "show_original", n_items == 1 && n_links == n_items); setMenuItemVisible(menu, "take_off", mask == MASK_CLOTHING && n_worn == n_items); @@ -1038,6 +1040,10 @@ bool LLWearableItemsList::ContextMenu::canAddWearables(const uuid_vec_t& item_id U32 n_clothes = m_it->second; U32 wearable_count = gAgentWearables.getWearableCount(w_type); + if ((wearable_count > 0) && !LLWearableType::getAllowMultiwear(w_type)) + { + return false; + } if ((wearable_count + n_clothes) > LLAgentWearables::MAX_CLOTHING_PER_TYPE) { return false; diff --git a/indra/newview/llwearabletype.cpp b/indra/newview/llwearabletype.cpp index 0d707d65bf..f933be4d8f 100644 --- a/indra/newview/llwearabletype.cpp +++ b/indra/newview/llwearabletype.cpp @@ -34,25 +34,27 @@ struct WearableEntry : public LLDictionaryEntry WearableEntry(const std::string &name, const std::string& default_new_name, LLAssetType::EType assetType, - LLInventoryIcon::EIconName iconName); + LLInventoryIcon::EIconName iconName, + BOOL disable_camera_switch = FALSE, + BOOL allow_multiwear = TRUE) : + LLDictionaryEntry(name), + mAssetType(assetType), + mDefaultNewName(default_new_name), + mLabel(LLTrans::getString(name)), + mIconName(iconName), + mDisableCameraSwitch(disable_camera_switch), + mAllowMultiwear(allow_multiwear) + { + + } const LLAssetType::EType mAssetType; const std::string mLabel; const std::string mDefaultNewName; //keep mLabel for backward compatibility LLInventoryIcon::EIconName mIconName; + BOOL mDisableCameraSwitch; + BOOL mAllowMultiwear; }; -WearableEntry::WearableEntry(const std::string &name, - const std::string& default_new_name, - LLAssetType::EType assetType, - LLInventoryIcon::EIconName iconName) : - LLDictionaryEntry(name), - mAssetType(assetType), - mDefaultNewName(default_new_name), - mLabel(LLTrans::getString(name)), - mIconName(iconName) -{ -} - class LLWearableDictionary : public LLSingleton<LLWearableDictionary>, public LLDictionary<LLWearableType::EType, WearableEntry> { @@ -62,23 +64,26 @@ public: LLWearableDictionary::LLWearableDictionary() { - addEntry(LLWearableType::WT_SHAPE, new WearableEntry("shape", "New Shape", LLAssetType::AT_BODYPART, LLInventoryIcon::ICONNAME_BODYPART_SHAPE)); - addEntry(LLWearableType::WT_SKIN, new WearableEntry("skin", "New Skin", LLAssetType::AT_BODYPART, LLInventoryIcon::ICONNAME_BODYPART_SKIN)); - addEntry(LLWearableType::WT_HAIR, new WearableEntry("hair", "New Hair", LLAssetType::AT_BODYPART, LLInventoryIcon::ICONNAME_BODYPART_HAIR)); - addEntry(LLWearableType::WT_EYES, new WearableEntry("eyes", "New Eyes", LLAssetType::AT_BODYPART, LLInventoryIcon::ICONNAME_BODYPART_EYES)); - addEntry(LLWearableType::WT_SHIRT, new WearableEntry("shirt", "New Shirt", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_SHIRT)); - addEntry(LLWearableType::WT_PANTS, new WearableEntry("pants", "New Pants", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_PANTS)); - addEntry(LLWearableType::WT_SHOES, new WearableEntry("shoes", "New Shoes", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_SHOES)); - addEntry(LLWearableType::WT_SOCKS, new WearableEntry("socks", "New Socks", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_SOCKS)); - addEntry(LLWearableType::WT_JACKET, new WearableEntry("jacket", "New Jacket", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_JACKET)); - addEntry(LLWearableType::WT_GLOVES, new WearableEntry("gloves", "New Gloves", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_GLOVES)); - addEntry(LLWearableType::WT_UNDERSHIRT, new WearableEntry("undershirt", "New Undershirt", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_UNDERSHIRT)); - addEntry(LLWearableType::WT_UNDERPANTS, new WearableEntry("underpants", "New Underpants", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_UNDERPANTS)); - addEntry(LLWearableType::WT_SKIRT, new WearableEntry("skirt", "New Skirt", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_SKIRT)); - addEntry(LLWearableType::WT_ALPHA, new WearableEntry("alpha", "New Alpha", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_ALPHA)); - addEntry(LLWearableType::WT_TATTOO, new WearableEntry("tattoo", "New Tattoo", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_TATTOO)); - addEntry(LLWearableType::WT_INVALID, new WearableEntry("invalid", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryIcon::ICONNAME_INVALID)); - addEntry(LLWearableType::WT_NONE, new WearableEntry("none", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryIcon::ICONNAME_INVALID)); + addEntry(LLWearableType::WT_SHAPE, new WearableEntry("shape", "New Shape", LLAssetType::AT_BODYPART, LLInventoryIcon::ICONNAME_BODYPART_SHAPE, FALSE, FALSE)); + addEntry(LLWearableType::WT_SKIN, new WearableEntry("skin", "New Skin", LLAssetType::AT_BODYPART, LLInventoryIcon::ICONNAME_BODYPART_SKIN, FALSE, FALSE)); + addEntry(LLWearableType::WT_HAIR, new WearableEntry("hair", "New Hair", LLAssetType::AT_BODYPART, LLInventoryIcon::ICONNAME_BODYPART_HAIR, FALSE, FALSE)); + addEntry(LLWearableType::WT_EYES, new WearableEntry("eyes", "New Eyes", LLAssetType::AT_BODYPART, LLInventoryIcon::ICONNAME_BODYPART_EYES, FALSE, FALSE)); + addEntry(LLWearableType::WT_SHIRT, new WearableEntry("shirt", "New Shirt", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_SHIRT, FALSE, TRUE)); + addEntry(LLWearableType::WT_PANTS, new WearableEntry("pants", "New Pants", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_PANTS, FALSE, TRUE)); + addEntry(LLWearableType::WT_SHOES, new WearableEntry("shoes", "New Shoes", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_SHOES, FALSE, TRUE)); + addEntry(LLWearableType::WT_SOCKS, new WearableEntry("socks", "New Socks", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_SOCKS, FALSE, TRUE)); + addEntry(LLWearableType::WT_JACKET, new WearableEntry("jacket", "New Jacket", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_JACKET, FALSE, TRUE)); + addEntry(LLWearableType::WT_GLOVES, new WearableEntry("gloves", "New Gloves", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_GLOVES, FALSE, TRUE)); + addEntry(LLWearableType::WT_UNDERSHIRT, new WearableEntry("undershirt", "New Undershirt", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_UNDERSHIRT, FALSE, TRUE)); + addEntry(LLWearableType::WT_UNDERPANTS, new WearableEntry("underpants", "New Underpants", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_UNDERPANTS, FALSE, TRUE)); + addEntry(LLWearableType::WT_SKIRT, new WearableEntry("skirt", "New Skirt", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_SKIRT, FALSE, TRUE)); + addEntry(LLWearableType::WT_ALPHA, new WearableEntry("alpha", "New Alpha", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_ALPHA, FALSE, TRUE)); + addEntry(LLWearableType::WT_TATTOO, new WearableEntry("tattoo", "New Tattoo", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_TATTOO, FALSE, TRUE)); + + addEntry(LLWearableType::WT_PHYSICS, new WearableEntry("physics", "New Physics", LLAssetType::AT_CLOTHING, LLInventoryIcon::ICONNAME_CLOTHING_PHYSICS, TRUE, FALSE)); + + addEntry(LLWearableType::WT_INVALID, new WearableEntry("invalid", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryIcon::ICONNAME_NONE, FALSE, FALSE)); + addEntry(LLWearableType::WT_NONE, new WearableEntry("none", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryIcon::ICONNAME_NONE, FALSE, FALSE)); } // static @@ -134,3 +139,19 @@ LLInventoryIcon::EIconName LLWearableType::getIconName(LLWearableType::EType typ return entry->mIconName; } +// static +BOOL LLWearableType::getDisableCameraSwitch(LLWearableType::EType type) +{ + const LLWearableDictionary *dict = LLWearableDictionary::getInstance(); + const WearableEntry *entry = dict->lookup(type); + return entry->mDisableCameraSwitch; +} + +// static +BOOL LLWearableType::getAllowMultiwear(LLWearableType::EType type) +{ + const LLWearableDictionary *dict = LLWearableDictionary::getInstance(); + const WearableEntry *entry = dict->lookup(type); + return entry->mAllowMultiwear; +} + diff --git a/indra/newview/llwearabletype.h b/indra/newview/llwearabletype.h index 3bbf8ba0bd..d633b4807e 100644 --- a/indra/newview/llwearabletype.h +++ b/indra/newview/llwearabletype.h @@ -52,7 +52,8 @@ public: WT_SKIRT = 12, WT_ALPHA = 13, WT_TATTOO = 14, - WT_COUNT = 15, + WT_PHYSICS = 15, + WT_COUNT = 16, WT_INVALID = 255, WT_NONE = -1, @@ -64,6 +65,8 @@ public: static LLAssetType::EType getAssetType(EType type); static EType typeNameToType(const std::string& type_name); static LLInventoryIcon::EIconName getIconName(EType type); + static BOOL getDisableCameraSwitch(EType type); + static BOOL getAllowMultiwear(EType type); protected: LLWearableType() {} diff --git a/indra/newview/skins/default/textures/icons/Inv_Physics.png b/indra/newview/skins/default/textures/icons/Inv_Physics.png Binary files differnew file mode 100644 index 0000000000..ddd36b446b --- /dev/null +++ b/indra/newview/skins/default/textures/icons/Inv_Physics.png diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index 2c00120177..c539ae6ed0 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -224,6 +224,7 @@ with the same filename but different name <texture name="Inv_SysClosed" file_name="icons/Inv_SysClosed.png" preload="false" /> <texture name="Inv_SysOpen" file_name="icons/Inv_SysOpen.png" preload="false" /> <texture name="Inv_Tattoo" file_name="icons/Inv_Tattoo.png" preload="false" /> + <texture name="Inv_Physics" file_name="icons/Inv_Physics.png" preload="false" /> <texture name="Inv_Texture" file_name="icons/Inv_Texture.png" preload="false" /> <texture name="Inv_TrashClosed" file_name="icons/Inv_TrashClosed.png" preload="false" /> <texture name="Inv_TrashOpen" file_name="icons/Inv_TrashOpen.png" preload="false" /> diff --git a/indra/newview/skins/default/xui/en/menu_avatar_self.xml b/indra/newview/skins/default/xui/en/menu_avatar_self.xml index 2afa29ec10..3f0f17d8e5 100644 --- a/indra/newview/skins/default/xui/en/menu_avatar_self.xml +++ b/indra/newview/skins/default/xui/en/menu_avatar_self.xml @@ -152,6 +152,18 @@ </menu_item_call> <menu_item_call enabled="false" + label="Physics" + layout="topleft" + name="Self Physics"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="physics" /> + <menu_item_call.on_enable + function="Edit.EnableTakeOff" + parameter="physics" /> + </menu_item_call> + <menu_item_call + enabled="false" label="Alpha" layout="topleft" name="Self Alpha"> diff --git a/indra/newview/skins/default/xui/en/menu_inventory.xml b/indra/newview/skins/default/xui/en/menu_inventory.xml index c0046d8e28..e91f4458ae 100644 --- a/indra/newview/skins/default/xui/en/menu_inventory.xml +++ b/indra/newview/skins/default/xui/en/menu_inventory.xml @@ -200,6 +200,14 @@ function="Inventory.DoCreate" parameter="tattoo" /> </menu_item_call> + <menu_item_call + label="New Physics" + layout="topleft" + name="New Physics"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="physics" /> + </menu_item_call> </menu> <menu label="New Body Parts" diff --git a/indra/newview/skins/default/xui/en/menu_inventory_add.xml b/indra/newview/skins/default/xui/en/menu_inventory_add.xml index ae98abf4fb..90e8db3709 100644 --- a/indra/newview/skins/default/xui/en/menu_inventory_add.xml +++ b/indra/newview/skins/default/xui/en/menu_inventory_add.xml @@ -188,6 +188,14 @@ function="Inventory.DoCreate" parameter="tattoo" /> </menu_item_call> + <menu_item_call + label="New Physics" + layout="topleft" + name="New Physics"> + <menu_item_call.on_click + function="Inventory.DoCreate" + parameter="physics" /> + </menu_item_call> </menu> <menu height="85" diff --git a/indra/newview/skins/default/xui/en/menu_outfit_gear.xml b/indra/newview/skins/default/xui/en/menu_outfit_gear.xml index 5fc25b8f0f..fc7272b904 100644 --- a/indra/newview/skins/default/xui/en/menu_outfit_gear.xml +++ b/indra/newview/skins/default/xui/en/menu_outfit_gear.xml @@ -133,6 +133,14 @@ parameter="alpha" /> </menu_item_call> <menu_item_call + label="New Physics" + layout="topleft" + name="New Physics"> + <menu_item_call.on_click + function="Gear.Create" + parameter="physics" /> + </menu_item_call> + <menu_item_call label="New Tattoo" layout="topleft" name="New Tattoo"> diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 3d500c2371..cbabdbd042 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -3400,6 +3400,16 @@ parameter="tattoo" /> </menu_item_call> <menu_item_call + label="Physics" + name="Physics"> + <menu_item_call.on_click + function="Edit.TakeOff" + parameter="physics" /> + <menu_item_call.on_enable + function="Edit.EnableTakeOff" + parameter="physics" /> + </menu_item_call> + <menu_item_call label="All Clothes" name="All Clothes"> <menu_item_call.on_click diff --git a/indra/newview/skins/default/xui/en/panel_edit_physics.xml b/indra/newview/skins/default/xui/en/panel_edit_physics.xml new file mode 100644 index 0000000000..4e781e2360 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_edit_physics.xml @@ -0,0 +1,51 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> + <panel + background_visible="true" + follows="all" + height="400" + layout="topleft" + left="0" + name="edit_physics_panel" + top_pad="10" + width="333" > + <panel + border="false" + bg_alpha_color="DkGray2" + bg_opaque_color="DkGray2" + background_visible="true" + background_opaque="true" + follows="all" + height="300" + layout="topleft" + left="10" + name="accordion_panel" + top_pad="10" + width="313"> + <accordion + fit_parent="true" + follows="all" + height ="300" + layout="topleft" + left="0" + name="wearable_accordion" + single_expansion="true" + top="0" + width="313"> + <accordion_tab + layout="topleft" + fit_panel="false" + min_height="150" + name="physics_main_tab" + title="Physics"> + <scrolling_panel_list + follows="all" + layout="topleft" + left="0" + name="physics_main_param_list" + top="0" + width="303" /> + </accordion_tab> + </accordion> + </panel> +</panel> + diff --git a/indra/newview/skins/default/xui/en/panel_edit_wearable.xml b/indra/newview/skins/default/xui/en/panel_edit_wearable.xml index ac8917d272..c8764a6a84 100644 --- a/indra/newview/skins/default/xui/en/panel_edit_wearable.xml +++ b/indra/newview/skins/default/xui/en/panel_edit_wearable.xml @@ -72,6 +72,10 @@ Editing Tattoo </string> <string + name="edit_physics_title"> + Editing Physics + </string> + <string name="shape_desc_text"> Shape: </string> @@ -131,6 +135,10 @@ name="tattoo_desc_text"> Tattoo: </string> + <string + name="physics_desc_text"> + Physics: + </string> <!-- Default width of the button should be to show it without label. Button will be extedned in code to show whole label when wearable is being changed. --> @@ -410,6 +418,16 @@ top="8" visible="false" width="333" /> + <panel + filename="panel_edit_physics.xml" + follows="all" + height="425" + layout="topleft" + left="0" + name="edit_physics_panel" + top="8" + visible="false" + width="333" /> </panel> <panel follows="bottom|left|right" diff --git a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml index 6573822d1a..6904cfa50e 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml @@ -2,7 +2,7 @@ <panel border="true" follows="left|top|right|bottom" - height="408" + height="418" label="Graphics" layout="topleft" left="102" @@ -327,6 +327,37 @@ value="4"/> </combo_box> + <slider + control_name="RenderAvatarPhysicsLODFactor" + follows="left|top" + height="16" + increment="0.125" + initial_value="160" + label=" Avatar Physics:" + label_width="85" + layout="topleft" + left_delta="-6" + name="AvatarPhysicsDetail" + show_text="false" + top_pad="12" + width="154"> + <slider.commit_callback + function="Pref.UpdateSliderText" + parameter="AvatarPhysicsDetailText" /> + </slider> + <text + type="string" + length="1" + follows="left|top" + height="12" + layout="topleft" + left_delta="160" + name="AvatarPhysicsDetailText" + top_pad="-16" + width="128"> + Low + </text> + <slider control_name="RenderFarClip" decimal_digits="0" @@ -618,6 +649,7 @@ width="128"> Low </text> + <text type="string" length="1" @@ -628,7 +660,7 @@ name="AvatarRenderingText" top_pad="18" width="128"> - Avatar rendering: + Avatar Rendering: </text> <check_box control_name="RenderUseImpostors" @@ -672,7 +704,7 @@ left="358" left_pad="-30" name="TerrainDetailText" - top="226" + top="250" width="155"> Terrain detail: </text> @@ -710,7 +742,7 @@ layout="topleft" left="10" name="Apply" - top="383" + top="390" width="115"> <button.commit_callback function="Pref.Apply" /> @@ -722,7 +754,7 @@ layout="topleft" left_pad="3" name="Defaults" - top="383" + top="390" width="115"> <button.commit_callback function="Pref.HardwareDefaults" /> diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 752bb6ed3a..c5ed86569b 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -1853,6 +1853,7 @@ Requests name of an avatar. When data is available the dataserver event will be <string name="skirt">Skirt</string> <string name="alpha">Alpha</string> <string name="tattoo">Tattoo</string> + <string name="physics">Physics</string> <string name="invalid">invalid</string> <string name="none">none</string> @@ -1868,6 +1869,7 @@ Requests name of an avatar. When data is available the dataserver event will be <string name="skirt_not_worn">Skirt not worn</string> <string name="alpha_not_worn">Alpha not worn</string> <string name="tattoo_not_worn">Tattoo not worn</string> + <string name="physics_not_worn">Physics not worn</string> <string name="invalid_not_worn">invalid</string> <!-- Create new wearable of the specified type --> @@ -1886,6 +1888,7 @@ Requests name of an avatar. When data is available the dataserver event will be <string name="create_new_skirt">Create new skirt</string> <string name="create_new_alpha">Create new alpha</string> <string name="create_new_tattoo">Create new tattoo</string> + <string name="create_new_physics">Create new physics</string> <string name="create_new_invalid">invalid</string> <!-- Wearable List--> @@ -2510,6 +2513,21 @@ If you continue to receive this message, contact the [SUPPORT_SITE]. <string name="Bulbous">Bulbous</string> <string name="Bulbous Nose">Bulbous Nose</string> +<string name="Breast Physics Mass">Breast Mass</string> +<string name="Breast Physics Smoothing">Breast Smoothing</string> +<string name="Breast Physics Gravity">Breast Gravity</string> + +<string name="Breast Physics Side Spring">Breast Side Spring</string> +<string name="Breast Physics Side Gain">Breast Side Gain</string> +<string name="Breast Physics Side Damping">Breast Side Damping</string> +<string name="Breast Physics Side Drag">Breast Side Drag</string> +<string name="Breast Physics Side Max Speed">Breast Side Max Speed</string> + +<string name="Breast Physics UpDown Spring">Breast UpDown Spring</string> +<string name="Breast Physics UpDown Gain">Breast UpDown Gain</string> +<string name="Breast Physics UpDown Damping">Breast UpDown Damping</string> +<string name="Breast Physics UpDown Drag">Breast UpDown Drag</string> +<string name="Breast Physics UpDown Max Speed">Breast UpDown Max Speed</string> <string name="Bushy Eyebrows">Bushy Eyebrows</string> <string name="Bushy Hair">Bushy Hair</string> @@ -3217,6 +3235,7 @@ Abuse Report</string> <string name="New Skirt">New Skirt</string> <string name="New Alpha">New Alpha</string> <string name="New Tattoo">New Tattoo</string> + <string name="New Physics">New Physics</string> <string name="Invalid Wearable">Invalid Wearable</string> <string name="New Gesture">New Gesture</string> <string name="New Script">New Script</string> |