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