diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index cc73ffc32..bd7a541fc 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -348,6 +348,7 @@ set(viewer_SOURCE_FILES llpanelweb.cpp llparcelselection.cpp llpatchvertexarray.cpp + llphysicsmotion.cpp llpolymesh.cpp llpolymorph.cpp llprefschat.cpp @@ -822,6 +823,7 @@ set(viewer_HEADER_FILES llpanelweb.h llparcelselection.h llpatchvertexarray.h + llphysicsmotion.h llpolymesh.h llpolymorph.h llprefschat.h diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 550eecce8..a1834dd3d 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -1784,6 +1784,17 @@ Value 2 + AvatarPhysics + + Comment + Enable avatar wearable physics. + Persist + 1 + Type + Boolean + Value + 1 + AvatarSex Comment @@ -8887,6 +8898,17 @@ Value 35 + RenderAvatarPhysicsLODFactor + + Comment + Controls level of detail of avatar physics (such as breast physics). + Persist + 1 + Type + F32 + Value + 1.0 + RenderAvatarInvisible Comment diff --git a/indra/newview/character/avatar_lad.xml b/indra/newview/character/avatar_lad.xml index 7c320eceb..2f92d6212 100755 --- a/indra/newview/character/avatar_lad.xml +++ b/indra/newview/character/avatar_lad.xml @@ -2923,6 +2923,8 @@ id="40" group="1" name="Male_Head" + wearable="shape" + edit_group="driven" value_min="0" value_max="1"> @@ -3508,6 +3510,8 @@ id="104" group="1" name="Big_Belly_Torso" + wearable="shape" + edit_group="driven" value_min="0" value_max="1"> @@ -3824,6 +3828,8 @@ id="855" group="1" name="Love_Handles" + wearable="shape" + edit_group="driven" value_default="0" value_min="-1" value_max="2"> @@ -3879,6 +3885,8 @@ id="100" group="1" name="Male_Torso" + wearable="shape" + edit_group="driven" label_min="Male_Torso" value_min="0" value_max="1"> @@ -4047,9 +4055,66 @@ - + + + + + + + + + + + + + + + + + + + @@ -4537,15 +4607,62 @@ id="153" group="1" name="Male_Legs" + wearable="shape" + edit_group="driven" value_min="0" value_max="1"> - - + + + + + + + + + + + + + + + + + @@ -4828,6 +4946,8 @@ id="852" group="1" name="skirt_bigbutt" + wearable="skirt" + edit_group="driven" label="bigbutt skirt" label_min="less" label_max="more" @@ -4840,6 +4960,8 @@ id="849" group="1" name="skirt_belly" + wearable="skirt" + edit_group="driven" label="big belly skirt" value_min="0" value_max="1"> @@ -4849,6 +4971,8 @@ @@ -4859,6 +4983,8 @@ id="851" group="1" name="skirt_chubby" + wearable="skirt" + edit_group="driven" label_min="less" label_max="more" value_min="0" @@ -4871,6 +4997,8 @@ id="856" group="1" name="skirt_lovehandles" + wearable="skirt" + edit_group="driven" label_min="less" label_max="more" value_min="-1" @@ -4888,11 +5016,32 @@ id="857" group="1" name="skirt_male" + wearable="skirt" + edit_group="driven" value_min="0" value_max="1"> - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 5917d402f..39da9489f 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -7306,7 +7306,8 @@ void LLAgent::createStandardWearables(BOOL female) TRUE, //WT_UNDERPANTS FALSE, //WT_SKIRT FALSE, //WT_ALPHA - FALSE //WT_TATTOO + FALSE, //WT_TATTOO + FALSE, //WT_PHYSICS }; for( S32 i=0; i < WT_COUNT; i++ ) @@ -7918,6 +7919,7 @@ void LLAgent::setWearableOutfit( wearables_to_remove[WT_SKIRT] = remove && gRlvWearableLocks.canRemove(WT_SKIRT); wearables_to_remove[WT_ALPHA] = remove && gRlvWearableLocks.canRemove(WT_ALPHA); wearables_to_remove[WT_TATTOO] = remove && gRlvWearableLocks.canRemove(WT_TATTOO); + wearables_to_remove[WT_PHYSICS] = remove && gRlvWearableLocks.canRemove(WT_PHYSICS); // [/RLVa:KB] S32 count = wearables.count(); @@ -8199,6 +8201,7 @@ void LLAgent::userRemoveAllClothesStep2( BOOL proceed, void* userdata ) gAgent.removeWearable( WT_SKIRT ); gAgent.removeWearable( WT_ALPHA ); gAgent.removeWearable( WT_TATTOO ); + gAgent.removeWearable( WT_PHYSICS ); } } diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 39eba7877..38ae9202e 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -429,6 +429,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 = gSavedSettings.getS32("RenderAvatarMaxVisible"); LLVOAvatar::sVisibleInFirstPerson = gSavedSettings.getBOOL("FirstPersonAvatarVisible"); // clamp auto-open time to some minimum usable value diff --git a/indra/newview/llassetconverter.cpp b/indra/newview/llassetconverter.cpp index 53c56a49c..73da5cd26 100644 --- a/indra/newview/llassetconverter.cpp +++ b/indra/newview/llassetconverter.cpp @@ -144,7 +144,7 @@ LLAssetType::EType LLAssetConverter::convert(std::string src_filename, std::stri return LLAssetType::AT_NONE; } } - else if(exten == "eyes" || exten == "gloves" || exten == "hair" || exten == "jacket" || exten == "pants" || exten == "shape" || exten == "shirt" || exten == "shoes" || exten == "skin" || exten == "skirt" || exten == "socks" || exten == "underpants" || exten == "undershirt" || exten == "bodypart" || exten == "clothing") + else if(exten == "eyes" || exten == "gloves" || exten == "hair" || exten == "jacket" || exten == "pants" || exten == "shape" || exten == "shirt" || exten == "shoes" || exten == "skin" || exten == "skirt" || exten == "socks" || exten == "underpants" || exten == "undershirt" || exten == "bodypart" || exten == "clothing" || exten == "physics") { asset_type = LLAssetType::AT_CLOTHING; if(!copyFile(src_filename, filename)) diff --git a/indra/newview/lldriverparam.h b/indra/newview/lldriverparam.h index 7bc0c1544..2e53ce563 100644 --- a/indra/newview/lldriverparam.h +++ b/indra/newview/lldriverparam.h @@ -35,6 +35,7 @@ #include "llviewervisualparam.h" +class LLPhysicsMotion; class LLVOAvatar; //----------------------------------------------------------------------------- @@ -78,6 +79,7 @@ protected: class LLDriverParam : public LLViewerVisualParam { + friend class LLPhysicsMotion; // physics motion needs to access driven params directly. public: LLDriverParam(LLVOAvatar *avatarp); ~LLDriverParam(); diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index 8648eef7c..5cea197ca 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -693,6 +693,16 @@ BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename) L"Asset Blacklists (*.blacklist)\0*.blacklist\0" \ L"\0"; break; + case FFSAVE_PHYSICS: + if(filename.empty()) + { + wcsncpy( mFilesW,L"untitled.phy", FILENAME_BUFFER_SIZE); + } + mOFN.lpstrDefExt = L"phy"; + mOFN.lpstrFilter = + L"Landmarks (*.phy)\0*.phy\0" \ + L"\0"; + break; // default: return FALSE; diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h index ea1e61fc2..feba53423 100644 --- a/indra/newview/llfilepicker.h +++ b/indra/newview/llfilepicker.h @@ -139,6 +139,7 @@ public: FFSAVE_LANDMARK = 34, FFSAVE_AO = 35, FFSAVE_BLACKLIST = 36, + FFSAVE_PHYSICS = 37, // }; diff --git a/indra/newview/llfloatercustomize.cpp b/indra/newview/llfloatercustomize.cpp index 39d3ce5ab..6a313c2bd 100644 --- a/indra/newview/llfloatercustomize.cpp +++ b/indra/newview/llfloatercustomize.cpp @@ -405,12 +405,19 @@ enum ESubpart { SUBPART_UNDERPANTS, SUBPART_SKIRT, SUBPART_ALPHA, - SUBPART_TATTOO + SUBPART_TATTOO, + SUBPART_PHYSICS_BREASTS_UPDOWN, + SUBPART_PHYSICS_BREASTS_INOUT, + SUBPART_PHYSICS_BREASTS_LEFTRIGHT, + SUBPART_PHYSICS_BELLY_UPDOWN, + SUBPART_PHYSICS_BUTT_UPDOWN, + SUBPART_PHYSICS_BUTT_LEFTRIGHT, + SUBPART_PHYSICS_ADVANCED }; struct LLSubpart { - LLSubpart() : mSex( SEX_BOTH ) {} + LLSubpart() : mSex( SEX_BOTH ), mVisualHint(true) {} std::string mButtonName; std::string mTargetJoint; @@ -418,6 +425,8 @@ struct LLSubpart LLVector3d mTargetOffset; LLVector3d mCameraOffset; ESex mSex; + + bool mVisualHint; }; //////////////////////////////////////////////////////////////////////////// @@ -622,7 +631,7 @@ void LLPanelEditWearable::setSubpart( ESubpart subpart ) llassert( sorted_params.find(-param->getDisplayOrder()) == sorted_params.end() ); // Check for duplicates sorted_params.insert(vt); } - gFloaterCustomize->generateVisualParamHints(NULL, sorted_params); + gFloaterCustomize->generateVisualParamHints(NULL, sorted_params, part->mVisualHint); gFloaterCustomize->updateScrollingPanelUI(); gFloaterCustomize->childSetEnabled("Export", can_export); gFloaterCustomize->childSetEnabled("Import", can_import); @@ -926,6 +935,7 @@ ESubpart LLPanelEditWearable::getDefaultSubpart() case WT_SKIRT: return SUBPART_SKIRT; case WT_ALPHA: return SUBPART_ALPHA; case WT_TATTOO: return SUBPART_TATTOO; + case WT_PHYSICS: return SUBPART_PHYSICS_BELLY_UPDOWN; default: llassert(0); return SUBPART_SHAPE_WHOLE; } @@ -974,6 +984,7 @@ void LLPanelEditWearable::draw() for (std::map::iterator iter = mSubpartList.begin(); iter != mSubpartList.end(); ++iter) { + childSetVisible(iter->second->mButtonName,has_wearable); if( has_wearable && is_complete && is_modifiable ) { childSetEnabled(iter->second->mButtonName, iter->second->mSex & avatar->getSex() ); @@ -993,6 +1004,8 @@ void LLPanelEditWearable::draw() childSetVisible("path", FALSE); + LLTextBox *av_height = getChild("avheight",FALSE,FALSE); + if(av_height) //Only display this if the element exists { // Display the shape's nominal height. // @@ -1006,8 +1019,8 @@ void LLPanelEditWearable::draw() std::ostringstream avheight(std::ostringstream::trunc); avheight << std::fixed << std::setprecision(2) << avsize << " m (" << feet << "' " << inches << "\")"; - childSetVisible("avheight", TRUE); - childSetTextArg("avheight", "[AVHEIGHT]", avheight.str()); + av_height->setVisible(TRUE); + av_height->setTextArg("[AVHEIGHT]",avheight.str()); } if(has_wearable && !is_modifiable) @@ -1271,7 +1284,7 @@ void LLPanelEditWearable::setUIPermissions(U32 perm_mask, BOOL is_complete) class LLScrollingPanelParam : public LLScrollingPanel { public: - LLScrollingPanelParam( const std::string& name, LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify ); + LLScrollingPanelParam( const std::string& name, LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, bool bVisualHint ); virtual ~LLScrollingPanelParam(); virtual void draw(); @@ -1299,6 +1312,9 @@ public: LLViewerVisualParam* mParam; LLPointer mHintMin; LLPointer mHintMax; + LLButton* mLess; + LLButton* mMore; + static S32 sUpdateDelayFrames; protected: @@ -1319,51 +1335,68 @@ const S32 PARAM_PANEL_WIDTH = 2 * (3* BTN_BORDER + PARAM_HINT_WIDTH + LLPANEL_B const S32 PARAM_PANEL_HEIGHT = 2 * BTN_BORDER + PARAM_HINT_HEIGHT + PARAM_HINT_LABEL_HEIGHT + 4 * LLPANEL_BORDER_WIDTH; LLScrollingPanelParam::LLScrollingPanelParam( const std::string& name, - LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify ) + LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, bool bVisualHint ) : LLScrollingPanel( name, LLRect( 0, PARAM_PANEL_HEIGHT, PARAM_PANEL_WIDTH, 0 ) ), mParam(param), - mAllowModify(allow_modify) + mAllowModify(allow_modify), + mLess(NULL), + mMore(NULL) { LLUICtrlFactory::getInstance()->buildPanel(this, "panel_scrolling_param.xml"); - - S32 pos_x = 2 * LLPANEL_BORDER_WIDTH; - S32 pos_y = 3 * LLPANEL_BORDER_WIDTH + SLIDERCTRL_HEIGHT; - F32 min_weight = param->getMinWeight(); - F32 max_weight = param->getMaxWeight(); - - mHintMin = new LLVisualParamHint( pos_x, pos_y, PARAM_HINT_WIDTH, PARAM_HINT_HEIGHT, mesh, param, min_weight); - pos_x += PARAM_HINT_WIDTH + 3 * BTN_BORDER; - mHintMax = new LLVisualParamHint( pos_x, pos_y, PARAM_HINT_WIDTH, PARAM_HINT_HEIGHT, mesh, param, max_weight ); - mHintMin->setAllowsUpdates( FALSE ); - mHintMax->setAllowsUpdates( FALSE ); - childSetValue("param slider", weightToPercent(param->getWeight())); - childSetLabelArg("param slider", "[DESC]", param->getDisplayName()); - childSetEnabled("param slider", mAllowModify); - childSetCommitCallback("param slider", LLScrollingPanelParam::onSliderMoved, this); + //Set up the slider + LLSliderCtrl *slider = getChild("param slider"); + slider->setValue(weightToPercent(param->getWeight())); + slider->setLabelArg("[DESC]", param->getDisplayName()); + slider->setEnabled(mAllowModify); + slider->setCommitCallback(LLScrollingPanelParam::onSliderMoved); + slider->setCallbackUserData(this); - // *TODO::translate - std::string min_name = param->getMinDisplayName(); - std::string max_name = param->getMaxDisplayName(); - childSetValue("min param text", min_name); - childSetValue("max param text", max_name); - - LLButton* less = getChild("less"); - if (less) + if(bVisualHint) { - less->setMouseDownCallback( LLScrollingPanelParam::onHintMinMouseDown ); - less->setMouseUpCallback( LLScrollingPanelParam::onHintMinMouseUp ); - less->setHeldDownCallback( LLScrollingPanelParam::onHintMinHeldDown ); - less->setHeldDownDelay( PARAM_STEP_TIME_THRESHOLD ); + S32 pos_x = 2 * LLPANEL_BORDER_WIDTH; + S32 pos_y = 3 * LLPANEL_BORDER_WIDTH + SLIDERCTRL_HEIGHT; + F32 min_weight = param->getMinWeight(); + F32 max_weight = param->getMaxWeight(); + + mHintMin = new LLVisualParamHint( pos_x, pos_y, PARAM_HINT_WIDTH, PARAM_HINT_HEIGHT, mesh, param, min_weight); + pos_x += PARAM_HINT_WIDTH + 3 * BTN_BORDER; + mHintMax = new LLVisualParamHint( pos_x, pos_y, PARAM_HINT_WIDTH, PARAM_HINT_HEIGHT, mesh, param, max_weight ); + + mHintMin->setAllowsUpdates( FALSE ); + mHintMax->setAllowsUpdates( FALSE ); + + // *TODO::translate + std::string min_name = param->getMinDisplayName(); + std::string max_name = param->getMaxDisplayName(); + childSetValue("min param text", min_name); + childSetValue("max param text", max_name); + mLess = getChild("less"); + mLess->setMouseDownCallback( LLScrollingPanelParam::onHintMinMouseDown ); + mLess->setMouseUpCallback( LLScrollingPanelParam::onHintMinMouseUp ); + mLess->setHeldDownCallback( LLScrollingPanelParam::onHintMinHeldDown ); + mLess->setHeldDownDelay( PARAM_STEP_TIME_THRESHOLD ); + + mMore = getChild("more"); + mMore->setMouseDownCallback( LLScrollingPanelParam::onHintMaxMouseDown ); + mMore->setMouseUpCallback( LLScrollingPanelParam::onHintMaxMouseUp ); + mMore->setHeldDownCallback( LLScrollingPanelParam::onHintMaxHeldDown ); + mMore->setHeldDownDelay( PARAM_STEP_TIME_THRESHOLD ); } - - LLButton* more = getChild("more"); - if (more) + else { - more->setMouseDownCallback( LLScrollingPanelParam::onHintMaxMouseDown ); - more->setMouseUpCallback( LLScrollingPanelParam::onHintMaxMouseUp ); - more->setHeldDownCallback( LLScrollingPanelParam::onHintMaxHeldDown ); - more->setHeldDownDelay( PARAM_STEP_TIME_THRESHOLD ); + //Kill everything that isn't the slider... + for(child_list_t::const_iterator it = getChildList()->begin();it!=getChildList()->end();) + { + if((*it)!=slider && (*it)->getName() != "panel border") + { + llinfos << "removing: " << (*it)->getName() << llendl; + removeChild((*(it++)),TRUE); + } + else ++it; + } + slider->translate(0,PARAM_HINT_HEIGHT); + reshape(getRect().getWidth(),getRect().getHeight()-PARAM_HINT_HEIGHT); } setVisible(FALSE); @@ -1378,15 +1411,19 @@ LLScrollingPanelParam::~LLScrollingPanelParam() void LLScrollingPanelParam::updatePanel(BOOL allow_modify) { - LLViewerVisualParam* param = mHintMin->getVisualParam(); - childSetValue("param slider", weightToPercent( param->getWeight() ) ); - mHintMin->requestUpdate( sUpdateDelayFrames++ ); - mHintMax->requestUpdate( sUpdateDelayFrames++ ); + childSetValue("param slider", weightToPercent( mParam->getWeight() ) ); + if(mHintMin) + mHintMin->requestUpdate( sUpdateDelayFrames++ ); + if(mHintMax) + mHintMax->requestUpdate( sUpdateDelayFrames++ ); mAllowModify = allow_modify; childSetEnabled("param slider", mAllowModify); - childSetEnabled("less", mAllowModify); - childSetEnabled("more", mAllowModify); + + if(mLess) + mLess->setEnabled(mAllowModify); + if(mMore) + mMore->setEnabled(mAllowModify); } void LLScrollingPanelParam::setVisible( BOOL visible ) @@ -1394,13 +1431,17 @@ void LLScrollingPanelParam::setVisible( BOOL visible ) if( getVisible() != visible ) { LLPanel::setVisible( visible ); - mHintMin->setAllowsUpdates( visible ); - mHintMax->setAllowsUpdates( visible ); + if(mHintMin) + mHintMin->setAllowsUpdates( visible ); + if(mHintMax) + mHintMax->setAllowsUpdates( visible ); if( visible ) { - mHintMin->setUpdateDelayFrames( sUpdateDelayFrames++ ); - mHintMax->setUpdateDelayFrames( sUpdateDelayFrames++ ); + if(mHintMin) + mHintMin->setUpdateDelayFrames( sUpdateDelayFrames++ ); + if(mHintMax) + mHintMax->setUpdateDelayFrames( sUpdateDelayFrames++ ); } } } @@ -1412,8 +1453,10 @@ void LLScrollingPanelParam::draw() return; } - childSetVisible("less", mHintMin->getVisible()); - childSetVisible("more", mHintMax->getVisible()); + if(mLess) + mLess->setVisible(mHintMin ? mHintMin->getVisible() : false); + if(mMore) + mMore->setVisible(mHintMax ? mHintMax->getVisible() : false); // Draw all the children except for the labels childSetVisible( "min param text", FALSE ); @@ -1421,25 +1464,31 @@ void LLScrollingPanelParam::draw() LLPanel::draw(); // Draw the hints over the "less" and "more" buttons. - glPushMatrix(); + if(mHintMin) { - const LLRect& r = mHintMin->getRect(); - F32 left = (F32)(r.mLeft + BTN_BORDER); - F32 bot = (F32)(r.mBottom + BTN_BORDER); - glTranslatef(left, bot, 0.f); - mHintMin->draw(); + glPushMatrix(); + { + const LLRect& r = mHintMin->getRect(); + F32 left = (F32)(r.mLeft + BTN_BORDER); + F32 bot = (F32)(r.mBottom + BTN_BORDER); + glTranslatef(left, bot, 0.f); + mHintMin->draw(); + } + glPopMatrix(); } - glPopMatrix(); - glPushMatrix(); + if(mHintMax) { - const LLRect& r = mHintMax->getRect(); - F32 left = (F32)(r.mLeft + BTN_BORDER); - F32 bot = (F32)(r.mBottom + BTN_BORDER); - glTranslatef(left, bot, 0.f); - mHintMax->draw(); + glPushMatrix(); + { + const LLRect& r = mHintMax->getRect(); + F32 left = (F32)(r.mLeft + BTN_BORDER); + F32 bot = (F32)(r.mBottom + BTN_BORDER); + glTranslatef(left, bot, 0.f); + mHintMax->draw(); + } + glPopMatrix(); } - glPopMatrix(); // Draw labels on top of the buttons @@ -1684,6 +1733,8 @@ LLFloaterCustomize::LLFloaterCustomize() mNextStepAfterSaveCallback( NULL ), mNextStepAfterSaveUserdata( NULL ) { + memset(&mWearablePanelList[0],0,sizeof(char*)*WT_COUNT); //Initialize to 0 + gSavedSettings.setU32("AvatarSex", (gAgent.getAvatarObject()->getSex() == SEX_MALE) ); mResetParams = new LLVisualParamReset(); @@ -1708,6 +1759,7 @@ LLFloaterCustomize::LLFloaterCustomize() factory_map["Skirt"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, WT_SKIRT) ) ); factory_map["Alpha"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, WT_ALPHA))); factory_map["Tattoo"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, WT_TATTOO))); + factory_map["Physics"] = LLCallbackMap(createWearablePanel, (void*)(new WearablePanelData(this, WT_PHYSICS))); LLUICtrlFactory::getInstance()->buildFloater(this, "floater_customize.xml", &factory_map); } @@ -1741,6 +1793,7 @@ BOOL LLFloaterCustomize::postBuild() childSetTabChangeCallback("customize tab container", "Skirt", onTabChanged, (void*)WT_SKIRT, onTabPrecommit ); childSetTabChangeCallback("customize tab container", "Alpha", onTabChanged, (void*)WT_ALPHA, onTabPrecommit); childSetTabChangeCallback("customize tab container", "Tattoo", onTabChanged, (void*)WT_TATTOO, onTabPrecommit); + childSetTabChangeCallback("customize tab container", "Physics", onTabChanged, (void*)WT_PHYSICS, onTabPrecommit); // Remove underwear panels for teens if (gAgent.isTeen()) @@ -2406,63 +2459,72 @@ void LLFloaterCustomize::initWearablePanels() } ///////////////////////////////////////// - // Alpha - panel = mWearablePanelList[WT_ALPHA]; + // Physics - if (panel) + panel = mWearablePanelList[WT_PHYSICS]; + + if(panel) { part = new LLSubpart(); - part->mTargetJoint = "mPelvis"; - part->mEditGroup = "alpha"; + part->mSex = SEX_FEMALE; + part->mTargetJoint = "mTorso"; + part->mEditGroup = "physics_breasts_updown"; part->mTargetOffset.setVec(0.f, 0.f, 0.1f); - part->mCameraOffset.setVec(-2.5f, 0.5f, 0.8f); - panel->addSubpart(LLStringUtil::null, SUBPART_ALPHA, part); + part->mCameraOffset.setVec(-0.8f, 0.15f, 0.38f); + part->mVisualHint = false; + panel->addSubpart("Breast Bounce", SUBPART_PHYSICS_BREASTS_UPDOWN, part); - panel->addTextureDropTarget(TEX_LOWER_ALPHA, "Lower Alpha", - LLUUID(gSavedSettings.getString("UIImgDefaultAlphaUUID")), - TRUE); - panel->addTextureDropTarget(TEX_UPPER_ALPHA, "Upper Alpha", - LLUUID(gSavedSettings.getString("UIImgDefaultAlphaUUID")), - TRUE); - panel->addTextureDropTarget(TEX_HEAD_ALPHA, "Head Alpha", - LLUUID(gSavedSettings.getString("UIImgDefaultAlphaUUID")), - TRUE); - panel->addTextureDropTarget(TEX_EYES_ALPHA, "Eye Alpha", - LLUUID(gSavedSettings.getString("UIImgDefaultAlphaUUID")), - TRUE); - panel->addTextureDropTarget(TEX_HAIR_ALPHA, "Hair Alpha", - LLUUID(gSavedSettings.getString("UIImgDefaultAlphaUUID")), - TRUE); + part = new LLSubpart(); + part->mSex = SEX_FEMALE; + part->mTargetJoint = "mTorso"; + part->mEditGroup = "physics_breasts_inout"; + part->mTargetOffset.setVec(0.f, 0.f, 0.1f); + part->mCameraOffset.setVec(-0.8f, 0.15f, 0.38f); + part->mVisualHint = false; + panel->addSubpart("Breast Cleavage", SUBPART_PHYSICS_BREASTS_INOUT, part); - panel->addInvisibilityCheckbox(TEX_LOWER_ALPHA, "lower alpha texture invisible"); - panel->addInvisibilityCheckbox(TEX_UPPER_ALPHA, "upper alpha texture invisible"); - panel->addInvisibilityCheckbox(TEX_HEAD_ALPHA, "head alpha texture invisible"); - panel->addInvisibilityCheckbox(TEX_EYES_ALPHA, "eye alpha texture invisible"); - panel->addInvisibilityCheckbox(TEX_HAIR_ALPHA, "hair alpha texture invisible"); - } + part = new LLSubpart(); + part->mSex = SEX_FEMALE; + part->mTargetJoint = "mTorso"; + part->mEditGroup = "physics_breasts_leftright"; + part->mTargetOffset.setVec(0.f, 0.f, 0.1f); + part->mCameraOffset.setVec(-0.8f, 0.15f, 0.38f); + part->mVisualHint = false; + panel->addSubpart("Breast Sway", SUBPART_PHYSICS_BREASTS_LEFTRIGHT, part); - ///////////////////////////////////////// - // Tattoo - panel = mWearablePanelList[WT_TATTOO]; + part = new LLSubpart(); + part->mSex = SEX_FEMALE; + part->mTargetJoint = "mTorso"; + part->mEditGroup = "physics_belly_updown"; + part->mTargetOffset.setVec(0.f, 0.f, -.05f); + part->mCameraOffset.setVec(-0.8f, 0.15f, 0.38f); + part->mVisualHint = false; + panel->addSubpart("Belly Bounce", SUBPART_PHYSICS_BELLY_UPDOWN, part); - if (panel) - { part = new LLSubpart(); part->mTargetJoint = "mPelvis"; - part->mEditGroup = "tattoo"; + part->mEditGroup = "physics_butt_updown"; + part->mTargetOffset.setVec(0.f, 0.f, -0.1f); + part->mCameraOffset.setVec(0.3f, 0.8f, -0.1f); + part->mVisualHint = false; + panel->addSubpart("Butt Bounce", SUBPART_PHYSICS_BUTT_UPDOWN, part); + + part = new LLSubpart(); + part->mTargetJoint = "mPelvis"; + part->mEditGroup = "physics_butt_leftright"; + part->mTargetOffset.setVec(0.f, 0.f, -0.1f); + part->mCameraOffset.setVec(0.3f, 0.8f, -0.1f); + part->mVisualHint = false; + panel->addSubpart("Butt Sway", SUBPART_PHYSICS_BUTT_LEFTRIGHT, part); + + part = new LLSubpart(); + part->mTargetJoint = "mTorso"; + part->mEditGroup = "physics_advanced"; part->mTargetOffset.setVec(0.f, 0.f, 0.1f); part->mCameraOffset.setVec(-2.5f, 0.5f, 0.8f); - panel->addSubpart(LLStringUtil::null, SUBPART_TATTOO, part); + part->mVisualHint = false; + panel->addSubpart("Advanced Parameters", SUBPART_PHYSICS_ADVANCED, part); - panel->addTextureDropTarget(TEX_LOWER_TATTOO, "Lower Tattoo", - LLUUID::null, - TRUE); - panel->addTextureDropTarget(TEX_UPPER_TATTOO, "Upper Tattoo", - LLUUID::null, - TRUE); - panel->addTextureDropTarget(TEX_HEAD_TATTOO, "Head Tattoo", - LLUUID::null, - TRUE); } } @@ -2597,7 +2659,7 @@ void LLFloaterCustomize::clearScrollingPanelList() } } -void LLFloaterCustomize::generateVisualParamHints(LLViewerJointMesh* joint_mesh, LLFloaterCustomize::param_map& params) +void LLFloaterCustomize::generateVisualParamHints(LLViewerJointMesh* joint_mesh, LLFloaterCustomize::param_map& params, bool bVisualHint) { // sorted_params is sorted according to magnitude of effect from // least to greatest. Adding to the front of the child list @@ -2608,7 +2670,7 @@ void LLFloaterCustomize::generateVisualParamHints(LLViewerJointMesh* joint_mesh, param_map::iterator end = params.end(); for(param_map::iterator it = params.begin(); it != end; ++it) { - mScrollingPanelList->addPanel( new LLScrollingPanelParam( "LLScrollingPanelParam", joint_mesh, (*it).second.second, (*it).second.first) ); + mScrollingPanelList->addPanel( new LLScrollingPanelParam( "LLScrollingPanelParam", joint_mesh, (*it).second.second, (*it).second.first, bVisualHint) ); } } } diff --git a/indra/newview/llfloatercustomize.h b/indra/newview/llfloatercustomize.h index 5648cc6af..ceb49af01 100644 --- a/indra/newview/llfloatercustomize.h +++ b/indra/newview/llfloatercustomize.h @@ -88,7 +88,7 @@ public: // New methods void clearScrollingPanelList(); void generateVisualParamHints(LLViewerJointMesh* joint_mesh, - param_map& params); + param_map& params, bool bVisualHint); const std::string& getEditGroup(); void updateScrollingPanelList(BOOL allow_modify); diff --git a/indra/newview/llinventoryactions.cpp b/indra/newview/llinventoryactions.cpp index 4c41ddb66..b770a531d 100644 --- a/indra/newview/llinventoryactions.cpp +++ b/indra/newview/llinventoryactions.cpp @@ -462,7 +462,11 @@ void do_create(LLInventoryModel *model, LLInventoryPanel *ptr, std::string type, LLUUID parent_id = self ? self->getUUID() : gInventory.findCategoryUUIDForType(LLAssetType::AT_BODYPART); LLFolderBridge::createWearable(parent_id, WT_EYES); } - + else if ("physics" == type) + { + LLUUID parent_id = self ? self->getUUID() : gInventory.findCategoryUUIDForType(LLAssetType::AT_CLOTHING); + LLFolderBridge::createWearable(parent_id, WT_PHYSICS); + } ptr->getRootFolder()->setNeedsAutoRename(TRUE); } diff --git a/indra/newview/llinventorybackup.cpp b/indra/newview/llinventorybackup.cpp index 4ad9e79bb..a5ce38e59 100644 --- a/indra/newview/llinventorybackup.cpp +++ b/indra/newview/llinventorybackup.cpp @@ -209,6 +209,8 @@ LLFilePicker::ESaveFilter LLInventoryBackup::getSaveFilter(LLInventoryItem* item return LLFilePicker::FFSAVE_UNDERPANTS; case WT_UNDERSHIRT: return LLFilePicker::FFSAVE_UNDERSHIRT; + case WT_PHYSICS: + return LLFilePicker::FFSAVE_PHYSICS; default: return LLFilePicker::FFSAVE_ALL; } diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 3ac7342ae..3455caf19 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -186,6 +186,7 @@ std::string ICON_NAME[ICON_NAME_COUNT] = "inv_item_skirt.tga", "inv_item_alpha.tga", "inv_item_tattoo.tga", + "inv_item_physics.png", "inv_item_animation.tga", "inv_item_gesture.tga", @@ -2712,6 +2713,10 @@ void LLFolderBridge::createNewEyes(void* user_data) LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_EYES); } +void LLFolderBridge::createNewPhysics(void* user_data) +{ + LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_PHYSICS); +} // static void LLFolderBridge::createWearable(LLFolderBridge* bridge, EWearableType type) { diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index e9f131f68..dcadc2781 100755 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -72,6 +72,7 @@ enum EInventoryIcon CLOTHING_SKIRT_ICON_NAME, CLOTHING_ALPHA_ICON_NAME, CLOTHING_TATTOO_ICON_NAME, + CLOTHING_PHYSICS_ICON_NAME, ANIMATION_ICON_NAME, GESTURE_ICON_NAME, @@ -375,6 +376,7 @@ protected: static void createNewSkin(void* user_data); static void createNewHair(void* user_data); static void createNewEyes(void* user_data); + static void createNewPhysics(void* user_data); BOOL checkFolderForContentsOfType(LLInventoryModel* model, LLInventoryCollectFunctor& typeToCheck); diff --git a/indra/newview/llinventoryview.cpp b/indra/newview/llinventoryview.cpp index 1e9ce663a..1d89872c9 100644 --- a/indra/newview/llinventoryview.cpp +++ b/indra/newview/llinventoryview.cpp @@ -1521,6 +1521,9 @@ std::string get_item_icon_name(LLAssetType::EType asset_type, case WT_TATTOO: idx = CLOTHING_TATTOO_ICON_NAME; break; + case WT_PHYSICS: + idx = CLOTHING_PHYSICS_ICON_NAME; + break; default: // no-op, go with choice above break; diff --git a/indra/newview/llphysicsmotion.cpp b/indra/newview/llphysicsmotion.cpp new file mode 100644 index 000000000..e9a127cf3 --- /dev/null +++ b/indra/newview/llphysicsmotion.cpp @@ -0,0 +1,773 @@ +/** + * @file llphysicsmotion.cpp + * @brief Implementation of LLPhysicsMotion class. + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +//----------------------------------------------------------------------------- +// Header Files +//----------------------------------------------------------------------------- +#include "llviewerprecompiledheaders.h" +#include "linden_common.h" + +#include "m3math.h" +#include "v3dmath.h" + +#include "llphysicsmotion.h" +#include "llagent.h" +#include "llcharacter.h" +#include "llviewercontrol.h" +#include "llviewervisualparam.h" +#include "llvoavatar.h" +#include "lldriverparam.h" + +typedef std::map controller_map_t; +typedef std::map default_controller_map_t; + +#define MIN_REQUIRED_PIXEL_AREA_AVATAR_PHYSICS_MOTION 0.f +#define TIME_ITERATION_STEP 0.1f + +inline F64 llsgn(const F64 a) +{ + if (a >= 0) + return 1; + return -1; +} + +/* + At a high level, this works by setting temporary parameters that are not stored + in the avatar's list of params, and are not conveyed to other users. We accomplish + this by creating some new temporary driven params inside avatar_lad that are then driven + by the actual params that the user sees and sets. For example, in the old system, + the user sets a param called breast bouyancy, which controls the Z value of the breasts. + In our new system, the user still sets the breast bouyancy, but that param is redefined + as a driver param so that affects a new temporary driven param that the bounce is applied + to. +*/ + +class LLPhysicsMotion +{ +public: + /* + param_driver_name: The param that controls the params that are being affected by the physics. + joint_name: The joint that the body part is attached to. The joint is + used to determine the orientation (rotation) of the body part. + + character: The avatar that this physics affects. + + motion_direction_vec: The direction (in world coordinates) that determines the + motion. For example, (0,0,1) is up-down, and means that up-down motion is what + determines how this joint moves. + + controllers: The various settings (e.g. spring force, mass) that determine how + the body part behaves. + */ + LLPhysicsMotion(const std::string ¶m_driver_name, + const std::string &joint_name, + LLCharacter *character, + const LLVector3 &motion_direction_vec, + const controller_map_t &controllers) : + mParamDriverName(param_driver_name), + mJointName(joint_name), + mMotionDirectionVec(motion_direction_vec), + mParamDriver(NULL), + mParamControllers(controllers), + mCharacter(character), + mLastTime(0), + mPosition_local(0), + mVelocityJoint_local(0), + mPositionLastUpdate_local(0) + { + mJointState = new LLJointState; + } + + BOOL initialize(); + + ~LLPhysicsMotion() {} + + BOOL onUpdate(F32 time); + + LLPointer getJointState() + { + return mJointState; + } + + void reset(); +protected: + F32 getParamValue(const std::string& controller_key) + { + const controller_map_t::const_iterator& entry = mParamControllers.find(controller_key); + if (entry == mParamControllers.end()) + { + return sDefaultController[controller_key]; + } + const std::string& param_name = (*entry).second.c_str(); + return mCharacter->getVisualParamWeight(param_name.c_str()); + } + void setParamValue(LLViewerVisualParam *param, + const F32 new_value_local, + F32 behavior_maxeffect); + + F32 toLocal(const LLVector3 &world); + F32 calculateVelocity_local(); + F32 calculateAcceleration_local(F32 velocity_local); + +private: + const std::string mParamDriverName; + const std::string mParamControllerName; + const LLVector3 mMotionDirectionVec; + const std::string mJointName; + + F32 mPosition_local; + F32 mVelocityJoint_local; // How fast the joint is moving + F32 mAccelerationJoint_local; // Acceleration on the joint + + F32 mVelocity_local; // How fast the param is moving + F32 mPositionLastUpdate_local; + LLVector3 mPosition_world; + + LLViewerVisualParam *mParamDriver; + const controller_map_t mParamControllers; + + LLPointer mJointState; + LLCharacter *mCharacter; + + F32 mLastTime; + + static default_controller_map_t sDefaultController; +}; + +default_controller_map_t initDefaultController() +{ + default_controller_map_t controller; + controller["Mass"] = 0.2f; + controller["Gravity"] = 0.0f; + controller["Damping"] = .05f; + controller["Drag"] = 0.15f; + controller["MaxEffect"] = 0.1f; + controller["Spring"] = 0.1f; + controller["Gain"] = 10.0f; + return controller; +} + +default_controller_map_t LLPhysicsMotion::sDefaultController = initDefaultController(); + +BOOL LLPhysicsMotion::initialize() +{ + if (!mJointState->setJoint(mCharacter->getJoint(mJointName.c_str()))) + return FALSE; + mJointState->setUsage(LLJointState::ROT); + + mParamDriver = (LLViewerVisualParam*)mCharacter->getVisualParam(mParamDriverName.c_str()); + if (mParamDriver == NULL) + { + llinfos << "Failure reading in [ " << mParamDriverName << " ]" << llendl; + return FALSE; + } + + return TRUE; +} + +LLPhysicsMotionController::LLPhysicsMotionController(const LLUUID &id) : + LLMotion(id), + mCharacter(NULL), + mIsDefault(true) +{ + mName = "breast_motion"; +} + +LLPhysicsMotionController::~LLPhysicsMotionController() +{ + for (motion_vec_t::iterator iter = mMotions.begin(); + iter != mMotions.end(); + ++iter) + { + delete (*iter); + } +} + +BOOL LLPhysicsMotionController::onActivate() +{ + return TRUE; +} + +void LLPhysicsMotionController::onDeactivate() +{ +} + +LLMotion::LLMotionInitStatus LLPhysicsMotionController::onInitialize(LLCharacter *character) +{ + mCharacter = character; + + mMotions.clear(); + + // Breast Cleavage + { + controller_map_t controller; + controller["Mass"] = "Breast_Physics_Mass"; + controller["Gravity"] = "Breast_Physics_Gravity"; + controller["Drag"] = "Breast_Physics_Drag"; + controller["Damping"] = "Breast_Physics_InOut_Damping"; + controller["MaxEffect"] = "Breast_Physics_InOut_Max_Effect"; + controller["Spring"] = "Breast_Physics_InOut_Spring"; + controller["Gain"] = "Breast_Physics_InOut_Gain"; + LLPhysicsMotion *motion = new LLPhysicsMotion("Breast_Physics_InOut_Controller", + "mChest", + character, + LLVector3(-1,0,0), + controller); + if (!motion->initialize()) + { + llassert_always(FALSE); + return STATUS_FAILURE; + } + addMotion(motion); + } + + // Breast Bounce + { + controller_map_t controller; + controller["Mass"] = "Breast_Physics_Mass"; + controller["Gravity"] = "Breast_Physics_Gravity"; + controller["Drag"] = "Breast_Physics_Drag"; + controller["Damping"] = "Breast_Physics_UpDown_Damping"; + controller["MaxEffect"] = "Breast_Physics_UpDown_Max_Effect"; + controller["Spring"] = "Breast_Physics_UpDown_Spring"; + controller["Gain"] = "Breast_Physics_UpDown_Gain"; + LLPhysicsMotion *motion = new LLPhysicsMotion("Breast_Physics_UpDown_Controller", + "mChest", + character, + LLVector3(0,0,1), + controller); + if (!motion->initialize()) + { + llassert_always(FALSE); + return STATUS_FAILURE; + } + addMotion(motion); + } + + // Breast Sway + { + controller_map_t controller; + controller["Mass"] = "Breast_Physics_Mass"; + controller["Gravity"] = "Breast_Physics_Gravity"; + controller["Drag"] = "Breast_Physics_Drag"; + controller["Damping"] = "Breast_Physics_LeftRight_Damping"; + controller["MaxEffect"] = "Breast_Physics_LeftRight_Max_Effect"; + controller["Spring"] = "Breast_Physics_LeftRight_Spring"; + controller["Gain"] = "Breast_Physics_LeftRight_Gain"; + LLPhysicsMotion *motion = new LLPhysicsMotion("Breast_Physics_LeftRight_Controller", + "mChest", + character, + LLVector3(0,-1,0), + controller); + if (!motion->initialize()) + { + llassert_always(FALSE); + return STATUS_FAILURE; + } + addMotion(motion); + } + // Butt Bounce + { + controller_map_t controller; + controller["Mass"] = "Butt_Physics_Mass"; + controller["Gravity"] = "Butt_Physics_Gravity"; + controller["Drag"] = "Butt_Physics_Drag"; + controller["Damping"] = "Butt_Physics_UpDown_Damping"; + controller["MaxEffect"] = "Butt_Physics_UpDown_Max_Effect"; + controller["Spring"] = "Butt_Physics_UpDown_Spring"; + controller["Gain"] = "Butt_Physics_UpDown_Gain"; + LLPhysicsMotion *motion = new LLPhysicsMotion("Butt_Physics_UpDown_Controller", + "mPelvis", + character, + LLVector3(0,0,-1), + controller); + if (!motion->initialize()) + { + llassert_always(FALSE); + return STATUS_FAILURE; + } + addMotion(motion); + } + + // Butt LeftRight + { + controller_map_t controller; + controller["Mass"] = "Butt_Physics_Mass"; + controller["Gravity"] = "Butt_Physics_Gravity"; + controller["Drag"] = "Butt_Physics_Drag"; + controller["Damping"] = "Butt_Physics_LeftRight_Damping"; + controller["MaxEffect"] = "Butt_Physics_LeftRight_Max_Effect"; + controller["Spring"] = "Butt_Physics_LeftRight_Spring"; + controller["Gain"] = "Butt_Physics_LeftRight_Gain"; + LLPhysicsMotion *motion = new LLPhysicsMotion("Butt_Physics_LeftRight_Controller", + "mPelvis", + character, + LLVector3(0,-1,0), + controller); + if (!motion->initialize()) + { + llassert_always(FALSE); + return STATUS_FAILURE; + } + addMotion(motion); + } + + // Belly Bounce + { + controller_map_t controller; + controller["Mass"] = "Belly_Physics_Mass"; + controller["Gravity"] = "Belly_Physics_Gravity"; + controller["Drag"] = "Belly_Physics_Drag"; + controller["Damping"] = "Belly_Physics_UpDown_Damping"; + controller["MaxEffect"] = "Belly_Physics_UpDown_Max_Effect"; + controller["Spring"] = "Belly_Physics_UpDown_Spring"; + controller["Gain"] = "Belly_Physics_UpDown_Gain"; + LLPhysicsMotion *motion = new LLPhysicsMotion("Belly_Physics_UpDown_Controller", + "mPelvis", + character, + LLVector3(0,0,-1), + controller); + if (!motion->initialize()) + { + llassert_always(FALSE); + return STATUS_FAILURE; + } + addMotion(motion); + } + + return STATUS_SUCCESS; +} + +void LLPhysicsMotionController::addMotion(LLPhysicsMotion *motion) +{ + addJointState(motion->getJointState()); + mMotions.push_back(motion); +} + +F32 LLPhysicsMotionController::getMinPixelArea() +{ + return MIN_REQUIRED_PIXEL_AREA_AVATAR_PHYSICS_MOTION; +} + +// Local space means "parameter space". +F32 LLPhysicsMotion::toLocal(const LLVector3 &world) +{ + LLJoint *joint = mJointState->getJoint(); + const LLQuaternion rotation_world = joint->getWorldRotation(); + + LLVector3 dir_world = mMotionDirectionVec * rotation_world; + dir_world.normalize(); + return world * dir_world; +} + +F32 LLPhysicsMotion::calculateVelocity_local() +{ + const F32 world_to_model_scale = 100.0f; + LLJoint *joint = mJointState->getJoint(); + const LLVector3 position_world = joint->getWorldPosition(); + const LLQuaternion rotation_world = joint->getWorldRotation(); + const LLVector3 last_position_world = mPosition_world; + const LLVector3 positionchange_world = (position_world-last_position_world) * world_to_model_scale; + const LLVector3 velocity_world = positionchange_world; + const F32 velocity_local = toLocal(velocity_world); + return velocity_local; +} + +F32 LLPhysicsMotion::calculateAcceleration_local(const F32 velocity_local) +{ +// const F32 smoothing = getParamValue("Smoothing"); + static const F32 smoothing = 3.0f; // Removed smoothing param since it's probably not necessary + const F32 acceleration_local = velocity_local - mVelocityJoint_local; + + const F32 smoothed_acceleration_local = + acceleration_local * 1.0/smoothing + + mAccelerationJoint_local * (smoothing-1.0)/smoothing; + + return smoothed_acceleration_local; +} + +BOOL LLPhysicsMotionController::onUpdate(F32 time, U8* joint_mask) +{ + // Skip if disabled globally. + static const LLCachedControl avatar_physics("AvatarPhysics",false); + if (!avatar_physics || (!((LLVOAvatar*)mCharacter)->isSelf() && !((LLVOAvatar*)mCharacter)->mSupportsPhysics)) + { + if(!mIsDefault) + { + mIsDefault = true; + for (motion_vec_t::iterator iter = mMotions.begin();iter != mMotions.end();++iter) + { + (*iter)->reset(); + } + mCharacter->updateVisualParams(); + } + ((LLVOAvatar*)mCharacter)->idleUpdateBoobEffect(); //Fall back to emerald physics + return TRUE; + } + + mIsDefault = false; + + BOOL update_visuals = FALSE; + for (motion_vec_t::iterator iter = mMotions.begin(); + iter != mMotions.end(); + ++iter) + { + LLPhysicsMotion *motion = (*iter); + update_visuals |= motion->onUpdate(time); + } + + if (update_visuals) + mCharacter->updateVisualParams(); + + return TRUE; +} + +// Return TRUE if character has to update visual params. +BOOL LLPhysicsMotion::onUpdate(F32 time) +{ + // static FILE *mFileWrite = fopen("c:\\temp\\avatar_data.txt","w"); + + if (!mParamDriver) + return FALSE; + + if (!mLastTime) + { + mLastTime = time; + return FALSE; + } + + //////////////////////////////////////////////////////////////////////////////// + // Get all parameters and settings + // + + const F32 time_delta = time - mLastTime; + + // Don't update too frequently, to avoid precision errors from small time slices. + if (time_delta <= .01) + { + return FALSE; + } + + // If less than 1FPS, we don't want to be spending time updating physics at all. + if (time_delta > 1.0) + { + mLastTime = time; + return FALSE; + } + + // Higher LOD is better. This controls the granularity + // and frequency of updates for the motions. + const F32 lod_factor = LLVOAvatar::sPhysicsLODFactor; + if (lod_factor == 0) + { + return TRUE; + } + + LLJoint *joint = mJointState->getJoint(); + + const F32 behavior_mass = getParamValue("Mass"); + const F32 behavior_gravity = getParamValue("Gravity"); + const F32 behavior_spring = getParamValue("Spring"); + const F32 behavior_gain = getParamValue("Gain"); + const F32 behavior_damping = getParamValue("Damping"); + const F32 behavior_drag = getParamValue("Drag"); + const BOOL physics_test = FALSE; // Enable this to simulate bouncing on all parts. + + F32 behavior_maxeffect = getParamValue("MaxEffect"); + if (physics_test) + behavior_maxeffect = 1.0f; + + // Normalize the param position to be from [0,1]. + // We have to use normalized values because there may be more than one driven param, + // and each of these driven params may have its own range. + // This means we'll do all our calculations in normalized [0,1] local coordinates. + const F32 position_user_local = (mParamDriver->getWeight() - mParamDriver->getMinWeight()) / (mParamDriver->getMaxWeight() - mParamDriver->getMinWeight()); + + // + // End parameters and settings + //////////////////////////////////////////////////////////////////////////////// + + + //////////////////////////////////////////////////////////////////////////////// + // Calculate velocity and acceleration in parameter space. + // + + //const F32 velocity_joint_local = calculateVelocity_local(time_iteration_step); + const F32 velocity_joint_local = calculateVelocity_local(); + const F32 acceleration_joint_local = calculateAcceleration_local(velocity_joint_local); + + // + // End velocity and acceleration + //////////////////////////////////////////////////////////////////////////////// + + BOOL update_visuals = FALSE; + + // Break up the physics into a bunch of iterations so that differing framerates will show + // roughly the same behavior. + for (F32 time_iteration = 0; time_iteration <= time_delta; time_iteration += TIME_ITERATION_STEP) + { + F32 time_iteration_step = TIME_ITERATION_STEP; + if (time_iteration + TIME_ITERATION_STEP > time_delta) + { + time_iteration_step = time_delta-time_iteration; + } + + // mPositon_local should be in normalized 0,1 range already. Just making sure... + const F32 position_current_local = llclamp(mPosition_local, + 0.0f, + 1.0f); + // If the effect is turned off then don't process unless we need one more update + // to set the position to the default (i.e. user) position. + if ((behavior_maxeffect == 0) && (position_current_local == position_user_local)) + { + return update_visuals; + } + + //////////////////////////////////////////////////////////////////////////////// + // Calculate the total force + // + + // Spring force is a restoring force towards the original user-set breast position. + // F = kx + const F32 spring_length = position_current_local - position_user_local; + const F32 force_spring = -spring_length * behavior_spring; + + // Acceleration is the force that comes from the change in velocity of the torso. + // F = ma + const F32 force_accel = behavior_gain * (acceleration_joint_local * behavior_mass); + + // Gravity always points downward in world space. + // F = mg + const LLVector3 gravity_world(0,0,1); + const F32 force_gravity = (toLocal(gravity_world) * behavior_gravity * behavior_mass); + + // Damping is a restoring force that opposes the current velocity. + // F = -kv + const F32 force_damping = -behavior_damping * mVelocity_local; + + // Drag is a force imparted by velocity (intuitively it is similar to wind resistance) + // F = .5kv^2 + const F32 force_drag = .5*behavior_drag*velocity_joint_local*velocity_joint_local*llsgn(velocity_joint_local); + + const F32 force_net = (force_accel + + force_gravity + + force_spring + + force_damping + + force_drag); + + // + // End total force + //////////////////////////////////////////////////////////////////////////////// + + + //////////////////////////////////////////////////////////////////////////////// + // Calculate new params + // + + // Calculate the new acceleration based on the net force. + // a = F/m + const F32 acceleration_new_local = force_net / behavior_mass; + static const F32 max_velocity = 100.0f; // magic number, used to be customizable. + F32 velocity_new_local = mVelocity_local + acceleration_new_local*time_iteration_step; + velocity_new_local = llclamp(velocity_new_local, + -max_velocity, max_velocity); + + // Temporary debugging setting to cause all avatars to move, for profiling purposes. + if (physics_test) + { + velocity_new_local = sin(time*4.0); + } + // Calculate the new parameters, or remain unchanged if max speed is 0. + F32 position_new_local = position_current_local + velocity_new_local*time_iteration_step; + if (behavior_maxeffect == 0) + position_new_local = position_user_local; + + // Zero out the velocity if the param is being pushed beyond its limits. + if ((position_new_local < 0 && velocity_new_local < 0) || + (position_new_local > 1 && velocity_new_local > 0)) + { + velocity_new_local = 0; + } + + // Check for NaN values. A NaN value is detected if the variables doesn't equal itself. + // If NaN, then reset everything. + if ((mPosition_local != mPosition_local) || + (mVelocity_local != mVelocity_local) || + (position_new_local != position_new_local)) + { + position_new_local = 0; + mVelocity_local = 0; + mVelocityJoint_local = 0; + mAccelerationJoint_local = 0; + mPosition_local = 0; + mPosition_world = LLVector3(0,0,0); + } + + const F32 position_new_local_clamped = llclamp(position_new_local, + 0.0f, + 1.0f); + + LLDriverParam *driver_param = dynamic_cast(mParamDriver); + llassert_always(driver_param); + if (driver_param) + { + // If this is one of our "hidden" driver params, then make sure it's + // the default value. + if ((driver_param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) && + (driver_param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT)) + { + mCharacter->setVisualParamWeight(driver_param, + 0, + FALSE); + } + for (LLDriverParam::entry_list_t::iterator iter = driver_param->mDriven.begin(); + iter != driver_param->mDriven.end(); + ++iter) + { + LLDrivenEntry &entry = (*iter); + LLViewerVisualParam *driven_param = entry.mParam; + setParamValue(driven_param,position_new_local_clamped, behavior_maxeffect); + } + } + + // + // End calculate new params + //////////////////////////////////////////////////////////////////////////////// + + //////////////////////////////////////////////////////////////////////////////// + // Conditionally update the visual params + // + + // Updating the visual params (i.e. what the user sees) is fairly expensive. + // So only update if the params have changed enough, and also take into account + // the graphics LOD settings. + + // For non-self, if the avatar is small enough visually, then don't update. + const F32 area_for_max_settings = 0.0; + const F32 area_for_min_settings = 1400.0; + const F32 area_for_this_setting = area_for_max_settings + (area_for_min_settings-area_for_max_settings)*(1.0-lod_factor); + const F32 pixel_area = fsqrtf(mCharacter->getPixelArea()); + + const BOOL is_self = (dynamic_cast(mCharacter) != NULL && ((LLVOAvatar*)mCharacter)->isSelf()); + if ((pixel_area > area_for_this_setting) || is_self) + { + const F32 position_diff_local = llabs(mPositionLastUpdate_local-position_new_local_clamped); + const F32 min_delta = (1.0001f-lod_factor)*0.4f; + if (llabs(position_diff_local) > min_delta) + { + update_visuals = TRUE; + mPositionLastUpdate_local = position_new_local; + } + } + + // + // End update visual params + //////////////////////////////////////////////////////////////////////////////// + + mVelocity_local = velocity_new_local; + mAccelerationJoint_local = acceleration_joint_local; + mPosition_local = position_new_local; + } + mLastTime = time; + mPosition_world = joint->getWorldPosition(); + mVelocityJoint_local = velocity_joint_local; + + + /* + // Write out debugging info into a spreadsheet. + if (mFileWrite != NULL && is_self) + { + fprintf(mFileWrite,"%f\t%f\t%f \t\t%f \t\t%f\t%f\t%f\t \t\t%f\t%f\t%f\t%f\t%f \t\t%f\t%f\t%f\n", + position_new_local, + velocity_new_local, + acceleration_new_local, + + time_delta, + + mPosition_world[0], + mPosition_world[1], + mPosition_world[2], + + force_net, + force_spring, + force_accel, + force_damping, + force_drag, + + spring_length, + velocity_joint_local, + acceleration_joint_local + ); + } + */ + + return update_visuals; +} + +// Range of new_value_local is assumed to be [0 , 1] normalized. +void LLPhysicsMotion::setParamValue(LLViewerVisualParam *param, + F32 new_value_normalized, + F32 behavior_maxeffect) +{ + const F32 value_min_local = param->getMinWeight(); + const F32 value_max_local = param->getMaxWeight(); + const F32 min_val = 0.5f-behavior_maxeffect/2.0; + const F32 max_val = 0.5f+behavior_maxeffect/2.0; + + // Scale from [0,1] to [min_val,max_val] + const F32 new_value_rescaled = min_val + (max_val-min_val) * new_value_normalized; + + // Scale from [0,1] to [value_min_local,value_max_local] + const F32 new_value_local = value_min_local + (value_max_local-value_min_local) * new_value_rescaled; + + mCharacter->setVisualParamWeight(param, + new_value_local, + FALSE); +} + +void LLPhysicsMotion::reset() +{ + LLDriverParam *driver_param = dynamic_cast(mParamDriver); + if (driver_param) + { + if ((driver_param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) && + (driver_param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT)) + { + mCharacter->setVisualParamWeight(driver_param,driver_param->getDefaultWeight()); + } + for (LLDriverParam::entry_list_t::iterator iter = driver_param->mDriven.begin(); + iter != driver_param->mDriven.end();++iter) + { + mCharacter->setVisualParamWeight((*iter).mParam,(*iter).mParam->getDefaultWeight()); + } + } +} \ No newline at end of file diff --git a/indra/newview/llphysicsmotion.h b/indra/newview/llphysicsmotion.h new file mode 100644 index 000000000..3ee44f8d5 --- /dev/null +++ b/indra/newview/llphysicsmotion.h @@ -0,0 +1,125 @@ +/** + * @file llphysicsmotion.h + * @brief Implementation of LLPhysicsMotion class. + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLPHYSICSMOTIONCONTROLLER_H +#define LL_LLPHYSICSMOTIONCONTROLLER_H + +//----------------------------------------------------------------------------- +// Header files +//----------------------------------------------------------------------------- +#include "llmotion.h" +#include "llframetimer.h" + +#define PHYSICS_MOTION_FADEIN_TIME 1.0f +#define PHYSICS_MOTION_FADEOUT_TIME 1.0f + +class LLPhysicsMotion; + +//----------------------------------------------------------------------------- +// class LLPhysicsMotion +//----------------------------------------------------------------------------- +class LLPhysicsMotionController : + public LLMotion +{ +public: + // Constructor + LLPhysicsMotionController(const LLUUID &id); + + // Destructor + virtual ~LLPhysicsMotionController(); + +public: + //------------------------------------------------------------------------- + // functions to support MotionController and MotionRegistry + //------------------------------------------------------------------------- + + // static constructor + // all subclasses must implement such a function and register it + static LLMotion *create(const LLUUID &id) { return new LLPhysicsMotionController(id); } + +public: + //------------------------------------------------------------------------- + // animation callbacks to be implemented by subclasses + //------------------------------------------------------------------------- + + // motions must specify whether or not they loop + virtual BOOL getLoop() { return TRUE; } + + // motions must report their total duration + virtual F32 getDuration() { return 0.0; } + + // motions must report their "ease in" duration + virtual F32 getEaseInDuration() { return PHYSICS_MOTION_FADEIN_TIME; } + + // motions must report their "ease out" duration. + virtual F32 getEaseOutDuration() { return PHYSICS_MOTION_FADEOUT_TIME; } + + // called to determine when a motion should be activated/deactivated based on avatar pixel coverage + virtual F32 getMinPixelArea(); + + // motions must report their priority + virtual LLJoint::JointPriority getPriority() { return LLJoint::MEDIUM_PRIORITY; } + + virtual LLMotionBlendType getBlendType() { return ADDITIVE_BLEND; } + + // run-time (post constructor) initialization, + // called after parameters have been set + // must return true to indicate success and be available for activation + virtual LLMotionInitStatus onInitialize(LLCharacter *character); + + // called when a motion is activated + // must return TRUE to indicate success, or else + // it will be deactivated + virtual BOOL onActivate(); + + // called per time step + // must return TRUE while it is active, and + // must return FALSE when the motion is completed. + virtual BOOL onUpdate(F32 time, U8* joint_mask); + + // called when a motion is deactivated + virtual void onDeactivate(); + + LLCharacter* getCharacter() { return mCharacter; } +protected: + void addMotion(LLPhysicsMotion *motion); +private: + LLCharacter* mCharacter; + + typedef std::vector motion_vec_t; + motion_vec_t mMotions; + + bool mIsDefault; +}; + +#endif // LL_LLPHYSICSMOTION_H + diff --git a/indra/newview/llpolymesh.cpp b/indra/newview/llpolymesh.cpp index dbe6079ed..a23c199c9 100644 --- a/indra/newview/llpolymesh.cpp +++ b/indra/newview/llpolymesh.cpp @@ -49,7 +49,16 @@ #define HEADER_ASCII "Linden Mesh 1.0" #define HEADER_BINARY "Linden Binary Mesh 1.0" -extern LLControlGroup gSavedSettings; // read only +extern LLControlGroup gSavedSettings; // read only + +LLPolyMorphData *clone_morph_param_duplicate(const LLPolyMorphData *src_data, + const std::string &name); +LLPolyMorphData *clone_morph_param_direction(const LLPolyMorphData *src_data, + const LLVector3 &direction, + const std::string &name); +LLPolyMorphData *clone_morph_param_cleavage(const LLPolyMorphData *src_data, + F32 scale, + const std::string &name); //----------------------------------------------------------------------------- // Global table of loaded LLPolyMeshes @@ -606,8 +615,60 @@ BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName ) continue; } - mMorphData.insert(morph_data); - } + mMorphData.insert(morph_data); + + if (!strcmp(morphName, "Breast_Female_Cleavage")) + { + mMorphData.insert(clone_morph_param_cleavage(morph_data, + .75f, + "Breast_Physics_LeftRight_Driven")); + } + + if (!strcmp(morphName, "Breast_Female_Cleavage")) + { + mMorphData.insert(clone_morph_param_duplicate(morph_data, + "Breast_Physics_InOut_Driven")); + } + if (!strcmp(morphName, "Breast_Gravity")) + { + mMorphData.insert(clone_morph_param_duplicate(morph_data, + "Breast_Physics_UpDown_Driven")); + } + + if (!strcmp(morphName, "Big_Belly_Torso")) + { + mMorphData.insert(clone_morph_param_direction(morph_data, + LLVector3(0,0,0.05f), + "Belly_Physics_Torso_UpDown_Driven")); + } + + if (!strcmp(morphName, "Big_Belly_Legs")) + { + mMorphData.insert(clone_morph_param_direction(morph_data, + LLVector3(0,0,0.05f), + "Belly_Physics_Legs_UpDown_Driven")); + } + + if (!strcmp(morphName, "skirt_belly")) + { + mMorphData.insert(clone_morph_param_direction(morph_data, + LLVector3(0,0,0.05f), + "Belly_Physics_Skirt_UpDown_Driven")); + } + + if (!strcmp(morphName, "Small_Butt")) + { + mMorphData.insert(clone_morph_param_direction(morph_data, + LLVector3(0,0,0.05f), + "Butt_Physics_UpDown_Driven")); + } + if (!strcmp(morphName, "Small_Butt")) + { + mMorphData.insert(clone_morph_param_direction(morph_data, + LLVector3(0,0.03f,0), + "Butt_Physics_LeftRight_Driven")); + } + } S32 numRemaps; if (fread(&numRemaps, sizeof(S32), 1, fp) == 1) @@ -1156,4 +1217,55 @@ void LLPolySkeletalDistortion::apply( ESex avatar_sex ) mLastWeight = mCurWeight; } + +LLPolyMorphData *clone_morph_param_duplicate(const LLPolyMorphData *src_data, + const std::string &name) +{ + LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data); + cloned_morph_data->mName = name; + for (U32 v=0; v < cloned_morph_data->mNumIndices; v++) + { + cloned_morph_data->mCoords[v] = src_data->mCoords[v]; + cloned_morph_data->mNormals[v] = src_data->mNormals[v]; + cloned_morph_data->mBinormals[v] = src_data->mBinormals[v]; + } + return cloned_morph_data; +} + +LLPolyMorphData *clone_morph_param_direction(const LLPolyMorphData *src_data, + const LLVector3 &direction, + const std::string &name) +{ + LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data); + cloned_morph_data->mName = name; + for (U32 v=0; v < cloned_morph_data->mNumIndices; v++) + { + cloned_morph_data->mCoords[v] = direction; + cloned_morph_data->mNormals[v] = LLVector3(0,0,0); + cloned_morph_data->mBinormals[v] = LLVector3(0,0,0); + } + return cloned_morph_data; +} + +LLPolyMorphData *clone_morph_param_cleavage(const LLPolyMorphData *src_data, + F32 scale, + const std::string &name) +{ + LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data); + cloned_morph_data->mName = name; + for (U32 v=0; v < cloned_morph_data->mNumIndices; v++) + { + cloned_morph_data->mCoords[v] = src_data->mCoords[v]*scale; + cloned_morph_data->mNormals[v] = src_data->mNormals[v]*scale; + cloned_morph_data->mBinormals[v] = src_data->mBinormals[v]*scale; + if (cloned_morph_data->mCoords[v][1] < 0) + { + cloned_morph_data->mCoords[v][1] *= -1; + cloned_morph_data->mNormals[v][1] *= -1; + cloned_morph_data->mBinormals[v][1] *= -1; + } + } + return cloned_morph_data; +} + // End diff --git a/indra/newview/llpolymorph.cpp b/indra/newview/llpolymorph.cpp index 3a57b6f9f..72a332440 100644 --- a/indra/newview/llpolymorph.cpp +++ b/indra/newview/llpolymorph.cpp @@ -64,6 +64,36 @@ LLPolyMorphData::LLPolyMorphData(const std::string& morph_name) mMesh = NULL; } +LLPolyMorphData::LLPolyMorphData(const LLPolyMorphData &rhs) : + mName(rhs.mName), + mNumIndices(rhs.mNumIndices), + mTotalDistortion(rhs.mTotalDistortion), + mAvgDistortion(rhs.mAvgDistortion), + mMaxDistortion(rhs.mMaxDistortion), + mVertexIndices(NULL), + mCoords(NULL), + mNormals(NULL), + mBinormals(NULL), + mTexCoords(NULL) +{ + const S32 numVertices = mNumIndices; + + mCoords = new LLVector3[numVertices]; + mNormals = new LLVector3[numVertices]; + mBinormals = new LLVector3[numVertices]; + mTexCoords = new LLVector2[numVertices]; + mVertexIndices = new U32[numVertices]; + + for (S32 v=0; v < numVertices; v++) + { + mCoords[v] = rhs.mCoords[v]; + mNormals[v] = rhs.mNormals[v]; + mBinormals[v] = rhs.mBinormals[v]; + mTexCoords[v] = rhs.mTexCoords[v]; + mVertexIndices[v] = rhs.mVertexIndices[v]; + } +} + //----------------------------------------------------------------------------- // ~LLPolyMorphData() //----------------------------------------------------------------------------- @@ -292,10 +322,22 @@ BOOL LLPolyMorphTarget::setInfo(LLPolyMorphTargetInfo* info) } } - mMorphData = mMesh->getMorphData(getInfo()->mMorphName); + std::string morph_param_name = getInfo()->mMorphName; + + mMorphData = mMesh->getMorphData(morph_param_name); if (!mMorphData) { - llwarns << "No morph target named " << getInfo()->mMorphName << " found in mesh." << llendl; + const std::string driven_tag = "_Driven"; + U32 pos = morph_param_name.find(driven_tag); + if (pos > 0) + { + morph_param_name = morph_param_name.substr(0,pos); + mMorphData = mMesh->getMorphData(morph_param_name); + } + } + if (!mMorphData) + { + llwarns << "No morph target named " << morph_param_name << " found in mesh." << llendl; return FALSE; // Continue, ignoring this tag } return TRUE; @@ -445,6 +487,16 @@ void LLPolyMorphTarget::apply( ESex avatar_sex ) mLastSex = avatar_sex; + // Check for NaN condition (NaN is detected if a variable doesn't equal itself. + if (mCurWeight != mCurWeight) + { + mCurWeight = 0.0; + } + if (mLastWeight != mLastWeight) + { + mLastWeight = mCurWeight+.001; + } + // perform differential update of morph F32 delta_weight = ( getSex() & avatar_sex ) ? (mCurWeight - mLastWeight) : (getDefaultWeight() - mLastWeight); // store last weight diff --git a/indra/newview/llpolymorph.h b/indra/newview/llpolymorph.h index f8dd52ca3..3fdaf3785 100644 --- a/indra/newview/llpolymorph.h +++ b/indra/newview/llpolymorph.h @@ -51,6 +51,7 @@ class LLPolyMorphData public: LLPolyMorphData(const std::string& morph_name); ~LLPolyMorphData(); + LLPolyMorphData(const LLPolyMorphData &rhs); BOOL loadBinary(LLFILE* fp, LLPolyMeshSharedData *mesh); const std::string& getName() { return mName; } diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index 1716b5c5d..5c27e365a 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -915,10 +915,12 @@ void LLTextureCache::purgeCache(ELLPath location) if(LLFile::isdir(mTexturesDirName)) { std::string file_name = gDirUtilp->getExpandedFilename(location, entries_filename); - LLAPRFile::remove(file_name); + if(LLAPRFile::isExist(file_name)) + LLAPRFile::remove(file_name); file_name = gDirUtilp->getExpandedFilename(location, cache_filename); - LLAPRFile::remove(file_name); + if(LLAPRFile::isExist(file_name)) + LLAPRFile::remove(file_name); purgeAllTextures(true); } @@ -1711,7 +1713,8 @@ void LLTextureCache::purgeTextureFilesTimeSliced(bool force) if (mHeaderIDMap.find(curiter->first) == mHeaderIDMap.end()) { filename = curiter->second; - LLAPRFile::remove(filename); + if(LLAPRFile::isExist(filename)) + LLAPRFile::remove(filename); } else { @@ -1963,7 +1966,7 @@ void LLTextureCache::removeEntry(S32 idx, Entry& entry, std::string& filename, b mFreeList.insert(idx); } - if (remove_file) + if (remove_file && LLAPRFile::isExist(filename)) { LLAPRFile::remove(filename); } diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 8af25724f..22609c938 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -216,6 +216,12 @@ static bool handleAvatarLODChanged(const LLSD& newvalue) return true; } +static bool handleAvatarPhysicsLODChanged(const LLSD& newvalue) +{ + LLVOAvatar::sLODFactor = (F32) newvalue.asReal(); + return true; +} + static bool handleAvatarMaxVisibleChanged(const LLSD& newvalue) { LLVOAvatar::sMaxVisible = (U32) newvalue.asInteger(); @@ -583,6 +589,7 @@ void settings_setup_listeners() gSavedSettings.getControl("RenderAvatarLODFactor")->getSignal()->connect(boost::bind(&handleAvatarLODChanged, _1)); gSavedSettings.getControl("RenderTerrainLODFactor")->getSignal()->connect(boost::bind(&handleTerrainLODChanged, _1)); gSavedSettings.getControl("RenderTreeLODFactor")->getSignal()->connect(boost::bind(&handleTreeLODChanged, _1)); + gSavedSettings.getControl("RenderAvatarPhysicsLODFactor")->getSignal()->connect(boost::bind(&handleAvatarPhysicsLODChanged, _1)); gSavedSettings.getControl("RenderFlexTimeFactor")->getSignal()->connect(boost::bind(&handleFlexLODChanged, _1)); gSavedSettings.getControl("ThrottleBandwidthKBPS")->getSignal()->connect(boost::bind(&handleBandwidthChanged, _1)); gSavedSettings.getControl("RenderGamma")->getSignal()->connect(boost::bind(&handleGammaChanged, _1)); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 956e31502..b75c3345e 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -3913,6 +3913,7 @@ class LLEditEnableCustomizeAvatar : public view_listener_t } }; + class LLEditEnableChangeDisplayname : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) @@ -8894,6 +8895,10 @@ class LLEditEnableTakeOff : public view_listener_t { new_value = LLAgent::selfHasWearable((void *)WT_TATTOO); } + if (clothing == "physics") + { + new_value = LLAgent::selfHasWearable((void *)WT_PHYSICS); + } // [RLVa:KB] - Checked: 2009-07-07 (RLVa-1.1.3b) | Modified: RLVa-1.1.3b | OK // Why aren't they using LLWearable::typeNameToType()? *confuzzled* @@ -8957,6 +8962,10 @@ class LLEditTakeOff : public view_listener_t { LLAgent::userRemoveWearable((void*)WT_TATTOO); } + else if (clothing == "physics") + { + LLAgent::userRemoveWearable((void*)WT_PHYSICS); + } else if (clothing == "all") { LLAgent::userRemoveAllClothes(NULL); diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 5f1749ddd..9624a2151 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -103,6 +103,8 @@ #include "llavatarname.h" #include "llavatarnamecache.h" +#include "llphysicsmotion.h" + // [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) #include "rlvhandler.h" // [/RLVa:KB] @@ -128,6 +130,7 @@ const LLUUID ANIM_AGENT_HEAD_ROT = LLUUID("e6e8d1dd-e643-fff7-b238-c6b4b056a68d" const LLUUID ANIM_AGENT_PELVIS_FIX = LLUUID("0c5dd2a2-514d-8893-d44d-05beffad208b"); //"pelvis_fix" const LLUUID ANIM_AGENT_TARGET = LLUUID("0e4896cb-fba4-926c-f355-8720189d5b55"); //"target" const LLUUID ANIM_AGENT_WALK_ADJUST = LLUUID("829bc85b-02fc-ec41-be2e-74cc6dd7215d"); //"walk_adjust" +const LLUUID ANIM_AGENT_PHYSICS_MOTION = LLUUID("7360e029-3cb8-ebc4-863e-212df440d987"); //"physics_motion" //----------------------------------------------------------------------------- @@ -720,6 +723,7 @@ BOOL LLVOAvatar::sShowAnimationDebug = FALSE; BOOL LLVOAvatar::sShowFootPlane = FALSE; BOOL LLVOAvatar::sVisibleInFirstPerson = FALSE; F32 LLVOAvatar::sLODFactor = 1.f; +F32 LLVOAvatar::sPhysicsLODFactor = 1.f; BOOL LLVOAvatar::sUseImpostors = FALSE; BOOL LLVOAvatar::sJointDebug = FALSE; @@ -791,7 +795,8 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mFullyLoadedInitialized(FALSE), mHasBakedHair( FALSE ), mSupportsAlphaLayers(FALSE), - mFirstSetActualBoobGravRan( false ) + mFirstSetActualBoobGravRan( false ), + mSupportsPhysics( false ) //mFirstSetActualButtGravRan( false ), //mFirstSetActualFatGravRan( false ) // @@ -1016,6 +1021,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, // motions without a start/stop bit registerMotion( ANIM_AGENT_BODY_NOISE, LLBodyNoiseMotion::create ); registerMotion( ANIM_AGENT_BREATHE_ROT, LLBreatheMotionRot::create ); + registerMotion( ANIM_AGENT_PHYSICS_MOTION, LLPhysicsMotionController::create ); registerMotion( ANIM_AGENT_EDITING, LLEditingMotion::create ); registerMotion( ANIM_AGENT_EYE, LLEyeMotion::create ); registerMotion( ANIM_AGENT_FLY_ADJUST, LLFlyAdjustMotion::create ); @@ -1970,6 +1976,7 @@ void LLVOAvatar::startDefaultMotions() startMotion( ANIM_AGENT_EYE ); startMotion( ANIM_AGENT_BODY_NOISE ); startMotion( ANIM_AGENT_BREATHE_ROT ); + startMotion( ANIM_AGENT_PHYSICS_MOTION ); startMotion( ANIM_AGENT_HAND_MOTION ); startMotion( ANIM_AGENT_PELVIS_FIX ); @@ -2791,7 +2798,7 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) idleUpdateAppearanceAnimation(); if (detailed_update) { - idleUpdateBoobEffect(); + //idleUpdateBoobEffect(); idleUpdateLipSync( voice_enabled ); idleUpdateLoadingEffect(); idleUpdateBelowWater(); // wind effect uses this @@ -9151,6 +9158,13 @@ void LLVOAvatar::wearableUpdated(EWearableType type, BOOL upload_result) } } } + + // Physics type has no associated baked textures, but change of params needs to be sent to + // other avatars. + if (isSelf() && type == WT_PHYSICS) + { + gAgent.sendAgentSetAppearance(); + } } @@ -9355,6 +9369,8 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) updateMeshTextures(); // enables updates for laysets without baked textures. + mSupportsPhysics = false; + // parse visual params S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_VisualParam); if( num_blocks > 1 ) @@ -9387,6 +9403,10 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) mesgsys->getU8Fast(_PREHASH_VisualParam, _PREHASH_ParamValue, value, i); F32 newWeight = U8_to_F32(value, param->getMinWeight(), param->getMaxWeight()); + if(param->getID() == 10000) + { + mSupportsPhysics = true; + } if(param->getID() == 507 && newWeight != getActualBoobGrav()) { llwarns << "Boob Grav SET to " << newWeight << " for " << getFullname() << llendl; @@ -9431,6 +9451,8 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) { if (param->getName() == "tattoo_red") llinfos << getFullname() << " does not have tattoo tinting." << llendl; + else if(param->getName() == "breast_physics_leftright_spring") + llinfos << getFullname() << " does not have avatar physics." << llendl; else llwarns << "Number of params in AvatarAppearance msg does not match number of params in avatar xml file for " << getFullname() << " (Prematurely reached end of list at " << param->getName() << ")." << llendl; //return; //ASC-TTRFE diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 4bedcbb10..e21337c90 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -55,6 +55,7 @@ extern const LLUUID ANIM_AGENT_BODY_NOISE; extern const LLUUID ANIM_AGENT_BREATHE_ROT; +extern const LLUUID ANIM_AGENT_PHYSICS_MOTION; extern const LLUUID ANIM_AGENT_EDITING; extern const LLUUID ANIM_AGENT_EYE; extern const LLUUID ANIM_AGENT_FLY_ADJUST; @@ -98,6 +99,9 @@ public: void getClientInfo(std::string& clientTag, LLColor4& tagColor, BOOL useComment=FALSE); std::string extraMetadata; // + + // EmeraldBoobUtils + bool mSupportsPhysics; //Client supports v2 wearable physics. Disable emerald physics. //-------------------------------------------------------------------- // LLViewerObject interface @@ -629,6 +633,7 @@ public: static BOOL sDebugInvisible; static BOOL sShowAttachmentPoints; static F32 sLODFactor; // user-settable LOD factor + static F32 sPhysicsLODFactor; // user-settable physics LOD factor static BOOL sJointDebug; // output total number of joints being touched for each avatar static BOOL sDebugAvatarRotation; static F32 sAvMorphTime; diff --git a/indra/newview/llwearable.cpp b/indra/newview/llwearable.cpp index 14c6220c5..e85726166 100644 --- a/indra/newview/llwearable.cpp +++ b/indra/newview/llwearable.cpp @@ -72,6 +72,7 @@ const std::string LLWearable::sTypeName[ WT_COUNT+1 ] = "skirt", "alpha", "tattoo", + "physics", "invalid" }; @@ -93,6 +94,7 @@ const std::string LLWearable::sTypeLabel[ WT_COUNT+1 ] = "Skirt", "Alpha", "Tattoo", + "Physics", "invalid" }; @@ -118,6 +120,7 @@ LLAssetType::EType LLWearable::typeToAssetType(EWearableType wearable_type) case WT_SKIRT: case WT_ALPHA: case WT_TATTOO: + case WT_PHYSICS: return LLAssetType::AT_CLOTHING; default: return LLAssetType::AT_NONE; diff --git a/indra/newview/llwearable.h b/indra/newview/llwearable.h index 253ae97b0..72d876359 100644 --- a/indra/newview/llwearable.h +++ b/indra/newview/llwearable.h @@ -58,7 +58,8 @@ enum EWearableType // If you change this, update LLWearable::getTypeName(), get WT_SKIRT = 12, WT_ALPHA = 13, WT_TATTOO = 14, - WT_COUNT = 15, + WT_PHYSICS = 15, + WT_COUNT = 16, WT_INVALID = 255 }; diff --git a/indra/newview/rlvhandler.cpp b/indra/newview/rlvhandler.cpp index 8fb992e0c..94b88fb0c 100644 --- a/indra/newview/rlvhandler.cpp +++ b/indra/newview/rlvhandler.cpp @@ -1993,7 +1993,7 @@ ERlvCmdRet RlvHandler::onGetOutfit(const RlvCommand& rlvCmd, std::string& strRep const EWearableType wtRlvTypes[] = { WT_GLOVES, WT_JACKET, WT_PANTS, WT_SHIRT, WT_SHOES, WT_SKIRT, WT_SOCKS, - WT_UNDERPANTS, WT_UNDERSHIRT, WT_SKIN, WT_EYES, WT_HAIR, WT_SHAPE, WT_ALPHA, WT_TATTOO + WT_UNDERPANTS, WT_UNDERSHIRT, WT_SKIN, WT_EYES, WT_HAIR, WT_SHAPE, WT_ALPHA, WT_TATTOO, WT_PHYSICS }; for (int idxType = 0, cntType = sizeof(wtRlvTypes) / sizeof(EWearableType); idxType < cntType; idxType++) diff --git a/indra/newview/skins/default/textures/inv_item_physics.png b/indra/newview/skins/default/textures/inv_item_physics.png new file mode 100644 index 000000000..360baec46 Binary files /dev/null and b/indra/newview/skins/default/textures/inv_item_physics.png differ diff --git a/indra/newview/skins/default/xui/en-us/floater_customize.xml b/indra/newview/skins/default/xui/en-us/floater_customize.xml index 2dea4626a..261ab3189 100644 --- a/indra/newview/skins/default/xui/en-us/floater_customize.xml +++ b/indra/newview/skins/default/xui/en-us/floater_customize.xml @@ -1298,11 +1298,103 @@ scratch and wear it.