Merge branch 'master' of https://github.com/FirestormViewer/phoenix-firestorm
commit
b49c3a083b
|
|
@ -86,7 +86,7 @@ jobs:
|
|||
variants: ${{ matrix.configuration }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
|
||||
|
|
@ -95,14 +95,14 @@ jobs:
|
|||
with:
|
||||
python-version: "3.11"
|
||||
- name: Checkout build variables
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
repository: secondlife/build-variables
|
||||
ref: master
|
||||
path: .build-variables
|
||||
|
||||
- name: Checkout master-message-template
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
repository: secondlife/master-message-template
|
||||
path: .master-message-template
|
||||
|
|
|
|||
|
|
@ -16,8 +16,6 @@ on:
|
|||
- "*alpha"
|
||||
- "*nightly"
|
||||
- "*preview"
|
||||
schedule:
|
||||
- cron: '00 03 * * *' # Run every day at 3am UTC
|
||||
env:
|
||||
AUTOBUILD_VARIABLES_FILE: ${{github.workspace}}/build-variables/variables
|
||||
EXTRA_ARGS: -DUSE_FMODSTUDIO=ON -DUSE_KDU=ON --crashreporting
|
||||
|
|
@ -58,7 +56,7 @@ jobs:
|
|||
echo "/usr/local/bin" >> $GITHUB_PATH
|
||||
echo "$(brew --prefix)/opt/gnu-sed/libexec/gnubin" >> $GITHUB_PATH
|
||||
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
# Use apt-based Python when inside the Ubuntu 22.04 container
|
||||
- name: Install Python 3.11 (container case)
|
||||
if: matrix.container_image == 'ubuntu:22.04'
|
||||
|
|
@ -185,12 +183,12 @@ jobs:
|
|||
shell: bash
|
||||
|
||||
- name: Get the code
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Checkout build vars (after the main code)
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
repository: FirestormViewer/fs-build-variables
|
||||
path: build-variables
|
||||
|
|
@ -521,7 +519,7 @@ jobs:
|
|||
if: always()
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
sparse-checkout: |
|
||||
fsutils/download_list.py
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ jobs:
|
|||
echo "/usr/local/bin" >> $GITHUB_PATH
|
||||
echo "$(brew --prefix)/opt/gnu-sed/libexec/gnubin" >> $GITHUB_PATH
|
||||
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
# Use apt-based Python when inside the Ubuntu 22.04 container
|
||||
- name: Install Python 3.11 (container case)
|
||||
if: matrix.container_image == 'ubuntu:22.04'
|
||||
|
|
@ -185,12 +185,12 @@ jobs:
|
|||
shell: bash
|
||||
|
||||
- name: Get the code
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Checkout build vars (after the main code)
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
repository: FirestormViewer/fs-build-variables
|
||||
path: build-variables
|
||||
|
|
@ -521,7 +521,7 @@ jobs:
|
|||
if: always()
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
sparse-checkout: |
|
||||
fsutils/download_list.py
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ jobs:
|
|||
contents: read
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
sparse-checkout: |
|
||||
fsutils/download_list.py
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ jobs:
|
|||
pre-commit:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: 3.x
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ jobs:
|
|||
steps:
|
||||
# Checkout the Repository
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0 # Necessary to fetch all history for tagging
|
||||
|
||||
|
|
|
|||
|
|
@ -278,3 +278,18 @@ void LLChatEntry::paste()
|
|||
}
|
||||
}
|
||||
// </FS:Ansariel>
|
||||
|
||||
// <FS:Zi> Add menu items to copy and/or insert mention URIs into chat
|
||||
void LLChatEntry::insertMentionAtCursor(const std::string& str)
|
||||
{
|
||||
S32 cursor_from_end = getLength() - getCursorPos();
|
||||
|
||||
insertText(str);
|
||||
|
||||
std::string new_text(wstring_to_utf8str(getConvertedText()));
|
||||
clear();
|
||||
appendTextImpl(new_text, LLStyle::Params(), true);
|
||||
|
||||
setCursorPos(getLength() - cursor_from_end);
|
||||
}
|
||||
// </FS:Zi>
|
||||
|
|
|
|||
|
|
@ -71,6 +71,9 @@ public:
|
|||
// <FS:Ansariel> Changed to public so we can update history when using modifier keys
|
||||
void updateHistory();
|
||||
|
||||
// <FS:Zi> Add menu items to copy and/or insert mention URIs into chat
|
||||
void insertMentionAtCursor(const std::string& str);
|
||||
|
||||
// <FS:Ansariel> Fix linefeed pasting
|
||||
/*virtual*/ void paste();
|
||||
|
||||
|
|
|
|||
|
|
@ -1268,6 +1268,7 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)
|
|||
p.button_flash_count(LLUI::getInstance()->mSettingGroups["config"]->getS32("FlashCount"));
|
||||
p.button_flash_rate(LLUI::getInstance()->mSettingGroups["config"]->getF32("FlashPeriod"));
|
||||
// </FS:Ansariel>
|
||||
p.handle_right_mouse = false; // <FS:Zi> Fix tab rearranging when active tab was right clicked before
|
||||
|
||||
// *TODO : It seems wrong not to use p in both cases considering the way p is initialized
|
||||
if (mCustomIconCtrlUsed)
|
||||
|
|
|
|||
|
|
@ -2482,6 +2482,11 @@ void LLTextBase::createUrlContextMenu(S32 x, S32 y, const std::string &in_url)
|
|||
enable_registrar.add("FS.EnableViewLog", std::bind(&FSRegistrarUtils::checkIsEnabled, gFSRegistrarUtils, target_id, EFSRegistrarFunctionActionType::FS_RGSTR_ACT_VIEW_TRANSCRIPT));
|
||||
// </FS:Ansariel>
|
||||
|
||||
// <FS:Zi> Add menu items to copy and/or insert mention URIs into chat
|
||||
registrar.add("Mention.CopyURI", boost::bind(&LLUrlAction::copyURLToClipboard, "secondlife:///app/agent/" + target_id_str + "/mention"));
|
||||
registrar.add("Mention.Chat", boost::bind(&LLTextBase::insertMentionAtCursor, this, "secondlife:///app/agent/" + target_id_str + "/mention"));
|
||||
// </FS:Zi>
|
||||
|
||||
// <FS:Zi> FIRE-30725 - Add more group functions to group URL context menu
|
||||
registrar.add("FS.JoinGroup", std::bind(&LLUrlAction::executeSLURL, "secondlife:///app/firestorm/" + target_id_str + "/groupjoin", true));
|
||||
registrar.add("FS.LeaveGroup", std::bind(&LLUrlAction::executeSLURL, "secondlife:///app/firestorm/" + target_id_str + "/groupleave", true));
|
||||
|
|
@ -2561,6 +2566,14 @@ void LLTextBase::createUrlContextMenu(S32 x, S32 y, const std::string &in_url)
|
|||
}
|
||||
// </FS:Zi>
|
||||
|
||||
// <FS:Zi> Add menu items to copy and/or insert mention URIs into chat
|
||||
if (!parent_floater || (parent_floater->getName() != "panel_im" && parent_floater->getName() != "nearby_chat"))
|
||||
{
|
||||
menu->getChild<LLView>("MentionURISeparator")->setVisible(false);
|
||||
menu->getChild<LLView>("mention_in_chat")->setVisible(false);
|
||||
}
|
||||
// </FS:Zi>
|
||||
|
||||
menu->show(x, y);
|
||||
LLMenuGL::showPopup(this, menu, x, y);
|
||||
}
|
||||
|
|
@ -4627,3 +4640,10 @@ void LLTextBase::setWordWrap(bool wrap)
|
|||
{
|
||||
mWordWrap = wrap;
|
||||
}
|
||||
|
||||
// <FS:Zi> Add menu items to copy and/or insert mention URIs into chat
|
||||
// virtual
|
||||
void LLTextBase::insertMentionAtCursor(const std::string& str)
|
||||
{
|
||||
}
|
||||
// </FS:Zi>
|
||||
|
|
|
|||
|
|
@ -731,6 +731,9 @@ protected:
|
|||
void appendAndHighlightTextImpl(const std::string &new_text, S32 highlight_part, const LLStyle::Params& style_params, e_underline underline_link = e_underline::UNDERLINE_ALWAYS);
|
||||
S32 normalizeUri(std::string& uri);
|
||||
|
||||
// <FS:Zi> Add menu items to copy and/or insert mention URIs into chat
|
||||
virtual void insertMentionAtCursor(const std::string& str);
|
||||
|
||||
protected:
|
||||
// virtual
|
||||
std::string _getSearchText() const override
|
||||
|
|
|
|||
|
|
@ -1268,9 +1268,11 @@ bool LLWindowMacOSX::setCursorPosition(const LLCoordWindow position)
|
|||
// trigger mouse move callback
|
||||
LLCoordGL gl_pos;
|
||||
convertCoords(position, &gl_pos);
|
||||
float scale = getSystemUISize();
|
||||
gl_pos.mX *= scale;
|
||||
gl_pos.mY *= scale;
|
||||
// <FS:TJ> gl_pos is not meant to be scaled and breaks our pie menu and possibly other things
|
||||
//float scale = getSystemUISize();
|
||||
//gl_pos.mX *= scale;
|
||||
//gl_pos.mY *= scale;
|
||||
// </FS:TJ>
|
||||
mCallbacks->handleMouseMove(this, gl_pos, (MASK)0);
|
||||
|
||||
return result;
|
||||
|
|
|
|||
|
|
@ -1108,7 +1108,6 @@ void MediaPluginCEF::keyEvent(dullahan::EKeyEvent key_event, LLSD native_key_dat
|
|||
|
||||
// <FS:ND> Keyboard handling for Linux.
|
||||
#if LL_LINUX
|
||||
#if LL_SDL2
|
||||
|
||||
uint32_t native_virtual_key = (uint32_t)(native_key_data["virtual_key"].asInteger()); // this is actually the SDL event.key.keysym.sym;
|
||||
uint32_t native_virtual_key_win = (uint32_t)(native_key_data["virtual_key_win"].asInteger());
|
||||
|
|
@ -1127,16 +1126,6 @@ void MediaPluginCEF::keyEvent(dullahan::EKeyEvent key_event, LLSD native_key_dat
|
|||
mCEFLib->nativeKeyboardEventSDL2(key_event, native_virtual_key_win, native_modifiers, keypad);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
uint32_t native_scan_code = (uint32_t)(native_key_data["sdl_sym"].asInteger());
|
||||
uint32_t native_virtual_key = (uint32_t)(native_key_data["virtual_key"].asInteger());
|
||||
uint32_t native_modifiers = (uint32_t)(native_key_data["cef_modifiers"].asInteger());
|
||||
if( native_scan_code == '\n' )
|
||||
native_scan_code = '\r';
|
||||
mCEFLib->nativeKeyboardEvent(key_event, native_scan_code, native_virtual_key, native_modifiers);
|
||||
|
||||
#endif // LL_SDL2
|
||||
#endif // LL_LINUX
|
||||
// </FS:ND>
|
||||
};
|
||||
|
|
@ -1171,7 +1160,6 @@ void MediaPluginCEF::unicodeInput(std::string event, LLSD native_key_data = LLSD
|
|||
#endif
|
||||
|
||||
#if LL_LINUX
|
||||
# if LL_SDL2
|
||||
|
||||
uint32_t native_scan_code = (uint32_t)(native_key_data["sdl_sym"].asInteger());
|
||||
uint32_t native_virtual_key = (uint32_t)(native_key_data["virtual_key"].asInteger());
|
||||
|
|
@ -1179,7 +1167,6 @@ void MediaPluginCEF::unicodeInput(std::string event, LLSD native_key_data = LLSD
|
|||
|
||||
mCEFLib->nativeKeyboardEvent(dullahan::KE_KEY_DOWN, native_scan_code, native_virtual_key, native_modifiers);
|
||||
|
||||
#endif // LL_SDL2
|
||||
#endif // LL_LINUX
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -133,6 +133,7 @@ set(viewer_SOURCE_FILES
|
|||
fsfloaterprotectedfolders.cpp
|
||||
fsfloaterradar.cpp
|
||||
fsfloatersearch.cpp
|
||||
fsfloatersplashscreensettings.cpp
|
||||
fsfloaterstatistics.cpp
|
||||
fsfloaterstreamtitle.cpp
|
||||
fsfloaterteleporthistory.cpp
|
||||
|
|
@ -974,6 +975,7 @@ set(viewer_HEADER_FILES
|
|||
fsfloaterprotectedfolders.h
|
||||
fsfloaterradar.h
|
||||
fsfloatersearch.h
|
||||
fsfloatersplashscreensettings.h
|
||||
fsfloaterstatistics.h
|
||||
fsfloaterstreamtitle.h
|
||||
fsfloaterteleporthistory.h
|
||||
|
|
@ -2514,6 +2516,7 @@ elseif (DARWIN)
|
|||
XCODE_ATTRIBUTE_OTHER_LDFLAGS[arch=x86_64] "$(inherited) -L${CMAKE_CURRENT_BINARY_DIR}/llphysicsextensions/$<IF:$<BOOL:${LL_GENERATOR_IS_MULTI_CONFIG}>,$<CONFIG>,${CMAKE_CFG_INTDIR}>/ -lllphysicsextensions -Xlinker -map -Xlinker ${CMAKE_CURRENT_BINARY_DIR}/${VIEWER_BINARY_NAME}.MAP"
|
||||
XCODE_ATTRIBUTE_OTHER_LDFLAGS[arch=arm64] "$(inherited) -L${CMAKE_BINARY_DIR}/llphysicsextensionsos/$<IF:$<BOOL:${LL_GENERATOR_IS_MULTI_CONFIG}>,$<CONFIG>,${CMAKE_CFG_INTDIR}>/ -lllphysicsextensionsos"
|
||||
)
|
||||
add_dependencies(${VIEWER_BINARY_NAME} llphysicsextensionsos)
|
||||
elseif(HAVOK_TPV)
|
||||
set_target_properties(${VIEWER_BINARY_NAME}
|
||||
PROPERTIES
|
||||
|
|
@ -2524,6 +2527,7 @@ elseif (DARWIN)
|
|||
XCODE_ATTRIBUTE_OTHER_LDFLAGS[arch=x86_64] "$(inherited) -L${ARCH_PREBUILT_DIRS}/ -lllphysicsextensions_tpv"
|
||||
XCODE_ATTRIBUTE_OTHER_LDFLAGS[arch=arm64] "$(inherited) -L${CMAKE_BINARY_DIR}/llphysicsextensionsos/$<IF:$<BOOL:${LL_GENERATOR_IS_MULTI_CONFIG}>,$<CONFIG>,${CMAKE_CFG_INTDIR}>/ -lllphysicsextensionsos"
|
||||
)
|
||||
add_dependencies(${VIEWER_BINARY_NAME} llphysicsextensionsos)
|
||||
else()
|
||||
target_link_libraries(${VIEWER_BINARY_NAME} llphysicsextensionsos)
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -152,11 +152,12 @@ void FloaterAO::updateList()
|
|||
mCurrentBoldItem = nullptr;
|
||||
reloading(false);
|
||||
|
||||
static std::string no_sets_label = getString("ao_no_sets_loaded");
|
||||
if (mSetList.empty())
|
||||
{
|
||||
LL_DEBUGS("AOEngine") << "empty set list" << LL_ENDL;
|
||||
mSetSelector->add(getString("ao_no_sets_loaded"));
|
||||
mSetSelectorSmall->add(getString("ao_no_sets_loaded"));
|
||||
mSetSelector->add(no_sets_label);
|
||||
mSetSelectorSmall->add(no_sets_label);
|
||||
mSetSelector->selectNthItem(0);
|
||||
mSetSelectorSmall->selectNthItem(0);
|
||||
enableSetControls(false);
|
||||
|
|
@ -164,13 +165,13 @@ void FloaterAO::updateList()
|
|||
}
|
||||
|
||||
// make sure we have an animation set name to display
|
||||
if (currentSetName.empty())
|
||||
if (currentSetName.empty() || currentSetName == no_sets_label)
|
||||
{
|
||||
// selected animation set was empty, get the currently active animation set from the engine
|
||||
currentSetName = AOEngine::instance().getCurrentSetName();
|
||||
LL_DEBUGS("AOEngine") << "Current set name was empty, fetched name \"" << currentSetName << "\" from AOEngine" << LL_ENDL;
|
||||
|
||||
if(currentSetName.empty())
|
||||
if (currentSetName.empty())
|
||||
{
|
||||
// selected animation set was empty, get the name of the first animation set in the list
|
||||
currentSetName = mSetList[0]->getName();
|
||||
|
|
@ -374,7 +375,7 @@ void FloaterAO::onSelectSet()
|
|||
// only update the interface when we actually selected a different set - FIRE-29542
|
||||
if (mSelectedSet != set)
|
||||
{
|
||||
mSelectedSet=set;
|
||||
mSelectedSet = set;
|
||||
|
||||
updateSetParameters();
|
||||
updateAnimationList();
|
||||
|
|
|
|||
|
|
@ -40,10 +40,11 @@
|
|||
#include "llnotificationsutil.h"
|
||||
#include "llstring.h"
|
||||
#include "llviewercontrol.h"
|
||||
#include "llxorcipher.h"
|
||||
|
||||
#define ROOT_AO_FOLDER "#AO"
|
||||
#include <boost/graph/graph_concepts.hpp>
|
||||
#define ROOT_AO_FOLDER "#AO"
|
||||
|
||||
static const LLUUID ENCRYPTION_MAGIC_ID("4b552ff5-fd63-408c-8288-cd09429852ba");
|
||||
constexpr F32 INVENTORY_POLLING_INTERVAL = 5.0f;
|
||||
|
||||
AOEngine::AOEngine() :
|
||||
|
|
@ -68,6 +69,31 @@ AOEngine::AOEngine() :
|
|||
|
||||
AOEngine::~AOEngine()
|
||||
{
|
||||
LLSD currentState = LLSD::emptyMap();
|
||||
if (mCurrentSet)
|
||||
{
|
||||
currentState = LLSD().with("CurrentSet", mCurrentSet->getName());
|
||||
LLSD currentAnimations;
|
||||
for (S32 index = 0; index < AOSet::AOSTATES_MAX; ++index)
|
||||
{
|
||||
if (auto state = mCurrentSet->getState(index); state && !state->mAnimations.empty())
|
||||
{
|
||||
LL_DEBUGS("AOEngine") << "Storing current animation for state " << index << ": Animation index " << state->mCurrentAnimation << LL_ENDL;
|
||||
LLUUID shadow_id{ state->mAnimations[state->mCurrentAnimation].mAssetUUID };
|
||||
LLXORCipher cipher(ENCRYPTION_MAGIC_ID.mData, UUID_BYTES);
|
||||
cipher.encrypt(shadow_id.mData, UUID_BYTES);
|
||||
currentAnimations.insert(state->mName, shadow_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_DEBUGS("AOEngine") << "No state " << index << " or no animations defined for this state" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
currentState.insert("CurrentStateAnimations", currentAnimations);
|
||||
}
|
||||
LL_DEBUGS("AOEngine") << "Stored AO state: " << currentState << LL_ENDL;
|
||||
gSavedPerAccountSettings.setLLSD("FSCurrentAOState", currentState);
|
||||
|
||||
clear(false);
|
||||
|
||||
if (mRegionChangeConnection.connected())
|
||||
|
|
@ -458,11 +484,9 @@ void AOEngine::enable(bool enable)
|
|||
// stop all overriders, catch leftovers
|
||||
for (S32 index = 0; index < AOSet::AOSTATES_MAX; ++index)
|
||||
{
|
||||
state = mCurrentSet->getState(index);
|
||||
if (state)
|
||||
if (auto state = mCurrentSet->getState(index))
|
||||
{
|
||||
LLUUID animation = state->mCurrentAnimationID;
|
||||
if (animation.notNull())
|
||||
if (LLUUID animation = state->mCurrentAnimationID; animation.notNull())
|
||||
{
|
||||
LL_DEBUGS("AOEngine") << "Stopping leftover animation from state " << state->mName << LL_ENDL;
|
||||
gAgent.sendAnimationRequest(animation, ANIM_REQUEST_STOP);
|
||||
|
|
@ -488,7 +512,7 @@ void AOEngine::enable(bool enable)
|
|||
|
||||
void AOEngine::setStateCycleTimer(const AOSet::AOState* state)
|
||||
{
|
||||
F32 timeout = (F32)state->mCycleTime;
|
||||
F32 timeout = state->mCycleTime;
|
||||
LL_DEBUGS("AOEngine") << "Setting cycle timeout for state " << state->mName << " of " << timeout << LL_ENDL;
|
||||
if (timeout > 0.0f)
|
||||
{
|
||||
|
|
@ -583,7 +607,7 @@ const LLUUID AOEngine::override(const LLUUID& motion, bool start)
|
|||
// case, as it plays at the same time as other motions
|
||||
if (motion != ANIM_AGENT_TYPE)
|
||||
{
|
||||
constexpr S32 cleanupStates[]=
|
||||
constexpr S32 cleanupStates[] =
|
||||
{
|
||||
AOSet::Standing,
|
||||
AOSet::Walking,
|
||||
|
|
@ -615,15 +639,14 @@ const LLUUID AOEngine::override(const LLUUID& motion, bool start)
|
|||
while ((stateNum = cleanupStates[index]) != AOSet::AOSTATES_MAX)
|
||||
{
|
||||
// check if the next state is the one we are currently animating and skip that
|
||||
AOSet::AOState* stateToCheck = mCurrentSet->getState(stateNum);
|
||||
if (stateToCheck != state)
|
||||
if (AOSet::AOState* stateToCheck = mCurrentSet->getState(stateNum); stateToCheck != state)
|
||||
{
|
||||
// check if there is an animation left over for that state
|
||||
if (!stateToCheck->mCurrentAnimationID.isNull())
|
||||
{
|
||||
LL_WARNS() << "cleaning up animation in state " << stateToCheck->mName << LL_ENDL;
|
||||
|
||||
// stop the leftover animation locally and in the region for everyone
|
||||
// stop the leftover animation locally and in the region for everyone
|
||||
gAgent.sendAnimationRequest(stateToCheck->mCurrentAnimationID, ANIM_REQUEST_STOP);
|
||||
gAgentAvatarp->LLCharacter::stopMotion(stateToCheck->mCurrentAnimationID);
|
||||
|
||||
|
|
@ -702,7 +725,7 @@ const LLUUID AOEngine::override(const LLUUID& motion, bool start)
|
|||
}
|
||||
|
||||
state->mCurrentAnimationID = animation;
|
||||
LL_DEBUGS("AOEngine") << "overriding " << gAnimLibrary.animationName(motion)
|
||||
LL_DEBUGS("AOEngine") << "overriding " << gAnimLibrary.animationName(motion)
|
||||
<< " with " << animation
|
||||
<< " in state " << state->mName
|
||||
<< " of set " << mCurrentSet->getName()
|
||||
|
|
@ -803,22 +826,21 @@ const LLUUID AOEngine::override(const LLUUID& motion, bool start)
|
|||
|
||||
void AOEngine::checkSitCancel()
|
||||
{
|
||||
if (foreignAnimations())
|
||||
if (!foreignAnimations())
|
||||
return;
|
||||
|
||||
if (AOSet::AOState* aoState = mCurrentSet->getStateByRemapID(ANIM_AGENT_SIT))
|
||||
{
|
||||
if (AOSet::AOState* aoState = mCurrentSet->getStateByRemapID(ANIM_AGENT_SIT); aoState)
|
||||
if (LLUUID animation = aoState->mCurrentAnimationID; animation.notNull())
|
||||
{
|
||||
LLUUID animation = aoState->mCurrentAnimationID;
|
||||
if (animation.notNull())
|
||||
{
|
||||
LL_DEBUGS("AOEngine") << "Stopping sit animation due to foreign animations running" << LL_ENDL;
|
||||
gAgent.sendAnimationRequest(animation, ANIM_REQUEST_STOP);
|
||||
// remove cycle point cover-up
|
||||
gAgent.sendAnimationRequest(ANIM_AGENT_SIT_GENERIC, ANIM_REQUEST_STOP);
|
||||
gAgentAvatarp->LLCharacter::stopMotion(animation);
|
||||
mSitCancelTimer.stop();
|
||||
// stop cycle tiemr
|
||||
mCurrentSet->stopTimer();
|
||||
}
|
||||
LL_DEBUGS("AOEngine") << "Stopping sit animation due to foreign animations running" << LL_ENDL;
|
||||
gAgent.sendAnimationRequest(animation, ANIM_REQUEST_STOP);
|
||||
// remove cycle point cover-up
|
||||
gAgent.sendAnimationRequest(ANIM_AGENT_SIT_GENERIC, ANIM_REQUEST_STOP);
|
||||
gAgentAvatarp->LLCharacter::stopMotion(animation);
|
||||
mSitCancelTimer.stop();
|
||||
// stop cycle tiemr
|
||||
mCurrentSet->stopTimer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -918,7 +940,7 @@ void AOEngine::cycle(eCycleMode cycleMode)
|
|||
{
|
||||
LL_DEBUGS("AOEngine") << "Asset UUID for cycled animation " << anim.mName << " not yet known, try to find it." << LL_ENDL;
|
||||
|
||||
if(LLViewerInventoryItem* item = gInventory.getItem(anim.mOriginalUUID) ; item)
|
||||
if (LLViewerInventoryItem* item = gInventory.getItem(anim.mOriginalUUID); item)
|
||||
{
|
||||
LL_DEBUGS("AOEngine") << "Found asset UUID for cycled animation: " << item->getAssetUUID() << " - Updating AOAnimation.mAssetUUID" << LL_ENDL;
|
||||
anim.mAssetUUID = item->getAssetUUID();
|
||||
|
|
@ -992,14 +1014,13 @@ void AOEngine::playAnimation(const LLUUID& animation)
|
|||
return;
|
||||
}
|
||||
|
||||
if (!state->mAnimations.size())
|
||||
if (state->mAnimations.empty())
|
||||
{
|
||||
LL_DEBUGS("AOEngine") << "cycle without animations in state." << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
LLViewerInventoryItem* item = gInventory.getItem(animation);
|
||||
|
||||
if (!item)
|
||||
{
|
||||
LL_WARNS("AOEngine") << "Inventory item for animation " << animation << " not found." << LL_ENDL;
|
||||
|
|
@ -1007,10 +1028,10 @@ void AOEngine::playAnimation(const LLUUID& animation)
|
|||
}
|
||||
|
||||
AOSet::AOAnimation anim;
|
||||
anim.mName = item->LLInventoryItem::getName();
|
||||
anim.mName = item->getName();
|
||||
anim.mInventoryUUID = item->getUUID();
|
||||
anim.mOriginalUUID = item->getLinkedUUID();
|
||||
anim.mAssetUUID = LLUUID::null;
|
||||
anim.mAssetUUID.setNull();
|
||||
|
||||
// if we can find the original animation already right here, save its asset ID, otherwise this will
|
||||
// be tried again in AOSet::getAnimationForState() and/or AOEngine::cycle()
|
||||
|
|
@ -1100,7 +1121,7 @@ void AOEngine::updateSortOrder(AOSet::AOState* state)
|
|||
std::ostringstream numStr("");
|
||||
numStr << index;
|
||||
|
||||
LL_DEBUGS("AOEngine") << "sort order is " << sortOrder << " but index is " << index
|
||||
LL_DEBUGS("AOEngine") << "sort order is " << sortOrder << " but index is " << index
|
||||
<< ", setting sort order description: " << numStr.str() << LL_ENDL;
|
||||
|
||||
state->mAnimations[index].mSortOrder = index;
|
||||
|
|
@ -1111,8 +1132,8 @@ void AOEngine::updateSortOrder(AOSet::AOState* state)
|
|||
LL_WARNS("AOEngine") << "NULL inventory item found while trying to copy " << state->mAnimations[index].mInventoryUUID << LL_ENDL;
|
||||
continue;
|
||||
}
|
||||
LLPointer<LLViewerInventoryItem> newItem = new LLViewerInventoryItem(item);
|
||||
|
||||
LLPointer<LLViewerInventoryItem> newItem = new LLViewerInventoryItem(item);
|
||||
newItem->setDescription(numStr.str());
|
||||
newItem->setComplete(true);
|
||||
newItem->updateServer(false);
|
||||
|
|
@ -1181,7 +1202,7 @@ void AOEngine::addAnimation(const AOSet* set, AOSet::AOState* state, const LLInv
|
|||
bool success = createAnimationLink(state, item);
|
||||
gSavedPerAccountSettings.setBOOL("LockAOFolders", wasProtected);
|
||||
|
||||
if(success)
|
||||
if (success)
|
||||
{
|
||||
if (reload)
|
||||
{
|
||||
|
|
@ -1197,7 +1218,7 @@ void AOEngine::addAnimation(const AOSet* set, AOSet::AOState* state, const LLInv
|
|||
state->mAddQueue.push_back(item);
|
||||
|
||||
// if this is the first queued animation for this state, create the folder asyncronously
|
||||
if(state->mAddQueue.size() == 1)
|
||||
if (state->mAddQueue.size() == 1)
|
||||
{
|
||||
gInventory.createNewCategory(set->getInventoryUUID(), LLFolderType::FT_NONE, state->mName, [this, state, reload, wasProtected](const LLUUID &new_cat_id)
|
||||
{
|
||||
|
|
@ -1440,7 +1461,7 @@ bool AOEngine::swapWithNext(AOSet::AOState* state, S32 index)
|
|||
return true;
|
||||
}
|
||||
|
||||
void AOEngine::reloadStateAnimations(AOSet::AOState* state)
|
||||
void AOEngine::reloadStateAnimations(AOSet* set, AOSet::AOState* state)
|
||||
{
|
||||
LLInventoryModel::item_array_t* items;
|
||||
LLInventoryModel::cat_array_t* dummy;
|
||||
|
|
@ -1458,11 +1479,10 @@ void AOEngine::reloadStateAnimations(AOSet::AOState* state)
|
|||
<< " asset " << item->getAssetUUID() << LL_ENDL;
|
||||
|
||||
AOSet::AOAnimation anim;
|
||||
anim.mName = item->LLInventoryItem::getName();
|
||||
anim.mName = item->getName();
|
||||
anim.mInventoryUUID = item->getUUID();
|
||||
anim.mOriginalUUID = item->getLinkedUUID();
|
||||
|
||||
anim.mAssetUUID = LLUUID::null;
|
||||
anim.mAssetUUID.setNull();
|
||||
|
||||
// if we can find the original animation already right here, save its asset ID, otherwise this will
|
||||
// be tried again in AOSet::getAnimationForState() and/or AOEngine::cycle()
|
||||
|
|
@ -1509,6 +1529,24 @@ void AOEngine::reloadStateAnimations(AOSet::AOState* state)
|
|||
}
|
||||
|
||||
updateSortOrder(state);
|
||||
|
||||
if (auto currentState = gSavedPerAccountSettings.getLLSD("FSCurrentAOState");
|
||||
currentState.has("CurrentSet") && currentState["CurrentSet"].asString() == set->getName() &&
|
||||
currentState.has("CurrentStateAnimations") && currentState["CurrentStateAnimations"].has(state->mName))
|
||||
{
|
||||
auto currentStateAnimId{ currentState["CurrentStateAnimations"][state->mName].asUUID() };
|
||||
LLXORCipher cipher(ENCRYPTION_MAGIC_ID.mData, UUID_BYTES);
|
||||
cipher.decrypt(currentStateAnimId.mData, UUID_BYTES);
|
||||
|
||||
for (const auto& animation : state->mAnimations)
|
||||
{
|
||||
if (animation.mAssetUUID == currentStateAnimId)
|
||||
{
|
||||
state->mCurrentAnimation = animation.mSortOrder;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AOEngine::update()
|
||||
|
|
@ -1559,19 +1597,27 @@ void AOEngine::update()
|
|||
continue;
|
||||
}
|
||||
|
||||
AOSet* newSet = getSetByName(params[0]);
|
||||
auto setName{ params[0] };
|
||||
AOSet* newSet = getSetByName(setName);
|
||||
if (!newSet)
|
||||
{
|
||||
LL_DEBUGS("AOEngine") << "Adding set " << setFolderName << " to AO." << LL_ENDL;
|
||||
newSet = new AOSet(currentCategory->getUUID());
|
||||
newSet->setName(params[0]);
|
||||
newSet->setName(setName);
|
||||
mSets.emplace_back(newSet);
|
||||
|
||||
if (auto currentState = gSavedPerAccountSettings.getLLSD("FSCurrentAOState");
|
||||
currentState.has("CurrentSet") && currentState["CurrentSet"].asString() == setName)
|
||||
{
|
||||
LL_DEBUGS("AOEngine") << "Selecting current set from settings: " << setName << LL_ENDL;
|
||||
mCurrentSet = newSet;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (newSet->getComplete())
|
||||
{
|
||||
LL_DEBUGS("AOEngine") << "Set " << params[0] << " already complete. Skipping." << LL_ENDL;
|
||||
LL_DEBUGS("AOEngine") << "Set " << setName << " already complete. Skipping." << LL_ENDL;
|
||||
continue;
|
||||
}
|
||||
LL_DEBUGS("AOEngine") << "Updating set " << setFolderName << " in AO." << LL_ENDL;
|
||||
|
|
@ -1599,7 +1645,11 @@ void AOEngine::update()
|
|||
else if (params[num] == "**")
|
||||
{
|
||||
mDefaultSet = newSet;
|
||||
mCurrentSet = newSet;
|
||||
if (!mCurrentSet)
|
||||
{
|
||||
LL_DEBUGS("AOEngine") << "No set selected as current yet - setting default set as current: " << setName << LL_ENDL;
|
||||
mCurrentSet = newSet;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1666,12 +1716,12 @@ void AOEngine::update()
|
|||
newSet->setComplete(false);
|
||||
continue;
|
||||
}
|
||||
reloadStateAnimations(state);
|
||||
reloadStateAnimations(newSet, state);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_DEBUGS("AOEngine") << "Set " << params[0] << " is incomplete, fetching descendents" << LL_ENDL;
|
||||
LL_DEBUGS("AOEngine") << "Set " << setName << " is incomplete, fetching descendents" << LL_ENDL;
|
||||
gInventory.fetchDescendentsOf(currentCategory->getUUID());
|
||||
}
|
||||
}
|
||||
|
|
@ -1683,7 +1733,7 @@ void AOEngine::update()
|
|||
|
||||
if (!mCurrentSet && !mSets.empty())
|
||||
{
|
||||
LL_DEBUGS("AOEngine") << "No default set defined, choosing the first in the list." << LL_ENDL;
|
||||
LL_DEBUGS("AOEngine") << "No set currently selected, choosing the first in the list." << LL_ENDL;
|
||||
selectSet(mSets[0]);
|
||||
}
|
||||
|
||||
|
|
@ -1723,16 +1773,15 @@ void AOEngine::reload(bool aFromTimer)
|
|||
|
||||
AOSet* AOEngine::getSetByName(const std::string& name) const
|
||||
{
|
||||
AOSet* found = nullptr;
|
||||
for (auto set : mSets)
|
||||
{
|
||||
if (set->getName().compare(name) == 0)
|
||||
if (set->getName() == name)
|
||||
{
|
||||
found = set;
|
||||
break;
|
||||
return set;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const std::string AOEngine::getCurrentSetName() const
|
||||
|
|
@ -1753,8 +1802,7 @@ void AOEngine::selectSet(AOSet* set)
|
|||
{
|
||||
if (mEnabled && mCurrentSet)
|
||||
{
|
||||
AOSet::AOState* state = mCurrentSet->getStateByRemapID(mLastOverriddenMotion);
|
||||
if (state)
|
||||
if (AOSet::AOState* state = mCurrentSet->getStateByRemapID(mLastOverriddenMotion))
|
||||
{
|
||||
gAgent.sendAnimationRequest(state->mCurrentAnimationID, ANIM_REQUEST_STOP);
|
||||
state->mCurrentAnimationID.setNull();
|
||||
|
|
@ -1773,8 +1821,7 @@ void AOEngine::selectSet(AOSet* set)
|
|||
|
||||
AOSet* AOEngine::selectSetByName(const std::string& name)
|
||||
{
|
||||
AOSet* set = getSetByName(name);
|
||||
if (set)
|
||||
if (AOSet* set = getSetByName(name))
|
||||
{
|
||||
selectSet(set);
|
||||
return set;
|
||||
|
|
@ -2176,8 +2223,7 @@ void AOEngine::onNotecardLoadComplete(const LLUUID& assetUUID, LLAssetType::ETyp
|
|||
char* buffer = new char[notecardSize + 1];
|
||||
buffer[notecardSize] = 0;
|
||||
|
||||
bool ret = file.read((U8*)buffer, notecardSize);
|
||||
if (ret)
|
||||
if (file.read((U8*)buffer, notecardSize))
|
||||
{
|
||||
AOEngine::instance().parseNotecard(buffer);
|
||||
}
|
||||
|
|
@ -2478,6 +2524,11 @@ void AOEngine::onRegionChange()
|
|||
gAgent.sendAnimationRequest(mLastMotion, ANIM_REQUEST_START);
|
||||
}
|
||||
|
||||
void AOEngine::updatePersistedStateAnimations()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------
|
||||
|
||||
AOSitCancelTimer::AOSitCancelTimer()
|
||||
|
|
@ -2487,10 +2538,6 @@ AOSitCancelTimer::AOSitCancelTimer()
|
|||
mEventTimer.stop();
|
||||
}
|
||||
|
||||
AOSitCancelTimer::~AOSitCancelTimer()
|
||||
{
|
||||
}
|
||||
|
||||
void AOSitCancelTimer::oneShot()
|
||||
{
|
||||
mTickCount = 0;
|
||||
|
|
@ -2525,10 +2572,6 @@ AOTimerCollection::AOTimerCollection()
|
|||
updateTimers();
|
||||
}
|
||||
|
||||
AOTimerCollection::~AOTimerCollection()
|
||||
{
|
||||
}
|
||||
|
||||
bool AOTimerCollection::tick()
|
||||
{
|
||||
if (mInventoryTimer)
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ class AOTimerCollection
|
|||
{
|
||||
public:
|
||||
AOTimerCollection();
|
||||
~AOTimerCollection();
|
||||
~AOTimerCollection() = default;
|
||||
|
||||
virtual bool tick();
|
||||
|
||||
|
|
@ -64,7 +64,7 @@ class AOSitCancelTimer
|
|||
{
|
||||
public:
|
||||
AOSitCancelTimer();
|
||||
~AOSitCancelTimer();
|
||||
~AOSitCancelTimer() = default;
|
||||
|
||||
void oneShot();
|
||||
void stop();
|
||||
|
|
@ -101,7 +101,7 @@ class AOEngine
|
|||
void tick();
|
||||
void update();
|
||||
void reload(bool);
|
||||
void reloadStateAnimations(AOSet::AOState* state);
|
||||
void reloadStateAnimations(AOSet* set, AOSet::AOState* state);
|
||||
void clear(bool from_timer);
|
||||
|
||||
const LLUUID& getAOFolder() const;
|
||||
|
|
@ -196,6 +196,8 @@ class AOEngine
|
|||
void* userdata, S32 status, LLExtStat extStatus);
|
||||
void parseNotecard(const char* buffer);
|
||||
|
||||
void updatePersistedStateAnimations();
|
||||
|
||||
updated_signal_t mUpdatedSignal;
|
||||
animation_changed_signal_t mAnimationChangedSignal;
|
||||
|
||||
|
|
|
|||
|
|
@ -171,8 +171,7 @@ const LLUUID& AOSet::getAnimationForState(AOState* state) const
|
|||
{
|
||||
if (state)
|
||||
{
|
||||
auto numOfAnimations = state->mAnimations.size();
|
||||
if (numOfAnimations)
|
||||
if (auto numOfAnimations = state->mAnimations.size(); numOfAnimations > 0)
|
||||
{
|
||||
if (state->mCycle)
|
||||
{
|
||||
|
|
@ -198,7 +197,7 @@ const LLUUID& AOSet::getAnimationForState(AOState* state) const
|
|||
{
|
||||
LL_DEBUGS("AOEngine") << "Asset UUID for chosen animation " << anim.mName << " not yet known, try to find it." << LL_ENDL;
|
||||
|
||||
if(LLViewerInventoryItem* item = gInventory.getItem(anim.mInventoryUUID) ; item)
|
||||
if (LLViewerInventoryItem* item = gInventory.getItem(anim.mInventoryUUID))
|
||||
{
|
||||
LL_DEBUGS("AOEngine") << "Found asset UUID for chosen animation: " << item->getAssetUUID() << " - Updating AOAnimation.mAssetUUID" << LL_ENDL;
|
||||
anim.mAssetUUID = item->getAssetUUID();
|
||||
|
|
@ -256,7 +255,7 @@ const std::string& AOSet::getName() const
|
|||
|
||||
void AOSet::setName(const std::string& name)
|
||||
{
|
||||
mName=name;
|
||||
mName = name;
|
||||
}
|
||||
|
||||
bool AOSet::getSitOverride() const
|
||||
|
|
|
|||
|
|
@ -8177,6 +8177,17 @@
|
|||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>FSPoserShowBoneHighlights</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Whether to highlight a bone with the debug beacon on selection from the UI.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>FSPoserStopPosingWhenClosed</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
|
|
@ -25399,6 +25410,94 @@ Change of this parameter will affect the layout of buttons in notification toast
|
|||
<key>HideFromEditor</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>FSSplashScreenHideTopBar</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Hide the top bar section on the splash screen</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>FSSplashScreenHideBlogs</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Hide the blogs section on the splash screen</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>FSSplashScreenHideDestinations</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Hide the destinations section on the splash screen</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>FSSplashScreenUseGrayMode</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Enable grayscale mode on the splash screen</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>FSSplashScreenUseHighContrast</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Enable high contrast mode on the splash screen</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>FSSplashScreenUseAllCaps</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Enable all caps mode on the splash screen</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>FSSplashScreenUseLargerFonts</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Use larger fonts on the splash screen</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>FSSplashScreenNoTransparency</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Disable transparency effects on the splash screen</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>FSllOwnerSayToScriptDebugWindowRouting</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
|
|
|
|||
|
|
@ -365,6 +365,19 @@
|
|||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>GlobalOnlineStatusCurrentlyReverting</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Flag to prevent infinite loop when reverting the setting on cancel</string>
|
||||
<key>HideFromEditor</key>
|
||||
<integer>1</integer>
|
||||
<key>Persist</key>
|
||||
<integer>0</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>InstantMessageLogPath</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
|
|
@ -1504,5 +1517,16 @@
|
|||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>FSCurrentAOState</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>The currently active AO set and animation per state</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>LLSD</string>
|
||||
<key>Value</key>
|
||||
<map/>
|
||||
</map>
|
||||
</map>
|
||||
</llsd>
|
||||
|
|
|
|||
|
|
@ -128,6 +128,8 @@ LLObjectIMHandler gObjectIMHandler;
|
|||
class FSChatHistoryHeader: public LLPanel
|
||||
{
|
||||
public:
|
||||
typedef boost::function<void (const std::string& speaker_id)> insert_mention_callback_t;
|
||||
|
||||
FSChatHistoryHeader()
|
||||
: LLPanel(),
|
||||
mInfoCtrl(NULL),
|
||||
|
|
@ -150,6 +152,7 @@ public:
|
|||
mTimeBoxTextBox(NULL),
|
||||
mHeaderLayoutStack(NULL),
|
||||
mAvatarNameCacheConnection(),
|
||||
mInsertMentionCallback(NULL),
|
||||
mTime(0)
|
||||
{}
|
||||
|
||||
|
|
@ -180,6 +183,24 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void setInsertMentionCallback(insert_mention_callback_t cb)
|
||||
{
|
||||
mInsertMentionCallback = cb;
|
||||
}
|
||||
|
||||
void copyURLToClipboard()
|
||||
{
|
||||
LLUrlAction::copyURLToClipboard("secondlife:///app/agent/" + mAvatarID.asString() + "/mention");
|
||||
}
|
||||
|
||||
void insertMentionAtCursor()
|
||||
{
|
||||
if (mInsertMentionCallback)
|
||||
{
|
||||
mInsertMentionCallback("secondlife:///app/agent/" + mAvatarID.asString() + "/mention");
|
||||
}
|
||||
}
|
||||
|
||||
bool handleMouseUp(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
return LLPanel::handleMouseUp(x,y,mask);
|
||||
|
|
@ -1070,6 +1091,9 @@ protected:
|
|||
registrar_enable.add("AvatarIcon.Enable", boost::bind(&FSChatHistoryHeader::onAvatarIconContextMenuItemEnabled, this, _2));
|
||||
registrar_enable.add("AvatarIcon.Visible", boost::bind(&FSChatHistoryHeader::onAvatarIconContextMenuItemVisible, this, _2));
|
||||
|
||||
registrar.add("Mention.CopyURI", boost::bind(&FSChatHistoryHeader::copyURLToClipboard, this));
|
||||
registrar.add("Mention.Chat", boost::bind(&FSChatHistoryHeader::insertMentionAtCursor, this));
|
||||
|
||||
menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_avatar_icon.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
|
||||
if (menu)
|
||||
{
|
||||
|
|
@ -1257,6 +1281,8 @@ protected:
|
|||
|
||||
private:
|
||||
boost::signals2::connection mAvatarNameCacheConnection;
|
||||
|
||||
insert_mention_callback_t mInsertMentionCallback;
|
||||
};
|
||||
|
||||
FSChatHistory::FSChatHistory(const FSChatHistory::Params& p)
|
||||
|
|
@ -1359,6 +1385,17 @@ void FSChatHistory::initFromParams(const FSChatHistory::Params& p)
|
|||
setShowContextMenu(true);
|
||||
}
|
||||
|
||||
// virtual
|
||||
void FSChatHistory::insertMentionAtCursor(const std::string& str)
|
||||
{
|
||||
updateChatInputLine();
|
||||
if (mChatInputLine)
|
||||
{
|
||||
mChatInputLine->insertMentionAtCursor(str);
|
||||
mChatInputLine->setFocus(true);
|
||||
}
|
||||
}
|
||||
|
||||
LLView* FSChatHistory::getSeparator()
|
||||
{
|
||||
LLPanel* separator = LLUICtrlFactory::getInstance()->createFromFile<LLPanel>(mMessageSeparatorFilename, NULL, LLPanel::child_registry_t::instance());
|
||||
|
|
@ -1371,6 +1408,7 @@ LLView* FSChatHistory::getHeader(const LLChat& chat,const LLStyle::Params& style
|
|||
if (header)
|
||||
{
|
||||
header->setup(chat, style_params, args);
|
||||
header->setInsertMentionCallback(boost::bind(&FSChatHistory::insertMentionAtCursor, this, _1));
|
||||
}
|
||||
return header;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -110,6 +110,8 @@ class FSChatHistory : public LLTextEditor // <FS:Zi> FIRE-8600: TAB out of cha
|
|||
LLSD getValue() const;
|
||||
void initFromParams(const Params&);
|
||||
|
||||
virtual void insertMentionAtCursor(const std::string& str);
|
||||
|
||||
/**
|
||||
* Appends a widget message.
|
||||
* If last user appended message, concurs with current user,
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ LLContextMenu* FSContactsFriendsMenu::createMenu()
|
|||
registrar.add("Contacts.Friends.CopyLabel", boost::bind(&FSContactsFriendsMenu::copyNameToClipboard, this, id));
|
||||
registrar.add("Contacts.Friends.CopyUrl", boost::bind(&FSContactsFriendsMenu::copySLURLToClipboard, this, id));
|
||||
registrar.add("Contacts.Friends.SelectOption", boost::bind(&FSContactsFriendsMenu::selectOption, this, _2));
|
||||
registrar.add("Mention.CopyURI", boost::bind(&FSContactsFriendsMenu::copyURLToClipboard, this));
|
||||
|
||||
enable_registrar.add("Contacts.Friends.EnableItem", boost::bind(&FSContactsFriendsMenu::enableContextMenuItem, this, _2));
|
||||
enable_registrar.add("Contacts.Friends.EnableZoomIn", boost::bind(&LLAvatarActions::canZoomIn, id));
|
||||
|
|
@ -237,3 +238,8 @@ bool FSContactsFriendsMenu::checkOption(const LLSD& userdata)
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
void FSContactsFriendsMenu::copyURLToClipboard()
|
||||
{
|
||||
LLUrlAction::copyURLToClipboard("secondlife:///app/agent/" + mUUIDs.front().asString() + "/mention");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ private:
|
|||
void copySLURLToClipboard(const LLUUID& id);
|
||||
void selectOption(const LLSD& userdata);
|
||||
bool checkOption(const LLSD& userdata);
|
||||
void copyURLToClipboard();
|
||||
};
|
||||
|
||||
extern FSContactsFriendsMenu gFSContactsFriendsMenu;
|
||||
|
|
|
|||
|
|
@ -271,7 +271,7 @@ void FSFloaterContacts::onOpen(const LLSD& key)
|
|||
LLFloater::onOpen(key);
|
||||
}
|
||||
|
||||
void FSFloaterContacts::openTab(const std::string& name)
|
||||
void FSFloaterContacts::openTab(std::string_view name)
|
||||
{
|
||||
if (name == "friends")
|
||||
{
|
||||
|
|
@ -291,8 +291,7 @@ void FSFloaterContacts::openTab(const std::string& name)
|
|||
return;
|
||||
}
|
||||
|
||||
FSFloaterIMContainer* floater_container = dynamic_cast<FSFloaterIMContainer*>(getHost());
|
||||
if (floater_container)
|
||||
if (auto floater_container = dynamic_cast<FSFloaterIMContainer*>(getHost()))
|
||||
{
|
||||
floater_container->setVisible(true);
|
||||
floater_container->showFloater(this);
|
||||
|
|
@ -391,7 +390,7 @@ void FSFloaterContacts::onAvatarPicked(const uuid_vec_t& ids, const std::vector<
|
|||
{
|
||||
if (!names.empty() && !ids.empty())
|
||||
{
|
||||
LLAvatarActions::requestFriendshipDialog(ids[0], names[0].getCompleteName());
|
||||
LLAvatarActions::requestFriendshipDialog(ids.front(), names.front().getCompleteName());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -405,8 +404,7 @@ void FSFloaterContacts::onAddFriendWizButtonClicked(LLUICtrl* ctrl)
|
|||
picker->setOkBtnEnableCb(boost::bind(&FSFloaterContacts::isItemsFreeOfFriends, this, _1));
|
||||
}
|
||||
|
||||
LLFloater* root_floater = gFloaterView->getParentFloater(this);
|
||||
if (root_floater)
|
||||
if (auto root_floater = gFloaterView->getParentFloater(this))
|
||||
{
|
||||
root_floater->addDependentFloater(picker);
|
||||
}
|
||||
|
|
@ -474,7 +472,7 @@ std::string FSFloaterContacts::getActiveTabName() const
|
|||
return mTabContainer->getCurrentPanel()->getName();
|
||||
}
|
||||
|
||||
LLPanel* FSFloaterContacts::getPanelByName(const std::string& panel_name)
|
||||
LLPanel* FSFloaterContacts::getPanelByName(std::string_view panel_name)
|
||||
{
|
||||
return mTabContainer->getPanelByName(panel_name);
|
||||
}
|
||||
|
|
@ -518,10 +516,9 @@ void FSFloaterContacts::getCurrentItemIDs(uuid_vec_t& selected_uuids) const
|
|||
|
||||
void FSFloaterContacts::getCurrentFriendItemIDs(uuid_vec_t& selected_uuids) const
|
||||
{
|
||||
listitem_vec_t selected = mFriendsList->getAllSelected();
|
||||
for (listitem_vec_t::iterator itr = selected.begin(); itr != selected.end(); ++itr)
|
||||
for (auto list_item : mFriendsList->getAllSelected())
|
||||
{
|
||||
selected_uuids.push_back((*itr)->getUUID());
|
||||
selected_uuids.push_back(list_item->getUUID());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -786,7 +783,7 @@ void FSFloaterContacts::refreshRightsChangeList()
|
|||
bool can_offer_teleport = num_selected >= 1;
|
||||
bool selected_friends_online = true;
|
||||
|
||||
const LLRelationship* friend_status = NULL;
|
||||
const LLRelationship* friend_status = nullptr;
|
||||
for (const auto& id : friends)
|
||||
{
|
||||
friend_status = LLAvatarTracker::instance().getBuddyInfo(id);
|
||||
|
|
@ -1064,8 +1061,8 @@ void FSFloaterContacts::sendRightsGrant(rights_map_t& ids)
|
|||
// setup message header
|
||||
msg->newMessageFast(_PREHASH_GrantUserRights);
|
||||
msg->nextBlockFast(_PREHASH_AgentData);
|
||||
msg->addUUID(_PREHASH_AgentID, gAgent.getID());
|
||||
msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID());
|
||||
msg->addUUID(_PREHASH_AgentID, gAgentID);
|
||||
msg->addUUID(_PREHASH_SessionID, gAgentSessionID);
|
||||
|
||||
for (const auto& [id, rights] : ids)
|
||||
{
|
||||
|
|
@ -1078,7 +1075,7 @@ void FSFloaterContacts::sendRightsGrant(rights_map_t& ids)
|
|||
gAgent.sendReliableMessage();
|
||||
}
|
||||
|
||||
void FSFloaterContacts::childShowTab(const std::string& id, const std::string& tabname)
|
||||
void FSFloaterContacts::childShowTab(std::string_view id, std::string_view tabname)
|
||||
{
|
||||
if (LLTabContainer* child = findChild<LLTabContainer>(id))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -63,8 +63,8 @@ public:
|
|||
static FSFloaterContacts* getInstance();
|
||||
static FSFloaterContacts* findInstance();
|
||||
|
||||
void openTab(const std::string& name);
|
||||
LLPanel* getPanelByName(const std::string& panel_name);
|
||||
void openTab(std::string_view name);
|
||||
LLPanel* getPanelByName(std::string_view panel_name);
|
||||
|
||||
void sortFriendList();
|
||||
void onDisplayNameChanged();
|
||||
|
|
@ -189,7 +189,7 @@ private:
|
|||
std::string mFriendFilterSubString{ LLStringUtil::null };
|
||||
std::string mFriendFilterSubStringOrig{ LLStringUtil::null };
|
||||
|
||||
void childShowTab(const std::string& id, const std::string& tabname);
|
||||
void childShowTab(std::string_view id, std::string_view tabname);
|
||||
|
||||
void updateRlvRestrictions(ERlvBehaviour behavior);
|
||||
boost::signals2::connection mRlvBehaviorCallbackConnection{};
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@
|
|||
#include "llinventoryfunctions.h"
|
||||
#include "lltoolcomp.h"
|
||||
#include "llloadingindicator.h"
|
||||
#include "llmutelist.h"
|
||||
#include "llappviewer.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
|
@ -57,6 +59,7 @@ constexpr std::string_view POSE_PRESETS_HANDS_SUBDIRECTORY = "hand_presets";
|
|||
constexpr char XML_LIST_HEADER_STRING_PREFIX[] = "header_";
|
||||
constexpr char XML_LIST_TITLE_STRING_PREFIX[] = "title_";
|
||||
constexpr char XML_JOINT_TRANSFORM_STRING_PREFIX[] = "joint_transform_";
|
||||
constexpr char XML_JOINT_FRAME_TRANSFORM_PREFIX[] = "joint_frame_";
|
||||
constexpr char XML_JOINT_DELTAROT_STRING_PREFIX[] = "joint_delta_rotate_";
|
||||
constexpr char BVH_JOINT_TRANSFORM_STRING_PREFIX[] = "bvh_joint_transform_";
|
||||
constexpr std::string_view POSER_TRACKPAD_SENSITIVITY_SAVE_KEY = "FSPoserTrackpadSensitivity";
|
||||
|
|
@ -64,6 +67,7 @@ constexpr std::string_view POSER_STOPPOSINGWHENCLOSED_SAVE_KEY = "FSPoserStopPos
|
|||
constexpr std::string_view POSER_SAVEEXTERNALFORMAT_SAVE_KEY = "FSPoserSaveExternalFileAlso";
|
||||
constexpr std::string_view POSER_SAVECONFIRMREQUIRED_SAVE_KEY = "FSPoserOnSaveConfirmOverwrite";
|
||||
constexpr std::string_view POSER_UNLOCKPELVISINBVH_SAVE_KEY = "FSPoserPelvisUnlockedForBvhSave";
|
||||
constexpr std::string_view POSER_SHOWBONEHIGHLIGHTS_SAVE_KEY = "FSManipShowJointMarkers";
|
||||
constexpr char ICON_SAVE_OK[] = "icon_rotation_is_own_work";
|
||||
constexpr char ICON_SAVE_FAILED[] = "icon_save_failed_button";
|
||||
|
||||
|
|
@ -82,6 +86,7 @@ FSFloaterPoser::FSFloaterPoser(const LLSD& key) : LLFloater(key)
|
|||
mCommitCallbackRegistrar.add("Poser.StartStopAnimating", [this](LLUICtrl*, const LLSD&) { onPoseStartStop(); });
|
||||
mCommitCallbackRegistrar.add("Poser.ToggleLoadSavePanel", [this](LLUICtrl*, const LLSD&) { onToggleLoadSavePanel(); });
|
||||
mCommitCallbackRegistrar.add("Poser.ToggleVisualManipulators", [this](LLUICtrl*, const LLSD&) { onToggleVisualManipulators(); });
|
||||
mCommitCallbackRegistrar.add("Poser.ToggleRotationFrame", [this](LLUICtrl* button, const LLSD&) { onToggleRotationFrameButton(button); });
|
||||
|
||||
mCommitCallbackRegistrar.add("Poser.UndoLastRotation", [this](LLUICtrl*, const LLSD&) { onUndoLastChange(); });
|
||||
mCommitCallbackRegistrar.add("Poser.RedoLastRotation", [this](LLUICtrl*, const LLSD&) { onRedoLastChange(); });
|
||||
|
|
@ -205,9 +210,17 @@ bool FSFloaterPoser::postBuild()
|
|||
mRedoChangeBtn = getChild<LLButton>("button_redo_change");
|
||||
mUndoChangeBtn = getChild<LLButton>("undo_change");
|
||||
mSetToTposeButton = getChild<LLButton>("set_t_pose_button");
|
||||
mBtnJointReset = getChild<LLButton>("poser_joint_reset");
|
||||
|
||||
mBtnWorldFrame = getChild<LLButton>("poser_world_frame_toggle");
|
||||
mBtnAvatarFrame = getChild<LLButton>("poser_avatar_frame_toggle");
|
||||
mBtnScreenFrame = getChild<LLButton>("poser_screen_frame_toggle");
|
||||
|
||||
mJointsParentPnl = getChild<LLPanel>("joints_parent_panel");
|
||||
mTrackballPnl = getChild<LLPanel>("trackball_panel");
|
||||
mPositionPnl = getChild<LLPanel>("position_panel");
|
||||
mMoveTabPnl = getChild<LLPanel>("move_tab_panel");
|
||||
mTrackballButtonPnl = getChild<LLPanel>("trackball_button_panel");
|
||||
mPositionRotationPnl = getChild<LLPanel>("positionRotation_panel");
|
||||
mBodyJointsPnl = getChild<LLPanel>("body_joints_panel");
|
||||
mFaceJointsPnl = getChild<LLPanel>("face_joints_panel");
|
||||
|
|
@ -269,6 +282,76 @@ void FSFloaterPoser::onFocusLost()
|
|||
}
|
||||
}
|
||||
|
||||
void FSFloaterPoser::draw()
|
||||
{
|
||||
LLFloater::draw();
|
||||
|
||||
drawOnHoverJointHint();
|
||||
}
|
||||
|
||||
void FSFloaterPoser::markSelectedJointsToHighlight()
|
||||
{
|
||||
bool toolsEnabled = mToggleVisualManipulators->getValue().asBoolean();
|
||||
if (toolsEnabled)
|
||||
return;
|
||||
|
||||
bool showHighlights = gSavedSettings.getBOOL(POSER_SHOWBONEHIGHLIGHTS_SAVE_KEY);
|
||||
if (!showHighlights)
|
||||
return;
|
||||
|
||||
auto selectedJoints = getUiSelectedPoserJoints();
|
||||
if (selectedJoints.empty())
|
||||
return;
|
||||
|
||||
std::string jointName = selectedJoints[0]->jointName();
|
||||
bool isRightLimb = jointName.find("Right") != std::string::npos;
|
||||
bool isLeftLimb = jointName.find("Left") != std::string::npos;
|
||||
|
||||
if (!(isRightLimb || isLeftLimb))
|
||||
return;
|
||||
|
||||
LLVOAvatar* avatar = getUiSelectedAvatar();
|
||||
if (!avatar)
|
||||
return;
|
||||
|
||||
if (!mPoserAnimator.isPosingAvatar(avatar))
|
||||
return;
|
||||
|
||||
mLastSelectedJoint = selectedJoints[0];
|
||||
timeFadeStartedMicrosec = gFrameTime;
|
||||
}
|
||||
|
||||
void FSFloaterPoser::drawOnHoverJointHint()
|
||||
{
|
||||
if (!mLastSelectedJoint)
|
||||
return;
|
||||
|
||||
constexpr U64 GLOW_TIME_US = 300000;
|
||||
U64 fadeTimeUs = gFrameTime - timeFadeStartedMicrosec;
|
||||
if (fadeTimeUs > GLOW_TIME_US)
|
||||
return;
|
||||
|
||||
LLVOAvatar* avatar = getUiSelectedAvatar();
|
||||
if (!avatar)
|
||||
return;
|
||||
|
||||
if (!mPoserAnimator.isPosingAvatar(avatar))
|
||||
return;
|
||||
|
||||
LLJoint* joint = avatar->getJoint(std::string(mLastSelectedJoint->jointName()));
|
||||
if (!joint)
|
||||
return;
|
||||
|
||||
F32 alphaFade = 1.f * (GLOW_TIME_US - fadeTimeUs) / GLOW_TIME_US;
|
||||
static LLUIColor mBeaconColor = LLUIColorTable::getInstance()->getColor("AreaSearchBeaconColor");
|
||||
LLColor4 beaconColour = mBeaconColor.get();
|
||||
beaconColour.setAlpha(alphaFade);
|
||||
LLVector3 joint_world_position = joint->getWorldPosition();
|
||||
|
||||
static LLCachedControl<S32> beacon_line_width(gSavedSettings, "DebugBeaconLineWidth");
|
||||
gObjectList.addDebugBeacon(joint_world_position, "", beaconColour, beaconColour, beacon_line_width);
|
||||
}
|
||||
|
||||
void FSFloaterPoser::enableVisualManipulators()
|
||||
{
|
||||
if (!gAgentAvatarp || gAgentAvatarp.isNull())
|
||||
|
|
@ -359,6 +442,9 @@ void FSFloaterPoser::onPoseFileSelect()
|
|||
if (!avatar)
|
||||
return;
|
||||
|
||||
if (!havePermissionToAnimateAvatar(avatar) && !havePermissionToAnimateOtherAvatar(avatar))
|
||||
return;
|
||||
|
||||
bool enableButtons = mPoserAnimator.isPosingAvatar(avatar);
|
||||
mLoadPosesBtn->setEnabled(enableButtons);
|
||||
mSavePosesBtn->setEnabled(enableButtons);
|
||||
|
|
@ -409,11 +495,14 @@ void FSFloaterPoser::onClickPoseSave()
|
|||
mSavePosesBtn->setImageOverlay(tryGetString(ICON_SAVE_FAILED), mSavePosesBtn->getImageOverlayHAlign());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
LLVOAvatar* avatar = getUiSelectedAvatar();
|
||||
if (!avatar)
|
||||
return;
|
||||
|
||||
if (!havePermissionToAnimateAvatar(avatar) && !havePermissionToAnimateOtherAvatar(avatar))
|
||||
{
|
||||
mSavePosesBtn->setImageOverlay(tryGetString(ICON_SAVE_FAILED), mSavePosesBtn->getImageOverlayHAlign());
|
||||
return;
|
||||
}
|
||||
|
||||
// if prompts are disabled or file doesn't exist, do the save immediately:
|
||||
const bool prompt = gSavedSettings.getBOOL(POSER_SAVECONFIRMREQUIRED_SAVE_KEY);
|
||||
|
||||
|
|
@ -534,7 +623,7 @@ bool FSFloaterPoser::savePoseToXml(LLVOAvatar* avatar, const std::string& poseFi
|
|||
record["startFromTeePose"]["value"] = !savingDiff;
|
||||
|
||||
if (savingDiff)
|
||||
mPoserAnimator.savePosingState(avatar, &record);
|
||||
mPoserAnimator.savePosingState(avatar, false, &record);
|
||||
|
||||
LLVector3 rotation, position, scale, zeroVector;
|
||||
bool baseRotationIsZero;
|
||||
|
|
@ -593,7 +682,7 @@ bool FSFloaterPoser::savePoseToXml(LLVOAvatar* avatar, const std::string& poseFi
|
|||
void FSFloaterPoser::onClickToggleSelectedBoneEnabled()
|
||||
{
|
||||
auto selectedJoints = getUiSelectedPoserJoints();
|
||||
if (selectedJoints.size() < 1)
|
||||
if (selectedJoints.empty())
|
||||
return;
|
||||
|
||||
LLVOAvatar *avatar = getUiSelectedAvatar();
|
||||
|
|
@ -617,7 +706,7 @@ void FSFloaterPoser::onClickToggleSelectedBoneEnabled()
|
|||
void FSFloaterPoser::onClickFlipSelectedJoints()
|
||||
{
|
||||
auto selectedJoints = getUiSelectedPoserJoints();
|
||||
if (selectedJoints.size() < 1)
|
||||
if (selectedJoints.empty())
|
||||
return;
|
||||
|
||||
LLVOAvatar *avatar = getUiSelectedAvatar();
|
||||
|
|
@ -676,7 +765,7 @@ void FSFloaterPoser::onClickFlipPose()
|
|||
void FSFloaterPoser::onClickRecaptureSelectedBones()
|
||||
{
|
||||
auto selectedJoints = getUiSelectedPoserJoints();
|
||||
if (selectedJoints.size() < 1)
|
||||
if (selectedJoints.empty())
|
||||
return;
|
||||
|
||||
LLVOAvatar *avatar = getUiSelectedAvatar();
|
||||
|
|
@ -694,31 +783,40 @@ void FSFloaterPoser::onClickRecaptureSelectedBones()
|
|||
if (currentlyPosing)
|
||||
continue;
|
||||
|
||||
mPoserAnimator.recaptureJoint(avatar, *item, getJointTranslation(item->jointName()), getJointNegation(item->jointName()));
|
||||
mPoserAnimator.recaptureJoint(avatar, *item);
|
||||
}
|
||||
|
||||
setSavePosesButtonText(true);
|
||||
refreshRotationSlidersAndSpinners();
|
||||
refreshPositionSlidersAndSpinners();
|
||||
refreshScaleSlidersAndSpinners();
|
||||
refreshTrackpadCursor();
|
||||
refreshTextHighlightingOnJointScrollLists();
|
||||
enableOrDisableRedoAndUndoButton();
|
||||
}
|
||||
|
||||
void FSFloaterPoser::updatePosedBones(const std::string& jointName)
|
||||
void FSFloaterPoser::updatePosedBones(const std::string& jointName, const LLQuaternion& rotation, const LLVector3& position, const LLVector3& scale)
|
||||
{
|
||||
LLVOAvatar *avatar = getUiSelectedAvatar();
|
||||
LLVOAvatar* avatar = getUiSelectedAvatar();
|
||||
if (!avatar)
|
||||
return;
|
||||
|
||||
if (!mPoserAnimator.isPosingAvatar(avatar))
|
||||
return;
|
||||
|
||||
bool haveImplicitPermission = havePermissionToAnimateAvatar(avatar); // self & control avatars you own
|
||||
bool iCanPoseThem = havePermissionToAnimateOtherAvatar(avatar);
|
||||
if (!haveImplicitPermission && !iCanPoseThem)
|
||||
return;
|
||||
|
||||
const FSPoserAnimator::FSPoserJoint* poserJoint = mPoserAnimator.getPoserJointByName(jointName);
|
||||
if (!poserJoint)
|
||||
return;
|
||||
|
||||
bool savingToExternal = getSavingToBvh();
|
||||
mPoserAnimator.recaptureJointAsDelta(avatar, poserJoint, savingToExternal, getUiSelectedBoneDeflectionStyle());
|
||||
bool savingToExternal = getSavingToBvh();
|
||||
E_PoserReferenceFrame frame = getReferenceFrame();
|
||||
E_BoneDeflectionStyles defl = getUiSelectedBoneDeflectionStyle();
|
||||
mPoserAnimator.updateJointFromManip(avatar, poserJoint, savingToExternal, defl, frame, rotation, position, scale);
|
||||
|
||||
refreshRotationSlidersAndSpinners();
|
||||
refreshPositionSlidersAndSpinners();
|
||||
|
|
@ -728,6 +826,24 @@ void FSFloaterPoser::updatePosedBones(const std::string& jointName)
|
|||
refreshTextHighlightingOnJointScrollLists();
|
||||
}
|
||||
|
||||
LLQuaternion FSFloaterPoser::getManipGimbalRotation(const std::string& jointName)
|
||||
{
|
||||
LLVOAvatar* avatar = getUiSelectedAvatar();
|
||||
if (!avatar)
|
||||
return LLQuaternion();
|
||||
|
||||
if (!mPoserAnimator.isPosingAvatar(avatar))
|
||||
return LLQuaternion();
|
||||
|
||||
const FSPoserAnimator::FSPoserJoint* poserJoint = mPoserAnimator.getPoserJointByName(jointName);
|
||||
if (!poserJoint)
|
||||
return LLQuaternion();
|
||||
|
||||
E_PoserReferenceFrame frame = getReferenceFrame();
|
||||
|
||||
return mPoserAnimator.getManipGimbalRotation(avatar, poserJoint, frame);
|
||||
}
|
||||
|
||||
void FSFloaterPoser::onClickBrowsePoseCache()
|
||||
{
|
||||
createUserPoseDirectoryIfNeeded();
|
||||
|
|
@ -930,6 +1046,9 @@ void FSFloaterPoser::timedReload()
|
|||
if (!avatar)
|
||||
return;
|
||||
|
||||
if (!havePermissionToAnimateAvatar(avatar) && !havePermissionToAnimateOtherAvatar(avatar))
|
||||
return;
|
||||
|
||||
if (loadPoseFromXml(avatar, mLoadPoseTimer->getPosePath(), mLoadPoseTimer->getLoadMethod()))
|
||||
{
|
||||
mLoadPoseTimer->completeLoading();
|
||||
|
|
@ -1024,6 +1143,8 @@ void FSFloaterPoser::onClickLoadHandPose(bool isRightHand)
|
|||
LLVOAvatar* avatar = getUiSelectedAvatar();
|
||||
if (!avatar)
|
||||
return;
|
||||
if (!havePermissionToAnimateAvatar(avatar) && !havePermissionToAnimateOtherAvatar(avatar))
|
||||
return;
|
||||
if (!mPoserAnimator.isPosingAvatar(avatar))
|
||||
return;
|
||||
|
||||
|
|
@ -1233,8 +1354,8 @@ bool FSFloaterPoser::loadPoseFromXml(LLVOAvatar* avatar, const std::string& pose
|
|||
mPoserAnimator.setRotationIsMirrored(avatar, *poserJoint, mirroredJoint);
|
||||
}
|
||||
|
||||
if (version > 6 && !startFromZeroRot)
|
||||
loadSuccess = mPoserAnimator.loadPosingState(avatar, pose);
|
||||
if (version > 6 && !startFromZeroRot && !loadSelective)
|
||||
loadSuccess = mPoserAnimator.loadPosingState(avatar, true, pose);
|
||||
}
|
||||
}
|
||||
catch ( const std::exception & e )
|
||||
|
|
@ -1310,7 +1431,7 @@ void FSFloaterPoser::onPoseStartStop()
|
|||
onAvatarSelect();
|
||||
}
|
||||
|
||||
bool FSFloaterPoser::couldAnimateAvatar(LLVOAvatar *avatar) const
|
||||
bool FSFloaterPoser::couldAnimateAvatar(LLVOAvatar* avatar) const
|
||||
{
|
||||
if (!avatar || avatar->isDead())
|
||||
return false;
|
||||
|
|
@ -1320,14 +1441,31 @@ bool FSFloaterPoser::couldAnimateAvatar(LLVOAvatar *avatar) const
|
|||
return true;
|
||||
}
|
||||
|
||||
bool FSFloaterPoser::havePermissionToAnimateAvatar(LLVOAvatar *avatar) const
|
||||
bool FSFloaterPoser::havePermissionToAnimateAvatar(LLVOAvatar* avatar) const
|
||||
{
|
||||
if (!avatar || avatar->isDead())
|
||||
return false;
|
||||
if (avatar->isSelf())
|
||||
return true;
|
||||
|
||||
if (avatar->isControlAvatar())
|
||||
return true;
|
||||
{
|
||||
LLControlAvatar* control_av = dynamic_cast<LLControlAvatar*>(avatar);
|
||||
const LLVOVolume* rootVolume = control_av->mRootVolp;
|
||||
const LLViewerObject* rootEditObject = (rootVolume) ? rootVolume->getRootEdit() : NULL;
|
||||
if (!rootEditObject)
|
||||
return false;
|
||||
|
||||
return rootEditObject->permYouOwner();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FSFloaterPoser::havePermissionToAnimateOtherAvatar(LLVOAvatar* avatar) const
|
||||
{
|
||||
if (!avatar || avatar->isDead())
|
||||
return false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1342,6 +1480,12 @@ void FSFloaterPoser::poseControlsEnable(bool enable)
|
|||
mLoadPosesBtn->setEnabled(enable);
|
||||
mSavePosesBtn->setEnabled(enable);
|
||||
mPoseSaveNameEditor->setEnabled(enable);
|
||||
mBtnJointReset->setEnabled(enable);
|
||||
mRedoChangeBtn->setEnabled(enable);
|
||||
mUndoChangeBtn->setEnabled(enable);
|
||||
mPositionPnl->setEnabled(enable);
|
||||
mMoveTabPnl->setEnabled(enable);
|
||||
mTrackballButtonPnl->setEnabled(enable);
|
||||
}
|
||||
|
||||
void FSFloaterPoser::refreshJointScrollListMembers()
|
||||
|
|
@ -1422,13 +1566,13 @@ void FSFloaterPoser::addHeaderRowToScrollList(const std::string& jointName, LLSc
|
|||
return;
|
||||
|
||||
LLScrollListItem *hdrRow = bodyJointsScrollList->addElement(headerRow);
|
||||
hdrRow->setEnabled(FALSE);
|
||||
hdrRow->setEnabled(false);
|
||||
}
|
||||
|
||||
LLSD FSFloaterPoser::createRowForJoint(const std::string& jointName, bool isHeaderRow)
|
||||
{
|
||||
if (jointName.empty())
|
||||
return NULL;
|
||||
return {};
|
||||
|
||||
std::string headerValue = "";
|
||||
if (isHeaderRow)
|
||||
|
|
@ -1439,7 +1583,7 @@ LLSD FSFloaterPoser::createRowForJoint(const std::string& jointName, bool isHead
|
|||
if (hasString(parameterName))
|
||||
jointValue = getString(parameterName);
|
||||
else
|
||||
return NULL;
|
||||
return {};
|
||||
|
||||
LLSD row;
|
||||
row["columns"][COL_ICON]["column"] = "icon";
|
||||
|
|
@ -1500,6 +1644,22 @@ void FSFloaterPoser::setRotationChangeButtons(bool togglingMirror, bool toggling
|
|||
refreshTrackpadCursor();
|
||||
}
|
||||
|
||||
void FSFloaterPoser::onToggleRotationFrameButton(const LLUICtrl* toggleButton)
|
||||
{
|
||||
if (!toggleButton)
|
||||
return;
|
||||
|
||||
if (bool buttonDown = toggleButton->getValue().asBoolean())
|
||||
{
|
||||
mBtnAvatarFrame->setValue(toggleButton == mBtnAvatarFrame);
|
||||
mBtnScreenFrame->setValue(toggleButton == mBtnScreenFrame);
|
||||
mBtnWorldFrame->setValue(toggleButton == mBtnWorldFrame);
|
||||
}
|
||||
|
||||
FSToolCompPose::getInstance()->setReferenceFrame(getReferenceFrame());
|
||||
refreshRotationSlidersAndSpinners();
|
||||
}
|
||||
|
||||
void FSFloaterPoser::onUndoLastChange()
|
||||
{
|
||||
LLVOAvatar* avatar = getUiSelectedAvatar();
|
||||
|
|
@ -1510,7 +1670,7 @@ void FSFloaterPoser::onUndoLastChange()
|
|||
return;
|
||||
|
||||
auto selectedJoints = getUiSelectedPoserJoints();
|
||||
if (selectedJoints.size() < 1)
|
||||
if (selectedJoints.empty())
|
||||
return;
|
||||
|
||||
for (auto item : selectedJoints)
|
||||
|
|
@ -1541,7 +1701,7 @@ void FSFloaterPoser::onSetAvatarToTpose()
|
|||
enableOrDisableRedoAndUndoButton();
|
||||
}
|
||||
|
||||
void FSFloaterPoser::onResetJoint(const LLSD data)
|
||||
void FSFloaterPoser::onResetJoint(const LLSD& data)
|
||||
{
|
||||
int resetType = data.asInteger();
|
||||
|
||||
|
|
@ -1553,7 +1713,7 @@ void FSFloaterPoser::onResetJoint(const LLSD data)
|
|||
return;
|
||||
|
||||
auto selectedJoints = getUiSelectedPoserJoints();
|
||||
if (selectedJoints.size() < 1)
|
||||
if (selectedJoints.empty())
|
||||
return;
|
||||
|
||||
for (auto item : selectedJoints)
|
||||
|
|
@ -1583,7 +1743,7 @@ void FSFloaterPoser::onRedoLastChange()
|
|||
return;
|
||||
|
||||
auto selectedJoints = getUiSelectedPoserJoints();
|
||||
if (selectedJoints.size() < 1)
|
||||
if (selectedJoints.empty())
|
||||
return;
|
||||
|
||||
for (auto item : selectedJoints)
|
||||
|
|
@ -1615,7 +1775,7 @@ void FSFloaterPoser::enableOrDisableRedoAndUndoButton()
|
|||
return;
|
||||
|
||||
auto selectedJoints = getUiSelectedPoserJoints();
|
||||
if (selectedJoints.size() < 1)
|
||||
if (selectedJoints.empty())
|
||||
return;
|
||||
|
||||
bool shouldEnableRedoButton = false;
|
||||
|
|
@ -1706,7 +1866,7 @@ void FSFloaterPoser::selectJointByName(const std::string& jointName)
|
|||
LL_WARNS() << "Joint not found: " << jointName << LL_ENDL;
|
||||
}
|
||||
|
||||
LLScrollListCtrl* FSFloaterPoser::getScrollListForTab(LLPanel * tabPanel) const
|
||||
LLScrollListCtrl* FSFloaterPoser::getScrollListForTab(LLPanel* tabPanel) const
|
||||
{
|
||||
if (tabPanel == mPositionRotationPnl)
|
||||
{
|
||||
|
|
@ -1733,7 +1893,6 @@ LLScrollListCtrl* FSFloaterPoser::getScrollListForTab(LLPanel * tabPanel) const
|
|||
return mCollisionVolumesScrollList;
|
||||
}
|
||||
|
||||
LL_WARNS() << "Unknown tab panel: " << tabPanel << LL_ENDL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -1769,8 +1928,7 @@ std::vector<FSPoserAnimator::FSPoserJoint*> FSFloaterPoser::getUiSelectedPoserJo
|
|||
|
||||
for (auto item : scrollList->getAllSelected())
|
||||
{
|
||||
auto* userData = static_cast<FSPoserAnimator::FSPoserJoint*>(item->getUserdata());
|
||||
if (userData)
|
||||
if (auto* userData = static_cast<FSPoserAnimator::FSPoserJoint*>(item->getUserdata()))
|
||||
{
|
||||
joints.push_back(userData);
|
||||
}
|
||||
|
|
@ -1781,13 +1939,16 @@ std::vector<FSPoserAnimator::FSPoserJoint*> FSFloaterPoser::getUiSelectedPoserJo
|
|||
return joints;
|
||||
}
|
||||
|
||||
void FSFloaterPoser::updateManipWithFirstSelectedJoint(std::vector<FSPoserAnimator::FSPoserJoint*> joints) const
|
||||
void FSFloaterPoser::updateManipWithFirstSelectedJoint(const std::vector<FSPoserAnimator::FSPoserJoint*>& joints) const
|
||||
{
|
||||
auto avatarp = getUiSelectedAvatar();
|
||||
if (!avatarp)
|
||||
return;
|
||||
|
||||
if (joints.size() >= 1)
|
||||
bool haveImplicitPermission = havePermissionToAnimateAvatar(avatarp);
|
||||
bool iCanPoseThem = havePermissionToAnimateOtherAvatar(avatarp);
|
||||
|
||||
if ((joints.size() >= 1) && (haveImplicitPermission || iCanPoseThem))
|
||||
FSToolCompPose::getInstance()->setJoint(avatarp->getJoint(joints[0]->jointName()));
|
||||
else
|
||||
FSToolCompPose::getInstance()->setJoint(nullptr);
|
||||
|
|
@ -2073,8 +2234,9 @@ void FSFloaterPoser::setSelectedJointsPosition(F32 x, F32 y, F32 z)
|
|||
if (!mPoserAnimator.isPosingAvatar(avatar))
|
||||
return;
|
||||
|
||||
LLVector3 vec3 = LLVector3(x, y, z);
|
||||
E_BoneDeflectionStyles defl = getUiSelectedBoneDeflectionStyle();
|
||||
LLVector3 vec3 = LLVector3(x, y, z);
|
||||
E_BoneDeflectionStyles defl = getUiSelectedBoneDeflectionStyle();
|
||||
E_PoserReferenceFrame frame = getReferenceFrame();
|
||||
|
||||
for (auto item : getUiSelectedPoserJoints())
|
||||
{
|
||||
|
|
@ -2082,7 +2244,7 @@ void FSFloaterPoser::setSelectedJointsPosition(F32 x, F32 y, F32 z)
|
|||
if (!currentlyPosingJoint)
|
||||
continue;
|
||||
|
||||
mPoserAnimator.setJointPosition(avatar, item, vec3, defl);
|
||||
mPoserAnimator.setJointPosition(avatar, item, vec3, frame, defl);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2097,7 +2259,8 @@ void FSFloaterPoser::setSelectedJointsRotation(const LLVector3& absoluteRot, con
|
|||
|
||||
auto selectedJoints = getUiSelectedPoserJoints();
|
||||
bool savingToExternal = getSavingToBvh();
|
||||
E_BoneDeflectionStyles defl = getUiSelectedBoneDeflectionStyle();
|
||||
E_BoneDeflectionStyles deflection = getUiSelectedBoneDeflectionStyle();
|
||||
E_PoserReferenceFrame frame = getReferenceFrame();
|
||||
|
||||
for (auto item : selectedJoints)
|
||||
{
|
||||
|
|
@ -2111,14 +2274,17 @@ void FSFloaterPoser::setSelectedJointsRotation(const LLVector3& absoluteRot, con
|
|||
bool oppositeJointAlsoSelectedOnUi =
|
||||
std::find(selectedJoints.begin(), selectedJoints.end(), oppositeJoint) != selectedJoints.end();
|
||||
|
||||
bool deflectionDoesOppositeLimbs = !(defl == NONE || defl == DELTAMODE);
|
||||
bool deflectionDoesOppositeLimbs = !(deflection == NONE || deflection == DELTAMODE);
|
||||
if (oppositeJointAlsoSelectedOnUi && deflectionDoesOppositeLimbs && item->dontFlipOnMirror())
|
||||
continue;
|
||||
}
|
||||
|
||||
mPoserAnimator.setJointRotation(avatar, item, absoluteRot, deltaRot, defl,
|
||||
getJointTranslation(item->jointName()), getJointNegation(item->jointName()), savingToExternal,
|
||||
getUiSelectedBoneRotationStyle(item->jointName()));
|
||||
S32 jointNegation = getJointNegation(frame, item->jointName());
|
||||
E_BoneAxisTranslation translation = getJointTranslation(frame, item->jointName());
|
||||
E_RotationStyle style = getUiSelectedBoneRotationStyle(item->jointName());
|
||||
|
||||
mPoserAnimator.setJointRotation(avatar, item, absoluteRot, deltaRot, deflection, frame, translation, jointNegation,
|
||||
savingToExternal, style);
|
||||
}
|
||||
|
||||
if (savingToExternal)
|
||||
|
|
@ -2134,8 +2300,9 @@ void FSFloaterPoser::setSelectedJointsScale(F32 x, F32 y, F32 z)
|
|||
if (!mPoserAnimator.isPosingAvatar(avatar))
|
||||
return;
|
||||
|
||||
LLVector3 vec3 = LLVector3(x, y, z);
|
||||
E_BoneDeflectionStyles defl = getUiSelectedBoneDeflectionStyle();
|
||||
LLVector3 vec3 = LLVector3(x, y, z);
|
||||
E_BoneDeflectionStyles defl = getUiSelectedBoneDeflectionStyle();
|
||||
E_PoserReferenceFrame frame = getReferenceFrame();
|
||||
|
||||
for (auto item : getUiSelectedPoserJoints())
|
||||
{
|
||||
|
|
@ -2143,7 +2310,7 @@ void FSFloaterPoser::setSelectedJointsScale(F32 x, F32 y, F32 z)
|
|||
if (!currentlyPosingJoint)
|
||||
continue;
|
||||
|
||||
mPoserAnimator.setJointScale(avatar, item, vec3, defl);
|
||||
mPoserAnimator.setJointScale(avatar, item, vec3, frame, defl);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2151,7 +2318,7 @@ LLVector3 FSFloaterPoser::getRotationOfFirstSelectedJoint() const
|
|||
{
|
||||
LLVector3 rotation;
|
||||
auto selectedJoints = getUiSelectedPoserJoints();
|
||||
if (selectedJoints.size() < 1)
|
||||
if (selectedJoints.empty())
|
||||
return rotation;
|
||||
|
||||
LLVOAvatar *avatar = getUiSelectedAvatar();
|
||||
|
|
@ -2161,8 +2328,10 @@ LLVector3 FSFloaterPoser::getRotationOfFirstSelectedJoint() const
|
|||
if (!mPoserAnimator.isPosingAvatar(avatar))
|
||||
return rotation;
|
||||
|
||||
rotation = mPoserAnimator.getJointRotation(avatar, *selectedJoints.front(), getJointTranslation(selectedJoints.front()->jointName()),
|
||||
getJointNegation(selectedJoints.front()->jointName()));
|
||||
E_PoserReferenceFrame frame = getReferenceFrame();
|
||||
|
||||
rotation = mPoserAnimator.getJointRotation(avatar, *selectedJoints.front(), getJointTranslation(frame, selectedJoints.front()->jointName()),
|
||||
getJointNegation(frame, selectedJoints.front()->jointName()));
|
||||
|
||||
return rotation;
|
||||
}
|
||||
|
|
@ -2171,7 +2340,7 @@ LLVector3 FSFloaterPoser::getPositionOfFirstSelectedJoint() const
|
|||
{
|
||||
LLVector3 position;
|
||||
auto selectedJoints = getUiSelectedPoserJoints();
|
||||
if (selectedJoints.size() < 1)
|
||||
if (selectedJoints.empty())
|
||||
return position;
|
||||
|
||||
LLVOAvatar *avatar = getUiSelectedAvatar();
|
||||
|
|
@ -2189,7 +2358,7 @@ LLVector3 FSFloaterPoser::getScaleOfFirstSelectedJoint() const
|
|||
{
|
||||
LLVector3 scale;
|
||||
auto selectedJoints = getUiSelectedPoserJoints();
|
||||
if (selectedJoints.size() < 1)
|
||||
if (selectedJoints.empty())
|
||||
return scale;
|
||||
|
||||
LLVOAvatar *avatar = getUiSelectedAvatar();
|
||||
|
|
@ -2210,18 +2379,25 @@ void FSFloaterPoser::onJointTabSelect()
|
|||
refreshTrackpadCursor();
|
||||
enableOrDisableRedoAndUndoButton();
|
||||
refreshScaleSlidersAndSpinners();
|
||||
markSelectedJointsToHighlight();
|
||||
}
|
||||
|
||||
E_BoneAxisTranslation FSFloaterPoser::getJointTranslation(const std::string& jointName) const
|
||||
E_BoneAxisTranslation FSFloaterPoser::getJointTranslation(E_PoserReferenceFrame frame, const std::string& jointName) const
|
||||
{
|
||||
if (jointName.empty())
|
||||
return SWAP_NOTHING;
|
||||
|
||||
bool hasTransformParameter = hasString(XML_JOINT_TRANSFORM_STRING_PREFIX + jointName);
|
||||
std::string paramName;
|
||||
if (frame == POSER_FRAME_BONE)
|
||||
paramName = XML_JOINT_TRANSFORM_STRING_PREFIX + jointName;
|
||||
else
|
||||
paramName = XML_JOINT_FRAME_TRANSFORM_PREFIX + jointName;
|
||||
|
||||
bool hasTransformParameter = hasString(paramName);
|
||||
if (!hasTransformParameter)
|
||||
return SWAP_NOTHING;
|
||||
|
||||
std::string paramValue = getString(XML_JOINT_TRANSFORM_STRING_PREFIX + jointName);
|
||||
std::string paramValue = getString(paramName);
|
||||
|
||||
if (strstr(paramValue.c_str(), "SWAP_YAW_AND_ROLL"))
|
||||
return SWAP_YAW_AND_ROLL;
|
||||
|
|
@ -2237,18 +2413,24 @@ E_BoneAxisTranslation FSFloaterPoser::getJointTranslation(const std::string& joi
|
|||
return SWAP_NOTHING;
|
||||
}
|
||||
|
||||
S32 FSFloaterPoser::getJointNegation(const std::string& jointName) const
|
||||
S32 FSFloaterPoser::getJointNegation(E_PoserReferenceFrame frame, const std::string& jointName) const
|
||||
{
|
||||
S32 result = NEGATE_NOTHING;
|
||||
|
||||
if (jointName.empty())
|
||||
return result;
|
||||
|
||||
bool hasTransformParameter = hasString(XML_JOINT_TRANSFORM_STRING_PREFIX + jointName);
|
||||
if (!hasTransformParameter)
|
||||
std::string paramName;
|
||||
if (frame == POSER_FRAME_BONE)
|
||||
paramName = XML_JOINT_TRANSFORM_STRING_PREFIX + jointName;
|
||||
else
|
||||
paramName = XML_JOINT_FRAME_TRANSFORM_PREFIX + jointName;
|
||||
|
||||
bool hasNegationParameter = hasString(paramName);
|
||||
if (!hasNegationParameter)
|
||||
return result;
|
||||
|
||||
std::string paramValue = getString(XML_JOINT_TRANSFORM_STRING_PREFIX + jointName);
|
||||
std::string paramValue = getString(paramName);
|
||||
|
||||
if (strstr(paramValue.c_str(), "NEGATE_YAW"))
|
||||
result |= NEGATE_YAW;
|
||||
|
|
@ -2262,6 +2444,23 @@ S32 FSFloaterPoser::getJointNegation(const std::string& jointName) const
|
|||
return result;
|
||||
}
|
||||
|
||||
E_PoserReferenceFrame FSFloaterPoser::getReferenceFrame() const
|
||||
{
|
||||
bool toggleButtonValue = mBtnScreenFrame->getValue().asBoolean();
|
||||
if (toggleButtonValue)
|
||||
return POSER_FRAME_CAMERA;
|
||||
|
||||
toggleButtonValue = mBtnAvatarFrame->getValue().asBoolean();
|
||||
if (toggleButtonValue)
|
||||
return POSER_FRAME_AVATAR;
|
||||
|
||||
toggleButtonValue = mBtnWorldFrame->getValue().asBoolean();
|
||||
if (toggleButtonValue)
|
||||
return POSER_FRAME_WORLD;
|
||||
|
||||
return POSER_FRAME_BONE;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An event handler for selecting an avatar or animesh on the POSES_AVATAR_SCROLL_LIST_NAME.
|
||||
/// In general this will refresh the views for joints or their proxies, and (dis/en)able elements of the view.
|
||||
|
|
@ -2269,16 +2468,26 @@ S32 FSFloaterPoser::getJointNegation(const std::string& jointName) const
|
|||
void FSFloaterPoser::onAvatarSelect()
|
||||
{
|
||||
LLVOAvatar* avatar = getUiSelectedAvatar();
|
||||
if(avatar)
|
||||
{
|
||||
if (!avatar)
|
||||
return;
|
||||
|
||||
bool isSelf = avatar->isSelf();
|
||||
bool haveImplicitPermission = havePermissionToAnimateAvatar(avatar); // self & control avatars you own
|
||||
bool haveExplicitPermission = havePermissionToAnimateOtherAvatar(avatar); // as permissions allow
|
||||
|
||||
if (haveImplicitPermission || haveExplicitPermission)
|
||||
FSToolCompPose::getInstance()->setAvatar(avatar);
|
||||
}
|
||||
mStartStopPosingBtn->setEnabled(couldAnimateAvatar(avatar));
|
||||
else
|
||||
FSToolCompPose::getInstance()->setAvatar(nullptr);
|
||||
|
||||
bool arePosingSelected = mPoserAnimator.isPosingAvatar(avatar);
|
||||
|
||||
mStartStopPosingBtn->setEnabled(haveImplicitPermission);
|
||||
mStartStopPosingBtn->setValue(arePosingSelected);
|
||||
mSetToTposeButton->setEnabled(arePosingSelected);
|
||||
poseControlsEnable(arePosingSelected);
|
||||
|
||||
mSetToTposeButton->setEnabled(haveImplicitPermission && arePosingSelected);
|
||||
poseControlsEnable(arePosingSelected && haveImplicitPermission);
|
||||
|
||||
refreshTextHighlightingOnAvatarScrollList();
|
||||
refreshTextHighlightingOnJointScrollLists();
|
||||
onJointTabSelect();
|
||||
|
|
@ -2292,7 +2501,16 @@ uuid_vec_t FSFloaterPoser::getNearbyAvatarsAndAnimeshes() const
|
|||
for (LLCharacter* character : LLCharacter::sInstances)
|
||||
{
|
||||
LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(character);
|
||||
if (!havePermissionToAnimateAvatar(avatar))
|
||||
if (!avatarIsNearbyMe(avatar))
|
||||
continue;
|
||||
|
||||
bool isMuted = LLMuteList::getInstance()->isMuted(avatar->getID());
|
||||
if (isMuted)
|
||||
continue;
|
||||
|
||||
bool isSelfOrCtrl = avatar->isControlAvatar() || avatar->isSelf();
|
||||
|
||||
if (!isSelfOrCtrl)
|
||||
continue;
|
||||
|
||||
avatar_ids.emplace_back(character->getID());
|
||||
|
|
@ -2301,6 +2519,16 @@ uuid_vec_t FSFloaterPoser::getNearbyAvatarsAndAnimeshes() const
|
|||
return avatar_ids;
|
||||
}
|
||||
|
||||
bool FSFloaterPoser::avatarIsNearbyMe(LLCharacter* character) const
|
||||
{
|
||||
if (!gAgentAvatarp || gAgentAvatarp.isNull() || !character)
|
||||
return false;
|
||||
|
||||
LLVector3 separationVector = character->getCharacterPosition() - gAgentAvatarp->getCharacterPosition();
|
||||
|
||||
return separationVector.magVec() < 50.f;
|
||||
}
|
||||
|
||||
uuid_vec_t FSFloaterPoser::getCurrentlyListedAvatarsAndAnimeshes() const
|
||||
{
|
||||
uuid_vec_t avatar_ids;
|
||||
|
|
@ -2351,22 +2579,18 @@ void FSFloaterPoser::onAvatarsRefresh()
|
|||
mAvatarSelectionScrollList->deleteSingleItem(indexToRemove);
|
||||
}
|
||||
|
||||
std::string iconCatagoryName = "Inv_BodyShape";
|
||||
if (hasString("icon_category"))
|
||||
iconCatagoryName = getString("icon_category");
|
||||
|
||||
std::string iconObjectName = "Inv_Object";
|
||||
if (hasString("icon_object"))
|
||||
iconObjectName = getString("icon_object");
|
||||
|
||||
// Add non-Animesh avatars
|
||||
for (LLCharacter *character : LLCharacter::sInstances)
|
||||
for (LLCharacter* character : LLCharacter::sInstances)
|
||||
{
|
||||
LLUUID uuid = character->getID();
|
||||
if (std::find(avatarsToAddToList.begin(), avatarsToAddToList.end(), uuid) == avatarsToAddToList.end())
|
||||
continue;
|
||||
|
||||
LLVOAvatar *avatar = dynamic_cast<LLVOAvatar *>(character);
|
||||
LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(character);
|
||||
if (!couldAnimateAvatar(avatar))
|
||||
continue;
|
||||
|
||||
|
|
@ -2377,10 +2601,16 @@ void FSFloaterPoser::onAvatarsRefresh()
|
|||
if (!LLAvatarNameCache::get(uuid, &av_name))
|
||||
continue;
|
||||
|
||||
if (LLMuteList::getInstance()->isMuted(uuid))
|
||||
continue;
|
||||
|
||||
if (!avatar->isSelf())
|
||||
continue;
|
||||
|
||||
LLSD row;
|
||||
row["columns"][COL_ICON]["column"] = "icon";
|
||||
row["columns"][COL_ICON]["type"] = "icon";
|
||||
row["columns"][COL_ICON]["value"] = iconCatagoryName;
|
||||
row["columns"][COL_ICON]["value"] = getIconNameForAvatar(avatar);
|
||||
row["columns"][COL_NAME]["column"] = "name";
|
||||
row["columns"][COL_NAME]["value"] = av_name.getDisplayName();
|
||||
row["columns"][COL_UUID]["column"] = "uuid";
|
||||
|
|
@ -2397,7 +2627,7 @@ void FSFloaterPoser::onAvatarsRefresh()
|
|||
if (std::find(avatarsToAddToList.begin(), avatarsToAddToList.end(), uuid) == avatarsToAddToList.end())
|
||||
continue;
|
||||
|
||||
LLControlAvatar *avatar = dynamic_cast<LLControlAvatar *>(character);
|
||||
LLControlAvatar* avatar = dynamic_cast<LLControlAvatar* >(character);
|
||||
if (!couldAnimateAvatar(avatar))
|
||||
continue;
|
||||
|
||||
|
|
@ -2423,18 +2653,33 @@ void FSFloaterPoser::onAvatarsRefresh()
|
|||
refreshTextHighlightingOnAvatarScrollList();
|
||||
}
|
||||
|
||||
std::string FSFloaterPoser::getIconNameForAvatar(LLVOAvatar* avatar)
|
||||
{
|
||||
std::string iconName = "Inv_BodyShape";
|
||||
if (hasString("icon_category"))
|
||||
iconName = getString("icon_category");
|
||||
|
||||
if (!avatar)
|
||||
return iconName;
|
||||
|
||||
if (avatar->isControlAvatar() && hasString("icon_object"))
|
||||
return getString("icon_object");
|
||||
|
||||
return iconName;
|
||||
}
|
||||
|
||||
std::string FSFloaterPoser::getControlAvatarName(const LLControlAvatar* avatar)
|
||||
{
|
||||
if (!avatar)
|
||||
return "";
|
||||
return {};
|
||||
|
||||
const LLVOVolume* rootVolume = avatar->mRootVolp;
|
||||
const LLViewerObject* rootEditObject = (rootVolume) ? rootVolume->getRootEdit() : NULL;
|
||||
const LLVOVolume* rootVolume = avatar->mRootVolp;
|
||||
const LLViewerObject* rootEditObject = rootVolume ? rootVolume->getRootEdit() : nullptr;
|
||||
if (!rootEditObject)
|
||||
return "";
|
||||
return {};
|
||||
|
||||
const LLViewerInventoryItem* attachedItem =
|
||||
(rootEditObject->isAttachment()) ? gInventory.getItem(rootEditObject->getAttachmentItemID()) : NULL;
|
||||
(rootEditObject->isAttachment()) ? gInventory.getItem(rootEditObject->getAttachmentItemID()) : nullptr;
|
||||
|
||||
if (attachedItem)
|
||||
return attachedItem->getName();
|
||||
|
|
@ -2442,7 +2687,7 @@ std::string FSFloaterPoser::getControlAvatarName(const LLControlAvatar* avatar)
|
|||
if (rootEditObject->permYouOwner())
|
||||
return avatar->getFullname();
|
||||
|
||||
return "";
|
||||
return {};
|
||||
}
|
||||
|
||||
void FSFloaterPoser::refreshTextHighlightingOnAvatarScrollList()
|
||||
|
|
@ -2456,10 +2701,12 @@ void FSFloaterPoser::refreshTextHighlightingOnAvatarScrollList()
|
|||
LLUUID selectedAvatarId = cell->getValue().asUUID();
|
||||
LLVOAvatar* listAvatar = getAvatarByUuid(selectedAvatarId);
|
||||
|
||||
((LLScrollListText*)listItem->getColumn(COL_ICON))->setValue(getIconNameForAvatar(listAvatar));
|
||||
|
||||
if (mPoserAnimator.isPosingAvatar(listAvatar))
|
||||
((LLScrollListText *) listItem->getColumn(COL_NAME))->setFontStyle(LLFontGL::BOLD);
|
||||
((LLScrollListText*)listItem->getColumn(COL_NAME))->setFontStyle(LLFontGL::BOLD);
|
||||
else
|
||||
((LLScrollListText *) listItem->getColumn(COL_NAME))->setFontStyle(LLFontGL::NORMAL);
|
||||
((LLScrollListText*)listItem->getColumn(COL_NAME))->setFontStyle(LLFontGL::NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2487,34 +2734,34 @@ void FSFloaterPoser::addBoldToScrollList(LLScrollListCtrl* list, LLVOAvatar* ava
|
|||
if (!list)
|
||||
return;
|
||||
|
||||
std::string iconValue = "";
|
||||
std::string iconValue = "";
|
||||
bool considerExternalFormatSaving = getSavingToBvh();
|
||||
|
||||
for (auto listItem : list->getAllData())
|
||||
{
|
||||
FSPoserAnimator::FSPoserJoint *poserJoint = static_cast<FSPoserAnimator::FSPoserJoint *>(listItem->getUserdata());
|
||||
FSPoserAnimator::FSPoserJoint* poserJoint = static_cast<FSPoserAnimator::FSPoserJoint*>(listItem->getUserdata());
|
||||
if (!poserJoint)
|
||||
continue;
|
||||
|
||||
((LLScrollListText*)listItem->getColumn(COL_ICON))->setValue(getScrollListIconForJoint(avatar, *poserJoint));
|
||||
|
||||
if (mPoserAnimator.isPosingAvatarJoint(avatar, *poserJoint))
|
||||
((LLScrollListText *) listItem->getColumn(COL_NAME))->setFontStyle(LLFontGL::BOLD);
|
||||
((LLScrollListText*)listItem->getColumn(COL_NAME))->setFontStyle(LLFontGL::BOLD);
|
||||
else
|
||||
((LLScrollListText *) listItem->getColumn(COL_NAME))->setFontStyle(LLFontGL::NORMAL);
|
||||
((LLScrollListText*)listItem->getColumn(COL_NAME))->setFontStyle(LLFontGL::NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
std::string FSFloaterPoser::getScrollListIconForJoint(LLVOAvatar* avatar, FSPoserAnimator::FSPoserJoint joint)
|
||||
{
|
||||
if (!avatar)
|
||||
return "";
|
||||
return {};
|
||||
|
||||
if (mPoserAnimator.getRotationIsWorldLocked(avatar, joint))
|
||||
return tryGetString("icon_rotation_is_world_locked");
|
||||
|
||||
if (!getSavingToBvh())
|
||||
return "";
|
||||
return {};
|
||||
|
||||
if (joint.boneType() == COL_VOLUMES)
|
||||
return tryGetString("icon_rotation_does_not_export");
|
||||
|
|
@ -2530,10 +2777,10 @@ std::string FSFloaterPoser::getScrollListIconForJoint(LLVOAvatar* avatar, FSPose
|
|||
return tryGetString("icon_rotation_bvh_unlocked");
|
||||
}
|
||||
|
||||
std::string FSFloaterPoser::tryGetString(std::string name)
|
||||
std::string FSFloaterPoser::tryGetString(std::string_view name)
|
||||
{
|
||||
if (name.empty())
|
||||
return "";
|
||||
return {};
|
||||
|
||||
return hasString(name) ? getString(name) : "";
|
||||
}
|
||||
|
|
@ -2560,8 +2807,7 @@ bool FSFloaterPoser::savePoseToBvh(LLVOAvatar* avatar, const std::string& poseFi
|
|||
std::string fullSavePath =
|
||||
gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, POSE_SAVE_SUBDIRECTORY, poseFileName + POSE_EXTERNAL_FORMAT_FILE_EXT);
|
||||
|
||||
llofstream file;
|
||||
file.open(fullSavePath.c_str());
|
||||
llofstream file(fullSavePath.c_str());
|
||||
if (!file.is_open())
|
||||
{
|
||||
LL_WARNS("Poser") << "Unable to save pose!" << LL_ENDL;
|
||||
|
|
@ -2658,7 +2904,7 @@ void FSFloaterPoser::writeBvhFragment(llofstream* fileStream, LLVOAvatar* avatar
|
|||
{
|
||||
for (size_t index = 0; index != numberOfBvhChildNodes; ++index)
|
||||
{
|
||||
auto nextJoint = mPoserAnimator.getPoserJointByName(joint->bvhChildren()[index]);
|
||||
auto nextJoint = mPoserAnimator.getPoserJointByName(joint->bvhChildren().at(index));
|
||||
writeBvhFragment(fileStream, avatar, nextJoint, tabStops + 1);
|
||||
}
|
||||
}
|
||||
|
|
@ -2693,7 +2939,7 @@ void FSFloaterPoser::writeFirstFrameOfBvhMotion(llofstream* fileStream, const FS
|
|||
size_t numberOfBvhChildNodes = joint->bvhChildren().size();
|
||||
for (size_t index = 0; index != numberOfBvhChildNodes; ++index)
|
||||
{
|
||||
auto nextJoint = mPoserAnimator.getPoserJointByName(joint->bvhChildren()[index]);
|
||||
auto nextJoint = mPoserAnimator.getPoserJointByName(joint->bvhChildren().at(index));
|
||||
writeFirstFrameOfBvhMotion(fileStream, nextJoint);
|
||||
}
|
||||
}
|
||||
|
|
@ -2722,15 +2968,15 @@ void FSFloaterPoser::writeBvhMotion(llofstream* fileStream, LLVOAvatar* avatar,
|
|||
size_t numberOfBvhChildNodes = joint->bvhChildren().size();
|
||||
for (size_t index = 0; index != numberOfBvhChildNodes; ++index)
|
||||
{
|
||||
auto nextJoint = mPoserAnimator.getPoserJointByName(joint->bvhChildren()[index]);
|
||||
auto nextJoint = mPoserAnimator.getPoserJointByName(joint->bvhChildren().at(index));
|
||||
writeBvhMotion(fileStream, avatar, nextJoint);
|
||||
}
|
||||
}
|
||||
|
||||
std::string FSFloaterPoser::positionToString(const LLVector3& val)
|
||||
{
|
||||
const float metresToInches = 39.37008f;
|
||||
return std::to_string(metresToInches * val[VY]) + " " + std::to_string(metresToInches * val[VZ]) + " " + std::to_string(metresToInches * val[VX]);
|
||||
constexpr F32 metersToInches = 39.37008f;
|
||||
return std::to_string(metersToInches * val[VY]) + " " + std::to_string(metersToInches * val[VZ]) + " " + std::to_string(metersToInches * val[VX]);
|
||||
}
|
||||
|
||||
std::string FSFloaterPoser::rotationToString(const LLVector3& val)
|
||||
|
|
@ -2797,7 +3043,7 @@ S32 FSFloaterPoser::getBvhJointNegation(const std::string& jointName) const
|
|||
return result;
|
||||
}
|
||||
|
||||
bool FSFloaterPoser::getSavingToBvh()
|
||||
bool FSFloaterPoser::getSavingToBvh() const
|
||||
{
|
||||
return gSavedSettings.getBOOL(POSER_SAVEEXTERNALFORMAT_SAVE_KEY);
|
||||
}
|
||||
|
|
@ -2811,7 +3057,7 @@ void FSFloaterPoser::onClickSavingToBvh()
|
|||
void FSFloaterPoser::onClickLockWorldRotBtn()
|
||||
{
|
||||
auto selectedJoints = getUiSelectedPoserJoints();
|
||||
if (selectedJoints.size() < 1)
|
||||
if (selectedJoints.empty())
|
||||
return;
|
||||
|
||||
LLVOAvatar* avatar = getUiSelectedAvatar();
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include "llfloater.h"
|
||||
#include "lltoolmgr.h"
|
||||
#include "fsposeranimator.h"
|
||||
#include "fsmaniprotatejoint.h"
|
||||
|
||||
class FSVirtualTrackpad;
|
||||
class LLButton;
|
||||
|
|
@ -80,7 +81,8 @@ class FSFloaterPoser : public LLFloater, public LLEditMenuHandler
|
|||
friend class LLFloaterReg;
|
||||
FSFloaterPoser(const LLSD &key);
|
||||
public:
|
||||
void updatePosedBones(const std::string& jointName);
|
||||
void updatePosedBones(const std::string& jointName, const LLQuaternion& rotation, const LLVector3& position, const LLVector3& scale);
|
||||
LLQuaternion getManipGimbalRotation(const std::string& jointName);
|
||||
void selectJointByName(const std::string& jointName);
|
||||
void undo() override { onUndoLastChange(); };
|
||||
bool canUndo() const override { return true; }
|
||||
|
|
@ -94,6 +96,8 @@ public:
|
|||
void onClose(bool app_quitting) override;
|
||||
void onFocusReceived() override;
|
||||
void onFocusLost() override;
|
||||
virtual void draw() override;
|
||||
|
||||
/// <summary>
|
||||
/// Refreshes the supplied pose list from the supplued subdirectory.
|
||||
/// </summary>
|
||||
|
|
@ -139,7 +143,7 @@ public:
|
|||
/// Updates the visual with the first selected joint from the supplied collection, if any.
|
||||
/// </summary>
|
||||
/// <param name="joints">The collection of selected joints.</param>
|
||||
void updateManipWithFirstSelectedJoint(std::vector<FSPoserAnimator::FSPoserJoint*> joints) const;
|
||||
void updateManipWithFirstSelectedJoint(const std::vector<FSPoserAnimator::FSPoserJoint*>& joints) const;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a detectable avatar by its UUID.
|
||||
|
|
@ -181,6 +185,13 @@ public:
|
|||
/// <returns>A the collection of UUIDs for nearby avatars.</returns>
|
||||
uuid_vec_t getNearbyAvatarsAndAnimeshes() const;
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the supplied character is within chat range of gAgentAvatar.
|
||||
/// </summary>
|
||||
/// <param name="character">The character to query whether nearby.</param>
|
||||
/// <returns>True if the supplied character is within chat range, otherwise false.</returns>
|
||||
bool avatarIsNearbyMe(LLCharacter* character) const;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a collection of UUIDs for avatars currently being presented on the UI.
|
||||
/// </summary>
|
||||
|
|
@ -218,7 +229,7 @@ public:
|
|||
LLVector3 getPositionOfFirstSelectedJoint() const;
|
||||
LLVector3 getScaleOfFirstSelectedJoint() const;
|
||||
|
||||
LLScrollListCtrl* getScrollListForTab(LLPanel * tabPanel) const;
|
||||
LLScrollListCtrl* getScrollListForTab(LLPanel* tabPanel) const;
|
||||
// Pose load/save
|
||||
void createUserPoseDirectoryIfNeeded();
|
||||
void onToggleLoadSavePanel();
|
||||
|
|
@ -242,17 +253,22 @@ public:
|
|||
void enableVisualManipulators();
|
||||
void disableVisualManipulators();
|
||||
|
||||
// Visual cue for which bone is under the mouse-cursor
|
||||
void drawOnHoverJointHint();
|
||||
void markSelectedJointsToHighlight();
|
||||
|
||||
// UI Event Handlers
|
||||
void onAvatarsRefresh();
|
||||
void onAvatarSelect();
|
||||
void onJointTabSelect();
|
||||
void onToggleMirrorChange();
|
||||
void onToggleSympatheticChange();
|
||||
void onToggleRotationFrameButton(const LLUICtrl* toggleButton);
|
||||
void onToggleVisualManipulators();
|
||||
void setRotationChangeButtons(bool mirror, bool sympathetic);
|
||||
void onUndoLastChange();
|
||||
void onRedoLastChange();
|
||||
void onResetJoint(const LLSD data);
|
||||
void onResetJoint(const LLSD& data);
|
||||
void onSetAvatarToTpose();
|
||||
void onPoseStartStop();
|
||||
void onTrackballChanged();
|
||||
|
|
@ -280,6 +296,14 @@ public:
|
|||
void refreshTrackpadCursor();
|
||||
void enableOrDisableRedoAndUndoButton();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Determines if we have permission to animate the supplied avatar.
|
||||
/// </summary>
|
||||
/// <param name="avatar">The avatar to animate.</param>
|
||||
/// <returns>True if we have permission to animate, otherwise false.</returns>
|
||||
bool havePermissionToAnimateOtherAvatar(LLVOAvatar* avatar) const;
|
||||
|
||||
/// <summary>
|
||||
/// Determines if we have permission to animate the supplied avatar.
|
||||
/// </summary>
|
||||
|
|
@ -306,6 +330,7 @@ public:
|
|||
/// This facilitates 'conceptual' conversion of Euler frame to up/down, left/right and roll and is rather subjective.
|
||||
/// Thus, many of these 'conversions' are backed by values in the XML.
|
||||
/// </summary>
|
||||
/// <param name="frame">The reference frame for the change.</param>
|
||||
/// <param name="jointName">The well-known name of the joint, eg: mChest.</param>
|
||||
/// <returns>The axial translation so the oily angles make better sense in terms of up/down/left/right/roll.</returns>
|
||||
/// <remarks>
|
||||
|
|
@ -313,14 +338,21 @@ public:
|
|||
/// No the translation isn't untangling all of that, it's not needed until it is.
|
||||
/// We're not landing on Mars with this code, just offering a user reasonable thumb-twiddlings.
|
||||
/// </remarks>
|
||||
E_BoneAxisTranslation getJointTranslation(const std::string& jointName) const;
|
||||
E_BoneAxisTranslation getJointTranslation(E_PoserReferenceFrame frame, const std::string& jointName) const;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the collection of E_BoneAxisNegation values for the supplied joint.
|
||||
/// </summary>
|
||||
/// <param name="frame">The reference frame for the change.</param>
|
||||
/// <param name="jointName">The name of the joind to get the axis transformation for.</param>
|
||||
/// <returns>The kind of axis transformation to perform.</returns>
|
||||
S32 getJointNegation(const std::string& jointName) const;
|
||||
S32 getJointNegation(E_PoserReferenceFrame frame, const std::string& jointName) const;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the reference frame for the rotation/position/scale change.
|
||||
/// </summary>
|
||||
/// <returns>The reference frame for the change.</returns>
|
||||
E_PoserReferenceFrame getReferenceFrame() const;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the axial translation required for joints when saving to BVH.
|
||||
|
|
@ -336,6 +368,13 @@ public:
|
|||
/// </summary>
|
||||
void refreshTextHighlightingOnAvatarScrollList();
|
||||
|
||||
/// <summary>
|
||||
/// Gets an appropriate icon for the supplied avatar, based on sharing permission.
|
||||
/// </summary>
|
||||
/// <param name="avatar">The avatar to get an icon for.</param>
|
||||
/// <returns>A string with the name of an icon.</returns>
|
||||
std::string getIconNameForAvatar(LLVOAvatar* avatar);
|
||||
|
||||
/// <summary>
|
||||
/// Refreshes the text on all joints scroll lists based on their state.
|
||||
/// </summary>
|
||||
|
|
@ -367,7 +406,7 @@ public:
|
|||
/// </summary>
|
||||
/// <param name="name">The name of the string.</param>
|
||||
/// <returns>The named string, if it exists, otherwise an empty string.</returns>
|
||||
std::string tryGetString(std::string name);
|
||||
std::string tryGetString(std::string_view name);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of an item from the supplied object ID.
|
||||
|
|
@ -383,7 +422,7 @@ public:
|
|||
/// Gets whether the pose should also write a BVH file when saved.
|
||||
/// </summary>
|
||||
/// <returns>True if the user wants to additionally save a BVH file, otherwise false.</returns>
|
||||
bool getSavingToBvh();
|
||||
bool getSavingToBvh() const;
|
||||
|
||||
/// <summary>
|
||||
/// Writes the current pose in BVH-format to the supplied stream.
|
||||
|
|
@ -450,10 +489,12 @@ public:
|
|||
/// </remarks>
|
||||
static F32 clipRange(F32 value);
|
||||
|
||||
LLToolset* mLastToolset{ nullptr };
|
||||
LLTool* mJointRotTool{ nullptr };
|
||||
|
||||
LLVector3 mLastSliderRotation;
|
||||
LLToolset* mLastToolset{ nullptr };
|
||||
LLTool* mJointRotTool{ nullptr };
|
||||
|
||||
LLVector3 mLastSliderRotation;
|
||||
FSPoserAnimator::FSPoserJoint* mLastSelectedJoint{ nullptr };
|
||||
U64 timeFadeStartedMicrosec;
|
||||
|
||||
FSVirtualTrackpad* mAvatarTrackball{ nullptr };
|
||||
|
||||
|
|
@ -502,6 +543,10 @@ public:
|
|||
LLButton* mUndoChangeBtn{ nullptr };
|
||||
LLButton* mSetToTposeButton{ nullptr };
|
||||
LLButton* mBtnJointRotate{ nullptr };
|
||||
LLButton* mBtnJointReset{ nullptr };
|
||||
LLButton* mBtnWorldFrame{ nullptr };
|
||||
LLButton* mBtnAvatarFrame{ nullptr };
|
||||
LLButton* mBtnScreenFrame{ nullptr };
|
||||
|
||||
LLLineEditor* mPoseSaveNameEditor{ nullptr };
|
||||
|
||||
|
|
@ -516,6 +561,9 @@ public:
|
|||
LLPanel* mMiscJointsPnl{ nullptr };
|
||||
LLPanel* mCollisionVolumesPnl{ nullptr };
|
||||
LLPanel* mPosesLoadSavePnl{ nullptr };
|
||||
LLPanel* mPositionPnl{ nullptr };
|
||||
LLPanel* mMoveTabPnl{ nullptr };
|
||||
LLPanel* mTrackballButtonPnl{ nullptr };
|
||||
|
||||
LLCheckBoxCtrl* mAlsoSaveBvhCbx{ nullptr };
|
||||
LLCheckBoxCtrl* mUnlockPelvisInBvhSaveCbx{ nullptr };
|
||||
|
|
|
|||
|
|
@ -0,0 +1,109 @@
|
|||
/**
|
||||
* @file fsfloatersplashscreensettings.cpp
|
||||
* @brief Splash screen settings floater
|
||||
*
|
||||
* $LicenseInfo:firstyear=2025&license=viewerlgpl$
|
||||
* Copyright (c) 2025 The Phoenix Firestorm Project, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA
|
||||
* http://www.firestormviewer.org
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "fsfloatersplashscreensettings.h"
|
||||
#include "llcheckboxctrl.h"
|
||||
#include "llviewercontrol.h"
|
||||
|
||||
FSFloaterSplashScreenSettings::FSFloaterSplashScreenSettings(const LLSD& key) :
|
||||
LLFloater(key),
|
||||
mHideTopBarCheck(nullptr),
|
||||
mHideBlogsCheck(nullptr),
|
||||
mHideDestinationsCheck(nullptr),
|
||||
mUseGrayModeCheck(nullptr),
|
||||
mUseHighContrastCheck(nullptr),
|
||||
mUseAllCapsCheck(nullptr),
|
||||
mUseLargerFontsCheck(nullptr),
|
||||
mNoTransparencyCheck(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
FSFloaterSplashScreenSettings::~FSFloaterSplashScreenSettings()
|
||||
{
|
||||
}
|
||||
|
||||
bool FSFloaterSplashScreenSettings::postBuild()
|
||||
{
|
||||
mHideTopBarCheck = getChild<LLCheckBoxCtrl>("hide_top_bar");
|
||||
mHideBlogsCheck = getChild<LLCheckBoxCtrl>("hide_blogs");
|
||||
mHideDestinationsCheck = getChild<LLCheckBoxCtrl>("hide_destinations");
|
||||
mUseGrayModeCheck = getChild<LLCheckBoxCtrl>("use_gray_mode");
|
||||
mUseHighContrastCheck = getChild<LLCheckBoxCtrl>("use_high_contrast");
|
||||
mUseAllCapsCheck = getChild<LLCheckBoxCtrl>("use_all_caps");
|
||||
mUseLargerFontsCheck = getChild<LLCheckBoxCtrl>("use_larger_fonts");
|
||||
mNoTransparencyCheck = getChild<LLCheckBoxCtrl>("no_transparency");
|
||||
|
||||
mHideTopBarCheck->setCommitCallback(boost::bind(&FSFloaterSplashScreenSettings::onSettingChanged, this));
|
||||
mHideBlogsCheck->setCommitCallback(boost::bind(&FSFloaterSplashScreenSettings::onSettingChanged, this));
|
||||
mHideDestinationsCheck->setCommitCallback(boost::bind(&FSFloaterSplashScreenSettings::onSettingChanged, this));
|
||||
mUseGrayModeCheck->setCommitCallback(boost::bind(&FSFloaterSplashScreenSettings::onSettingChanged, this));
|
||||
mUseHighContrastCheck->setCommitCallback(boost::bind(&FSFloaterSplashScreenSettings::onSettingChanged, this));
|
||||
mUseAllCapsCheck->setCommitCallback(boost::bind(&FSFloaterSplashScreenSettings::onSettingChanged, this));
|
||||
mUseLargerFontsCheck->setCommitCallback(boost::bind(&FSFloaterSplashScreenSettings::onSettingChanged, this));
|
||||
mNoTransparencyCheck->setCommitCallback(boost::bind(&FSFloaterSplashScreenSettings::onSettingChanged, this));
|
||||
|
||||
loadSettings();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FSFloaterSplashScreenSettings::onOpen(const LLSD& key)
|
||||
{
|
||||
LLFloater::onOpen(key);
|
||||
loadSettings();
|
||||
}
|
||||
|
||||
void FSFloaterSplashScreenSettings::loadSettings()
|
||||
{
|
||||
mHideTopBarCheck->setValue(gSavedSettings.getBOOL("FSSplashScreenHideTopBar"));
|
||||
mHideBlogsCheck->setValue(gSavedSettings.getBOOL("FSSplashScreenHideBlogs"));
|
||||
mHideDestinationsCheck->setValue(gSavedSettings.getBOOL("FSSplashScreenHideDestinations"));
|
||||
mUseGrayModeCheck->setValue(gSavedSettings.getBOOL("FSSplashScreenUseGrayMode"));
|
||||
mUseHighContrastCheck->setValue(gSavedSettings.getBOOL("FSSplashScreenUseHighContrast"));
|
||||
mUseAllCapsCheck->setValue(gSavedSettings.getBOOL("FSSplashScreenUseAllCaps"));
|
||||
mUseLargerFontsCheck->setValue(gSavedSettings.getBOOL("FSSplashScreenUseLargerFonts"));
|
||||
mNoTransparencyCheck->setValue(gSavedSettings.getBOOL("FSSplashScreenNoTransparency"));
|
||||
}
|
||||
|
||||
void FSFloaterSplashScreenSettings::saveSettings()
|
||||
{
|
||||
gSavedSettings.setBOOL("FSSplashScreenHideTopBar", mHideTopBarCheck->getValue().asBoolean());
|
||||
gSavedSettings.setBOOL("FSSplashScreenHideBlogs", mHideBlogsCheck->getValue().asBoolean());
|
||||
gSavedSettings.setBOOL("FSSplashScreenHideDestinations", mHideDestinationsCheck->getValue().asBoolean());
|
||||
gSavedSettings.setBOOL("FSSplashScreenUseGrayMode", mUseGrayModeCheck->getValue().asBoolean());
|
||||
gSavedSettings.setBOOL("FSSplashScreenUseHighContrast", mUseHighContrastCheck->getValue().asBoolean());
|
||||
gSavedSettings.setBOOL("FSSplashScreenUseAllCaps", mUseAllCapsCheck->getValue().asBoolean());
|
||||
gSavedSettings.setBOOL("FSSplashScreenUseLargerFonts", mUseLargerFontsCheck->getValue().asBoolean());
|
||||
gSavedSettings.setBOOL("FSSplashScreenNoTransparency", mNoTransparencyCheck->getValue().asBoolean());
|
||||
}
|
||||
|
||||
void FSFloaterSplashScreenSettings::onSettingChanged()
|
||||
{
|
||||
saveSettings();
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
/**
|
||||
* @file fsfloatersplashscreensettings.h
|
||||
* @brief Splash screen settings floater
|
||||
*
|
||||
* $LicenseInfo:firstyear=2025&license=viewerlgpl$
|
||||
* Copyright (c) 2025 The Phoenix Firestorm Project, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA
|
||||
* http://www.firestormviewer.org
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef FS_FLOATERSPLASHSCREENSETTINGS_H
|
||||
#define FS_FLOATERSPLASHSCREENSETTINGS_H
|
||||
|
||||
#include "llfloater.h"
|
||||
|
||||
class LLCheckBoxCtrl;
|
||||
|
||||
class FSFloaterSplashScreenSettings : public LLFloater
|
||||
{
|
||||
public:
|
||||
FSFloaterSplashScreenSettings(const LLSD& key);
|
||||
virtual ~FSFloaterSplashScreenSettings();
|
||||
|
||||
/*virtual*/ bool postBuild();
|
||||
/*virtual*/ void onOpen(const LLSD& key);
|
||||
|
||||
private:
|
||||
void onSettingChanged();
|
||||
void loadSettings();
|
||||
void saveSettings();
|
||||
|
||||
LLCheckBoxCtrl* mHideTopBarCheck;
|
||||
LLCheckBoxCtrl* mHideBlogsCheck;
|
||||
LLCheckBoxCtrl* mHideDestinationsCheck;
|
||||
LLCheckBoxCtrl* mUseGrayModeCheck;
|
||||
LLCheckBoxCtrl* mUseHighContrastCheck;
|
||||
LLCheckBoxCtrl* mUseAllCapsCheck;
|
||||
LLCheckBoxCtrl* mUseLargerFontsCheck;
|
||||
LLCheckBoxCtrl* mNoTransparencyCheck;
|
||||
};
|
||||
|
||||
#endif // FS_FLOATERSPLASHSCREENSETTINGS_H
|
||||
|
||||
|
|
@ -25,7 +25,6 @@
|
|||
*/
|
||||
|
||||
#include <deque>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include "fsposingmotion.h"
|
||||
#include "llcharacter.h"
|
||||
|
||||
|
|
@ -47,23 +46,26 @@ FSJointPose::FSJointPose(LLJoint* joint, U32 usage, bool isCollisionVolume)
|
|||
|
||||
mJointName = joint->getName();
|
||||
mIsCollisionVolume = isCollisionVolume;
|
||||
mJointNumber = joint->getJointNum();
|
||||
|
||||
mCurrentState = FSJointState(joint);
|
||||
mCurrentState = FSJointState(joint);
|
||||
}
|
||||
|
||||
void FSJointPose::setPublicPosition(const LLVector3& pos)
|
||||
{
|
||||
addStateToUndo(FSJointState(mCurrentState));
|
||||
addStateToUndo(mCurrentState);
|
||||
mCurrentState.mPosition.set(pos);
|
||||
mCurrentState.mLastChangeWasRotational = false;
|
||||
}
|
||||
|
||||
void FSJointPose::setPublicRotation(bool zeroBase, const LLQuaternion& rot)
|
||||
{
|
||||
addStateToUndo(FSJointState(mCurrentState));
|
||||
addStateToUndo(mCurrentState);
|
||||
|
||||
if (zeroBase)
|
||||
zeroBaseRotation(true);
|
||||
else
|
||||
mCurrentState.mUserSpecifiedBaseZero = false;
|
||||
|
||||
mCurrentState.mRotation.set(rot);
|
||||
mCurrentState.mLastChangeWasRotational = true;
|
||||
|
|
@ -71,7 +73,7 @@ void FSJointPose::setPublicRotation(bool zeroBase, const LLQuaternion& rot)
|
|||
|
||||
void FSJointPose::setPublicScale(const LLVector3& scale)
|
||||
{
|
||||
addStateToUndo(FSJointState(mCurrentState));
|
||||
addStateToUndo(mCurrentState);
|
||||
mCurrentState.mScale.set(scale);
|
||||
mCurrentState.mLastChangeWasRotational = false;
|
||||
}
|
||||
|
|
@ -79,27 +81,30 @@ void FSJointPose::setPublicScale(const LLVector3& scale)
|
|||
bool FSJointPose::undoLastChange()
|
||||
{
|
||||
bool changeType = mCurrentState.mLastChangeWasRotational;
|
||||
mCurrentState = undoLastStateChange(FSJointState(mCurrentState));
|
||||
mCurrentState = undoLastStateChange(mCurrentState);
|
||||
|
||||
return changeType;
|
||||
}
|
||||
|
||||
void FSJointPose::redoLastChange()
|
||||
{
|
||||
mCurrentState = redoLastStateChange(FSJointState(mCurrentState));
|
||||
mCurrentState = redoLastStateChange(mCurrentState);
|
||||
}
|
||||
|
||||
void FSJointPose::resetJoint()
|
||||
{
|
||||
addStateToUndo(FSJointState(mCurrentState));
|
||||
addStateToUndo(mCurrentState);
|
||||
mCurrentState.resetJoint();
|
||||
mCurrentState.mLastChangeWasRotational = true;
|
||||
}
|
||||
|
||||
void FSJointPose::addStateToUndo(FSJointState stateToAddToUndo)
|
||||
void FSJointPose::addStateToUndo(const FSJointState& stateToAddToUndo)
|
||||
{
|
||||
auto timeIntervalSinceLastChange = std::chrono::system_clock::now() - mTimeLastUpdatedCurrentState;
|
||||
mTimeLastUpdatedCurrentState = std::chrono::system_clock::now();
|
||||
mModifiedThisSession = true;
|
||||
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto timeIntervalSinceLastChange = now - mTimeLastUpdatedCurrentState;
|
||||
mTimeLastUpdatedCurrentState = now;
|
||||
|
||||
if (timeIntervalSinceLastChange < UndoUpdateInterval)
|
||||
return;
|
||||
|
|
@ -119,7 +124,7 @@ void FSJointPose::addStateToUndo(FSJointState stateToAddToUndo)
|
|||
mLastSetJointStates.pop_back();
|
||||
}
|
||||
|
||||
FSJointPose::FSJointState FSJointPose::undoLastStateChange(FSJointState thingToSet)
|
||||
FSJointPose::FSJointState FSJointPose::undoLastStateChange(const FSJointState& thingToSet)
|
||||
{
|
||||
if (mLastSetJointStates.empty())
|
||||
return thingToSet;
|
||||
|
|
@ -133,7 +138,7 @@ FSJointPose::FSJointState FSJointPose::undoLastStateChange(FSJointState thingToS
|
|||
return mLastSetJointStates.at(mUndoneJointStatesIndex);
|
||||
}
|
||||
|
||||
FSJointPose::FSJointState FSJointPose::redoLastStateChange(FSJointState thingToSet)
|
||||
FSJointPose::FSJointState FSJointPose::redoLastStateChange(const FSJointState& thingToSet)
|
||||
{
|
||||
if (mLastSetJointStates.empty())
|
||||
return thingToSet;
|
||||
|
|
@ -151,40 +156,41 @@ FSJointPose::FSJointState FSJointPose::redoLastStateChange(FSJointState thingToS
|
|||
|
||||
void FSJointPose::recaptureJoint()
|
||||
{
|
||||
if (mIsCollisionVolume)
|
||||
return;
|
||||
|
||||
LLJoint* joint = mJointState->getJoint();
|
||||
if (!joint)
|
||||
return;
|
||||
|
||||
addStateToUndo(FSJointState(mCurrentState));
|
||||
addStateToUndo(mCurrentState);
|
||||
|
||||
if (mIsCollisionVolume)
|
||||
{
|
||||
mCurrentState.mPosition.clear();
|
||||
mCurrentState.mScale.clear();
|
||||
}
|
||||
|
||||
mCurrentState = FSJointState(joint);
|
||||
mCurrentState.mLastChangeWasRotational = true;
|
||||
}
|
||||
|
||||
LLQuaternion FSJointPose::recaptureJointAsDelta(bool zeroBase)
|
||||
LLQuaternion FSJointPose::updateJointAsDelta(bool zeroBase, const LLQuaternion& rotation, const LLVector3& position, const LLVector3& scale)
|
||||
{
|
||||
LLJoint* joint = mJointState->getJoint();
|
||||
if (!joint)
|
||||
return LLQuaternion::DEFAULT;
|
||||
|
||||
addStateToUndo(FSJointState(mCurrentState));
|
||||
addStateToUndo(mCurrentState);
|
||||
mCurrentState.mLastChangeWasRotational = true;
|
||||
return mCurrentState.updateFromJoint(joint, zeroBase);
|
||||
|
||||
return mCurrentState.updateFromJointProperties(zeroBase, rotation, position, scale);
|
||||
}
|
||||
|
||||
void FSJointPose::setBaseRotation(LLQuaternion rotation, LLJoint::JointPriority priority)
|
||||
void FSJointPose::setBaseRotation(const LLQuaternion& rotation, LLJoint::JointPriority priority)
|
||||
{
|
||||
mCurrentState.resetBaseRotation(rotation, priority);
|
||||
}
|
||||
|
||||
void FSJointPose::setBasePosition(LLVector3 position, LLJoint::JointPriority priority)
|
||||
void FSJointPose::setBasePosition(const LLVector3& position, LLJoint::JointPriority priority)
|
||||
{
|
||||
mCurrentState.resetBasePosition(position, priority);
|
||||
}
|
||||
|
||||
void FSJointPose::setBaseScale(LLVector3 scale, LLJoint::JointPriority priority)
|
||||
void FSJointPose::setBaseScale(const LLVector3& scale, LLJoint::JointPriority priority)
|
||||
{
|
||||
mCurrentState.resetBaseScale(scale, priority);
|
||||
}
|
||||
|
|
@ -247,6 +253,7 @@ void FSJointPose::reflectRotation()
|
|||
if (mIsCollisionVolume)
|
||||
return;
|
||||
|
||||
mModifiedThisSession = true;
|
||||
mCurrentState.reflectRotation();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -97,6 +97,8 @@ class FSJointPose
|
|||
/// 'Public rotation' is the amount of rotation the user has added to the initial state.
|
||||
/// Public rotation is what a user may save to an external format (such as BVH).
|
||||
/// This distinguishes 'private' rotation, which is the state inherited from something like a pose in-world.
|
||||
/// If zeroBase is true, we treat rotations as if in BVH mode: user work.
|
||||
/// If zeroBase is false, we treat as NOT BVH: some existing pose and user work.
|
||||
/// </remarks>
|
||||
void setPublicRotation(bool zeroBase, const LLQuaternion& rot);
|
||||
|
||||
|
|
@ -173,29 +175,32 @@ class FSJointPose
|
|||
/// Recalculates the delta reltive to the base for a new rotation.
|
||||
/// </summary>
|
||||
/// <param name="zeroBase">Whether to zero the base rotation on setting the supplied rotation.</param>
|
||||
/// <param name="rotation">The rotation of the supplied joint.</param>
|
||||
/// <param name="position">The position of the supplied joint.</param>
|
||||
/// <param name="scale">The scale of the supplied joint.</param>
|
||||
/// <returns>The rotation of the public difference between before and after recapture.</returns>
|
||||
LLQuaternion recaptureJointAsDelta(bool zeroBase);
|
||||
LLQuaternion updateJointAsDelta(bool zeroBase, const LLQuaternion& rotation, const LLVector3& position, const LLVector3& scale);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the base rotation to the supplied rotation if the supplied priority is appropriate.
|
||||
/// </summary>
|
||||
/// <param name="rotation">The base rotation to set; zero is ignored.</param>
|
||||
/// <param name="priority">The priority of the base rotation; only priority equal or higher than any prior sets have any effect.</param>
|
||||
void setBaseRotation(LLQuaternion rotation, LLJoint::JointPriority priority);
|
||||
void setBaseRotation(const LLQuaternion& rotation, LLJoint::JointPriority priority);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the base position to the supplied position if the supplied priority is appropriate.
|
||||
/// </summary>
|
||||
/// <param name="position">The base position to set; zero is ignored.</param>
|
||||
/// <param name="priority">The priority of the base rotation; only priority equal or higher than any prior sets have any effect.</param>
|
||||
void setBasePosition(LLVector3 position, LLJoint::JointPriority priority);
|
||||
void setBasePosition(const LLVector3& position, LLJoint::JointPriority priority);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the base scale to the supplied scale if the supplied priority is appropriate.
|
||||
/// </summary>
|
||||
/// <param name="scale">The base scale to set; zero is ignored.</param>
|
||||
/// <param name="priority">The priority of the base rotation; only priority equal or higher than any prior sets have any effect.</param>
|
||||
void setBaseScale(LLVector3 scale, LLJoint::JointPriority priority);
|
||||
void setBaseScale(const LLVector3& scale, LLJoint::JointPriority priority);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the priority of the bone to the supplied value.
|
||||
|
|
@ -253,6 +258,18 @@ class FSJointPose
|
|||
/// </summary>
|
||||
LLPointer<LLJointState> getJointState() const { return mJointState; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether this joint has been modified this session.
|
||||
/// </summary>
|
||||
/// <returns>True if the joint has been changed at all, otherwise false.</returns>
|
||||
bool getJointModified() const { return mModifiedThisSession; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of the joint represented by this.
|
||||
/// </summary>
|
||||
/// <returns>The joint number, derived from LLjoint.</returns>
|
||||
S32 getJointNumber() const { return mJointNumber; }
|
||||
|
||||
class FSJointState
|
||||
{
|
||||
public:
|
||||
|
|
@ -326,15 +343,12 @@ class FSJointPose
|
|||
joint->setScale(mBaseScale);
|
||||
}
|
||||
|
||||
LLQuaternion updateFromJoint(LLJoint* joint, bool zeroBase)
|
||||
LLQuaternion updateFromJointProperties(bool zeroBase, const LLQuaternion rotation, const LLVector3 position, const LLVector3 scale)
|
||||
{
|
||||
if (!joint)
|
||||
return LLQuaternion::DEFAULT;
|
||||
|
||||
LLQuaternion initalPublicRot = mRotation;
|
||||
LLQuaternion invRot = mBaseRotation;
|
||||
invRot.conjugate();
|
||||
LLQuaternion newPublicRot = joint->getRotation() * invRot;
|
||||
LLQuaternion newPublicRot = rotation * invRot;
|
||||
|
||||
if (zeroBase)
|
||||
{
|
||||
|
|
@ -343,8 +357,8 @@ class FSJointPose
|
|||
}
|
||||
|
||||
mRotation.set(newPublicRot);
|
||||
mPosition.set(joint->getPosition() - mBasePosition);
|
||||
mScale.set(joint->getScale() - mBaseScale);
|
||||
mPosition.set(position - mBasePosition);
|
||||
mScale.set(scale - mBaseScale);
|
||||
|
||||
return newPublicRot *= ~initalPublicRot;
|
||||
}
|
||||
|
|
@ -441,7 +455,7 @@ class FSJointPose
|
|||
};
|
||||
|
||||
private:
|
||||
std::string mJointName = ""; // expected to be a match to LLJoint.getName() for a joint implementation.
|
||||
std::string mJointName = ""; // expected to be a match to LLJoint.getName() for a joint implementation.
|
||||
LLPointer<LLJointState> mJointState{ nullptr };
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -450,15 +464,22 @@ class FSJointPose
|
|||
/// </summary>
|
||||
bool mIsCollisionVolume{ false };
|
||||
|
||||
S32 mJointNumber = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Whether this joint has ever been changed by poser.
|
||||
/// </summary>
|
||||
bool mModifiedThisSession{ false };
|
||||
|
||||
std::deque<FSJointState> mLastSetJointStates;
|
||||
size_t mUndoneJointStatesIndex = 0;
|
||||
std::chrono::system_clock::time_point mTimeLastUpdatedCurrentState = std::chrono::system_clock::now();
|
||||
|
||||
FSJointState mCurrentState;
|
||||
|
||||
void addStateToUndo(FSJointState stateToAddToUndo);
|
||||
FSJointState undoLastStateChange(FSJointState currentState);
|
||||
FSJointState redoLastStateChange(FSJointState currentState);
|
||||
void addStateToUndo(const FSJointState& stateToAddToUndo);
|
||||
FSJointState undoLastStateChange(const FSJointState& currentState);
|
||||
FSJointState redoLastStateChange(const FSJointState& currentState);
|
||||
};
|
||||
|
||||
#endif // FS_JOINTPPOSE_H
|
||||
|
|
|
|||
|
|
@ -25,11 +25,8 @@
|
|||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "fsmaniprotatejoint.h"
|
||||
|
||||
// library includes
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
#include "fsmaniprotatejoint.h"
|
||||
#include "llmath.h"
|
||||
#include "llgl.h"
|
||||
#include "llrender.h"
|
||||
|
|
@ -37,11 +34,10 @@
|
|||
#include "llprimitive.h"
|
||||
#include "llview.h"
|
||||
#include "llfontgl.h"
|
||||
|
||||
#include "llrendersphere.h"
|
||||
#include "llvoavatar.h"
|
||||
#include "lljoint.h"
|
||||
#include "llagent.h" // for gAgent, etc.
|
||||
#include "llagent.h" // for gAgent, etc.
|
||||
#include "llagentcamera.h"
|
||||
#include "llappviewer.h"
|
||||
#include "llcontrol.h"
|
||||
|
|
@ -173,15 +169,18 @@ static void renderStaticSphere(const LLVector3& joint_world_position, const LLCo
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
bool FSManipRotateJoint::isMouseOverJoint(S32 mouseX, S32 mouseY, const LLVector3& jointWorldPos, F32 jointRadius, F32& outDistanceFromCamera, F32& outRayDistanceFromCenter) const
|
||||
{
|
||||
// LL_INFOS("FSManipRotateJoint") << "Checking mouse("<< mouseX << "," << mouseY << ") over joint at: " << jointWorldPos << LL_ENDL;
|
||||
|
||||
auto joint_center = gAgent.getPosGlobalFromAgent( jointWorldPos );
|
||||
if (!mJoint || !mAvatar)
|
||||
return false;
|
||||
|
||||
if (mAvatar->isDead() || !mAvatar->isFullyLoaded())
|
||||
return false;
|
||||
|
||||
auto joint_center = mAvatar->getPosGlobalFromAgent(jointWorldPos);
|
||||
|
||||
// centre in *agent* space
|
||||
LLVector3 agent_space_center = gAgent.getPosAgentFromGlobal(joint_center);
|
||||
LLVector3 agent_space_center = mAvatar->getPosAgentFromGlobal(joint_center);
|
||||
LLVector3 ray_pt, ray_dir;
|
||||
LLManipRotate::mouseToRay(mouseX, mouseY, &ray_pt, &ray_dir);
|
||||
|
||||
|
|
@ -201,9 +200,9 @@ bool FSManipRotateJoint::isMouseOverJoint(S32 mouseX, S32 mouseY, const LLVector
|
|||
outDistanceFromCamera = proj_len - offset; // distance along the ray to the front intersection
|
||||
outRayDistanceFromCenter = offset;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (false);
|
||||
return false;
|
||||
}
|
||||
|
||||
//static
|
||||
|
|
@ -232,7 +231,6 @@ const std::vector<std::string_view> FSManipRotateJoint::sSelectableJoints =
|
|||
{ "mHipRight" },
|
||||
{ "mKneeRight" },
|
||||
{ "mAnkleRight" },
|
||||
|
||||
};
|
||||
|
||||
const std::unordered_map<FSManipRotateJoint::e_manip_part, FSManipRotateJoint::RingRenderParams> FSManipRotateJoint::sRingParams =
|
||||
|
|
@ -241,6 +239,7 @@ const std::unordered_map<FSManipRotateJoint::e_manip_part, FSManipRotateJoint::R
|
|||
{ LL_ROT_Y, { LL_ROT_Y, LLVector4(1.f, SELECTED_MANIPULATOR_SCALE, 1.f, 1.f), 90.f, LLVector3(1.f,0.f,0.f), LLColor4(0.f,1.f,0.f,1.f), LLColor4(0.f,1.f,0.f,0.3f), 1 } },
|
||||
{ LL_ROT_X, { LL_ROT_X, LLVector4(SELECTED_MANIPULATOR_SCALE, 1.f, 1.f, 1.f), 90.f, LLVector3(0.f,1.f,0.f), LLColor4(1.f,0.f,0.f,1.f), LLColor4(1.f,0.f,0.f,0.3f), 0 } }
|
||||
};
|
||||
|
||||
// Helper function: Builds an alignment quaternion from the computed bone axes.
|
||||
// This quaternion rotates from the default coordinate system (assumed to be
|
||||
// X = (1,0,0), Y = (0,1,0), Z = (0,0,1)) into the bone’s natural coordinate system.
|
||||
|
|
@ -268,7 +267,7 @@ FSManipRotateJoint::BoneAxes FSManipRotateJoint::computeBoneAxes() const
|
|||
BoneAxes axes;
|
||||
|
||||
// Use 0,0,0 as local start for joint.
|
||||
LLVector3 joint_local_pos (0.f,0.f,0.f);
|
||||
LLVector3 joint_local_pos(0.f,0.f,0.f);
|
||||
|
||||
// Transform the local endpoint (mEnd) into world space.
|
||||
LLVector3 localEnd = mJoint->getEnd();
|
||||
|
|
@ -331,13 +330,14 @@ void FSManipRotateJoint::highlightHoverSpheres(S32 mouseX, S32 mouseY)
|
|||
mHighlightedJoint = nullptr; // reset the highlighted joint
|
||||
|
||||
// Iterate through the avatar's joint map.
|
||||
F32 nearest_hit_distance = 0.f;
|
||||
F32 nearest_ray_distance = 0.f;
|
||||
LLJoint * nearest_joint = nullptr;
|
||||
for ( const auto& entry : getSelectableJoints())
|
||||
F32 nearest_hit_distance = 0.f;
|
||||
F32 nearest_ray_distance = 0.f;
|
||||
LLJoint* nearest_joint = nullptr;
|
||||
LLCachedControl<F32> target_radius(gSavedSettings, "FSManipRotateJointTargetSize", 0.03f);
|
||||
|
||||
for (const auto& entry : getSelectableJoints())
|
||||
{
|
||||
|
||||
LLJoint* joint = mAvatar->getJoint(std::string(entry));
|
||||
LLJoint* joint = mAvatar->getJoint(std::string(entry));
|
||||
if (!joint)
|
||||
continue;
|
||||
|
||||
|
|
@ -347,23 +347,22 @@ void FSManipRotateJoint::highlightHoverSpheres(S32 mouseX, S32 mouseY)
|
|||
|
||||
// Retrieve the joint's world position (in agent space).
|
||||
LLVector3 jointWorldPos = joint->getWorldPosition();
|
||||
LLCachedControl<F32> target_radius(gSavedSettings, "FSManipRotateJointTargetSize", 0.03f);
|
||||
F32 distance_from_camera;
|
||||
F32 distance_from_joint;
|
||||
if (isMouseOverJoint(mouseX, mouseY, jointWorldPos, target_radius, distance_from_camera, distance_from_joint) == true)
|
||||
if (!isMouseOverJoint(mouseX, mouseY, jointWorldPos, target_radius, distance_from_camera, distance_from_joint))
|
||||
continue;
|
||||
|
||||
// we want to highlight the closest
|
||||
// If there is no joint or this joint is a closer hit than the previous one
|
||||
if (!nearest_joint || nearest_ray_distance > distance_from_camera ||
|
||||
(nearest_ray_distance == distance_from_camera && nearest_hit_distance > distance_from_joint))
|
||||
{
|
||||
// we want to highlight the closest
|
||||
// If there is no joint or
|
||||
// this joint is a closer hit than the previous one
|
||||
if (!nearest_joint || nearest_ray_distance > distance_from_camera ||
|
||||
(nearest_ray_distance == distance_from_camera && nearest_hit_distance > distance_from_joint))
|
||||
{
|
||||
nearest_joint = joint;
|
||||
nearest_hit_distance = distance_from_joint;
|
||||
nearest_ray_distance = distance_from_camera;
|
||||
}
|
||||
nearest_joint = joint;
|
||||
nearest_hit_distance = distance_from_joint;
|
||||
nearest_ray_distance = distance_from_camera;
|
||||
}
|
||||
}
|
||||
|
||||
mHighlightedJoint = nearest_joint;
|
||||
}
|
||||
|
||||
|
|
@ -376,19 +375,23 @@ FSManipRotateJoint::FSManipRotateJoint(LLToolComposite* composite)
|
|||
void FSManipRotateJoint::setJoint(LLJoint* joint)
|
||||
{
|
||||
mJoint = joint;
|
||||
if (!mJoint)
|
||||
return;
|
||||
|
||||
// Save initial rotation as baseline for delta rotation
|
||||
if (mJoint)
|
||||
{
|
||||
mSavedJointRot = mJoint->getWorldRotation();
|
||||
mBoneAxes = computeBoneAxes();
|
||||
mNaturalAlignmentQuat = computeAlignmentQuat(mBoneAxes);
|
||||
}
|
||||
mSavedJointRot = getSelectedJointWorldRotation();
|
||||
mBoneAxes = computeBoneAxes();
|
||||
mNaturalAlignmentQuat = computeAlignmentQuat(mBoneAxes);
|
||||
}
|
||||
|
||||
void FSManipRotateJoint::setAvatar(LLVOAvatar* avatar)
|
||||
{
|
||||
mAvatar = avatar;
|
||||
if (!avatar)
|
||||
mJoint = nullptr;
|
||||
|
||||
if (mAvatar && mJoint)
|
||||
setJoint(avatar->getJoint(mJoint->getJointNum()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -403,7 +406,7 @@ void FSManipRotateJoint::handleSelect()
|
|||
// Not entirely sure this is needed in the current implementation.
|
||||
if (mJoint)
|
||||
{
|
||||
mSavedJointRot = mJoint->getWorldRotation();
|
||||
mSavedJointRot = getSelectedJointWorldRotation();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -422,15 +425,12 @@ void FSManipRotateJoint::handleSelect()
|
|||
*/
|
||||
bool FSManipRotateJoint::updateVisiblity()
|
||||
{
|
||||
if (!mJoint)
|
||||
{
|
||||
// No joint to manipulate, not visible
|
||||
if (!isAvatarJointSafeToUse())
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!hasMouseCapture())
|
||||
{
|
||||
mRotationCenter = gAgent.getPosGlobalFromAgent( mJoint->getWorldPosition() );
|
||||
mRotationCenter = mAvatar->getPosGlobalFromAgent(mJoint->getWorldPosition());
|
||||
mCamEdgeOn = false;
|
||||
}
|
||||
|
||||
|
|
@ -439,7 +439,7 @@ bool FSManipRotateJoint::updateVisiblity()
|
|||
//Assume that UI scale factor is equivalent for X and Y axis
|
||||
F32 ui_scale_factor = LLUI::getScaleFactor().mV[VX];
|
||||
|
||||
const LLVector3 agent_space_center = gAgent.getPosAgentFromGlobal( mRotationCenter ); // Convert from world/agent to global
|
||||
const LLVector3 agent_space_center = mAvatar->getPosAgentFromGlobal(mRotationCenter); // Convert from world/agent to global
|
||||
|
||||
const auto * viewer_camera = LLViewerCamera::getInstance();
|
||||
visible = viewer_camera->projectPosAgentToScreen(agent_space_center, mCenterScreen );
|
||||
|
|
@ -473,7 +473,6 @@ bool FSManipRotateJoint::updateVisiblity()
|
|||
return visible;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Updates the scale of a specific manipulator part.
|
||||
*
|
||||
|
|
@ -500,21 +499,29 @@ void FSManipRotateJoint::renderRingPass(const RingRenderParams& params, float ra
|
|||
{
|
||||
gGL.pushMatrix();
|
||||
{
|
||||
// If an extra rotation is specified, apply it.
|
||||
if (params.extraRotateAngle != 0.f)
|
||||
{
|
||||
gGL.rotatef(params.extraRotateAngle, params.extraRotateAxis.mV[0],
|
||||
params.extraRotateAxis.mV[1], params.extraRotateAxis.mV[2]);
|
||||
}
|
||||
// If an extra rotation is specified, apply it.
|
||||
if (params.extraRotateAngle != 0.f)
|
||||
{
|
||||
gGL.rotatef(params.extraRotateAngle, params.extraRotateAxis.mV[VX], params.extraRotateAxis.mV[VY], params.extraRotateAxis.mV[VZ]);
|
||||
}
|
||||
// Get the appropriate scale value from mManipulatorScales.
|
||||
float scaleVal = 1.f;
|
||||
switch (params.scaleIndex)
|
||||
{
|
||||
case 0: scaleVal = mManipulatorScales.mV[VX]; break;
|
||||
case 1: scaleVal = mManipulatorScales.mV[VY]; break;
|
||||
case 2: scaleVal = mManipulatorScales.mV[VZ]; break;
|
||||
case 3: scaleVal = mManipulatorScales.mV[VW]; break;
|
||||
default: break;
|
||||
case 0:
|
||||
scaleVal = mManipulatorScales.mV[VX];
|
||||
break;
|
||||
case 1:
|
||||
scaleVal = mManipulatorScales.mV[VY];
|
||||
break;
|
||||
case 2:
|
||||
scaleVal = mManipulatorScales.mV[VZ];
|
||||
break;
|
||||
case 3:
|
||||
scaleVal = mManipulatorScales.mV[VW];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
gGL.scalef(scaleVal, scaleVal, scaleVal);
|
||||
gl_ring(radius, width, params.primaryColor, params.secondaryColor, CIRCLE_STEPS, pass);
|
||||
|
|
@ -552,7 +559,7 @@ void FSManipRotateJoint::renderManipulatorRings(const LLVector3& agent_space_cen
|
|||
|
||||
for (int pass = 0; pass < 2; ++pass)
|
||||
{
|
||||
if( mManipPart == LL_NO_PART || mManipPart == LL_ROT_ROLL || mHighlightedPart == LL_ROT_ROLL)
|
||||
if (mManipPart == LL_NO_PART || mManipPart == LL_ROT_ROLL || mHighlightedPart == LL_ROT_ROLL)
|
||||
{
|
||||
renderCenterSphere( mRadiusMeters);
|
||||
for (auto& ring_params : sRingParams)
|
||||
|
|
@ -565,16 +572,17 @@ void FSManipRotateJoint::renderManipulatorRings(const LLVector3& agent_space_cen
|
|||
}
|
||||
renderRingPass(params, mRadiusMeters, width_meters, pass);
|
||||
}
|
||||
|
||||
if( mManipPart == LL_ROT_ROLL || mHighlightedPart == LL_ROT_ROLL)
|
||||
{
|
||||
static const auto roll_color = LLColor4(1.f,0.65f,0.0f,0.4f);
|
||||
static const auto roll_color = LLColor4(1.f, 0.65f, 0.0f, 0.4f);
|
||||
updateManipulatorScale(mManipPart, mManipulatorScales);
|
||||
gGL.pushMatrix();
|
||||
{
|
||||
// Cancel the rotation applied earlier:
|
||||
LLMatrix4 inv_rot_mat(rotation);
|
||||
inv_rot_mat.invert();
|
||||
gGL.multMatrix((GLfloat*)inv_rot_mat.mMatrix);
|
||||
gGL.multMatrix((GLfloat*)inv_rot_mat.mMatrix);
|
||||
renderCenterCircle( mRadiusMeters*1.2f, roll_color, roll_color );
|
||||
}
|
||||
gGL.popMatrix();
|
||||
|
|
@ -619,7 +627,7 @@ void FSManipRotateJoint::renderCenterCircle(const F32 radius, const LLColor4& no
|
|||
|
||||
LLVector3 rotationAxis = defaultNormal % targetNormal; // Cross product.
|
||||
F32 dot = defaultNormal * targetNormal; // Dot product.
|
||||
F32 angle = acosf(dot) * RAD_TO_DEG; // Convert to degrees.
|
||||
F32 angle = acosf(dot) * RAD_TO_DEG; // Convert to degrees.
|
||||
|
||||
if (rotationAxis.magVec() > 0.001f)
|
||||
{
|
||||
|
|
@ -664,16 +672,15 @@ void FSManipRotateJoint::renderCenterSphere(const F32 radius, const LLColor4& no
|
|||
// Use an average of the manipulator scales when no specific part is selected
|
||||
scale *= (mManipulatorScales.mV[VX] + mManipulatorScales.mV[VY] + mManipulatorScales.mV[VZ] + mManipulatorScales.mV[VW]) / 4.0f;
|
||||
}
|
||||
|
||||
|
||||
gGL.scalef(scale, scale, scale);
|
||||
gSphere.render();
|
||||
|
||||
gGL.flush();
|
||||
gGL.flush();
|
||||
}
|
||||
gGL.popMatrix();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Renders the joint rotation manipulator and associated visual elements.
|
||||
*
|
||||
|
|
@ -697,72 +704,65 @@ void FSManipRotateJoint::renderCenterSphere(const F32 radius, const LLColor4& no
|
|||
*/
|
||||
void FSManipRotateJoint::render()
|
||||
{
|
||||
// Early-out if no joint or avatar.
|
||||
// Needs more something: if they log out while dots on them, asplode
|
||||
if (!mJoint || !mAvatar || mAvatar->isDead())
|
||||
{
|
||||
if (!isAvatarJointSafeToUse())
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// update visibility and rotation center.
|
||||
bool activeJointVisible = updateVisiblity();
|
||||
|
||||
// Setup GL state.
|
||||
LLGLSUIDefault gls_ui;
|
||||
gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep);
|
||||
LLGLDepthTest gls_depth(GL_TRUE);
|
||||
LLGLEnable gl_blend(GL_BLEND);
|
||||
|
||||
|
||||
// Iterate through the avatar's joint map.
|
||||
// If a joint other than the currently selected is highlighted, render a pulsing sphere.
|
||||
// otherwise a small static sphere
|
||||
LLCachedControl<bool> show_joint_markers(gSavedSettings, "FSManipShowJointMarkers", true);
|
||||
LLVector3 jointLocation;
|
||||
for (const auto& entry : getSelectableJoints())
|
||||
{
|
||||
LLJoint* joint = mAvatar->getJoint(std::string(entry));
|
||||
if (!joint)
|
||||
continue;
|
||||
|
||||
// Update the joint's world matrix to ensure its position is current.
|
||||
joint->updateWorldMatrixParent();
|
||||
joint->updateWorldMatrix();
|
||||
|
||||
if( joint == mHighlightedJoint && joint != mJoint )
|
||||
if (joint == mJoint)
|
||||
continue;
|
||||
|
||||
jointLocation = joint->getWorldPosition();
|
||||
if (joint == mHighlightedJoint)
|
||||
{
|
||||
renderPulsingSphere(joint->getWorldPosition());
|
||||
}
|
||||
else if( joint != mJoint )
|
||||
{
|
||||
// Render a static sphere for the joint being manipulated.
|
||||
LLCachedControl<bool> show_joint_markers(gSavedSettings, "FSManipShowJointMarkers", true);
|
||||
if(show_joint_markers)
|
||||
{
|
||||
renderStaticSphere(joint->getWorldPosition(), LLColor4(1.f, 0.5f, 0.f, 0.5f), 0.01f);
|
||||
}
|
||||
renderPulsingSphere(jointLocation);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (show_joint_markers)
|
||||
renderStaticSphere(jointLocation, LLColor4(1.f, 0.5f, 0.f, 0.5f), 0.01f);
|
||||
}
|
||||
|
||||
if (!activeJointVisible)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Update joint world matrices.
|
||||
mJoint->updateWorldMatrixParent();
|
||||
mJoint->updateWorldMatrix();
|
||||
|
||||
const LLQuaternion joint_world_rotation = mJoint->getWorldRotation();
|
||||
|
||||
const LLQuaternion joint_world_rotation = getSelectedJointWorldRotation();
|
||||
const LLQuaternion parentWorldRot = (mJoint->getParent()) ? mJoint->getParent()->getWorldRotation() : LLQuaternion::DEFAULT;
|
||||
|
||||
LLQuaternion currentLocalRot = mJoint->getRotation();
|
||||
|
||||
LLQuaternion rotatedNaturalAlignment = mNaturalAlignmentQuat * currentLocalRot;
|
||||
|
||||
// Compute the final world alignment:
|
||||
LLQuaternion final_world_alignment = rotatedNaturalAlignment * parentWorldRot;
|
||||
|
||||
const LLVector3 agent_space_center = gAgent.getPosAgentFromGlobal(mRotationCenter);
|
||||
const LLVector3 agent_space_center = mAvatar->getPosAgentFromGlobal(mRotationCenter);
|
||||
|
||||
LLCachedControl<bool> use_natural_direction(gSavedSettings, "FSManipRotateJointUseNaturalDirection", true);
|
||||
LLQuaternion active_rotation = use_natural_direction? final_world_alignment : joint_world_rotation;
|
||||
LLCachedControl<bool> use_natural_direction(gSavedSettings, "FSManipRotateJointUseNaturalDirection", true);
|
||||
LLQuaternion active_rotation = use_natural_direction ? final_world_alignment : joint_world_rotation;
|
||||
active_rotation.normalize();
|
||||
|
||||
// Render the manipulator rings in a separate function.
|
||||
gGL.matrixMode(LLRender::MM_MODELVIEW);
|
||||
renderAxes(agent_space_center, mRadiusMeters * 1.5f, active_rotation);
|
||||
|
|
@ -779,13 +779,13 @@ void FSManipRotateJoint::renderAxes(const LLVector3& agent_space_center, F32 siz
|
|||
LLGLDepthTest gls_depth(GL_FALSE);
|
||||
gGL.pushMatrix();
|
||||
gGL.translatef(agent_space_center.mV[VX], agent_space_center.mV[VY], agent_space_center.mV[VZ]);
|
||||
|
||||
|
||||
LLMatrix4 rot_mat(rotation);
|
||||
|
||||
gGL.multMatrix((GLfloat*)rot_mat.mMatrix);
|
||||
|
||||
gGL.begin(LLRender::LINES);
|
||||
|
||||
|
||||
// X-axis (Red)
|
||||
gGL.color4f(1.0f, 0.0f, 0.0f, 1.0f);
|
||||
gGL.vertex3f(-size, 0.0f, 0.0f);
|
||||
|
|
@ -875,9 +875,7 @@ void FSManipRotateJoint::renderNameXYZ(const LLQuaternion& rot)
|
|||
S32 vertical_offset = window_center_y - VERTICAL_OFFSET;
|
||||
|
||||
LLVector3 euler_angles;
|
||||
rot.getEulerAngles(&euler_angles.mV[0],
|
||||
&euler_angles.mV[1],
|
||||
&euler_angles.mV[2]);
|
||||
rot.getEulerAngles(&euler_angles.mV[VX], &euler_angles.mV[VY], &euler_angles.mV[VZ]);
|
||||
euler_angles *= RAD_TO_DEG;
|
||||
for (S32 i = 0; i < 3; ++i)
|
||||
{
|
||||
|
|
@ -925,15 +923,6 @@ void FSManipRotateJoint::renderNameXYZ(const LLQuaternion& rot)
|
|||
base_y += 20.f;
|
||||
renderTextWithShadow(llformat("Joint: %s", mJoint->getName().c_str()), window_center_x - 130.f, base_y, LLColor4(1.f, 0.1f, 1.f, 1.f));
|
||||
renderTextWithShadow(llformat("Manip: %s%c", getManipPartString(mManipPart).c_str(), mCamEdgeOn?'*':' '), window_center_x + 30.f, base_y, LLColor4(1.f, 1.f, .1f, 1.f));
|
||||
if (mManipPart != LL_NO_PART)
|
||||
{
|
||||
LL_INFOS("FSManipRotateJoint") << "Joint: " << mJoint->getName()
|
||||
<< ", Manip: " << getManipPartString(mManipPart)
|
||||
<< ", Quaternion: " << rot
|
||||
<< ", Euler Angles: " << mLastEuler
|
||||
<< ", Delta Angle: " << mLastAngle * RAD_TO_DEG
|
||||
<< LL_ENDL;
|
||||
}
|
||||
}
|
||||
gGL.popMatrix();
|
||||
|
||||
|
|
@ -954,48 +943,46 @@ void FSManipRotateJoint::renderActiveRing( F32 radius, F32 width, const LLColor4
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------
|
||||
// Overriding because the base uses mObjectSelection->getFirstMoveableObject(true)
|
||||
// Not sure we use it though...TBC (see mouse down on part instead)
|
||||
bool FSManipRotateJoint::handleMouseDown(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
if (!mJoint)
|
||||
{
|
||||
if (!isAvatarJointSafeToUse())
|
||||
return false;
|
||||
}
|
||||
|
||||
// Highlight the manipulator as before.
|
||||
highlightManipulators(x, y);
|
||||
|
||||
if (mHighlightedPart != LL_NO_PART)
|
||||
if (mHighlightedPart == LL_NO_PART)
|
||||
return false;
|
||||
|
||||
mManipPart = (EManipPart)mHighlightedPart;
|
||||
|
||||
// Get the joint's center in agent space.
|
||||
LLVector3 agent_space_center = mAvatar->getPosAgentFromGlobal(mRotationCenter);
|
||||
|
||||
// Use the existing function to get the intersection point.
|
||||
LLVector3 intersection = intersectMouseWithSphere(x, y, agent_space_center, mRadiusMeters);
|
||||
|
||||
// Check if the returned intersection is valid.
|
||||
if (intersection.isExactlyZero())
|
||||
{
|
||||
mManipPart = (EManipPart)mHighlightedPart;
|
||||
|
||||
// Get the joint's center in agent space.
|
||||
LLVector3 agent_space_center = gAgent.getPosAgentFromGlobal(mRotationCenter);
|
||||
|
||||
// Use the existing function to get the intersection point.
|
||||
LLVector3 intersection = intersectMouseWithSphere(x, y, agent_space_center, mRadiusMeters);
|
||||
|
||||
// Check if the returned intersection is valid.
|
||||
if (intersection.isExactlyZero())
|
||||
{
|
||||
// Treat this as a "raycast miss" and do not capture the mouse.
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Save the valid intersection point.
|
||||
mInitialIntersection = intersection;
|
||||
// Also store the joint's current rotation.
|
||||
mSavedJointRot = mJoint->getWorldRotation();
|
||||
|
||||
// Capture the mouse for dragging.
|
||||
setMouseCapture(true);
|
||||
return true;
|
||||
}
|
||||
// Treat this as a "raycast miss" and do not capture the mouse.
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Save the valid intersection point.
|
||||
mInitialIntersection = intersection;
|
||||
// Also store the joint's current rotation.
|
||||
mSavedJointRot = getSelectedJointWorldRotation();
|
||||
|
||||
// Capture the mouse for dragging.
|
||||
setMouseCapture(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1017,24 +1004,27 @@ bool FSManipRotateJoint::handleMouseDown(S32 x, S32 y, MASK mask)
|
|||
*/
|
||||
bool FSManipRotateJoint::handleMouseDownOnPart(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
auto * poser = dynamic_cast<FSFloaterPoser*>(LLFloaterReg::findInstance("fs_poser"));
|
||||
// For joint manipulation, require both a valid joint and avatar.
|
||||
if (!isAvatarJointSafeToUse())
|
||||
return false;
|
||||
|
||||
auto* poser = LLFloaterReg::findTypedInstance<FSFloaterPoser>("fs_poser");
|
||||
if (!poser)
|
||||
return false;
|
||||
|
||||
// Determine which ring (axis) is under the mouse, also highlights selectable joints.
|
||||
highlightManipulators(x, y);
|
||||
// For joint manipulation, require both a valid joint and avatar.
|
||||
if (!mJoint || !mAvatar || mAvatar->isDead() || !poser)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
poser->setFocus(true);
|
||||
S32 hit_part = mHighlightedPart;
|
||||
|
||||
// Save the joint’s current world rotation as the basis for the drag.
|
||||
mSavedJointRot = mJoint->getWorldRotation();
|
||||
|
||||
mSavedJointRot = getSelectedJointWorldRotation();
|
||||
mLastSetRotation.set(LLQuaternion());
|
||||
mManipPart = (EManipPart)hit_part;
|
||||
|
||||
// Convert rotation center from global to agent space.
|
||||
LLVector3 agent_space_center = gAgent.getPosAgentFromGlobal(mRotationCenter);
|
||||
LLVector3 agent_space_center = mAvatar->getPosAgentFromGlobal(mRotationCenter);
|
||||
|
||||
// based on mManipPArt (set in highlightmanipulators). decide whether we are constrained or not in the rotation
|
||||
if (mManipPart == LL_ROT_GENERAL)
|
||||
|
|
@ -1098,35 +1088,27 @@ bool FSManipRotateJoint::handleMouseDownOnPart(S32 x, S32 y, MASK mask)
|
|||
// We use mouseUp to update the UI, updating it during the drag is too slow.
|
||||
bool FSManipRotateJoint::handleMouseUp(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
|
||||
auto * poser = dynamic_cast<FSFloaterPoser*>(LLFloaterReg::findInstance("fs_poser"));
|
||||
if (hasMouseCapture())
|
||||
{
|
||||
// Update the UI, by causing it to read back the position of the selected joints and aply those relative to the base rot
|
||||
if (poser && mJoint)
|
||||
{
|
||||
poser->updatePosedBones(mJoint->getName());
|
||||
}
|
||||
|
||||
// Release mouse
|
||||
{
|
||||
setMouseCapture(false);
|
||||
mManipPart = LL_NO_PART;
|
||||
mLastAngle = 0.0f;
|
||||
mLastAngle = 0.0f;
|
||||
mCamEdgeOn = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
else if(mHighlightedJoint)
|
||||
else if (mHighlightedJoint)
|
||||
{
|
||||
auto* poser = dynamic_cast<FSFloaterPoser*>(LLFloaterReg::findInstance("fs_poser"));
|
||||
if (poser)
|
||||
{
|
||||
poser->selectJointByName(mHighlightedJoint->getName());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Does all the hard work of working out what inworld control we are interacting with
|
||||
*
|
||||
|
|
@ -1143,7 +1125,7 @@ void FSManipRotateJoint::highlightManipulators(S32 x, S32 y)
|
|||
mHighlightedPart = LL_NO_PART;
|
||||
// Instead of using mObjectSelection->getFirstMoveableObject(),
|
||||
// simply require that the joint (and the avatar) is valid.
|
||||
if (!mJoint || !mAvatar || mAvatar->isDead())
|
||||
if (!isAvatarJointSafeToUse())
|
||||
{
|
||||
highlightHoverSpheres(x, y);
|
||||
gViewerWindow->setCursor(UI_CURSOR_ARROW);
|
||||
|
|
@ -1153,25 +1135,24 @@ void FSManipRotateJoint::highlightManipulators(S32 x, S32 y)
|
|||
// Decide which rotation to use based on a user toggle.
|
||||
LLCachedControl<bool> use_natural_direction(gSavedSettings, "FSManipRotateJointUseNaturalDirection", true);
|
||||
// Compute the rotation center in agent space.
|
||||
LLVector3 agent_space_rotation_center = gAgent.getPosAgentFromGlobal(mRotationCenter);
|
||||
LLVector3 agent_space_rotation_center = mAvatar->getPosAgentFromGlobal(mRotationCenter);
|
||||
|
||||
// Update joint world matrices.
|
||||
mJoint->updateWorldMatrixParent();
|
||||
mJoint->updateWorldMatrix();
|
||||
|
||||
const LLQuaternion joint_world_rotation = mJoint->getWorldRotation();
|
||||
const LLQuaternion joint_world_rotation = getSelectedJointWorldRotation();
|
||||
|
||||
const LLQuaternion parentWorldRot = (mJoint->getParent()) ? mJoint->getParent()->getWorldRotation() : LLQuaternion::DEFAULT;
|
||||
|
||||
LLQuaternion currentLocalRot = mJoint->getRotation();
|
||||
|
||||
|
||||
LLQuaternion rotatedNaturalAlignment = mNaturalAlignmentQuat * currentLocalRot;
|
||||
rotatedNaturalAlignment.normalize();
|
||||
// Compute the final world alignment:
|
||||
LLQuaternion final_world_alignment = rotatedNaturalAlignment * parentWorldRot;
|
||||
final_world_alignment.normalize();
|
||||
|
||||
|
||||
LLQuaternion joint_rot = use_natural_direction ? final_world_alignment : joint_world_rotation;
|
||||
|
||||
// Compute the three local axes in world space.
|
||||
|
|
@ -1308,14 +1289,18 @@ bool FSManipRotateJoint::handleHover(S32 x, S32 y, MASK mask)
|
|||
{
|
||||
highlightManipulators(x, y);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
LLQuaternion FSManipRotateJoint::dragUnconstrained(S32 x, S32 y)
|
||||
{
|
||||
if (!isAvatarJointSafeToUse())
|
||||
return LLQuaternion();
|
||||
|
||||
// Get the camera position and the joint’s pivot (in agent space)
|
||||
LLVector3 cam = gAgentCamera.getCameraPositionAgent();
|
||||
LLVector3 agent_space_center = gAgent.getPosAgentFromGlobal(mRotationCenter);
|
||||
LLVector3 agent_space_center = mAvatar->getPosAgentFromGlobal(mRotationCenter);
|
||||
|
||||
// Compute the current intersection on the sphere.
|
||||
mMouseCur = intersectMouseWithSphere(x, y, agent_space_center, mRadiusMeters);
|
||||
|
|
@ -1388,27 +1373,29 @@ static LLQuaternion extractTwist(const LLQuaternion& rot, const LLVector3& axis)
|
|||
LLVector3 proj = axis * dot; // proj is now purely along 'axis'
|
||||
|
||||
// Build the “twist” quaternion from (proj, w), then renormalize
|
||||
LLQuaternion twist(proj.mV[VX],
|
||||
proj.mV[VY],
|
||||
proj.mV[VZ],
|
||||
w);
|
||||
LLQuaternion twist(proj.mV[VX], proj.mV[VY], proj.mV[VZ], w);
|
||||
if (w < 0.f)
|
||||
{
|
||||
{
|
||||
twist = -twist;
|
||||
}
|
||||
twist.normalize();
|
||||
return twist;
|
||||
}
|
||||
|
||||
LLQuaternion FSManipRotateJoint::dragConstrained(S32 x, S32 y)
|
||||
{
|
||||
if (!isAvatarJointSafeToUse())
|
||||
return LLQuaternion();
|
||||
|
||||
// Get the constraint axis from our joint manipulator.
|
||||
LLVector3 constraint_axis = getConstraintAxis();
|
||||
LLVector3 agent_space_center = gAgent.getPosAgentFromGlobal(mRotationCenter);
|
||||
LLVector3 agent_space_center = mAvatar->getPosAgentFromGlobal(mRotationCenter);
|
||||
if (mCamEdgeOn)
|
||||
{
|
||||
LLQuaternion freeRot = dragUnconstrained(x, y);
|
||||
return extractTwist(freeRot, constraint_axis);
|
||||
}
|
||||
|
||||
// Project the current mouse position onto the plane defined by the constraint axis.
|
||||
LLVector3 projected_mouse;
|
||||
bool hit = getMousePointOnPlaneAgent(projected_mouse, x, y, agent_space_center, constraint_axis);
|
||||
|
|
@ -1416,6 +1403,7 @@ LLQuaternion FSManipRotateJoint::dragConstrained(S32 x, S32 y)
|
|||
{
|
||||
return LLQuaternion::DEFAULT;
|
||||
}
|
||||
|
||||
projected_mouse -= agent_space_center;
|
||||
projected_mouse.normalize();
|
||||
|
||||
|
|
@ -1424,6 +1412,7 @@ LLQuaternion FSManipRotateJoint::dragConstrained(S32 x, S32 y)
|
|||
initial_proj -= (initial_proj * constraint_axis) * constraint_axis;
|
||||
initial_proj.normalize();
|
||||
|
||||
//float angle = acos(initial_proj * projected_mouse); // angle in (-pi, pi)
|
||||
// Compute the signed angle using atan2.
|
||||
// The numerator is the magnitude of the cross product projected along the constraint axis.
|
||||
float numerator = (initial_proj % projected_mouse) * constraint_axis;
|
||||
|
|
@ -1431,14 +1420,16 @@ LLQuaternion FSManipRotateJoint::dragConstrained(S32 x, S32 y)
|
|||
float denominator = initial_proj * projected_mouse;
|
||||
float angle = atan2(numerator, denominator); // angle in (-pi, pi)
|
||||
mLastAngle = angle;
|
||||
|
||||
return LLQuaternion(angle, constraint_axis);
|
||||
}
|
||||
|
||||
void FSManipRotateJoint::drag(S32 x, S32 y)
|
||||
{
|
||||
if (!updateVisiblity() || !mJoint) return;
|
||||
if (!updateVisiblity())
|
||||
return;
|
||||
|
||||
LLQuaternion delta_rot;
|
||||
LLQuaternion delta_send, delta_rot;
|
||||
if (mManipPart == LL_ROT_GENERAL)
|
||||
{
|
||||
delta_rot = dragUnconstrained(x, y);
|
||||
|
|
@ -1447,10 +1438,31 @@ void FSManipRotateJoint::drag(S32 x, S32 y)
|
|||
{
|
||||
delta_rot = dragConstrained(x, y);
|
||||
}
|
||||
|
||||
// Compose the saved joint rotation with the delta to compute the new world rotation.
|
||||
LLQuaternion new_world_rot = mSavedJointRot * delta_rot;
|
||||
mJoint->setWorldRotation(new_world_rot);
|
||||
|
||||
delta_send.set(delta_rot);
|
||||
delta_send *= ~mLastSetRotation;
|
||||
mLastSetRotation.set(delta_rot);
|
||||
delta_send = mSavedJointRot * delta_send * ~mSavedJointRot;
|
||||
|
||||
switch (mReferenceFrame)
|
||||
{
|
||||
case POSER_FRAME_CAMERA:
|
||||
case POSER_FRAME_AVATAR:
|
||||
delta_send.conjugate();
|
||||
break;
|
||||
|
||||
case POSER_FRAME_WORLD:
|
||||
delta_send.mQ[VX] *= -1;
|
||||
break;
|
||||
|
||||
case POSER_FRAME_BONE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
auto* poser = LLFloaterReg::findTypedInstance<FSFloaterPoser>("fs_poser");
|
||||
if (poser && mJoint)
|
||||
poser->updatePosedBones(mJoint->getName(), delta_send, LLVector3::zero, LLVector3::zero);
|
||||
}
|
||||
|
||||
// set mConstrainedAxis based on mManipParat and returns it too.
|
||||
|
|
@ -1478,10 +1490,10 @@ LLVector3 FSManipRotateJoint::setConstraintAxis()
|
|||
// Transform the local axis into world space using the joint's world rotation.
|
||||
if (mJoint)
|
||||
{
|
||||
LLCachedControl<bool> use_natural_direction(gSavedSettings, "FSManipRotateJointUseNaturalDirection", true);
|
||||
LLCachedControl<bool> use_natural_direction(gSavedSettings, "FSManipRotateJointUseNaturalDirection", true);
|
||||
LLQuaternion active_rotation;
|
||||
if (use_natural_direction)
|
||||
{
|
||||
{
|
||||
// Get the joint's current local rotation.
|
||||
LLQuaternion currentLocalRot = mJoint->getRotation();
|
||||
const LLQuaternion parentWorldRot = (mJoint->getParent()) ? mJoint->getParent()->getWorldRotation() : LLQuaternion::DEFAULT;
|
||||
|
|
@ -1493,12 +1505,41 @@ LLVector3 FSManipRotateJoint::setConstraintAxis()
|
|||
}
|
||||
else
|
||||
{
|
||||
active_rotation = mJoint->getWorldRotation();
|
||||
active_rotation = getSelectedJointWorldRotation();
|
||||
}
|
||||
axis = axis * active_rotation;
|
||||
axis.normalize();
|
||||
}
|
||||
}
|
||||
|
||||
mConstraintAxis = axis;
|
||||
|
||||
return axis;
|
||||
}
|
||||
|
||||
LLQuaternion FSManipRotateJoint::getSelectedJointWorldRotation()
|
||||
{
|
||||
LLQuaternion joinRot;
|
||||
if (!mJoint || !mAvatar)
|
||||
return joinRot;
|
||||
|
||||
auto* poser = dynamic_cast<FSFloaterPoser*>(LLFloaterReg::findInstance("fs_poser"));
|
||||
if (!poser)
|
||||
return joinRot;
|
||||
|
||||
return poser->getManipGimbalRotation(mJoint->getName());
|
||||
}
|
||||
|
||||
bool FSManipRotateJoint::isAvatarJointSafeToUse()
|
||||
{
|
||||
if (!mJoint || !mAvatar)
|
||||
return false;
|
||||
|
||||
if (mAvatar->isDead() || !mAvatar->isFullyLoaded())
|
||||
{
|
||||
setAvatar(nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* @file fsmaniproatejoint.h
|
||||
* @file fsmaniprotatejoint.h
|
||||
* @brief custom manipulator for rotating joints
|
||||
*
|
||||
* $LicenseInfo:firstyear=2024&license=viewerlgpl$
|
||||
|
|
@ -32,11 +32,22 @@
|
|||
#include "llmaniprotate.h"
|
||||
|
||||
class LLJoint;
|
||||
class LLVOAvatar; // or LLVOAvatarSelf, etc.
|
||||
class LLVOAvatar; // for LLVOAvatarSelf, etc.
|
||||
|
||||
/// <summary>
|
||||
/// A set of reference frames for presenting the gimbal within.
|
||||
/// </summary>
|
||||
typedef enum E_PoserReferenceFrame
|
||||
{
|
||||
POSER_FRAME_BONE = 0, // frame is the bone the gimbal is centered on
|
||||
POSER_FRAME_WORLD = 1, // frame is world North-South-East-West-Up-Down
|
||||
POSER_FRAME_AVATAR = 2, // frame is mPelvis rotation
|
||||
POSER_FRAME_CAMERA = 3, // frame is defined by vector of camera position to bone position
|
||||
} E_PoserReferenceFrame;
|
||||
|
||||
namespace {
|
||||
const F32 AXIS_ONTO_CAM_TOLERANCE = cos( 85.f * DEG_TO_RAD ); // cos() is not constexpr til c++26
|
||||
constexpr F32 RADIUS_PIXELS = 100.f; // size in screen space
|
||||
constexpr F32 RADIUS_PIXELS = 100.f; // size in screen space
|
||||
constexpr S32 CIRCLE_STEPS = 100;
|
||||
constexpr F32 CIRCLE_STEP_SIZE = 2.0f * F_PI / CIRCLE_STEPS;
|
||||
constexpr F32 SQ_RADIUS = RADIUS_PIXELS * RADIUS_PIXELS;
|
||||
|
|
@ -74,11 +85,25 @@ public:
|
|||
FSManipRotateJoint(LLToolComposite* composite);
|
||||
virtual ~FSManipRotateJoint() {}
|
||||
static std::string getManipPartString(EManipPart part);
|
||||
// Called to designate which joint we are going to manipulate.
|
||||
|
||||
/// <summary>
|
||||
/// Sets the joint we are going to manipulate.
|
||||
/// </summary>
|
||||
/// <param name="joint">The joint to interact with.</param>
|
||||
void setJoint(LLJoint* joint);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the avatar the manip should interact with.
|
||||
/// </summary>
|
||||
/// <param name="avatar">The avatar to interact with.</param>
|
||||
void setAvatar(LLVOAvatar* avatar);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the reference frame for the manipulator.
|
||||
/// </summary>
|
||||
/// <param name="avatar">The E_PoserReferenceFrame to use.</param>
|
||||
void setReferenceFrame(const E_PoserReferenceFrame frame) { mReferenceFrame = frame; };
|
||||
|
||||
// Overrides
|
||||
void handleSelect() override;
|
||||
bool updateVisiblity() override;
|
||||
|
|
@ -138,8 +163,13 @@ private:
|
|||
void renderRingPass(const RingRenderParams& params, float radius, float width, int pass);
|
||||
void renderAxes(const LLVector3& center, F32 size, const LLQuaternion& rotation);
|
||||
|
||||
bool isAvatarJointSafeToUse();
|
||||
LLQuaternion getSelectedJointWorldRotation();
|
||||
|
||||
float mLastAngle = 0.f;
|
||||
LLVector3 mConstraintAxis;
|
||||
E_PoserReferenceFrame mReferenceFrame = POSER_FRAME_BONE;
|
||||
LLQuaternion mLastSetRotation;
|
||||
};
|
||||
|
||||
#endif // FS_MANIP_ROTATE_JOINT_H
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@
|
|||
|
||||
#include "fsparticipantlist.h"
|
||||
#include "llagent.h"
|
||||
#include "llchatentry.h"
|
||||
#include "fsfloaterim.h"
|
||||
#include "llimview.h"
|
||||
#include "llspeakers.h"
|
||||
|
||||
|
|
@ -88,9 +90,18 @@ void FSPanelGroupControlPanel::setSessionId(const LLUUID& session_id)
|
|||
return;
|
||||
|
||||
mParticipantList = new FSParticipantList(speaker_manager, getChild<LLAvatarList>("grp_speakers_list"), true,false);
|
||||
if (mParticipantList)
|
||||
{
|
||||
mParticipantList->setInsertMentionCallback(boost::bind(&FSPanelGroupControlPanel::insertMentionAtCursor, this, _1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FSPanelGroupControlPanel::insertMentionAtCursor(const LLUUID& avatar_id)
|
||||
{
|
||||
FSFloaterIM::getInstance(getSessionId())->findChild<LLChatEntry>("chat_editor")->insertMentionAtCursor("secondlife:///app/agent/" + avatar_id.asString() + "/mention");
|
||||
}
|
||||
|
||||
uuid_vec_t FSPanelGroupControlPanel::getParticipants() const
|
||||
{
|
||||
return mParticipantList->getAvatarIds();
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ public:
|
|||
void draw() override;
|
||||
|
||||
uuid_vec_t getParticipants() const override;
|
||||
void insertMentionAtCursor(const LLUUID& url);
|
||||
|
||||
protected:
|
||||
LLUUID mGroupID;
|
||||
|
|
|
|||
|
|
@ -929,6 +929,23 @@ void FSPanelLogin::loadLoginPage()
|
|||
params["noversionpopup"] = "true";
|
||||
}
|
||||
|
||||
// Splash screen settings
|
||||
static const std::pair<std::string, std::string> mappings[] = {
|
||||
{"FSSplashScreenHideTopBar", "hidetopbar"},
|
||||
{"FSSplashScreenHideBlogs", "hideblogs"},
|
||||
{"FSSplashScreenHideDestinations", "hidedestinations"},
|
||||
{"FSSplashScreenUseGrayMode", "usegraymode"},
|
||||
{"FSSplashScreenUseHighContrast", "usehighcontrast"},
|
||||
{"FSSplashScreenUseAllCaps", "useallcaps"},
|
||||
{"FSSplashScreenUseLargerFonts", "uselargerfonts"},
|
||||
{"FSSplashScreenNoTransparency", "notransparency"},
|
||||
};
|
||||
|
||||
for (const auto &m : mappings)
|
||||
{
|
||||
params[m.second] = gSavedSettings.getBOOL(m.first) ? "1" : "0";
|
||||
}
|
||||
|
||||
// Make an LLURI with this augmented info
|
||||
std::string url = login_page.scheme().empty()? login_page.authority() : login_page.scheme() + "://" + login_page.authority();
|
||||
LLURI login_uri(LLURI::buildHTTP(url,
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
#include "llnotificationsutil.h"
|
||||
#include "lloutputmonitorctrl.h"
|
||||
#include "llspeakers.h"
|
||||
#include "llurlaction.h"
|
||||
#include "llviewercontrol.h"
|
||||
#include "llviewermenu.h"
|
||||
#include "llvoiceclient.h"
|
||||
|
|
@ -69,6 +70,7 @@ FSParticipantList::FSParticipantList(LLSpeakerMgr* data_source,
|
|||
mParticipantListMenu(NULL),
|
||||
mExcludeAgent(exclude_agent),
|
||||
mValidateSpeakerCallback(NULL),
|
||||
mInsertMentionCallback(NULL),
|
||||
mConvType(CONV_UNKNOWN)
|
||||
{
|
||||
mSpeakerAddListener = new SpeakerAddListener(*this);
|
||||
|
|
@ -301,6 +303,11 @@ void FSParticipantList::setValidateSpeakerCallback(validate_speaker_callback_t c
|
|||
mValidateSpeakerCallback = cb;
|
||||
}
|
||||
|
||||
void FSParticipantList::setInsertMentionCallback(insert_mention_callback_t cb)
|
||||
{
|
||||
mInsertMentionCallback = cb;
|
||||
}
|
||||
|
||||
void FSParticipantList::update()
|
||||
{
|
||||
mSpeakerMgr->update(true);
|
||||
|
|
@ -530,6 +537,9 @@ LLContextMenu* FSParticipantList::FSParticipantListMenu::createMenu()
|
|||
|
||||
registrar.add("ParticipantList.ModerateVoice", boost::bind(&FSParticipantList::FSParticipantListMenu::moderateVoice, this, _2));
|
||||
|
||||
registrar.add("Mention.CopyURI", boost::bind(&FSParticipantList::FSParticipantListMenu::copyURLToClipboard, this, mUUIDs.front()));
|
||||
registrar.add("Mention.Chat", boost::bind(&FSParticipantList::FSParticipantListMenu::insertMentionAtCursor, this, mUUIDs.front()));
|
||||
|
||||
enable_registrar.add("ParticipantList.EnableItem", boost::bind(&FSParticipantList::FSParticipantListMenu::enableContextMenuItem, this, _2));
|
||||
enable_registrar.add("ParticipantList.EnableItem.Moderate", boost::bind(&FSParticipantList::FSParticipantListMenu::enableModerateContextMenuItem, this, _2));
|
||||
enable_registrar.add("ParticipantList.CheckItem", boost::bind(&FSParticipantList::FSParticipantListMenu::checkContextMenuItem, this, _2));
|
||||
|
|
@ -556,6 +566,19 @@ LLContextMenu* FSParticipantList::FSParticipantListMenu::createMenu()
|
|||
return main_menu;
|
||||
}
|
||||
|
||||
void FSParticipantList::FSParticipantListMenu::copyURLToClipboard(const LLUUID& avatar_id)
|
||||
{
|
||||
LLUrlAction::copyURLToClipboard("secondlife:///app/agent/" + mUUIDs.front().asString() + "/mention");
|
||||
}
|
||||
|
||||
void FSParticipantList::FSParticipantListMenu::insertMentionAtCursor(const LLUUID& avatar_id)
|
||||
{
|
||||
if (mParent.mInsertMentionCallback)
|
||||
{
|
||||
mParent.mInsertMentionCallback(avatar_id);
|
||||
}
|
||||
}
|
||||
|
||||
void FSParticipantList::FSParticipantListMenu::show(LLView* spawning_view, const uuid_vec_t& uuids, S32 x, S32 y)
|
||||
{
|
||||
if (uuids.size() == 0) return;
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ public:
|
|||
};
|
||||
|
||||
typedef boost::function<bool (const LLUUID& speaker_id)> validate_speaker_callback_t;
|
||||
typedef boost::function<void (const LLUUID& speaker_id)> insert_mention_callback_t;
|
||||
|
||||
FSParticipantList(LLSpeakerMgr* data_source,
|
||||
LLAvatarList* avatar_list,
|
||||
|
|
@ -94,6 +95,7 @@ public:
|
|||
* @see onAddItemEvent()
|
||||
*/
|
||||
void setValidateSpeakerCallback(validate_speaker_callback_t cb);
|
||||
void setInsertMentionCallback(insert_mention_callback_t cb);
|
||||
|
||||
EConversationType const getType() const { return mConvType; }
|
||||
|
||||
|
|
@ -240,6 +242,10 @@ protected:
|
|||
static void confirmMuteAllCallback(const LLSD& notification, const LLSD& response);
|
||||
|
||||
void handleAddToContactSet();
|
||||
|
||||
// mentions support
|
||||
void copyURLToClipboard(const LLUUID& avatar_id);
|
||||
void insertMentionAtCursor(const LLUUID& avatar_id);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -300,6 +306,8 @@ private:
|
|||
LLPointer<LLAvatarItemRecentSpeakerComparator> mSortByRecentSpeakers;
|
||||
validate_speaker_callback_t mValidateSpeakerCallback;
|
||||
|
||||
insert_mention_callback_t mInsertMentionCallback;
|
||||
|
||||
EConversationType mConvType;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include "fsposeranimator.h"
|
||||
#include "llcharacter.h"
|
||||
#include "llagent.h"
|
||||
#include "llagentcamera.h"
|
||||
#include "fsposingmotion.h"
|
||||
|
||||
std::map<LLUUID, LLAssetID> FSPoserAnimator::sAvatarIdToRegisteredAnimationId;
|
||||
|
|
@ -52,6 +53,25 @@ bool FSPoserAnimator::isPosingAvatarJoint(LLVOAvatar* avatar, const FSPoserJoint
|
|||
return posingMotion->currentlyPosingJoint(jointPose);
|
||||
}
|
||||
|
||||
bool FSPoserAnimator::hasJointBeenChanged(LLVOAvatar* avatar, const FSPoserJoint& joint)
|
||||
{
|
||||
if (!isAvatarSafeToUse(avatar))
|
||||
return false;
|
||||
|
||||
FSPosingMotion* posingMotion = getPosingMotion(avatar);
|
||||
if (!posingMotion)
|
||||
return false;
|
||||
|
||||
if (posingMotion->isStopped())
|
||||
return false;
|
||||
|
||||
FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName());
|
||||
if (!jointPose)
|
||||
return false;
|
||||
|
||||
return jointPose->getJointModified();
|
||||
}
|
||||
|
||||
void FSPoserAnimator::setPosingAvatarJoint(LLVOAvatar* avatar, const FSPoserJoint& joint, bool shouldPose)
|
||||
{
|
||||
if (!isAvatarSafeToUse(avatar))
|
||||
|
|
@ -212,7 +232,8 @@ LLVector3 FSPoserAnimator::getJointPosition(LLVOAvatar* avatar, const FSPoserJoi
|
|||
return jointPose->getPublicPosition();
|
||||
}
|
||||
|
||||
void FSPoserAnimator::setJointPosition(LLVOAvatar* avatar, const FSPoserJoint* joint, const LLVector3& position, E_BoneDeflectionStyles style)
|
||||
void FSPoserAnimator::setJointPosition(LLVOAvatar* avatar, const FSPoserJoint* joint, const LLVector3& position, E_PoserReferenceFrame frame,
|
||||
E_BoneDeflectionStyles style)
|
||||
{
|
||||
if (!isAvatarSafeToUse(avatar))
|
||||
return;
|
||||
|
|
@ -231,7 +252,8 @@ void FSPoserAnimator::setJointPosition(LLVOAvatar* avatar, const FSPoserJoint* j
|
|||
if (!jointPose)
|
||||
return;
|
||||
|
||||
LLVector3 positionDelta = jointPose->getPublicPosition() - position;
|
||||
LLVector3 jointPosition = jointPose->getPublicPosition();
|
||||
LLVector3 positionDelta = jointPosition - position;
|
||||
|
||||
switch (style)
|
||||
{
|
||||
|
|
@ -239,13 +261,13 @@ void FSPoserAnimator::setJointPosition(LLVOAvatar* avatar, const FSPoserJoint* j
|
|||
case MIRROR_DELTA:
|
||||
case SYMPATHETIC_DELTA:
|
||||
case SYMPATHETIC:
|
||||
jointPose->setPublicPosition(position);
|
||||
jointPose->setPublicPosition(jointPosition - positionDelta);
|
||||
break;
|
||||
|
||||
case DELTAMODE:
|
||||
case NONE:
|
||||
default:
|
||||
jointPose->setPublicPosition(position);
|
||||
jointPose->setPublicPosition(jointPosition - positionDelta);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -406,6 +428,7 @@ void FSPoserAnimator::setAllAvatarStartingRotationsToZero(LLVOAvatar* avatar)
|
|||
return;
|
||||
|
||||
posingMotion->setAllRotationsToZeroAndClearUndo();
|
||||
mPosingState.purgeMotionStates(avatar);
|
||||
|
||||
for (size_t index = 0; index != PoserJoints.size(); ++index)
|
||||
{
|
||||
|
|
@ -420,10 +443,9 @@ void FSPoserAnimator::setAllAvatarStartingRotationsToZero(LLVOAvatar* avatar)
|
|||
|
||||
posingMotion->setJointBvhLock(jointPose, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void FSPoserAnimator::recaptureJoint(LLVOAvatar* avatar, const FSPoserJoint& joint, E_BoneAxisTranslation translation, S32 negation)
|
||||
void FSPoserAnimator::recaptureJoint(LLVOAvatar* avatar, const FSPoserJoint& joint)
|
||||
{
|
||||
if (!isAvatarSafeToUse(avatar))
|
||||
return;
|
||||
|
|
@ -440,8 +462,9 @@ void FSPoserAnimator::recaptureJoint(LLVOAvatar* avatar, const FSPoserJoint& joi
|
|||
setPosingAvatarJoint(avatar, joint, true);
|
||||
}
|
||||
|
||||
void FSPoserAnimator::recaptureJointAsDelta(LLVOAvatar* avatar, const FSPoserJoint* joint, bool resetBaseRotationToZero,
|
||||
E_BoneDeflectionStyles style)
|
||||
void FSPoserAnimator::updateJointFromManip(LLVOAvatar* avatar, const FSPoserJoint* joint, bool resetBaseRotationToZero,
|
||||
E_BoneDeflectionStyles style, E_PoserReferenceFrame frame, const LLQuaternion& rotation,
|
||||
const LLVector3& position, const LLVector3& scale)
|
||||
{
|
||||
if (!isAvatarSafeToUse(avatar))
|
||||
return;
|
||||
|
|
@ -454,27 +477,34 @@ void FSPoserAnimator::recaptureJointAsDelta(LLVOAvatar* avatar, const FSPoserJoi
|
|||
if (!jointPose)
|
||||
return;
|
||||
|
||||
LLQuaternion deltaRot = jointPose->recaptureJointAsDelta(resetBaseRotationToZero);
|
||||
LLQuaternion framedRotation = changeToRotationFrame(avatar, rotation, frame, jointPose);
|
||||
jointPose->setPublicRotation(resetBaseRotationToZero, framedRotation * jointPose->getPublicRotation());
|
||||
|
||||
deRotateWorldLockedDescendants(joint, posingMotion, deltaRot);
|
||||
deRotateWorldLockedDescendants(joint, posingMotion, framedRotation);
|
||||
|
||||
if (style == NONE || style == DELTAMODE)
|
||||
return;
|
||||
|
||||
auto oppositePoserJoint = getPoserJointByName(joint->mirrorJointName());
|
||||
FSJointPose* oppositeJointPose = posingMotion->getJointPoseByJointName(joint->mirrorJointName());
|
||||
if (!oppositeJointPose)
|
||||
return;
|
||||
|
||||
LLQuaternion mirroredRotation = LLQuaternion(-framedRotation.mQ[VX], framedRotation.mQ[VY], -framedRotation.mQ[VZ], framedRotation.mQ[VW]);
|
||||
switch (style)
|
||||
{
|
||||
case SYMPATHETIC:
|
||||
case SYMPATHETIC_DELTA:
|
||||
oppositeJointPose->cloneRotationFrom(jointPose);
|
||||
oppositeJointPose->setPublicRotation(resetBaseRotationToZero, framedRotation * oppositeJointPose->getPublicRotation());
|
||||
if (oppositePoserJoint)
|
||||
deRotateWorldLockedDescendants(oppositePoserJoint, posingMotion, framedRotation);
|
||||
break;
|
||||
|
||||
case MIRROR:
|
||||
case MIRROR_DELTA:
|
||||
oppositeJointPose->mirrorRotationFrom(jointPose);
|
||||
oppositeJointPose->setPublicRotation(resetBaseRotationToZero, mirroredRotation * oppositeJointPose->getPublicRotation());
|
||||
if (oppositePoserJoint)
|
||||
deRotateWorldLockedDescendants(oppositePoserJoint, posingMotion, mirroredRotation);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -482,6 +512,54 @@ void FSPoserAnimator::recaptureJointAsDelta(LLVOAvatar* avatar, const FSPoserJoi
|
|||
}
|
||||
}
|
||||
|
||||
LLQuaternion FSPoserAnimator::getManipGimbalRotation(LLVOAvatar* avatar, const FSPoserJoint* joint, E_PoserReferenceFrame frame)
|
||||
{
|
||||
LLQuaternion globalRot(-1.f, 0.f, 0.f, 0.f);
|
||||
if (frame == POSER_FRAME_WORLD)
|
||||
return globalRot;
|
||||
|
||||
if (!joint)
|
||||
return globalRot;
|
||||
|
||||
if (!isAvatarSafeToUse(avatar))
|
||||
return globalRot;
|
||||
|
||||
if (frame == POSER_FRAME_AVATAR)
|
||||
{
|
||||
LLJoint* pelvis = avatar->getJoint("mPelvis");
|
||||
if (pelvis)
|
||||
return pelvis->getWorldRotation();
|
||||
|
||||
return globalRot;
|
||||
}
|
||||
|
||||
FSPosingMotion* posingMotion = getPosingMotion(avatar);
|
||||
if (!posingMotion)
|
||||
return globalRot;
|
||||
|
||||
FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint->jointName());
|
||||
if (!jointPose)
|
||||
return globalRot;
|
||||
|
||||
LLJoint* llJoint = jointPose->getJointState()->getJoint();
|
||||
if (!llJoint)
|
||||
return globalRot;
|
||||
|
||||
if (frame == POSER_FRAME_BONE)
|
||||
return llJoint->getWorldRotation();
|
||||
|
||||
LLVector3 skyward(0.f, 0.f, 1.f);
|
||||
LLVector3 left(1.f, 0.f, 0.f);
|
||||
LLVector3 up, jointToCameraPosition, jointPosition;
|
||||
jointPosition = llJoint->getWorldPosition();
|
||||
jointToCameraPosition = jointPosition - gAgentCamera.getCameraPositionAgent();
|
||||
jointToCameraPosition.normalize();
|
||||
left.setVec(skyward % jointToCameraPosition);
|
||||
up.setVec(jointToCameraPosition % left);
|
||||
|
||||
return LLQuaternion(jointToCameraPosition, left, up);
|
||||
}
|
||||
|
||||
LLVector3 FSPoserAnimator::getJointExportRotation(LLVOAvatar* avatar, const FSPoserJoint& joint, bool lockWholeAvatar) const
|
||||
{
|
||||
auto rotation = getJointRotation(avatar, joint, SWAP_NOTHING, NEGATE_NOTHING);
|
||||
|
|
@ -525,12 +603,13 @@ LLVector3 FSPoserAnimator::getJointRotation(LLVOAvatar* avatar, const FSPoserJoi
|
|||
if (!jointPose)
|
||||
return vec3;
|
||||
|
||||
return translateRotationFromQuaternion(translation, negation, jointPose->getPublicRotation());
|
||||
return translateRotationFromQuaternion(jointPose, translation, negation, jointPose->getPublicRotation());
|
||||
}
|
||||
|
||||
void FSPoserAnimator::setJointRotation(LLVOAvatar* avatar, const FSPoserJoint* joint, const LLVector3& absRotation,
|
||||
const LLVector3& deltaRotation, E_BoneDeflectionStyles deflectionStyle,
|
||||
E_BoneAxisTranslation translation, S32 negation, bool resetBaseRotationToZero, E_RotationStyle rotationStyle)
|
||||
const LLVector3& deltaRotation, E_BoneDeflectionStyles style, E_PoserReferenceFrame frame,
|
||||
E_BoneAxisTranslation translation, S32 negation, bool resetBaseRotationToZero,
|
||||
E_RotationStyle rotationStyle)
|
||||
{
|
||||
if (!isAvatarSafeToUse(avatar))
|
||||
return;
|
||||
|
|
@ -545,13 +624,15 @@ void FSPoserAnimator::setJointRotation(LLVOAvatar* avatar, const FSPoserJoint* j
|
|||
if (!jointPose)
|
||||
return;
|
||||
|
||||
LLQuaternion absRot = translateRotationToQuaternion(translation, negation, absRotation);
|
||||
LLQuaternion deltaRot = translateRotationToQuaternion(translation, negation, deltaRotation);
|
||||
switch (deflectionStyle)
|
||||
bool translationRequiresDelta = frame != POSER_FRAME_BONE;
|
||||
|
||||
LLQuaternion absRot = translateRotationToQuaternion(avatar, jointPose, frame, translation, negation, absRotation);
|
||||
LLQuaternion deltaRot = translateRotationToQuaternion(avatar, jointPose, frame, translation, negation, deltaRotation);
|
||||
switch (style)
|
||||
{
|
||||
case SYMPATHETIC:
|
||||
case MIRROR:
|
||||
if (rotationStyle == DELTAIC_ROT)
|
||||
if (rotationStyle == DELTAIC_ROT || translationRequiresDelta)
|
||||
jointPose->setPublicRotation(resetBaseRotationToZero, deltaRot * jointPose->getPublicRotation());
|
||||
else
|
||||
jointPose->setPublicRotation(resetBaseRotationToZero, absRot);
|
||||
|
|
@ -570,7 +651,7 @@ void FSPoserAnimator::setJointRotation(LLVOAvatar* avatar, const FSPoserJoint* j
|
|||
|
||||
case NONE:
|
||||
default:
|
||||
if (rotationStyle == DELTAIC_ROT)
|
||||
if (rotationStyle == DELTAIC_ROT || translationRequiresDelta)
|
||||
jointPose->setPublicRotation(resetBaseRotationToZero, deltaRot * jointPose->getPublicRotation());
|
||||
else
|
||||
jointPose->setPublicRotation(resetBaseRotationToZero, absRot);
|
||||
|
|
@ -586,8 +667,8 @@ void FSPoserAnimator::setJointRotation(LLVOAvatar* avatar, const FSPoserJoint* j
|
|||
if (!oppositeJointPose)
|
||||
return;
|
||||
|
||||
LLQuaternion inv_quat = LLQuaternion(-deltaRot.mQ[VX], deltaRot.mQ[VY], -deltaRot.mQ[VZ], deltaRot.mQ[VW]);
|
||||
switch (deflectionStyle)
|
||||
LLQuaternion mirroredRotation = LLQuaternion(-deltaRot.mQ[VX], deltaRot.mQ[VY], -deltaRot.mQ[VZ], deltaRot.mQ[VW]);
|
||||
switch (style)
|
||||
{
|
||||
case SYMPATHETIC:
|
||||
oppositeJointPose->cloneRotationFrom(jointPose);
|
||||
|
|
@ -604,13 +685,13 @@ void FSPoserAnimator::setJointRotation(LLVOAvatar* avatar, const FSPoserJoint* j
|
|||
case MIRROR:
|
||||
oppositeJointPose->mirrorRotationFrom(jointPose);
|
||||
if (oppositePoserJoint)
|
||||
deRotateWorldLockedDescendants(oppositePoserJoint, posingMotion, inv_quat);
|
||||
deRotateWorldLockedDescendants(oppositePoserJoint, posingMotion, mirroredRotation);
|
||||
break;
|
||||
|
||||
case MIRROR_DELTA:
|
||||
oppositeJointPose->setPublicRotation(resetBaseRotationToZero, inv_quat * oppositeJointPose->getPublicRotation());
|
||||
oppositeJointPose->setPublicRotation(resetBaseRotationToZero, mirroredRotation * oppositeJointPose->getPublicRotation());
|
||||
if (oppositePoserJoint)
|
||||
deRotateWorldLockedDescendants(oppositePoserJoint, posingMotion, inv_quat);
|
||||
deRotateWorldLockedDescendants(oppositePoserJoint, posingMotion, mirroredRotation);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -709,8 +790,9 @@ void FSPoserAnimator::flipEntirePose(LLVOAvatar* avatar)
|
|||
}
|
||||
}
|
||||
|
||||
// from the UI to the bone, the inverse translation, the un-swap, the backwards
|
||||
LLQuaternion FSPoserAnimator::translateRotationToQuaternion(E_BoneAxisTranslation translation, S32 negation, LLVector3 rotation)
|
||||
// from the UI to the bone. Bone rotations we store are relative to the skeleton (or to T-Pose, if you want to visualize).
|
||||
LLQuaternion FSPoserAnimator::translateRotationToQuaternion(LLVOAvatar* avatar, FSJointPose* joint, E_PoserReferenceFrame frame,
|
||||
E_BoneAxisTranslation translation, S32 negation, LLVector3 rotation)
|
||||
{
|
||||
if (negation & NEGATE_ALL)
|
||||
{
|
||||
|
|
@ -728,7 +810,7 @@ LLQuaternion FSPoserAnimator::translateRotationToQuaternion(E_BoneAxisTranslatio
|
|||
rotation.mV[VZ] *= -1;
|
||||
}
|
||||
|
||||
LLMatrix3 rot_mat;
|
||||
LLMatrix3 rot_mat;
|
||||
switch (translation)
|
||||
{
|
||||
case SWAP_YAW_AND_ROLL:
|
||||
|
|
@ -761,11 +843,63 @@ LLQuaternion FSPoserAnimator::translateRotationToQuaternion(E_BoneAxisTranslatio
|
|||
rot_quat = LLQuaternion(rot_mat) * rot_quat;
|
||||
rot_quat.normalize();
|
||||
|
||||
rot_quat = changeToRotationFrame(avatar, rot_quat, frame, joint);
|
||||
|
||||
return rot_quat;
|
||||
}
|
||||
|
||||
LLQuaternion FSPoserAnimator::changeToRotationFrame(LLVOAvatar* avatar, const LLQuaternion& rotation, E_PoserReferenceFrame frame, FSJointPose* joint)
|
||||
{
|
||||
if (!joint || !avatar)
|
||||
return rotation;
|
||||
|
||||
LLJoint* pelvis = avatar->getJoint("mPelvis");
|
||||
if (!pelvis)
|
||||
return rotation;
|
||||
|
||||
LLVector3 skyward(0.f, 0.f, 1.f);
|
||||
LLVector3 left(1.f, 0.f, 0.f);
|
||||
LLVector3 forwards(0.f, 1.f, 0.f);
|
||||
LLVector3 up, jointToCameraPosition, jointPosition;
|
||||
LLQuaternion worldRotOfWorld(forwards, left, skyward);
|
||||
LLQuaternion differenceInWorldRot, rotDiffInChildFrame, worldRotOfPelvis, worldRotOfCamera;
|
||||
LLQuaternion worldRotOfThisJoint = joint->getJointState()->getJoint()->getWorldRotation();
|
||||
|
||||
switch (frame)
|
||||
{
|
||||
case POSER_FRAME_WORLD:
|
||||
differenceInWorldRot = worldRotOfThisJoint * ~worldRotOfWorld;
|
||||
break;
|
||||
|
||||
case POSER_FRAME_AVATAR:
|
||||
worldRotOfPelvis = pelvis->getWorldRotation();
|
||||
differenceInWorldRot = worldRotOfThisJoint * ~worldRotOfPelvis;
|
||||
break;
|
||||
|
||||
case POSER_FRAME_CAMERA:
|
||||
jointPosition = joint->getJointState()->getJoint()->getWorldPosition();
|
||||
jointToCameraPosition = jointPosition - gAgentCamera.getCameraPositionAgent();
|
||||
jointToCameraPosition.normalize();
|
||||
left.setVec(skyward % jointToCameraPosition);
|
||||
up.setVec(jointToCameraPosition % left);
|
||||
|
||||
worldRotOfCamera = LLQuaternion(jointToCameraPosition, left, up);
|
||||
differenceInWorldRot = worldRotOfThisJoint * ~worldRotOfCamera;
|
||||
break;
|
||||
|
||||
case POSER_FRAME_BONE:
|
||||
default:
|
||||
return rotation;
|
||||
}
|
||||
|
||||
rotDiffInChildFrame = differenceInWorldRot * rotation * ~differenceInWorldRot;
|
||||
rotDiffInChildFrame.conjugate();
|
||||
|
||||
return rotDiffInChildFrame;
|
||||
}
|
||||
|
||||
// from the bone to the UI; this is the 'forwards' use of the enum
|
||||
LLVector3 FSPoserAnimator::translateRotationFromQuaternion(E_BoneAxisTranslation translation, S32 negation, const LLQuaternion& rotation) const
|
||||
LLVector3 FSPoserAnimator::translateRotationFromQuaternion(FSJointPose* joint, E_BoneAxisTranslation translation, S32 negation, const LLQuaternion& rotation) const
|
||||
{
|
||||
LLVector3 vec3;
|
||||
|
||||
|
|
@ -833,7 +967,8 @@ LLVector3 FSPoserAnimator::getJointScale(LLVOAvatar* avatar, const FSPoserJoint&
|
|||
return jointPose->getPublicScale();
|
||||
}
|
||||
|
||||
void FSPoserAnimator::setJointScale(LLVOAvatar* avatar, const FSPoserJoint* joint, const LLVector3& scale, E_BoneDeflectionStyles style)
|
||||
void FSPoserAnimator::setJointScale(LLVOAvatar* avatar, const FSPoserJoint* joint, const LLVector3& scale, E_PoserReferenceFrame frame,
|
||||
E_BoneDeflectionStyles style)
|
||||
{
|
||||
if (!isAvatarSafeToUse(avatar))
|
||||
return;
|
||||
|
|
@ -852,25 +987,46 @@ void FSPoserAnimator::setJointScale(LLVOAvatar* avatar, const FSPoserJoint* join
|
|||
if (!jointPose)
|
||||
return;
|
||||
|
||||
jointPose->setPublicScale(scale);
|
||||
FSJointPose* oppositeJointPose = posingMotion->getJointPoseByJointName(joint->mirrorJointName());
|
||||
if (!oppositeJointPose)
|
||||
return;
|
||||
LLVector3 jointScale = jointPose->getPublicScale();
|
||||
LLVector3 scaleDelta = jointScale - scale;
|
||||
|
||||
switch (style)
|
||||
{
|
||||
case SYMPATHETIC:
|
||||
case MIRROR:
|
||||
case SYMPATHETIC_DELTA:
|
||||
case MIRROR_DELTA:
|
||||
oppositeJointPose->setPublicScale(scale);
|
||||
case SYMPATHETIC_DELTA:
|
||||
case SYMPATHETIC:
|
||||
jointPose->setPublicScale(jointScale - scaleDelta);
|
||||
break;
|
||||
|
||||
case DELTAMODE:
|
||||
case NONE:
|
||||
default:
|
||||
jointPose->setPublicScale(jointScale - scaleDelta);
|
||||
return;
|
||||
}
|
||||
|
||||
FSJointPose* oppositeJointPose = posingMotion->getJointPoseByJointName(joint->mirrorJointName());
|
||||
if (!oppositeJointPose)
|
||||
return;
|
||||
|
||||
LLVector3 oppositeJointScale = oppositeJointPose->getPublicScale();
|
||||
|
||||
switch (style)
|
||||
{
|
||||
case MIRROR:
|
||||
case MIRROR_DELTA:
|
||||
oppositeJointPose->setPublicScale(oppositeJointScale + scaleDelta);
|
||||
break;
|
||||
|
||||
case SYMPATHETIC_DELTA:
|
||||
case SYMPATHETIC:
|
||||
oppositeJointPose->setPublicScale(oppositeJointScale - scaleDelta);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool FSPoserAnimator::tryGetJointSaveVectors(LLVOAvatar* avatar, const FSPoserJoint& joint, LLVector3* rot, LLVector3* pos,
|
||||
|
|
@ -914,7 +1070,7 @@ void FSPoserAnimator::loadJointRotation(LLVOAvatar* avatar, const FSPoserJoint*
|
|||
|
||||
jointPose->purgeUndoQueue();
|
||||
|
||||
LLQuaternion rot = translateRotationToQuaternion(SWAP_NOTHING, NEGATE_NOTHING, rotation);
|
||||
LLQuaternion rot = translateRotationToQuaternion(avatar, jointPose, POSER_FRAME_BONE, SWAP_NOTHING, NEGATE_NOTHING, rotation);
|
||||
jointPose->setPublicRotation(setBaseToZero, rot);
|
||||
}
|
||||
|
||||
|
|
@ -963,13 +1119,21 @@ void FSPoserAnimator::loadJointScale(LLVOAvatar* avatar, const FSPoserJoint* joi
|
|||
}
|
||||
}
|
||||
|
||||
bool FSPoserAnimator::loadPosingState(LLVOAvatar* avatar, LLSD pose)
|
||||
bool FSPoserAnimator::loadPosingState(LLVOAvatar* avatar, bool ignoreOwnership, LLSD pose)
|
||||
{
|
||||
if (!isAvatarSafeToUse(avatar))
|
||||
return false;
|
||||
|
||||
mPosingState.purgeMotionStates(avatar);
|
||||
mPosingState.restoreMotionStates(avatar, pose);
|
||||
mPosingState.restoreMotionStates(avatar, ignoreOwnership, pose);
|
||||
|
||||
return applyStatesToPosingMotion(avatar);
|
||||
}
|
||||
|
||||
bool FSPoserAnimator::applyStatesToPosingMotion(LLVOAvatar* avatar)
|
||||
{
|
||||
if (!isAvatarSafeToUse(avatar))
|
||||
return false;
|
||||
|
||||
FSPosingMotion* posingMotion = getPosingMotion(avatar);
|
||||
if (!posingMotion)
|
||||
|
|
@ -1007,9 +1171,9 @@ void FSPoserAnimator::applyJointMirrorToBaseRotations(FSPosingMotion* posingMoti
|
|||
}
|
||||
}
|
||||
|
||||
void FSPoserAnimator::savePosingState(LLVOAvatar* avatar, LLSD* saveRecord)
|
||||
void FSPoserAnimator::savePosingState(LLVOAvatar* avatar, bool ignoreOwnership, LLSD* saveRecord)
|
||||
{
|
||||
mPosingState.writeMotionStates(avatar, saveRecord);
|
||||
mPosingState.writeMotionStates(avatar, ignoreOwnership, saveRecord);
|
||||
}
|
||||
|
||||
const FSPoserAnimator::FSPoserJoint* FSPoserAnimator::getPoserJointByName(const std::string& jointName) const
|
||||
|
|
@ -1023,6 +1187,39 @@ const FSPoserAnimator::FSPoserJoint* FSPoserAnimator::getPoserJointByName(const
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
const FSPoserAnimator::FSPoserJoint* FSPoserAnimator::getPoserJointByNumber(LLVOAvatar* avatar, const S32 jointNumber) const
|
||||
{
|
||||
if (!avatar)
|
||||
return nullptr;
|
||||
|
||||
FSPosingMotion* posingMotion = getPosingMotion(avatar);
|
||||
if (!posingMotion)
|
||||
return nullptr;
|
||||
|
||||
FSJointPose* parentJoint = posingMotion->getJointPoseByJointNumber(jointNumber);
|
||||
if (!parentJoint)
|
||||
return nullptr;
|
||||
|
||||
return getPoserJointByName(parentJoint->jointName());
|
||||
}
|
||||
|
||||
bool FSPoserAnimator::tryGetJointNumber(LLVOAvatar* avatar, const FSPoserJoint &poserJoint, S32& jointNumber)
|
||||
{
|
||||
if (!avatar)
|
||||
return false;
|
||||
|
||||
FSPosingMotion* posingMotion = getPosingMotion(avatar);
|
||||
if (!posingMotion)
|
||||
return false;
|
||||
|
||||
FSJointPose* parentJoint = posingMotion->getJointPoseByJointName(poserJoint.jointName());
|
||||
if (!parentJoint)
|
||||
return false;
|
||||
|
||||
jointNumber = parentJoint->getJointNumber();
|
||||
return jointNumber >= 0;
|
||||
}
|
||||
|
||||
bool FSPoserAnimator::tryPosingAvatar(LLVOAvatar* avatar)
|
||||
{
|
||||
if (!isAvatarSafeToUse(avatar))
|
||||
|
|
@ -1038,7 +1235,6 @@ bool FSPoserAnimator::tryPosingAvatar(LLVOAvatar* avatar)
|
|||
gAgent.stopFidget();
|
||||
|
||||
mPosingState.captureMotionStates(avatar);
|
||||
|
||||
avatar->startDefaultMotions();
|
||||
avatar->startMotion(posingMotion->motionId());
|
||||
|
||||
|
|
@ -1048,7 +1244,7 @@ bool FSPoserAnimator::tryPosingAvatar(LLVOAvatar* avatar)
|
|||
return false;
|
||||
}
|
||||
|
||||
void FSPoserAnimator::updatePosingState(LLVOAvatar* avatar, std::vector<FSPoserAnimator::FSPoserJoint*> jointsRecaptured)
|
||||
void FSPoserAnimator::updatePosingState(LLVOAvatar* avatar, const std::vector<FSPoserAnimator::FSPoserJoint*>& jointsRecaptured)
|
||||
{
|
||||
if (!avatar)
|
||||
return;
|
||||
|
|
@ -1057,14 +1253,20 @@ void FSPoserAnimator::updatePosingState(LLVOAvatar* avatar, std::vector<FSPoserA
|
|||
if (!posingMotion)
|
||||
return;
|
||||
|
||||
std::string jointNamesRecaptured;
|
||||
std::vector<S32> jointNumbersRecaptured;
|
||||
for (auto item : jointsRecaptured)
|
||||
jointNamesRecaptured += item->jointName();
|
||||
{
|
||||
auto poserJoint = posingMotion->getJointPoseByJointName(item->jointName());
|
||||
if (!poserJoint)
|
||||
continue;
|
||||
|
||||
mPosingState.updateMotionStates(avatar, posingMotion, jointNamesRecaptured);
|
||||
jointNumbersRecaptured.push_back(poserJoint->getJointNumber());
|
||||
}
|
||||
|
||||
mPosingState.updateMotionStates(avatar, posingMotion, jointNumbersRecaptured);
|
||||
}
|
||||
|
||||
void FSPoserAnimator::stopPosingAvatar(LLVOAvatar *avatar)
|
||||
void FSPoserAnimator::stopPosingAvatar(LLVOAvatar* avatar)
|
||||
{
|
||||
if (!avatar || avatar->isDead())
|
||||
return;
|
||||
|
|
@ -1128,7 +1330,7 @@ bool FSPoserAnimator::isAvatarSafeToUse(LLVOAvatar* avatar) const
|
|||
return true;
|
||||
}
|
||||
|
||||
int FSPoserAnimator::getChildJointDepth(const FSPoserJoint* joint, int depth) const
|
||||
int FSPoserAnimator::getChildJointDepth(const FSPoserJoint* joint, S32 depth) const
|
||||
{
|
||||
size_t numberOfBvhChildNodes = joint->bvhChildren().size();
|
||||
if (numberOfBvhChildNodes < 1)
|
||||
|
|
@ -1138,7 +1340,7 @@ int FSPoserAnimator::getChildJointDepth(const FSPoserJoint* joint, int depth) co
|
|||
|
||||
for (size_t index = 0; index != numberOfBvhChildNodes; ++index)
|
||||
{
|
||||
auto nextJoint = getPoserJointByName(joint->bvhChildren()[index]);
|
||||
auto nextJoint = getPoserJointByName(joint->bvhChildren().at(index));
|
||||
if (!nextJoint)
|
||||
continue;
|
||||
|
||||
|
|
@ -1162,7 +1364,7 @@ void FSPoserAnimator::deRotateWorldLockedDescendants(const FSPoserJoint* joint,
|
|||
|
||||
for (size_t index = 0; index != numberOfBvhChildNodes; ++index)
|
||||
{
|
||||
auto nextJoint = getPoserJointByName(joint->bvhChildren()[index]);
|
||||
auto nextJoint = getPoserJointByName(joint->bvhChildren().at(index));
|
||||
if (!nextJoint)
|
||||
continue;
|
||||
|
||||
|
|
@ -1193,7 +1395,7 @@ void FSPoserAnimator::deRotateJointOrFirstLockedChild(const FSPoserJoint* joint,
|
|||
|
||||
for (size_t index = 0; index != numberOfBvhChildNodes; ++index)
|
||||
{
|
||||
auto nextJoint = getPoserJointByName(joint->bvhChildren()[index]);
|
||||
auto nextJoint = getPoserJointByName(joint->bvhChildren().at(index));
|
||||
if (!nextJoint)
|
||||
continue;
|
||||
|
||||
|
|
@ -1209,7 +1411,7 @@ void FSPoserAnimator::undoOrRedoWorldLockedDescendants(const FSPoserJoint& joint
|
|||
|
||||
for (size_t index = 0; index != numberOfBvhChildNodes; ++index)
|
||||
{
|
||||
auto nextJoint = getPoserJointByName(joint.bvhChildren()[index]);
|
||||
auto nextJoint = getPoserJointByName(joint.bvhChildren().at(index));
|
||||
if (!nextJoint)
|
||||
continue;
|
||||
|
||||
|
|
@ -1219,6 +1421,9 @@ void FSPoserAnimator::undoOrRedoWorldLockedDescendants(const FSPoserJoint& joint
|
|||
|
||||
void FSPoserAnimator::undoOrRedoJointOrFirstLockedChild(const FSPoserJoint& joint, FSPosingMotion* posingMotion, bool redo)
|
||||
{
|
||||
if (!posingMotion)
|
||||
return;
|
||||
|
||||
FSJointPose* jointPose = posingMotion->getJointPoseByJointName(joint.jointName());
|
||||
if (!jointPose)
|
||||
return;
|
||||
|
|
@ -1239,7 +1444,7 @@ void FSPoserAnimator::undoOrRedoJointOrFirstLockedChild(const FSPoserJoint& join
|
|||
|
||||
for (size_t index = 0; index != numberOfBvhChildNodes; ++index)
|
||||
{
|
||||
auto nextJoint = getPoserJointByName(joint.bvhChildren()[index]);
|
||||
auto nextJoint = getPoserJointByName(joint.bvhChildren().at(index));
|
||||
if (!nextJoint)
|
||||
continue;
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include "fsposingmotion.h"
|
||||
#include "fsposestate.h"
|
||||
#include "llvoavatar.h"
|
||||
#include "fsmaniprotatejoint.h"
|
||||
|
||||
/// <summary>
|
||||
/// Describes how we will cluster the joints/bones/thingos.
|
||||
|
|
@ -360,31 +361,31 @@ public:
|
|||
{ "mSpine4", "", MISC, { "mChest", }, "-0.205 0.015 0.000" },
|
||||
|
||||
// Collision Volumes
|
||||
{ "HEAD", "", COL_VOLUMES },
|
||||
{ "NECK", "", COL_VOLUMES },
|
||||
{ "L_CLAVICLE", "R_CLAVICLE", COL_VOLUMES },
|
||||
{ "R_CLAVICLE", "L_CLAVICLE", COL_VOLUMES, {}, "", "", true },
|
||||
{ "CHEST", "", COL_VOLUMES },
|
||||
{ "LEFT_PEC", "RIGHT_PEC", COL_VOLUMES },
|
||||
{ "RIGHT_PEC", "LEFT_PEC", COL_VOLUMES, {}, "", "", true },
|
||||
{ "UPPER_BACK", "", COL_VOLUMES },
|
||||
{ "LEFT_HANDLE", "RIGHT_HANDLE", COL_VOLUMES },
|
||||
{ "RIGHT_HANDLE", "LEFT_HANDLE", COL_VOLUMES, {}, "", "", true },
|
||||
{ "BELLY", "", COL_VOLUMES },
|
||||
{ "PELVIS", "", COL_VOLUMES },
|
||||
{ "BUTT", "", COL_VOLUMES },
|
||||
{ "L_UPPER_ARM", "R_UPPER_ARM", COL_VOLUMES },
|
||||
{ "R_UPPER_ARM", "L_UPPER_ARM", COL_VOLUMES, {}, "", "", true },
|
||||
{ "L_LOWER_ARM", "R_LOWER_ARM", COL_VOLUMES },
|
||||
{ "R_LOWER_ARM", "L_LOWER_ARM", COL_VOLUMES, {}, "", "", true },
|
||||
{ "L_HAND", "R_HAND", COL_VOLUMES },
|
||||
{ "R_HAND", "L_HAND", COL_VOLUMES, {}, "", "", true },
|
||||
{ "L_UPPER_LEG", "R_UPPER_LEG", COL_VOLUMES },
|
||||
{ "R_UPPER_LEG", "L_UPPER_LEG", COL_VOLUMES, {}, "", "", true },
|
||||
{ "L_LOWER_LEG", "R_LOWER_LEG", COL_VOLUMES },
|
||||
{ "R_LOWER_LEG", "L_LOWER_LEG", COL_VOLUMES, {}, "", "", true },
|
||||
{ "L_FOOT", "R_FOOT", COL_VOLUMES },
|
||||
{ "R_FOOT", "L_FOOT", COL_VOLUMES, {}, "", "", true },
|
||||
{ "HEAD", "", COL_VOLUMES, {}, "0 0.07 0.02", "0.000 0.100 0.000" },
|
||||
{ "NECK", "", COL_VOLUMES, {}, "0 0.02 0.0", "0.000 0.080 0.000" },
|
||||
{ "L_CLAVICLE", "R_CLAVICLE", COL_VOLUMES, {}, "0 0.02 0.02", "0.1 0.0 0.0" },
|
||||
{ "R_CLAVICLE", "L_CLAVICLE", COL_VOLUMES, {}, "0 0.02 0.02", "-0.1 0.0 0.0", true },
|
||||
{ "CHEST", "", COL_VOLUMES, {}, "0 0.07 0.028", "0.000 0.152 -0.096" },
|
||||
{ "LEFT_PEC", "RIGHT_PEC", COL_VOLUMES, {}, "0.082 0.042 0.119", "0.000 -0.006 0.080" },
|
||||
{ "RIGHT_PEC", "LEFT_PEC", COL_VOLUMES, {}, "-0.082 0.042 0.119", "0.000 -0.006 0.080", true },
|
||||
{ "UPPER_BACK", "", COL_VOLUMES, {}, "0.0 0.017 0.0", "0.0 0.0 -0.100" },
|
||||
{ "LEFT_HANDLE", "RIGHT_HANDLE", COL_VOLUMES, {}, "0.10 0.058 0.0", "0.100 0.000 0.000" },
|
||||
{ "RIGHT_HANDLE", "LEFT_HANDLE", COL_VOLUMES, {}, "-0.10 0.058 0.0", "-0.100 0.000 0.000", true },
|
||||
{ "BELLY", "", COL_VOLUMES, {}, "0 0.04 0.028", "0.000 0.094 0.028" },
|
||||
{ "PELVIS", "", COL_VOLUMES, {}, "0 -0.02 -0.01", "0.000 0.095 0.030" },
|
||||
{ "BUTT", "", COL_VOLUMES, {}, "0 -0.1 -0.06", "0.000 0.000 -0.100" },
|
||||
{ "L_UPPER_ARM", "R_UPPER_ARM", COL_VOLUMES, {}, "0.12 0.01 0.0", "0.130 -0.003 0.000" },
|
||||
{ "R_UPPER_ARM", "L_UPPER_ARM", COL_VOLUMES, {}, "-0.12 0.01 0.0", "-0.130 -0.003 0.000", true },
|
||||
{ "L_LOWER_ARM", "R_LOWER_ARM", COL_VOLUMES, {}, "0.1 0.0 0.0", "0.100 -0.001 0.000" },
|
||||
{ "R_LOWER_ARM", "L_LOWER_ARM", COL_VOLUMES, {}, "-0.1 0.0 0.0", "-0.100 -0.001 0.000", true },
|
||||
{ "L_HAND", "R_HAND", COL_VOLUMES, {}, "0.05 0.0 0.01", "0.049 -0.001 0.005" },
|
||||
{ "R_HAND", "L_HAND", COL_VOLUMES, {}, "-0.05 0.0 0.01", "-0.049 -0.001 0.005", true },
|
||||
{ "L_UPPER_LEG", "R_UPPER_LEG", COL_VOLUMES, {}, "-0.05 -0.22 -0.02", "0.000 -0.200 0.000" },
|
||||
{ "R_UPPER_LEG", "L_UPPER_LEG", COL_VOLUMES, {}, "0.05 -0.22 -0.02", "0.000 -0.200 0.000", true },
|
||||
{ "L_LOWER_LEG", "R_LOWER_LEG", COL_VOLUMES, {}, "0.0 -0.2 -0.02", "0.000 -0.150 -0.010" },
|
||||
{ "R_LOWER_LEG", "L_LOWER_LEG", COL_VOLUMES, {}, "0.0 -0.2 -0.02", "0.000 -0.150 -0.010", true },
|
||||
{ "L_FOOT", "R_FOOT", COL_VOLUMES, {}, "0.0 -0.041 0.077", "0.000 -0.026 0.089" },
|
||||
{ "R_FOOT", "L_FOOT", COL_VOLUMES, {}, "0.0 -0.041 0.077", "0.000 -0.026 0.089", true },
|
||||
};
|
||||
|
||||
public:
|
||||
|
|
@ -395,6 +396,20 @@ public:
|
|||
/// <returns>The matching joint if found, otherwise nullptr</returns>
|
||||
const FSPoserJoint* getPoserJointByName(const std::string& jointName) const;
|
||||
|
||||
/// <summary>
|
||||
/// Get a PoserJoint case-insensitive-matching the supplied name.
|
||||
/// </summary>
|
||||
/// <param name="jointNumber">The name of the joint to match.</param>
|
||||
/// <returns>The matching joint if found, otherwise nullptr</returns>
|
||||
const FSPoserJoint* getPoserJointByNumber(LLVOAvatar* avatar, const S32 jointNumber) const;
|
||||
|
||||
/// <summary>
|
||||
/// Get a PoserJoint by its LLJoint number.
|
||||
/// </summary>
|
||||
/// <param name="jointNumber">The name of the joint to match.</param>
|
||||
/// <returns>The matching joint if found, otherwise nullptr</returns>
|
||||
bool tryGetJointNumber(LLVOAvatar* avatar, const FSPoserJoint &poserJoint, S32& jointNumber);
|
||||
|
||||
/// <summary>
|
||||
/// Tries to start posing the supplied avatar.
|
||||
/// </summary>
|
||||
|
|
@ -423,6 +438,14 @@ public:
|
|||
/// <returns>True if this is joint is being posed for the supplied avatar, otherwise false.</returns>
|
||||
bool isPosingAvatarJoint(LLVOAvatar* avatar, const FSPoserJoint& joint);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the supplied PoserJoint for the supplied avatar has been modified this session, even if all change has been reverted.
|
||||
/// </summary>
|
||||
/// <param name="avatar">The avatar having the joint to which we refer.</param>
|
||||
/// <param name="joint">The joint being queried for.</param>
|
||||
/// <returns>True if this is joint has been changed while posing even if the change has been reverted or undone, otherwise false.</returns>
|
||||
bool hasJointBeenChanged(LLVOAvatar* avatar, const FSPoserJoint& joint);
|
||||
|
||||
/// <summary>
|
||||
/// Sets whether the supplied PoserJoint for the supplied avatar should be posed.
|
||||
/// </summary>
|
||||
|
|
@ -479,8 +502,10 @@ public:
|
|||
/// <param name="avatar">The avatar whose joint is to be set.</param>
|
||||
/// <param name="joint">The joint to set.</param>
|
||||
/// <param name="position">The position to set the joint to.</param>
|
||||
/// <param name="frame">The frame to translate the position to.</param>
|
||||
/// <param name="style">Any ancilliary action to be taken with the change to be made.</param>
|
||||
void setJointPosition(LLVOAvatar* avatar, const FSPoserJoint* joint, const LLVector3& position, E_BoneDeflectionStyles style);
|
||||
void setJointPosition(LLVOAvatar* avatar, const FSPoserJoint* joint, const LLVector3& position, E_PoserReferenceFrame frame,
|
||||
E_BoneDeflectionStyles style);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the rotation of a joint for the supplied avatar.
|
||||
|
|
@ -506,6 +531,15 @@ public:
|
|||
/// </remarks>
|
||||
LLVector3 getJointExportRotation(LLVOAvatar* avatar, const FSPoserJoint& joint, bool lockWholeAvatar) const;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the rotation suitable for the Manip gimbal for the supplied avatar and joint.
|
||||
/// </summary>
|
||||
/// <param name="avatar">The avatar having the Manip gimbal placed upon it.</param>
|
||||
/// <param name="joint">The joint on the avatar where the manip should be placed.</param>
|
||||
/// <param name="frame">The frame of reference for the gimbal.</param>
|
||||
/// <returns>The rotation to set the gimbal to.</returns>
|
||||
LLQuaternion getManipGimbalRotation(LLVOAvatar* avatar, const FSPoserJoint* joint, E_PoserReferenceFrame frame);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the rotation of a joint for the supplied avatar.
|
||||
/// </summary>
|
||||
|
|
@ -518,8 +552,9 @@ public:
|
|||
/// <param name="negation">The style of negation to apply to the set.</param>
|
||||
/// <param name="resetBaseRotationToZero">Whether to set the base rotation to zero on setting the rotation.</param>
|
||||
/// <param name="rotationStyle">Whether to apply the supplied rotation as a delta to the supplied joint.</param>
|
||||
void setJointRotation(LLVOAvatar* avatar, const FSPoserJoint* joint, const LLVector3& absRotation, const LLVector3& deltaRotation, E_BoneDeflectionStyles style,
|
||||
E_BoneAxisTranslation translation, S32 negation, bool resetBaseRotationToZero, E_RotationStyle rotationStyle);
|
||||
void setJointRotation(LLVOAvatar* avatar, const FSPoserJoint* joint, const LLVector3& absRotation, const LLVector3& deltaRotation,
|
||||
E_BoneDeflectionStyles style, E_PoserReferenceFrame frame, E_BoneAxisTranslation translation, S32 negation,
|
||||
bool resetBaseRotationToZero, E_RotationStyle rotationStyle);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the scale of a joint for the supplied avatar.
|
||||
|
|
@ -535,8 +570,10 @@ public:
|
|||
/// <param name="avatar">The avatar whose joint is to be set.</param>
|
||||
/// <param name="joint">The joint to set.</param>
|
||||
/// <param name="scale">The scale to set the joint to.</param>
|
||||
/// <param name="frame">The frame to translate the position to.</param>
|
||||
/// <param name="style">Any ancilliary action to be taken with the change to be made.</param>
|
||||
void setJointScale(LLVOAvatar* avatar, const FSPoserJoint* joint, const LLVector3& scale, E_BoneDeflectionStyles style);
|
||||
void setJointScale(LLVOAvatar* avatar, const FSPoserJoint* joint, const LLVector3& scale, E_PoserReferenceFrame frame,
|
||||
E_BoneDeflectionStyles style);
|
||||
|
||||
/// <summary>
|
||||
/// Reflects the joint with its opposite if it has one, or just mirror the rotation of itself.
|
||||
|
|
@ -564,9 +601,7 @@ public:
|
|||
/// </summary>
|
||||
/// <param name="avatar">The avatar whose joint is to be recaptured.</param>
|
||||
/// <param name="joint">The joint to recapture.</param>
|
||||
/// <param name="translation">The axial translation form the supplied joint.</param>
|
||||
/// <param name="negation">The style of negation to apply to the recapture.</param>
|
||||
void recaptureJoint(LLVOAvatar* avatar, const FSPoserJoint& joint, E_BoneAxisTranslation translation, S32 negation);
|
||||
void recaptureJoint(LLVOAvatar* avatar, const FSPoserJoint& joint);
|
||||
|
||||
/// <summary>
|
||||
/// Recaptures any change in joint state.
|
||||
|
|
@ -575,7 +610,11 @@ public:
|
|||
/// <param name="joint">The joint to recapture.</param>
|
||||
/// <param name="resetBaseRotationToZero">Whether to set the base rotation to zero on setting the rotation.</param>
|
||||
/// <param name="style">Any ancilliary action to be taken with the change to be made.</param>
|
||||
void recaptureJointAsDelta(LLVOAvatar* avatar, const FSPoserJoint* joint, bool resetBaseRotationToZero, E_BoneDeflectionStyles style);
|
||||
/// <param name="rotation">The rotation of the supplied joint.</param>
|
||||
/// <param name="position">The position of the supplied joint.</param>
|
||||
/// <param name="scale">The scale of the supplied joint.</param>
|
||||
void updateJointFromManip(LLVOAvatar* avatar, const FSPoserJoint* joint, bool resetBaseRotationToZero, E_BoneDeflectionStyles style,
|
||||
E_PoserReferenceFrame frame, const LLQuaternion& rotation, const LLVector3& position, const LLVector3& scale);
|
||||
|
||||
/// <summary>
|
||||
/// Sets all of the joint rotations of the supplied avatar to zero.
|
||||
|
|
@ -711,6 +750,7 @@ public:
|
|||
/// Loads the posing state (base rotations) to the supplied avatars posing-motion, from the supplied record.
|
||||
/// </summary>
|
||||
/// <param name="avatar">That avatar whose posing state should be loaded.</param>
|
||||
/// <param name="ignoreOwnership">Whether to ignore ownership. For use when reading a local file.</param>
|
||||
/// <param name="pose">The record to read the posing state from.</param>
|
||||
/// <returns>True if the pose loaded successfully, otherwise false.</returns>
|
||||
/// <remarks>
|
||||
|
|
@ -718,32 +758,29 @@ public:
|
|||
/// it can take several frames for the animation to be loaded and ready.
|
||||
/// It may therefore be necessary to attempt this several times.
|
||||
/// </remarks>
|
||||
bool loadPosingState(LLVOAvatar* avatar, LLSD pose);
|
||||
bool loadPosingState(LLVOAvatar* avatar, bool ignoreOwnership, LLSD pose);
|
||||
|
||||
/// <summary>
|
||||
/// Applies the posing states to the posing motion for the supplied avatar.
|
||||
/// </summary>
|
||||
/// <param name="avatar">That avatar whose posing state should be loaded.</param>
|
||||
/// <returns>True if the state applied successfully, otherwise false.</returns>
|
||||
bool applyStatesToPosingMotion(LLVOAvatar* avatar);
|
||||
|
||||
/// <summary>
|
||||
/// Adds the posing state for the supplied avatar to the supplied record.
|
||||
/// </summary>
|
||||
/// <param name="avatar">That avatar whose posing state should be written.</param>
|
||||
/// <param name="ignoreOwnership">Whether to ignore ownership while saving.</param>
|
||||
/// <param name="saveRecord">The record to write the posing state to.</param>
|
||||
void savePosingState(LLVOAvatar* avatar, LLSD* saveRecord);
|
||||
void savePosingState(LLVOAvatar* avatar, bool ignoreOwnership, LLSD* saveRecord);
|
||||
|
||||
/// <summary>
|
||||
/// Purges and recaptures the pose state for the supplied avatar.
|
||||
/// </summary>
|
||||
/// <param name="avatar">The avatar whose pose state is to be recapture.</param>
|
||||
/// <param name="jointsRecaptured">The joints which were recaptured.</param>
|
||||
void updatePosingState(LLVOAvatar* avatar, std::vector<FSPoserAnimator::FSPoserJoint*> jointsRecaptured);
|
||||
|
||||
/// <summary>
|
||||
/// Add a new posing state, or updates the matching posing state with the supplied data.
|
||||
/// </summary>
|
||||
/// <param name="avatar">The avatar the posing state is intended for.</param>
|
||||
/// <param name="animId">The ID of the animation.</param>
|
||||
/// <param name="updateTime">The frame-time of the animation.</param>
|
||||
/// <param name="jointNames">The names of the joints, if any, the animation should specifically be applied to.</param>
|
||||
/// <param name="captureOrder">The capture order.</param>
|
||||
/// <returns>True if the posing state was added or changed by the update data, otherwise false.</returns>
|
||||
bool addOrUpdatePosingState(LLVOAvatar* avatar, LLUUID animId, F32 updateTime, std::string jointNames, int captureOrder);
|
||||
void updatePosingState(LLVOAvatar* avatar, const std::vector<FSPoserAnimator::FSPoserJoint*>& jointsRecaptured);
|
||||
|
||||
/// <summary>
|
||||
/// Traverses the joints and applies reversals to the base rotations if needed.
|
||||
|
|
@ -755,14 +792,19 @@ public:
|
|||
void applyJointMirrorToBaseRotations(FSPosingMotion* posingMotion);
|
||||
|
||||
private:
|
||||
/// <summary>
|
||||
/// Translates a rotation vector from the UI to a Quaternion for the bone.
|
||||
/// This also performs the axis-swapping the UI needs for up/down/left/right to make sense.
|
||||
/// </summary>
|
||||
/// <param name="translation">The axis translation to perform.</param>
|
||||
/// <param name="rotation">The rotation to transform to quaternion.</param>
|
||||
/// <returns>The rotation quaternion.</returns>
|
||||
LLQuaternion translateRotationToQuaternion(E_BoneAxisTranslation translation, S32 negation, LLVector3 rotation);
|
||||
/// <summary>
|
||||
/// Translates the supplied rotation vector from UI to a Quaternion for the bone.
|
||||
/// Also performs the axis-swapping and other transformations for up/down/left/right to make sense.
|
||||
/// </summary>
|
||||
/// <param name="avatar">The avatar whose joint is being manipulated.</param>
|
||||
/// <param name="joint">The joint which is being altered.</param>
|
||||
/// <param name="frame">The frame of reference the translation should be performed in.</param>
|
||||
/// <param name="translation">The axis translation to perform.</param>
|
||||
/// <param name="negation">The style of axis-negation.</param>
|
||||
/// <param name="rotation">The rotation to translate and transform to quaternion.</param>
|
||||
/// <returns>The translated rotation quaternion.</returns>
|
||||
LLQuaternion translateRotationToQuaternion(LLVOAvatar* avatar, FSJointPose* joint, E_PoserReferenceFrame frame,
|
||||
E_BoneAxisTranslation translation, S32 negation, LLVector3 rotation);
|
||||
|
||||
/// <summary>
|
||||
/// Translates a bone-rotation quaternion to a vector usable easily on the UI.
|
||||
|
|
@ -770,7 +812,7 @@ public:
|
|||
/// <param name="translation">The axis translation to perform.</param>
|
||||
/// <param name="rotation">The rotation to transform to matrix.</param>
|
||||
/// <returns>The rotation vector.</returns>
|
||||
LLVector3 translateRotationFromQuaternion(E_BoneAxisTranslation translation, S32 negation, const LLQuaternion& rotation) const;
|
||||
LLVector3 translateRotationFromQuaternion(FSJointPose* joint, E_BoneAxisTranslation translation, S32 negation, const LLQuaternion& rotation) const;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a posing motion for the supplied avatar.
|
||||
|
|
@ -803,7 +845,7 @@ public:
|
|||
/// <param name="joint">The joint to determine the depth for.</param>
|
||||
/// <param name="depth">The depth of the supplied joint.</param>
|
||||
/// <returns>The number of generations of descendents the joint has, if none, then zero.</returns>
|
||||
int getChildJointDepth(const FSPoserJoint* joint, int depth) const;
|
||||
int getChildJointDepth(const FSPoserJoint* joint, S32 depth) const;
|
||||
|
||||
/// <summary>
|
||||
/// Derotates the first world-locked child joint to the supplied joint.
|
||||
|
|
@ -844,6 +886,20 @@ public:
|
|||
/// <param name="redo">Whether to redo the edit, otherwise the edit is undone.</param>
|
||||
void undoOrRedoJointOrFirstLockedChild(const FSPoserJoint& joint, FSPosingMotion* posingMotion, bool redo);
|
||||
|
||||
/// <summary>
|
||||
/// Converts the supplied rotation into the desired frame.
|
||||
/// </summary>
|
||||
/// <param name="avatar">The avatar owning the supplied joint.</param>
|
||||
/// <param name="rotation">The rotation to convert.</param>
|
||||
/// <param name="frame">The frame to translate the rotation to.</param>
|
||||
/// <param name="joint">The joint whose rotation is being changed.</param>
|
||||
/// <remarks>
|
||||
/// Input rotations have no implicit frame: it's just a rotation and ordinarily applied, inherits the joint's rotational framing.
|
||||
/// This method imposes a framing upon the supplied rotation, meaning user input is considered as relative to something like
|
||||
/// 'the world', 'avatar pelvis' or the position of the camera relative to the joint.
|
||||
/// </remarks>
|
||||
LLQuaternion changeToRotationFrame(LLVOAvatar* avatar, const LLQuaternion& rotation, E_PoserReferenceFrame frame, FSJointPose* joint);
|
||||
|
||||
/// <summary>
|
||||
/// Maps the avatar's ID to the animation registered to them.
|
||||
/// Thus we start/stop the same animation, and get/set the same rotations etc.
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
std::map<LLUUID, std::vector<FSPoseState::fsMotionState>> FSPoseState::sMotionStates;
|
||||
std::map<LLUUID, int> FSPoseState::sCaptureOrder;
|
||||
std::map<LLUUID, bool> FSPoseState::sMotionStatesOwnedByMe;
|
||||
|
||||
void FSPoseState::captureMotionStates(LLVOAvatar* avatar)
|
||||
{
|
||||
|
|
@ -10,6 +11,7 @@ void FSPoseState::captureMotionStates(LLVOAvatar* avatar)
|
|||
return;
|
||||
|
||||
sCaptureOrder[avatar->getID()] = 0;
|
||||
int animNumber = 0;
|
||||
|
||||
for (auto anim_it = avatar->mPlayingAnimations.begin(); anim_it != avatar->mPlayingAnimations.end(); ++anim_it)
|
||||
{
|
||||
|
|
@ -21,27 +23,26 @@ void FSPoseState::captureMotionStates(LLVOAvatar* avatar)
|
|||
newState.motionId = anim_it->first;
|
||||
newState.lastUpdateTime = motion->getLastUpdateTime();
|
||||
newState.captureOrder = 0;
|
||||
newState.avatarOwnsPose = canSaveMotionId(avatar, anim_it->first);
|
||||
newState.inLayerOrder = animNumber++;
|
||||
newState.gAgentOwnsPose = canSaveMotionId(avatar, anim_it->first);
|
||||
|
||||
sMotionStates[avatar->getID()].push_back(newState);
|
||||
}
|
||||
}
|
||||
|
||||
void FSPoseState::updateMotionStates(LLVOAvatar* avatar, FSPosingMotion* posingMotion, std::string jointNamesRecaptured)
|
||||
void FSPoseState::updateMotionStates(LLVOAvatar* avatar, FSPosingMotion* posingMotion, const std::vector<S32>& jointNumbersRecaptured)
|
||||
{
|
||||
if (!avatar || !posingMotion)
|
||||
return;
|
||||
|
||||
sCaptureOrder[avatar->getID()]++;
|
||||
S32 animNumber = 0;
|
||||
|
||||
// if an animation for avatar is a subset of jointNamesRecaptured, delete it
|
||||
// if an animation for avatar is a subset of jointNumbersRecaptured, delete it
|
||||
// this happens on second/subsequent recaptures; the first recapture is no longer needed
|
||||
for (auto it = sMotionStates[avatar->getID()].begin(); it != sMotionStates[avatar->getID()].end();)
|
||||
{
|
||||
std::string joints = (*it).jointNamesAnimated;
|
||||
bool recaptureMatches = !joints.empty() && !jointNamesRecaptured.empty() && jointNamesRecaptured.find(joints) != std::string::npos;
|
||||
|
||||
if (recaptureMatches)
|
||||
if (vector2IsSubsetOfVector1(jointNumbersRecaptured, (*it).jointNumbersAnimated))
|
||||
it = sMotionStates[avatar->getID()].erase(it);
|
||||
else
|
||||
it++;
|
||||
|
|
@ -53,7 +54,7 @@ void FSPoseState::updateMotionStates(LLVOAvatar* avatar, FSPosingMotion* posingM
|
|||
if (!motion)
|
||||
continue;
|
||||
|
||||
if (!posingMotion->otherMotionAnimatesJoints(motion, jointNamesRecaptured))
|
||||
if (!posingMotion->otherMotionAnimatesJoints(motion, jointNumbersRecaptured))
|
||||
continue;
|
||||
|
||||
bool foundMatch = false;
|
||||
|
|
@ -71,45 +72,17 @@ void FSPoseState::updateMotionStates(LLVOAvatar* avatar, FSPosingMotion* posingM
|
|||
continue;
|
||||
|
||||
fsMotionState newState;
|
||||
newState.motionId = anim_it->first;
|
||||
newState.lastUpdateTime = motion->getLastUpdateTime();
|
||||
newState.jointNamesAnimated = jointNamesRecaptured;
|
||||
newState.captureOrder = sCaptureOrder[avatar->getID()];
|
||||
newState.avatarOwnsPose = canSaveMotionId(avatar, anim_it->first);
|
||||
newState.motionId = anim_it->first;
|
||||
newState.lastUpdateTime = motion->getLastUpdateTime();
|
||||
newState.jointNumbersAnimated = jointNumbersRecaptured;
|
||||
newState.captureOrder = sCaptureOrder[avatar->getID()];
|
||||
newState.inLayerOrder = animNumber++;
|
||||
newState.gAgentOwnsPose = canSaveMotionId(avatar, anim_it->first);
|
||||
|
||||
sMotionStates[avatar->getID()].push_back(newState);
|
||||
}
|
||||
}
|
||||
|
||||
bool FSPoseState::addOrUpdatePosingMotionState(LLVOAvatar* avatar, LLUUID animId, F32 updateTime, std::string jointNames, int captureOrder)
|
||||
{
|
||||
if (!avatar)
|
||||
return false;
|
||||
|
||||
bool foundMatch = false;
|
||||
for (auto it = sMotionStates[avatar->getID()].begin(); it != sMotionStates[avatar->getID()].end(); it++)
|
||||
{
|
||||
bool motionIdMatches = (*it).motionId == animId;
|
||||
bool updateTimesMatch = (*it).lastUpdateTime == updateTime;
|
||||
bool jointNamesMatch = (*it).jointNamesAnimated == jointNames;
|
||||
bool captureOrdersMatch = (*it).captureOrder == captureOrder;
|
||||
|
||||
foundMatch = motionIdMatches && updateTimesMatch && jointNamesMatch && captureOrdersMatch;
|
||||
if (foundMatch)
|
||||
return false;
|
||||
}
|
||||
|
||||
fsMotionState newState;
|
||||
newState.motionId = animId;
|
||||
newState.lastUpdateTime = updateTime;
|
||||
newState.jointNamesAnimated = jointNames;
|
||||
newState.captureOrder = captureOrder;
|
||||
newState.avatarOwnsPose = false;
|
||||
|
||||
sMotionStates[avatar->getID()].push_back(newState);
|
||||
return true;
|
||||
}
|
||||
|
||||
void FSPoseState::purgeMotionStates(LLVOAvatar* avatar)
|
||||
{
|
||||
if (!avatar)
|
||||
|
|
@ -118,26 +91,35 @@ void FSPoseState::purgeMotionStates(LLVOAvatar* avatar)
|
|||
sMotionStates[avatar->getID()].clear();
|
||||
}
|
||||
|
||||
void FSPoseState::writeMotionStates(LLVOAvatar* avatar, LLSD* saveRecord)
|
||||
void FSPoseState::writeMotionStates(LLVOAvatar* avatar, bool ignoreOwnership, LLSD* saveRecord)
|
||||
{
|
||||
if (!avatar)
|
||||
return;
|
||||
|
||||
int animNumber = 0;
|
||||
S32 animNumber = 0;
|
||||
for (auto it = sMotionStates[avatar->getID()].begin(); it != sMotionStates[avatar->getID()].end(); ++it)
|
||||
{
|
||||
if (!it->avatarOwnsPose)
|
||||
continue;
|
||||
if (!ignoreOwnership && !it->gAgentOwnsPose)
|
||||
{
|
||||
if (it->requeriedAssetInventory)
|
||||
continue;
|
||||
|
||||
std::string uniqueAnimId = "poseState" + std::to_string(animNumber++);
|
||||
(*saveRecord)[uniqueAnimId]["animationId"] = it->motionId.asString();
|
||||
(*saveRecord)[uniqueAnimId]["lastUpdateTime"] = it->lastUpdateTime;
|
||||
(*saveRecord)[uniqueAnimId]["jointNamesAnimated"] = it->jointNamesAnimated;
|
||||
(*saveRecord)[uniqueAnimId]["captureOrder"] = it->captureOrder;
|
||||
it->gAgentOwnsPose = canSaveMotionId(avatar, it->motionId);
|
||||
it->requeriedAssetInventory = true;
|
||||
if (!it->gAgentOwnsPose)
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string uniqueAnimId = "poseState" + std::to_string(animNumber++);
|
||||
(*saveRecord)[uniqueAnimId]["animationId"] = it->motionId.asString();
|
||||
(*saveRecord)[uniqueAnimId]["lastUpdateTime"] = it->lastUpdateTime;
|
||||
(*saveRecord)[uniqueAnimId]["jointNumbersAnimated"] = encodeVectorToString(it->jointNumbersAnimated);
|
||||
(*saveRecord)[uniqueAnimId]["captureOrder"] = it->captureOrder;
|
||||
(*saveRecord)[uniqueAnimId]["inLayerOrder"] = it->inLayerOrder;
|
||||
}
|
||||
}
|
||||
|
||||
void FSPoseState::restoreMotionStates(LLVOAvatar* avatar, LLSD pose)
|
||||
void FSPoseState::restoreMotionStates(LLVOAvatar* avatar, bool ignoreOwnership, LLSD pose)
|
||||
{
|
||||
if (!avatar)
|
||||
return;
|
||||
|
|
@ -153,25 +135,33 @@ void FSPoseState::restoreMotionStates(LLVOAvatar* avatar, LLSD pose)
|
|||
continue;
|
||||
|
||||
fsMotionState newState;
|
||||
newState.avatarOwnsPose = true;
|
||||
|
||||
if (control_map.has("animationId"))
|
||||
{
|
||||
std::string const name = control_map["animationId"].asString();
|
||||
LLUUID animId;
|
||||
if (LLUUID::parseUUID(name, &animId))
|
||||
{
|
||||
newState.motionId = animId;
|
||||
newState.gAgentOwnsPose = ignoreOwnership || canSaveMotionId(avatar, animId);
|
||||
|
||||
if (ignoreOwnership)
|
||||
sMotionStatesOwnedByMe[animId] = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (control_map.has("lastUpdateTime"))
|
||||
newState.lastUpdateTime = (F32)control_map["lastUpdateTime"].asReal();
|
||||
|
||||
if (control_map.has("jointNamesAnimated"))
|
||||
newState.jointNamesAnimated = control_map["jointNamesAnimated"].asString();
|
||||
if (control_map.has("jointNumbersAnimated"))
|
||||
newState.jointNumbersAnimated = decodeStringToVector(control_map["jointNumbersAnimated"].asString());
|
||||
|
||||
if (control_map.has("captureOrder"))
|
||||
newState.captureOrder = control_map["captureOrder"].asInteger();
|
||||
|
||||
if (control_map.has("inLayerOrder"))
|
||||
newState.inLayerOrder = control_map["inLayerOrder"].asInteger();
|
||||
|
||||
if (newState.captureOrder > sCaptureOrder[avatar->getID()])
|
||||
sCaptureOrder[avatar->getID()] = newState.captureOrder;
|
||||
|
||||
|
|
@ -188,7 +178,7 @@ bool FSPoseState::applyMotionStatesToPosingMotion(LLVOAvatar* avatar, FSPosingMo
|
|||
|
||||
std::sort(sMotionStates[avatar->getID()].begin(), sMotionStates[avatar->getID()].end(), compareByCaptureOrder());
|
||||
|
||||
int lastCaptureOrder = 0;
|
||||
S32 lastCaptureOrder = 0;
|
||||
bool needPriorityReset = false;
|
||||
for (auto it = sMotionStates[avatar->getID()].begin(); it != sMotionStates[avatar->getID()].end(); it++)
|
||||
{
|
||||
|
|
@ -207,7 +197,7 @@ bool FSPoseState::applyMotionStatesToPosingMotion(LLVOAvatar* avatar, FSPosingMo
|
|||
resetPriorityForCaptureOrder(avatar, posingMotion, lastCaptureOrder);
|
||||
}
|
||||
|
||||
it->motionApplied = posingMotion->loadOtherMotionToBaseOfThisMotion(kfm, it->lastUpdateTime, it->jointNamesAnimated);
|
||||
it->motionApplied = posingMotion->loadOtherMotionToBaseOfThisMotion(kfm, it->lastUpdateTime, it->jointNumbersAnimated);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -221,30 +211,50 @@ bool FSPoseState::applyMotionStatesToPosingMotion(LLVOAvatar* avatar, FSPosingMo
|
|||
return allMotionsApplied;
|
||||
}
|
||||
|
||||
void FSPoseState::resetPriorityForCaptureOrder(LLVOAvatar* avatar, FSPosingMotion* posingMotion, int captureOrder)
|
||||
void FSPoseState::resetPriorityForCaptureOrder(LLVOAvatar* avatar, FSPosingMotion* posingMotion, S32 captureOrder)
|
||||
{
|
||||
for (auto it = sMotionStates[avatar->getID()].begin(); it != sMotionStates[avatar->getID()].end(); it++)
|
||||
{
|
||||
if (it->jointNamesAnimated.empty())
|
||||
if (it->jointNumbersAnimated.empty())
|
||||
continue;
|
||||
if (it->motionApplied)
|
||||
continue;
|
||||
if (it->captureOrder != captureOrder)
|
||||
continue;
|
||||
|
||||
posingMotion->resetBonePriority(it->jointNamesAnimated);
|
||||
posingMotion->resetBonePriority(it->jointNumbersAnimated);
|
||||
}
|
||||
}
|
||||
|
||||
bool FSPoseState::canSaveMotionId(LLVOAvatar* avatar, LLAssetID motionId)
|
||||
bool FSPoseState::canSaveMotionId(LLVOAvatar* avatarPlayingMotionId, LLAssetID motionId)
|
||||
{
|
||||
if (!gAgentAvatarp || gAgentAvatarp.isNull())
|
||||
return false;
|
||||
|
||||
if (sMotionStatesOwnedByMe[motionId])
|
||||
return true;
|
||||
|
||||
// does the animation exist in inventory
|
||||
LLInventoryItem* item = gInventory.getItem(motionId);
|
||||
if (item && item->getPermissions().getOwner() == avatar->getID())
|
||||
return true;
|
||||
if (item && item->getPermissions().getOwner() == gAgentAvatarp->getID())
|
||||
{
|
||||
sMotionStatesOwnedByMe[motionId] = true;
|
||||
return sMotionStatesOwnedByMe[motionId];
|
||||
}
|
||||
|
||||
if (!avatarPlayingMotionId)
|
||||
return false;
|
||||
|
||||
if (avatarPlayingMotionId->getID() == gAgentAvatarp->getID())
|
||||
return motionIdIsAgentAnimationSource(motionId);
|
||||
|
||||
return motionIdIsFromPrimAgentOwnsAgentIsSittingOn(avatarPlayingMotionId, motionId);
|
||||
}
|
||||
|
||||
bool FSPoseState::motionIdIsAgentAnimationSource(LLAssetID motionId)
|
||||
{
|
||||
if (!gAgentAvatarp || gAgentAvatarp.isNull())
|
||||
return false;
|
||||
|
||||
for (const auto& [anim_object_id, anim_anim_id] : gAgentAvatarp->mAnimationSources)
|
||||
{
|
||||
|
|
@ -252,17 +262,150 @@ bool FSPoseState::canSaveMotionId(LLVOAvatar* avatar, LLAssetID motionId)
|
|||
continue;
|
||||
|
||||
// is the item that started the anim in inventory
|
||||
item = gInventory.getItem(anim_object_id);
|
||||
if (item && item->getPermissions().getOwner() == avatar->getID())
|
||||
return true;
|
||||
LLInventoryItem* item = gInventory.getItem(anim_object_id);
|
||||
if (item && item->getPermissions().getOwner() == gAgentAvatarp->getID())
|
||||
{
|
||||
sMotionStatesOwnedByMe[motionId] = true;
|
||||
return sMotionStatesOwnedByMe[motionId];
|
||||
}
|
||||
|
||||
// is the item that start the animation in-world
|
||||
LLViewerObject* object = gObjectList.findObject(anim_object_id);
|
||||
if (object && object->permYouOwner())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
{
|
||||
sMotionStatesOwnedByMe[motionId] = true;
|
||||
return sMotionStatesOwnedByMe[motionId];
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FSPoseState::motionIdIsFromPrimAgentOwnsAgentIsSittingOn(LLVOAvatar* avatarPlayingMotionId, LLAssetID motionId)
|
||||
{
|
||||
if (!avatarPlayingMotionId)
|
||||
return false;
|
||||
|
||||
const LLViewerObject* agentRoot = dynamic_cast<LLViewerObject*>(avatarPlayingMotionId->getRoot());
|
||||
if (!agentRoot)
|
||||
return false;
|
||||
|
||||
const LLUUID& assetIdTheyAreSittingOn = agentRoot->getID();
|
||||
if (assetIdTheyAreSittingOn == avatarPlayingMotionId->getID())
|
||||
return false; // they are not sitting on a thing
|
||||
|
||||
LLViewerObject* object = gObjectList.findObject(assetIdTheyAreSittingOn);
|
||||
if (!object || !object->permYouOwner())
|
||||
return false; // gAgent does not own what they are sitting on
|
||||
|
||||
if (object->isInventoryPending())
|
||||
return false;
|
||||
|
||||
if (object->isInventoryDirty() || !object->getInventoryRoot())
|
||||
{
|
||||
object->requestInventory();
|
||||
return false; // whatever they are sitting on, we don't have the inventory list for yet
|
||||
}
|
||||
|
||||
LLInventoryItem* item = object->getInventoryItemByAsset(motionId, LLAssetType::AT_ANIMATION);
|
||||
if (item && item->getPermissions().getOwner() == gAgentAvatarp->getID())
|
||||
{
|
||||
sMotionStatesOwnedByMe[motionId] = true;
|
||||
return sMotionStatesOwnedByMe[motionId];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FSPoseState::vector2IsSubsetOfVector1(std::vector<S32> newRecapture, std::vector<S32> oldRecapture)
|
||||
{
|
||||
if (newRecapture.empty())
|
||||
return false;
|
||||
if (oldRecapture.empty())
|
||||
return false;
|
||||
|
||||
if (newRecapture.size() < oldRecapture.size())
|
||||
return false;
|
||||
|
||||
for (S32 number : oldRecapture)
|
||||
if (std::find(newRecapture.begin(), newRecapture.end(), number) == newRecapture.end())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string FSPoseState::encodeVectorToString(const std::vector<S32>& vector)
|
||||
{
|
||||
std::string encoded = "";
|
||||
if (vector.empty())
|
||||
return encoded;
|
||||
|
||||
for (S32 numberToEncode : vector)
|
||||
{
|
||||
if (numberToEncode > 251) // max 216 at time of writing
|
||||
continue;
|
||||
|
||||
S32 number = numberToEncode;
|
||||
|
||||
if (number >= 189)
|
||||
{
|
||||
encoded += "~";
|
||||
number -= 189;
|
||||
}
|
||||
|
||||
if (number >= 126)
|
||||
{
|
||||
encoded += "}";
|
||||
number -= 126;
|
||||
}
|
||||
|
||||
if (number >= 63)
|
||||
{
|
||||
encoded += "|";
|
||||
number -= 63;
|
||||
}
|
||||
|
||||
encoded += char(number + int('?'));
|
||||
}
|
||||
|
||||
return encoded;
|
||||
}
|
||||
|
||||
std::vector<S32> FSPoseState::decodeStringToVector(std::string_view vector)
|
||||
{
|
||||
std::vector<S32> decoded;
|
||||
if (vector.empty())
|
||||
return decoded;
|
||||
|
||||
S32 number = 0;
|
||||
for (char ch : vector)
|
||||
{
|
||||
if (ch > '~' || ch < '?')
|
||||
continue;
|
||||
|
||||
if (ch == '~')
|
||||
{
|
||||
number += 189;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch == '}')
|
||||
{
|
||||
number += 126;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch == '|')
|
||||
{
|
||||
number += 63;
|
||||
continue;
|
||||
}
|
||||
|
||||
number -= int('?');
|
||||
number += S32(ch);
|
||||
decoded.push_back(number);
|
||||
number = 0;
|
||||
}
|
||||
|
||||
return decoded;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,18 +49,7 @@ public:
|
|||
/// <param name="avatar">The avatar whose animations are to be captured.</param>
|
||||
/// <param name="posingMotion">The posing motion.</param>
|
||||
/// <param name="jointNamesRecaptured">The names of the joints being recaptured.</param>
|
||||
void updateMotionStates(LLVOAvatar* avatar, FSPosingMotion* posingMotion, std::string jointNamesRecaptured);
|
||||
|
||||
/// <summary>
|
||||
/// Add a new posing state, or updates the matching posing state with the supplied data.
|
||||
/// </summary>
|
||||
/// <param name="avatar">The avatar the posing state is intended for.</param>
|
||||
/// <param name="animId">The ID of the animation.</param>
|
||||
/// <param name="updateTime">The frame-time of the animation.</param>
|
||||
/// <param name="jointNames">The names of the joints, if any, the animation should specifically be applied to.</param>
|
||||
/// <param name="captureOrder">The capture order.</param>
|
||||
/// <returns>True if the posing state was added or changed by the update data, otherwise false.</returns>
|
||||
bool addOrUpdatePosingMotionState(LLVOAvatar* avatar, LLUUID animId, F32 updateTime, std::string jointNames, int captureOrder);
|
||||
void updateMotionStates(LLVOAvatar* avatar, FSPosingMotion* posingMotion, const std::vector<S32>& jointNamesRecaptured);
|
||||
|
||||
/// <summary>
|
||||
/// Removes all current animation states for the supplied avatar.
|
||||
|
|
@ -72,16 +61,17 @@ public:
|
|||
/// Writes any documented poses for the supplied avatar to the supplied stream.
|
||||
/// </summary>
|
||||
/// <param name="avatar">The avatar whose animations may have been captured.</param>
|
||||
/// <param name="ignoreOwnership">Whether to ignore ownership. For use when preparing saveRecord to send to another by collab.</param>
|
||||
/// <param name="saveRecord">The record to add to.</param>
|
||||
void writeMotionStates(LLVOAvatar* avatar, LLSD* saveRecord);
|
||||
void writeMotionStates(LLVOAvatar* avatar, bool ignoreOwnership, LLSD* saveRecord);
|
||||
|
||||
/// <summary>
|
||||
/// Restores pose state(s) from the supplied record.
|
||||
/// </summary>
|
||||
/// <param name="avatar">The avatar whose animations may have been captured.</param>
|
||||
/// <param name="posingMotion">The posing motion.</param>
|
||||
/// <param name="ignoreOwnership">Whether to ignore ownership. For use when reading a local file.</param>
|
||||
/// <param name="pose">The record to read from.</param>
|
||||
void restoreMotionStates(LLVOAvatar* avatar, LLSD pose);
|
||||
void restoreMotionStates(LLVOAvatar* avatar, bool ignoreOwnership, LLSD pose);
|
||||
|
||||
/// <summary>
|
||||
/// Applies the motion states for the supplied avatar to the supplied motion.
|
||||
|
|
@ -122,20 +112,30 @@ private:
|
|||
bool motionApplied = false;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the avatar owns the pose, or the pose was loaded.
|
||||
/// For non-gAgent, we permit a query of the inventory of a prim they are sitting on.
|
||||
/// Because this involves latency, we may retry ownership checking at save-time.
|
||||
/// </summary>
|
||||
bool avatarOwnsPose = false;
|
||||
bool requeriedAssetInventory = false;
|
||||
|
||||
/// <summary>
|
||||
/// When reloading, larger numbers are loaded last, nesting order and priority.
|
||||
/// This is used to represent recaptures, where joints could be animated with different poses.
|
||||
/// Whether gAgent owns the pose, or the pose was loaded from XML.
|
||||
/// </summary>
|
||||
int captureOrder = 0;
|
||||
bool gAgentOwnsPose = false;
|
||||
|
||||
/// <summary>
|
||||
/// When reloading, and if not-empty, the names of the bones this motionId should affect.
|
||||
/// Represents 'capture layers: how the user layers animations 'on top of' others.
|
||||
/// </summary>
|
||||
std ::string jointNamesAnimated;
|
||||
S32 captureOrder = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Represents in-layer order of capture.
|
||||
/// </summary>
|
||||
S32 inLayerOrder = 0;
|
||||
|
||||
/// <summary>
|
||||
/// When reloading, and if not-empty, the bone-numbers this motionId should affect.
|
||||
/// </summary>
|
||||
std ::vector<S32> jointNumbersAnimated;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -144,15 +144,61 @@ private:
|
|||
/// <param name="avatar">The avatar being posed by the motion.</param>
|
||||
/// <param name="posingMotion">The posing motion.</param>
|
||||
/// <param name="captureOrder">The order of the capture.</param>
|
||||
void resetPriorityForCaptureOrder(LLVOAvatar* avatar, FSPosingMotion* posingMotion, int captureOrder);
|
||||
void resetPriorityForCaptureOrder(LLVOAvatar* avatar, FSPosingMotion* posingMotion, S32 captureOrder);
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the supplied avatar owns, and thus can save information about the supplied asset ID.
|
||||
/// Gets whether gAgentID owns, and thus can save information about the supplied motionId.
|
||||
/// </summary>
|
||||
/// <param name="avatar">The avatar to query ownership for.</param>
|
||||
/// <param name="motionId">The asset ID of the object.</param>
|
||||
/// <returns>True if the avatar owns the asset, otherwise false.</returns>
|
||||
bool canSaveMotionId(LLVOAvatar* avatar, LLAssetID motionId);
|
||||
/// <param name="avatarPlayingMotionId">The avatar playing the supplied motionId.</param>
|
||||
/// <param name="motionId">The motionId of the animation.</param>
|
||||
/// <returns>True if the gAgent owns the motionId, otherwise false.</returns>
|
||||
/// <remarks>
|
||||
/// This only works reliably for self.
|
||||
/// For motions playing on others, the motion needs to be an asset in gAgent's inventory.
|
||||
/// </remarks>
|
||||
bool canSaveMotionId(LLVOAvatar* avatarPlayingMotionId, LLAssetID motionId);
|
||||
|
||||
/// <summary>
|
||||
/// Examines gAgent's animation source list for the supplied animation Id.
|
||||
/// </summary>
|
||||
/// <param name="motionId">The ID of the motion to query.</param>
|
||||
/// <returns>True if gAgent is playing the animation, otherwise false.</returns>
|
||||
bool motionIdIsAgentAnimationSource(LLAssetID motionId);
|
||||
|
||||
/// <summary>
|
||||
/// Queries a specific condition of the supplied animation ID.
|
||||
/// </summary>
|
||||
/// <param name="avatarPlayingMotionId">The avatar to query for.</param>
|
||||
/// <param name="motionId">The motion ID to query for.</param>
|
||||
/// <returns>
|
||||
/// True if the supplied avatar is sitting on an object owned by gAgent, and that object
|
||||
/// contains an animation asset with the same assetId.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// This is intended to test for a situation a photographer might arrange.
|
||||
/// If you are sitting on photographer's prim, playing photographer's pose, and photographer wants to save their work,
|
||||
/// this allows them to save the Animation ID and state to XML.
|
||||
/// It is intended this be called twice at least, as it does not implement a callback onInventoryLoaded.
|
||||
/// Presently this works fine: first time being when posing starts, second when pose is saved.
|
||||
/// </remarks>
|
||||
bool motionIdIsFromPrimAgentOwnsAgentIsSittingOn(LLVOAvatar* avatarPlayingMotionId, LLAssetID motionId);
|
||||
|
||||
/// <summary>
|
||||
/// Tests if all the members of supplied vector2 are members of supplied vector1.
|
||||
/// </summary>
|
||||
/// <param name="vector1">The super-set.</param>
|
||||
/// <param name="vector2">The possible sub-set.</param>
|
||||
/// <returns>True if all members of vector2 are members of vector1, otherwise false.</returns>
|
||||
bool vector2IsSubsetOfVector1(std::vector<S32> vector1, std::vector<S32> vector2);
|
||||
|
||||
/// <summary>
|
||||
/// Two symmetric methods for (de)serializing vectors to both XML and collab-safe short-as-possible strings and back again.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Collab-safe means ASCII-printable chars, and delimiter usage does not conflict with Collab's delimiter.
|
||||
/// </remarks>
|
||||
std::string encodeVectorToString(const std::vector<S32>& vector);
|
||||
std::vector<S32> decodeStringToVector(std::string_view vector);
|
||||
|
||||
struct compareByCaptureOrder
|
||||
{
|
||||
|
|
@ -160,13 +206,16 @@ private:
|
|||
{
|
||||
if (a.captureOrder < b.captureOrder)
|
||||
return true; // Ascending order
|
||||
if (a.captureOrder == b.captureOrder && a.inLayerOrder < b.inLayerOrder)
|
||||
return true; // Ascending order in layer
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
static std::map <LLUUID, std::vector<fsMotionState>> sMotionStates;
|
||||
static std::map<LLUUID, int> sCaptureOrder;
|
||||
static std::map<LLUUID, std::vector<fsMotionState>> sMotionStates;
|
||||
static std::map<LLUUID, S32> sCaptureOrder;
|
||||
static std::map<LLUUID, bool> sMotionStatesOwnedByMe;
|
||||
};
|
||||
|
||||
#endif // LL_FSPoseState_H
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ FSPosingMotion::FSPosingMotion(const LLUUID& id) : LLKeyframeMotion(id)
|
|||
mJointMotionList = &dummyMotionList;
|
||||
}
|
||||
|
||||
LLMotion::LLMotionInitStatus FSPosingMotion::onInitialize(LLCharacter *character)
|
||||
LLMotion::LLMotionInitStatus FSPosingMotion::onInitialize(LLCharacter* character)
|
||||
{
|
||||
if (!character)
|
||||
return STATUS_FAILURE;
|
||||
|
|
@ -184,7 +184,7 @@ void FSPosingMotion::removeJointFromState(LLJoint* joint)
|
|||
|
||||
void FSPosingMotion::setJointState(LLJoint* joint, U32 state)
|
||||
{
|
||||
if (mJointPoses.size() < 1)
|
||||
if (mJointPoses.empty())
|
||||
return;
|
||||
if (!joint)
|
||||
return;
|
||||
|
|
@ -208,7 +208,7 @@ void FSPosingMotion::setJointState(LLJoint* joint, U32 state)
|
|||
|
||||
FSJointPose* FSPosingMotion::getJointPoseByJointName(const std::string& name)
|
||||
{
|
||||
if (mJointPoses.size() < 1)
|
||||
if (name.empty() || mJointPoses.empty())
|
||||
return nullptr;
|
||||
|
||||
for (auto poserJoint_iter = mJointPoses.begin(); poserJoint_iter != mJointPoses.end(); ++poserJoint_iter)
|
||||
|
|
@ -222,15 +222,33 @@ FSJointPose* FSPosingMotion::getJointPoseByJointName(const std::string& name)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
FSJointPose* FSPosingMotion::getJointPoseByJointNumber(const S32 number)
|
||||
{
|
||||
if (mJointPoses.empty())
|
||||
return nullptr;
|
||||
if (number < 0)
|
||||
return nullptr;
|
||||
|
||||
for (auto poserJoint_iter = mJointPoses.begin(); poserJoint_iter != mJointPoses.end(); ++poserJoint_iter)
|
||||
{
|
||||
if (poserJoint_iter->getJointNumber() != number)
|
||||
continue;
|
||||
|
||||
return &*poserJoint_iter;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool FSPosingMotion::currentlyPosingJoint(LLJoint* joint)
|
||||
{
|
||||
if (mJointPoses.size() < 1)
|
||||
if (mJointPoses.empty())
|
||||
return false;
|
||||
|
||||
if (!joint)
|
||||
return false;
|
||||
|
||||
LLPose* pose = this->getPose();
|
||||
LLPose* pose = getPose();
|
||||
if (!pose)
|
||||
return false;
|
||||
|
||||
|
|
@ -270,14 +288,14 @@ void FSPosingMotion::setJointBvhLock(FSJointPose* joint, bool lockInBvh)
|
|||
joint->zeroBaseRotation(lockInBvh);
|
||||
}
|
||||
|
||||
bool FSPosingMotion::loadOtherMotionToBaseOfThisMotion(LLKeyframeMotion* motionToLoad, F32 timeToLoadAt, std::string selectedJointNames)
|
||||
bool FSPosingMotion::loadOtherMotionToBaseOfThisMotion(LLKeyframeMotion* motionToLoad, F32 timeToLoadAt, const std::vector<S32>& selectedJointNumbers)
|
||||
{
|
||||
FSPosingMotion* motionToLoadAsFsPosingMotion = static_cast<FSPosingMotion*>(motionToLoad);
|
||||
if (!motionToLoadAsFsPosingMotion)
|
||||
return false;
|
||||
|
||||
LLJoint::JointPriority priority = motionToLoad->getPriority();
|
||||
bool motionIsForAllJoints = selectedJointNames.empty();
|
||||
bool motionIsForAllJoints = selectedJointNumbers.empty();
|
||||
|
||||
LLQuaternion rot;
|
||||
LLVector3 position, scale;
|
||||
|
|
@ -285,16 +303,18 @@ bool FSPosingMotion::loadOtherMotionToBaseOfThisMotion(LLKeyframeMotion* motionT
|
|||
|
||||
for (auto poserJoint_iter = mJointPoses.begin(); poserJoint_iter != mJointPoses.end(); ++poserJoint_iter)
|
||||
{
|
||||
std::string jointName = poserJoint_iter->jointName();
|
||||
S32 jointNumber = poserJoint_iter->getJointNumber();
|
||||
std::string jointName = poserJoint_iter->jointName();
|
||||
|
||||
bool motionIsForThisJoint = selectedJointNames.find(jointName) != std::string::npos;
|
||||
bool motionIsForThisJoint =
|
||||
std::find(selectedJointNumbers.begin(), selectedJointNumbers.end(), jointNumber) != selectedJointNumbers.end();
|
||||
if (!motionIsForAllJoints && !motionIsForThisJoint)
|
||||
continue;
|
||||
|
||||
hasRotation = hasPosition = hasScale = false;
|
||||
motionToLoadAsFsPosingMotion->getJointStateAtTime(jointName, timeToLoadAt, &hasRotation, &rot, &hasPosition, &position, &hasScale, &scale);
|
||||
|
||||
if (hasRotation)
|
||||
if (hasRotation && !poserJoint_iter->userHasSetBaseRotationToZero())
|
||||
poserJoint_iter->setBaseRotation(rot, priority);
|
||||
|
||||
if (hasPosition)
|
||||
|
|
@ -337,16 +357,17 @@ void FSPosingMotion::getJointStateAtTime(std::string jointPoseName, F32 timeToLo
|
|||
}
|
||||
}
|
||||
|
||||
bool FSPosingMotion::otherMotionAnimatesJoints(LLKeyframeMotion* motionToQuery, std::string recapturedJointNames)
|
||||
bool FSPosingMotion::otherMotionAnimatesJoints(LLKeyframeMotion* motionToQuery, const std::vector<S32>& recapturedJointNumbers)
|
||||
{
|
||||
FSPosingMotion* motionToLoadAsFsPosingMotion = static_cast<FSPosingMotion*>(motionToQuery);
|
||||
if (!motionToLoadAsFsPosingMotion)
|
||||
return false;
|
||||
|
||||
return motionToLoadAsFsPosingMotion->motionAnimatesJoints(recapturedJointNames);
|
||||
return motionToLoadAsFsPosingMotion->motionAnimatesJoints(recapturedJointNumbers);
|
||||
}
|
||||
|
||||
bool FSPosingMotion::motionAnimatesJoints(std::string recapturedJointNames)
|
||||
// Do not try to access FSPosingMotion state; you are a LLKeyframeMotion cast as a FSPosingMotion, NOT an FSPosingMotion.
|
||||
bool FSPosingMotion::motionAnimatesJoints(const std::vector<S32>& recapturedJointNumbers)
|
||||
{
|
||||
if (mJointMotionList == nullptr)
|
||||
return false;
|
||||
|
|
@ -354,7 +375,9 @@ bool FSPosingMotion::motionAnimatesJoints(std::string recapturedJointNames)
|
|||
for (U32 i = 0; i < mJointMotionList->getNumJointMotions(); i++)
|
||||
{
|
||||
JointMotion* jm = mJointMotionList->getJointMotion(i);
|
||||
if (recapturedJointNames.find(jm->mJointName) == std::string::npos)
|
||||
LLJoint* joint = mCharacter->getJoint(jm->mJointName);
|
||||
|
||||
if (std::find(recapturedJointNumbers.begin(), recapturedJointNumbers.end(), joint->getJointNum()) == recapturedJointNumbers.end())
|
||||
continue;
|
||||
|
||||
if (jm->mRotationCurve.mNumKeys > 0)
|
||||
|
|
@ -364,20 +387,19 @@ bool FSPosingMotion::motionAnimatesJoints(std::string recapturedJointNames)
|
|||
return false;
|
||||
}
|
||||
|
||||
void FSPosingMotion::resetBonePriority(std::string boneNamesToReset)
|
||||
void FSPosingMotion::resetBonePriority(const std::vector<S32>& boneNumbersToReset)
|
||||
{
|
||||
if (boneNamesToReset.empty())
|
||||
return;
|
||||
|
||||
for (auto poserJoint_iter = mJointPoses.begin(); poserJoint_iter != mJointPoses.end(); ++poserJoint_iter)
|
||||
for (S32 boneNumber : boneNumbersToReset)
|
||||
{
|
||||
std::string jointName = poserJoint_iter->jointName();
|
||||
if (boneNamesToReset.find(jointName) != std::string::npos)
|
||||
poserJoint_iter->setJointPriority(LLJoint::LOW_PRIORITY);
|
||||
for (auto poserJoint_iter = mJointPoses.begin(); poserJoint_iter != mJointPoses.end(); ++poserJoint_iter)
|
||||
{
|
||||
if (poserJoint_iter->getJointNumber() == boneNumber)
|
||||
poserJoint_iter->setJointPriority(LLJoint::LOW_PRIORITY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool FSPosingMotion::vectorsNotQuiteEqual(LLVector3 v1, LLVector3 v2) const
|
||||
bool FSPosingMotion::vectorsNotQuiteEqual(const LLVector3& v1, const LLVector3& v2) const
|
||||
{
|
||||
if (vectorAxesAlmostEqual(v1.mV[VX], v2.mV[VX]) &&
|
||||
vectorAxesAlmostEqual(v1.mV[VY], v2.mV[VY]) &&
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ public:
|
|||
// 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);
|
||||
virtual LLMotionInitStatus onInitialize(LLCharacter* character);
|
||||
|
||||
// called when a motion is activated
|
||||
// must return TRUE to indicate success, or else
|
||||
|
|
@ -108,6 +108,13 @@ public:
|
|||
/// <returns>The matching joint pose, if found, otherwise null.</returns>
|
||||
FSJointPose* getJointPoseByJointName(const std::string& name);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the joint pose by its LLJoint number.
|
||||
/// </summary>
|
||||
/// <param name="number">The number of the joint to get the pose for.</param>
|
||||
/// <returns>The matching joint pose, if found, otherwise null.</returns>
|
||||
FSJointPose* getJointPoseByJointNumber(const S32 number);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the motion identity for this animation.
|
||||
/// </summary>
|
||||
|
|
@ -139,9 +146,9 @@ public:
|
|||
/// </summary>
|
||||
/// <param name="motionToLoad">The motion whose joint rotations (etc) we want to copy to this.</param>
|
||||
/// <param name="timeToLoadAt">The play-time the animation should be advanced to derive the correct joint state.</param>
|
||||
/// <param name="selectedJointNames">If only some of the joints should be animated by this motion, name them here.</param>
|
||||
/// <param name="selectedJointNumbers">If only some of the joints should be animated by this motion, number them here.</param>
|
||||
/// <returns></returns>
|
||||
bool loadOtherMotionToBaseOfThisMotion(LLKeyframeMotion* motionToLoad, F32 timeToLoadAt, std::string selectedJointNames);
|
||||
bool loadOtherMotionToBaseOfThisMotion(LLKeyframeMotion* motionToLoad, F32 timeToLoadAt, const std::vector<S32>& selectedJointNumbers);
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get the rotation, position and scale for the supplied joint name at the supplied time.
|
||||
|
|
@ -164,27 +171,27 @@ public:
|
|||
/// <summary>
|
||||
/// Resets the bone priority to zero for the joints named in the supplied string.
|
||||
/// </summary>
|
||||
/// <param name="boneNamesToReset">The string containg bone names (like mPelvis).</param>
|
||||
void resetBonePriority(std::string boneNamesToReset);
|
||||
/// <param name="boneNumbersToReset">The vector containing bone numbers.</param>
|
||||
void resetBonePriority(const std::vector<S32>& boneNumbersToReset);
|
||||
|
||||
/// <summary>
|
||||
/// Queries whether the supplied motion animates any of the joints named in the supplied string.
|
||||
/// </summary>
|
||||
/// <param name="motionToQuery">The motion to query.</param>
|
||||
/// <param name="recapturedJointNames">A string containing all of the joint names.</param>
|
||||
/// <param name="recapturedJointNumbers">A string containing all of the joint numbers.</param>
|
||||
/// <returns>True if the motion animates any of the bones named, otherwise false.</returns>
|
||||
bool otherMotionAnimatesJoints(LLKeyframeMotion* motionToQuery, std::string recapturedJointNames);
|
||||
bool otherMotionAnimatesJoints(LLKeyframeMotion* motionToQuery, const std::vector<S32>& recapturedJointNumbers);
|
||||
|
||||
/// <summary>
|
||||
/// Queries whether the this motion animates any of the joints named in the supplied string.
|
||||
/// </summary>
|
||||
/// <param name="recapturedJointNames">A string containing all of the joint names.</param>
|
||||
/// <param name="recapturedJointNames">A vector containing all of the joint numbers this motion animates.</param>
|
||||
/// <returns>True if the motion animates any of the bones named, otherwise false.</returns>
|
||||
/// <remarks>
|
||||
/// The most significant thing this method does is provide access to protected properties of an LLPosingMotion.
|
||||
/// Thus its most common usage would be to access those properties for an arbitrary animation.
|
||||
/// </remarks>
|
||||
bool motionAnimatesJoints(std::string recapturedJointNames);
|
||||
bool motionAnimatesJoints(const std::vector<S32>& recapturedJointNumbers);
|
||||
|
||||
private:
|
||||
/// <summary>
|
||||
|
|
@ -267,7 +274,7 @@ private:
|
|||
/// <param name="v1">The first vector to compare.</param>
|
||||
/// <param name="v2">The sceond vector to compare.</param>
|
||||
/// <returns>true if the vectors are "close enough", otherwise false.</returns>
|
||||
bool vectorsNotQuiteEqual(LLVector3 v1, LLVector3 v2) const;
|
||||
bool vectorsNotQuiteEqual(const LLVector3& v1, const LLVector3& v2) const;
|
||||
|
||||
/// <summary>
|
||||
/// Determines if two quaternions are near enough to equal.
|
||||
|
|
|
|||
|
|
@ -292,10 +292,10 @@ using namespace LL;
|
|||
#include "nd/ndetw.h" // <FS:ND/> Windows Event Tracing, does nothing on OSX/Linux.
|
||||
#include "nd/ndlogthrottle.h"
|
||||
|
||||
#include "aoengine.h"
|
||||
#include "fsradar.h"
|
||||
#include "fsassetblacklist.h"
|
||||
#include "bugsplatattributes.h"
|
||||
// #include "fstelemetry.h" // <FS:Beq> Tracy profiler support
|
||||
|
||||
#if LL_LINUX && LL_GTK
|
||||
#include "glib.h"
|
||||
|
|
@ -2271,6 +2271,8 @@ bool LLAppViewer::cleanup()
|
|||
LLEnvironment::getInstance()->saveToSettings();
|
||||
}
|
||||
|
||||
AOEngine::deleteSingleton();
|
||||
|
||||
// Must do this after all panels have been deleted because panels that have persistent rects
|
||||
// save their rects on delete.
|
||||
if(mSaveSettingsOnExit) // <FS:Zi> Backup Settings
|
||||
|
|
|
|||
|
|
@ -191,8 +191,8 @@ LLAvatarList::LLAvatarList(const Params& p)
|
|||
, mRlvCheckShowNames(false)
|
||||
// [/RLVa:KB]
|
||||
, mShowVoiceVolume(p.show_voice_volume)
|
||||
, mShowUsername((bool)gSavedSettings.getBOOL("NameTagShowUsernames"))
|
||||
, mShowDisplayName((bool)gSavedSettings.getBOOL("UseDisplayNames"))
|
||||
, mShowUsername(gSavedSettings.getBOOL("NameTagShowUsernames"))
|
||||
, mShowDisplayName(gSavedSettings.getBOOL("UseDisplayNames"))
|
||||
{
|
||||
setCommitOnSelectionChange(true);
|
||||
|
||||
|
|
@ -219,13 +219,13 @@ LLAvatarList::LLAvatarList(const Params& p)
|
|||
void LLAvatarList::handleDisplayNamesOptionChanged()
|
||||
{
|
||||
// <FS:Ansariel> FIRE-1089: Set the proper name options for the AvatarListItem before we update the list.
|
||||
mShowUsername = (bool)gSavedSettings.getBOOL("NameTagShowUsernames");
|
||||
mShowDisplayName = (bool)gSavedSettings.getBOOL("UseDisplayNames");
|
||||
mShowUsername = gSavedSettings.getBOOL("NameTagShowUsernames");
|
||||
mShowDisplayName = gSavedSettings.getBOOL("UseDisplayNames");
|
||||
std::vector<LLPanel*> items;
|
||||
getItems(items);
|
||||
for( std::vector<LLPanel*>::const_iterator it = items.begin(); it != items.end(); it++)
|
||||
for (auto panel : items)
|
||||
{
|
||||
LLAvatarListItem* item = static_cast<LLAvatarListItem*>(*it);
|
||||
LLAvatarListItem* item = static_cast<LLAvatarListItem*>(panel);
|
||||
item->showUsername(mShowUsername, false);
|
||||
item->showDisplayName(mShowDisplayName, false);
|
||||
}
|
||||
|
|
@ -265,9 +265,9 @@ void LLAvatarList::updateRlvRestrictions(ERlvBehaviour behavior, ERlvParamType t
|
|||
{
|
||||
std::vector<LLPanel*> items;
|
||||
getItems(items);
|
||||
for (std::vector<LLPanel*>::const_iterator it = items.begin(); it != items.end(); it++)
|
||||
for (auto panel : items)
|
||||
{
|
||||
LLAvatarListItem* item = static_cast<LLAvatarListItem*>(*it);
|
||||
LLAvatarListItem* item = static_cast<LLAvatarListItem*>(panel);
|
||||
item->updateRlvRestrictions();
|
||||
}
|
||||
}
|
||||
|
|
@ -559,11 +559,11 @@ S32 LLAvatarList::notifyParent(const LLSD& info)
|
|||
return 1;
|
||||
}
|
||||
// [SL:KB] - Patch: UI-AvatarListDndShare | Checked: 2011-06-19 (Catznip-2.6.0c) | Added: Catznip-2.6.0c
|
||||
else if ( (info.has("select")) && (info["select"].isUUID()) )
|
||||
else if (info.has("select") && info["select"].isUUID())
|
||||
{
|
||||
const LLSD& sdValue = getSelectedValue();
|
||||
const LLUUID idItem = info["select"].asUUID();
|
||||
if ( (!sdValue.isDefined()) || ((sdValue.isUUID()) && (sdValue.asUUID() != idItem)) )
|
||||
if (!sdValue.isDefined() || (sdValue.isUUID() && sdValue.asUUID() != idItem))
|
||||
{
|
||||
resetSelection();
|
||||
selectItemByUUID(info["select"].asUUID());
|
||||
|
|
@ -731,18 +731,18 @@ void LLAvatarList::onItemClicked(LLUICtrl* ctrl, S32 x, S32 y, MASK mask)
|
|||
// static
|
||||
std::string LLAvatarList::getNameForDisplay(const LLUUID& avatar_id, const LLAvatarName& av_name, bool show_displayname, bool show_username, bool force_use_complete_name, bool rlv_check_shownames)
|
||||
{
|
||||
bool fRlvCanShowName = (!rlv_check_shownames) || (RlvActions::canShowName(RlvActions::SNC_DEFAULT, avatar_id));
|
||||
const bool fRlvCanShowName = (!rlv_check_shownames) || (RlvActions::canShowName(RlvActions::SNC_DEFAULT, avatar_id));
|
||||
if (show_displayname && !show_username)
|
||||
{
|
||||
return ( (fRlvCanShowName) ? av_name.getDisplayName() : RlvStrings::getAnonym(av_name) );
|
||||
return (fRlvCanShowName ? av_name.getDisplayName() : RlvStrings::getAnonym(av_name));
|
||||
}
|
||||
else if (!show_displayname && show_username)
|
||||
{
|
||||
return ( (fRlvCanShowName) ? av_name.getUserName() : RlvStrings::getAnonym(av_name) );
|
||||
return (fRlvCanShowName ? av_name.getUserName() : RlvStrings::getAnonym(av_name));
|
||||
}
|
||||
else
|
||||
{
|
||||
return ( (fRlvCanShowName) ? av_name.getCompleteName(false, force_use_complete_name) : RlvStrings::getAnonym(av_name) );
|
||||
return (fRlvCanShowName ? av_name.getCompleteName(true, force_use_complete_name) : RlvStrings::getAnonym(av_name));
|
||||
}
|
||||
}
|
||||
// </FS:Ansariel>
|
||||
|
|
|
|||
|
|
@ -368,7 +368,12 @@ void LLFloaterModelPreview::reshape(S32 width, S32 height, bool called_from_pare
|
|||
{
|
||||
LLFloaterModelUploadBase::reshape(width, height, called_from_parent);
|
||||
|
||||
LLView* preview_panel = getChild<LLView>("preview_panel");
|
||||
// <FS:Ansariel> This can get called before the floater is actually built
|
||||
//LLView* preview_panel = getChild<LLView>("preview_panel");
|
||||
LLView* preview_panel = findChild<LLView>("preview_panel");
|
||||
if (!preview_panel)
|
||||
return;
|
||||
// </FS:Ansariel>
|
||||
LLRect rect = preview_panel->getRect();
|
||||
|
||||
if (rect != mPreviewRect)
|
||||
|
|
|
|||
|
|
@ -1129,7 +1129,7 @@ void LLOutfitListBase::refreshList(const LLUUID& category_id)
|
|||
|
||||
// <FS:ND> FIRE-6958/VWR-2862; Handle large amounts of outfits, write a least a warning into the logs.
|
||||
S32 currentOutfitsAmount = (S32)mRefreshListState.Added.size();
|
||||
constexpr S32 maxSuggestedOutfits = 200;
|
||||
constexpr S32 maxSuggestedOutfits = 1000;
|
||||
if (currentOutfitsAmount > maxSuggestedOutfits)
|
||||
{
|
||||
LL_WARNS() << "Large amount of outfits found: " << currentOutfitsAmount << " this may cause hangs and disconnects" << LL_ENDL;
|
||||
|
|
|
|||
|
|
@ -272,7 +272,8 @@ public:
|
|||
virtual bool handleDoubleClick(S32 x, S32 y, MASK mask) override;
|
||||
virtual void render() override;
|
||||
void setAvatar(LLVOAvatar* avatar) { mManip->setAvatar(avatar); };
|
||||
void setJoint( LLJoint * joint ) { mManip->setJoint( joint ); };
|
||||
void setJoint(LLJoint* joint) { mManip->setJoint(joint); };
|
||||
void setReferenceFrame(E_PoserReferenceFrame frame) { mManip->setReferenceFrame(frame); };
|
||||
|
||||
// Optional override if you have SHIFT/CTRL combos
|
||||
virtual LLTool* getOverrideTool(MASK mask) override;
|
||||
|
|
|
|||
|
|
@ -913,7 +913,27 @@ void handleUsernameFormatOptionChanged(const LLSD& newvalue)
|
|||
// <FS:Ansariel> Global online status toggle
|
||||
void handleGlobalOnlineStatusChanged(const LLSD& newvalue)
|
||||
{
|
||||
if (gSavedPerAccountSettings.getBOOL("GlobalOnlineStatusCurrentlyReverting"))
|
||||
{
|
||||
gSavedPerAccountSettings.setBOOL("GlobalOnlineStatusCurrentlyReverting", false);
|
||||
return;
|
||||
}
|
||||
bool visible = newvalue.asBoolean();
|
||||
LLSD payload;
|
||||
payload["visible"] = visible;
|
||||
LLNotificationsUtil::add("ConfirmGlobalOnlineStatusToggle", LLSD(), payload, applyGlobalOnlineStatusChange);
|
||||
}
|
||||
|
||||
void applyGlobalOnlineStatusChange(const LLSD& notification, const LLSD& response)
|
||||
{
|
||||
bool visible = notification["payload"]["visible"].asBoolean();
|
||||
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
|
||||
if (option != 0)
|
||||
{
|
||||
gSavedPerAccountSettings.setBOOL("GlobalOnlineStatusCurrentlyReverting", true);
|
||||
gSavedPerAccountSettings.setBOOL("GlobalOnlineStatusToggle", !visible);
|
||||
return;
|
||||
}
|
||||
|
||||
LLAvatarTracker::buddy_map_t all_buddies;
|
||||
LLAvatarTracker::instance().copyBuddyList(all_buddies);
|
||||
|
|
|
|||
|
|
@ -61,4 +61,8 @@ extern LLControlGroup gCrashSettings;
|
|||
// Set after settings loaded
|
||||
extern std::string gLastRunVersion;
|
||||
|
||||
// <FS> Global online status toggle
|
||||
void applyGlobalOnlineStatusChange(const LLSD& notification, const LLSD& response);
|
||||
// </FS>
|
||||
|
||||
#endif // LL_LLVIEWERCONTROL_H
|
||||
|
|
|
|||
|
|
@ -216,6 +216,7 @@
|
|||
#include "fsfloaterprotectedfolders.h"
|
||||
#include "fsfloaterradar.h"
|
||||
#include "fsfloatersearch.h"
|
||||
#include "fsfloatersplashscreensettings.h"
|
||||
#include "fsfloaterstatistics.h"
|
||||
#include "fsfloaterstreamtitle.h"
|
||||
#include "fsfloaterteleporthistory.h"
|
||||
|
|
@ -654,6 +655,7 @@ void LLViewerFloaterReg::registerFloaters()
|
|||
LLFloaterReg::add("fs_poser", "floater_fs_poser.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<FSFloaterPoser>); // <FS:AR> [FIRE-30873]: Poser
|
||||
LLFloaterReg::add("fs_protectedfolders", "floater_fs_protectedfolders.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<FSFloaterProtectedFolders>);
|
||||
LLFloaterReg::add("fs_radar", "floater_fs_radar.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<FSFloaterRadar>);
|
||||
LLFloaterReg::add("fs_splash_screen_settings", "floater_fs_splash_screen_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<FSFloaterSplashScreenSettings>);
|
||||
LLFloaterReg::add("fs_streamtitle", "floater_fs_streamtitle.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<FSFloaterStreamTitle>);
|
||||
LLFloaterReg::add("fs_streamtitlehistory", "floater_fs_streamtitlehistory.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<FSFloaterStreamTitleHistory>);
|
||||
LLFloaterReg::add("fs_teleporthistory", "floater_fs_teleporthistory.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<FSFloaterTeleportHistory>);
|
||||
|
|
|
|||
|
|
@ -2296,12 +2296,50 @@ void menu_create_inventory_item(LLInventoryPanel* panel, LLUUID dest_id, const L
|
|||
else if ("lsl" == type_name)
|
||||
{
|
||||
const LLUUID parent_id = dest_id.notNull() ? dest_id : gInventory.findCategoryUUIDForType(LLFolderType::FT_LSL_TEXT);
|
||||
|
||||
// <FS:PP> FIRE-36164 Apply the custom "New Script" setting for inventory scripts
|
||||
bool custom_script_inserted = false;
|
||||
if (gSavedPerAccountSettings.getBOOL("FSBuildPrefs_UseCustomScript"))
|
||||
{
|
||||
if (LLUUID custom_script_id(gSavedPerAccountSettings.getString("FSBuildPrefs_CustomScriptItem")); custom_script_id.notNull())
|
||||
{
|
||||
if (auto custom_script = gInventory.getItem(custom_script_id); custom_script && custom_script->getType() == LLAssetType::AT_LSL_TEXT)
|
||||
{
|
||||
LLPointer<LLBoostFuncInventoryCallback> cb = NULL;
|
||||
if (created_cb != NULL)
|
||||
{
|
||||
cb = new LLBoostFuncInventoryCallback(create_script_cb);
|
||||
cb->addOnFireFunc(created_cb);
|
||||
}
|
||||
else
|
||||
{
|
||||
cb = new LLBoostFuncInventoryCallback(create_script_cb);
|
||||
}
|
||||
copy_inventory_item(
|
||||
gAgent.getID(),
|
||||
custom_script->getPermissions().getOwner(),
|
||||
custom_script_id,
|
||||
parent_id,
|
||||
NEW_LSL_NAME,
|
||||
cb);
|
||||
custom_script_inserted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!custom_script_inserted)
|
||||
{
|
||||
// </FS:PP>
|
||||
|
||||
create_new_item(NEW_LSL_NAME,
|
||||
parent_id,
|
||||
LLAssetType::AT_LSL_TEXT,
|
||||
LLInventoryType::IT_LSL,
|
||||
PERM_MOVE | PERM_TRANSFER,
|
||||
created_cb); // overridden in create_new_item
|
||||
|
||||
// <FS:PP>
|
||||
}
|
||||
// </FS:PP>
|
||||
}
|
||||
else if ("notecard" == type_name)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
<floater name="splash_screen_settings" title="Giriş Ekranı Seçimləri">
|
||||
<text name="description">
|
||||
Giriş ekranının göstərilmə seçimlərini burada tənzimləyin. Bu seçimlər baxış proqramını növbəti dəfə yenidən başlatdığınız zaman qüvvəyə minəcək.
|
||||
</text>
|
||||
<text name="section_visibility">
|
||||
Bölmənin Görünürlüyü:
|
||||
</text>
|
||||
<check_box label="Üst paneli gizlət" name="hide_top_bar" />
|
||||
<check_box label="Bloqlar bölməsini gizlət" name="hide_blogs" />
|
||||
<check_box label="Təyinat yerlərini gizlət" name="hide_destinations" />
|
||||
<text name="section_accessibility">
|
||||
Əlçatanlıq Seçimləri:
|
||||
</text>
|
||||
<check_box label="Boz rəng rejimini aktivləşdir" name="use_gray_mode" />
|
||||
<check_box label="Yüksək kontrast rejimini aktivləşdir" name="use_high_contrast" />
|
||||
<check_box label=""BÖYÜK HƏRİFLƏR" rejimini aktivləşdirin" name="use_all_caps" />
|
||||
<check_box label="Daha böyük şriftlərdən istifadə edin" name="use_larger_fonts"/>
|
||||
<check_box label="Şəffaflıq effektlərini söndürün" name="no_transparency" />
|
||||
</floater>
|
||||
|
|
@ -259,7 +259,7 @@
|
|||
name="mesh_preview_degenerate_edge_color"/>
|
||||
<color_swatch label="Pis doldurma"
|
||||
tool_tip="Önizləmə pəncərəsində degenerativ (nazik) üçbucaqların rəngini doldurun"
|
||||
name="mesh_degenerate_fill_color"/>
|
||||
name="mesh_preview_degenerate_fill_color"/>
|
||||
</panel>
|
||||
</tab_container>
|
||||
<panel name="weights_and_warning_panel">
|
||||
|
|
|
|||
|
|
@ -186,7 +186,7 @@
|
|||
<panel name="joints_parent_panel">
|
||||
<tab_container name="joints_tabs">
|
||||
<panel title="Beweg." name="positionRotation_panel">
|
||||
<panel name="title">
|
||||
<panel name="move_tab_panel">
|
||||
<text name="av_position_updown_label">
|
||||
Hoch/Runter:
|
||||
</text>
|
||||
|
|
@ -245,7 +245,7 @@
|
|||
<scroll_list.columns label="Auswahl..." name="name"/>
|
||||
</scroll_list>
|
||||
<button name="refresh_avatars" tool_tip="Liste der Avatar und Animeshe aktualisieren"/>
|
||||
<button label="Posieren starten" label_selected="Posieren stoppen" tool_tip="Posieren des ausgewählten Avatar oder Animesh starten sofern berechtigt" name="start_stop_posing_button"/>
|
||||
<button label="Posieren starten" label_selected="Posieren stoppen" tool_tip="Posieren des ausgewählten Avatar oder Animesh starten sofern berechtigt." name="start_stop_posing_button"/>
|
||||
<button label="Auf T-Pose setzen" tool_tip="Klicken, um den ausgewählten Avatar auf eine T-Pose zu setzen" name="set_t_pose_button"/>
|
||||
</panel>
|
||||
<panel title="Einst." name="settings_panel">
|
||||
|
|
@ -306,6 +306,9 @@
|
|||
<button name="toggle_LockWorldRotation" tool_tip="Rotation In-World für die ausgewählten Glieder sperren. Gesperrte Glieder behalten dieselbe Rotation, wenn ihre Eltern-Glieder bewegt werden. Beispiel: Wenn die Augen gesperrt sind und der Kopf gedreht wird, schauen die Augen weiterhin (fast) in dieselbe Richtung."/>
|
||||
<button label="Spieg." name="button_toggleMirrorRotation" tool_tip="Änderungen an gegenüberliegendem Gelenk spiegeln."/>
|
||||
<button label="Sym." name="button_toggleSympatheticRotation" tool_tip="Gegenüberliegendes Gelenk gleichermaßen anpassen."/>
|
||||
<button label="W" name="poser_world_frame_toggle" tool_tip="Rotationsänderung relativ zur Welt durchführen"/>
|
||||
<button label="A" name="poser_avatar_frame_toggle" tool_tip="Rotationsänderung relativ zum Avatar durchführen"/>
|
||||
<button label="B" name="poser_screen_frame_toggle" tool_tip="Rotationsänderung relativ zum Bildschirm durchführen"/>
|
||||
<button label="Kopie L > P" name="button_symmetrize_left_to_right" tool_tip="Klicken, um Änderung von linker Seite zur rechten Seite zu kopieren." />
|
||||
<button label="Kopie P > L" name="button_symmetrize_right_to_left" tool_tip="Klicken, um Änderung von rechter Seite zur linken Seite zu kopieren." />
|
||||
</panel>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
<floater name="splash_screen_settings" title="Splash Screen Einstellungen">
|
||||
<text name="description">
|
||||
Konfigurieren Sie hier die Anzeigeoptionen für den Splash Screen. Diese Einstellungen werden beim nächsten Neustart des Viewers wirksam.
|
||||
</text>
|
||||
<text name="section_visibility">
|
||||
Sichtbarkeit des Bereichs:
|
||||
</text>
|
||||
<check_box label="Obere Leiste ausblenden" name="hide_top_bar" />
|
||||
<check_box label="Blogbereich ausblenden" name="hide_blogs" />
|
||||
<check_box label="Ziele ausblenden" name="hide_destinations" />
|
||||
<text name="section_accessibility">
|
||||
Barrierefreiheitsoptionen:
|
||||
</text>
|
||||
<check_box label="Graustufenmodus aktivieren" name="use_gray_mode" />
|
||||
<check_box label="Modus für hohen Kontrast aktivieren" name="use_high_contrast" />
|
||||
<check_box label="„GROSSBUCHSTABEN“-Modus aktivieren" name="use_all_caps" />
|
||||
<check_box label="Größere Schriftarten verwenden" name="use_larger_fonts"/>
|
||||
<check_box label="Transparenzeffekte deaktivieren" name="no_transparency" />
|
||||
</floater>
|
||||
|
|
@ -481,7 +481,7 @@
|
|||
Physik-Probleme:
|
||||
</text>
|
||||
<color_swatch label="Schlechte Kante" tool_tip="Farbe für degenerierte (dünne) Dreiecks-Kanten im Vorschau-Fenster" name="mesh_preview_degenerate_edge_color"/>
|
||||
<color_swatch label="Schlechte Dreiecke" tool_tip="Füllfarbe für degenerierte (dünne) Dreiecke im Vorschau-Fenster" name="mesh_degenerate_fill_color"/>
|
||||
<color_swatch label="Schlechte Dreiecke" tool_tip="Füllfarbe für degenerierte (dünne) Dreiecke im Vorschau-Fenster" name="mesh_preview_degenerate_fill_color"/>
|
||||
</panel>
|
||||
</tab_container>
|
||||
<panel name="weights_and_warning_panel">
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
<menu_item_call label="Bezahlen" name="Pay"/>
|
||||
<menu_item_call label="Name in Zwischenablage kopieren" name="copy name"/>
|
||||
<menu_item_call label="Url in Zwischenablage kopieren" name="copy url"/>
|
||||
<menu_item_call label="Erwähnung-Url in Zwischenablage kopieren" name="mention_copy_label"/>
|
||||
<menu_item_call label="Missbrauch melden" name="Report Abuse"/>
|
||||
<menu_item_check label="Voice blockieren" name="Block Unblock"/>
|
||||
<menu_item_check label="Chat blockieren" name="Mute Text"/>
|
||||
|
|
@ -28,4 +29,5 @@
|
|||
<menu_item_call label="Stummschaltung für diesen Teilnehmer aufheben" name="ModerateVoiceUnMuteSelected"/>
|
||||
</context_menu>
|
||||
<menu_item_call label="Mitglied verbannen" name="BanMember"/>
|
||||
<menu_item_call label="Einwohner in Chat erwähnen" name="mention_in_chat"/>
|
||||
</toggleable_menu>
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@
|
|||
<menu_item_call label="Freund verfolgen" name="track_agent"/>
|
||||
<menu_item_call label="Freund entfernen..." name="remove_friend"/>
|
||||
<menu_item_call label="Name in Zwischenablage kopieren" name="url_copy_label"/>
|
||||
<menu_item_call label="SLurl in die Zwischenablage kopieren" name="url_copy"/>
|
||||
<menu_item_call label="Url in die Zwischenablage kopieren" name="url_copy"/>
|
||||
<menu_item_call label="Erwähnung-Url in Zwischenablage kopieren" name="mention_copy_label"/>
|
||||
<menu name="options" label="Optionen...">
|
||||
<menu_item_check label="Benutzername anzeigen" name="show_username"/>
|
||||
<menu_item_check label="Anzeigename anzeigen" name="show_displayname"/>
|
||||
|
|
|
|||
|
|
@ -23,4 +23,6 @@
|
|||
<menu_item_call label="Alle freischalten" name="ModerateVoiceUnmute"/>
|
||||
</context_menu>
|
||||
<menu_item_call label="Mitglied verbannen" name="BanMember"/>
|
||||
<menu_item_call label="Erwähnung-Url in Zwischenablage kopieren" name="mention_copy_label"/>
|
||||
<menu_item_call label="Einwohner in Chat erwähnen" name="mention_in_chat"/>
|
||||
</context_menu>
|
||||
|
|
|
|||
|
|
@ -20,5 +20,7 @@
|
|||
<menu_item_call label="Aus Gruppe entfernen" name="BanEjectMember"/>
|
||||
</context_menu>
|
||||
<menu_item_call label="Name in Zwischenablage kopieren" name="url_copy_label"/>
|
||||
<menu_item_call label="SLurl in die Zwischenablage kopieren" name="url_copy"/>
|
||||
<menu_item_call label="Url in die Zwischenablage kopieren" name="url_copy"/>
|
||||
<menu_item_call label="Erwähnung-Url in Zwischenablage kopieren" name="mention_copy_label"/>
|
||||
<menu_item_call label="Einwohner in Chat erwähnen" name="mention_in_chat"/>
|
||||
</context_menu>
|
||||
|
|
|
|||
|
|
@ -5844,6 +5844,12 @@ Welche Bezeichnung soll für die Region
|
|||
Neue Auswahl kann nicht erstellt werden, da bereits die maximale Anzahl an Auswahlen erstellt wurde.
|
||||
<usetemplate name="okbutton" yestext="OK"/>
|
||||
</notification>
|
||||
<notification name="ConfirmGlobalOnlineStatusToggle">
|
||||
Sind Sie sicher, dass Sie die Sichtbarkeit Ihres Online-Status für alle Ihre Freunde auf einmal ändern möchten?
|
||||
|
||||
Abhängig von der Serverauslastung kann es einen Moment dauern, bis das Umschalten der Sichtbarkeit des Online-Status effektiv wird, und es kann zeitweise zu Problemen mit Ihrem Online-Status für Ihre Freunde führen.
|
||||
<usetemplate name="okcancelbuttons" notext="Abbrechen" yestext="OK"/>
|
||||
</notification>
|
||||
<notification name="GlobalOnlineStatusToggle">
|
||||
Abhängig von der Serverauslastung kann es einen Moment dauern, bis das Umschalten der Sichtbarkeit des Online-Status effektiv wird.
|
||||
<usetemplate ignoretext="Weise mich darauf hin, dass das Umschalten der Sichtbarkeit des Online-Status etwas dauern kann." name="okignore" yestext="OK"/>
|
||||
|
|
@ -5915,7 +5921,7 @@ https://wiki.firestormviewer.org/antivirus_whitelisting
|
|||
<usetemplate name="okcancelbuttons" notext="Abbrechen" yestext="Okay"/>
|
||||
</notification>
|
||||
<notification name="FSLargeOutfitsWarningInThisSession">
|
||||
Eine große Anzahl an Outfits wurde erkannt: [AMOUNT]. Dies kann zu einem Blockieren des Viewers oder zu Verbindungsabbrüchen führen. Ziehen Sie eine Reduzierung der Outfits für eine bessere Performance in Betracht (unter [MAX]).
|
||||
Eine große Anzahl an Outfits wurde erkannt: [AMOUNT]. Dies kann zu einem Blockieren des Viewers oder zu Verbindungsabbrüchen führen. Ziehen Sie eine Reduzierung der Outfits für eine bessere Performance in Betracht (unter [MAX]). DIES IST NUR EIN VORSCHLAG - wenn Ihr Computer normal funktioniert, können Sie diesen Vorschlag bedenkenlos ignorieren.
|
||||
<usetemplate ignoretext="Warnung bei zu vielen Outfits" name="okignore" yestext="OK" />
|
||||
</notification>
|
||||
<notification name="PrimfeedLoginRequestFailed">
|
||||
|
|
|
|||
|
|
@ -7303,4 +7303,22 @@ Ihre aktuelle Position: [AVATAR_POS]
|
|||
<string name="ImportSuccessful">
|
||||
[COUNT] Einträge erfolgreich verarbeitet.
|
||||
</string>
|
||||
<string name="Flood">
|
||||
Füllen
|
||||
</string>
|
||||
<string name="Surface Only">
|
||||
Nur Oberfläche
|
||||
</string>
|
||||
<string name="Raycast">
|
||||
Raycast
|
||||
</string>
|
||||
<string name="Very High">
|
||||
Sehr Hoch
|
||||
</string>
|
||||
<string name="Ultra">
|
||||
Ultra
|
||||
</string>
|
||||
<string name="Maximum">
|
||||
Maximum
|
||||
</string>
|
||||
</strings>
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
|
||||
<floater
|
||||
positioning="None"
|
||||
save_rect="true"
|
||||
height="330"
|
||||
layout="topleft"
|
||||
name="floater_poser"
|
||||
title="Avatar and Animesh Poser"
|
||||
help_topic="poser"
|
||||
width="430">
|
||||
positioning="None"
|
||||
save_rect="true"
|
||||
height="330"
|
||||
layout="topleft"
|
||||
name="floater_poser"
|
||||
title="Avatar and Animesh Poser"
|
||||
help_topic="poser"
|
||||
width="450">
|
||||
<string name="icon_category" translate="false">Inv_BodyShape</string>
|
||||
<string name="icon_bone" translate="false"></string>
|
||||
<string name="icon_object" translate="false">Inv_Object</string>
|
||||
|
|
@ -83,8 +83,6 @@ width="430">
|
|||
<string name="joint_transform_mFaceCheekLowerLeft" translate="false">SWAP_YAW_AND_ROLL NEGATE_PITCH</string>
|
||||
<string name="joint_transform_mFaceCheekUpperRight" translate="false">SWAP_YAW_AND_ROLL NEGATE_PITCH</string>
|
||||
<string name="joint_transform_mFaceCheekLowerRight" translate="false">SWAP_YAW_AND_ROLL NEGATE_PITCH</string>
|
||||
<string name="joint_transform_mFaceLipUpperLeft" translate="false">SWAP_YAW_AND_ROLL NEGATE_PITCH</string>
|
||||
<string name="joint_transform_mFaceLipUpperRight" translate="false">SWAP_YAW_AND_ROLL NEGATE_PITCH</string>
|
||||
<string name="joint_transform_mHandThumb1Left" translate="false">SWAP_ROLL_AND_PITCH</string>
|
||||
<string name="joint_transform_mHandThumb1Right" translate="false">SWAP_ROLL_AND_PITCH NEGATE_PITCH</string>
|
||||
<string name="joint_transform_mHandThumb2Left" translate="false">SWAP_ROLL_AND_PITCH</string>
|
||||
|
|
@ -160,6 +158,105 @@ width="430">
|
|||
<string name="joint_transform_mFaceForeheadCenter" translate="false">SWAP_YAW_AND_ROLL NEGATE_PITCH</string>
|
||||
<string name="joint_transform_mFaceForeheadRight" translate="false">SWAP_YAW_AND_ROLL NEGATE_PITCH</string>
|
||||
|
||||
<!-- Begins with joint_transform_ then has an internal joint name, ONE swap choice of:
|
||||
SWAP_NOTHING, SWAP_YAW_AND_ROLL, SWAP_YAW_AND_PITCH , SWAP_ROLL_AND_PITCH, SWAP_X2Y_Y2Z_Z2X, SWAP_X2Z_Y2X_Z2Y -->
|
||||
<string name="joint_frame_mPelvis" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mTorso" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mChest" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mNeck" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mHead" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mCollarLeft" translate="false">NEGATE_ROLL NEGATE_PITCH</string>
|
||||
<string name="joint_frame_mShoulderLeft" translate="false">NEGATE_ROLL NEGATE_PITCH</string>
|
||||
<string name="joint_frame_mElbowLeft" translate="false">NEGATE_ROLL NEGATE_PITCH</string>
|
||||
<string name="joint_frame_mWristLeft" translate="false">NEGATE_ROLL NEGATE_PITCH</string>
|
||||
<string name="joint_frame_mCollarRight" translate="false">NEGATE_ROLL NEGATE_PITCH</string>
|
||||
<string name="joint_frame_mShoulderRight" translate="false">NEGATE_ROLL NEGATE_PITCH</string>
|
||||
<string name="joint_frame_mElbowRight" translate="false">NEGATE_ROLL NEGATE_PITCH</string>
|
||||
<string name="joint_frame_mWristRight" translate="false">NEGATE_ROLL NEGATE_PITCH</string>
|
||||
<string name="joint_frame_mHipLeft" translate="false">NEGATE_ROLL NEGATE_PITCH</string>
|
||||
<string name="joint_frame_mKneeLeft" translate="false">NEGATE_ROLL NEGATE_PITCH</string>
|
||||
<string name="joint_frame_mAnkleLeft" translate="false">NEGATE_ROLL NEGATE_PITCH</string>
|
||||
<string name="joint_frame_mFootLeft" translate="false">NEGATE_ROLL NEGATE_PITCH</string>
|
||||
<string name="joint_frame_mToeLeft" translate="false">NEGATE_ROLL NEGATE_PITCH</string>
|
||||
<string name="joint_frame_mHipRight" translate="false">NEGATE_ROLL NEGATE_PITCH</string>
|
||||
<string name="joint_frame_mKneeRight" translate="false">NEGATE_ROLL NEGATE_PITCH</string>
|
||||
<string name="joint_frame_mAnkleRight" translate="false">NEGATE_ROLL NEGATE_PITCH</string>
|
||||
<string name="joint_frame_mFootRight" translate="false">NEGATE_ROLL NEGATE_PITCH</string>
|
||||
<string name="joint_frame_mToeRight" translate="false">NEGATE_ROLL NEGATE_PITCH</string>
|
||||
<string name="joint_frame_mHandThumb1Left" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mHandThumb1Right" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mHandThumb2Left" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mHandThumb2Right" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mHandThumb3Left" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mHandThumb3Right" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mHandIndex1Left" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mHandIndex1Right" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mHandIndex2Left" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mHandIndex2Right" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mHandIndex3Left" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mHandIndex3Right" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mHandMiddle1Left" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mHandMiddle1Right" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mHandMiddle2Left" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mHandMiddle2Right" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mHandMiddle3Left" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mHandMiddle3Right" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mHandRing1Left" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mHandRing1Right" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mHandRing2Left" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mHandRing2Right" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mHandRing3Left" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mHandRing3Right" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mHandPinky1Left" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mHandPinky1Right" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mHandPinky2Left" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mHandPinky2Right" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mHandPinky3Left" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mHandPinky3Right" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mEyeRight" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mEyeLeft" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceTeethLower" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceTeethUpper" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceLipCornerRight" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceLipCornerLeft" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceLipUpperLeft" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceLipUpperCenter" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceLipUpperRight" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceLipLowerLeft" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceLipLowerCenter" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceLipLowerRight" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceEyeLidUpperLeft" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceEyeLidUpperRight" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceEyecornerInnerLeft" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceEyecornerInnerRight" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceEyeLidLowerLeft" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceEyeLidLowerRight" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceEyebrowOuterLeft" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceEyebrowOuterRight" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceEyebrowCenterLeft" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceEyebrowCenterRight" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceEyebrowInnerLeft" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceEyebrowInnerRight" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceCheekUpperLeft" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceCheekLowerLeft" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceCheekUpperRight" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceCheekLowerRight" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceTongueBase" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceTongueTip" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceEar1Left" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceEar2Left" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceEar1Right" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceEar2Right" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceNoseBase" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceNoseBridge" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceNoseLeft" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceNoseCenter" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceNoseRight" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceForeheadLeft" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceForeheadCenter" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceForeheadRight" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
<string name="joint_frame_mFaceJaw" translate="false">SWAP_YAW_AND_ROLL NEGATE_ALL</string>
|
||||
|
||||
<!-- For the joints/bones/thingos that are apt to Gimbal Lock, we may instead apply rotations as deltas by default, which never lock -->
|
||||
<string name="joint_delta_rotate_mHipLeft">true</string>
|
||||
<string name="joint_delta_rotate_mHipRight">true</string>
|
||||
|
|
@ -416,7 +513,7 @@ width="430">
|
|||
layout="topleft"
|
||||
mouse_opaque="false"
|
||||
left="5"
|
||||
name="title"
|
||||
name="move_tab_panel"
|
||||
top="0"
|
||||
width="235">
|
||||
<text follows="left|top"
|
||||
|
|
@ -873,7 +970,7 @@ width="430">
|
|||
name="refresh_avatars"
|
||||
tool_tip="Refresh the list of avatars and animeshes"
|
||||
width="20"
|
||||
top="232"
|
||||
top="221"
|
||||
left="3">
|
||||
<button.commit_callback
|
||||
function="Poser.RefreshAvatars"/>
|
||||
|
|
@ -894,7 +991,7 @@ width="430">
|
|||
flash_color="0.7 0.7 1 1"
|
||||
button_flash_count="64"
|
||||
button_flash_rate="0.5"
|
||||
tool_tip="Start posing the selected avatar or animesh, if you are allowed to"
|
||||
tool_tip="Start posing the selected avatar or animesh, if you are allowed to."
|
||||
name="start_stop_posing_button"
|
||||
width="150">
|
||||
<button.commit_callback
|
||||
|
|
@ -1018,7 +1115,7 @@ width="430">
|
|||
label="Show joint markers"
|
||||
follows="left|top"
|
||||
left="5"
|
||||
tool_tip="Show small indicators to aid joint selection when visually posing."
|
||||
tool_tip="Show small indicators to aid joint selection when posing."
|
||||
top_pad="5"
|
||||
width="134" />
|
||||
<check_box
|
||||
|
|
@ -1060,7 +1157,7 @@ width="430">
|
|||
name="joint_manipulation_panel"
|
||||
enabled="true"
|
||||
top="0"
|
||||
width="215"
|
||||
width="235"
|
||||
left_pad="0">
|
||||
<tab_container
|
||||
follows="all"
|
||||
|
|
@ -1073,7 +1170,7 @@ width="430">
|
|||
tab_group="1"
|
||||
tab_position="top"
|
||||
top_pad="0"
|
||||
width="215">
|
||||
width="235">
|
||||
<panel
|
||||
follows="left|right|top|bottom"
|
||||
height="265"
|
||||
|
|
@ -1084,7 +1181,7 @@ width="430">
|
|||
name="trackball_panel"
|
||||
enabled="false"
|
||||
top="0"
|
||||
width="215"
|
||||
width="235"
|
||||
left="0">
|
||||
<fs_virtual_trackpad
|
||||
name="limb_rotation"
|
||||
|
|
@ -1092,7 +1189,7 @@ width="430">
|
|||
top="2"
|
||||
height="160"
|
||||
width="160"
|
||||
left="15"
|
||||
left="30"
|
||||
tool_tip="Change the rotation of the currently selected body part(s). Hold Ctrl to move slow. Roll the wheel to adjust the 3rd axis. Use Shift or Alt to swap which rotations change"
|
||||
pinch_mode="false"
|
||||
infinite_scroll_mode="true"/>
|
||||
|
|
@ -1103,7 +1200,7 @@ width="430">
|
|||
layout="topleft"
|
||||
left="5"
|
||||
top_pad="2"
|
||||
width="200">
|
||||
width="220">
|
||||
Up/Down:
|
||||
</text>
|
||||
<slider
|
||||
|
|
@ -1120,7 +1217,7 @@ width="430">
|
|||
max_val="180"
|
||||
name="limb_pitch_slider"
|
||||
top_pad="2"
|
||||
width="130" >
|
||||
width="150">
|
||||
<slider.commit_callback
|
||||
function="Poser.CommitSlider"
|
||||
parameter="4"/>
|
||||
|
|
@ -1138,7 +1235,7 @@ width="430">
|
|||
width="53">
|
||||
<spinner.commit_callback
|
||||
function="Poser.CommitSpinner"
|
||||
parameter="4"/>
|
||||
parameter="4"/>
|
||||
</spinner>
|
||||
<text
|
||||
follows="left|top"
|
||||
|
|
@ -1147,7 +1244,7 @@ width="430">
|
|||
layout="topleft"
|
||||
left="5"
|
||||
top_pad="2"
|
||||
width="200">
|
||||
width="220">
|
||||
Left/Right:
|
||||
</text>
|
||||
<slider
|
||||
|
|
@ -1164,10 +1261,10 @@ width="430">
|
|||
max_val="180"
|
||||
name="limb_yaw_slider"
|
||||
top_pad="2"
|
||||
width="130" >
|
||||
width="150">
|
||||
<slider.commit_callback
|
||||
function="Poser.CommitSlider"
|
||||
parameter="5"/>
|
||||
parameter="5"/>
|
||||
</slider>
|
||||
<spinner
|
||||
height="16"
|
||||
|
|
@ -1182,7 +1279,7 @@ width="430">
|
|||
width="53">
|
||||
<spinner.commit_callback
|
||||
function="Poser.CommitSpinner"
|
||||
parameter="5"/>
|
||||
parameter="5"/>
|
||||
</spinner>
|
||||
<text
|
||||
follows="left|top"
|
||||
|
|
@ -1191,7 +1288,7 @@ width="430">
|
|||
layout="topleft"
|
||||
left="5"
|
||||
top_pad="2"
|
||||
width="200">
|
||||
width="220">
|
||||
Roll:
|
||||
</text>
|
||||
<slider
|
||||
|
|
@ -1208,10 +1305,10 @@ width="430">
|
|||
max_val="180"
|
||||
name="limb_roll_slider"
|
||||
top_pad="2"
|
||||
width="130" >
|
||||
width="150">
|
||||
<slider.commit_callback
|
||||
function="Poser.CommitSlider"
|
||||
parameter="6"/>
|
||||
parameter="6"/>
|
||||
</slider>
|
||||
<spinner
|
||||
height="16"
|
||||
|
|
@ -1226,7 +1323,7 @@ width="430">
|
|||
width="53">
|
||||
<spinner.commit_callback
|
||||
function="Poser.CommitSpinner"
|
||||
parameter="6"/>
|
||||
parameter="6"/>
|
||||
</spinner>
|
||||
</panel>
|
||||
<panel
|
||||
|
|
@ -1238,7 +1335,7 @@ width="430">
|
|||
title="Move / Scale"
|
||||
name="position_panel"
|
||||
top="0"
|
||||
width="170">
|
||||
width="190">
|
||||
<text
|
||||
follows="left|top"
|
||||
name="pos_x_label"
|
||||
|
|
@ -1246,7 +1343,7 @@ width="430">
|
|||
layout="topleft"
|
||||
left="5"
|
||||
top_pad="2"
|
||||
width="200">
|
||||
width="220">
|
||||
Position X:
|
||||
</text>
|
||||
<slider
|
||||
|
|
@ -1263,7 +1360,7 @@ width="430">
|
|||
min_val="-1.5"
|
||||
name="Advanced_Position_X"
|
||||
top_pad="2"
|
||||
width="130" >
|
||||
width="150">
|
||||
<slider.commit_callback
|
||||
function="Poser.CommitSlider"
|
||||
parameter="7"/>
|
||||
|
|
@ -1281,7 +1378,7 @@ width="430">
|
|||
width="53">
|
||||
<spinner.commit_callback
|
||||
function="Poser.CommitSpinner"
|
||||
parameter="7"/>
|
||||
parameter="7"/>
|
||||
</spinner>
|
||||
<text
|
||||
follows="left|top"
|
||||
|
|
@ -1290,7 +1387,7 @@ width="430">
|
|||
layout="topleft"
|
||||
left="5"
|
||||
top_pad="2"
|
||||
width="200">
|
||||
width="220">
|
||||
Position Y:
|
||||
</text>
|
||||
<slider
|
||||
|
|
@ -1307,10 +1404,10 @@ width="430">
|
|||
min_val="-1.5"
|
||||
name="Advanced_Position_Y"
|
||||
top_pad="2"
|
||||
width="130" >
|
||||
width="150">
|
||||
<slider.commit_callback
|
||||
function="Poser.CommitSlider"
|
||||
parameter="8"/>
|
||||
parameter="8"/>
|
||||
</slider>
|
||||
<spinner
|
||||
height="20"
|
||||
|
|
@ -1325,7 +1422,7 @@ width="430">
|
|||
width="53">
|
||||
<spinner.commit_callback
|
||||
function="Poser.CommitSpinner"
|
||||
parameter="8"/>
|
||||
parameter="8"/>
|
||||
</spinner>
|
||||
<text
|
||||
follows="left|top"
|
||||
|
|
@ -1334,7 +1431,7 @@ width="430">
|
|||
layout="topleft"
|
||||
left="5"
|
||||
top_pad="2"
|
||||
width="200">
|
||||
width="220">
|
||||
Position Z:
|
||||
</text>
|
||||
<slider
|
||||
|
|
@ -1351,10 +1448,10 @@ width="430">
|
|||
min_val="-1.5"
|
||||
name="Advanced_Position_Z"
|
||||
top_pad="2"
|
||||
width="130" >
|
||||
width="150">
|
||||
<slider.commit_callback
|
||||
function="Poser.CommitSlider"
|
||||
parameter="9"/>
|
||||
parameter="9"/>
|
||||
</slider>
|
||||
<spinner
|
||||
height="20"
|
||||
|
|
@ -1369,7 +1466,7 @@ width="430">
|
|||
width="53">
|
||||
<spinner.commit_callback
|
||||
function="Poser.CommitSpinner"
|
||||
parameter="9"/>
|
||||
parameter="9"/>
|
||||
</spinner>
|
||||
<text
|
||||
follows="left|top"
|
||||
|
|
@ -1378,7 +1475,7 @@ width="430">
|
|||
layout="topleft"
|
||||
left="5"
|
||||
top_pad="15"
|
||||
width="200">
|
||||
width="220">
|
||||
Scale X:
|
||||
</text>
|
||||
<slider
|
||||
|
|
@ -1395,10 +1492,10 @@ width="430">
|
|||
min_val="-1.5"
|
||||
name="Advanced_Scale_X"
|
||||
top_pad="2"
|
||||
width="130" >
|
||||
width="150">
|
||||
<slider.commit_callback
|
||||
function="Poser.CommitSlider"
|
||||
parameter="10"/>
|
||||
parameter="10"/>
|
||||
</slider>
|
||||
<spinner
|
||||
height="20"
|
||||
|
|
@ -1413,7 +1510,7 @@ width="430">
|
|||
width="53">
|
||||
<spinner.commit_callback
|
||||
function="Poser.CommitSpinner"
|
||||
parameter="10"/>
|
||||
parameter="10"/>
|
||||
</spinner>
|
||||
<text
|
||||
follows="left|top"
|
||||
|
|
@ -1422,7 +1519,7 @@ width="430">
|
|||
layout="topleft"
|
||||
left="5"
|
||||
top_pad="2"
|
||||
width="200">
|
||||
width="220">
|
||||
Scale Y:
|
||||
</text>
|
||||
<slider
|
||||
|
|
@ -1439,10 +1536,10 @@ width="430">
|
|||
min_val="-1.5"
|
||||
name="Advanced_Scale_Y"
|
||||
top_pad="2"
|
||||
width="130" >
|
||||
width="150">
|
||||
<slider.commit_callback
|
||||
function="Poser.CommitSlider"
|
||||
parameter="11"/>
|
||||
parameter="11"/>
|
||||
</slider>
|
||||
<spinner
|
||||
height="20"
|
||||
|
|
@ -1457,7 +1554,7 @@ width="430">
|
|||
width="53">
|
||||
<spinner.commit_callback
|
||||
function="Poser.CommitSpinner"
|
||||
parameter="11"/>
|
||||
parameter="11"/>
|
||||
</spinner>
|
||||
<text
|
||||
follows="left|top"
|
||||
|
|
@ -1466,7 +1563,7 @@ width="430">
|
|||
layout="topleft"
|
||||
left="5"
|
||||
top_pad="2"
|
||||
width="200">
|
||||
width="220">
|
||||
Scale Z:
|
||||
</text>
|
||||
<slider
|
||||
|
|
@ -1483,10 +1580,10 @@ width="430">
|
|||
min_val="-1.5"
|
||||
name="Advanced_Scale_Z"
|
||||
top_pad="2"
|
||||
width="130" >
|
||||
width="150">
|
||||
<slider.commit_callback
|
||||
function="Poser.CommitSlider"
|
||||
parameter="12"/>
|
||||
parameter="12"/>
|
||||
</slider>
|
||||
<spinner
|
||||
height="20"
|
||||
|
|
@ -1501,7 +1598,7 @@ width="430">
|
|||
width="53">
|
||||
<spinner.commit_callback
|
||||
function="Poser.CommitSpinner"
|
||||
parameter="12"/>
|
||||
parameter="12"/>
|
||||
</spinner>
|
||||
</panel>
|
||||
</tab_container>
|
||||
|
|
@ -1514,7 +1611,7 @@ width="430">
|
|||
left="0"
|
||||
top_pad="2"
|
||||
name="trackball_button_panel"
|
||||
width="232">
|
||||
width="252">
|
||||
<button
|
||||
height="21"
|
||||
follows="top|left"
|
||||
|
|
@ -1583,7 +1680,7 @@ width="430">
|
|||
left_pad="1"
|
||||
top_delta="0"
|
||||
tool_tip="Lock rotation in the world for the selected limb(s). Limbs that are world-locked keep the same rotation in-world when their parent-limbs move. Eg: lock your eyes and turn your head, your eyes keep looking (mostly) in the same direction."
|
||||
width="18" >
|
||||
width="18">
|
||||
</button>
|
||||
<button
|
||||
follows="left|top"
|
||||
|
|
@ -1602,7 +1699,7 @@ width="430">
|
|||
tool_tip="Mirror changes to the opposite joint."
|
||||
left_pad="1"
|
||||
top_delta="0"
|
||||
width="43" >
|
||||
width="53">
|
||||
<button.commit_callback
|
||||
function="Poser.ToggleMirrorChanges"/>
|
||||
</button>
|
||||
|
|
@ -1623,34 +1720,112 @@ width="430">
|
|||
tool_tip="Copy changes to the opposite joint."
|
||||
left_pad="1"
|
||||
top_delta="0"
|
||||
width="43" >
|
||||
width="53">
|
||||
<button.commit_callback
|
||||
function="Poser.ToggleSympatheticChanges"/>
|
||||
</button>
|
||||
<button
|
||||
follows="left|top"
|
||||
height="18"
|
||||
is_toggle="true"
|
||||
layout="topleft"
|
||||
label="W"
|
||||
image_hover_unselected="Toolbar_Middle_Over"
|
||||
image_selected="Toolbar_Middle_Selected"
|
||||
image_unselected="Toolbar_Middle_Off"
|
||||
button_flash_enable="true"
|
||||
flash_color="0.7 0.7 1 1"
|
||||
button_flash_count="64"
|
||||
button_flash_rate="0.5"
|
||||
name="poser_world_frame_toggle"
|
||||
left_pad="1"
|
||||
left="2"
|
||||
top_pad="0"
|
||||
tool_tip="Make rotational changes relative to World"
|
||||
width="18">
|
||||
<button.commit_callback
|
||||
function="Poser.ToggleRotationFrame"/>
|
||||
</button>
|
||||
<button
|
||||
follows="left|top"
|
||||
height="18"
|
||||
is_toggle="true"
|
||||
layout="topleft"
|
||||
label="A"
|
||||
image_hover_unselected="Toolbar_Middle_Over"
|
||||
image_selected="Toolbar_Middle_Selected"
|
||||
image_unselected="Toolbar_Middle_Off"
|
||||
button_flash_enable="true"
|
||||
flash_color="0.7 0.7 1 1"
|
||||
button_flash_count="64"
|
||||
button_flash_rate="0.5"
|
||||
name="poser_avatar_frame_toggle"
|
||||
left_pad="0"
|
||||
top_delta="0"
|
||||
tool_tip="Make rotational changes relative to Avatar"
|
||||
width="15">
|
||||
<button.commit_callback
|
||||
function="Poser.ToggleRotationFrame"/>
|
||||
</button>
|
||||
<button
|
||||
follows="left|top"
|
||||
height="18"
|
||||
is_toggle="true"
|
||||
layout="topleft"
|
||||
label="S"
|
||||
image_hover_unselected="Toolbar_Middle_Over"
|
||||
image_selected="Toolbar_Middle_Selected"
|
||||
image_unselected="Toolbar_Middle_Off"
|
||||
button_flash_enable="true"
|
||||
flash_color="0.7 0.7 1 1"
|
||||
button_flash_count="64"
|
||||
button_flash_rate="0.5"
|
||||
name="poser_screen_frame_toggle"
|
||||
left_pad="0"
|
||||
top_delta="0"
|
||||
tool_tip="Make rotational changes relative to Screen"
|
||||
width="15">
|
||||
<button.commit_callback
|
||||
function="Poser.ToggleRotationFrame"/>
|
||||
</button>
|
||||
<button
|
||||
follows="left|top"
|
||||
height="18"
|
||||
layout="topleft"
|
||||
label="Copy L > R"
|
||||
name="button_symmetrize_left_to_right"
|
||||
image_hover_unselected="Toolbar_Middle_Over"
|
||||
image_selected="Toolbar_Middle_Selected"
|
||||
image_unselected="Toolbar_Middle_Off"
|
||||
button_flash_enable="true"
|
||||
flash_color="0.7 0.7 1 1"
|
||||
button_flash_count="64"
|
||||
button_flash_rate="0.5"
|
||||
tool_tip="Click to copy change from left side to right side."
|
||||
left="14"
|
||||
top_pad="0"
|
||||
width="70" >
|
||||
left_pad="1"
|
||||
top_delta="0"
|
||||
width="77">
|
||||
<button.commit_callback
|
||||
function="Poser.Symmetrize"
|
||||
parameter="1"/>
|
||||
</button>
|
||||
<button
|
||||
follows="left|top"
|
||||
height="19"
|
||||
height="18"
|
||||
layout="topleft"
|
||||
label="Copy R > L"
|
||||
name="button_symmetrize_right_to_left"
|
||||
image_hover_unselected="Toolbar_Middle_Over"
|
||||
image_selected="Toolbar_Middle_Selected"
|
||||
image_unselected="Toolbar_Middle_Off"
|
||||
button_flash_enable="true"
|
||||
flash_color="0.7 0.7 1 1"
|
||||
button_flash_count="64"
|
||||
button_flash_rate="0.5"
|
||||
tool_tip="Click to copy change from right side to left side."
|
||||
left_pad="23"
|
||||
left_pad="1"
|
||||
top_delta="0"
|
||||
width="70" >
|
||||
width="77">
|
||||
<button.commit_callback
|
||||
function="Poser.Symmetrize"
|
||||
parameter="2"/>
|
||||
|
|
@ -1795,7 +1970,7 @@ width="430">
|
|||
left_pad="0"
|
||||
top_delta="0"
|
||||
name="button_spacer_panel"
|
||||
width="80"/>
|
||||
width="82"/>
|
||||
<button
|
||||
follows="left|top"
|
||||
height="21"
|
||||
|
|
@ -1816,7 +1991,7 @@ width="430">
|
|||
left_pad="1"
|
||||
top_delta="0"
|
||||
tool_tip="Load, save and manage the poses you make"
|
||||
width="105" >
|
||||
width="125" >
|
||||
<button.commit_callback
|
||||
function="Poser.ToggleLoadSavePanel"/>
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,132 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
<floater
|
||||
name="splash_screen_settings"
|
||||
title="Splash Screen Settings"
|
||||
width="350"
|
||||
height="320"
|
||||
min_width="350"
|
||||
min_height="300"
|
||||
save_rect="true"
|
||||
single_instance="true"
|
||||
can_resize="false"
|
||||
can_minimize="true"
|
||||
can_close="true"
|
||||
can_drag_on_left="false">
|
||||
|
||||
<text
|
||||
follows="left|top"
|
||||
height="40"
|
||||
layout="topleft"
|
||||
left="10"
|
||||
name="description"
|
||||
top="10"
|
||||
word_wrap="true"
|
||||
width="330">
|
||||
Configure splash screen display options here. These settings will take effect after the next viewer restart.
|
||||
</text>
|
||||
|
||||
<text
|
||||
follows="left|top"
|
||||
height="16"
|
||||
layout="topleft"
|
||||
left="10"
|
||||
name="section_visibility"
|
||||
top_pad="10"
|
||||
width="330"
|
||||
font="SansSerifBold">
|
||||
Section Visibility:
|
||||
</text>
|
||||
|
||||
<check_box
|
||||
control_name="FSSplashScreenHideTopBar"
|
||||
height="20"
|
||||
label="Hide top bar"
|
||||
layout="topleft"
|
||||
left="20"
|
||||
name="hide_top_bar"
|
||||
top_pad="5"
|
||||
width="310"/>
|
||||
|
||||
<check_box
|
||||
control_name="FSSplashScreenHideBlogs"
|
||||
height="20"
|
||||
label="Hide blogs section"
|
||||
layout="topleft"
|
||||
left="20"
|
||||
name="hide_blogs"
|
||||
top_pad="2"
|
||||
width="310"/>
|
||||
|
||||
<check_box
|
||||
control_name="FSSplashScreenHideDestinations"
|
||||
height="20"
|
||||
label="Hide destinations section"
|
||||
layout="topleft"
|
||||
left="20"
|
||||
name="hide_destinations"
|
||||
top_pad="2"
|
||||
width="310"/>
|
||||
|
||||
<text
|
||||
follows="left|top"
|
||||
height="16"
|
||||
layout="topleft"
|
||||
left="10"
|
||||
name="section_accessibility"
|
||||
top_pad="15"
|
||||
width="330"
|
||||
font="SansSerifBold">
|
||||
Accessibility Options:
|
||||
</text>
|
||||
|
||||
<check_box
|
||||
control_name="FSSplashScreenUseGrayMode"
|
||||
height="20"
|
||||
label="Enable grayscale mode"
|
||||
layout="topleft"
|
||||
left="20"
|
||||
name="use_gray_mode"
|
||||
top_pad="5"
|
||||
width="310"/>
|
||||
|
||||
<check_box
|
||||
control_name="FSSplashScreenUseHighContrast"
|
||||
height="20"
|
||||
label="Enable high contrast mode"
|
||||
layout="topleft"
|
||||
left="20"
|
||||
name="use_high_contrast"
|
||||
top_pad="2"
|
||||
width="310"/>
|
||||
|
||||
<check_box
|
||||
control_name="FSSplashScreenUseAllCaps"
|
||||
height="20"
|
||||
label="Enable all caps mode"
|
||||
layout="topleft"
|
||||
left="20"
|
||||
name="use_all_caps"
|
||||
top_pad="2"
|
||||
width="310"/>
|
||||
|
||||
<check_box
|
||||
control_name="FSSplashScreenUseLargerFonts"
|
||||
height="20"
|
||||
label="Use larger fonts"
|
||||
layout="topleft"
|
||||
left="20"
|
||||
name="use_larger_fonts"
|
||||
top_pad="2"
|
||||
width="310"/>
|
||||
|
||||
<check_box
|
||||
control_name="FSSplashScreenNoTransparency"
|
||||
height="20"
|
||||
label="Disable transparency effects"
|
||||
layout="topleft"
|
||||
left="20"
|
||||
name="no_transparency"
|
||||
top_pad="2"
|
||||
width="310"/>
|
||||
|
||||
</floater>
|
||||
|
|
@ -1559,7 +1559,6 @@
|
|||
height="306"
|
||||
layout="topleft"
|
||||
left="3"
|
||||
ignore_tab="false"
|
||||
right="-21"
|
||||
name="log_tab_border"
|
||||
top_pad="0"
|
||||
|
|
@ -1605,7 +1604,6 @@
|
|||
height="306"
|
||||
layout="topleft"
|
||||
left="3"
|
||||
ignore_tab="false"
|
||||
right="-21"
|
||||
name="mesh_preview_settings_tab_border"
|
||||
top_pad="0"
|
||||
|
|
@ -1952,7 +1950,7 @@
|
|||
can_apply_immediately="true"
|
||||
label="Bad Triangle Fill"
|
||||
tool_tip="Fill color for degenerate (thin) triangles in preview window on the Mesh uploader"
|
||||
name="mesh_degenerate_fill_color"/>
|
||||
name="mesh_preview_degenerate_fill_color"/>
|
||||
</panel>
|
||||
</tab_container>
|
||||
<panel
|
||||
|
|
@ -2213,7 +2211,6 @@ Analysed:
|
|||
Preview controls
|
||||
</text>
|
||||
<combo_box
|
||||
can_resize="false"
|
||||
follows="top|left"
|
||||
left="-85"
|
||||
top_delta="-2"
|
||||
|
|
@ -2236,7 +2233,6 @@ Analysed:
|
|||
left="3"
|
||||
name="preview_controls_border"
|
||||
top_pad="5"
|
||||
halign="center"
|
||||
width="250"/>
|
||||
<check_box
|
||||
follows="top|left"
|
||||
|
|
|
|||
|
|
@ -129,6 +129,14 @@
|
|||
name="copy url">
|
||||
<on_click function="AvatarIcon.Action" parameter="copy_url" />
|
||||
</menu_item_call>
|
||||
<!-- <FS:Zi> Add menu items to copy and/or insert mention URIs into chat -->
|
||||
<menu_item_call
|
||||
label="Copy Mention URI to clipboard"
|
||||
layout="topleft"
|
||||
name="mention_copy_label">
|
||||
<on_click function="Mention.CopyURI" />
|
||||
</menu_item_call>
|
||||
<!-- </FS:Zi> -->
|
||||
<menu_item_separator layout="topleft" name="separator_block"/>
|
||||
<menu_item_call
|
||||
label="Report Abuse"
|
||||
|
|
@ -195,4 +203,16 @@
|
|||
<on_click function="AvatarIcon.Action" parameter="ban_member" />
|
||||
<on_enable function="AvatarIcon.Enable" parameter="can_ban_member" />
|
||||
</menu_item_call>
|
||||
<!-- <FS:Zi> Add menu items to copy and/or insert mention URIs into chat -->
|
||||
<menu_item_separator
|
||||
name="MentionURISeparator"
|
||||
layout="topleft" />
|
||||
<menu_item_call
|
||||
label="Mention User in Chat"
|
||||
layout="topleft"
|
||||
name="mention_in_chat">
|
||||
<menu_item_call.on_click
|
||||
function="Mention.Chat" />
|
||||
</menu_item_call>
|
||||
<!-- </FS:Zi> -->
|
||||
</toggleable_menu>
|
||||
|
|
|
|||
|
|
@ -115,6 +115,15 @@
|
|||
<menu_item_call.on_click
|
||||
function="Contacts.Friends.CopyUrl"/>
|
||||
</menu_item_call>
|
||||
<!-- <FS:Zi> Add menu items to copy and/or insert mention URIs into chat -->
|
||||
<menu_item_call
|
||||
label="Copy Mention URI to clipboard"
|
||||
layout="topleft"
|
||||
name="mention_copy_label">
|
||||
<menu_item_call.on_click
|
||||
function="Mention.CopyURI" />
|
||||
</menu_item_call>
|
||||
<!-- </FS:Zi> -->
|
||||
<menu_item_separator/>
|
||||
<menu name="options" label="Options...">
|
||||
<menu_item_check
|
||||
|
|
|
|||
|
|
@ -241,4 +241,21 @@
|
|||
<on_click function="Avatar.BanMember" parameter="ban_member" />
|
||||
<on_enable function="ParticipantList.EnableItem" parameter="can_ban_member" />
|
||||
</menu_item_call>
|
||||
<!-- <FS:Zi> Add menu items to copy and/or insert mention URIs into chat -->
|
||||
<menu_item_separator layout="topleft" name="MentionURISeparator"/>
|
||||
<menu_item_call
|
||||
label="Copy Mention URI to clipboard"
|
||||
layout="topleft"
|
||||
name="mention_copy_label">
|
||||
<menu_item_call.on_click
|
||||
function="Mention.CopyURI" />
|
||||
</menu_item_call>
|
||||
<menu_item_call
|
||||
label="Mention User in Chat"
|
||||
layout="topleft"
|
||||
name="mention_in_chat">
|
||||
<menu_item_call.on_click
|
||||
function="Mention.Chat" />
|
||||
</menu_item_call>
|
||||
<!-- </FS:Zi> -->
|
||||
</context_menu>
|
||||
|
|
|
|||
|
|
@ -177,4 +177,23 @@
|
|||
<menu_item_call.on_click
|
||||
function="Url.CopyUrl" />
|
||||
</menu_item_call>
|
||||
<!-- <FS:Zi> Add menu items to copy and/or insert mention URIs into chat -->
|
||||
<menu_item_call
|
||||
label="Copy Mention URI to clipboard"
|
||||
layout="topleft"
|
||||
name="mention_copy_label">
|
||||
<menu_item_call.on_click
|
||||
function="Mention.CopyURI" />
|
||||
</menu_item_call>
|
||||
<menu_item_separator
|
||||
name="MentionURISeparator"
|
||||
layout="topleft" />
|
||||
<menu_item_call
|
||||
label="Mention User in Chat"
|
||||
layout="topleft"
|
||||
name="mention_in_chat">
|
||||
<menu_item_call.on_click
|
||||
function="Mention.Chat" />
|
||||
</menu_item_call>
|
||||
<!-- </FS:Zi> -->
|
||||
</context_menu>
|
||||
|
|
|
|||
|
|
@ -14144,6 +14144,19 @@ the region "[REGION]"?
|
|||
name="okbutton"
|
||||
yestext="OK"/>
|
||||
</notification>
|
||||
<notification
|
||||
icon="alertmodal.tga"
|
||||
name="ConfirmGlobalOnlineStatusToggle"
|
||||
type="alertmodal">
|
||||
Are you sure you want to change your online status visibility for all friends at once?
|
||||
|
||||
Due to server load, this mass change can take a while to become effective and may cause temporary issues for some friends seeing your online status.
|
||||
<tag>confirm</tag>
|
||||
<usetemplate
|
||||
name="okcancelbuttons"
|
||||
notext="Cancel"
|
||||
yestext="OK"/>
|
||||
</notification>
|
||||
<notification
|
||||
icon="alertmodal.tga"
|
||||
name="GlobalOnlineStatusToggle"
|
||||
|
|
@ -14815,7 +14828,7 @@ https://wiki.firestormviewer.org/antivirus_whitelisting
|
|||
name="FSLargeOutfitsWarningInThisSession"
|
||||
type="alertmodal">
|
||||
<unique/>
|
||||
A large number of outfits were detected: [AMOUNT]. This may cause viewer hangs or disconnects. Consider reducing the number of outfits for better performance (below [MAX]).
|
||||
A large number of outfits were detected: [AMOUNT]. This may cause viewer hangs or disconnects. Consider reducing the number of outfits for better performance (below [MAX]). THIS IS ONLY A SUGGESTION - if your computer is functioning normally, you can safely ignore it.
|
||||
<usetemplate
|
||||
ignoretext="Outfit count warning"
|
||||
name="okignore"
|
||||
|
|
|
|||
|
|
@ -3333,4 +3333,12 @@ Your current position: [AVATAR_POS]
|
|||
<string name="ImportListTooLarge">Too many entries. The CSV file has [COUNT] entries and there are [MAX] slots available.</string>
|
||||
<string name="ImportSuccessful">Successfully processed [COUNT] entries.</string>
|
||||
|
||||
<!-- VHACD enum strings -->
|
||||
<string name="Flood">Flood</string>
|
||||
<string name="Surface Only">Surface Only</string>
|
||||
<string name="Raycast">Raycast</string>
|
||||
<string name="Very High">Very High</string>
|
||||
<string name="Ultra">Ultra</string>
|
||||
<string name="Maximum">Maximum</string>
|
||||
|
||||
</strings>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
<floater name="splash_screen_settings" title="Ajustes de la Pantalla de Inicio">
|
||||
<text name="description">
|
||||
Configure aquí las opciones de visualización de la pantalla de inicio. Estos ajustes tendrán efecto después del próximo reinicio del visor.
|
||||
</text>
|
||||
<text name="section_visibility">
|
||||
Visibilidad de la sección:
|
||||
</text>
|
||||
<check_box label="Ocultar barra superior" name="hide_top_bar" />
|
||||
<check_box label="Ocultar sección de blogs" name="hide_blogs" />
|
||||
<check_box label="Ocultar destinos" name="hide_destinations" />
|
||||
<text name="section_accessibility">
|
||||
Opciones de Accesibilidad:
|
||||
</text>
|
||||
<check_box label="Habilitar el modo de escala de grises" name="use_gray_mode" />
|
||||
<check_box label="Habilitar el modo de alto contraste" name="use_high_contrast" />
|
||||
<check_box label="Habilitar el modo "TODO EN MAYÚSCULAS"" name="use_all_caps" />
|
||||
<check_box label="Usa fuentes más grandes" name="use_larger_fonts"/>
|
||||
<check_box label="Deshabilitar efectos de transparencia" name="no_transparency" />
|
||||
</floater>
|
||||
|
|
@ -181,7 +181,7 @@
|
|||
<panel name="joints_parent_panel">
|
||||
<tab_container name="joints_tabs">
|
||||
<panel title="Dépl." name="positionRotation_panel">
|
||||
<panel name="title">
|
||||
<panel name="move_tab_panel">
|
||||
<text name="av_position_updown_label">
|
||||
Haut/bas :
|
||||
</text>
|
||||
|
|
@ -248,7 +248,7 @@
|
|||
<check_box name="also_save_bvh_checkbox" label="Ajouter BVH à l'enregis.**" tool_tip="Lorsque vous enregistrez votre pose, écrivez également un fichier BVH, qui peut être téléchargé via 'Construire > Charger > Animation' pour poser vous-même ou d'autres personnes dans le monde. Pour ce faire, les articulations doivent remettre leur « base » à zéro, car le BVH nécessite que l'on travaille sur l'original."/>
|
||||
<check_box name="confirm_overwrite_on_save_checkbox" label="Confirmer l'écrasement" tool_tip="Lorsque vous enregistrez une pose, si le fichier existe déjà, vous devez cliquer à nouveau sur le bouton d'enregistrement pour confirmer que vous êtes sûr de vouloir l'écraser."/>
|
||||
<check_box name="natural_direction_checkbox" label="Utiliser l'alignement naturel" tool_tip="Le squelette a des rotations d'articulations non naturelles par défaut. Cela complique la pose. Si cette option est cochée, les articulations tourneront de manière plus naturelle."/>
|
||||
<check_box name="show_joint_markers_checkbox" label="Aff. marqueurs de jointure" tool_tip="Afficher de petits indicateurs pour faciliter la sélection des articulations lors de la pose visuelle."/>
|
||||
<check_box name="show_joint_markers_checkbox" label="Aff. marqueurs de jointure" tool_tip="Afficher de petits indicateurs pour faciliter la sélection des articulations lors de la pose."/>
|
||||
</panel>
|
||||
</tab_container>
|
||||
<button name="toggleVisualManipulators" tool_tip="Activer et désactiver les manipulateurs visuels"/>
|
||||
|
|
@ -295,6 +295,9 @@
|
|||
<button name="delta_mode_toggle" tool_tip="Si vous modifiez plusieurs articulations, chacune d'entre elles sera modifiée de la même manière, au lieu de toutes les modifier du même coup. Sert également à déverrouiller le Gimbal Lock." />
|
||||
<button label="Miroir" name="button_toggleMirrorRotation" tool_tip="Changer l'articulation opposée, comme dans un miroir." />
|
||||
<button label="Sym." name="button_toggleSympatheticRotation" tool_tip="Copier les modifications sur l'articulation opposée." />
|
||||
<button label="M" name="poser_world_frame_toggle" tool_tip="Effectuer des changements de rotation par rapport au Monde"/>
|
||||
<button label="A" name="poser_avatar_frame_toggle" tool_tip="Effectuer des changements de rotation par rapport à l'Avatar"/>
|
||||
<button label="É" name="poser_screen_frame_toggle" tool_tip="Effectuer des changements de rotation par rapport à l'Écran"/>
|
||||
<button label="Cop. G > D" name="button_symmetrize_left_to_right" tool_tip="Cliquez pour copier la modification du côté gauche vers le côté droit."/>
|
||||
<button label="Cop. D > G" name="button_symmetrize_right_to_left" tool_tip="Cliquez pour copier la modification du côté droit vers le côté gauche."/>
|
||||
</panel>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
<floater name="splash_screen_settings" title="Réglages de l'écran d'accueil">
|
||||
<text name="description">
|
||||
Configurez ici les options d'affichage de l'écran d'accueil. Ces réglages prendront effet après le prochain redémarrage du client.
|
||||
</text>
|
||||
<text name="section_visibility">
|
||||
Visibilité des sections :
|
||||
</text>
|
||||
<check_box label="Masquer la barre supérieure" name="hide_top_bar" />
|
||||
<check_box label="Masquer la section des blogs" name="hide_blogs" />
|
||||
<check_box label="Masquer les destinations" name="hide_destinations" />
|
||||
<text name="section_accessibility">
|
||||
Options d'accessibilité :
|
||||
</text>
|
||||
<check_box label="Activer le mode niveaux de gris" name="use_gray_mode" />
|
||||
<check_box label="Activer le mode contraste élevé" name="use_high_contrast" />
|
||||
<check_box label="Activer le mode "TOUT EN MAJUSCULES"" name="use_all_caps" />
|
||||
<check_box label="Utiliser des polices plus grandes" name="use_larger_fonts"/>
|
||||
<check_box label="Désactiver les effets de transparence" name="no_transparency" />
|
||||
</floater>
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
<radio_item label="Ouvre une nouvelle fenêtre" name="true"/>
|
||||
</radio_group>
|
||||
<text name="find_original_txt">
|
||||
Cliquer sur "Afficher dans l'inventaire" ou "Trouver l'original":
|
||||
Clic "Afficher dans l'inventaire" ou "Trouver l'original":
|
||||
</text>
|
||||
<radio_group name="find_original_settings">
|
||||
<radio_item label="Afficher dans la fenêtre d'inventaire principale" name="false"/>
|
||||
|
|
@ -29,7 +29,7 @@
|
|||
<check_box label="Étoile sur les dossiers contenant un favori" name="favorite_hollow_star"/>
|
||||
<check_box label="Texte coloré" name="favorites_color"/>
|
||||
<text name="attachment_return_txt">
|
||||
Appuyer sur Entrée sur un élément attaché à l'avatar
|
||||
Appuyer sur Entrée ou cliquer deux fois sur un élément attaché à l'avatar
|
||||
</text>
|
||||
<combo_box name="attach_combo">
|
||||
<combo_box.item label="Ajoute l'élément (recommandé)" name="1"/>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
<floater name="Marketplace" title="Marketplace">
|
||||
<layout_stack name="stack1">
|
||||
<layout_panel name="nav_controls">
|
||||
<button tool_tip="Revenir en arrière" name="back"/>
|
||||
<button tool_tip="Aller vers l'avant" name="forward"/>
|
||||
<button tool_tip="Arrêter la navigation" name="stop"/>
|
||||
<button tool_tip="Recharger la page" name="reload"/>
|
||||
<combo_box name="address" tool_tip="Entrez l'URL ici"/>
|
||||
<icon name="media_secure_lock_flag" tool_tip="Navigation sécurisée"/>
|
||||
<button tool_tip="Ouvrir l'URL dans le navigateur de votre ordinateur" name="popexternal"/>
|
||||
</layout_panel>
|
||||
</layout_stack>
|
||||
</floater>
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
<floater name="Model Preview" title="CHARGEMENT DU MODELE">
|
||||
<floater name="Model Preview" title="Chargement du modèle">
|
||||
<string name="no_havok">téléchargement du maillage avec physique</string>
|
||||
<string name="status_parse_error">Erreur : Problème d'analyse du modèle ; reportez-vous au journal pour plus de détails.</string>
|
||||
<string name="status_bind_shape_orientation">Avertissement : la matrice de formes de reliure n'est pas dans l'orientation standard X-avant.</string>
|
||||
|
|
@ -217,6 +217,28 @@
|
|||
<button label="Analyser" name="Decompose"/>
|
||||
<button label="Annuler" name="decompose_cancel"/>
|
||||
</panel>
|
||||
<panel name="physics analysis vhacd">
|
||||
<text name="method_label">
|
||||
Étape 2 : Convertir en hulls (facultatif)
|
||||
</text>
|
||||
<text name="fill_mode_label">
|
||||
Mode remplissage :
|
||||
</text>
|
||||
<text name="resolution_label">
|
||||
Résolution :
|
||||
</text>
|
||||
<text name="hulls_per_mesh_label">
|
||||
Hulls par Mesh :
|
||||
</text>
|
||||
<text name="vertices_per_hull_label">
|
||||
Vertices par hull :
|
||||
</text>
|
||||
<text name="tolerance_label">
|
||||
Tolérance erreurs :
|
||||
</text>
|
||||
<button label="Analyser" name="Analyze"/>
|
||||
<button label="Annuler" name="analyze_cancel"/>
|
||||
</panel>
|
||||
<panel name="physics simplification">
|
||||
<text name="second_step_label">
|
||||
Étape 3 : Simplifier
|
||||
|
|
@ -364,7 +386,7 @@
|
|||
Pb des physiques :
|
||||
</text>
|
||||
<color_swatch label="Mauvaises arêtes" tool_tip="Couleur des arêtes pour les triangles dégénérés (fin) dans l'aperçu de l'uploader" name="mesh_preview_degenerate_edge_color"/>
|
||||
<color_swatch label="Mauvais triangles" tool_tip="Couleur de remplissage pour les triangles dégénérés (fin) dans l'aperçu de l'uploader" name="mesh_degenerate_fill_color"/>
|
||||
<color_swatch label="Mauvais triangles" tool_tip="Couleur de remplissage pour les triangles dégénérés (fin) dans l'aperçu de l'uploader" name="mesh_preview_degenerate_fill_color"/>
|
||||
</panel>
|
||||
</tab_container>
|
||||
<panel name="weights_and_warning_panel">
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
<floater name="Search" title="Recherche">
|
||||
<layout_stack name="stack1">
|
||||
<layout_panel name="nav_controls">
|
||||
<button tool_tip="Revenir en arrière" name="back"/>
|
||||
<button tool_tip="Aller vers l'avant" name="forward"/>
|
||||
<button tool_tip="Arrêter la navigation" name="stop"/>
|
||||
<button tool_tip="Recharger la page" name="reload"/>
|
||||
<combo_box name="address" tool_tip="Entrez l'URL ici"/>
|
||||
<icon name="media_secure_lock_flag" tool_tip="Navigation sécurisée"/>
|
||||
<button tool_tip="Ouvrir l'URL dans le navigateur de votre ordinateur" name="popexternal"/>
|
||||
</layout_panel>
|
||||
</layout_stack>
|
||||
</floater>
|
||||
|
|
@ -9,6 +9,7 @@
|
|||
<menu_item_call label="Inviter dans un groupe" name="Invite..."/>
|
||||
<menu_item_call label="Réinitialiser le squelette" name="Reset Skeleton"/>
|
||||
<menu_item_call label="Réinitialiser le squelette et les animations" name="Reset Skeleton And Animations"/>
|
||||
<menu_item_call label="Réinitialiser le LOD du mesh" name="Reset Mesh LOD"/>
|
||||
<context_menu label="Dérangement" name="Annoyance">
|
||||
<menu_item_call label="Ignorer" name="Avatar Mute"/>
|
||||
<menu_item_call label="Cesser d'ignorer" name="Avatar Unmute"/>
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
<menu_item_call label="Voltigement" name="Hover Height"/>
|
||||
<menu_item_call label="Réinitialiser le squelette" name="Reset Skeleton"/>
|
||||
<menu_item_call label="Réinitialiser le squelette et les animations" name="Reset Skeleton And Animations"/>
|
||||
<menu_item_call label="Réinitialiser le LOD du mesh" name="Reset Mesh LOD"/>
|
||||
<menu_item_call label="Réinitialiser le LOD du maillage" name="Reset Mesh LOD"/>
|
||||
</context_menu>
|
||||
<context_menu label="Enlever" name="Take Off >">
|
||||
|
|
|
|||
|
|
@ -18,7 +18,16 @@
|
|||
<menu_item_call label="Payer" name="Pay"/>
|
||||
<menu_item_call label="Copier le nom" name="copy name"/>
|
||||
<menu_item_call label="Copier l'URL" name="copy url"/>
|
||||
<menu_item_call label="Copier l'URI de la mention" name="mention_copy_label"/>
|
||||
<menu_item_call label="Signaler une infraction" name="Report Abuse"/>
|
||||
<menu_item_check label="Muter" name="Block Unblock"/>
|
||||
<menu_item_check label="Ignorer" name="Mute Text"/>
|
||||
<menu_item_check label="Bloquer la voix" name="Block Unblock"/>
|
||||
<menu_item_check label="Bloquer le texte" name="Mute Text"/>
|
||||
<context_menu label="Options du modérateur" name="Moderator Options">
|
||||
<menu_item_call label="Autorisez les échanges écrits" name="AllowTextChat"/>
|
||||
<menu_item_call label="Interdire les échanges écrits" name="ForbidTextChat"/>
|
||||
<menu_item_call label="Bloquer ce participant" name="ModerateVoiceMuteSelected"/>
|
||||
<menu_item_call label="Débloquer ce participant" name="ModerateVoiceUnMuteSelected"/>
|
||||
</context_menu>
|
||||
<menu_item_call label="Bannir ce membre" name="BanMember"/>
|
||||
<menu_item_call label="Mentionner le résident dans le chat" name="mention_in_chat"/>
|
||||
</menu>
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
<menu_item_call label="Inviter dans un groupe" name="Invite..."/>
|
||||
<menu_item_call label="Réinitialiser le squelette" name="Reset Skeleton"/>
|
||||
<menu_item_call label="Réinitialiser le squelette et les animations" name="Reset Skeleton And Animations"/>
|
||||
<menu_item_call label="Réinitialiser le LOD du mesh" name="Reset Mesh LOD"/>
|
||||
<context_menu label="Dérangement" name="Remove">
|
||||
<menu_item_call label="Ignorer" name="Avatar Mute"/>
|
||||
<menu_item_call label="Cesser d'ignorer" name="Avatar Unmute"/>
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
<menu_item_call label="Activer le groupe" name="activate_group"/>
|
||||
<menu_item_call label="Quitter le groupe" name="leave_group"/>
|
||||
<context_menu label="Options de modération" name="Moderator Options">
|
||||
<menu_item_check label="Autoriser le chat écrit" name="AllowTextChat"/>
|
||||
<menu_item_check label="Autoriser les échanges écrits" name="AllowTextChat"/>
|
||||
<menu_item_call label="Muter ce participant" name="ModerateVoiceMuteSelected"/>
|
||||
<menu_item_call label="Ecouter ce participant" name="ModerateVoiceUnMuteSelected"/>
|
||||
<menu_item_call label="Muter tout le monde" name="ModerateVoiceMute"/>
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@
|
|||
<menu_item_call label="Suivre" name="track_agent"/>
|
||||
<menu_item_call label="Supprimer cet ami" name="remove_friend"/>
|
||||
<menu_item_call label="Copier le nom" name="url_copy_label"/>
|
||||
<menu_item_call label="Copier l'adresse" name="url_copy"/>
|
||||
<menu_item_call label="Copier l'URL" name="url_copy"/>
|
||||
<menu_item_call label="Copier l'URI de la mention" name="mention_copy_label"/>
|
||||
<menu name="options" label="Options...">
|
||||
<menu_item_check label="Afficher la colonne Nom d'utilisateur" name="show_username"/>
|
||||
<menu_item_check label="Afficher la colonne Nom d'affichage" name="show_displayname"/>
|
||||
|
|
|
|||
|
|
@ -4,4 +4,5 @@
|
|||
<menu_item_call label="Copier" name="Copy"/>
|
||||
<menu_item_call label="Coller" name="Paste"/>
|
||||
<menu_item_call label="Ouvrir l'inspecteur Web" name="open_webinspector"/>
|
||||
<menu_item_call label="Afficher le code" name="show_page_source"/>
|
||||
</context_menu>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
<context_menu name="Object Pie">
|
||||
<menu_item_call label="Toucher" name="Object Touch"/>
|
||||
<menu_item_call label="Modifier" name="Edit..."/>
|
||||
<menu_item_call label="Modifier le matériau PBR" name="EditGLTFMaterial"/>
|
||||
<menu_item_call label="Construire" name="Build"/>
|
||||
<menu_item_call label="Ouvrir" name="Open"/>
|
||||
<menu_item_call label="S'asseoir ici" name="Object Sit"/>
|
||||
|
|
@ -21,7 +22,7 @@
|
|||
<menu_item_call label="Supprimer les scripts" name="Remove Scripts From Selection"/>
|
||||
</context_menu>
|
||||
<menu_item_call label="Zoomer" name="Zoom In"/>
|
||||
<menu_item_call label="Afficher dans les ensembles définis" name="show_in_linksets"/>
|
||||
<menu_item_call label="Afficher dans les objets de la région" name="show_in_linksets"/>
|
||||
<menu_item_call label="Show in characters" name="show_in_characters"/>
|
||||
<context_menu label="Mettre" name="Put On">
|
||||
<menu_item_call label="Porter" name="Wear"/>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
<menu_item_call label="Propriétés de l'objet" name="Object Profile"/>
|
||||
<menu_item_call label="Ignorer" name="Block"/>
|
||||
<menu_item_call label="Ne plus ignorer" name="Unblock"/>
|
||||
<menu_item_call label="Zoom avant" name="zoom_in"/>
|
||||
<menu_item_call label="Voir sur la carte" name="show_on_map"/>
|
||||
<menu_item_call label="Se téléporter à l'emplacement de l'objet" name="teleport_to_object"/>
|
||||
</menu>
|
||||
|
|
|
|||
|
|
@ -11,15 +11,18 @@
|
|||
<menu_item_check label="Trier par nom" name="SortByName"/>
|
||||
<menu_item_check label="Trier par dernière activité" name="SortByRecentSpeakers"/>
|
||||
<menu_item_check label="Afficher les icônes des personnes" name="View Icons"/>
|
||||
<menu_item_check label="Ignorer" name="Block/Unblock"/>
|
||||
<menu_item_check label="Bloquer" name="Block/Unblock"/>
|
||||
<menu_item_check label="Ignorer" name="MuteText"/>
|
||||
<context_menu label="Options du modérateur" name="Moderator Options">
|
||||
<menu_item_call label="Éjecter du groupe" name="EjectSelected"/>
|
||||
<menu_item_check label="Autoriser le chat écrit" name="AllowTextChat"/>
|
||||
<menu_item_check label="Autoriser les échanges écrits" name="AllowTextChat"/>
|
||||
<menu_item_call label="Interdire les échanges écrits" name="ForbidTextChat"/>
|
||||
<menu_item_call label="Muter ce participant" name="ModerateVoiceMuteSelected"/>
|
||||
<menu_item_call label="Écouter à nouveau ce participant" name="ModerateVoiceUnMuteSelected"/>
|
||||
<menu_item_call label="Muter tout le monde" name="ModerateVoiceMute"/>
|
||||
<menu_item_call label="Écouter à nouveau tout le monde" name="ModerateVoiceUnmute"/>
|
||||
</context_menu>
|
||||
<menu_item_call label="Bannir le membre" name="BanMember"/>
|
||||
<menu_item_call label="Copier l'URI de la mention" name="mention_copy_label"/>
|
||||
<menu_item_call label="Mentioner le résident dans la discussion" name="mention_in_chat"/>
|
||||
</context_menu>
|
||||
|
|
|
|||
|
|
@ -13,6 +13,14 @@
|
|||
<menu_item_call label="Supprimer cet ami" name="remove_friend"/>
|
||||
<menu_item_call label="Signaler une infraction" name="report_abuse"/>
|
||||
<menu_item_check label="Ignorer" name="Block"/>
|
||||
<context_menu label="Moderator Options" name="GroupModerationSubmenu">
|
||||
<menu_item_call label="Autoriser les échanges écrits" name="AllowGroupChat"/>
|
||||
<menu_item_call label="Interdire les échanges écrits" name="ForbidGroupChat"/>
|
||||
<menu_item_call label="Bannir le membre" name="BanGroupMember"/>
|
||||
<menu_item_call label="Éjecter le membre" name="BanEjectMember"/>
|
||||
</context_menu>
|
||||
<menu_item_call label="Copier le nom" name="url_copy_label"/>
|
||||
<menu_item_call label="Copier l'adresse" name="url_copy"/>
|
||||
<menu_item_call label="Copier l'URL" name="url_copy"/>
|
||||
<menu_item_call label="Copier l'URI de la mention" name="mention_copy_label"/>
|
||||
<menu_item_call label="Mentioner le résident dans la discussion" name="mention_in_chat"/>
|
||||
</context_menu>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
<menu_item_call label="Profil de l'objet" name="show_object"/>
|
||||
<menu_item_call label="Ignorer" name="block_object"/>
|
||||
<menu_item_call label="Ne plus ignorer" name="unblock_object"/>
|
||||
<menu_item_call label="Zoom avant" name="zoom_in"/>
|
||||
<menu_item_call label="Voir sur la carte" name="show_on_map"/>
|
||||
<menu_item_call label="Se téléporter à l'emplacement de l'objet" name="teleport_to_object"/>
|
||||
<menu_item_call label="Copier le nom de l'objet dans le presse-papiers" name="url_copy_label"/>
|
||||
|
|
|
|||
|
|
@ -882,6 +882,15 @@ Assurez-vous que le fichier a l'extension correcte.
|
|||
Impossible de lire le fichier son chargé :
|
||||
[FILE]
|
||||
</notification>
|
||||
<notification name="ModelUploaderMissingPhysicsApple">
|
||||
Le chargement de modèles n'est pas encore disponible sur Apple Silicon, mais sera pris en charge dans une prochaine version.
|
||||
|
||||
Solution de contournement : cliquez avec le bouton droit sur l'application [APP_NAME] dans le Finder, sélectionnez
|
||||
« Obtenir des informations », puis cochez « Ouvrir avec Rosetta ».
|
||||
</notification>
|
||||
<notification name="ModelUploaderMissingPhysics">
|
||||
La bibliothèque physique n'est pas présente, certaines fonctionnalités du programme de chargement de modèles peuvent ne pas fonctionner ou ne pas fonctionner correctement.
|
||||
</notification>
|
||||
<notification name="SoundFileNotRIFF">
|
||||
Il semble que le fichier ne soit pas un fichier RIFF WAVE :
|
||||
[FILE]
|
||||
|
|
@ -5187,6 +5196,10 @@ Ils peuvent utiliser http://opensimulator.org/wiki/inventory pour résoudre les
|
|||
Impossible de déplacer les fichiers. Chemin précédent rétabli.
|
||||
<usetemplate ignoretext="Impossible de déplacer les fichiers. Chemin précédent rétabli." name="okignore" yestext="OK"/>
|
||||
</notification>
|
||||
<notification name="PreferenceQualityWithLowMemory">
|
||||
Votre système dispose de [TOTAL_MEM] Mo de mémoire, ce qui peut s'avérer insuffisant pour exécuter la visionneuse avec des paramètres élevés et risque d'entraîner des problèmes.
|
||||
<usetemplate name="okcancelbuttons" notext="Annuler" yestext="Continuer"/>
|
||||
</notification>
|
||||
<notification name="DefaultObjectPermissions">
|
||||
Problème lors de l'enregistrement des droits d'objet par défaut : [REASON]. Réessayez de définir les droits par défaut ultérieurement.
|
||||
<usetemplate name="okbutton" yestext="OK"/>
|
||||
|
|
@ -5404,6 +5417,12 @@ la région "[REGION]" ?
|
|||
Impossible de créer un autre favori car le nombre maximum de favoris a déjà été créé.
|
||||
<usetemplate name="okbutton" yestext="OK"/>
|
||||
</notification>
|
||||
<notification name="ConfirmGlobalOnlineStatusToggle">
|
||||
Êtes-vous sûr de vouloir modifier la visibilité de votre statut en ligne pour tous vos amis à la fois ?
|
||||
|
||||
En raison de la charge du serveur, cette modification en masse peut prendre un certain temps avant de prendre effet et peut entraîner des problèmes temporaires pour certains amis qui voient votre statut en ligne.
|
||||
<usetemplate name="okcancelbuttons" notext="Annuler" yestext="OK"/>
|
||||
</notification>
|
||||
<notification name="GlobalOnlineStatusToggle">
|
||||
En raison de la charge du serveur, le basculement massif de la visibilité du statut en ligne peut prendre un certain temps avant d'être effectif. Veuillez être patient.
|
||||
<usetemplate ignoretext="Informez-moi que le changement de visibilité du statut en ligne peut prendre un certain temps." name="okignore" yestext="OK"/>
|
||||
|
|
@ -5655,6 +5674,10 @@ https://wiki.firestormviewer.org/antivirus_whitelisting
|
|||
Remplacer la pose “[POSE_NAME]”?
|
||||
<usetemplate name="okcancelbuttons" notext="Annuler" yestext="Ok"/>
|
||||
</notification>
|
||||
<notification name="FSLargeOutfitsWarningInThisSession">
|
||||
Un grand nombre de tenues ont été détectées : [AMOUNT]. Cela peut entraîner des blocages ou des déconnexions de la visionneuse. Envisagez de réduire le nombre de tenues pour améliorer les performances (en dessous de [MAX]). IL S'AGIT UNIQUEMENT D'UNE SUGGESTION. Si votre ordinateur fonctionne normalement, vous pouvez ignorer cette recommandation.
|
||||
<usetemplate ignoretext="Avertissement nombre de tenues" name="okignore" yestext="OK" />
|
||||
</notification>
|
||||
<notification name="PrimfeedLoginRequestFailed">
|
||||
Demande de connexion refusée par Primfeed.
|
||||
</notification>
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ Pour rechercher des résidents avec qui passer du temps, utilisez [secondlife://
|
|||
<button name="add_friend_btn" tool_tip="Proposer à ce résident de devenir votre ami"/>
|
||||
<dnd_button name="nearby_del_btn" tool_tip="Supprimer la personne sélectionnée des amis"/>
|
||||
</panel>
|
||||
<slider label="Distance :" name="near_me_range" tool_tip="Distance des personnes à proximité"/>
|
||||
-->
|
||||
</panel>
|
||||
<panel label="Amis" name="friends_panel">
|
||||
|
|
|
|||
|
|
@ -109,10 +109,10 @@
|
|||
<combo_item name="High" label="Haut"/>
|
||||
</combo_box>
|
||||
<check_box name="FSBuildPrefs_EmbedItem" label="Intégrer un objet dans le nouveau prim"/>
|
||||
<fs_embedded_item_drop_target name="embed_item" tool_tip="Glissez un objet ici.">Glissez un objet ici.</fs_embedded_item_drop_target>
|
||||
<fs_embedded_item_drop_target name="embed_item" tool_tip="Déposez ici un objet provenant de votre inventaire.">Déposez un objet ici.</fs_embedded_item_drop_target>
|
||||
<text name="build_item_add_disp_rect_txt">Actuellement : [ITEM]</text>
|
||||
<check_box name="FSBuildPrefs_UseCustomScript" label="Use custom script for New Script button"/>
|
||||
<fs_embedded_item_drop_target name="custom_script" tool_tip="Drop a script from your inventory here.">Drop a script here.</fs_embedded_item_drop_target>
|
||||
<check_box name="FSBuildPrefs_UseCustomScript" label="Script personnalisé pour bouton Nouveau script"/>
|
||||
<fs_embedded_item_drop_target name="custom_script" tool_tip="Déposez ici un script provenant de votre inventaire.">Déposez un script ici.</fs_embedded_item_drop_target>
|
||||
<text name="custom_script_disp_rect_txt">Actuellement: [SCRIPT]</text>
|
||||
<button label="Permissions de création par défaut" name="fs_default_creation_permissions"/>
|
||||
<check_box label="Contours lumineux des prims sélectionnées" tool_tip="Quand décoché, les contours jaunes/bleus ne seront pas affichés, améliorant les performances quand un grand nombre de prims est sélectionné." name="FSBuildPrefsRenderHighlight_toggle"/>
|
||||
|
|
@ -145,7 +145,7 @@
|
|||
<check_box label="Points d'attachement alphabétiques dans les menus "Attacher à" (redémarrage requis)" tool_tip="Si cette option est activée, la liste des points d'attachement dans les menus 'Attacher à' sera triée par ordre alphabétique." name="FSSortAttachmentSpotsAlphabetically"/>
|
||||
<check_box label="Nouveau module de texture Firestorm dans la fenêtre d'outils (nécessite un redémarrage)" tool_tip="Si cette option est activée, les outils d'édition de textures utiliseront le flux de travail amélioré de FS et permettront l'édition de textures Blinn-Phong et PBR." name="FSUseNewTexturePanel"/>
|
||||
</panel>
|
||||
<panel label="Script Editor" name="BuildTabScriptEditor">
|
||||
<panel label="Éditeur de script" name="BuildTabScriptEditor">
|
||||
<text name="text_box_scripting_font" width="155">Police de l'éditeur de script :</text>
|
||||
<combo_box name="FSScriptingFontName" tool_tip="Nom de la police utilisée dans l'éditeur de script LSL" />
|
||||
<combo_box name="FSScriptingFontSize" tool_tip="Taille de la police utilisée dans l'éditeur de script LSL">
|
||||
|
|
@ -168,6 +168,7 @@
|
|||
<text name="title">Dossiers de destination pour les chargements :</text>
|
||||
<text name="title_sounds">Sons</text>
|
||||
<text name="title_models">Modèles</text>
|
||||
<text name="title_pbr">Matériaux PBR</text>
|
||||
<text name="upload_help">Pour changer le dossier de destination, cliquez droit dessus dans l'inventaire et sélectionnez
|
||||
"Par défaut pour"
|
||||
</text>
|
||||
|
|
|
|||
|
|
@ -3809,7 +3809,7 @@ Veuillez réinstaller la visionneuse à partir de [DOWNLOAD_URL] et contacter [S
|
|||
Taille
|
||||
</string>
|
||||
<string name="High">
|
||||
Haut
|
||||
Élevée
|
||||
</string>
|
||||
<string name="High Heels">
|
||||
Talons hauts
|
||||
|
|
@ -4013,7 +4013,7 @@ Veuillez réinstaller la visionneuse à partir de [DOWNLOAD_URL] et contacter [S
|
|||
Poignées d'amour
|
||||
</string>
|
||||
<string name="Low">
|
||||
Bas
|
||||
Basse
|
||||
</string>
|
||||
<string name="Low Heels">
|
||||
Talons bas
|
||||
|
|
@ -6222,7 +6222,7 @@ Essayez avec le chemin d'accès à l'éditeur entre guillemets doubles
|
|||
Aperçu
|
||||
</string>
|
||||
<string name="Normal">
|
||||
Normal
|
||||
Normale
|
||||
</string>
|
||||
<string name="Pathfinding_Wiki_URL">
|
||||
http://wiki.secondlife.com/wiki/Pathfinding_Tools_in_the_Second_Life_Viewer
|
||||
|
|
@ -7166,6 +7166,22 @@ Votre position actuelle : [AVATAR_POS]
|
|||
Trop d'entrées. Le fichier CSV contient [COUNT] entrées et il y a [MAX] emplacements disponibles.
|
||||
</string>
|
||||
<string name="ImportSuccessful">
|
||||
Successfully processed [COUNT] entries.
|
||||
[COUNT] entrées traitées avec succès.
|
||||
</string>
|
||||
<!-- VHACD enum strings -->
|
||||
<string name="Flood">
|
||||
Inondation
|
||||
</string>
|
||||
<string name="Surface Only">
|
||||
Surface seulement
|
||||
</string>
|
||||
<string name="Raycast">
|
||||
Diffusion de rayons
|
||||
</string>
|
||||
<string name="Very High">
|
||||
Très élevée
|
||||
</string>
|
||||
<string name="Maximum">
|
||||
Maximale
|
||||
</string>
|
||||
</strings>
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@
|
|||
<panel name="joints_parent_panel">
|
||||
<tab_container name="joints_tabs">
|
||||
<panel title="Muovi" name="positionRotation_panel">
|
||||
<panel name="title">
|
||||
<panel name="move_tab_panel">
|
||||
<text name="av_position_updown_label">
|
||||
Su / Giù:
|
||||
</text>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
<floater name="splash_screen_settings" title="Impostazioni Schermata Iniziale">
|
||||
<text name="description">
|
||||
Configura qui le opzioni di visualizzazione della schermata iniziale. Queste impostazioni avranno effetto dopo il prossimo riavvio del visualizzatore.
|
||||
</text>
|
||||
<text name="section_visibility">
|
||||
Visibilità sezione:
|
||||
</text>
|
||||
<check_box label="Nascondi barra superiore" name="hide_top_bar" />
|
||||
<check_box label="Nascondi sezione blog" name="hide_blogs" />
|
||||
<check_box label="Nascondi destinazioni" name="hide_destinations" />
|
||||
<text name="section_accessibility">
|
||||
Opzioni di Accessibilità:
|
||||
</text>
|
||||
<check_box label="Abilita modalità scala di grigi" name="use_gray_mode" />
|
||||
<check_box label="Abilita modalità contrasto elevato" name="use_high_contrast" />
|
||||
<check_box label="Abilita la modalità "TUTTO MAIUSCOLO"" name="use_all_caps" />
|
||||
<check_box label="Usa caratteri più grandi" name="use_larger_fonts"/>
|
||||
<check_box label="Disabilita effetti di trasparenza" name="no_transparency" />
|
||||
</floater>
|
||||
|
|
@ -407,7 +407,7 @@
|
|||
Problemi di fisica:
|
||||
</text>
|
||||
<color_swatch label="Bordi triangoli difettosi" tool_tip="Colore dei bordi per triangoli degenerati (sottili) nella finestra di anteprima per il caricamento della mesh" name="mesh_preview_degenerate_edge_color" />
|
||||
<color_swatch label="Riempim. triangoli difet." tool_tip="Colore di riempimento per triangoli degenerati (sottili) nella finestra di anteprima per il caricamento della mesh" name="mesh_degenerate_fill_color" />
|
||||
<color_swatch label="Riempim. triangoli difet." tool_tip="Colore di riempimento per triangoli degenerati (sottili) nella finestra di anteprima per il caricamento della mesh" name="mesh_preview_degenerate_fill_color" />
|
||||
</panel>
|
||||
</tab_container>
|
||||
<panel name="weights_and_warning_panel">
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue