Merge branch 'master' of git@github.com:singularity-viewer/SingularityViewer.git
This commit is contained in:
@@ -54,6 +54,11 @@ if (WINDOWS)
|
||||
# Remove default /Zm1000 flag that cmake inserts
|
||||
string (REPLACE "/Zm1000" " " CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
|
||||
if (MSVC11)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zm140")
|
||||
endif (MSVC11)
|
||||
|
||||
|
||||
# Don't build DLLs.
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
|
||||
@@ -246,30 +251,28 @@ endif (LINUX)
|
||||
|
||||
|
||||
if (DARWIN)
|
||||
add_definitions(-DLL_DARWIN=1 -D_XOPEN_SOURCE)
|
||||
set(CMAKE_CXX_LINK_FLAGS "-Wl,-headerpad_max_install_names,-search_paths_first")
|
||||
add_definitions(-DLL_DARWIN=1)
|
||||
set(CMAKE_CXX_LINK_FLAGS "-Wl,-no_compact_unwind -Wl,-headerpad_max_install_names,-search_paths_first")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_CXX_LINK_FLAGS}")
|
||||
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mlong-branch")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mlong-branch")
|
||||
# NOTE: it's critical that the optimization flag is put in front.
|
||||
# NOTE: it's critical to have both CXX_FLAGS and C_FLAGS covered.
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -msse3 -mtune=generic -mfpmath=sse ${GCC_EXTRA_OPTIMIZATIONS}")
|
||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3 -msse3 -mtune=generic -mfpmath=sse ${GCC_EXTRA_OPTIMIZATIONS}")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -O3 -msse3 -mtune=generic -mfpmath=sse ${GCC_EXTRA_OPTIMIZATIONS}")
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -O3 -msse3 -mtune=generic -mfpmath=sse ${GCC_EXTRA_OPTIMIZATIONS}")
|
||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
# NOTE: it's critical that the optimization flag is put in front.
|
||||
# NOTE: it's critical to have both CXX_FLAGS and C_FLAGS covered.
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -msse3")
|
||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3 -msse3")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -O3 -msse3")
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -O3 -msse3")
|
||||
endif()
|
||||
set(DARWIN_extra_cstar_flags "-g")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${DARWIN_extra_cstar_flags} -ftemplate-depth=256")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${DARWIN_extra_cstar_flags}")
|
||||
# NOTE: it's critical that the optimization flag is put in front.
|
||||
# NOTE: it's critical to have both CXX_FLAGS and C_FLAGS covered.
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O0 ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O0 ${CMAKE_C_FLAGS_RELWITHDEBINFO}")
|
||||
set(CMAKE_XCODE_ATTRIBUTE_CLANG_X86_VECTOR_INSTRUCTIONS SSE3)
|
||||
set(CMAKE_XCODE_ATTRIBUTE_GCC_OPTIMIZATION_LEVEL -O3)
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -msse3 ${CMAKE_CXX_FLAGS_RELEASE}")
|
||||
set(CMAKE_C_FLAGS_RELEASE "-O3 -msse3 ${CMAKE_C_FLAGS_RELEASE}")
|
||||
if (XCODE_VERSION GREATER 4.2)
|
||||
set(ENABLE_SIGNING TRUE)
|
||||
set(SIGNING_IDENTITY "Developer ID Application: Linden Research, Inc.")
|
||||
endif (XCODE_VERSION GREATER 4.2)
|
||||
endif (DARWIN)
|
||||
|
||||
|
||||
|
||||
if (LINUX OR DARWIN)
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
add_definitions(-DLL_GNUC=1)
|
||||
@@ -277,13 +280,11 @@ if (LINUX OR DARWIN)
|
||||
set(UNIX_CXX_WARNINGS "${UNIX_WARNINGS} -Wno-reorder -Wno-non-virtual-dtor -Woverloaded-virtual")
|
||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
add_definitions(-DLL_CLANG=1)
|
||||
set(UNIX_WARNINGS "-Wall -Wno-sign-compare -Wno-trigraphs -Wno-tautological-compare -Wno-char-subscripts -Wno-gnu -Wno-logical-op-parentheses -Wno-non-virtual-dtor")
|
||||
set(UNIX_WARNINGS "${UNIX_WARNINGS} -Woverloaded-virtual -Wno-parentheses-equality -Wno-reorder -Wno-unused-function -Wno-unused-value -Wno-unused-variable")
|
||||
set(UNIX_WARNINGS "-Wall -Wno-sign-compare -Wno-trigraphs -Wno-tautological-compare -Wno-char-subscripts -Wno-gnu -Wno-logical-op-parentheses -Wno-logical-not-parentheses -Wno-non-virtual-dtor -Wno-deprecated")
|
||||
set(UNIX_WARNINGS "${UNIX_WARNINGS} -Woverloaded-virtual -Wno-parentheses-equality -Wno-reorder -Wno-unused-function -Wno-unused-value -Wno-unused-variable -Wno-unused-private-field -Wno-parentheses")
|
||||
set(UNIX_CXX_WARNINGS "${UNIX_WARNINGS}")
|
||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")
|
||||
add_definitions(-DLL_ICC=1)
|
||||
set(UNIX_WARNINGS "-wd327 -wd597 -wd858")
|
||||
set(UNIX_CXX_WARNINGS "${UNIX_WARNINGS}")
|
||||
endif ()
|
||||
|
||||
if (NOT DISABLE_FATAL_WARNINGS)
|
||||
|
||||
@@ -97,24 +97,54 @@ endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
set(DARWIN 1)
|
||||
|
||||
if(${CMAKE_GENERATOR} MATCHES "Xcode")
|
||||
#SDK Compiler and Deployment targets for XCode
|
||||
if (${XCODE_VERSION} VERSION_LESS 4.0.0)
|
||||
set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.5.sdk)
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.5)
|
||||
else (${XCODE_VERSION} VERSION_LESS 4.0.0)
|
||||
set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.6.sdk)
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.6)
|
||||
endif (${XCODE_VERSION} VERSION_LESS 4.0.0)
|
||||
else(${CMAKE_GENERATOR} MATCHES "Xcode")
|
||||
set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.6.sdk)
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.6)
|
||||
endif(${CMAKE_GENERATOR} MATCHES "Xcode")
|
||||
execute_process(
|
||||
COMMAND sh -c "xcodebuild -version | grep Xcode | cut -d ' ' -f2 | cut -d'.' -f1-2"
|
||||
OUTPUT_VARIABLE XCODE_VERSION )
|
||||
string(REGEX REPLACE "(\r?\n)+$" "" XCODE_VERSION "${XCODE_VERSION}")
|
||||
|
||||
# # To support a different SDK update these Xcode settings:
|
||||
# if (XCODE_VERSION GREATER 4.9) # (Which would be 5.0+)
|
||||
# set(CMAKE_OSX_DEPLOYMENT_TARGET 10.8)
|
||||
# set(CMAKE_OSX_SYSROOT macosx10.9)
|
||||
# else (XCODE_VERION GREATER 4.9)
|
||||
# if (XCODE_VERSION GREATER 4.5)
|
||||
# set(CMAKE_OSX_DEPLOYMENT_TARGET 10.7)
|
||||
# set(CMAKE_OSX_SYSROOT macosx10.8)
|
||||
# else (XCODE_VERSION GREATER 4.5)
|
||||
# if (XCODE_VERSION GREATER 4.2)
|
||||
# set(CMAKE_OSX_DEPLOYMENT_TARGET 10.6)
|
||||
# set(CMAKE_OSX_SYSROOT macosx10.7)
|
||||
# else (XCODE_VERSION GREATER 4.2)
|
||||
# set(CMAKE_OSX_DEPLOYMENT_TARGET 10.6)
|
||||
# set(CMAKE_OSX_SYSROOT macosx10.7)
|
||||
# endif (XCODE_VERSION GREATER 4.2)
|
||||
# endif (XCODE_VERSION GREATER 4.5)
|
||||
# endif (XCODE_VERSION GREATER 4.9)
|
||||
|
||||
set(CMAKE_XCODE_ATTRIBUTE_GCC_VERSION "com.apple.compilers.llvmgcc42")
|
||||
# Hardcode SDK we build against until we can test and allow newer ones
|
||||
# as autodetected in the code above
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.6)
|
||||
set(CMAKE_OSX_SYSROOT macosx10.6)
|
||||
|
||||
# Support for Unix Makefiles generator
|
||||
if (CMAKE_GENERATOR STREQUAL "Unix Makefiles")
|
||||
execute_process(COMMAND xcodebuild -version -sdk "${CMAKE_OSX_SYSROOT}" Path | head -n 1 OUTPUT_VARIABLE CMAKE_OSX_SYSROOT)
|
||||
string(REGEX REPLACE "(\r?\n)+$" "" CMAKE_OSX_SYSROOT "${CMAKE_OSX_SYSROOT}")
|
||||
endif (CMAKE_GENERATOR STREQUAL "Unix Makefiles")
|
||||
|
||||
# LLVM-GCC has been removed in Xcode5
|
||||
if (XCODE_VERSION GREATER 4.9)
|
||||
set(CMAKE_XCODE_ATTRIBUTE_GCC_VERSION "com.apple.compilers.llvm.clang.1_0")
|
||||
else (XCODE_VERSION GREATER 4.9)
|
||||
set(CMAKE_XCODE_ATTRIBUTE_GCC_VERSION "com.apple.compilers.llvmgcc42")
|
||||
endif (XCODE_VERSION GREATER 4.9)
|
||||
|
||||
set(CMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT dwarf-with-dsym)
|
||||
|
||||
message(STATUS "Xcode version: ${XCODE_VERSION}")
|
||||
message(STATUS "OSX sysroot: ${CMAKE_OSX_SYSROOT}")
|
||||
message(STATUS "OSX deployment target: ${CMAKE_OSX_DEPLOYMENT_TARGET}")
|
||||
|
||||
# Build only for i386 by default, system default on MacOSX 10.6 is x86_64
|
||||
set(CMAKE_OSX_ARCHITECTURES i386)
|
||||
set(ARCH i386)
|
||||
|
||||
@@ -392,6 +392,40 @@ void InstanceTracker<T>::dump(void)
|
||||
|
||||
} // namespace debug
|
||||
|
||||
template<class T>
|
||||
class AIDebugInstanceCounter
|
||||
{
|
||||
public:
|
||||
static int sInstanceCount;
|
||||
|
||||
protected:
|
||||
static void print_count(char const* name, int count, bool destruction);
|
||||
|
||||
AIDebugInstanceCounter()
|
||||
{
|
||||
print_count(typeid(T).name(), ++sInstanceCount, false);
|
||||
}
|
||||
AIDebugInstanceCounter(AIDebugInstanceCounter const&)
|
||||
{
|
||||
print_count(typeid(T).name(), ++sInstanceCount, false);
|
||||
}
|
||||
~AIDebugInstanceCounter()
|
||||
{
|
||||
print_count(typeid(T).name(), --sInstanceCount, true);
|
||||
}
|
||||
};
|
||||
|
||||
//static
|
||||
template<class T>
|
||||
int AIDebugInstanceCounter<T>::sInstanceCount;
|
||||
|
||||
//static
|
||||
template<class T>
|
||||
void AIDebugInstanceCounter<T>::print_count(char const* name, int count, bool destruction)
|
||||
{
|
||||
Dout(dc::notice, (destruction ? "Destructed " : "Constructing ") << name << ", now " << count << " instance" << ((count == 1) ? "." : "s."));
|
||||
}
|
||||
|
||||
//! Debugging macro.
|
||||
//
|
||||
// Print "Entering " << \a data to channel \a cntrl and increment
|
||||
|
||||
@@ -694,6 +694,8 @@ class CygwinSetup(WindowsSetup):
|
||||
project_name=self.project_name,
|
||||
word_size=self.word_size,
|
||||
)
|
||||
if self.word_size == 64:
|
||||
args["generator"] += r' Win64'
|
||||
#if simple:
|
||||
# return 'cmake %(opts)s "%(dir)s"' % args
|
||||
return ('cmake -G "%(generator)s" '
|
||||
|
||||
@@ -7,7 +7,7 @@ include(00-Common)
|
||||
include_directories(${LIBS_OPEN_DIR}/libhacd)
|
||||
|
||||
set (libndhacd_SOURCE_FILES
|
||||
LLConvexDecomposition.cpp
|
||||
llconvexdecomposition.cpp
|
||||
nd_hacdConvexDecomposition.cpp
|
||||
nd_hacdStructs.cpp
|
||||
nd_hacdUtils.cpp
|
||||
@@ -16,12 +16,12 @@ set (libndhacd_SOURCE_FILES
|
||||
)
|
||||
|
||||
set (libndhacd_HEADER_FILES
|
||||
LLConvexDecomposition.h
|
||||
llconvexdecomposition.h
|
||||
ndConvexDecomposition.h
|
||||
nd_hacdConvexDecomposition.h
|
||||
nd_hacdStructs.h
|
||||
nd_StructTracer.h
|
||||
LLConvexDecompositionStubImpl.h
|
||||
llconvexdecompositionstubimpl.h
|
||||
nd_EnterExitTracer.h
|
||||
nd_hacdDefines.h
|
||||
nd_hacdUtils.h
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @file LLConvexDecomposition.cpp
|
||||
* @file llconvexdecomposition.cpp
|
||||
* @author falcon@lindenlab.com
|
||||
* @brief A stub implementation of LLConvexDecomposition interface
|
||||
*
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
#include "nd_hacdConvexDecomposition.h"
|
||||
|
||||
#include "LLConvexDecomposition.h"
|
||||
#include "llconvexdecomposition.h"
|
||||
|
||||
|
||||
/*static */bool LLConvexDecomposition::s_isInitialized = false;
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @file LLConvexDecomposition.cpp
|
||||
* @file llconvexdecomposition.cpp
|
||||
* @brief LLConvexDecomposition interface definition
|
||||
*
|
||||
* $LicenseInfo:firstyear=2011&license=viewerlgpl$
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @file LLConvexDecompositionStubImpl.cpp
|
||||
* @file llconvexdecompositionstubimpl.cpp
|
||||
* @author falcon@lindenlab.com
|
||||
* @brief A stub implementation of LLConvexDecomposition
|
||||
*
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <memory>
|
||||
#include "LLConvexDecompositionStubImpl.h"
|
||||
#include "llconvexdecompositionstubimpl.h"
|
||||
|
||||
LLConvexDecomposition* LLConvexDecompositionImpl::getInstance()
|
||||
{
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @file LLConvexDecompositionStubImpl.h
|
||||
* @file llconvexdecompositionstubimpl.h
|
||||
* @author falcon@lindenlab.com
|
||||
* @brief A stub implementation of LLConvexDecomposition
|
||||
*
|
||||
@@ -29,7 +29,7 @@
|
||||
#ifndef LL_CONVEX_DECOMP_UTIL_H
|
||||
#define LL_CONVEX_DECOMP_UTIL_H
|
||||
|
||||
#include "LLConvexDecomposition.h"
|
||||
#include "llconvexdecomposition.h"
|
||||
|
||||
class LLConvexDecompositionImpl : public LLConvexDecomposition
|
||||
{
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
|
||||
#include "ndConvexDecomposition.h"
|
||||
#include "LLConvexDecomposition.h"
|
||||
#include "llconvexdecomposition.h"
|
||||
#include "nd_hacdStructs.h"
|
||||
|
||||
namespace ndStructTracer
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#ifndef ND_HACD_CONVEXDECOMP_H
|
||||
#define ND_HACD_CONVEXDECOMP_H
|
||||
|
||||
#include "LLConvexDecomposition.h"
|
||||
#include "llconvexdecomposition.h"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
*/
|
||||
|
||||
#include "nd_hacdStructs.h"
|
||||
#include "LLConvexDecomposition.h"
|
||||
|
||||
void DecompHull::clear()
|
||||
{
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
#include "nd_hacdDefines.h"
|
||||
#include "hacdHACD.h"
|
||||
#include "LLConvexDecomposition.h"
|
||||
#include "llconvexdecomposition.h"
|
||||
#include <vector>
|
||||
|
||||
struct LLCDHull;
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#define ND_HACD_UTILS_H
|
||||
|
||||
#include "nd_hacdStructs.h"
|
||||
#include "LLConvexDecomposition.h"
|
||||
|
||||
tHACD* init( int nConcavity, int nClusters, int nMaxVerticesPerHull, double dMaxConnectDist, HACDDecoder *aData );
|
||||
DecompData decompose( tHACD *aHACD );
|
||||
|
||||
@@ -29,7 +29,6 @@ set(llcharacter_SOURCE_FILES
|
||||
lljointsolverrp3.cpp
|
||||
llkeyframefallmotion.cpp
|
||||
llkeyframemotion.cpp
|
||||
llkeyframemotionparam.cpp
|
||||
llkeyframestandmotion.cpp
|
||||
llkeyframewalkmotion.cpp
|
||||
llmotion.cpp
|
||||
@@ -57,7 +56,6 @@ set(llcharacter_HEADER_FILES
|
||||
lljointstate.h
|
||||
llkeyframefallmotion.h
|
||||
llkeyframemotion.h
|
||||
llkeyframemotionparam.h
|
||||
llkeyframestandmotion.h
|
||||
llkeyframewalkmotion.h
|
||||
llmotion.h
|
||||
|
||||
@@ -136,7 +136,6 @@ LLMotion* LLCharacter::findMotion( const LLUUID &id )
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// createMotion()
|
||||
// NOTE: Always assign the result to a LLPointer!
|
||||
//-----------------------------------------------------------------------------
|
||||
LLMotion* LLCharacter::createMotion( const LLUUID &id )
|
||||
{
|
||||
@@ -195,11 +194,26 @@ void LLCharacter::updateMotions(e_update_t update_type)
|
||||
{
|
||||
if (update_type == HIDDEN_UPDATE)
|
||||
{
|
||||
//<singu>
|
||||
// Keep updating avatars that have at least one motion that is synchronized with a still running motion.
|
||||
// This call tells the other controllers that we are in principle hidden.
|
||||
// It returns false if we need to keep updating anyway.
|
||||
if (!mMotionController.hidden(true))
|
||||
{
|
||||
mMotionController.updateMotions(LLCharacter::NORMAL_UPDATE);
|
||||
return;
|
||||
}
|
||||
//</singu>
|
||||
LLFastTimer t(FTM_UPDATE_HIDDEN_ANIMATION);
|
||||
mMotionController.updateMotionsMinimal();
|
||||
}
|
||||
else
|
||||
{
|
||||
//<singu>
|
||||
// This call tells the other controllers that we are visible and that they need
|
||||
// to keep updating if they are synchronized with us, even if they are hidden.
|
||||
mMotionController.hidden(false);
|
||||
//</singu>
|
||||
LLFastTimer t(FTM_UPDATE_ANIMATION);
|
||||
// unpause if the number of outstanding pause requests has dropped to the initial one
|
||||
if (mMotionController.isPaused() && mPauseRequest->getNumRefs() == 1)
|
||||
@@ -529,3 +543,17 @@ LLAnimPauseRequest LLCharacter::requestPause()
|
||||
return mPauseRequest;
|
||||
}
|
||||
|
||||
void LLCharacter::requestPause(std::vector<LLAnimPauseRequest>& avatar_pause_handles)
|
||||
{
|
||||
mMotionController.pauseAllMotions();
|
||||
avatar_pause_handles.push_back(mPauseRequest);
|
||||
}
|
||||
|
||||
void LLCharacter::pauseAllSyncedCharacters(std::vector<LLAnimPauseRequest>& avatar_pause_handles)
|
||||
{
|
||||
// Pause this avatar.
|
||||
requestPause(avatar_pause_handles);
|
||||
// Also pause all avatars with synchronized motions.
|
||||
mMotionController.pauseAllSyncedCharacters(avatar_pause_handles);
|
||||
}
|
||||
|
||||
|
||||
@@ -146,6 +146,7 @@ public:
|
||||
|
||||
// is this motion active?
|
||||
BOOL isMotionActive( const LLUUID& id );
|
||||
bool isMotionActive(U32 bit) const { return mMotionController.isactive(bit); }
|
||||
|
||||
// Event handler for motion deactivation.
|
||||
// Called when a motion has completely stopped and has been deactivated.
|
||||
@@ -158,6 +159,8 @@ public:
|
||||
void updateMotions(e_update_t update_type);
|
||||
|
||||
LLAnimPauseRequest requestPause();
|
||||
void requestPause(std::vector<LLAnimPauseRequest>& avatar_pause_handles);
|
||||
void pauseAllSyncedCharacters(std::vector<LLAnimPauseRequest>& avatar_pause_handles);
|
||||
BOOL areAnimationsPaused() const { return mMotionController.isPaused(); }
|
||||
void setAnimTimeFactor(F32 factor) { mMotionController.setTimeFactor(factor); }
|
||||
void setTimeStep(F32 time_step) { mMotionController.setTimeStep(time_step); }
|
||||
|
||||
@@ -49,7 +49,7 @@ S32 LLEditingMotion::sHandPosePriority = 3;
|
||||
// LLEditingMotion()
|
||||
// Class Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
LLEditingMotion::LLEditingMotion( const LLUUID &id) : LLMotion(id)
|
||||
LLEditingMotion::LLEditingMotion(LLUUID const& id, LLMotionController* controller) : AIMaskedMotion(id, controller, ANIM_AGENT_EDITING)
|
||||
{
|
||||
mCharacter = NULL;
|
||||
|
||||
@@ -155,7 +155,7 @@ BOOL LLEditingMotion::onActivate()
|
||||
mShoulderJoint.setRotation( mShoulderState->getJoint()->getRotation() );
|
||||
mElbowJoint.setRotation( mElbowState->getJoint()->getRotation() );
|
||||
|
||||
return TRUE;
|
||||
return AIMaskedMotion::onActivate();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -256,12 +256,4 @@ BOOL LLEditingMotion::onUpdate(F32 time, U8* joint_mask)
|
||||
return result;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLEditingMotion::onDeactivate()
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLEditingMotion::onDeactivate()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// End
|
||||
|
||||
@@ -49,11 +49,11 @@
|
||||
// class LLEditingMotion
|
||||
//-----------------------------------------------------------------------------
|
||||
class LLEditingMotion :
|
||||
public LLMotion
|
||||
public AIMaskedMotion
|
||||
{
|
||||
public:
|
||||
// Constructor
|
||||
LLEditingMotion(const LLUUID &id);
|
||||
LLEditingMotion(LLUUID const& id, LLMotionController* controller);
|
||||
|
||||
// Destructor
|
||||
virtual ~LLEditingMotion();
|
||||
@@ -65,7 +65,7 @@ public:
|
||||
|
||||
// static constructor
|
||||
// all subclasses must implement such a function and register it
|
||||
static LLMotion *create(const LLUUID &id) { return new LLEditingMotion(id); }
|
||||
static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLEditingMotion(id, controller); }
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------------------
|
||||
@@ -107,9 +107,6 @@ public:
|
||||
// must return FALSE when the motion is completed.
|
||||
virtual BOOL onUpdate(F32 time, U8* joint_mask);
|
||||
|
||||
// called when a motion is deactivated
|
||||
virtual void onDeactivate();
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------------------
|
||||
// joint states to be animated
|
||||
|
||||
@@ -61,7 +61,7 @@ const F32 HAND_MORPH_BLEND_TIME = 0.2f;
|
||||
// LLHandMotion()
|
||||
// Class Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
LLHandMotion::LLHandMotion(const LLUUID &id) : LLMotion(id)
|
||||
LLHandMotion::LLHandMotion(LLUUID const& id, LLMotionController* controller) : AIMaskedMotion(id, controller, ANIM_AGENT_HAND_MOTION)
|
||||
{
|
||||
mCharacter = NULL;
|
||||
mLastTime = 0.f;
|
||||
@@ -112,7 +112,7 @@ BOOL LLHandMotion::onActivate()
|
||||
mCharacter->setVisualParamWeight(gHandPoseNames[mCurrentPose], 1.f);
|
||||
mCharacter->updateVisualParams();
|
||||
}
|
||||
return TRUE;
|
||||
return AIMaskedMotion::onActivate();
|
||||
}
|
||||
|
||||
|
||||
@@ -235,14 +235,6 @@ BOOL LLHandMotion::onUpdate(F32 time, U8* joint_mask)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLHandMotion::onDeactivate()
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLHandMotion::onDeactivate()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLHandMotion::getHandPoseName()
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
// class LLHandMotion
|
||||
//-----------------------------------------------------------------------------
|
||||
class LLHandMotion :
|
||||
public LLMotion
|
||||
public AIMaskedMotion
|
||||
{
|
||||
public:
|
||||
typedef enum e_hand_pose
|
||||
@@ -68,7 +68,7 @@ public:
|
||||
} eHandPose;
|
||||
|
||||
// Constructor
|
||||
LLHandMotion(const LLUUID &id);
|
||||
LLHandMotion(LLUUID const& id, LLMotionController* controller);
|
||||
|
||||
// Destructor
|
||||
virtual ~LLHandMotion();
|
||||
@@ -80,7 +80,7 @@ public:
|
||||
|
||||
// static constructor
|
||||
// all subclasses must implement such a function and register it
|
||||
static LLMotion *create(const LLUUID &id) { return new LLHandMotion(id); }
|
||||
static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLHandMotion(id, controller); }
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------------------
|
||||
@@ -122,9 +122,6 @@ public:
|
||||
// must return FALSE when the motion is completed.
|
||||
virtual BOOL onUpdate(F32 time, U8* joint_mask);
|
||||
|
||||
// called when a motion is deactivated
|
||||
virtual void onDeactivate();
|
||||
|
||||
virtual BOOL canDeprecate() { return FALSE; }
|
||||
|
||||
static std::string getHandPoseName(eHandPose pose);
|
||||
|
||||
@@ -76,8 +76,8 @@ const F32 EYE_BLINK_TIME_DELTA = 0.005f; // time between one eye starting a blin
|
||||
// LLHeadRotMotion()
|
||||
// Class Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
LLHeadRotMotion::LLHeadRotMotion(const LLUUID &id) :
|
||||
LLMotion(id),
|
||||
LLHeadRotMotion::LLHeadRotMotion(LLUUID const& id, LLMotionController* controller) :
|
||||
AIMaskedMotion(id, controller, ANIM_AGENT_HEAD_ROT),
|
||||
mCharacter(NULL),
|
||||
mTorsoJoint(NULL),
|
||||
mHeadJoint(NULL)
|
||||
@@ -104,7 +104,10 @@ LLHeadRotMotion::~LLHeadRotMotion()
|
||||
LLMotion::LLMotionInitStatus LLHeadRotMotion::onInitialize(LLCharacter *character)
|
||||
{
|
||||
if (!character)
|
||||
{
|
||||
llwarns << "character is NULL." << llendl;
|
||||
return STATUS_FAILURE;
|
||||
}
|
||||
mCharacter = character;
|
||||
|
||||
mPelvisJoint = character->getJoint("mPelvis");
|
||||
@@ -169,16 +172,6 @@ LLMotion::LLMotionInitStatus LLHeadRotMotion::onInitialize(LLCharacter *characte
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLHeadRotMotion::onActivate()
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL LLHeadRotMotion::onActivate()
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLHeadRotMotion::onUpdate()
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -263,19 +256,11 @@ BOOL LLHeadRotMotion::onUpdate(F32 time, U8* joint_mask)
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLHeadRotMotion::onDeactivate()
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLHeadRotMotion::onDeactivate()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLEyeMotion()
|
||||
// Class Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
LLEyeMotion::LLEyeMotion(const LLUUID &id) : LLMotion(id)
|
||||
LLEyeMotion::LLEyeMotion(LLUUID const& id, LLMotionController* controller) : AIMaskedMotion(id, controller, ANIM_AGENT_EYE)
|
||||
{
|
||||
mCharacter = NULL;
|
||||
mEyeJitterTime = 0.f;
|
||||
@@ -343,16 +328,6 @@ LLMotion::LLMotionInitStatus LLEyeMotion::onInitialize(LLCharacter *character)
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLEyeMotion::onActivate()
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL LLEyeMotion::onActivate()
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLEyeMotion::onUpdate()
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -533,6 +508,8 @@ void LLEyeMotion::onDeactivate()
|
||||
{
|
||||
joint->setRotation(LLQuaternion::DEFAULT);
|
||||
}
|
||||
|
||||
AIMaskedMotion::onDeactivate();
|
||||
}
|
||||
|
||||
// End
|
||||
|
||||
@@ -46,11 +46,11 @@
|
||||
// class LLHeadRotMotion
|
||||
//-----------------------------------------------------------------------------
|
||||
class LLHeadRotMotion :
|
||||
public LLMotion
|
||||
public AIMaskedMotion
|
||||
{
|
||||
public:
|
||||
// Constructor
|
||||
LLHeadRotMotion(const LLUUID &id);
|
||||
LLHeadRotMotion(LLUUID const& id, LLMotionController* controller);
|
||||
|
||||
// Destructor
|
||||
virtual ~LLHeadRotMotion();
|
||||
@@ -62,7 +62,7 @@ public:
|
||||
|
||||
// static constructor
|
||||
// all subclasses must implement such a function and register it
|
||||
static LLMotion *create(const LLUUID &id) { return new LLHeadRotMotion(id); }
|
||||
static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLHeadRotMotion(id, controller); }
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------------------
|
||||
@@ -94,19 +94,11 @@ public:
|
||||
// must return true to indicate success and be available for activation
|
||||
virtual LLMotionInitStatus onInitialize(LLCharacter *character);
|
||||
|
||||
// called when a motion is activated
|
||||
// must return TRUE to indicate success, or else
|
||||
// it will be deactivated
|
||||
virtual BOOL onActivate();
|
||||
|
||||
// called per time step
|
||||
// must return TRUE while it is active, and
|
||||
// must return FALSE when the motion is completed.
|
||||
virtual BOOL onUpdate(F32 time, U8* joint_mask);
|
||||
|
||||
// called when a motion is deactivated
|
||||
virtual void onDeactivate();
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------------------
|
||||
// joint states to be animated
|
||||
@@ -129,11 +121,11 @@ public:
|
||||
// class LLEyeMotion
|
||||
//-----------------------------------------------------------------------------
|
||||
class LLEyeMotion :
|
||||
public LLMotion
|
||||
public AIMaskedMotion
|
||||
{
|
||||
public:
|
||||
// Constructor
|
||||
LLEyeMotion(const LLUUID &id);
|
||||
LLEyeMotion(LLUUID const& id, LLMotionController* controller);
|
||||
|
||||
// Destructor
|
||||
virtual ~LLEyeMotion();
|
||||
@@ -145,7 +137,7 @@ public:
|
||||
|
||||
// static constructor
|
||||
// all subclasses must implement such a function and register it
|
||||
static LLMotion *create( const LLUUID &id) { return new LLEyeMotion(id); }
|
||||
static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLEyeMotion(id, controller); }
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------------------
|
||||
@@ -177,11 +169,6 @@ public:
|
||||
// must return true to indicate success and be available for activation
|
||||
virtual LLMotionInitStatus onInitialize(LLCharacter *character);
|
||||
|
||||
// called when a motion is activated
|
||||
// must return TRUE to indicate success, or else
|
||||
// it will be deactivated
|
||||
virtual BOOL onActivate();
|
||||
|
||||
// called per time step
|
||||
// must return TRUE while it is active, and
|
||||
// must return FALSE when the motion is completed.
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
#include "lldarray.h"
|
||||
|
||||
const S32 LL_CHARACTER_MAX_JOINTS_PER_MESH = 15;
|
||||
const U32 LL_CHARACTER_MAX_JOINTS = 32; // must be divisible by 4!
|
||||
const U32 LL_CHARACTER_MAX_JOINTS = 32; // must be divisible by 16!
|
||||
const U32 LL_HAND_JOINT_NUM = 31;
|
||||
const U32 LL_FACE_JOINT_NUM = 30;
|
||||
const S32 LL_CHARACTER_MAX_PRIORITY = 7;
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
// LLKeyframeFallMotion()
|
||||
// Class Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
LLKeyframeFallMotion::LLKeyframeFallMotion(const LLUUID &id) : LLKeyframeMotion(id)
|
||||
LLKeyframeFallMotion::LLKeyframeFallMotion(LLUUID const& id, LLMotionController* controller) : LLKeyframeMotion(id, controller)
|
||||
{
|
||||
mVelocityZ = 0.f;
|
||||
mCharacter = NULL;
|
||||
|
||||
@@ -47,7 +47,7 @@ class LLKeyframeFallMotion :
|
||||
{
|
||||
public:
|
||||
// Constructor
|
||||
LLKeyframeFallMotion(const LLUUID &id);
|
||||
LLKeyframeFallMotion(LLUUID const& id, LLMotionController* controller);
|
||||
|
||||
// Destructor
|
||||
virtual ~LLKeyframeFallMotion();
|
||||
@@ -59,7 +59,7 @@ public:
|
||||
|
||||
// static constructor
|
||||
// all subclasses must implement such a function and register it
|
||||
static LLMotion *create(const LLUUID &id) { return new LLKeyframeFallMotion(id); }
|
||||
static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLKeyframeFallMotion(id, controller); }
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
@@ -84,38 +84,55 @@ LLKeyframeMotion::JointMotionList::~JointMotionList()
|
||||
for_each(mJointMotionArray.begin(), mJointMotionArray.end(), DeletePointer());
|
||||
}
|
||||
|
||||
U32 LLKeyframeMotion::JointMotionList::dumpDiagInfo()
|
||||
//Singu: add parameter 'silent'.
|
||||
U32 LLKeyframeMotion::JointMotionList::dumpDiagInfo(bool silent) const
|
||||
{
|
||||
S32 total_size = sizeof(JointMotionList);
|
||||
|
||||
for (U32 i = 0; i < getNumJointMotions(); i++)
|
||||
{
|
||||
LLKeyframeMotion::JointMotion* joint_motion_p = mJointMotionArray[i];
|
||||
LLKeyframeMotion::JointMotion const* joint_motion_p = mJointMotionArray[i];
|
||||
|
||||
llinfos << "\tJoint " << joint_motion_p->mJointName << llendl;
|
||||
if (!silent)
|
||||
{
|
||||
llinfos << "\tJoint " << joint_motion_p->mJointName << llendl;
|
||||
}
|
||||
if (joint_motion_p->mUsage & LLJointState::SCALE)
|
||||
{
|
||||
llinfos << "\t" << joint_motion_p->mScaleCurve.mNumKeys << " scale keys at "
|
||||
<< joint_motion_p->mScaleCurve.mNumKeys * sizeof(ScaleKey) << " bytes" << llendl;
|
||||
|
||||
if (!silent)
|
||||
{
|
||||
llinfos << "\t" << joint_motion_p->mScaleCurve.mNumKeys << " scale keys at "
|
||||
<< joint_motion_p->mScaleCurve.mNumKeys * sizeof(ScaleKey) << " bytes" << llendl;
|
||||
}
|
||||
total_size += joint_motion_p->mScaleCurve.mNumKeys * sizeof(ScaleKey);
|
||||
}
|
||||
if (joint_motion_p->mUsage & LLJointState::ROT)
|
||||
{
|
||||
llinfos << "\t" << joint_motion_p->mRotationCurve.mNumKeys << " rotation keys at "
|
||||
<< joint_motion_p->mRotationCurve.mNumKeys * sizeof(RotationKey) << " bytes" << llendl;
|
||||
|
||||
if (!silent)
|
||||
{
|
||||
llinfos << "\t" << joint_motion_p->mRotationCurve.mNumKeys << " rotation keys at "
|
||||
<< joint_motion_p->mRotationCurve.mNumKeys * sizeof(RotationKey) << " bytes" << llendl;
|
||||
}
|
||||
total_size += joint_motion_p->mRotationCurve.mNumKeys * sizeof(RotationKey);
|
||||
}
|
||||
if (joint_motion_p->mUsage & LLJointState::POS)
|
||||
{
|
||||
llinfos << "\t" << joint_motion_p->mPositionCurve.mNumKeys << " position keys at "
|
||||
<< joint_motion_p->mPositionCurve.mNumKeys * sizeof(PositionKey) << " bytes" << llendl;
|
||||
|
||||
if (!silent)
|
||||
{
|
||||
llinfos << "\t" << joint_motion_p->mPositionCurve.mNumKeys << " position keys at "
|
||||
<< joint_motion_p->mPositionCurve.mNumKeys * sizeof(PositionKey) << " bytes" << llendl;
|
||||
}
|
||||
total_size += joint_motion_p->mPositionCurve.mNumKeys * sizeof(PositionKey);
|
||||
}
|
||||
}
|
||||
llinfos << "Size: " << total_size << " bytes" << llendl;
|
||||
//Singu: Also add memory used by the constraints.
|
||||
S32 constraints_size = mConstraints.size() * sizeof(constraint_list_t::value_type);
|
||||
total_size += constraints_size;
|
||||
if (!silent)
|
||||
{
|
||||
llinfos << "\t" << mConstraints.size() << " constraints at " << constraints_size << " bytes" << llendl;
|
||||
llinfos << "Size: " << total_size << " bytes" << llendl;
|
||||
}
|
||||
|
||||
return total_size;
|
||||
}
|
||||
@@ -427,9 +444,8 @@ void LLKeyframeMotion::JointMotion::update(LLJointState* joint_state, F32 time,
|
||||
// LLKeyframeMotion()
|
||||
// Class Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
LLKeyframeMotion::LLKeyframeMotion(const LLUUID &id)
|
||||
: LLMotion(id),
|
||||
mJointMotionList(NULL),
|
||||
LLKeyframeMotion::LLKeyframeMotion(const LLUUID &id, LLMotionController* controller)
|
||||
: LLMotion(id, controller),
|
||||
mPelvisp(NULL),
|
||||
mLastSkeletonSerialNum(0),
|
||||
mLastUpdateTime(0.f),
|
||||
@@ -452,9 +468,9 @@ LLKeyframeMotion::~LLKeyframeMotion()
|
||||
//-----------------------------------------------------------------------------
|
||||
// create()
|
||||
//-----------------------------------------------------------------------------
|
||||
LLMotion *LLKeyframeMotion::create(const LLUUID &id)
|
||||
LLMotion* LLKeyframeMotion::create(LLUUID const& id, LLMotionController* controller)
|
||||
{
|
||||
return new LLKeyframeMotion(id);
|
||||
return new LLKeyframeMotion(id, controller);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -517,6 +533,7 @@ LLMotion::LLMotionInitStatus LLKeyframeMotion::onInitialize(LLCharacter *charact
|
||||
case ASSET_FETCHED:
|
||||
return STATUS_HOLD;
|
||||
case ASSET_FETCH_FAILED:
|
||||
llwarns << "Trying to initialize a motion that failed to be fetched." << llendl;
|
||||
return STATUS_FAILURE;
|
||||
case ASSET_LOADED:
|
||||
return STATUS_SUCCESS;
|
||||
@@ -526,7 +543,7 @@ LLMotion::LLMotionInitStatus LLKeyframeMotion::onInitialize(LLCharacter *charact
|
||||
break;
|
||||
}
|
||||
|
||||
LLKeyframeMotion::JointMotionList* joint_motion_list = LLKeyframeDataCache::getKeyframeData(getID());
|
||||
LLKeyframeMotion::JointMotionListPtr joint_motion_list = LLKeyframeDataCache::getKeyframeData(getID());
|
||||
|
||||
if(joint_motion_list)
|
||||
{
|
||||
@@ -801,7 +818,44 @@ void LLKeyframeMotion::onDeactivate()
|
||||
//-----------------------------------------------------------------------------
|
||||
// setStopTime()
|
||||
//-----------------------------------------------------------------------------
|
||||
// time is in seconds since character creation
|
||||
//
|
||||
// Consider a looping animation of 20 frames, where the loop in point is at 3 frames
|
||||
// and the loop out point at 16 frames:
|
||||
//
|
||||
// The first 3 frames of the animation would be the "loop in" animation.
|
||||
// The last 4 frames of the animation would be the "loop out" animation.
|
||||
// Frames 4 through 15 would be the looping animation frames.
|
||||
//
|
||||
// If the animation would not be looping, all frames would just be played once sequentially:
|
||||
//
|
||||
// mActivationTimestamp -.
|
||||
// v
|
||||
// 0 3 15 16 20
|
||||
// | | \| |
|
||||
// ---------------------
|
||||
// <--> <-- mLoopInPoint (relative to mActivationTimestamp)
|
||||
// <--------------> <-- mLoopOutPoint (relative to mActivationTimestamp)
|
||||
// <----mDuration------>
|
||||
//
|
||||
// When looping the animation would repeat frames 3 to 16 (loop) a few times, for example:
|
||||
//
|
||||
// 0 3 15 3 15 3 15 3 15 16 20
|
||||
// | | loop 1 \| loop 2 \| loop 3 \| loop 4 \| |
|
||||
// ------------------------------------------------------------
|
||||
//LOOP^ ^ LOOP
|
||||
// IN | <----->| OUT
|
||||
// start_loop_time loop_fraction_time-' time
|
||||
//
|
||||
// The time at which the animation is started corresponds to frame 0 and is stored
|
||||
// in mActivationTimestamp (in seconds since character creation).
|
||||
//
|
||||
// If setStopTime() is called with a time somewhere inside loop 4,
|
||||
// then 'loop_fraction_time' is the time from the beginning of
|
||||
// loop 4 till 'time'. Thus 'time - loop_fraction_time' is the first
|
||||
// frame of loop 4, and '(time - loop_fraction_time) +
|
||||
// (mJointMotionList->mDuration - mJointMotionList->mLoopInPoint)'
|
||||
// would correspond to frame 20.
|
||||
//
|
||||
void LLKeyframeMotion::setStopTime(F32 time)
|
||||
{
|
||||
LLMotion::setStopTime(time);
|
||||
@@ -819,6 +873,8 @@ void LLKeyframeMotion::setStopTime(F32 time)
|
||||
loop_fraction_time = fmod(time - start_loop_time,
|
||||
mJointMotionList->mLoopOutPoint - mJointMotionList->mLoopInPoint);
|
||||
}
|
||||
// This sets mStopTimestamp to the time that corresponds to the end of the animation (ie, frame 20 in the above example)
|
||||
// minus the ease out duration, so that the animation eases out during the loop out and finishes exactly at the end.
|
||||
mStopTimestamp = llmax(time,
|
||||
(time - loop_fraction_time) + (mJointMotionList->mDuration - mJointMotionList->mLoopInPoint) - getEaseOutDuration());
|
||||
}
|
||||
@@ -1227,13 +1283,42 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8
|
||||
}
|
||||
}
|
||||
|
||||
// Helper class.
|
||||
template<typename T>
|
||||
struct AIAutoDestruct
|
||||
{
|
||||
T* mPtr;
|
||||
AIAutoDestruct() : mPtr(NULL) { }
|
||||
~AIAutoDestruct() { delete mPtr; }
|
||||
void add(T* ptr) { mPtr = ptr; }
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// deserialize()
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp)
|
||||
{
|
||||
BOOL old_version = FALSE;
|
||||
mJointMotionList = new LLKeyframeMotion::JointMotionList;
|
||||
|
||||
//<singu>
|
||||
|
||||
// First add a new LLKeyframeMotion::JointMotionList to the cache, then assign a pointer
|
||||
// to that to mJointMotionList. In LLs code the cache is never deleted again. Now it is
|
||||
// is deleted when the last mJointMotionList pointer is destructed.
|
||||
//
|
||||
// It is possible that we get here for an already added animation, because animations can
|
||||
// be requested multiple times (we get here from LLKeyframeMotion::onLoadComplete) when
|
||||
// the animation was still downloading from a previous request for another LLMotionController
|
||||
// object (avatar). In that case we just overwrite the old data while decoding it again.
|
||||
mJointMotionList = LLKeyframeDataCache::getKeyframeData(getID());
|
||||
bool singu_new_joint_motion_list = !mJointMotionList;
|
||||
if (singu_new_joint_motion_list)
|
||||
{
|
||||
// Create a new JointMotionList.
|
||||
mJointMotionList = LLKeyframeDataCache::createKeyframeData(getID());
|
||||
}
|
||||
|
||||
//</singu>
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// get base priority
|
||||
@@ -1396,8 +1481,10 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
mJointMotionList->mJointMotionArray.clear();
|
||||
mJointMotionList->mJointMotionArray.reserve(num_motions);
|
||||
if (singu_new_joint_motion_list)
|
||||
{
|
||||
mJointMotionList->mJointMotionArray.reserve(num_motions);
|
||||
}
|
||||
mJointStates.clear();
|
||||
mJointStates.reserve(num_motions);
|
||||
|
||||
@@ -1407,8 +1494,19 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp)
|
||||
|
||||
for(U32 i=0; i<num_motions; ++i)
|
||||
{
|
||||
AIAutoDestruct<JointMotion> watcher;
|
||||
|
||||
JointMotion* joint_motion = new JointMotion;
|
||||
mJointMotionList->mJointMotionArray.push_back(joint_motion);
|
||||
if (singu_new_joint_motion_list)
|
||||
{
|
||||
// Pass ownership to mJointMotionList.
|
||||
mJointMotionList->mJointMotionArray.push_back(joint_motion);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Just delete this at the end.
|
||||
watcher.add(joint_motion);
|
||||
}
|
||||
|
||||
std::string joint_name;
|
||||
if (!dp.unpackString(joint_name, "joint_name"))
|
||||
@@ -1836,7 +1934,15 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
mJointMotionList->mConstraints.push_front(constraintp);
|
||||
AIAutoDestruct<JointConstraintSharedData> watcher;
|
||||
if (singu_new_joint_motion_list)
|
||||
{
|
||||
mJointMotionList->mConstraints.push_front(constraintp);
|
||||
}
|
||||
else
|
||||
{
|
||||
watcher.add(constraintp);
|
||||
}
|
||||
|
||||
constraintp->mJointStateIndices = new S32[constraintp->mChainLength + 1]; // note: mChainLength is size-limited - comes from a byte
|
||||
|
||||
@@ -1876,15 +1982,12 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp)
|
||||
if (constraintp->mJointStateIndices[i] < 0 )
|
||||
{
|
||||
llwarns << "No joint index for constraint " << i << llendl;
|
||||
delete constraintp;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// *FIX: support cleanup of old keyframe data
|
||||
LLKeyframeDataCache::addKeyframeData(getID(), mJointMotionList);
|
||||
mAssetStatus = ASSET_LOADED;
|
||||
|
||||
setupPose();
|
||||
@@ -2226,16 +2329,24 @@ void LLKeyframeMotion::onLoadComplete(LLVFS *vfs,
|
||||
//--------------------------------------------------------------------
|
||||
// LLKeyframeDataCache::dumpDiagInfo()
|
||||
//--------------------------------------------------------------------
|
||||
void LLKeyframeDataCache::dumpDiagInfo()
|
||||
// <singu>
|
||||
// quiet = 0 : print everything in detail.
|
||||
// 1 : print the UUIDs of all animations in the cache and the total memory usage.
|
||||
// 2 : only print the total memory usage.
|
||||
// </singu>
|
||||
void LLKeyframeDataCache::dumpDiagInfo(int quiet)
|
||||
{
|
||||
// keep track of totals
|
||||
U32 total_size = 0;
|
||||
|
||||
char buf[1024]; /* Flawfinder: ignore */
|
||||
|
||||
llinfos << "-----------------------------------------------------" << llendl;
|
||||
llinfos << " Global Motion Table (DEBUG only)" << llendl;
|
||||
llinfos << "-----------------------------------------------------" << llendl;
|
||||
if (quiet < 2)
|
||||
{
|
||||
llinfos << "-----------------------------------------------------" << llendl;
|
||||
llinfos << " Global Motion Table" << llendl;
|
||||
llinfos << "-----------------------------------------------------" << llendl;
|
||||
}
|
||||
|
||||
// print each loaded mesh, and it's memory usage
|
||||
for (keyframe_data_map_t::iterator map_it = sKeyframeDataMap.begin();
|
||||
@@ -2243,30 +2354,46 @@ void LLKeyframeDataCache::dumpDiagInfo()
|
||||
{
|
||||
U32 joint_motion_kb;
|
||||
|
||||
LLKeyframeMotion::JointMotionList *motion_list_p = map_it->second;
|
||||
LLKeyframeMotion::JointMotionList const* motion_list_p = map_it->get();
|
||||
|
||||
llinfos << "Motion: " << map_it->first << llendl;
|
||||
if (quiet < 2)
|
||||
{
|
||||
llinfos << "Motion: " << map_it->key() << llendl;
|
||||
}
|
||||
|
||||
joint_motion_kb = motion_list_p->dumpDiagInfo();
|
||||
|
||||
total_size += joint_motion_kb;
|
||||
if (motion_list_p)
|
||||
{
|
||||
joint_motion_kb = motion_list_p->dumpDiagInfo(quiet);
|
||||
total_size += joint_motion_kb;
|
||||
}
|
||||
}
|
||||
|
||||
llinfos << "-----------------------------------------------------" << llendl;
|
||||
if (quiet < 2)
|
||||
{
|
||||
llinfos << "-----------------------------------------------------" << llendl;
|
||||
}
|
||||
llinfos << "Motions\tTotal Size" << llendl;
|
||||
snprintf(buf, sizeof(buf), "%d\t\t%d bytes", (S32)sKeyframeDataMap.size(), total_size ); /* Flawfinder: ignore */
|
||||
llinfos << buf << llendl;
|
||||
llinfos << "-----------------------------------------------------" << llendl;
|
||||
if (quiet < 2)
|
||||
{
|
||||
llinfos << "-----------------------------------------------------" << llendl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// LLKeyframeDataCache::addKeyframeData()
|
||||
// LLKeyframeDataCache::createKeyframeData()
|
||||
//--------------------------------------------------------------------
|
||||
void LLKeyframeDataCache::addKeyframeData(const LLUUID& id, LLKeyframeMotion::JointMotionList* joint_motion_listp)
|
||||
//<singu> This function replaces LLKeyframeDataCache::addKeyframeData and was rewritten to fix a memory leak (aka, the usage of AICachedPointer).
|
||||
LLKeyframeMotion::JointMotionListPtr LLKeyframeDataCache::createKeyframeData(LLUUID const& id)
|
||||
{
|
||||
sKeyframeDataMap[id] = joint_motion_listp;
|
||||
std::pair<keyframe_data_map_t::iterator, bool> result =
|
||||
sKeyframeDataMap.insert(AICachedPointer<LLUUID, LLKeyframeMotion::JointMotionList>(id, new LLKeyframeMotion::JointMotionList, &sKeyframeDataMap));
|
||||
llassert(result.second); // id may not already exist in the cache.
|
||||
return &*result.first; // Construct and return a JointMotionListPt from a pointer to the actually inserted AICachedPointer.
|
||||
}
|
||||
//</singu>
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// LLKeyframeDataCache::removeKeyframeData()
|
||||
@@ -2276,7 +2403,6 @@ void LLKeyframeDataCache::removeKeyframeData(const LLUUID& id)
|
||||
keyframe_data_map_t::iterator found_data = sKeyframeDataMap.find(id);
|
||||
if (found_data != sKeyframeDataMap.end())
|
||||
{
|
||||
delete found_data->second;
|
||||
sKeyframeDataMap.erase(found_data);
|
||||
}
|
||||
}
|
||||
@@ -2284,14 +2410,14 @@ void LLKeyframeDataCache::removeKeyframeData(const LLUUID& id)
|
||||
//--------------------------------------------------------------------
|
||||
// LLKeyframeDataCache::getKeyframeData()
|
||||
//--------------------------------------------------------------------
|
||||
LLKeyframeMotion::JointMotionList* LLKeyframeDataCache::getKeyframeData(const LLUUID& id)
|
||||
LLKeyframeMotion::JointMotionListPtr LLKeyframeDataCache::getKeyframeData(const LLUUID& id)
|
||||
{
|
||||
keyframe_data_map_t::iterator found_data = sKeyframeDataMap.find(id);
|
||||
if (found_data == sKeyframeDataMap.end())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return found_data->second;
|
||||
return &*found_data; // Construct and return a JointMotionListPt from a pointer to the found AICachedPointer.
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
@@ -2307,7 +2433,6 @@ LLKeyframeDataCache::~LLKeyframeDataCache()
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLKeyframeDataCache::clear()
|
||||
{
|
||||
for_each(sKeyframeDataMap.begin(), sKeyframeDataMap.end(), DeletePairedPointer());
|
||||
sKeyframeDataMap.clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
* $LicenseInfo:firstyear=2001&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2001-2009, Linden Research, Inc.
|
||||
* AICachedPointer and AICachedPointPtr copyright (c) 2013, Aleric Inglewood.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
@@ -48,10 +49,12 @@
|
||||
#include "v3dmath.h"
|
||||
#include "v3math.h"
|
||||
#include "llbvhconsts.h"
|
||||
#include <boost/intrusive_ptr.hpp>
|
||||
|
||||
class LLKeyframeDataCache;
|
||||
class LLVFS;
|
||||
class LLDataPacker;
|
||||
class LLMotionController;
|
||||
|
||||
#define MIN_REQUIRED_PIXEL_AREA_KEYFRAME (40.f)
|
||||
#define MAX_CHAIN_LENGTH (4)
|
||||
@@ -59,6 +62,112 @@ class LLDataPacker;
|
||||
const S32 KEYFRAME_MOTION_VERSION = 1;
|
||||
const S32 KEYFRAME_MOTION_SUBVERSION = 0;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// <singu>
|
||||
|
||||
template<typename KEY, typename T>
|
||||
class AICachedPointer;
|
||||
|
||||
template<typename KEY, typename T>
|
||||
void intrusive_ptr_add_ref(AICachedPointer<KEY, T> const* p);
|
||||
|
||||
template<typename KEY, typename T>
|
||||
void intrusive_ptr_release(AICachedPointer<KEY, T> const* p);
|
||||
|
||||
template<typename KEY, typename T>
|
||||
class AICachedPointer
|
||||
{
|
||||
public:
|
||||
typedef std::set<AICachedPointer<KEY, T> > container_type;
|
||||
|
||||
private:
|
||||
KEY mKey; // The unique key.
|
||||
LLPointer<T> mData; // The actual data pointer.
|
||||
container_type* mCache; // Pointer to the underlaying cache.
|
||||
mutable int mRefCount; // Number of AICachedPointerPtr's pointing to this object.
|
||||
|
||||
public:
|
||||
// Construct a NULL pointer. This is needed when adding a new entry to a std::set, it is always first default constructed.
|
||||
AICachedPointer(void) : mCache(NULL) { }
|
||||
|
||||
// Copy constructor. This is needed to replace the std::set inserted instance with its actual value.
|
||||
AICachedPointer(AICachedPointer const& cptr) : mKey(cptr.mKey), mData(cptr.mData), mCache(cptr.mCache), mRefCount(0) { }
|
||||
|
||||
// Construct a AICachedPointer that points to 'ptr' with key 'key'.
|
||||
AICachedPointer(KEY const& key, T* ptr, container_type* cache) : mKey(key), mData(ptr), mCache(cache), mRefCount(-1) { }
|
||||
|
||||
// Construct a temporary NULL pointer that can be used in a search for a key.
|
||||
AICachedPointer(KEY const& key) : mKey(key), mCache(NULL) { }
|
||||
|
||||
// Accessors for key and data.
|
||||
KEY const& key(void) const { return mKey; }
|
||||
T const* get(void) const { return mData.get(); }
|
||||
T* get(void) { return mData.get(); }
|
||||
|
||||
// Order only by key.
|
||||
friend bool operator<(AICachedPointer const& cp1, AICachedPointer const& cp2) { return cp1.mKey < cp2.mKey; }
|
||||
|
||||
private:
|
||||
friend void intrusive_ptr_add_ref<>(AICachedPointer<KEY, T> const* p);
|
||||
friend void intrusive_ptr_release<>(AICachedPointer<KEY, T> const* p);
|
||||
|
||||
private:
|
||||
AICachedPointer& operator=(AICachedPointer const&);
|
||||
};
|
||||
|
||||
template<typename KEY, typename T>
|
||||
void intrusive_ptr_add_ref(AICachedPointer<KEY, T> const* p)
|
||||
{
|
||||
llassert(p->mCache);
|
||||
if (p->mCache)
|
||||
{
|
||||
p->mRefCount++;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename KEY, typename T>
|
||||
void intrusive_ptr_release(AICachedPointer<KEY, T> const* p)
|
||||
{
|
||||
llassert(p->mCache);
|
||||
if (p->mCache)
|
||||
{
|
||||
if (--p->mRefCount == 0)
|
||||
{
|
||||
p->mCache->erase(p->mKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename KEY, typename T>
|
||||
class AICachedPointerPtr
|
||||
{
|
||||
private:
|
||||
boost::intrusive_ptr<AICachedPointer<KEY, T> const> mPtr;
|
||||
static int sCnt;
|
||||
|
||||
public:
|
||||
AICachedPointerPtr(void) { ++sCnt; }
|
||||
AICachedPointerPtr(AICachedPointerPtr const& cpp) : mPtr(cpp.mPtr) { ++sCnt; }
|
||||
AICachedPointerPtr(AICachedPointer<KEY, T> const* cp) : mPtr(cp) { ++sCnt; }
|
||||
~AICachedPointerPtr() { --sCnt; }
|
||||
|
||||
typedef boost::intrusive_ptr<AICachedPointer<KEY, T> const> const AICachedPointerPtr<KEY, T>::* const bool_type;
|
||||
operator bool_type() const { return mPtr ? &AICachedPointerPtr<KEY, T>::mPtr : NULL; }
|
||||
|
||||
T const* operator->() const { return mPtr->get(); }
|
||||
T* operator->() { return const_cast<AICachedPointer<KEY, T>&>(*mPtr).get(); }
|
||||
T const& operator*() const { return *mPtr->get(); }
|
||||
T& operator*() { return *const_cast<AICachedPointer<KEY, T>&>(*mPtr).get(); }
|
||||
|
||||
AICachedPointerPtr& operator=(AICachedPointerPtr const& cpp) { mPtr = cpp.mPtr; return *this; }
|
||||
};
|
||||
|
||||
template<typename KEY, typename T>
|
||||
int AICachedPointerPtr<KEY, T>::sCnt;
|
||||
|
||||
// </singu>
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// class LLKeyframeMotion
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -68,7 +177,7 @@ class LLKeyframeMotion :
|
||||
friend class LLKeyframeDataCache;
|
||||
public:
|
||||
// Constructor
|
||||
LLKeyframeMotion(const LLUUID &id);
|
||||
LLKeyframeMotion(const LLUUID &id, LLMotionController* controller);
|
||||
|
||||
// Destructor
|
||||
virtual ~LLKeyframeMotion();
|
||||
@@ -85,7 +194,7 @@ public:
|
||||
|
||||
// static constructor
|
||||
// all subclasses must implement such a function and register it
|
||||
static LLMotion *create(const LLUUID& id);
|
||||
static LLMotion* create(LLUUID const& id, LLMotionController* controller);
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------------------
|
||||
@@ -158,7 +267,7 @@ public:
|
||||
U32 getFileSize();
|
||||
BOOL serialize(LLDataPacker& dp) const;
|
||||
BOOL deserialize(LLDataPacker& dp);
|
||||
BOOL isLoaded() { return mJointMotionList != NULL; }
|
||||
BOOL isLoaded() { return !!mJointMotionList; }
|
||||
|
||||
|
||||
// setters for modifying a keyframe animation
|
||||
@@ -393,7 +502,7 @@ public:
|
||||
//-------------------------------------------------------------------------
|
||||
// JointMotionList
|
||||
//-------------------------------------------------------------------------
|
||||
class JointMotionList
|
||||
class JointMotionList : public LLRefCount
|
||||
{
|
||||
public:
|
||||
std::vector<JointMotion*> mJointMotionArray;
|
||||
@@ -416,19 +525,22 @@ public:
|
||||
public:
|
||||
JointMotionList();
|
||||
~JointMotionList();
|
||||
U32 dumpDiagInfo();
|
||||
U32 dumpDiagInfo(bool silent = false) const;
|
||||
JointMotion* getJointMotion(U32 index) const { llassert(index < mJointMotionArray.size()); return mJointMotionArray[index]; }
|
||||
U32 getNumJointMotions() const { return mJointMotionArray.size(); }
|
||||
};
|
||||
|
||||
|
||||
// Singu: Type of a pointer to the cached pointer (in LLKeyframeDataCache::sKeyframeDataMap) to a JointMotionList object.
|
||||
typedef AICachedPointerPtr<LLUUID, JointMotionList> JointMotionListPtr;
|
||||
|
||||
protected:
|
||||
static LLVFS* sVFS;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Member Data
|
||||
//-------------------------------------------------------------------------
|
||||
JointMotionList* mJointMotionList;
|
||||
JointMotionListPtr mJointMotionList; // singu: automatically clean up cache entry when destructed.
|
||||
std::vector<LLPointer<LLJointState> > mJointStates;
|
||||
LLJoint* mPelvisp;
|
||||
LLCharacter* mCharacter;
|
||||
@@ -442,21 +554,24 @@ protected:
|
||||
|
||||
class LLKeyframeDataCache
|
||||
{
|
||||
public:
|
||||
// *FIX: implement this as an actual singleton member of LLKeyframeMotion
|
||||
private:
|
||||
friend class LLKeyframeMotion;
|
||||
LLKeyframeDataCache(){};
|
||||
~LLKeyframeDataCache();
|
||||
|
||||
typedef std::map<LLUUID, class LLKeyframeMotion::JointMotionList*> keyframe_data_map_t;
|
||||
public:
|
||||
typedef AICachedPointer<LLUUID, LLKeyframeMotion::JointMotionList>::container_type keyframe_data_map_t; // singu: add automatic cache cleanup.
|
||||
static keyframe_data_map_t sKeyframeDataMap;
|
||||
|
||||
static void addKeyframeData(const LLUUID& id, LLKeyframeMotion::JointMotionList*);
|
||||
static LLKeyframeMotion::JointMotionList* getKeyframeData(const LLUUID& id);
|
||||
//<singu>
|
||||
static LLKeyframeMotion::JointMotionListPtr createKeyframeData(LLUUID const& id); // id may not exist.
|
||||
static LLKeyframeMotion::JointMotionListPtr getKeyframeData(LLUUID const& id); // id may or may not exists. Returns a NULL pointer when it doesn't exist.
|
||||
//</singu>
|
||||
|
||||
static void removeKeyframeData(const LLUUID& id);
|
||||
|
||||
//print out diagnostic info
|
||||
static void dumpDiagInfo();
|
||||
static void dumpDiagInfo(int quiet = 0); // singu: added param 'quiet'.
|
||||
static void clear();
|
||||
};
|
||||
|
||||
|
||||
@@ -1,456 +0,0 @@
|
||||
/**
|
||||
* @file llkeyframemotionparam.cpp
|
||||
* @brief Implementation of LLKeyframeMotion class.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, 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
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Header Files
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llkeyframemotionparam.h"
|
||||
#include "llcharacter.h"
|
||||
#include "llmath.h"
|
||||
#include "m3math.h"
|
||||
#include "lldir.h"
|
||||
#include "llanimationstates.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLKeyframeMotionParam class
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLKeyframeMotionParam()
|
||||
// Class Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
LLKeyframeMotionParam::LLKeyframeMotionParam( const LLUUID &id) : LLMotion(id)
|
||||
{
|
||||
mDefaultKeyframeMotion = NULL;
|
||||
mCharacter = NULL;
|
||||
|
||||
mEaseInDuration = 0.f;
|
||||
mEaseOutDuration = 0.f;
|
||||
mDuration = 0.f;
|
||||
mPriority = LLJoint::LOW_PRIORITY;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ~LLKeyframeMotionParam()
|
||||
// Class Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
LLKeyframeMotionParam::~LLKeyframeMotionParam()
|
||||
{
|
||||
for (motion_map_t::iterator iter = mParameterizedMotions.begin();
|
||||
iter != mParameterizedMotions.end(); ++iter)
|
||||
{
|
||||
motion_list_t& motionList = iter->second;
|
||||
for (motion_list_t::iterator iter2 = motionList.begin(); iter2 != motionList.end(); ++iter2)
|
||||
{
|
||||
const ParameterizedMotion& paramMotion = *iter2;
|
||||
delete paramMotion.mMotion;
|
||||
}
|
||||
motionList.clear();
|
||||
}
|
||||
mParameterizedMotions.clear();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLKeyframeMotionParam::onInitialize(LLCharacter *character)
|
||||
//-----------------------------------------------------------------------------
|
||||
LLMotion::LLMotionInitStatus LLKeyframeMotionParam::onInitialize(LLCharacter *character)
|
||||
{
|
||||
mCharacter = character;
|
||||
|
||||
if (!loadMotions())
|
||||
{
|
||||
return STATUS_FAILURE;
|
||||
}
|
||||
|
||||
for (motion_map_t::iterator iter = mParameterizedMotions.begin();
|
||||
iter != mParameterizedMotions.end(); ++iter)
|
||||
{
|
||||
motion_list_t& motionList = iter->second;
|
||||
for (motion_list_t::iterator iter2 = motionList.begin(); iter2 != motionList.end(); ++iter2)
|
||||
{
|
||||
const ParameterizedMotion& paramMotion = *iter2;
|
||||
LLMotion* motion = paramMotion.mMotion;
|
||||
motion->onInitialize(character);
|
||||
|
||||
if (motion->getDuration() > mEaseInDuration)
|
||||
{
|
||||
mEaseInDuration = motion->getEaseInDuration();
|
||||
}
|
||||
|
||||
if (motion->getEaseOutDuration() > mEaseOutDuration)
|
||||
{
|
||||
mEaseOutDuration = motion->getEaseOutDuration();
|
||||
}
|
||||
|
||||
if (motion->getDuration() > mDuration)
|
||||
{
|
||||
mDuration = motion->getDuration();
|
||||
}
|
||||
|
||||
if (motion->getPriority() > mPriority)
|
||||
{
|
||||
mPriority = motion->getPriority();
|
||||
}
|
||||
|
||||
LLPose *pose = motion->getPose();
|
||||
|
||||
mPoseBlender.addMotion(motion);
|
||||
for (LLJointState *jsp = pose->getFirstJointState(); jsp; jsp = pose->getNextJointState())
|
||||
{
|
||||
LLPose *blendedPose = mPoseBlender.getBlendedPose();
|
||||
blendedPose->addJointState(jsp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLKeyframeMotionParam::onActivate()
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL LLKeyframeMotionParam::onActivate()
|
||||
{
|
||||
for (motion_map_t::iterator iter = mParameterizedMotions.begin();
|
||||
iter != mParameterizedMotions.end(); ++iter)
|
||||
{
|
||||
motion_list_t& motionList = iter->second;
|
||||
for (motion_list_t::iterator iter2 = motionList.begin(); iter2 != motionList.end(); ++iter2)
|
||||
{
|
||||
const ParameterizedMotion& paramMotion = *iter2;
|
||||
paramMotion.mMotion->activate(mActivationTimestamp);
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLKeyframeMotionParam::onUpdate()
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL LLKeyframeMotionParam::onUpdate(F32 time, U8* joint_mask)
|
||||
{
|
||||
F32 weightFactor = 1.f / (F32)mParameterizedMotions.size();
|
||||
|
||||
// zero out all pose weights
|
||||
for (motion_map_t::iterator iter = mParameterizedMotions.begin();
|
||||
iter != mParameterizedMotions.end(); ++iter)
|
||||
{
|
||||
motion_list_t& motionList = iter->second;
|
||||
for (motion_list_t::iterator iter2 = motionList.begin(); iter2 != motionList.end(); ++iter2)
|
||||
{
|
||||
const ParameterizedMotion& paramMotion = *iter2;
|
||||
// llinfos << "Weight for pose " << paramMotion.mMotion->getName() << " is " << paramMotion.mMotion->getPose()->getWeight() << llendl;
|
||||
paramMotion.mMotion->getPose()->setWeight(0.f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (motion_map_t::iterator iter = mParameterizedMotions.begin();
|
||||
iter != mParameterizedMotions.end(); ++iter)
|
||||
{
|
||||
const std::string& paramName = iter->first;
|
||||
F32* paramValue = (F32 *)mCharacter->getAnimationData(paramName);
|
||||
if (NULL == paramValue) // unexpected, but...
|
||||
{
|
||||
llwarns << "paramValue == NULL" << llendl;
|
||||
continue;
|
||||
}
|
||||
|
||||
// DANGER! Do not modify mParameterizedMotions while using these pointers!
|
||||
const ParameterizedMotion* firstMotion = NULL;
|
||||
const ParameterizedMotion* secondMotion = NULL;
|
||||
|
||||
motion_list_t& motionList = iter->second;
|
||||
for (motion_list_t::iterator iter2 = motionList.begin(); iter2 != motionList.end(); ++iter2)
|
||||
{
|
||||
const ParameterizedMotion& paramMotion = *iter2;
|
||||
paramMotion.mMotion->onUpdate(time, joint_mask);
|
||||
|
||||
F32 distToParam = paramMotion.mParam - *paramValue;
|
||||
|
||||
if ( distToParam <= 0.f)
|
||||
{
|
||||
// keep track of the motion closest to the parameter value
|
||||
firstMotion = ¶mMotion;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we've passed the parameter value
|
||||
// so store the first motion we find as the second one we want to blend...
|
||||
if (firstMotion && !secondMotion )
|
||||
{
|
||||
secondMotion = ¶mMotion;
|
||||
}
|
||||
//...or, if we've seen no other motion so far, make sure we blend to this only
|
||||
else if (!firstMotion)
|
||||
{
|
||||
firstMotion = ¶mMotion;
|
||||
secondMotion = ¶mMotion;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LLPose *firstPose;
|
||||
LLPose *secondPose;
|
||||
|
||||
if (firstMotion)
|
||||
firstPose = firstMotion->mMotion->getPose();
|
||||
else
|
||||
firstPose = NULL;
|
||||
|
||||
if (secondMotion)
|
||||
secondPose = secondMotion->mMotion->getPose();
|
||||
else
|
||||
secondPose = NULL;
|
||||
|
||||
// now modify weight of the subanim (only if we are blending between two motions)
|
||||
if (firstMotion && secondMotion)
|
||||
{
|
||||
if (firstMotion == secondMotion)
|
||||
{
|
||||
firstPose->setWeight(weightFactor);
|
||||
}
|
||||
else if (firstMotion->mParam == secondMotion->mParam)
|
||||
{
|
||||
firstPose->setWeight(0.5f * weightFactor);
|
||||
secondPose->setWeight(0.5f * weightFactor);
|
||||
}
|
||||
else
|
||||
{
|
||||
F32 first_weight = 1.f -
|
||||
((llclamp(*paramValue - firstMotion->mParam, 0.f, (secondMotion->mParam - firstMotion->mParam))) /
|
||||
(secondMotion->mParam - firstMotion->mParam));
|
||||
first_weight = llclamp(first_weight, 0.f, 1.f);
|
||||
|
||||
F32 second_weight = 1.f - first_weight;
|
||||
|
||||
firstPose->setWeight(first_weight * weightFactor);
|
||||
secondPose->setWeight(second_weight * weightFactor);
|
||||
|
||||
// llinfos << "Parameter " << *paramName << ": " << *paramValue << llendl;
|
||||
// llinfos << "Weights " << firstPose->getWeight() << " " << secondPose->getWeight() << llendl;
|
||||
}
|
||||
}
|
||||
else if (firstMotion && !secondMotion)
|
||||
{
|
||||
firstPose->setWeight(weightFactor);
|
||||
}
|
||||
}
|
||||
|
||||
// blend poses
|
||||
mPoseBlender.blendAndApply();
|
||||
|
||||
llinfos << "Param Motion weight " << mPoseBlender.getBlendedPose()->getWeight() << llendl;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLKeyframeMotionParam::onDeactivate()
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLKeyframeMotionParam::onDeactivate()
|
||||
{
|
||||
for (motion_map_t::iterator iter = mParameterizedMotions.begin();
|
||||
iter != mParameterizedMotions.end(); ++iter)
|
||||
{
|
||||
motion_list_t& motionList = iter->second;
|
||||
for (motion_list_t::iterator iter2 = motionList.begin(); iter2 != motionList.end(); ++iter2)
|
||||
{
|
||||
const ParameterizedMotion& paramMotion = *iter2;
|
||||
paramMotion.mMotion->onDeactivate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLKeyframeMotionParam::addKeyframeMotion()
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL LLKeyframeMotionParam::addKeyframeMotion(char *name, const LLUUID &id, char *param, F32 value)
|
||||
{
|
||||
LLMotion *newMotion = mCharacter->createMotion( id );
|
||||
|
||||
if (!newMotion)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
newMotion->setName(name);
|
||||
|
||||
// now add motion to this list
|
||||
mParameterizedMotions[param].insert(ParameterizedMotion(newMotion, value));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLKeyframeMotionParam::setDefaultKeyframeMotion()
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLKeyframeMotionParam::setDefaultKeyframeMotion(char *name)
|
||||
{
|
||||
for (motion_map_t::iterator iter = mParameterizedMotions.begin();
|
||||
iter != mParameterizedMotions.end(); ++iter)
|
||||
{
|
||||
motion_list_t& motionList = iter->second;
|
||||
for (motion_list_t::iterator iter2 = motionList.begin(); iter2 != motionList.end(); ++iter2)
|
||||
{
|
||||
const ParameterizedMotion& paramMotion = *iter2;
|
||||
if (paramMotion.mMotion->getName() == name)
|
||||
{
|
||||
mDefaultKeyframeMotion = paramMotion.mMotion;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// loadMotions()
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL LLKeyframeMotionParam::loadMotions()
|
||||
{
|
||||
//-------------------------------------------------------------------------
|
||||
// Load named file by concatenating the character prefix with the motion name.
|
||||
// Load data into a buffer to be parsed.
|
||||
//-------------------------------------------------------------------------
|
||||
//std::string path = gDirUtilp->getExpandedFilename(LL_PATH_MOTIONS,mCharacter->getAnimationPrefix())
|
||||
// + "_" + getName() + ".llp";
|
||||
//RN: deprecated unused reference to "motion" directory
|
||||
std::string path;
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// open the file
|
||||
//-------------------------------------------------------------------------
|
||||
S32 fileSize = 0;
|
||||
LLAPRFile infile(path, LL_APR_R, &fileSize);
|
||||
apr_file_t* fp = infile.getFileHandle() ;
|
||||
if (!fp || fileSize == 0)
|
||||
{
|
||||
llinfos << "ERROR: can't open: " << path << llendl;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// allocate a text buffer
|
||||
try
|
||||
{
|
||||
std::vector<char> text(fileSize+1);
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// load data from file into buffer
|
||||
//-------------------------------------------------------------------------
|
||||
bool error = false;
|
||||
char *p = &text[0];
|
||||
while ( 1 )
|
||||
{
|
||||
if (apr_file_eof(fp) == APR_EOF)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (apr_file_gets(p, 1024, fp) != APR_SUCCESS)
|
||||
{
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
while ( *(++p) )
|
||||
;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// close the file
|
||||
//-------------------------------------------------------------------------
|
||||
infile.close();
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// check for error
|
||||
//-------------------------------------------------------------------------
|
||||
llassert( p <= (&text[0] + fileSize) );
|
||||
|
||||
if ( error )
|
||||
{
|
||||
llinfos << "ERROR: error while reading from " << path << llendl;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
llinfos << "Loading parametric keyframe data for: " << getName() << llendl;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// parse the text and build keyframe data structures
|
||||
//-------------------------------------------------------------------------
|
||||
p = &text[0];
|
||||
S32 num;
|
||||
char strA[80]; /* Flawfinder: ignore */
|
||||
char strB[80]; /* Flawfinder: ignore */
|
||||
F32 floatA = 0.0f;
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// get priority
|
||||
//-------------------------------------------------------------------------
|
||||
BOOL isFirstMotion = TRUE;
|
||||
num = sscanf(p, "%79s %79s %f", strA, strB, &floatA); /* Flawfinder: ignore */
|
||||
|
||||
while(1)
|
||||
{
|
||||
if (num == 0 || num == EOF) break;
|
||||
if ((num != 3))
|
||||
{
|
||||
llinfos << "WARNING: can't read parametric motion" << llendl;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
addKeyframeMotion(strA, gAnimLibrary.stringToAnimState(std::string(strA)), strB, floatA);
|
||||
if (isFirstMotion)
|
||||
{
|
||||
isFirstMotion = FALSE;
|
||||
setDefaultKeyframeMotion(strA);
|
||||
}
|
||||
|
||||
p = strstr(p, "\n");
|
||||
if (!p)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
p++;
|
||||
num = sscanf(p, "%79s %79s %f", strA, strB, &floatA); /* Flawfinder: ignore */
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
catch(std::bad_alloc)
|
||||
{
|
||||
llinfos << "ERROR: Unable to allocate keyframe text buffer." << llendl;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// End
|
||||
@@ -1,176 +0,0 @@
|
||||
/**
|
||||
* @file llkeyframemotionparam.h
|
||||
* @brief Implementation of LLKeframeMotionParam class.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2002-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLKEYFRAMEMOTIONPARAM_H
|
||||
#define LL_LLKEYFRAMEMOTIONPARAM_H
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Header files
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "llmotion.h"
|
||||
#include "lljointstate.h"
|
||||
#include "v3math.h"
|
||||
#include "llquaternion.h"
|
||||
#include "linked_lists.h"
|
||||
#include "llkeyframemotion.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// class LLKeyframeMotionParam
|
||||
//-----------------------------------------------------------------------------
|
||||
class LLKeyframeMotionParam :
|
||||
public LLMotion
|
||||
{
|
||||
public:
|
||||
// Constructor
|
||||
LLKeyframeMotionParam(const LLUUID &id);
|
||||
|
||||
// Destructor
|
||||
virtual ~LLKeyframeMotionParam();
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------------------
|
||||
// functions to support MotionController and MotionRegistry
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
// static constructor
|
||||
// all subclasses must implement such a function and register it
|
||||
static LLMotion *create(const LLUUID &id) { return new LLKeyframeMotionParam(id); }
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------------------
|
||||
// animation callbacks to be implemented by subclasses
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
// motions must specify whether or not they loop
|
||||
virtual BOOL getLoop() {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// motions must report their total duration
|
||||
virtual F32 getDuration() {
|
||||
return mDuration;
|
||||
}
|
||||
|
||||
// motions must report their "ease in" duration
|
||||
virtual F32 getEaseInDuration() {
|
||||
return mEaseInDuration;
|
||||
}
|
||||
|
||||
// motions must report their "ease out" duration.
|
||||
virtual F32 getEaseOutDuration() {
|
||||
return mEaseOutDuration;
|
||||
}
|
||||
|
||||
// motions must report their priority
|
||||
virtual LLJoint::JointPriority getPriority() {
|
||||
return mPriority;
|
||||
}
|
||||
|
||||
virtual LLMotionBlendType getBlendType() { return NORMAL_BLEND; }
|
||||
|
||||
// called to determine when a motion should be activated/deactivated based on avatar pixel coverage
|
||||
virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_KEYFRAME; }
|
||||
|
||||
// run-time (post constructor) initialization,
|
||||
// called after parameters have been set
|
||||
// must return true to indicate success and be available for activation
|
||||
virtual LLMotionInitStatus onInitialize(LLCharacter *character);
|
||||
|
||||
// called when a motion is activated
|
||||
// must return TRUE to indicate success, or else
|
||||
// it will be deactivated
|
||||
virtual BOOL onActivate();
|
||||
|
||||
// called per time step
|
||||
// must return TRUE while it is active, and
|
||||
// must return FALSE when the motion is completed.
|
||||
virtual BOOL onUpdate(F32 time, U8* joint_mask);
|
||||
|
||||
// called when a motion is deactivated
|
||||
virtual void onDeactivate();
|
||||
|
||||
virtual LLPose* getPose() { return mPoseBlender.getBlendedPose();}
|
||||
|
||||
protected:
|
||||
//-------------------------------------------------------------------------
|
||||
// new functions defined by this subclass
|
||||
//-------------------------------------------------------------------------
|
||||
struct ParameterizedMotion
|
||||
{
|
||||
ParameterizedMotion(LLMotion* motion, F32 param) : mMotion(motion), mParam(param) {}
|
||||
LLMotion* mMotion;
|
||||
F32 mParam;
|
||||
};
|
||||
|
||||
// add a motion and associated parameter triplet
|
||||
BOOL addKeyframeMotion(char *name, const LLUUID &id, char *param, F32 value);
|
||||
|
||||
// set default motion for LOD and retrieving blend constants
|
||||
void setDefaultKeyframeMotion(char *);
|
||||
|
||||
BOOL loadMotions();
|
||||
|
||||
protected:
|
||||
//-------------------------------------------------------------------------
|
||||
// Member Data
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
struct compare_motions
|
||||
{
|
||||
bool operator() (const ParameterizedMotion& a, const ParameterizedMotion& b) const
|
||||
{
|
||||
if (a.mParam != b.mParam)
|
||||
return (a.mParam < b.mParam);
|
||||
else
|
||||
return a.mMotion < b.mMotion;
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::set < ParameterizedMotion, compare_motions > motion_list_t;
|
||||
typedef std::map <std::string, motion_list_t > motion_map_t;
|
||||
motion_map_t mParameterizedMotions;
|
||||
LLMotion* mDefaultKeyframeMotion;
|
||||
LLCharacter* mCharacter;
|
||||
LLPoseBlender mPoseBlender;
|
||||
|
||||
F32 mEaseInDuration;
|
||||
F32 mEaseOutDuration;
|
||||
F32 mDuration;
|
||||
LLJoint::JointPriority mPriority;
|
||||
|
||||
LLUUID mTransactionID;
|
||||
};
|
||||
|
||||
#endif // LL_LLKEYFRAMEMOTIONPARAM_H
|
||||
@@ -50,7 +50,7 @@ const F32 POSITION_THRESHOLD = 0.1f;
|
||||
// LLKeyframeStandMotion()
|
||||
// Class Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
LLKeyframeStandMotion::LLKeyframeStandMotion(const LLUUID &id) : LLKeyframeMotion(id)
|
||||
LLKeyframeStandMotion::LLKeyframeStandMotion(LLUUID const& id, LLMotionController* controller) : LLKeyframeMotion(id, controller)
|
||||
{
|
||||
mFlipFeet = FALSE;
|
||||
mCharacter = NULL;
|
||||
|
||||
@@ -48,7 +48,7 @@ class LLKeyframeStandMotion :
|
||||
{
|
||||
public:
|
||||
// Constructor
|
||||
LLKeyframeStandMotion(const LLUUID &id);
|
||||
LLKeyframeStandMotion(LLUUID const& id, LLMotionController* controller);
|
||||
|
||||
// Destructor
|
||||
virtual ~LLKeyframeStandMotion();
|
||||
@@ -60,7 +60,7 @@ public:
|
||||
|
||||
// static constructor
|
||||
// all subclasses must implement such a function and register it
|
||||
static LLMotion *create(const LLUUID &id) { return new LLKeyframeStandMotion(id); }
|
||||
static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLKeyframeStandMotion(id, controller); }
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
@@ -55,8 +55,8 @@ const F32 SPEED_ADJUST_TIME_CONSTANT = 0.1f; // time constant for speed adjustm
|
||||
// LLKeyframeWalkMotion()
|
||||
// Class Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
LLKeyframeWalkMotion::LLKeyframeWalkMotion(const LLUUID &id)
|
||||
: LLKeyframeMotion(id),
|
||||
LLKeyframeWalkMotion::LLKeyframeWalkMotion(LLUUID const& id, LLMotionController* controller)
|
||||
: LLKeyframeMotion(id, controller),
|
||||
mCharacter(NULL),
|
||||
mCyclePhase(0.0f),
|
||||
mRealTimeLast(0.0f),
|
||||
@@ -138,8 +138,8 @@ BOOL LLKeyframeWalkMotion::onUpdate(F32 time, U8* joint_mask)
|
||||
// LLWalkAdjustMotion()
|
||||
// Class Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
LLWalkAdjustMotion::LLWalkAdjustMotion(const LLUUID &id) :
|
||||
LLMotion(id),
|
||||
LLWalkAdjustMotion::LLWalkAdjustMotion(LLUUID const& id, LLMotionController* controller) :
|
||||
AIMaskedMotion(id, controller, ANIM_AGENT_WALK_ADJUST),
|
||||
mLastTime(0.f),
|
||||
mAnimSpeed(0.f),
|
||||
mAdjustedSpeed(0.f),
|
||||
@@ -193,7 +193,7 @@ BOOL LLWalkAdjustMotion::onActivate()
|
||||
F32 rightAnkleOffset = (mRightAnkleJoint->getWorldPosition() - mCharacter->getCharacterPosition()).magVec();
|
||||
mAnkleOffset = llmax(leftAnkleOffset, rightAnkleOffset);
|
||||
|
||||
return TRUE;
|
||||
return AIMaskedMotion::onActivate();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -325,13 +325,14 @@ BOOL LLWalkAdjustMotion::onUpdate(F32 time, U8* joint_mask)
|
||||
void LLWalkAdjustMotion::onDeactivate()
|
||||
{
|
||||
mCharacter->removeAnimationData("Walk Speed");
|
||||
AIMaskedMotion::onDeactivate();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLFlyAdjustMotion::LLFlyAdjustMotion()
|
||||
//-----------------------------------------------------------------------------
|
||||
LLFlyAdjustMotion::LLFlyAdjustMotion(const LLUUID &id)
|
||||
: LLMotion(id),
|
||||
LLFlyAdjustMotion::LLFlyAdjustMotion(LLUUID const& id, LLMotionController* controller)
|
||||
: AIMaskedMotion(id, controller, ANIM_AGENT_FLY_ADJUST),
|
||||
mRoll(0.f)
|
||||
{
|
||||
mName = "fly_adjust";
|
||||
@@ -368,7 +369,7 @@ BOOL LLFlyAdjustMotion::onActivate()
|
||||
mPelvisState->setPosition(LLVector3::zero);
|
||||
mPelvisState->setRotation(LLQuaternion::DEFAULT);
|
||||
mRoll = 0.f;
|
||||
return TRUE;
|
||||
return AIMaskedMotion::onActivate();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -52,7 +52,7 @@ class LLKeyframeWalkMotion :
|
||||
friend class LLWalkAdjustMotion;
|
||||
public:
|
||||
// Constructor
|
||||
LLKeyframeWalkMotion(const LLUUID &id);
|
||||
LLKeyframeWalkMotion(LLUUID const& id, LLMotionController* controller);
|
||||
|
||||
// Destructor
|
||||
virtual ~LLKeyframeWalkMotion();
|
||||
@@ -64,7 +64,7 @@ public:
|
||||
|
||||
// static constructor
|
||||
// all subclasses must implement such a function and register it
|
||||
static LLMotion *create(const LLUUID &id) { return new LLKeyframeWalkMotion(id); }
|
||||
static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLKeyframeWalkMotion(id, controller); }
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------------------
|
||||
@@ -86,11 +86,11 @@ public:
|
||||
S32 mDownFoot;
|
||||
};
|
||||
|
||||
class LLWalkAdjustMotion : public LLMotion
|
||||
class LLWalkAdjustMotion : public AIMaskedMotion
|
||||
{
|
||||
public:
|
||||
// Constructor
|
||||
LLWalkAdjustMotion(const LLUUID &id);
|
||||
LLWalkAdjustMotion(LLUUID const& id, LLMotionController* controller);
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------------------
|
||||
@@ -99,7 +99,7 @@ public:
|
||||
|
||||
// static constructor
|
||||
// all subclasses must implement such a function and register it
|
||||
static LLMotion *create(const LLUUID &id) { return new LLWalkAdjustMotion(id); }
|
||||
static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLWalkAdjustMotion(id, controller); }
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------------------
|
||||
@@ -136,11 +136,11 @@ public:
|
||||
F32 mAnkleOffset;
|
||||
};
|
||||
|
||||
class LLFlyAdjustMotion : public LLMotion
|
||||
class LLFlyAdjustMotion : public AIMaskedMotion
|
||||
{
|
||||
public:
|
||||
// Constructor
|
||||
LLFlyAdjustMotion(const LLUUID &id);
|
||||
LLFlyAdjustMotion(LLUUID const& id, LLMotionController* controller);
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------------------
|
||||
@@ -149,7 +149,7 @@ public:
|
||||
|
||||
// static constructor
|
||||
// all subclasses must implement such a function and register it
|
||||
static LLMotion *create(const LLUUID &id) { return new LLFlyAdjustMotion(id); }
|
||||
static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLFlyAdjustMotion(id, controller); }
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------------------
|
||||
@@ -157,7 +157,6 @@ public:
|
||||
//-------------------------------------------------------------------------
|
||||
virtual LLMotionInitStatus onInitialize(LLCharacter *character);
|
||||
virtual BOOL onActivate();
|
||||
virtual void onDeactivate() {};
|
||||
virtual BOOL onUpdate(F32 time, U8* joint_mask);
|
||||
virtual LLJoint::JointPriority getPriority(){return LLJoint::HIGHER_PRIORITY;}
|
||||
virtual BOOL getLoop() { return TRUE; }
|
||||
|
||||
@@ -37,6 +37,125 @@
|
||||
|
||||
#include "llmotion.h"
|
||||
#include "llcriticaldamp.h"
|
||||
#include "llmotioncontroller.h"
|
||||
|
||||
//<singu>
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// AISyncClientMotion class
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
AISyncKey* AISyncClientMotion::createSyncKey(AISyncKey const* from_key) const
|
||||
{
|
||||
// The const cast is needed because getDuration() is non-const while it should have been.
|
||||
AISyncClientMotion* self = const_cast<AISyncClientMotion*>(this);
|
||||
// Only synchronize motions with the same duration and loop value.
|
||||
return new AISyncKeyMotion(from_key, self->getDuration(), self->getLoop());
|
||||
}
|
||||
|
||||
void AISyncClientMotion::aisync_loading(void)
|
||||
{
|
||||
// Register the motion for (possible) synchronization: this marks the time at which is should have started.
|
||||
unregister_client(); // In case it is already registered. Getting here means we are being (re)started now, we need to synchronize with other motions that start now.
|
||||
register_client();
|
||||
}
|
||||
|
||||
void AISyncClientMotion::aisync_loaded(void)
|
||||
{
|
||||
AISyncServer* server = this->server();
|
||||
if (!server)
|
||||
{
|
||||
// Already expired without being synchronized (no other motion was started at the same time).
|
||||
return;
|
||||
}
|
||||
AISyncKey const& key = server->key(); // The allocation of this is owned by server.
|
||||
// There is no need to resync if there was not another motion started at the same time and the key already expired.
|
||||
bool need_resync = !(server->never_synced() && key.expired());
|
||||
AISyncKey* new_key = NULL;
|
||||
if (need_resync)
|
||||
{
|
||||
// Create a new key using the old start time.
|
||||
new_key = createSyncKey(&key);
|
||||
}
|
||||
server->remove(this); // This resets mServer and might even delete server.
|
||||
if (need_resync)
|
||||
{
|
||||
// Add the client to another server (based on the new key). This takes ownership of the key allocation.
|
||||
AISyncServerMap::instance().register_client(this, new_key);
|
||||
}
|
||||
}
|
||||
|
||||
F32 LLMotion::getRuntime(void) const
|
||||
{
|
||||
llassert(mActive);
|
||||
return mController->getAnimTime() - mActivationTimestamp;
|
||||
}
|
||||
|
||||
F32 LLMotion::getAnimTime(void) const
|
||||
{
|
||||
return mController->getAnimTime();
|
||||
}
|
||||
|
||||
F32 LLMotion::syncActivationTime(F32 time)
|
||||
{
|
||||
AISyncServer* server = this->server();
|
||||
if (!server)
|
||||
{
|
||||
register_client();
|
||||
server = this->server();
|
||||
}
|
||||
AISyncServer::client_list_t const& clients = server->getClients();
|
||||
if (clients.size() > 1)
|
||||
{
|
||||
// Look for the client with the smallest runtime.
|
||||
AISyncClientMotion* motion_with_smallest_runtime = NULL;
|
||||
F32 runtime = 1e10;
|
||||
// Run over all motions in this to be synchronized group.
|
||||
for (AISyncServer::client_list_t::const_iterator client = clients.begin(); client != clients.end(); ++client)
|
||||
{
|
||||
if ((client->mReadyEvents & 2)) // Is this motion active? Motions that aren't loaded yet are not active.
|
||||
{
|
||||
// Currently, if event 2 is set then this is an LLMotion.
|
||||
llassert(dynamic_cast<AISyncClientMotion*>(client->mClientPtr));
|
||||
AISyncClientMotion* motion = static_cast<AISyncClientMotion*>(client->mClientPtr);
|
||||
// Deactivated motions should have been deregistered, certainly not have event 2 set.
|
||||
llassert(static_cast<LLMotion*>(motion)->isActive());
|
||||
if (motion->getRuntime() < runtime)
|
||||
{
|
||||
// This is a bit fuzzy since theoretically the runtime of all active motions in the list should be the same.
|
||||
// Just use the smallest value to get rid of some randomness. We might even synchronizing with ourselves
|
||||
// in which case 'time' would be set to a value such that mActivationTimestamp won't change.
|
||||
// In practise however, this list will contain only two clients: this, being inactive, and our partner.
|
||||
runtime = motion->getRuntime();
|
||||
motion_with_smallest_runtime = motion;
|
||||
}
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------
|
||||
// Here is where the actual synchronization takes place.
|
||||
// Current we only synchronize looped motions.
|
||||
if (getLoop())
|
||||
{
|
||||
if (motion_with_smallest_runtime)
|
||||
{
|
||||
// Pretend the motion was started in the past at the same time as the other motion(s).
|
||||
time = getAnimTime() - runtime;
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------
|
||||
}
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
void AISyncClientMotion::deregistered(void)
|
||||
{
|
||||
#ifdef SHOW_ASSERT
|
||||
mReadyEvents = 0;
|
||||
#endif
|
||||
}
|
||||
//</singu>
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -48,10 +167,11 @@
|
||||
// LLMotion()
|
||||
// Class Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
LLMotion::LLMotion( const LLUUID &id ) :
|
||||
LLMotion::LLMotion(LLUUID const& id, LLMotionController* controller) :
|
||||
mStopped(TRUE),
|
||||
mActive(FALSE),
|
||||
mID(id),
|
||||
mController(controller),
|
||||
mActivationTimestamp(0.f),
|
||||
mStopTimestamp(0.f),
|
||||
mSendStopTimestamp(F32_MAX),
|
||||
@@ -147,6 +267,19 @@ void LLMotion::activate(F32 time)
|
||||
{
|
||||
mActivationTimestamp = time;
|
||||
mStopped = FALSE;
|
||||
//<singu>
|
||||
if (mController && !mController->syncing_disabled()) // Avoid being registered when syncing is disabled for this motion.
|
||||
{
|
||||
if (mActive)
|
||||
{
|
||||
// If the motion is already active then we are being restarted.
|
||||
// Unregister it first (if it is registered) so that the call to ready will cause it to be registered
|
||||
// and be synchronized with other motions that are started at this moment.
|
||||
unregister_client();
|
||||
}
|
||||
ready(6, 2 | (mController->isHidden() ? 0 : 4)); // Signal that mActivationTimestamp is set/valid (2), and that this server has a visible motion (4) (or not).
|
||||
}
|
||||
//</singu>
|
||||
mActive = TRUE;
|
||||
onActivate();
|
||||
}
|
||||
@@ -159,6 +292,14 @@ void LLMotion::deactivate()
|
||||
mActive = FALSE;
|
||||
mPose.setWeight(0.f);
|
||||
|
||||
//<singu>
|
||||
if (server()) // Only when this motion is already registered.
|
||||
{
|
||||
ready(6, 0); // Signal that mActivationTimestamp is no longer valid.
|
||||
unregister_client(); // No longer running, so no longer a part of this sync group.
|
||||
}
|
||||
//</singu>
|
||||
|
||||
if (mDeactivateCallback)
|
||||
{
|
||||
(*mDeactivateCallback)(mDeactivateCallbackUserData);
|
||||
@@ -174,4 +315,19 @@ BOOL LLMotion::canDeprecate()
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// AIMaskedMotion
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
BOOL AIMaskedMotion::onActivate()
|
||||
{
|
||||
mController->activated(mMaskBit);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void AIMaskedMotion::onDeactivate()
|
||||
{
|
||||
mController->deactivated(mMaskBit);
|
||||
}
|
||||
|
||||
// End
|
||||
|
||||
@@ -38,16 +38,85 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
#include <string>
|
||||
|
||||
#include "aisyncclient.h"
|
||||
#include "llerror.h"
|
||||
#include "llpose.h"
|
||||
#include "lluuid.h"
|
||||
|
||||
class LLCharacter;
|
||||
class LLMotionController;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// class AISync* stuff
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class AISyncKeyMotion : public AISyncKey
|
||||
{
|
||||
private:
|
||||
F32 mDuration;
|
||||
bool mLoop;
|
||||
|
||||
public:
|
||||
AISyncKeyMotion(AISyncKey const* from_key, F32 duration, bool loop) : AISyncKey(from_key), mDuration(duration), mLoop(loop) { }
|
||||
|
||||
// Virtual functions of AISyncKey.
|
||||
public:
|
||||
/*virtual*/ synckeytype_t getkeytype(void) const
|
||||
{
|
||||
// Return a unique identifier for this class, where the low 8 bits represent the syncgroup.
|
||||
return synckeytype_motion;
|
||||
}
|
||||
|
||||
/*virtual*/ bool equals(AISyncKey const& key) const
|
||||
{
|
||||
switch (key.getkeytype())
|
||||
{
|
||||
case synckeytype_motion:
|
||||
{
|
||||
// The other key is of the same type.
|
||||
AISyncKeyMotion const& motion_key = static_cast<AISyncKeyMotion const&>(key);
|
||||
return mLoop == motion_key.mLoop && is_approx_equal(mDuration, motion_key.mDuration);
|
||||
}
|
||||
default:
|
||||
// The keys must be in the same syncgroup.
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class AISyncClientMotion : public AISyncClient
|
||||
{
|
||||
protected:
|
||||
// Make sure that clients that are destroyed are first unregistered.
|
||||
// This is needed, for example, when loading fails or when excess motions are being purged.
|
||||
/*virtual*/ ~AISyncClientMotion() { unregister_client(); }
|
||||
|
||||
// AISyncClient events.
|
||||
/*virtual*/ AISyncKey* createSyncKey(AISyncKey const* from_key = NULL) const;
|
||||
/*virtual*/ void event1_ready(void) { }
|
||||
/*virtual*/ void event1_not_ready(void) { }
|
||||
/*virtual*/ void deregistered(void);
|
||||
|
||||
protected:
|
||||
// This is called when the server sent us a message that it wants us to play this animation, but we can't because it isn't fully downloaded yet.
|
||||
void aisync_loading(void);
|
||||
// This is called when that motion is successfully loaded and it has to be re-registered because now the duration etc is known.
|
||||
void aisync_loaded(void);
|
||||
|
||||
public:
|
||||
// Virtual functions of AISyncClientMotion.
|
||||
// These are defined by classes derived from LLMotion (which is derived from this class).
|
||||
virtual BOOL getLoop() = 0;
|
||||
virtual F32 getDuration() = 0;
|
||||
virtual F32 getAnimTime(void) const = 0;
|
||||
virtual F32 getRuntime(void) const = 0;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// class LLMotion
|
||||
//-----------------------------------------------------------------------------
|
||||
class LLMotion
|
||||
class LLMotion : public AISyncClientMotion
|
||||
{
|
||||
friend class LLMotionController;
|
||||
|
||||
@@ -66,7 +135,7 @@ public:
|
||||
};
|
||||
|
||||
// Constructor
|
||||
LLMotion(const LLUUID &id);
|
||||
LLMotion(LLUUID const& id, LLMotionController* controller);
|
||||
|
||||
// Destructor
|
||||
virtual ~LLMotion();
|
||||
@@ -114,7 +183,22 @@ protected:
|
||||
BOOL isActive() { return mActive; }
|
||||
public:
|
||||
void activate(F32 time);
|
||||
|
||||
|
||||
//<singu>
|
||||
// Returns the time that this motion has been running.
|
||||
virtual F32 getRuntime(void) const;
|
||||
|
||||
// Return the current time (in seconds since creation of the controller).
|
||||
virtual F32 getAnimTime(void) const;
|
||||
|
||||
// This is called when a motion is to be activated, but might need synchronization.
|
||||
// It adjusts the start time to match that of other motions in the same synchronization group that were already started.
|
||||
F32 syncActivationTime(F32 time);
|
||||
|
||||
// Accessor.
|
||||
LLMotionController* getController(void) const { return mController; }
|
||||
//</singu>
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------------------
|
||||
// animation callbacks to be implemented by subclasses
|
||||
@@ -181,6 +265,9 @@ protected:
|
||||
//-------------------------------------------------------------------------
|
||||
std::string mName; // instance name assigned by motion controller
|
||||
LLUUID mID;
|
||||
//<singu>
|
||||
LLMotionController* mController;
|
||||
//</singu>
|
||||
|
||||
F32 mActivationTimestamp; // time when motion was activated
|
||||
F32 mStopTimestamp; // time when motion was told to stop
|
||||
@@ -199,9 +286,9 @@ protected:
|
||||
class LLTestMotion : public LLMotion
|
||||
{
|
||||
public:
|
||||
LLTestMotion(const LLUUID &id) : LLMotion(id){}
|
||||
LLTestMotion(LLUUID const& id, LLMotionController* controller) : LLMotion(id, controller){}
|
||||
~LLTestMotion() {}
|
||||
static LLMotion *create(const LLUUID& id) { return new LLTestMotion(id); }
|
||||
static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLTestMotion(id, controller); }
|
||||
BOOL getLoop() { return FALSE; }
|
||||
F32 getDuration() { return 0.0f; }
|
||||
F32 getEaseInDuration() { return 0.0f; }
|
||||
@@ -223,9 +310,9 @@ public:
|
||||
class LLNullMotion : public LLMotion
|
||||
{
|
||||
public:
|
||||
LLNullMotion(const LLUUID &id) : LLMotion(id) {}
|
||||
LLNullMotion(LLUUID const& id, LLMotionController* controller) : LLMotion(id, controller) {}
|
||||
~LLNullMotion() {}
|
||||
static LLMotion *create(const LLUUID &id) { return new LLNullMotion(id); }
|
||||
static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLNullMotion(id, controller); }
|
||||
|
||||
// motions must specify whether or not they loop
|
||||
/*virtual*/ BOOL getLoop() { return TRUE; }
|
||||
@@ -266,5 +353,41 @@ public:
|
||||
// called when a motion is deactivated
|
||||
/*virtual*/ void onDeactivate() {}
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// AIMaskedMotion
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// These motions have a bit assigned in LLMotionController::mActiveMask
|
||||
// that is set and uset upon activation/deactivation.
|
||||
|
||||
// This must be in the same order as ANIM_AGENT_BODY_NOISE_ID through ANIM_AGENT_WALK_ADJUST_ID in llvoavatar.cpp.
|
||||
U32 const ANIM_AGENT_BODY_NOISE = 0x001;
|
||||
U32 const ANIM_AGENT_BREATHE_ROT = 0x002;
|
||||
U32 const ANIM_AGENT_PHYSICS_MOTION = 0x004;
|
||||
U32 const ANIM_AGENT_EDITING = 0x008;
|
||||
U32 const ANIM_AGENT_EYE = 0x010;
|
||||
U32 const ANIM_AGENT_FLY_ADJUST = 0x020;
|
||||
U32 const ANIM_AGENT_HAND_MOTION = 0x040;
|
||||
U32 const ANIM_AGENT_HEAD_ROT = 0x080;
|
||||
U32 const ANIM_AGENT_PELVIS_FIX = 0x100;
|
||||
U32 const ANIM_AGENT_TARGET = 0x200;
|
||||
U32 const ANIM_AGENT_WALK_ADJUST = 0x400;
|
||||
|
||||
class AIMaskedMotion : public LLMotion
|
||||
{
|
||||
private:
|
||||
U32 mMaskBit;
|
||||
|
||||
public:
|
||||
AIMaskedMotion(LLUUID const& id, LLMotionController* controller, U32 mask_bit) : LLMotion(id, controller), mMaskBit(mask_bit) { }
|
||||
|
||||
/*virtual*/ BOOL onActivate();
|
||||
/*virtual*/ void onDeactivate();
|
||||
|
||||
U32 getMaskBit(void) const { return mMaskBit; }
|
||||
};
|
||||
|
||||
#endif // LL_LLMOTION_H
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ void LLMotionRegistry::markBad( const LLUUID& id )
|
||||
//-----------------------------------------------------------------------------
|
||||
// createMotion()
|
||||
//-----------------------------------------------------------------------------
|
||||
LLMotion *LLMotionRegistry::createMotion( const LLUUID &id )
|
||||
LLMotion* LLMotionRegistry::createMotion(LLUUID const& id, LLMotionController* controller)
|
||||
{
|
||||
LLMotionConstructor constructor = get_if_there(mMotionTable, id, LLMotionConstructor(NULL));
|
||||
LLMotion* motion = NULL;
|
||||
@@ -105,11 +105,11 @@ LLMotion *LLMotionRegistry::createMotion( const LLUUID &id )
|
||||
if ( constructor == NULL )
|
||||
{
|
||||
// *FIX: need to replace with a better default scheme. RN
|
||||
motion = LLKeyframeMotion::create(id);
|
||||
motion = LLKeyframeMotion::create(id, controller);
|
||||
}
|
||||
else
|
||||
{
|
||||
motion = constructor(id);
|
||||
motion = constructor(id, controller);
|
||||
}
|
||||
|
||||
return motion;
|
||||
@@ -126,18 +126,22 @@ LLMotion *LLMotionRegistry::createMotion( const LLUUID &id )
|
||||
// Class Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
LLMotionController::LLMotionController()
|
||||
: mTimeFactor(sCurrentTimeFactor),
|
||||
: mIsSelf(FALSE),
|
||||
mTimeFactor(sCurrentTimeFactor),
|
||||
mCharacter(NULL),
|
||||
mAnimTime(0.f),
|
||||
mActiveMask(0),
|
||||
mDisableSyncing(0),
|
||||
mHidden(false),
|
||||
mHaveVisibleSyncedMotions(false),
|
||||
mPrevTimerElapsed(0.f),
|
||||
mAnimTime(0.f),
|
||||
mLastTime(0.0f),
|
||||
mHasRunOnce(FALSE),
|
||||
mPaused(FALSE),
|
||||
mPauseTime(0.f),
|
||||
mTimeStep(0.f),
|
||||
mTimeStepCount(0),
|
||||
mLastInterp(0.f),
|
||||
mIsSelf(FALSE)
|
||||
mLastInterp(0.f)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -168,7 +172,15 @@ void LLMotionController::deleteAllMotions()
|
||||
mLoadingMotions.clear();
|
||||
mLoadedMotions.clear();
|
||||
mActiveMotions.clear();
|
||||
|
||||
//<singu>
|
||||
mActiveMask = 0;
|
||||
for_each(mDeprecatedMotions.begin(), mDeprecatedMotions.end(), DeletePointer());
|
||||
mDeprecatedMotions.clear();
|
||||
for (motion_map_t::iterator iter = mAllMotions.begin(); iter != mAllMotions.end(); ++iter)
|
||||
{
|
||||
iter->second->unregister_client();
|
||||
}
|
||||
//</singu>
|
||||
for_each(mAllMotions.begin(), mAllMotions.end(), DeletePairedPointer());
|
||||
mAllMotions.clear();
|
||||
}
|
||||
@@ -178,26 +190,19 @@ void LLMotionController::deleteAllMotions()
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLMotionController::purgeExcessMotions()
|
||||
{
|
||||
if (mLoadedMotions.size() > MAX_MOTION_INSTANCES)
|
||||
//<singu>
|
||||
// The old code attempted to remove non-active motions from mDeprecatedMotions,
|
||||
// but that is nonsense: there are no motions in mDeprecatedMotions that are not active.
|
||||
if (mLoadedMotions.size() <= MAX_MOTION_INSTANCES)
|
||||
{
|
||||
// clean up deprecated motions
|
||||
for (motion_set_t::iterator deprecated_motion_it = mDeprecatedMotions.begin();
|
||||
deprecated_motion_it != mDeprecatedMotions.end(); )
|
||||
{
|
||||
motion_set_t::iterator cur_iter = deprecated_motion_it++;
|
||||
LLMotion* cur_motionp = *cur_iter;
|
||||
if (!isMotionActive(cur_motionp))
|
||||
{
|
||||
// Motion is deprecated so we know it's not cannonical,
|
||||
// we can safely remove the instance
|
||||
removeMotionInstance(cur_motionp); // modifies mDeprecatedMotions
|
||||
mDeprecatedMotions.erase(cur_iter);
|
||||
}
|
||||
}
|
||||
// Speed up, no need to create motions_to_kill.
|
||||
return;
|
||||
}
|
||||
//</singu>
|
||||
|
||||
std::set<LLUUID> motions_to_kill;
|
||||
if (mLoadedMotions.size() > MAX_MOTION_INSTANCES)
|
||||
|
||||
if (1) // Singu: leave indentation alone...
|
||||
{
|
||||
// too many motions active this frame, kill all blenders
|
||||
mPoseBlender.clearBlenders();
|
||||
@@ -308,24 +313,44 @@ BOOL LLMotionController::registerMotion( const LLUUID& id, LLMotionConstructor c
|
||||
void LLMotionController::removeMotion( const LLUUID& id)
|
||||
{
|
||||
LLMotion* motionp = findMotion(id);
|
||||
mAllMotions.erase(id);
|
||||
removeMotionInstance(motionp);
|
||||
//<singu>
|
||||
// If a motion is erased from mAllMotions, it must be deleted.
|
||||
if (motionp)
|
||||
{
|
||||
mAllMotions.erase(id);
|
||||
removeMotionInstance(motionp);
|
||||
delete motionp;
|
||||
}
|
||||
//</singu>
|
||||
}
|
||||
|
||||
// removes instance of a motion from all runtime structures, but does
|
||||
// not erase entry by ID, as this could be a duplicate instance
|
||||
// use removeMotion(id) to remove all references to a given motion by id.
|
||||
// use removeMotion(id) to remove a reference to a given motion by id
|
||||
// (that will not remove (active) deprecated motions).
|
||||
void LLMotionController::removeMotionInstance(LLMotion* motionp)
|
||||
{
|
||||
if (motionp)
|
||||
{
|
||||
llassert(findMotion(motionp->getID()) != motionp);
|
||||
if (motionp->isActive())
|
||||
motionp->deactivate();
|
||||
mLoadingMotions.erase(motionp);
|
||||
mLoadedMotions.erase(motionp);
|
||||
mActiveMotions.remove(motionp);
|
||||
delete motionp;
|
||||
//<singu>
|
||||
// Deactivation moved here. Only delete motionp when it is being removed from mDeprecatedMotions.
|
||||
if (motionp->isActive())
|
||||
{
|
||||
motionp->deactivate();
|
||||
// If a motion is deactivated, it must be removed from mDeprecatedMotions if there.
|
||||
motion_set_t::iterator found_it = mDeprecatedMotions.find(motionp);
|
||||
if (found_it != mDeprecatedMotions.end())
|
||||
{
|
||||
mDeprecatedMotions.erase(found_it);
|
||||
// If a motion is erased from mDeprecatedMotions, it must be deleted.
|
||||
delete motionp;
|
||||
}
|
||||
}
|
||||
//</singu>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -341,7 +366,7 @@ LLMotion* LLMotionController::createMotion( const LLUUID &id )
|
||||
if (!motion)
|
||||
{
|
||||
// look up constructor and create it
|
||||
motion = sRegistry.createMotion(id);
|
||||
motion = sRegistry.createMotion(id, this);
|
||||
if (!motion)
|
||||
{
|
||||
return NULL;
|
||||
@@ -393,6 +418,7 @@ BOOL LLMotionController::startMotion(const LLUUID &id, F32 start_offset)
|
||||
if (motion
|
||||
&& !mPaused
|
||||
&& motion->canDeprecate()
|
||||
&& motion->isActive() // singu: do not deprecate motions that are not active.
|
||||
&& motion->getFadeWeight() > 0.01f // not LOD-ed out
|
||||
&& (motion->isBlending() || motion->getStopTime() != 0.f))
|
||||
{
|
||||
@@ -418,7 +444,19 @@ BOOL LLMotionController::startMotion(const LLUUID &id, F32 start_offset)
|
||||
}
|
||||
|
||||
// llinfos << "Starting motion " << name << llendl;
|
||||
return activateMotionInstance(motion, mAnimTime - start_offset);
|
||||
//<singu>
|
||||
F32 start_time = mAnimTime - start_offset;
|
||||
if (!mDisableSyncing)
|
||||
{
|
||||
start_time = motion->syncActivationTime(start_time);
|
||||
}
|
||||
++mDisableSyncing;
|
||||
//</singu>
|
||||
BOOL res = activateMotionInstance(motion, start_time);
|
||||
//<singu>
|
||||
--mDisableSyncing;
|
||||
//</singu>
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@@ -774,7 +812,19 @@ void LLMotionController::updateLoadingMotions()
|
||||
// this motion should be playing
|
||||
if (!motionp->isStopped())
|
||||
{
|
||||
activateMotionInstance(motionp, mAnimTime);
|
||||
//<singu>
|
||||
F32 start_time = mAnimTime;
|
||||
if (!mDisableSyncing)
|
||||
{
|
||||
motionp->aisync_loaded();
|
||||
start_time = motionp->syncActivationTime(start_time);
|
||||
}
|
||||
++mDisableSyncing;
|
||||
//</singu>
|
||||
activateMotionInstance(motionp, start_time);
|
||||
//<singu>
|
||||
--mDisableSyncing;
|
||||
//</singu>
|
||||
}
|
||||
}
|
||||
else if (status == LLMotion::STATUS_FAILURE)
|
||||
@@ -782,12 +832,15 @@ void LLMotionController::updateLoadingMotions()
|
||||
llinfos << "Motion " << motionp->getID() << " init failed." << llendl;
|
||||
sRegistry.markBad(motionp->getID());
|
||||
mLoadingMotions.erase(curiter);
|
||||
motion_set_t::iterator found_it = mDeprecatedMotions.find(motionp);
|
||||
if (found_it != mDeprecatedMotions.end())
|
||||
{
|
||||
mDeprecatedMotions.erase(found_it);
|
||||
}
|
||||
// Singu note: a motion in mLoadingMotions will not be in mActiveMotions
|
||||
// and therefore not be in mDeprecatedMotions. So, we don't have to
|
||||
// check for it's existence there.
|
||||
llassert(mDeprecatedMotions.find(motionp) == mDeprecatedMotions.end());
|
||||
mAllMotions.erase(motionp->getID());
|
||||
//<singu>
|
||||
// Make sure we're not registered anymore.
|
||||
motionp->unregister_client();
|
||||
//</singu>
|
||||
delete motionp;
|
||||
}
|
||||
}
|
||||
@@ -821,8 +874,15 @@ void LLMotionController::updateMotions(bool force_update)
|
||||
{
|
||||
F32 time_interval = fmodf(update_time, mTimeStep);
|
||||
|
||||
// always animate *ahead* of actual time
|
||||
S32 quantum_count = llmax(0, llfloor((update_time - time_interval) / mTimeStep)) + 1;
|
||||
//<singu>
|
||||
// This old code is nonsense.
|
||||
//S32 quantum_count = llmax(0, llround((update_time - time_interval) / mTimeStep)) + 1;
|
||||
// (update_time - time_interval) / mTimeStep is an integer! We need llround to get rid of floating point errors, not llfloor.
|
||||
// Moreover, just rounding off to the nearest integer with llround(update_time / mTimeStep) makes a lot more sense:
|
||||
// it is the best we can do to get as close to what we should draw as possible.
|
||||
// However, mAnimTime may only be incremented; therefore make sure of that with the llmax.
|
||||
S32 quantum_count = llmax(llround(update_time / mTimeStep), llceil(mAnimTime / mTimeStep));
|
||||
//</singu>
|
||||
if (quantum_count == mTimeStepCount)
|
||||
{
|
||||
// we're still in same time quantum as before, so just interpolate and exit
|
||||
@@ -848,7 +908,8 @@ void LLMotionController::updateMotions(bool force_update)
|
||||
}
|
||||
else
|
||||
{
|
||||
mAnimTime = update_time;
|
||||
// Singu note: mAnimTime may never be set back in time.
|
||||
mAnimTime = llmax(mAnimTime, update_time);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -915,6 +976,12 @@ BOOL LLMotionController::activateMotionInstance(LLMotion *motion, F32 time)
|
||||
|
||||
if (mLoadingMotions.find(motion) != mLoadingMotions.end())
|
||||
{
|
||||
//<singu>
|
||||
if (!syncing_disabled())
|
||||
{
|
||||
motion->aisync_loading();
|
||||
}
|
||||
//</singu>
|
||||
// we want to start this motion, but we can't yet, so flag it as started
|
||||
motion->setStopped(FALSE);
|
||||
// report pending animations as activated
|
||||
@@ -970,18 +1037,16 @@ BOOL LLMotionController::activateMotionInstance(LLMotion *motion, F32 time)
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL LLMotionController::deactivateMotionInstance(LLMotion *motion)
|
||||
{
|
||||
motion->deactivate();
|
||||
|
||||
motion_set_t::iterator found_it = mDeprecatedMotions.find(motion);
|
||||
if (found_it != mDeprecatedMotions.end())
|
||||
{
|
||||
// deprecated motions need to be completely excised
|
||||
removeMotionInstance(motion);
|
||||
mDeprecatedMotions.erase(found_it);
|
||||
removeMotionInstance(motion); // singu note: this deactivates motion and removes it from mDeprecatedMotions.
|
||||
}
|
||||
else
|
||||
{
|
||||
// for motions that we are keeping, simply remove from active queue
|
||||
motion->deactivate(); // singu note: moved here from the top of the function.
|
||||
mActiveMotions.remove(motion);
|
||||
}
|
||||
|
||||
@@ -1049,11 +1114,26 @@ void LLMotionController::dumpMotions()
|
||||
state_string += std::string("L");
|
||||
if (std::find(mActiveMotions.begin(), mActiveMotions.end(), motion)!=mActiveMotions.end())
|
||||
state_string += std::string("A");
|
||||
if (mDeprecatedMotions.find(motion) != mDeprecatedMotions.end())
|
||||
state_string += std::string("D");
|
||||
llassert(mDeprecatedMotions.find(motion) == mDeprecatedMotions.end()); // singu: it's impossible that a motion is in mAllMotions and mDeprecatedMotions at the same time.
|
||||
llinfos << gAnimLibrary.animationName(id) << " " << state_string << llendl;
|
||||
|
||||
}
|
||||
//<singu>
|
||||
// Also dump the deprecated motions.
|
||||
for (motion_set_t::iterator iter = mDeprecatedMotions.begin();
|
||||
iter != mDeprecatedMotions.end(); ++iter)
|
||||
{
|
||||
std::string state_string;
|
||||
LLMotion* motion = *iter;
|
||||
LLUUID id = motion->getID();
|
||||
llassert(mLoadingMotions.find(motion) == mLoadingMotions.end());
|
||||
if (mLoadedMotions.find(motion) != mLoadedMotions.end())
|
||||
state_string += std::string("L");
|
||||
if (std::find(mActiveMotions.begin(), mActiveMotions.end(), motion)!=mActiveMotions.end())
|
||||
state_string += std::string("A");
|
||||
state_string += "D";
|
||||
llinfos << gAnimLibrary.animationName(id) << " " << state_string << llendl;
|
||||
}
|
||||
//</singu>
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -1061,11 +1141,11 @@ void LLMotionController::dumpMotions()
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLMotionController::deactivateAllMotions()
|
||||
{
|
||||
for (motion_map_t::iterator iter = mAllMotions.begin();
|
||||
iter != mAllMotions.end(); iter++)
|
||||
// Singu note: this must run over mActiveMotions: other motions are not active,
|
||||
// and running over mAllMotions will miss the ones in mDeprecatedMotions.
|
||||
for (motion_list_t::iterator iter = mActiveMotions.begin(); iter != mActiveMotions.end();)
|
||||
{
|
||||
LLMotion* motionp = iter->second;
|
||||
deactivateMotionInstance(motionp);
|
||||
deactivateMotionInstance(*iter++); // This might invalidate iter by erasing it from mActiveMotions.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1086,8 +1166,7 @@ void LLMotionController::flushAllMotions()
|
||||
active_motions.push_back(std::make_pair(motionp->getID(),dtime));
|
||||
motionp->deactivate(); // don't call deactivateMotionInstance() because we are going to reactivate it
|
||||
}
|
||||
mActiveMotions.clear();
|
||||
|
||||
|
||||
// delete all motion instances
|
||||
deleteAllMotions();
|
||||
|
||||
@@ -1096,13 +1175,136 @@ void LLMotionController::flushAllMotions()
|
||||
mCharacter->removeAnimationData("Hand Pose");
|
||||
|
||||
// restart motions
|
||||
//<singu>
|
||||
// Because we called motionp->deactivate() above, instead of deactivateMotionInstance(),
|
||||
// prevent calling AISyncClientMotion::activateInstance in startMotion below.
|
||||
disable_syncing();
|
||||
//</singu>
|
||||
for (std::vector<std::pair<LLUUID,F32> >::iterator iter = active_motions.begin();
|
||||
iter != active_motions.end(); ++iter)
|
||||
{
|
||||
startMotion(iter->first, iter->second);
|
||||
}
|
||||
//<singu>
|
||||
enable_syncing();
|
||||
//</singu>
|
||||
}
|
||||
|
||||
//<singu>
|
||||
//-----------------------------------------------------------------------------
|
||||
// toggle_hidden()
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLMotionController::toggle_hidden(void)
|
||||
{
|
||||
mHaveVisibleSyncedMotions = mHidden; // Default is false if we just became invisible (otherwise this value isn't used).
|
||||
mHidden = !mHidden;
|
||||
synceventset_t const visible = mHidden ? 0 : 4;
|
||||
|
||||
// Run over all motions.
|
||||
for (motion_list_t::iterator iter = mActiveMotions.begin(); iter != mActiveMotions.end(); ++iter)
|
||||
{
|
||||
LLMotion* motionp = *iter;
|
||||
AISyncServer* server = motionp->server();
|
||||
if (server && !server->never_synced() && motionp->isActive()) // Skip motions that aren't synchronized at all or that are not active.
|
||||
{
|
||||
bool visible_before = server->events_with_at_least_one_client_ready() & 4;
|
||||
server->ready(4, visible, motionp); // Mark that now we are visible or no longer visible.
|
||||
bool visible_after = server->events_with_at_least_one_client_ready() & 4;
|
||||
if (visible_after) // Are there any synchronized motions (left) that ARE visible?
|
||||
{
|
||||
mHaveVisibleSyncedMotions = true;
|
||||
}
|
||||
if (visible_before != visible_after)
|
||||
{
|
||||
// The group as a whole now might need to change whether or not it is animated.
|
||||
AISyncServer::client_list_t const& clients = server->getClients();
|
||||
for (AISyncServer::client_list_t::const_iterator client = clients.begin(); client != clients.end(); ++client)
|
||||
{
|
||||
LLMotion* motion = dynamic_cast<LLMotion*>(client->mClientPtr);
|
||||
if (!motion)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
LLMotionController* controller = motion->getController();
|
||||
if (controller == this)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (visible_after)
|
||||
{
|
||||
// Us becoming visible means that all synchronized avatars need to be animated again too.
|
||||
controller->setHaveVisibleSyncedMotions();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Us becoming hidden means that all synchronized avatars might stop animating.
|
||||
controller->refresh_hidden(); // It is extremely unlikely, but harmless, to call this twice on the same controller.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLMotionController::refresh_hidden(void)
|
||||
{
|
||||
mHaveVisibleSyncedMotions = !mHidden;
|
||||
|
||||
// Run over all motions.
|
||||
for (motion_list_t::iterator iter = mActiveMotions.begin(); iter != mActiveMotions.end(); ++iter)
|
||||
{
|
||||
LLMotion* motionp = *iter;
|
||||
AISyncServer* server = motionp->server();
|
||||
if (server && !server->never_synced() && motionp->isActive()) // Skip motions that aren't synchronized at all or that are not active.
|
||||
{
|
||||
bool visible_after = server->events_with_at_least_one_client_ready() & 4;
|
||||
if (visible_after) // Are there any synchronized motions (left) that ARE visible?
|
||||
{
|
||||
mHaveVisibleSyncedMotions = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLMotionController::pauseAllSyncedCharacters(std::vector<LLAnimPauseRequest>& avatar_pause_handles)
|
||||
{
|
||||
// Run over all motions.
|
||||
for (motion_list_t::iterator iter = mActiveMotions.begin(); iter != mActiveMotions.end(); ++iter)
|
||||
{
|
||||
LLMotion* motionp = *iter;
|
||||
AISyncServer* server = motionp->server();
|
||||
if (server && !server->never_synced() && motionp->isActive()) // Skip motions that aren't synchronized at all or that are not active.
|
||||
{
|
||||
// Run over all clients of the found servers.
|
||||
AISyncServer::client_list_t const& clients = server->getClients();
|
||||
for (AISyncServer::client_list_t::const_iterator client = clients.begin(); client != clients.end(); ++client)
|
||||
{
|
||||
LLMotion* motion = dynamic_cast<LLMotion*>(client->mClientPtr);
|
||||
if (!motion)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
LLMotionController* controller = motion->getController();
|
||||
if (controller == this)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
controller->requestPause(avatar_pause_handles);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLMotionController::requestPause(std::vector<LLAnimPauseRequest>& avatar_pause_handles)
|
||||
{
|
||||
if (mCharacter)
|
||||
{
|
||||
mCharacter->requestPause(avatar_pause_handles);
|
||||
}
|
||||
}
|
||||
|
||||
//</singu>
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// pause()
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -51,11 +51,14 @@
|
||||
// This is necessary because llcharacter.h includes this file.
|
||||
//-----------------------------------------------------------------------------
|
||||
class LLCharacter;
|
||||
class LLMotionController;
|
||||
class LLPauseRequestHandle;
|
||||
typedef LLPointer<LLPauseRequestHandle> LLAnimPauseRequest;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLMotionRegistry
|
||||
//-----------------------------------------------------------------------------
|
||||
typedef LLMotion*(*LLMotionConstructor)(const LLUUID &id);
|
||||
typedef LLMotion* (*LLMotionConstructor)(LLUUID const& id, LLMotionController*);
|
||||
|
||||
class LLMotionRegistry
|
||||
{
|
||||
@@ -72,7 +75,7 @@ public:
|
||||
|
||||
// creates a new instance of a named motion
|
||||
// returns NULL motion is not registered
|
||||
LLMotion *createMotion( const LLUUID &id );
|
||||
LLMotion* createMotion(LLUUID const& id, LLMotionController* controller);
|
||||
|
||||
// initialization of motion failed, don't try to create this motion again
|
||||
void markBad( const LLUUID& id );
|
||||
@@ -115,7 +118,6 @@ public:
|
||||
|
||||
// unregisters a motion with the controller
|
||||
// (actually just forwards call to motion registry)
|
||||
// returns true if successfull
|
||||
void removeMotion( const LLUUID& id );
|
||||
|
||||
// start motion
|
||||
@@ -150,10 +152,20 @@ public:
|
||||
//Flush is a liar.
|
||||
void deactivateAllMotions();
|
||||
|
||||
//<singu>
|
||||
void activated(U32 bit) { mActiveMask |= bit; }
|
||||
void deactivated(U32 bit) { mActiveMask &= ~bit; }
|
||||
bool isactive(U32 bit) const { return (mActiveMask & bit) != 0; }
|
||||
//</singu>
|
||||
|
||||
// pause and continue all motions
|
||||
void pauseAllMotions();
|
||||
void unpauseAllMotions();
|
||||
BOOL isPaused() const { return mPaused; }
|
||||
//<singu>
|
||||
void requestPause(std::vector<LLAnimPauseRequest>& avatar_pause_handles);
|
||||
void pauseAllSyncedCharacters(std::vector<LLAnimPauseRequest>& avatar_pause_handles);
|
||||
//</singu>
|
||||
|
||||
void setTimeStep(F32 step);
|
||||
|
||||
@@ -180,7 +192,10 @@ protected:
|
||||
// internal operations act on motion instances directly
|
||||
// as there can be duplicate motions per id during blending overlap
|
||||
void deleteAllMotions();
|
||||
// singu: LLMotion needs access to activateMotionInstance.
|
||||
public:
|
||||
BOOL activateMotionInstance(LLMotion *motion, F32 time);
|
||||
protected:
|
||||
BOOL deactivateMotionInstance(LLMotion *motion);
|
||||
void deprecateMotionInstance(LLMotion* motion);
|
||||
BOOL stopMotionInstance(LLMotion *motion, BOOL stop_imemdiate);
|
||||
@@ -205,10 +220,13 @@ protected:
|
||||
// Life cycle of an animation:
|
||||
//
|
||||
// Animations are instantiated and immediately put in the mAllMotions map for their entire lifetime.
|
||||
// Singu note: that is not true, they are moved to mDeprecatedMotions (often) for the last part of their lifetime.
|
||||
// If the animations depend on any asset data, the appropriate data is fetched from the data server,
|
||||
// and the animation is put on the mLoadingMotions list.
|
||||
// Once an animations is loaded, it will be initialized and put on the mLoadedMotions list.
|
||||
// Any animation that is currently playing also sits in the mActiveMotions list.
|
||||
// Singu note: animations are only put in mDeprecatedMotions if and while they are playing,
|
||||
// therefore animations in mDeprecatedMotions will be (must be) active and in mActiveMotions.
|
||||
|
||||
typedef std::map<LLUUID, LLMotion*> motion_map_t;
|
||||
motion_map_t mAllMotions;
|
||||
@@ -217,7 +235,13 @@ protected:
|
||||
motion_set_t mLoadedMotions;
|
||||
motion_list_t mActiveMotions;
|
||||
motion_set_t mDeprecatedMotions;
|
||||
|
||||
|
||||
//<singu>
|
||||
U32 mActiveMask;
|
||||
int mDisableSyncing; // Set while LLMotion::onActivate (and onDeactivate) are called for this controller.
|
||||
bool mHidden; // The value of the last call to hidden().
|
||||
bool mHaveVisibleSyncedMotions; // Set when we are synchronized with one or more motions of a controller that is not hidden.
|
||||
//</singu>
|
||||
LLFrameTimer mTimer;
|
||||
F32 mPrevTimerElapsed;
|
||||
F32 mAnimTime;
|
||||
@@ -230,6 +254,26 @@ protected:
|
||||
F32 mLastInterp;
|
||||
|
||||
U8 mJointSignature[2][LL_CHARACTER_MAX_JOINTS];
|
||||
|
||||
//<singu>
|
||||
public:
|
||||
// Internal administration for AISync.
|
||||
void disable_syncing(void) { mDisableSyncing += 100; }
|
||||
void enable_syncing(void) { mDisableSyncing -= 100; }
|
||||
bool syncing_disabled(void) const { return mDisableSyncing >= 100; }
|
||||
|
||||
// Accessors needed for synchronization.
|
||||
F32 getAnimTime(void) const { return mAnimTime; }
|
||||
bool isHidden(void) const { return mHidden; }
|
||||
|
||||
// Called often. Should return false if we still need to keep updating our motions even if we're not visible.
|
||||
bool hidden(bool not_visible) { if (mHidden != not_visible) toggle_hidden(); return !mHaveVisibleSyncedMotions; }
|
||||
|
||||
private:
|
||||
void toggle_hidden(void);
|
||||
void refresh_hidden(void);
|
||||
void setHaveVisibleSyncedMotions(void) { mHaveVisibleSyncedMotions = true; }
|
||||
//</singu>
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -52,7 +52,7 @@ const F32 TORSO_ROT_FRACTION = 0.5f;
|
||||
// LLTargetingMotion()
|
||||
// Class Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
LLTargetingMotion::LLTargetingMotion(const LLUUID &id) : LLMotion(id)
|
||||
LLTargetingMotion::LLTargetingMotion(LLUUID const& id, LLMotionController* controller) : AIMaskedMotion(id, controller, ANIM_AGENT_TARGET)
|
||||
{
|
||||
mCharacter = NULL;
|
||||
mName = "targeting";
|
||||
@@ -99,14 +99,6 @@ LLMotion::LLMotionInitStatus LLTargetingMotion::onInitialize(LLCharacter *charac
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLTargetingMotion::onActivate()
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL LLTargetingMotion::onActivate()
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLTargetingMotion::onUpdate()
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -166,12 +158,4 @@ BOOL LLTargetingMotion::onUpdate(F32 time, U8* joint_mask)
|
||||
return result;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLTargetingMotion::onDeactivate()
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLTargetingMotion::onDeactivate()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// End
|
||||
|
||||
@@ -48,11 +48,11 @@
|
||||
// class LLTargetingMotion
|
||||
//-----------------------------------------------------------------------------
|
||||
class LLTargetingMotion :
|
||||
public LLMotion
|
||||
public AIMaskedMotion
|
||||
{
|
||||
public:
|
||||
// Constructor
|
||||
LLTargetingMotion(const LLUUID &id);
|
||||
LLTargetingMotion(LLUUID const& id, LLMotionController* controller);
|
||||
|
||||
// Destructor
|
||||
virtual ~LLTargetingMotion();
|
||||
@@ -64,7 +64,7 @@ public:
|
||||
|
||||
// static constructor
|
||||
// all subclasses must implement such a function and register it
|
||||
static LLMotion *create(const LLUUID &id) { return new LLTargetingMotion(id); }
|
||||
static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLTargetingMotion(id, controller); }
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------------------
|
||||
@@ -96,19 +96,11 @@ public:
|
||||
// must return true to indicate success and be available for activation
|
||||
virtual LLMotionInitStatus onInitialize(LLCharacter *character);
|
||||
|
||||
// called when a motion is activated
|
||||
// must return TRUE to indicate success, or else
|
||||
// it will be deactivated
|
||||
virtual BOOL onActivate();
|
||||
|
||||
// called per time step
|
||||
// must return TRUE while it is active, and
|
||||
// must return FALSE when the motion is completed.
|
||||
virtual BOOL onUpdate(F32 time, U8* joint_mask);
|
||||
|
||||
// called when a motion is deactivated
|
||||
virtual void onDeactivate();
|
||||
|
||||
public:
|
||||
|
||||
LLCharacter *mCharacter;
|
||||
|
||||
@@ -20,6 +20,7 @@ set(llcommon_SOURCE_FILES
|
||||
aialert.cpp
|
||||
aifile.cpp
|
||||
aiframetimer.cpp
|
||||
aisyncclient.cpp
|
||||
aithreadid.cpp
|
||||
imageids.cpp
|
||||
indra_constants.cpp
|
||||
@@ -59,7 +60,6 @@ set(llcommon_SOURCE_FILES
|
||||
llformat.cpp
|
||||
llframetimer.cpp
|
||||
llheartbeat.cpp
|
||||
llindraconfigfile.cpp
|
||||
llinitparam.cpp
|
||||
llinstancetracker.cpp
|
||||
llliveappconfig.cpp
|
||||
@@ -112,6 +112,7 @@ set(llcommon_HEADER_FILES
|
||||
aifile.h
|
||||
aiframetimer.h
|
||||
airecursive.h
|
||||
aisyncclient.h
|
||||
aithreadid.h
|
||||
aithreadsafe.h
|
||||
bitpack.h
|
||||
@@ -184,7 +185,6 @@ set(llcommon_HEADER_FILES
|
||||
llheartbeat.h
|
||||
llhttpstatuscodes.h
|
||||
llindexedqueue.h
|
||||
llindraconfigfile.h
|
||||
llinitparam.h
|
||||
llinstancetracker.h
|
||||
llkeythrottle.h
|
||||
|
||||
698
indra/llcommon/aisyncclient.cpp
Normal file
698
indra/llcommon/aisyncclient.cpp
Normal file
@@ -0,0 +1,698 @@
|
||||
/**
|
||||
* @file aisyncclient.cpp
|
||||
*
|
||||
* Copyright (c) 2013, Aleric Inglewood.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution.
|
||||
*
|
||||
* CHANGELOG
|
||||
* and additional copyright holders.
|
||||
*
|
||||
* 13/12/2013
|
||||
* - Initial version, written by Aleric Inglewood @ SL
|
||||
*/
|
||||
|
||||
/*
|
||||
* AISyncClient : the base class of a client object (LLMotion) that needs to be informed
|
||||
* of the state of other such objects and/or to poll a server object about the state of
|
||||
* other such objects, in order to be and stay synchronized with those other objects.
|
||||
* In the case of an LLMotion (animation), all clients would be started and stopped at
|
||||
* the same time, as long as they are part of the same synchronization group (AISyncServer).
|
||||
*
|
||||
* AISyncKey: object that determines what synchronization group a client belongs to.
|
||||
* When a new client is created, a new AISyncKey is created too, using information from
|
||||
* the client, the current frame number and the current frame time. If two AISyncKey
|
||||
* compare equal, using operator==(AISyncKey const& key1, AISyncKey const& key2),
|
||||
* then the clients that created them need to be synchronized.
|
||||
*
|
||||
* AISyncServer: object that represents a group of clients that need to be synchronized:
|
||||
* it's a wrapper around a std::list<AISyncClientData> with pointers to all the clients
|
||||
* that need to be synchronized. It also stores the AISyncKey of the first (oldest) client
|
||||
* that was added. Clients with keys that compare equal to that will be added.
|
||||
* If a client is added with a synckeytype_t that is larger then it always replaces
|
||||
* the existing key however.
|
||||
*
|
||||
* AISyncServerMap: A wrapper around std::list<boost::intrusive_ptr<AISyncServer> >
|
||||
* that stores pointers to all currently existing AISyncServer objects. New entries
|
||||
* are added at the end, so the oldest key is at the front.
|
||||
*
|
||||
* AISyncServerMap list + - - - - - - + - - - - - - + ... The AISyncServerMap is
|
||||
* | | | a list with refcounted
|
||||
* V V V pointers to AISyncServers.
|
||||
* AISyncClient +--> AISyncServer
|
||||
* | <--- list key ---> AISyncKey Each AISyncServer is a
|
||||
* DerivedClient . list of normal pointers
|
||||
* . AISyncClients and one
|
||||
* <--- . pointer to a AISyncKey.
|
||||
* Each AISyncClient is the
|
||||
* base class of a DerivedClient
|
||||
* and pointers back to the
|
||||
* server with a refcounted
|
||||
* pointer.
|
||||
*
|
||||
* A new client is passed to the AISyncServerMap to be stored in a new or existing AISyncServer
|
||||
* object, using the key that the client produces. A boost::intrusive_ptr<AISyncServer> member
|
||||
* of the client is set to point to this server.
|
||||
*
|
||||
* The lifetime of the server objects is determined by the intrusive_ptr objects that
|
||||
* point to it: all the clients (which have an externally determined lifetime) and one
|
||||
* pointer in the AISyncServerMap. However, regularly a check is done on all servers in
|
||||
* the list to find expired servers: objects with keys older than two frames and older
|
||||
* than 0.1 seconds; if such a server is found and it has zero or one client, then the
|
||||
* client is unregistered and the pointer (and thus the server) removed from the
|
||||
* AISyncServerMap. If it has two or more clients then the entry is kept until both
|
||||
* clients are removed, which therefore can only be detected in intrusive_ptr_release
|
||||
* which only has access to the server object. The server then is removed from the list
|
||||
* by searching through it for the pointer to the server.
|
||||
*/
|
||||
|
||||
#include "sys.h"
|
||||
#include "aisyncclient.h"
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
#include "debug.h"
|
||||
|
||||
bool operator==(AISyncKey const& key1, AISyncKey const& key2)
|
||||
{
|
||||
// Test if these keys match based on time.
|
||||
if (std::abs((S32)(key1.mStartFrameCount - key2.mStartFrameCount)) > 1 &&
|
||||
std::abs(key1.mFrameTimer.getStartTime() - key2.mFrameTimer.getStartTime()) >= sSyncKeyExpirationTime)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Time matches, let the derived classes determine if they also match otherwise.
|
||||
return key1.equals(key2);
|
||||
}
|
||||
|
||||
#ifdef CWDEBUG
|
||||
struct SyncEventSet {
|
||||
synceventset_t mBits;
|
||||
SyncEventSet(synceventset_t bits) : mBits(bits) { }
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, SyncEventSet const& ses)
|
||||
{
|
||||
for (int b = sizeof(ses.mBits) * 8 - 1; b >= 0; --b)
|
||||
{
|
||||
int m = 1 << b;
|
||||
os << ((ses.mBits & m) ? '1' : '0');
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
void print_clients(AISyncServer const* server, AISyncServer::client_list_t const& client_list)
|
||||
{
|
||||
Dout(dc::notice, "Clients of server " << server << ": ");
|
||||
for (AISyncServer::client_list_t::const_iterator iter = client_list.begin(); iter != client_list.end(); ++ iter)
|
||||
{
|
||||
llassert(iter->mClientPtr->mReadyEvents == iter->mReadyEvents);
|
||||
Dout(dc::notice, "-> " << iter->mClientPtr << " : " << SyncEventSet(iter->mReadyEvents));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void AISyncServerMap::register_client(AISyncClient* client, AISyncKey* new_key)
|
||||
{
|
||||
// client must always be a new client that has to be stored somewhere.
|
||||
llassert(client->server() == NULL);
|
||||
// Obviously the client can't be ready for anything when it isn't registered yet.
|
||||
llassert(!client->mReadyEvents);
|
||||
|
||||
// Find if a server with this key already exists.
|
||||
AISyncServer* server = NULL;
|
||||
for (server_list_t::iterator iter = mServers.begin(); iter != mServers.end();)
|
||||
{
|
||||
boost::intrusive_ptr<AISyncServer>& server_ptr = *iter++; // Immediately increment iter because the call to unregister_last_client will erase it.
|
||||
AISyncKey const& server_key(server_ptr->key());
|
||||
if (server_key.is_older_than(*new_key)) // This means that the server key is expired: a new key will never match.
|
||||
{
|
||||
if (server_ptr->never_synced()) // This means that it contains one or zero clients and will never contain more.
|
||||
{
|
||||
// Get rid of this server.
|
||||
server_ptr->unregister_last_client(); // This will cause the server to be deleted, and erased from mServers.
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (*new_key == server_key)
|
||||
{
|
||||
server = server_ptr.get();
|
||||
// mServers stores new servers in strict order of the creation time of the keys,
|
||||
// so once we find a server with a key that is equal, none of the remaining servers
|
||||
// will have expired if they were never synced and we're done with the loop.
|
||||
// Servers that synced might have been added later, but we don't unregister
|
||||
// clients from those anyway because their sync partner might still show up.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (server)
|
||||
{
|
||||
// A server already exists.
|
||||
// Keep the oldest key, unless this new key has a synckeytype_t that is larger!
|
||||
if (new_key->getkeytype() > server->key().getkeytype())
|
||||
{
|
||||
server->swapkey(new_key);
|
||||
}
|
||||
delete new_key;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create a new server for this client. Transfers the ownership of the key allocation to the server.
|
||||
server = new AISyncServer(new_key);
|
||||
// Add it to mServers, before the last server that is younger then the new key.
|
||||
server_list_t::iterator where = mServers.end(); // Insert the new server before 'where',
|
||||
server_list_t::iterator new_where = where;
|
||||
while (where != mServers.begin()) // unless there exists a server before that
|
||||
{
|
||||
--new_where;
|
||||
if (new_key->getCreationTime() > (*new_where)->key().getCreationTime()) // and the new key is not younger then that,
|
||||
{
|
||||
break;
|
||||
}
|
||||
where = new_where; // then insert it before that element (etc).
|
||||
}
|
||||
// This method causes a single call to intrusive_ptr_add_ref and none to intrusive_ptr_release.
|
||||
server_ptr_t server_ptr = server;
|
||||
mServers.insert(where, server_ptr_t())->swap(server_ptr);
|
||||
}
|
||||
|
||||
// Add the client to the server.
|
||||
server->add(client);
|
||||
}
|
||||
|
||||
#ifdef SYNC_TESTSUITE
|
||||
void AISyncServer::sanity_check(void) const
|
||||
{
|
||||
synceventset_t ready_events = (synceventset_t)-1; // All clients are ready.
|
||||
client_list_t::const_iterator client_iter = mClients.begin();
|
||||
while (client_iter != mClients.end())
|
||||
{
|
||||
ready_events &= client_iter->mReadyEvents;
|
||||
++client_iter;
|
||||
}
|
||||
synceventset_t pending_events = 0; // At least one client is ready.
|
||||
client_iter = mClients.begin();
|
||||
while (client_iter != mClients.end())
|
||||
{
|
||||
pending_events |= client_iter->mReadyEvents;
|
||||
++client_iter;
|
||||
}
|
||||
llassert(ready_events == mReadyEvents);
|
||||
llassert(pending_events == mPendingEvents);
|
||||
}
|
||||
#endif
|
||||
|
||||
void AISyncServer::add(AISyncClient* client)
|
||||
{
|
||||
#ifdef SYNC_TESTSUITE
|
||||
sanity_check();
|
||||
#endif
|
||||
|
||||
// The client can't already be ready when it isn't even added to a server yet.
|
||||
llassert(!client->mReadyEvents);
|
||||
synceventset_t old_ready_events = mReadyEvents;
|
||||
// A new client is not ready for anything.
|
||||
mReadyEvents = 0;
|
||||
// Set mSynchronized if after adding client we'll have more than 1 client (that prevents the
|
||||
// server from being deleted unless all clients are actually destructed or explicitly unregistered).
|
||||
if (!mSynchronized && mClients.size() > 0)
|
||||
{
|
||||
mSynchronized = true;
|
||||
}
|
||||
// Trigger the existing clients to be not-ready anymore (if we were before).
|
||||
trigger(old_ready_events);
|
||||
// Only then add the new client (so that it didn't get not-ready trigger).
|
||||
mClients.push_back(client);
|
||||
client->mServer = this;
|
||||
|
||||
#ifdef SYNC_TESTSUITE
|
||||
sanity_check();
|
||||
#endif
|
||||
}
|
||||
|
||||
void AISyncServer::remove(AISyncClient* client)
|
||||
{
|
||||
#ifdef SYNC_TESTSUITE
|
||||
sanity_check();
|
||||
#endif
|
||||
|
||||
client_list_t::iterator client_iter = mClients.begin();
|
||||
synceventset_t remaining_ready_events = (synceventset_t)-1; // All clients are ready.
|
||||
synceventset_t remaining_pending_events = 0; // At least one client is ready (waiting for the other clients thus).
|
||||
client_list_t::iterator found_client = mClients.end();
|
||||
while (client_iter != mClients.end())
|
||||
{
|
||||
if (client_iter->mClientPtr == client)
|
||||
{
|
||||
found_client = client_iter;
|
||||
}
|
||||
else
|
||||
{
|
||||
remaining_ready_events &= client_iter->mReadyEvents;
|
||||
remaining_pending_events |= client_iter->mReadyEvents;
|
||||
}
|
||||
++client_iter;
|
||||
}
|
||||
llassert(found_client != mClients.end());
|
||||
// This must be the same as client->mReadyEvents.
|
||||
llassert(found_client->mReadyEvents == client->mReadyEvents);
|
||||
mClients.erase(found_client);
|
||||
synceventset_t old_ready_events = mReadyEvents;
|
||||
mReadyEvents = remaining_ready_events;
|
||||
mPendingEvents = remaining_pending_events;
|
||||
trigger(old_ready_events);
|
||||
client->mServer.reset();
|
||||
client->deregistered();
|
||||
|
||||
#ifdef SYNC_TESTSUITE
|
||||
sanity_check();
|
||||
#endif
|
||||
}
|
||||
|
||||
void AISyncServer::unregister_last_client(void)
|
||||
{
|
||||
#ifdef SYNC_TESTSUITE
|
||||
sanity_check();
|
||||
#endif
|
||||
|
||||
// This function may only be called for servers with exactly one client that was never (potentially) synchronized.
|
||||
llassert(!mSynchronized && mClients.size() == 1);
|
||||
AISyncClient* client = mClients.begin()->mClientPtr;
|
||||
mClients.clear();
|
||||
client->mServer.reset();
|
||||
llassert(mReadyEvents == client->mReadyEvents);
|
||||
llassert(mPendingEvents == mReadyEvents);
|
||||
// No need to update mReadyEvents/mPendingEvents because the server is going to be deleted,
|
||||
// but inform the client that is no longer has a server.
|
||||
client->deregistered();
|
||||
|
||||
#ifdef SYNC_TESTSUITE
|
||||
sanity_check();
|
||||
#endif
|
||||
}
|
||||
|
||||
void AISyncServer::trigger(synceventset_t old_ready_events)
|
||||
{
|
||||
// If event 1 changed, informat all clients about it.
|
||||
if (((old_ready_events ^ mReadyEvents) & 1))
|
||||
{
|
||||
for (client_list_t::iterator client_iter = mClients.begin(); client_iter != mClients.end(); ++client_iter)
|
||||
{
|
||||
if ((mReadyEvents & 1))
|
||||
{
|
||||
client_iter->mClientPtr->event1_ready();
|
||||
}
|
||||
else
|
||||
{
|
||||
client_iter->mClientPtr->event1_not_ready();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AISyncServer::ready(synceventset_t events, synceventset_t yesno, AISyncClient* client)
|
||||
{
|
||||
#ifdef SYNC_TESTSUITE
|
||||
sanity_check();
|
||||
#endif
|
||||
|
||||
synceventset_t added_events = events & yesno;
|
||||
synceventset_t removed_events = events & ~yesno;
|
||||
|
||||
// Run over all clients to find the client and calculate the current state.
|
||||
synceventset_t remaining_ready_events = (synceventset_t)-1; // All clients are ready.
|
||||
synceventset_t remaining_pending_events = 0; // At least one client is ready (waiting for the other clients thus).
|
||||
client_list_t::iterator found_client = mClients.end();
|
||||
for (client_list_t::iterator client_iter = mClients.begin(); client_iter != mClients.end(); ++client_iter)
|
||||
{
|
||||
if (client_iter->mClientPtr == client)
|
||||
{
|
||||
found_client = client_iter;
|
||||
}
|
||||
else
|
||||
{
|
||||
remaining_ready_events &= client_iter->mReadyEvents;
|
||||
remaining_pending_events |= client_iter->mReadyEvents;
|
||||
}
|
||||
}
|
||||
|
||||
llassert(mReadyEvents == (remaining_ready_events & found_client->mReadyEvents));
|
||||
llassert(mPendingEvents == (remaining_pending_events | found_client->mReadyEvents));
|
||||
|
||||
found_client->mReadyEvents &= ~removed_events;
|
||||
found_client->mReadyEvents |= added_events;
|
||||
#ifdef SHOW_ASSERT
|
||||
client->mReadyEvents = found_client->mReadyEvents;
|
||||
#endif
|
||||
|
||||
synceventset_t old_ready_events = mReadyEvents;
|
||||
|
||||
mReadyEvents = remaining_ready_events & found_client->mReadyEvents;
|
||||
mPendingEvents = remaining_pending_events | found_client->mReadyEvents;
|
||||
|
||||
trigger(old_ready_events);
|
||||
|
||||
#ifdef SYNC_TESTSUITE
|
||||
sanity_check();
|
||||
#endif
|
||||
}
|
||||
|
||||
void intrusive_ptr_add_ref(AISyncServer* server)
|
||||
{
|
||||
server->mRefCount++;
|
||||
}
|
||||
|
||||
void intrusive_ptr_release(AISyncServer* server)
|
||||
{
|
||||
llassert(server->mRefCount > 0);
|
||||
server->mRefCount--;
|
||||
if (server->mRefCount == 0)
|
||||
{
|
||||
delete server;
|
||||
}
|
||||
else if (server->mRefCount == 1)
|
||||
{
|
||||
// If the the last pointer to this server is in the the AISyncServerMap, then delete that too.
|
||||
AISyncServerMap::instance().remove_server(server);
|
||||
}
|
||||
}
|
||||
|
||||
void AISyncServerMap::remove_server(AISyncServer* server)
|
||||
{
|
||||
for (server_list_t::iterator iter = mServers.begin(); iter != mServers.end(); ++iter)
|
||||
{
|
||||
if (server == iter->get())
|
||||
{
|
||||
mServers.erase(iter); // This causes server to be deleted too.
|
||||
return;
|
||||
}
|
||||
}
|
||||
// The server must be found: this function is only called from intrusive_ptr_release for servers
|
||||
// with just a single server_ptr_t left, which must be the one in mServers (otherwise it wasn't
|
||||
// even registered properly!)
|
||||
llassert(false);
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
// SYNC_TESTSUITE
|
||||
//=============================================================================
|
||||
|
||||
#ifdef SYNC_TESTSUITE
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <cstdlib>
|
||||
#include <boost/io/ios_state.hpp>
|
||||
|
||||
//static
|
||||
U32 LLFrameTimer::sFrameCount;
|
||||
|
||||
double innerloop_count = 0;
|
||||
|
||||
double LLFrameTimer::getCurrentTime()
|
||||
{
|
||||
return innerloop_count * 0.001;
|
||||
}
|
||||
|
||||
template<synckeytype_t synckeytype>
|
||||
class TestsuiteKey : public AISyncKey
|
||||
{
|
||||
private:
|
||||
int mIndex;
|
||||
|
||||
public:
|
||||
TestsuiteKey(int index) : mIndex(index) { }
|
||||
|
||||
int getIndex(void) const { return mIndex; }
|
||||
|
||||
// Virtual functions of AISyncKey.
|
||||
public:
|
||||
/*virtual*/ synckeytype_t getkeytype(void) const
|
||||
{
|
||||
// Return a unique identifier for this class, where the low 8 bits represent the syncgroup.
|
||||
return synckeytype;
|
||||
}
|
||||
|
||||
/*virtual*/ bool equals(AISyncKey const& key) const
|
||||
{
|
||||
synckeytype_t const theotherkey = (synckeytype_t)(synckeytype ^ 0x100);
|
||||
switch (key.getkeytype())
|
||||
{
|
||||
case synckeytype:
|
||||
{
|
||||
// The other key is of the same type.
|
||||
TestsuiteKey<synckeytype> const& test_key = static_cast<TestsuiteKey<synckeytype> const&>(key);
|
||||
return (mIndex & 1) == (test_key.mIndex & 1);
|
||||
}
|
||||
case theotherkey:
|
||||
{
|
||||
TestsuiteKey<theotherkey> const& test_key = static_cast<TestsuiteKey<theotherkey> const&>(key);
|
||||
return (mIndex & 2) == (test_key.getIndex() & 2);
|
||||
}
|
||||
default:
|
||||
// The keys must be in the same syncgroup.
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template<synckeytype_t synckeytype>
|
||||
class TestsuiteClient : public AISyncClient
|
||||
{
|
||||
// AISyncClient events.
|
||||
protected:
|
||||
/*virtual*/ AISyncKey* createSyncKey(void) const
|
||||
{
|
||||
return new TestsuiteKey<synckeytype>(mIndex);
|
||||
}
|
||||
|
||||
private:
|
||||
int mIndex;
|
||||
bool mRequestedRegistered;
|
||||
synceventset_t mRequestedReady;
|
||||
bool mActualReady1;
|
||||
|
||||
public:
|
||||
TestsuiteClient() : mIndex(-1), mRequestedRegistered(false), mRequestedReady(0), mActualReady1(false) { }
|
||||
~TestsuiteClient() { if (is_registered()) this->ready(mRequestedReady, (synceventset_t)0); }
|
||||
|
||||
void setIndex(int index) { mIndex = index; }
|
||||
|
||||
protected:
|
||||
/*virtual*/ void event1_ready(void)
|
||||
{
|
||||
#ifdef DEBUG_SYNCOUTPUT
|
||||
Dout(dc::notice, "Calling TestsuiteClient<" << synckeytype << ">::event1_ready() (mIndex = " << mIndex << ") of client " << this);
|
||||
#endif
|
||||
llassert(!mActualReady1);
|
||||
mActualReady1 = true;
|
||||
}
|
||||
|
||||
/*virtual*/ void event1_not_ready(void)
|
||||
{
|
||||
#ifdef DEBUG_SYNCOUTPUT
|
||||
Dout(dc::notice, "Calling TestsuiteClient<" << synckeytype << ">::event1_not_ready() (mIndex = " << mIndex << ") of client " << this);
|
||||
#endif
|
||||
llassert(mActualReady1);
|
||||
mActualReady1 = false;
|
||||
}
|
||||
|
||||
// This is called when the server expired and we're the only client on it.
|
||||
/*virtual*/ void deregistered(void)
|
||||
{
|
||||
#ifdef DEBUG_SYNCOUTPUT
|
||||
DoutEntering(dc::notice, "TestsuiteClient<" << synckeytype << ">::deregistered(), with this = " << this);
|
||||
#endif
|
||||
mRequestedRegistered = false;
|
||||
mRequestedReady = 0;
|
||||
mActualReady1 = false;
|
||||
this->mReadyEvents = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
bool is_registered(void) const { return this->server(); }
|
||||
|
||||
public:
|
||||
void change_state(unsigned long r);
|
||||
bool getRequestedRegistered(void) const { return mRequestedRegistered; }
|
||||
synceventset_t getRequestedReady(void) const { return mRequestedReady; }
|
||||
};
|
||||
|
||||
TestsuiteClient<synckeytype_test1a>* client1ap;
|
||||
TestsuiteClient<synckeytype_test1b>* client1bp;
|
||||
TestsuiteClient<synckeytype_test2a>* client2ap;
|
||||
TestsuiteClient<synckeytype_test2b>* client2bp;
|
||||
|
||||
int const number_of_clients_per_syncgroup = 8;
|
||||
|
||||
template<synckeytype_t synckeytype>
|
||||
void TestsuiteClient<synckeytype>::change_state(unsigned long r)
|
||||
{
|
||||
bool change_registered = r & 1;
|
||||
r >>= 1;
|
||||
synceventset_t toggle_events = r & 15;
|
||||
r >>= 4;
|
||||
if (change_registered)
|
||||
{
|
||||
if (mRequestedRegistered && !mRequestedReady)
|
||||
{
|
||||
mRequestedRegistered = false;
|
||||
this->unregister_client();
|
||||
}
|
||||
}
|
||||
else if (toggle_events)
|
||||
{
|
||||
mRequestedReady ^= toggle_events;
|
||||
mRequestedRegistered = true;
|
||||
this->ready(toggle_events, mRequestedReady & toggle_events);
|
||||
}
|
||||
llassert(mRequestedRegistered == is_registered());
|
||||
AISyncServer* server = this->server();
|
||||
if (mRequestedRegistered)
|
||||
{
|
||||
synceventset_t all_ready = synceventset_t(-1);
|
||||
synceventset_t any_ready = 0;
|
||||
int nr = 0;
|
||||
for (int cl = 0; cl < number_of_clients_per_syncgroup; ++cl)
|
||||
{
|
||||
switch ((synckeytype & 0xff))
|
||||
{
|
||||
case syncgroup_test1:
|
||||
{
|
||||
if (client1ap[cl].server() == server)
|
||||
{
|
||||
if (client1ap[cl].getRequestedRegistered())
|
||||
{
|
||||
++nr;
|
||||
all_ready &= client1ap[cl].getRequestedReady();
|
||||
any_ready |= client1ap[cl].getRequestedReady();
|
||||
}
|
||||
}
|
||||
if (client1bp[cl].server() == server)
|
||||
{
|
||||
if (client1bp[cl].getRequestedRegistered())
|
||||
{
|
||||
++nr;
|
||||
all_ready &= client1bp[cl].getRequestedReady();
|
||||
any_ready |= client1bp[cl].getRequestedReady();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case syncgroup_test2:
|
||||
{
|
||||
if (client2ap[cl].server() == server)
|
||||
{
|
||||
if (client2ap[cl].getRequestedRegistered())
|
||||
{
|
||||
++nr;
|
||||
all_ready &= client2ap[cl].getRequestedReady();
|
||||
any_ready |= client2ap[cl].getRequestedReady();
|
||||
}
|
||||
}
|
||||
if (client2bp[cl].server() == server)
|
||||
{
|
||||
if (client2bp[cl].getRequestedRegistered())
|
||||
{
|
||||
++nr;
|
||||
all_ready &= client2bp[cl].getRequestedReady();
|
||||
any_ready |= client2bp[cl].getRequestedReady();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
llassert(nr == server->getClients().size());
|
||||
llassert(!!(all_ready & 1) == mActualReady1);
|
||||
llassert(this->server()->events_with_all_clients_ready() == all_ready);
|
||||
llassert(this->server()->events_with_at_least_one_client_ready() == any_ready);
|
||||
llassert(nr == 0 || (any_ready & all_ready) == all_ready);
|
||||
}
|
||||
llassert(mRequestedReady == this->mReadyEvents);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
Debug(libcw_do.on());
|
||||
Debug(dc::notice.on());
|
||||
Debug(libcw_do.set_ostream(&std::cout));
|
||||
Debug(list_channels_on(libcw_do));
|
||||
|
||||
unsigned short seed16v[3] = { 0x1234, 0xfedc, 0x7091 };
|
||||
|
||||
for (int k = 0;; ++k)
|
||||
{
|
||||
std::cout << "Loop: " << k << "; SEED: " << std::hex << seed16v[0] << ", " << seed16v[1] << ", " << seed16v[2] << std::dec << std::endl;
|
||||
++LLFrameTimer::sFrameCount;
|
||||
|
||||
seed48(seed16v);
|
||||
seed16v[0] = lrand48() & 0xffff;
|
||||
seed16v[1] = lrand48() & 0xffff;
|
||||
seed16v[2] = lrand48() & 0xffff;
|
||||
|
||||
TestsuiteClient<synckeytype_test1a> client1a[number_of_clients_per_syncgroup];
|
||||
TestsuiteClient<synckeytype_test1b> client1b[number_of_clients_per_syncgroup];
|
||||
TestsuiteClient<synckeytype_test2a> client2a[number_of_clients_per_syncgroup];
|
||||
TestsuiteClient<synckeytype_test2b> client2b[number_of_clients_per_syncgroup];
|
||||
client1ap = client1a;
|
||||
client1bp = client1b;
|
||||
client2ap = client2a;
|
||||
client2bp = client2b;
|
||||
|
||||
for (int i = 0; i < number_of_clients_per_syncgroup; ++i)
|
||||
{
|
||||
client1a[i].setIndex(i);
|
||||
client1b[i].setIndex(i);
|
||||
client2a[i].setIndex(i);
|
||||
client2b[i].setIndex(i);
|
||||
}
|
||||
|
||||
for (int j = 0; j < 1000000; ++j)
|
||||
{
|
||||
innerloop_count += 1;
|
||||
|
||||
#ifdef DEBUG_SYNCOUTPUT
|
||||
Dout(dc::notice, "Innerloop: " << j);
|
||||
#endif
|
||||
unsigned long r = lrand48();
|
||||
synckeytype_t keytype = (r & 1) ? ((r & 2) ? synckeytype_test1a : synckeytype_test1b) : ((r & 2) ? synckeytype_test2a : synckeytype_test2b);
|
||||
r >>= 2;
|
||||
int cl = (r & 255) % number_of_clients_per_syncgroup;
|
||||
r >>= 8;
|
||||
switch (keytype)
|
||||
{
|
||||
case synckeytype_test1a:
|
||||
client1a[cl].change_state(r);
|
||||
break;
|
||||
case synckeytype_test1b:
|
||||
client1b[cl].change_state(r);
|
||||
break;
|
||||
case synckeytype_test2a:
|
||||
client2a[cl].change_state(r);
|
||||
break;
|
||||
case synckeytype_test2b:
|
||||
client2b[cl].change_state(r);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
304
indra/llcommon/aisyncclient.h
Normal file
304
indra/llcommon/aisyncclient.h
Normal file
@@ -0,0 +1,304 @@
|
||||
/**
|
||||
* @file aisyncclient.h
|
||||
* @brief Declaration of AISyncClient.
|
||||
*
|
||||
* Copyright (c) 2013, Aleric Inglewood.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution.
|
||||
*
|
||||
* CHANGELOG
|
||||
* and additional copyright holders.
|
||||
*
|
||||
* 12/12/2013
|
||||
* Initial version, written by Aleric Inglewood @ SL
|
||||
*/
|
||||
|
||||
#ifndef AI_SYNC_CLIENT_H
|
||||
#define AI_SYNC_CLIENT_H
|
||||
|
||||
#ifdef SYNC_TESTSUITE
|
||||
/*
|
||||
* To compile the testsuite, run:
|
||||
*
|
||||
* cd indra/llcommon
|
||||
* g++ -O3 -DCWDEBUG -DSYNC_TESTSUITE -I. -I../cwdebug aisyncclient.cpp -lcwd
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <cassert>
|
||||
typedef uint32_t U32;
|
||||
typedef int32_t S32;
|
||||
typedef uint64_t U64;
|
||||
typedef float F32;
|
||||
typedef double F64;
|
||||
#define LL_COMMON_API
|
||||
#define SHOW_ASSERT
|
||||
#define ASSERT_ONLY_COMMA(...) , __VA_ARGS__
|
||||
#define llassert assert
|
||||
|
||||
struct LLFrameTimer
|
||||
{
|
||||
double mStartTime;
|
||||
double mExpiry;
|
||||
static double getCurrentTime(void);
|
||||
static U32 sFrameCount;
|
||||
static U32 getFrameCount() { return sFrameCount; }
|
||||
F64 getStartTime() const { return mStartTime; }
|
||||
void reset(double expiration) { mStartTime = getCurrentTime(); mExpiry = mStartTime + expiration; }
|
||||
bool hasExpired(void) const { return getCurrentTime() > mExpiry; }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct LLSingleton
|
||||
{
|
||||
static T sInstance;
|
||||
static T& instance(void) { return sInstance; }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
T LLSingleton<T>::sInstance;
|
||||
|
||||
#else // !SYNC_TESTSUITE
|
||||
#include "llsingleton.h"
|
||||
#include "llframetimer.h"
|
||||
#endif
|
||||
#include <list>
|
||||
#include <boost/intrusive_ptr.hpp>
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// Keys with a different syncgroup are never equal (so they are never synchronized).
|
||||
enum syncgroups
|
||||
{
|
||||
#ifdef SYNC_TESTSUITE
|
||||
syncgroup_test1,
|
||||
syncgroup_test2,
|
||||
#else
|
||||
syncgroup_motions, // Syncgroup used for animations.
|
||||
#endif
|
||||
syncgroup_size
|
||||
};
|
||||
|
||||
// Each key type must return a unique identifier that exists of its syncgroup (the least significant 8 bit) plus a few bit to make it unique (bit 9 and higher).
|
||||
enum synckeytype_t
|
||||
{
|
||||
#ifdef SYNC_TESTSUITE
|
||||
synckeytype_test1a = 0x000 + syncgroup_test1,
|
||||
synckeytype_test1b = 0x100 + syncgroup_test1,
|
||||
synckeytype_test2a = 0x000 + syncgroup_test2,
|
||||
synckeytype_test2b = 0x100 + syncgroup_test2,
|
||||
#else
|
||||
synckeytype_motion = syncgroup_motions // There is currently only one key type in the syncgroup_motions group: AISyncKeyMotion.
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef U32 synceventset_t; // A mask where each bit represents a ready state.
|
||||
|
||||
static F32 const sSyncKeyExpirationTime = 0.25; // In seconds.
|
||||
|
||||
class LL_COMMON_API AISyncKey
|
||||
{
|
||||
private:
|
||||
LLFrameTimer mFrameTimer; // This timer is started at the moment the sync key is created.
|
||||
U32 mStartFrameCount; // The frame count at which the timer was started.
|
||||
|
||||
public:
|
||||
// Constructor.
|
||||
AISyncKey(AISyncKey const* from_key) : mStartFrameCount(from_key ? from_key->mStartFrameCount : LLFrameTimer::getFrameCount())
|
||||
{
|
||||
if (from_key)
|
||||
{
|
||||
mFrameTimer.copy(from_key->mFrameTimer);
|
||||
}
|
||||
else
|
||||
{
|
||||
mFrameTimer.reset(sSyncKeyExpirationTime);
|
||||
}
|
||||
}
|
||||
|
||||
// Destructor.
|
||||
virtual ~AISyncKey() { }
|
||||
|
||||
// Return true if this key expired.
|
||||
bool expired(void) const
|
||||
{
|
||||
// The key has expired when sSyncKeyExpirationTime seconds have elapsed AND at least two frames have passed.
|
||||
return mFrameTimer.getFrameCount() > mStartFrameCount + 1 && mFrameTimer.hasExpired();
|
||||
}
|
||||
|
||||
// Returns true if this object and key would not compare equal based on time because this object is too old.
|
||||
bool is_older_than(AISyncKey const& key) const
|
||||
{
|
||||
return key.mStartFrameCount > mStartFrameCount + 1 && key.mFrameTimer.getStartTime() > mFrameTimer.getStartTime() + sSyncKeyExpirationTime;
|
||||
}
|
||||
|
||||
// Return the creation time of this key (in number of seconds since application start).
|
||||
F64 getCreationTime(void) const { return mFrameTimer.getStartTime(); }
|
||||
|
||||
// Returns true if the two keys match, meaning that they should be synchronized.
|
||||
friend bool operator==(AISyncKey const& key1, AISyncKey const& key2);
|
||||
|
||||
// Returns an ID that uniquely identifies the derived type.
|
||||
// Currently the only derived type is AISyncKeyMotion with ID synckeytype_motion.
|
||||
virtual synckeytype_t getkeytype(void) const = 0;
|
||||
|
||||
// Returns true if the data in the derived objects match, meaning that they should be synchronized.
|
||||
virtual bool equals(AISyncKey const& key) const = 0;
|
||||
};
|
||||
|
||||
// Forward declaration.
|
||||
class AISyncClient;
|
||||
class AISyncServer;
|
||||
LL_COMMON_API extern void intrusive_ptr_add_ref(AISyncServer* server);
|
||||
LL_COMMON_API extern void intrusive_ptr_release(AISyncServer* server);
|
||||
|
||||
struct LL_COMMON_API AISyncClientData
|
||||
{
|
||||
AISyncClient* mClientPtr;
|
||||
synceventset_t mReadyEvents;
|
||||
|
||||
AISyncClientData(AISyncClient* client) : mClientPtr(client), mReadyEvents(0) { }
|
||||
};
|
||||
|
||||
class LL_COMMON_API AISyncServer
|
||||
{
|
||||
public:
|
||||
typedef std::list<AISyncClientData> client_list_t;
|
||||
|
||||
private:
|
||||
int mRefCount; // Number of boost::intrusive_ptr objects pointing to this object.
|
||||
AISyncKey* mKey; // The key of the first client that was added.
|
||||
client_list_t mClients; // A list with pointers to all registered clients.
|
||||
bool mSynchronized; // Set when a server gets more than one client, and not reset anymore after that.
|
||||
synceventset_t mReadyEvents; // 0xFFFFFFFF bitwise-AND-ed with all clients.
|
||||
synceventset_t mPendingEvents; // The bitwise-OR of all clients.
|
||||
|
||||
public:
|
||||
AISyncServer(AISyncKey* key) : mRefCount(0), mKey(key), mSynchronized(false), mReadyEvents((synceventset_t)-1), mPendingEvents(0) { }
|
||||
~AISyncServer() { delete mKey; }
|
||||
|
||||
// Add a new client to this server.
|
||||
void add(AISyncClient* client);
|
||||
|
||||
// Remove a client from this server.
|
||||
void remove(AISyncClient* client);
|
||||
|
||||
// Return the key associated to this server (which is the key produced by the first client of the largest synckeytype_t that was added).
|
||||
AISyncKey const& key(void) const { return *mKey; }
|
||||
// Replace they key with another key (of larger synckeytype_t).
|
||||
void swapkey(AISyncKey*& key_ptr) { AISyncKey* tmp = key_ptr; key_ptr = mKey; mKey = tmp; }
|
||||
|
||||
// Returns true if this server never had more than one client.
|
||||
bool never_synced(void) const { return !mSynchronized; }
|
||||
|
||||
// Set readiness of all events at once.
|
||||
void ready(synceventset_t events, synceventset_t yesno, AISyncClient* client);
|
||||
|
||||
// Unregister the (only) client because it's own its own and will never need synchronization.
|
||||
void unregister_last_client(void);
|
||||
|
||||
// Return the events that all clients for.
|
||||
synceventset_t events_with_all_clients_ready(void) const { return mReadyEvents; }
|
||||
|
||||
// Return events that at least one client is ready for.
|
||||
synceventset_t events_with_at_least_one_client_ready(void) const { return mPendingEvents; }
|
||||
|
||||
// Return a list of all registered clients.
|
||||
client_list_t const& getClients(void) const { return mClients; }
|
||||
|
||||
private:
|
||||
// Call event1_ready() or event1_not_ready() on all clients if the least significant bit of mReadyEvents changed.
|
||||
void trigger(synceventset_t old_ready_events);
|
||||
|
||||
#ifdef SYNC_TESTSUITE
|
||||
void sanity_check(void) const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
friend LL_COMMON_API void intrusive_ptr_add_ref(AISyncServer* server);
|
||||
friend LL_COMMON_API void intrusive_ptr_release(AISyncServer* server);
|
||||
};
|
||||
|
||||
class LL_COMMON_API AISyncServerMap : public LLSingleton<AISyncServerMap>
|
||||
{
|
||||
public:
|
||||
typedef boost::intrusive_ptr<AISyncServer> server_ptr_t; // The type of a (stored) pointer to the server objects.
|
||||
typedef std::list<server_ptr_t> server_list_t; // The type of the list with pointers to the server objects.
|
||||
|
||||
private:
|
||||
server_list_t mServers; // A list with pointers to all server objects.
|
||||
|
||||
public:
|
||||
// Find or create a server object that the client belongs to and store the client in it.
|
||||
// If a new server is created, it is stored in mServers.
|
||||
void register_client(AISyncClient* client, AISyncKey* new_key);
|
||||
|
||||
private:
|
||||
friend LL_COMMON_API void intrusive_ptr_release(AISyncServer* server);
|
||||
// Remove a server from the map, only called by intrusive_ptr_release when there is one pointer left;
|
||||
// therefore, the server should not have any clients.
|
||||
void remove_server(AISyncServer* server);
|
||||
};
|
||||
|
||||
class LL_COMMON_API AISyncClient
|
||||
{
|
||||
private:
|
||||
friend class AISyncServer;
|
||||
boost::intrusive_ptr<AISyncServer> mServer; // The server this client was registered with, or NULL when unregistered.
|
||||
|
||||
public:
|
||||
#ifdef SHOW_ASSERT
|
||||
synceventset_t mReadyEvents;
|
||||
AISyncClient(void) : mReadyEvents(0) { }
|
||||
#endif
|
||||
virtual ~AISyncClient() { llassert(!mServer); /* If this fails then you need to add unregister_client() to the top of the destructor of the derived class that implements deregistered(). */ }
|
||||
virtual AISyncKey* createSyncKey(AISyncKey const* from_key = NULL) const = 0;
|
||||
|
||||
virtual void event1_ready(void) = 0;
|
||||
virtual void event1_not_ready(void) = 0;
|
||||
|
||||
// Only client. Client was forcefully deregistered from expired server because it was the only client.
|
||||
virtual void deregistered(void)
|
||||
{
|
||||
#ifdef SHOW_ASSERT
|
||||
mReadyEvents = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
AISyncServer* server(void) const { return mServer.get(); }
|
||||
|
||||
// Add this client to a server with matching sync key. Optionally the server is first created.
|
||||
void register_client(void) { AISyncServerMap::instance().register_client(this, createSyncKey()); }
|
||||
|
||||
// Remove this client from its server, if any.
|
||||
void unregister_client(void) { if (mServer) mServer->remove(this); }
|
||||
|
||||
// Call 'ready' when you are ready (or not) to get a call to start().
|
||||
// Returns true if that call was made (immediately), otherwise it may happen later.
|
||||
|
||||
// Set readiness of all events at once.
|
||||
void ready(synceventset_t events, synceventset_t yesno)
|
||||
{
|
||||
if (!mServer)
|
||||
{
|
||||
register_client();
|
||||
}
|
||||
mServer->ready(events, yesno, this);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -47,6 +47,10 @@ public:
|
||||
// Create an LLFrameTimer and start it. After creation it is running and in the state expired (hasExpired will return true).
|
||||
LLFrameTimer(void) : mExpiry(0), mRunning(true), mPaused(false) { if (!sGlobalMutex) global_initialization(); setAge(0.0); }
|
||||
|
||||
//<singu>
|
||||
void copy(LLFrameTimer const& timer) { mStartTime = timer.mStartTime; mExpiry = timer.mExpiry; mRunning = timer.mRunning; mPaused = timer.mPaused; }
|
||||
//</singu>
|
||||
|
||||
// Atomic reads of static variables.
|
||||
|
||||
// Return the number of seconds since the start of the application.
|
||||
@@ -142,6 +146,9 @@ public:
|
||||
bool hasExpired() const { return getElapsedSeconds() >= mExpiry; }
|
||||
F32 getElapsedTimeF32() const { llassert(mRunning); return mPaused ? (F32)mStartTime : (F32)(getElapsedSeconds() - mStartTime); }
|
||||
bool getStarted() const { return mRunning; }
|
||||
//<singu>
|
||||
F64 getStartTime() const { llassert(!mPaused); return mStartTime; }
|
||||
//</singu>
|
||||
|
||||
// return the seconds since epoch when this timer will expire.
|
||||
F64 expiresAt() const;
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
/**
|
||||
* @file llindraconfigfile.cpp
|
||||
*
|
||||
*
|
||||
* This class is an LLLiveFile that has config info for indra
|
||||
* Currently only whether it's blacklisted
|
||||
*
|
||||
* $LicenseInfo:firstyear=2007&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2007-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llindraconfigfile.h"
|
||||
|
||||
#include "llfile.h"
|
||||
#include "llsd.h"
|
||||
#include "llsdserialize.h"
|
||||
#include "llframetimer.h"
|
||||
|
||||
static std::string sConfigDir = "";
|
||||
static const char indraConfigFileName[] = "indra.xml";
|
||||
|
||||
|
||||
LLIndraConfigFile::LLIndraConfigFile()
|
||||
: LLLiveFile(filename()),
|
||||
mConfig(LLSD())
|
||||
{
|
||||
}
|
||||
|
||||
//static
|
||||
void LLIndraConfigFile::initClass(const std::string& config_dir)
|
||||
{
|
||||
sConfigDir = config_dir;
|
||||
llinfos << "LLIndraConfigFile::initClass config dir "
|
||||
<< config_dir << "/" << indraConfigFileName << llendl;
|
||||
}
|
||||
|
||||
LLSD LLIndraConfigFile::getConfig(const std::string& config_name)
|
||||
{
|
||||
if (sConfigDir.empty())
|
||||
{
|
||||
llerrs << "LLIndraConfigFile::initClass() not called" << llendl;
|
||||
}
|
||||
|
||||
LLFrameTimer::updateFrameTime();
|
||||
|
||||
static LLIndraConfigFile the_file;
|
||||
the_file.checkAndReload();
|
||||
|
||||
return the_file.mConfig[config_name];
|
||||
}
|
||||
|
||||
std::string LLIndraConfigFile::filename()
|
||||
{
|
||||
std::ostringstream ostr;
|
||||
|
||||
ostr << sConfigDir
|
||||
<< "/" << indraConfigFileName;
|
||||
|
||||
return ostr.str();
|
||||
}
|
||||
|
||||
/* virtual */
|
||||
bool LLIndraConfigFile::loadFile()
|
||||
{
|
||||
llinfos << "LLIndraConfigFile::loadFile: reading from "
|
||||
<< filename() << llendl;
|
||||
|
||||
LLSD config;
|
||||
|
||||
{
|
||||
llifstream file(filename());
|
||||
if (file.is_open())
|
||||
{
|
||||
LLSDSerialize::fromXML(config, file);
|
||||
}
|
||||
|
||||
if (config.isUndefined())
|
||||
{
|
||||
llinfos << "LLIndraConfigFile::loadFile: file missing, ill-formed,"
|
||||
" or simply undefined; not changing the blacklist" << llendl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (config.isMap())
|
||||
{
|
||||
mConfig = config;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
llwarns << "LLIndraConfigFile: " << indraConfigFileName << " expects a map; wrong format" << llendl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/**
|
||||
* @file llindraconfigfile.h
|
||||
* @brief manages configuration file for indra.xml
|
||||
*
|
||||
* $LicenseInfo:firstyear=2007&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2007-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLINDRACONFIGFILE_H
|
||||
#define LL_LLINDRACONFIGFILE_H
|
||||
|
||||
#include "linden_common.h"
|
||||
#include <string>
|
||||
|
||||
#include "lllivefile.h"
|
||||
#include "llsd.h"
|
||||
|
||||
|
||||
// To use, call LLIndraConfigFile::initClass(config_dir);
|
||||
// Then whenever getConfig is called, it will check and reload automatically
|
||||
|
||||
class LLIndraConfigFile : public LLLiveFile
|
||||
{
|
||||
public:
|
||||
LLIndraConfigFile();
|
||||
static void initClass(const std::string& config_dir);
|
||||
static LLSD getConfig(const std::string& config_name);
|
||||
|
||||
private:
|
||||
static std::string filename();
|
||||
|
||||
protected:
|
||||
/* virtual */ bool loadFile();
|
||||
LLSD mConfig;
|
||||
};
|
||||
|
||||
#endif //LL_LLINDRACONFIGFILE_H
|
||||
@@ -965,7 +965,6 @@ P(newAgentInventoryVariablePriceResponder);
|
||||
P(objectCostResponder);
|
||||
P(objectLinksetsResponder);
|
||||
P(physicsFlagsResponder);
|
||||
P(placeAvatarTeleportResponder);
|
||||
P(productInfoRequestResponder);
|
||||
P(regionResponder);
|
||||
P(remoteParcelRequestResponder);
|
||||
|
||||
@@ -237,13 +237,21 @@ void LLHTTPClient::request(
|
||||
req->run(parent, new_parent_state, parent != NULL, true, default_engine);
|
||||
}
|
||||
|
||||
void LLHTTPClient::getByteRange(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug))
|
||||
bool LLHTTPClient::getByteRange(std::string const& url, AIHTTPHeaders& headers, S32 offset, S32 bytes, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug))
|
||||
{
|
||||
if(offset > 0 || bytes > 0)
|
||||
try
|
||||
{
|
||||
headers.addHeader("Range", llformat("bytes=%d-%d", offset, offset + bytes - 1));
|
||||
if (offset > 0 || bytes > 0)
|
||||
{
|
||||
headers.addHeader("Range", llformat("bytes=%d-%d", offset, offset + bytes - 1));
|
||||
}
|
||||
request(url, HTTP_GET, NULL, responder, headers, NULL/*,*/ DEBUG_CURLIO_PARAM(debug));
|
||||
}
|
||||
request(url, HTTP_GET, NULL, responder, headers, NULL/*,*/ DEBUG_CURLIO_PARAM(debug));
|
||||
catch(AICurlNoEasyHandle const&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void LLHTTPClient::head(std::string const& url, ResponderHeadersOnly* responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug))
|
||||
|
||||
@@ -133,6 +133,14 @@ public:
|
||||
public:
|
||||
typedef boost::shared_ptr<LLBufferArray> buffer_ptr_t;
|
||||
|
||||
/**
|
||||
* @brief return true if the status code indicates success.
|
||||
*/
|
||||
static bool isGoodStatus(U32 status)
|
||||
{
|
||||
return((200 <= status) && (status < 300));
|
||||
}
|
||||
|
||||
protected:
|
||||
ResponderBase(void);
|
||||
virtual ~ResponderBase();
|
||||
@@ -452,9 +460,9 @@ public:
|
||||
static void head(std::string const& url, ResponderHeadersOnly* responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off))
|
||||
{ AIHTTPHeaders headers; head(url, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); }
|
||||
|
||||
static void getByteRange(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off));
|
||||
static void getByteRange(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off))
|
||||
{ AIHTTPHeaders headers; getByteRange(url, offset, bytes, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); }
|
||||
static bool getByteRange(std::string const& url, AIHTTPHeaders& headers, S32 offset, S32 bytes, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off));
|
||||
static bool getByteRange(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off))
|
||||
{ AIHTTPHeaders headers; return getByteRange(url, headers, offset, bytes, responder/*,*/ DEBUG_CURLIO_PARAM(debug)); }
|
||||
|
||||
static void get(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off));
|
||||
static void get(std::string const& url, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off))
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
#include "llmodel.h"
|
||||
#include "llmemory.h"
|
||||
#include "LLConvexDecomposition.h"
|
||||
#include "llconvexdecomposition.h"
|
||||
#include "llsdserialize.h"
|
||||
#include "llvector4a.h"
|
||||
#if LL_MSVC
|
||||
@@ -168,6 +168,7 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa
|
||||
|
||||
if ( !get_dom_sources(inputs, pos_offset, tc_offset, norm_offset, idx_stride, pos_source, tc_source, norm_source) || !pos_source )
|
||||
{
|
||||
llwarns << "Could not find dom sources for basic geo data; invalid model." << llendl;
|
||||
return LLModel::BAD_ELEMENT;
|
||||
}
|
||||
|
||||
@@ -188,27 +189,78 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa
|
||||
|
||||
LLVolumeFace::VertexMapData::PointMap point_map;
|
||||
|
||||
for (U32 i = 0; i < idx.getCount(); i += idx_stride)
|
||||
U32 index_count = idx.getCount();
|
||||
U32 vertex_count = pos_source ? v.getCount() : 0;
|
||||
U32 tc_count = tc_source ? tc.getCount() : 0;
|
||||
U32 norm_count = norm_source ? n.getCount() : 0;
|
||||
|
||||
for (U32 i = 0; i < index_count; i += idx_stride)
|
||||
{
|
||||
LLVolumeFace::VertexData cv;
|
||||
if (pos_source)
|
||||
{
|
||||
// guard against model data specifiying out of range indices or verts
|
||||
//
|
||||
if (((i + pos_offset) > index_count)
|
||||
|| ((idx[i+pos_offset]*3+2) > vertex_count))
|
||||
{
|
||||
llwarns << "Out of range index data; invalid model." << llendl;
|
||||
return LLModel::BAD_ELEMENT;
|
||||
}
|
||||
|
||||
cv.setPosition(LLVector4a(v[idx[i+pos_offset]*3+0],
|
||||
v[idx[i+pos_offset]*3+1],
|
||||
v[idx[i+pos_offset]*3+2]));
|
||||
|
||||
if (!cv.getPosition().isFinite3())
|
||||
{
|
||||
llwarns << "Nan positional data, invalid model." << llendl;
|
||||
return LLModel::BAD_ELEMENT;
|
||||
}
|
||||
}
|
||||
|
||||
if (tc_source)
|
||||
{
|
||||
// guard against model data specifiying out of range indices or tcs
|
||||
//
|
||||
|
||||
if (((i + tc_offset) > index_count)
|
||||
|| ((idx[i+tc_offset]*2+1) > tc_count))
|
||||
{
|
||||
llwarns << "Out of range TC indices." << llendl;
|
||||
return LLModel::BAD_ELEMENT;
|
||||
}
|
||||
|
||||
cv.mTexCoord.setVec(tc[idx[i+tc_offset]*2+0],
|
||||
tc[idx[i+tc_offset]*2+1]);
|
||||
|
||||
if (!cv.mTexCoord.isFinite())
|
||||
{
|
||||
llwarns << "Found NaN while loading tex coords from DAE-Model, invalid model." << llendl;
|
||||
return LLModel::BAD_ELEMENT;
|
||||
}
|
||||
}
|
||||
|
||||
if (norm_source)
|
||||
{
|
||||
// guard against model data specifiying out of range indices or norms
|
||||
//
|
||||
if (((i + norm_offset) > index_count)
|
||||
|| ((idx[i+norm_offset]*3+2) > norm_count))
|
||||
{
|
||||
llwarns << "Found out of range norm indices, invalid model." << llendl;
|
||||
return LLModel::BAD_ELEMENT;
|
||||
}
|
||||
|
||||
cv.setNormal(LLVector4a(n[idx[i+norm_offset]*3+0],
|
||||
n[idx[i+norm_offset]*3+1],
|
||||
n[idx[i+norm_offset]*3+2]));
|
||||
|
||||
if (!cv.getNormal().isFinite3())
|
||||
{
|
||||
llwarns << "Found NaN while loading normals from DAE-Model, invalid model." << llendl;
|
||||
return LLModel::BAD_ELEMENT;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL found = FALSE;
|
||||
@@ -263,7 +315,7 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa
|
||||
LLVolumeFace& new_face = *face_list.rbegin();
|
||||
if (!norm_source)
|
||||
{
|
||||
//l_aligned_free_16(new_face.mNormals);
|
||||
//ll_aligned_free_16(new_face.mNormals);
|
||||
new_face.mNormals = NULL;
|
||||
}
|
||||
|
||||
@@ -335,6 +387,7 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac
|
||||
|
||||
if (!get_dom_sources(inputs, pos_offset, tc_offset, norm_offset, idx_stride, pos_source, tc_source, norm_source))
|
||||
{
|
||||
llwarns << "Could not get DOM sources for basic geo data, invalid model." << llendl;
|
||||
return LLModel::BAD_ELEMENT;
|
||||
}
|
||||
|
||||
@@ -366,6 +419,11 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac
|
||||
|
||||
LLVolumeFace::VertexMapData::PointMap point_map;
|
||||
|
||||
U32 index_count = idx.getCount();
|
||||
U32 vertex_count = pos_source ? v.getCount() : 0;
|
||||
U32 tc_count = tc_source ? tc.getCount() : 0;
|
||||
U32 norm_count = norm_source ? n.getCount() : 0;
|
||||
|
||||
U32 cur_idx = 0;
|
||||
for (U32 i = 0; i < vcount.getCount(); ++i)
|
||||
{ //for each polygon
|
||||
@@ -378,22 +436,68 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac
|
||||
|
||||
if (pos_source)
|
||||
{
|
||||
// guard against model data specifiying out of range indices or verts
|
||||
//
|
||||
if (((cur_idx + pos_offset) > index_count)
|
||||
|| ((idx[cur_idx+pos_offset]*3+2) > vertex_count))
|
||||
{
|
||||
llwarns << "Out of range position indices, invalid model." << llendl;
|
||||
return LLModel::BAD_ELEMENT;
|
||||
}
|
||||
|
||||
cv.getPosition().set(v[idx[cur_idx+pos_offset]*3+0],
|
||||
v[idx[cur_idx+pos_offset]*3+1],
|
||||
v[idx[cur_idx+pos_offset]*3+2]);
|
||||
|
||||
if (!cv.getPosition().isFinite3())
|
||||
{
|
||||
llwarns << "Found NaN while loading positions from DAE-Model, invalid model." << llendl;
|
||||
return LLModel::BAD_ELEMENT;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (tc_source)
|
||||
{
|
||||
// guard against model data specifiying out of range indices or tcs
|
||||
//
|
||||
if (((cur_idx + tc_offset) > index_count)
|
||||
|| ((idx[cur_idx+tc_offset]*2+1) > tc_count))
|
||||
{
|
||||
llwarns << "Out of range TC indices, invalid model." << llendl;
|
||||
return LLModel::BAD_ELEMENT;
|
||||
}
|
||||
|
||||
cv.mTexCoord.setVec(tc[idx[cur_idx+tc_offset]*2+0],
|
||||
tc[idx[cur_idx+tc_offset]*2+1]);
|
||||
|
||||
if (!cv.mTexCoord.isFinite())
|
||||
{
|
||||
llwarns << "Found NaN while loading tex coords from DAE-Model, invalid model." << llendl;
|
||||
return LLModel::BAD_ELEMENT;
|
||||
}
|
||||
}
|
||||
|
||||
if (norm_source)
|
||||
{
|
||||
// guard against model data specifiying out of range indices or norms
|
||||
//
|
||||
if (((cur_idx + norm_offset) > index_count)
|
||||
|| ((idx[cur_idx+norm_offset]*3+2) > norm_count))
|
||||
{
|
||||
llwarns << "Out of range norm indices, invalid model." << llendl;
|
||||
return LLModel::BAD_ELEMENT;
|
||||
}
|
||||
|
||||
cv.getNormal().set(n[idx[cur_idx+norm_offset]*3+0],
|
||||
n[idx[cur_idx+norm_offset]*3+1],
|
||||
n[idx[cur_idx+norm_offset]*3+2]);
|
||||
|
||||
if (!cv.getNormal().isFinite3())
|
||||
{
|
||||
llwarns << "Found NaN while loading normals from DAE-Model, invalid model." << llendl;
|
||||
return LLModel::BAD_ELEMENT;
|
||||
}
|
||||
}
|
||||
|
||||
cur_idx += idx_stride;
|
||||
@@ -560,6 +664,7 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac
|
||||
domVertices* vertices = (domVertices*) elem.cast();
|
||||
if (!vertices)
|
||||
{
|
||||
llwarns << "Could not find vertex source, invalid model." << llendl;
|
||||
return LLModel::BAD_ELEMENT;
|
||||
}
|
||||
domInputLocal_Array& v_inp = vertices->getInput_array();
|
||||
@@ -573,6 +678,7 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac
|
||||
domSource* src = (domSource*) elem.cast();
|
||||
if (!src)
|
||||
{
|
||||
llwarns << "Could not find DOM source, invalid model." << llendl;
|
||||
return LLModel::BAD_ELEMENT;
|
||||
}
|
||||
v = &(src->getFloat_array()->getValue());
|
||||
@@ -588,6 +694,7 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac
|
||||
domSource* src = (domSource*) elem.cast();
|
||||
if (!src)
|
||||
{
|
||||
llwarns << "Could not find DOM source, invalid model." << llendl;
|
||||
return LLModel::BAD_ELEMENT;
|
||||
}
|
||||
n = &(src->getFloat_array()->getValue());
|
||||
@@ -600,6 +707,7 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac
|
||||
domSource* src = (domSource*) elem.cast();
|
||||
if (!src)
|
||||
{
|
||||
llwarns << "Could not find DOM source, invalid model." << llendl;
|
||||
return LLModel::BAD_ELEMENT;
|
||||
}
|
||||
t = &(src->getFloat_array()->getValue());
|
||||
@@ -634,6 +742,12 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac
|
||||
vert.getPosition().set(v->get(v_idx),
|
||||
v->get(v_idx+1),
|
||||
v->get(v_idx+2));
|
||||
|
||||
if (!vert.getPosition().isFinite3())
|
||||
{
|
||||
llwarns << "Found NaN while loading position data from DAE-Model, invalid model." << llendl;
|
||||
return LLModel::BAD_ELEMENT;
|
||||
}
|
||||
}
|
||||
|
||||
//bounds check n and t lookups because some FBX to DAE converters
|
||||
@@ -646,6 +760,12 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac
|
||||
vert.getNormal().set(n->get(n_idx),
|
||||
n->get(n_idx+1),
|
||||
n->get(n_idx+2));
|
||||
|
||||
if (!vert.getNormal().isFinite3())
|
||||
{
|
||||
llwarns << "Found NaN while loading normals from DAE-Model, invalid model." << llendl;
|
||||
return LLModel::BAD_ELEMENT;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -659,6 +779,12 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac
|
||||
t_idx = llclamp(t_idx, (U32) 0, (U32) t->getCount());
|
||||
vert.mTexCoord.setVec(t->get(t_idx),
|
||||
t->get(t_idx+1));
|
||||
|
||||
if (!vert.mTexCoord.isFinite())
|
||||
{
|
||||
llwarns << "Found NaN while loading tex coords from DAE-Model, invalid model." << llendl;
|
||||
return LLModel::BAD_ELEMENT;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1591,6 +1717,7 @@ LLSD LLModel::writeModel(
|
||||
mdl[model_names[idx]][i]["TexCoord0Domain"]["Max"] = max_tc.getValue();
|
||||
mdl[model_names[idx]][i]["TexCoord0"] = tc;
|
||||
}
|
||||
|
||||
mdl[model_names[idx]][i]["TriangleList"] = indices;
|
||||
|
||||
if (skinning)
|
||||
|
||||
@@ -921,6 +921,23 @@ void LLLineEditor::addChar(const llwchar uni_char)
|
||||
|
||||
mText.insert(getCursor(), w_buf);
|
||||
setCursor(getCursor() + 1);
|
||||
|
||||
if (!mReadOnly && mAutoreplaceCallback != NULL)
|
||||
{
|
||||
// autoreplace the text, if necessary
|
||||
S32 replacement_start;
|
||||
S32 replacement_length;
|
||||
LLWString replacement_string;
|
||||
S32 new_cursor_pos = getCursor();
|
||||
mAutoreplaceCallback(replacement_start, replacement_length, replacement_string, new_cursor_pos, mText);
|
||||
|
||||
if (replacement_length > 0 || !replacement_string.empty())
|
||||
{
|
||||
mText.erase(replacement_start, replacement_length);
|
||||
mText.insert(replacement_start, replacement_string);
|
||||
setCursor(new_cursor_pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -167,6 +167,10 @@ public:
|
||||
virtual BOOL isSpellDirty() const { return mText.getString() != mPrevSpelledText; } // Returns TRUE if user changed value at all
|
||||
virtual void resetSpellDirty() { mPrevSpelledText = mText.getString(); } // Clear dirty state
|
||||
|
||||
typedef boost::function<void(S32&, S32&, LLWString&, S32&, const LLWString&)> autoreplace_callback_t;
|
||||
autoreplace_callback_t mAutoreplaceCallback;
|
||||
void setAutoreplaceCallback(autoreplace_callback_t cb) { mAutoreplaceCallback = cb; }
|
||||
|
||||
// assumes UTF8 text
|
||||
virtual void setValue(const LLSD& value ) { setText(value.asString()); }
|
||||
virtual LLSD getValue() const { return LLSD(getText()); }
|
||||
|
||||
@@ -156,8 +156,6 @@ LLDir_Win32::LLDir_Win32()
|
||||
mAppRODataDir = mWorkingDir;
|
||||
|
||||
|
||||
// if (mExecutableDir.find("indra") == std::string::npos)
|
||||
|
||||
// *NOTE:Mani - It is a mistake to put viewer specific code in
|
||||
// the LLDir implementation. The references to 'skins' and
|
||||
// 'llplugin' need to go somewhere else.
|
||||
@@ -172,7 +170,18 @@ LLDir_Win32::LLDir_Win32()
|
||||
|
||||
llinfos << "mAppRODataDir = " << mAppRODataDir << llendl;
|
||||
|
||||
mSkinBaseDir = mAppRODataDir + mDirDelimiter + "skins";
|
||||
std::string::size_type build_dir_pos = mExecutableDir.rfind("indra" + mDirDelimiter);
|
||||
if (build_dir_pos != std::string::npos)
|
||||
{
|
||||
// ...we're in a dev checkout
|
||||
mSkinBaseDir = mExecutableDir.substr(0, build_dir_pos) + "indra" + mDirDelimiter + "newview" + mDirDelimiter + "skins";
|
||||
llinfos << "Running in dev checkout with mSkinBaseDir " << mSkinBaseDir << llendl;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ...normal installation running
|
||||
mSkinBaseDir = mAppRODataDir + mDirDelimiter + "skins";
|
||||
}
|
||||
|
||||
// Build the default cache directory
|
||||
mDefaultCacheDir = buildSLOSCacheDir();
|
||||
|
||||
@@ -3277,7 +3277,7 @@ void LLWindowMacOSX::spawnWebBrowser(const std::string& escaped_url, bool async)
|
||||
|
||||
llinfos << "Opening URL " << escaped_url << llendl;
|
||||
|
||||
CFStringRef stringRef = CFStringCreateWithCString(NULL, escaped_url.c_str(), kCFStringEncodingUTF8);
|
||||
CFStringRef stringRef = CFStringCreateWithBytes(NULL, (UInt8 *)escaped_url.c_str(), strlen(escaped_url.c_str()), kCFStringEncodingUTF8, false);
|
||||
if (stringRef)
|
||||
{
|
||||
// This will succeed if the string is a full URL, including the http://
|
||||
@@ -3315,6 +3315,21 @@ void LLWindowMacOSX::setTitle(const std::string &title)
|
||||
SetWindowTitleWithCFString(mWindow, title_str);
|
||||
}
|
||||
|
||||
// virtual
|
||||
void LLWindowMacOSX::ShellEx(const std::string& command)
|
||||
{
|
||||
char * path = NULL;
|
||||
asprintf(&path, "%s %s", (char*)"file://", command.c_str());
|
||||
CFURLRef url = CFURLCreateAbsoluteURLWithBytes(NULL, (UInt8 *)path, strlen(path),
|
||||
kCFURLPOSIXPathStyle, NULL, true);
|
||||
if (url != NULL)
|
||||
{
|
||||
LSOpenCFURLRef(url, NULL);
|
||||
CFRelease(url);
|
||||
}
|
||||
free(path);
|
||||
}
|
||||
|
||||
LLSD LLWindowMacOSX::getNativeKeyData()
|
||||
{
|
||||
LLSD result = LLSD::emptyMap();
|
||||
|
||||
@@ -116,6 +116,7 @@ public:
|
||||
/*virtual*/ void spawnWebBrowser(const std::string& escaped_url, bool async);
|
||||
|
||||
/*virtual*/ void setTitle(const std::string &title);
|
||||
/*virtual*/ void ShellEx(const std::string& command);
|
||||
|
||||
static std::vector<std::string> getDynamicFallbackFontList();
|
||||
|
||||
|
||||
@@ -3329,9 +3329,9 @@ S32 OSMessageBoxWin32(const std::string& text, const std::string& caption, U32 t
|
||||
return retval;
|
||||
}
|
||||
|
||||
void LLWindowWin32::ShellEx(const std::string& command )
|
||||
void LLWindowWin32::ShellEx(const std::string& command)
|
||||
{
|
||||
LLWString url_wstring = utf8str_to_wstring( command );
|
||||
LLWString url_wstring = utf8str_to_wstring( "\"" + command + "\"" );
|
||||
llutf16string url_utf16 = wstring_to_utf16str( url_wstring );
|
||||
|
||||
SHELLEXECUTEINFO sei = { sizeof( sei ) };
|
||||
|
||||
@@ -126,6 +126,7 @@ set(viewer_SOURCE_FILES
|
||||
llassetuploadresponders.cpp
|
||||
llattachmentsmgr.cpp
|
||||
llaudiosourcevo.cpp
|
||||
llautoreplace.cpp
|
||||
llavataractions.cpp
|
||||
llavatarpropertiesprocessor.cpp
|
||||
llbox.cpp
|
||||
@@ -181,6 +182,7 @@ set(viewer_SOURCE_FILES
|
||||
llfloaterabout.cpp
|
||||
llfloateractivespeakers.cpp
|
||||
llfloaterauction.cpp
|
||||
llfloaterautoreplacesettings.cpp
|
||||
llfloateravatarinfo.cpp
|
||||
llfloateravatarlist.cpp
|
||||
llfloateravatarpicker.cpp
|
||||
@@ -244,7 +246,6 @@ set(viewer_SOURCE_FILES
|
||||
llfloaterpathfindingcharacters.cpp
|
||||
llfloaterpathfindinglinksets.cpp
|
||||
llfloaterpathfindingobjects.cpp
|
||||
llfloaterpermissionsmgr.cpp
|
||||
llfloaterperms.cpp
|
||||
llfloaterpostcard.cpp
|
||||
llfloaterpostprocess.cpp
|
||||
@@ -252,6 +253,7 @@ set(viewer_SOURCE_FILES
|
||||
llfloaterproperties.cpp
|
||||
llfloaterregiondebugconsole.cpp
|
||||
llfloaterregioninfo.cpp
|
||||
llfloaterregionrestarting.cpp
|
||||
llfloaterreporter.cpp
|
||||
llfloaterscriptdebug.cpp
|
||||
llfloaterscriptlimits.cpp
|
||||
@@ -646,6 +648,7 @@ set(viewer_HEADER_FILES
|
||||
llassetuploadresponders.h
|
||||
llattachmentsmgr.h
|
||||
llaudiosourcevo.h
|
||||
llautoreplace.h
|
||||
llavataractions.h
|
||||
llavatarpropertiesprocessor.h
|
||||
llbox.h
|
||||
@@ -701,6 +704,7 @@ set(viewer_HEADER_FILES
|
||||
llfloaterabout.h
|
||||
llfloateractivespeakers.h
|
||||
llfloaterauction.h
|
||||
llfloaterautoreplacesettings.h
|
||||
llfloateravatarinfo.h
|
||||
llfloateravatarlist.h
|
||||
llfloateravatarpicker.h
|
||||
@@ -764,7 +768,6 @@ set(viewer_HEADER_FILES
|
||||
llfloaterpathfindingcharacters.h
|
||||
llfloaterpathfindinglinksets.h
|
||||
llfloaterpathfindingobjects.h
|
||||
llfloaterpermissionsmgr.h
|
||||
llfloaterperms.h
|
||||
llfloaterpostcard.h
|
||||
llfloaterpostprocess.h
|
||||
@@ -772,6 +775,7 @@ set(viewer_HEADER_FILES
|
||||
llfloaterproperties.h
|
||||
llfloaterregiondebugconsole.h
|
||||
llfloaterregioninfo.h
|
||||
llfloaterregionrestarting.h
|
||||
llfloaterreporter.h
|
||||
llfloaterscriptdebug.h
|
||||
llfloaterscriptlimits.h
|
||||
@@ -1140,7 +1144,7 @@ if (DARWIN)
|
||||
|
||||
# Add resource files to the project.
|
||||
set(viewer_RESOURCE_FILES
|
||||
${VIEWER_BRANDING_ID}.icns
|
||||
${VIEWER_BRANDING_ID}_icon.icns
|
||||
macview.r
|
||||
gpu_table.txt
|
||||
SecondLife.nib/
|
||||
@@ -1702,7 +1706,7 @@ if (DARWIN)
|
||||
PROPERTIES
|
||||
OUTPUT_NAME "${product}"
|
||||
MACOSX_BUNDLE_INFO_STRING "A stable third-party Second Life viewer."
|
||||
MACOSX_BUNDLE_ICON_FILE "${VIEWER_BRANDING_ID}.icns"
|
||||
MACOSX_BUNDLE_ICON_FILE "${VIEWER_BRANDING_ID}_icon.icns"
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER "${VIEWER_BRANDING_NAME}"
|
||||
MACOSX_BUNDLE_LONG_VERSION_STRING "${viewer_VERSION}"
|
||||
MACOSX_BUNDLE_BUNDLE_NAME "${VIEWER_BRANDING_NAME}"
|
||||
|
||||
8330
indra/newview/app_settings/autoreplace.xml
Normal file
8330
indra/newview/app_settings/autoreplace.xml
Normal file
File diff suppressed because it is too large
Load Diff
@@ -738,7 +738,7 @@
|
||||
<key>LiruLegacyLogLaunch</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>When opening a chat log, open in an external text editor instead of a browser floater(Windows Only).</string>
|
||||
<string>When opening a chat log, open in an external text editor instead of a browser floater(Windows and Mac Only).</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
@@ -834,6 +834,17 @@
|
||||
<key>Value</key>
|
||||
<boolean>0</boolean>
|
||||
</map>
|
||||
<key>LiruMouselookHidesToolbar</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Whether or not the toolbar will be hidden in mouselook</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<boolean>1</boolean>
|
||||
</map>
|
||||
<key>LiruMouselookMenu</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -893,6 +904,19 @@
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>LiruRegionRestartMinimized</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Whether or not to spawn the region restart notice minimized (Useful for sim owners and people who need to pack up before leaving)</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
<key>IsCOA</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>LiruScriptErrorsStealFocus</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -1313,6 +1337,17 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>AnnounceBumps</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Announce if someone bumps into you.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<boolean>0</boolean>
|
||||
</map>
|
||||
<key>AnnounceSnapshots</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -2222,6 +2257,17 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<key>IsCOA</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>UISndRestart</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Sound file for region restarting (uuid for sound asset)</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>String</string>
|
||||
<key>Value</key>
|
||||
<string>1e506d0c-4811-bdf3-5ec7-d624284c9040</string>
|
||||
</map>
|
||||
<key>UISndSnapshot</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -2396,6 +2442,17 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>AllowSelectAvatar</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Allow selecting an avatar that you have modify rights on (via tag) while in edit mode to reposition them</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>AllowTapTapHoldRun</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -2693,6 +2750,17 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>AutoReplace</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Replaces keywords with a configured word or phrase</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>AutoAcceptAllNewInventory</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -7277,6 +7345,17 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<key>Value</key>
|
||||
<integer>24</integer>
|
||||
</map>
|
||||
<key>RadarColumnVoiceWidth</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Width for radar's voice status column</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>S32</string>
|
||||
<key>Value</key>
|
||||
<integer>24</integer>
|
||||
</map>
|
||||
<key>RadarColumnAgeWidth</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -7354,6 +7433,17 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>RadarColumnVoiceHidden</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Hide radar's voice status column</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<boolean>0</boolean>
|
||||
</map>
|
||||
<key>RadarColumnAgeHidden</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -11123,22 +11213,6 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>PermissionsManagerRect</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Rectangle for permissions manager window</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Rect</string>
|
||||
<key>Value</key>
|
||||
<array>
|
||||
<integer>0</integer>
|
||||
<integer>85</integer>
|
||||
<integer>300</integer>
|
||||
<integer>0</integer>
|
||||
</array>
|
||||
</map>
|
||||
<key>PickerContextOpacity</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -14559,9 +14633,9 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<key>ShowChatHistory</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string/>
|
||||
<string>Open local chat window on login</string>
|
||||
<key>Persist</key>
|
||||
<integer>0</integer>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
@@ -14570,14 +14644,25 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<key>ShowCommunicate</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string/>
|
||||
<string>Open communicate window on login</string>
|
||||
<key>Persist</key>
|
||||
<integer>0</integer>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>ShowContacts</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Open contacts window on login</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<boolean>0</boolean>
|
||||
</map>
|
||||
<key>ShowConsoleWindow</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -406,6 +406,17 @@
|
||||
<key>Value</key>
|
||||
<string>This is an autoresponse!</string>
|
||||
</map>
|
||||
<key>AutoresponseOnlyIfAway</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>When true, enabled autoresponses (not busy responses) will only be sent while in away (or Fake Away) mode. Does not apply to autoresponses to muted persons, they don't need to know you're away.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>BusyModeResponse</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -723,6 +734,16 @@
|
||||
<key>Value</key>
|
||||
<string></string>
|
||||
</map>
|
||||
|
||||
<key>EmergencyTeleportLandmark</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>UUID of the landmark to teleport to in the last twenty seconds before a region will restart, empty is none.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>String</string>
|
||||
<key>Value</key>
|
||||
<string/>
|
||||
</map>
|
||||
</map>
|
||||
</llsd>
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "llagent.h"
|
||||
#include "llcolorswatch.h"
|
||||
#include "llcombobox.h"
|
||||
#include "llfloaterautoreplacesettings.h"
|
||||
#include "llradiogroup.h"
|
||||
#include "lluictrlfactory.h"
|
||||
#include "llviewercontrol.h"
|
||||
@@ -88,10 +89,8 @@ LLPrefsAscentChat::LLPrefsAscentChat()
|
||||
|
||||
childSetEnabled("reset_antispam", started);
|
||||
getChild<LLUICtrl>("reset_antispam")->setCommitCallback(boost::bind(NACLAntiSpamRegistry::purgeAllQueues));
|
||||
getChild<LLUICtrl>("enable_as")->setCommitCallback(boost::bind(&LLPrefsAscentChat::onCommitEnableAS, this, _2));
|
||||
getChild<LLUICtrl>("antispam_checkbox")->setCommitCallback(boost::bind(&LLPrefsAscentChat::onCommitDialogBlock, this, _1, _2));
|
||||
getChild<LLUICtrl>("Group Invites")->setCommitCallback(boost::bind(&LLPrefsAscentChat::onCommitDialogBlock, this, _1, _2));
|
||||
|
||||
getChild<LLUICtrl>("autoreplace")->setCommitCallback(boost::bind(LLFloaterAutoReplaceSettings::showInstance, LLSD()));
|
||||
getChild<LLUICtrl>("KeywordsOn")->setCommitCallback(boost::bind(&LLPrefsAscentChat::onCommitKeywords, this, _1));
|
||||
getChild<LLUICtrl>("KeywordsList")->setCommitCallback(boost::bind(&LLPrefsAscentChat::onCommitKeywords, this, _1));
|
||||
getChild<LLUICtrl>("KeywordsSound")->setCommitCallback(boost::bind(&LLPrefsAscentChat::onCommitKeywords, this, _1));
|
||||
@@ -184,39 +183,6 @@ void LLPrefsAscentChat::onCommitTimeDate(LLUICtrl* ctrl)
|
||||
gSavedSettings.setString("TimestampFormat", timestamp);
|
||||
}
|
||||
|
||||
void LLPrefsAscentChat::onCommitEnableAS(const LLSD& value)
|
||||
{
|
||||
bool enabled = value.asBoolean();
|
||||
childSetEnabled("spammsg_checkbox", enabled);
|
||||
childSetEnabled("antispamtime", enabled);
|
||||
childSetEnabled("antispamamount", enabled);
|
||||
childSetEnabled("antispamsoundmulti", enabled);
|
||||
childSetEnabled("antispamsoundpreloadmulti", enabled);
|
||||
childSetEnabled("antispamnewlines", enabled);
|
||||
childSetEnabled("Notify On Spam", enabled);
|
||||
}
|
||||
|
||||
void LLPrefsAscentChat::onCommitDialogBlock(LLUICtrl* ctrl, const LLSD& value)
|
||||
{
|
||||
childSetEnabled("Group Fee Invites", !childGetValue("antispam_checkbox").asBoolean() && !childGetValue("Group Invites").asBoolean());
|
||||
bool enabled = value.asBoolean();
|
||||
if (ctrl->getName() == "antispam_checkbox")
|
||||
{
|
||||
childSetEnabled("Block All Dialogs From", !enabled);
|
||||
childSetEnabled("Alerts", !enabled);
|
||||
childSetEnabled("Friendship Offers", !enabled);
|
||||
childSetEnabled("Group Invites", !enabled);
|
||||
childSetEnabled("Group Notices", !enabled);
|
||||
childSetEnabled("Item Offers", !enabled);
|
||||
childSetEnabled("Scripts", !enabled);
|
||||
childSetEnabled("Teleport Offers", !enabled);
|
||||
childSetEnabled("Teleport Requests", !enabled);
|
||||
childSetEnabled("Except those from:", !enabled);
|
||||
childSetEnabled("My objects", !enabled);
|
||||
childSetEnabled("My friends", !enabled);
|
||||
}
|
||||
}
|
||||
|
||||
void LLPrefsAscentChat::onCommitKeywords(LLUICtrl* ctrl)
|
||||
{
|
||||
if (ctrl->getName() == "KeywordsOn")
|
||||
@@ -392,26 +358,6 @@ void LLPrefsAscentChat::refresh()
|
||||
if (combo = getChild<LLComboBox>("speaker_namesystem_combobox"))
|
||||
combo->setCurrentByIndex(mSpeakerNames);
|
||||
|
||||
//Antispam ------------------------------------------------------------------------
|
||||
// sensitivity tuners
|
||||
childSetEnabled("spammsg_checkbox", mEnableAS);
|
||||
childSetEnabled("antispamtime", mEnableAS);
|
||||
childSetEnabled("antispamamount", mEnableAS);
|
||||
childSetEnabled("antispamsoundmulti", mEnableAS);
|
||||
childSetEnabled("antispamsoundpreloadmulti", mEnableAS);
|
||||
childSetEnabled("antispamnewlines", mEnableAS);
|
||||
childSetEnabled("Notify On Spam", mEnableAS);
|
||||
// dialog blocking tuners
|
||||
childSetEnabled("Block All Dialogs From", !mBlockDialogSpam);
|
||||
childSetEnabled("Alerts", !mBlockDialogSpam);
|
||||
childSetEnabled("Friendship Offers", !mBlockDialogSpam);
|
||||
childSetEnabled("Group Invites", !mBlockDialogSpam);
|
||||
childSetEnabled("Group Fee Invites", !mBlockDialogSpam && !mBlockGroupInviteSpam);
|
||||
childSetEnabled("Group Notices", !mBlockDialogSpam);
|
||||
childSetEnabled("Item Offers", !mBlockDialogSpam);
|
||||
childSetEnabled("Scripts", !mBlockDialogSpam);
|
||||
childSetEnabled("Teleport Offers", !mBlockDialogSpam);
|
||||
|
||||
//Text Options ------------------------------------------------------------------------
|
||||
combo = getChild<LLComboBox>("SpellBase");
|
||||
|
||||
|
||||
@@ -52,8 +52,6 @@ protected:
|
||||
void onSpellEditCustom();
|
||||
void onSpellBaseComboBoxCommit(const LLSD& value);
|
||||
void onCommitTimeDate(LLUICtrl* ctrl);
|
||||
void onCommitEnableAS(const LLSD& value);
|
||||
void onCommitDialogBlock(LLUICtrl* ctrl, const LLSD& value);
|
||||
void onCommitKeywords(LLUICtrl* ctrl);
|
||||
|
||||
private:
|
||||
|
||||
@@ -51,33 +51,30 @@ LLPrefsAscentSys::LLPrefsAscentSys()
|
||||
LLUICtrlFactory::getInstance()->buildPanel(this, "panel_preferences_ascent_system.xml");
|
||||
|
||||
//General -----------------------------------------------------------------------------
|
||||
getChild<LLUICtrl>("speed_rez_check")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCheckBox, this, _1, _2));
|
||||
getChild<LLUICtrl>("double_click_teleport_check")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCheckBox, this, _1, _2));
|
||||
getChild<LLUICtrl>("show_look_at_check")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCheckBox, this, _1, _2));
|
||||
getChild<LLUICtrl>("enable_clouds")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCheckBox, this, _1, _2));
|
||||
getChild<LLUICtrl>("power_user_check")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCheckBox, this, _1, _2));
|
||||
getChild<LLUICtrl>("power_user_confirm_check")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCheckBox, this, _1, _2));
|
||||
|
||||
//Command Line ------------------------------------------------------------------------
|
||||
getChild<LLUICtrl>("chat_cmd_toggle")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCmdLine, this, _1, _2));
|
||||
getChild<LLUICtrl>("AscentCmdLinePos")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCmdLine, this, _1, _2));
|
||||
getChild<LLUICtrl>("AscentCmdLineGround")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCmdLine, this, _1, _2));
|
||||
getChild<LLUICtrl>("AscentCmdLineHeight")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCmdLine, this, _1, _2));
|
||||
getChild<LLUICtrl>("AscentCmdLineTeleportHome")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCmdLine, this, _1, _2));
|
||||
getChild<LLUICtrl>("AscentCmdLineRezPlatform")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCmdLine, this, _1, _2));
|
||||
getChild<LLUICtrl>("AscentCmdLineCalc")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCmdLine, this, _1, _2));
|
||||
getChild<LLUICtrl>("AscentCmdLineClearChat")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCmdLine, this, _1, _2));
|
||||
getChild<LLUICtrl>("AscentCmdLineDrawDistance")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCmdLine, this, _1, _2));
|
||||
getChild<LLUICtrl>("AscentCmdTeleportToCam")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCmdLine, this, _1, _2));
|
||||
getChild<LLUICtrl>("AscentCmdLineKeyToName")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCmdLine, this, _1, _2));
|
||||
getChild<LLUICtrl>("AscentCmdLineOfferTp")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCmdLine, this, _1, _2));
|
||||
getChild<LLUICtrl>("AscentCmdLineMapTo")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCmdLine, this, _1, _2));
|
||||
getChild<LLUICtrl>("AscentCmdLineTP2")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCmdLine, this, _1, _2));
|
||||
getChild<LLUICtrl>("SinguCmdLineAway")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCmdLine, this, _1, _2));
|
||||
getChild<LLUICtrl>("SinguCmdLineURL")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCmdLine, this, _1, _2));
|
||||
commit_callback_t lineEditorControl(boost::bind(&LLControlGroup::setString, boost::ref(gSavedSettings), boost::bind(&LLUICtrl::getName, _1), _2));
|
||||
getChild<LLUICtrl>("AscentCmdLinePos")->setCommitCallback(lineEditorControl);
|
||||
getChild<LLUICtrl>("AscentCmdLineGround")->setCommitCallback(lineEditorControl);
|
||||
getChild<LLUICtrl>("AscentCmdLineHeight")->setCommitCallback(lineEditorControl);
|
||||
getChild<LLUICtrl>("AscentCmdLineTeleportHome")->setCommitCallback(lineEditorControl);
|
||||
getChild<LLUICtrl>("AscentCmdLineRezPlatform")->setCommitCallback(lineEditorControl);
|
||||
getChild<LLUICtrl>("AscentCmdLineCalc")->setCommitCallback(lineEditorControl);
|
||||
getChild<LLUICtrl>("AscentCmdLineClearChat")->setCommitCallback(lineEditorControl);
|
||||
getChild<LLUICtrl>("AscentCmdLineDrawDistance")->setCommitCallback(lineEditorControl);
|
||||
getChild<LLUICtrl>("AscentCmdTeleportToCam")->setCommitCallback(lineEditorControl);
|
||||
getChild<LLUICtrl>("AscentCmdLineKeyToName")->setCommitCallback(lineEditorControl);
|
||||
getChild<LLUICtrl>("AscentCmdLineOfferTp")->setCommitCallback(lineEditorControl);
|
||||
getChild<LLUICtrl>("AscentCmdLineMapTo")->setCommitCallback(lineEditorControl);
|
||||
getChild<LLUICtrl>("AscentCmdLineTP2")->setCommitCallback(lineEditorControl);
|
||||
getChild<LLUICtrl>("SinguCmdLineAway")->setCommitCallback(lineEditorControl);
|
||||
getChild<LLUICtrl>("SinguCmdLineURL")->setCommitCallback(lineEditorControl);
|
||||
|
||||
//Security ----------------------------------------------------------------------------
|
||||
getChild<LLUICtrl>("disable_click_sit_check")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCheckBox, this, _1, _2));
|
||||
getChild<LLUICtrl>("UISndRestart")->setCommitCallback(lineEditorControl);
|
||||
|
||||
//Build -------------------------------------------------------------------------------
|
||||
getChild<LLUICtrl>("next_owner_copy")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCheckBox, this, _1, _2));
|
||||
@@ -101,21 +98,7 @@ void LLPrefsAscentSys::onCommitCheckBox(LLUICtrl* ctrl, const LLSD& value)
|
||||
|
||||
const std::string name = ctrl->getName();
|
||||
bool enabled = value.asBoolean();
|
||||
if (name == "speed_rez_check")
|
||||
{
|
||||
childSetEnabled("speed_rez_interval", enabled);
|
||||
childSetEnabled("speed_rez_seconds", enabled);
|
||||
}
|
||||
else if (name == "double_click_teleport_check")
|
||||
{
|
||||
childSetEnabled("center_after_teleport_check", enabled);
|
||||
childSetEnabled("offset_teleport_check", enabled);
|
||||
}
|
||||
else if (name == "enable_clouds")
|
||||
{
|
||||
childSetEnabled("enable_classic_clouds", enabled);
|
||||
}
|
||||
else if (name == "power_user_check")
|
||||
if (name == "power_user_check")
|
||||
{
|
||||
childSetEnabled("power_user_confirm_check", enabled);
|
||||
childSetValue("power_user_confirm_check", false);
|
||||
@@ -135,10 +118,6 @@ void LLPrefsAscentSys::onCommitCheckBox(LLUICtrl* ctrl, const LLSD& value)
|
||||
LLFloaterChat::addChat(chat);
|
||||
}
|
||||
}
|
||||
else if (name == "disable_click_sit_check")
|
||||
{
|
||||
childSetEnabled("disable_click_sit_own_check", !enabled);
|
||||
}
|
||||
else if (name == "next_owner_copy")
|
||||
{
|
||||
if (!enabled) gSavedSettings.setBOOL("NextOwnerTransfer", true);
|
||||
@@ -146,49 +125,6 @@ void LLPrefsAscentSys::onCommitCheckBox(LLUICtrl* ctrl, const LLSD& value)
|
||||
}
|
||||
}
|
||||
|
||||
void LLPrefsAscentSys::onCommitCmdLine(LLUICtrl* ctrl, const LLSD& value)
|
||||
{
|
||||
const std::string& name = ctrl->getName();
|
||||
if (name == "chat_cmd_toggle")
|
||||
{
|
||||
bool enabled = value.asBoolean();
|
||||
childSetEnabled("cmd_line_text_2", enabled);
|
||||
childSetEnabled("cmd_line_text_3", enabled);
|
||||
childSetEnabled("cmd_line_text_4", enabled);
|
||||
childSetEnabled("cmd_line_text_5", enabled);
|
||||
childSetEnabled("cmd_line_text_6", enabled);
|
||||
childSetEnabled("cmd_line_text_7", enabled);
|
||||
childSetEnabled("cmd_line_text_8", enabled);
|
||||
childSetEnabled("cmd_line_text_9", enabled);
|
||||
childSetEnabled("cmd_line_text_10", enabled);
|
||||
childSetEnabled("cmd_line_text_11", enabled);
|
||||
childSetEnabled("cmd_line_text_12", enabled);
|
||||
childSetEnabled("cmd_line_text_13", enabled);
|
||||
childSetEnabled("cmd_line_text_15", enabled);
|
||||
childSetEnabled("AscentCmdLinePos", enabled);
|
||||
childSetEnabled("AscentCmdLineGround", enabled);
|
||||
childSetEnabled("AscentCmdLineHeight", enabled);
|
||||
childSetEnabled("AscentCmdLineTeleportHome", enabled);
|
||||
childSetEnabled("AscentCmdLineRezPlatform", enabled);
|
||||
childSetEnabled("AscentPlatformSize", enabled);
|
||||
childSetEnabled("AscentCmdLineCalc", enabled);
|
||||
childSetEnabled("AscentCmdLineClearChat", enabled);
|
||||
childSetEnabled("AscentCmdLineDrawDistance", enabled);
|
||||
childSetEnabled("AscentCmdTeleportToCam", enabled);
|
||||
childSetEnabled("AscentCmdLineKeyToName", enabled);
|
||||
childSetEnabled("AscentCmdLineOfferTp", enabled);
|
||||
childSetEnabled("AscentCmdLineMapTo", enabled);
|
||||
childSetEnabled("map_to_keep_pos", enabled);
|
||||
childSetEnabled("AscentCmdLineTP2", enabled);
|
||||
childSetEnabled("SinguCmdLineAway", enabled);
|
||||
childSetEnabled("SinguCmdLineURL", enabled);
|
||||
}
|
||||
else
|
||||
{
|
||||
gSavedSettings.setString(name, value); // Singu Note: Keep commandline settings using the same name as their settings
|
||||
}
|
||||
}
|
||||
|
||||
void LLPrefsAscentSys::onCommitComboBox(LLUICtrl* ctrl, const LLSD& value)
|
||||
{
|
||||
gSavedSettings.setString(ctrl->getControlName(), value.asString());
|
||||
@@ -252,12 +188,16 @@ void LLPrefsAscentSys::refreshValues()
|
||||
mPrivateLookAt = gSavedSettings.getBOOL("PrivateLookAt");
|
||||
mShowLookAt = gSavedSettings.getBOOL("AscentShowLookAt");
|
||||
mQuietSnapshotsToDisk = gSavedSettings.getBOOL("QuietSnapshotsToDisk");
|
||||
mAnnounceBumps = gSavedSettings.getBOOL("AnnounceBumps");
|
||||
mDetachBridge = gSavedSettings.getBOOL("SGDetachBridge");
|
||||
mRevokePermsOnStandUp = gSavedSettings.getBOOL("RevokePermsOnStandUp");
|
||||
mDisableClickSit = gSavedSettings.getBOOL("DisableClickSit");
|
||||
mDisableClickSitOtherOwner = gSavedSettings.getBOOL("DisableClickSitOtherOwner");
|
||||
mDisplayScriptJumps = gSavedSettings.getBOOL("AscentDisplayTotalScriptJumps");
|
||||
mNumScriptDiff = gSavedSettings.getF32("Ascentnumscriptdiff");
|
||||
mRestartMinimized = gSavedSettings.getBOOL("LiruRegionRestartMinimized");
|
||||
mRestartSound = gSavedSettings.getString("UISndRestart");
|
||||
mLandmark = gSavedPerAccountSettings.getString("EmergencyTeleportLandmark");
|
||||
|
||||
//Build -------------------------------------------------------------------------------
|
||||
mAlpha = gSavedSettings.getF32("EmeraldBuildPrefs_Alpha");
|
||||
@@ -282,44 +222,12 @@ void LLPrefsAscentSys::refreshValues()
|
||||
void LLPrefsAscentSys::refresh()
|
||||
{
|
||||
//General -----------------------------------------------------------------------------
|
||||
childSetEnabled("center_after_teleport_check", mDoubleClickTeleport);
|
||||
childSetEnabled("offset_teleport_check", mDoubleClickTeleport);
|
||||
childSetValue("power_user_check", mPowerUser);
|
||||
childSetValue("power_user_confirm_check", mPowerUser);
|
||||
childSetEnabled("speed_rez_interval", mSpeedRez);
|
||||
childSetEnabled("speed_rez_seconds", mSpeedRez);
|
||||
|
||||
//Command Line ------------------------------------------------------------------------
|
||||
childSetEnabled("cmd_line_text_2", mCmdLine);
|
||||
childSetEnabled("cmd_line_text_3", mCmdLine);
|
||||
childSetEnabled("cmd_line_text_4", mCmdLine);
|
||||
childSetEnabled("cmd_line_text_5", mCmdLine);
|
||||
childSetEnabled("cmd_line_text_6", mCmdLine);
|
||||
childSetEnabled("cmd_line_text_7", mCmdLine);
|
||||
childSetEnabled("cmd_line_text_8", mCmdLine);
|
||||
childSetEnabled("cmd_line_text_9", mCmdLine);
|
||||
childSetEnabled("cmd_line_text_10", mCmdLine);
|
||||
childSetEnabled("cmd_line_text_11", mCmdLine);
|
||||
childSetEnabled("cmd_line_text_12", mCmdLine);
|
||||
childSetEnabled("cmd_line_text_13", mCmdLine);
|
||||
childSetEnabled("cmd_line_text_15", mCmdLine);
|
||||
childSetEnabled("AscentCmdLinePos", mCmdLine);
|
||||
childSetEnabled("AscentCmdLineGround", mCmdLine);
|
||||
childSetEnabled("AscentCmdLineHeight", mCmdLine);
|
||||
childSetEnabled("AscentCmdLineTeleportHome", mCmdLine);
|
||||
childSetEnabled("AscentCmdLineRezPlatform", mCmdLine);
|
||||
childSetEnabled("AscentPlatformSize", mCmdLine);
|
||||
childSetEnabled("AscentCmdLineCalc", mCmdLine);
|
||||
childSetEnabled("AscentCmdLineClearChat", mCmdLine);
|
||||
childSetEnabled("AscentCmdLineDrawDistance", mCmdLine);
|
||||
childSetEnabled("AscentCmdTeleportToCam", mCmdLine);
|
||||
childSetEnabled("AscentCmdLineKeyToName", mCmdLine);
|
||||
childSetEnabled("AscentCmdLineOfferTp", mCmdLine);
|
||||
childSetEnabled("AscentCmdLineMapTo", mCmdLine);
|
||||
childSetEnabled("map_to_keep_pos", mCmdLine);
|
||||
childSetEnabled("AscentCmdLineTP2", mCmdLine);
|
||||
childSetEnabled("SinguCmdLineAway", mCmdLine);
|
||||
childSetEnabled("SinguCmdLineURL", mCmdLine);
|
||||
if (LLUICtrl* ctrl = getChild<LLUICtrl>("power_user_confirm_check"))
|
||||
{
|
||||
ctrl->setEnabled(mPowerUser);
|
||||
ctrl->setValue(mPowerUser);
|
||||
}
|
||||
|
||||
//Security ----------------------------------------------------------------------------
|
||||
childSetValue("AscentCmdLinePos", mCmdLinePos);
|
||||
@@ -338,6 +246,9 @@ void LLPrefsAscentSys::refresh()
|
||||
childSetValue("SinguCmdLineAway", mCmdLineAway);
|
||||
childSetValue("SinguCmdLineURL", mCmdLineURL);
|
||||
|
||||
//Security ----------------------------------------------------------------------------
|
||||
getChildView("UISndRestart")->setValue(mRestartSound);
|
||||
|
||||
//Build -------------------------------------------------------------------------------
|
||||
childSetValue("alpha", mAlpha);
|
||||
getChild<LLColorSwatchCtrl>("colorswatch")->setOriginal(mColor);
|
||||
@@ -408,12 +319,16 @@ void LLPrefsAscentSys::cancel()
|
||||
gSavedSettings.setBOOL("PrivateLookAt", mPrivateLookAt);
|
||||
gSavedSettings.setBOOL("AscentShowLookAt", mShowLookAt);
|
||||
gSavedSettings.setBOOL("QuietSnapshotsToDisk", mQuietSnapshotsToDisk);
|
||||
gSavedSettings.setBOOL("AnnounceBumps", mAnnounceBumps);
|
||||
gSavedSettings.setBOOL("SGDetachBridge", mDetachBridge);
|
||||
gSavedSettings.setBOOL("RevokePermsOnStandUp", mRevokePermsOnStandUp);
|
||||
gSavedSettings.setBOOL("DisableClickSit", mDisableClickSit);
|
||||
gSavedSettings.setBOOL("DisableClickSitOtherOwner", mDisableClickSitOtherOwner);
|
||||
gSavedSettings.setBOOL("AscentDisplayTotalScriptJumps", mDisplayScriptJumps);
|
||||
gSavedSettings.setF32("Ascentnumscriptdiff", mNumScriptDiff);
|
||||
gSavedSettings.setBOOL("LiruRegionRestartMinimized", mRestartMinimized);
|
||||
gSavedSettings.setString("UISndRestart", mRestartSound);
|
||||
gSavedPerAccountSettings.setString("EmergencyTeleportLandmark", mLandmark);
|
||||
|
||||
//Build -------------------------------------------------------------------------------
|
||||
gSavedSettings.setF32("EmeraldBuildPrefs_Alpha", mAlpha);
|
||||
|
||||
@@ -48,7 +48,6 @@ public:
|
||||
|
||||
protected:
|
||||
void onCommitCheckBox(LLUICtrl* ctrl, const LLSD& value);
|
||||
void onCommitCmdLine(LLUICtrl* ctrl, const LLSD& value);
|
||||
void onCommitComboBox(LLUICtrl* ctrl, const LLSD& value);
|
||||
void onCommitTexturePicker(LLUICtrl* ctrl);
|
||||
|
||||
@@ -103,12 +102,16 @@ private:
|
||||
bool mPrivateLookAt;
|
||||
bool mShowLookAt;
|
||||
bool mQuietSnapshotsToDisk;
|
||||
bool mAnnounceBumps;
|
||||
bool mDetachBridge;
|
||||
bool mRevokePermsOnStandUp;
|
||||
bool mDisableClickSit;
|
||||
bool mDisableClickSitOtherOwner;
|
||||
bool mDisplayScriptJumps;
|
||||
bool mRestartMinimized;
|
||||
F32 mNumScriptDiff;
|
||||
std::string mRestartSound;
|
||||
std::string mLandmark;
|
||||
|
||||
//Build -------------------------------------------------------------------------------
|
||||
F32 mAlpha;
|
||||
|
||||
@@ -61,14 +61,7 @@ LLPrefsAscentVan::LLPrefsAscentVan()
|
||||
|
||||
getChild<LLUICtrl>("tag_spoofing_combobox")->setCommitCallback(boost::bind(&LLPrefsAscentVan::onCommitClientTag, this, _1));
|
||||
|
||||
getChild<LLUICtrl>("show_my_tag_check")->setCommitCallback(boost::bind(&LLPrefsAscentVan::onCommitCheckBox, this, _1, _2));
|
||||
getChild<LLUICtrl>("show_self_tag_check")->setCommitCallback(boost::bind(&LLPrefsAscentVan::onCommitCheckBox, this, _1, _2));
|
||||
getChild<LLUICtrl>("show_self_tag_color_check")->setCommitCallback(boost::bind(&LLPrefsAscentVan::onCommitCheckBox, this, _1, _2));
|
||||
getChild<LLUICtrl>("customize_own_tag_check")->setCommitCallback(boost::bind(&LLPrefsAscentVan::onCommitCheckBox, this, _1, _2));
|
||||
getChild<LLUICtrl>("show_friend_tag_check")->setCommitCallback(boost::bind(&LLPrefsAscentVan::onCommitCheckBox, this, _1, _2));
|
||||
getChild<LLUICtrl>("use_status_check")->setCommitCallback(boost::bind(&LLPrefsAscentVan::onCommitCheckBox, this, _1, _2));
|
||||
|
||||
getChild<LLUICtrl>("custom_tag_label_box")->setCommitCallback(boost::bind(&LLPrefsAscentVan::onCommitTextModified, this, _1, _2));
|
||||
getChild<LLUICtrl>("custom_tag_label_box")->setCommitCallback(boost::bind(&LLControlGroup::setString, boost::ref(gSavedSettings), "AscentCustomTagLabel", _2));
|
||||
|
||||
getChild<LLUICtrl>("update_clientdefs")->setCommitCallback(boost::bind(LLPrefsAscentVan::onManualClientUpdate));
|
||||
|
||||
@@ -104,14 +97,6 @@ void LLPrefsAscentVan::onCommitClientTag(LLUICtrl* ctrl)
|
||||
}
|
||||
}
|
||||
|
||||
void LLPrefsAscentVan::onCommitTextModified(LLUICtrl* ctrl, const LLSD& value)
|
||||
{
|
||||
if (ctrl->getName() == "custom_tag_label_box")
|
||||
{
|
||||
gSavedSettings.setString("AscentCustomTagLabel", value);
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void LLPrefsAscentVan::onManualClientUpdate()
|
||||
{
|
||||
@@ -127,29 +112,6 @@ void LLPrefsAscentVan::onManualClientUpdate()
|
||||
LLFloaterChat::addChat(chat);
|
||||
}
|
||||
|
||||
void LLPrefsAscentVan::onCommitCheckBox(LLUICtrl* ctrl, const LLSD& value)
|
||||
{
|
||||
// llinfos << "Control named " << ctrl->getControlName() << llendl;
|
||||
|
||||
if (ctrl->getName() == "use_status_check")
|
||||
{
|
||||
bool showCustomColors = value.asBoolean();
|
||||
childSetEnabled("friends_color_textbox", showCustomColors);
|
||||
childSetEnabled("friend_color_swatch", showCustomColors || gSavedSettings.getBOOL("ColorFriendChat"));
|
||||
childSetEnabled("estate_owner_color_swatch", showCustomColors || gSavedSettings.getBOOL("ColorEstateOwnerChat"));
|
||||
childSetEnabled("linden_color_swatch", showCustomColors || gSavedSettings.getBOOL("ColorLindenChat"));
|
||||
childSetEnabled("muted_color_swatch", showCustomColors || gSavedSettings.getBOOL("ColorMutedChat"));
|
||||
}
|
||||
else if (ctrl->getName() == "customize_own_tag_check")
|
||||
{
|
||||
bool showCustomOptions = value.asBoolean();
|
||||
childSetEnabled("custom_tag_label_text", showCustomOptions);
|
||||
childSetEnabled("custom_tag_label_box", showCustomOptions);
|
||||
childSetEnabled("custom_tag_color_text", showCustomOptions);
|
||||
childSetEnabled("custom_tag_color_swatch", showCustomOptions);
|
||||
}
|
||||
}
|
||||
|
||||
// Store current settings for cancel
|
||||
void LLPrefsAscentVan::refreshValues()
|
||||
{
|
||||
|
||||
@@ -48,8 +48,6 @@ public:
|
||||
|
||||
protected:
|
||||
void onCommitClientTag(LLUICtrl* ctrl);
|
||||
void onCommitCheckBox(LLUICtrl* ctrl, const LLSD& value);
|
||||
void onCommitTextModified(LLUICtrl* ctrl, const LLSD& value);
|
||||
static void onManualClientUpdate();
|
||||
|
||||
private:
|
||||
|
||||
@@ -29,8 +29,11 @@
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
#ifndef MS_CHATBARCMDLINE_H
|
||||
#define MS_CHATBARCMDLINE_H
|
||||
|
||||
#include "llchatbar.h"
|
||||
|
||||
bool cmd_line_chat(std::string revised_text, EChatType type);
|
||||
|
||||
#endif
|
||||
@@ -22,6 +22,9 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef SG_GENERICHANDLERS_H
|
||||
#define SG_GENERICHANDLERS_H
|
||||
|
||||
class GenericHandlers
|
||||
{
|
||||
public:
|
||||
@@ -29,3 +32,5 @@ public:
|
||||
};
|
||||
|
||||
extern GenericHandlers *gGenericHandlers;
|
||||
|
||||
#endif // SG_GENERIC_HANDLERS
|
||||
@@ -31,6 +31,9 @@
|
||||
* Modified, debugged, optimized and improved by Henri Beauchamp Feb 2010.
|
||||
*/
|
||||
|
||||
#ifndef JC_FLOATERAREASEARCH_H
|
||||
#define JC_FLOATERAREASEARCH_H
|
||||
|
||||
#include "llfloater.h"
|
||||
#include "lluuid.h"
|
||||
#include "llstring.h"
|
||||
@@ -90,3 +93,5 @@ private:
|
||||
|
||||
std::string mFilterStrings[LIST_OBJECT_COUNT];
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -28,6 +28,8 @@
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef LGG_DICDOWNLOAD_H
|
||||
#define LGG_DICDOWNLOAD_H
|
||||
|
||||
class LggDicDownload
|
||||
{
|
||||
@@ -35,3 +37,4 @@ class LggDicDownload
|
||||
static void show( BOOL showw , std::vector<std::string> shortNames, std::vector<std::string> longNames, void * data);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1507,8 +1507,6 @@ bool LLAppViewer::cleanup()
|
||||
llinfos << "HUD Objects cleaned up" << llendflush;
|
||||
}
|
||||
|
||||
LLKeyframeDataCache::clear();
|
||||
|
||||
// End TransferManager before deleting systems it depends on (Audio, VFS, AssetStorage)
|
||||
#if 0 // this seems to get us stuck in an infinite loop...
|
||||
gTransferManager.cleanup();
|
||||
|
||||
802
indra/newview/llautoreplace.cpp
Normal file
802
indra/newview/llautoreplace.cpp
Normal file
@@ -0,0 +1,802 @@
|
||||
/**
|
||||
* @file llautoreplace.cpp
|
||||
* @brief Auto Replace Manager
|
||||
*
|
||||
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2012, Linden Research, 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; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
#include "llautoreplace.h"
|
||||
#include "llsdserialize.h"
|
||||
#include "llboost.h"
|
||||
#include "llcontrol.h"
|
||||
#include "llviewercontrol.h"
|
||||
#include "llnotificationsutil.h"
|
||||
|
||||
const char* LLAutoReplace::SETTINGS_FILE_NAME = "autoreplace.xml";
|
||||
|
||||
void LLAutoReplace::autoreplaceCallback(S32& replacement_start, S32& replacement_length, LLWString& replacement_string, S32& cursor_pos, const LLWString& input_text)
|
||||
{
|
||||
// make sure these returned values are cleared in case there is no replacement
|
||||
replacement_start = 0;
|
||||
replacement_length = 0;
|
||||
replacement_string.clear();
|
||||
|
||||
static LLCachedControl<bool> perform_autoreplace(gSavedSettings, "AutoReplace", 0);
|
||||
if (perform_autoreplace)
|
||||
{
|
||||
S32 word_end = cursor_pos - 1;
|
||||
|
||||
bool at_space = (input_text[word_end] == ' ');
|
||||
bool have_word = (LLWStringUtil::isPartOfWord(input_text[word_end]));
|
||||
|
||||
if (at_space || have_word)
|
||||
{
|
||||
if (at_space && word_end > 0)
|
||||
{
|
||||
// find out if this space immediately follows a word
|
||||
word_end--;
|
||||
have_word = (LLWStringUtil::isPartOfWord(input_text[word_end]));
|
||||
}
|
||||
if (have_word)
|
||||
{
|
||||
// word_end points to the end of a word, now find the start of the word
|
||||
std::string word;
|
||||
S32 word_start = word_end;
|
||||
for (S32 back_one = word_start - 1;
|
||||
back_one >= 0 && LLWStringUtil::isPartOfWord(input_text[back_one]);
|
||||
back_one--
|
||||
)
|
||||
{
|
||||
word_start--; // walk word_start back to the beginning of the word
|
||||
}
|
||||
LL_DEBUGS("AutoReplace") << "word_start: " << word_start << " word_end: " << word_end << LL_ENDL;
|
||||
std::string str_text = std::string(input_text.begin(), input_text.end());
|
||||
std::string last_word = str_text.substr(word_start, word_end - word_start + 1);
|
||||
std::string replacement_word(mSettings.replaceWord(last_word));
|
||||
|
||||
if (replacement_word != last_word)
|
||||
{
|
||||
// The last word is one for which we have a replacement
|
||||
if (at_space)
|
||||
{
|
||||
// return the replacement string
|
||||
replacement_start = word_start;
|
||||
replacement_length = last_word.length();
|
||||
replacement_string = utf8str_to_wstring(replacement_word);
|
||||
LLWString old_string = utf8str_to_wstring(last_word);
|
||||
S32 size_change = replacement_string.size() - old_string.size();
|
||||
cursor_pos += size_change;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string LLAutoReplace::getUserSettingsFileName()
|
||||
{
|
||||
std::string path=gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "");
|
||||
|
||||
if (!path.empty())
|
||||
{
|
||||
path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, SETTINGS_FILE_NAME);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
std::string LLAutoReplace::getAppSettingsFileName()
|
||||
{
|
||||
std::string path=gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "");
|
||||
|
||||
if (!path.empty())
|
||||
{
|
||||
path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, SETTINGS_FILE_NAME);
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_ERRS("AutoReplace") << "Failed to get app settings directory name" << LL_ENDL;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
LLAutoReplaceSettings LLAutoReplace::getSettings()
|
||||
{
|
||||
return mSettings;
|
||||
}
|
||||
|
||||
void LLAutoReplace::setSettings(const LLAutoReplaceSettings& newSettings)
|
||||
{
|
||||
mSettings.set(newSettings);
|
||||
/// Make the newSettings active and write them to user storage
|
||||
saveToUserSettings();
|
||||
}
|
||||
|
||||
LLAutoReplace::LLAutoReplace()
|
||||
{
|
||||
}
|
||||
|
||||
void LLAutoReplace::initSingleton()
|
||||
{
|
||||
loadFromSettings();
|
||||
}
|
||||
|
||||
void LLAutoReplace::loadFromSettings()
|
||||
{
|
||||
std::string filename=getUserSettingsFileName();
|
||||
if (filename.empty())
|
||||
{
|
||||
LL_INFOS("AutoReplace") << "no valid user settings directory." << LL_ENDL;
|
||||
}
|
||||
if(gDirUtilp->fileExists(filename))
|
||||
{
|
||||
LLSD userSettings;
|
||||
llifstream file;
|
||||
file.open(filename.c_str());
|
||||
if (file.is_open())
|
||||
{
|
||||
LLSDSerialize::fromXML(userSettings, file);
|
||||
}
|
||||
file.close();
|
||||
if ( mSettings.setFromLLSD(userSettings) )
|
||||
{
|
||||
LL_INFOS("AutoReplace") << "settings loaded from '" << filename << "'" << LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "invalid settings found in '" << filename << "'" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
else // no user settings found, try application settings
|
||||
{
|
||||
std::string defaultName = getAppSettingsFileName();
|
||||
LL_INFOS("AutoReplace") << " user settings file '" << filename << "' not found"<< LL_ENDL;
|
||||
|
||||
bool gotSettings = false;
|
||||
if(gDirUtilp->fileExists(defaultName))
|
||||
{
|
||||
LLSD appDefault;
|
||||
llifstream file;
|
||||
file.open(defaultName.c_str());
|
||||
if (file.is_open())
|
||||
{
|
||||
LLSDSerialize::fromXMLDocument(appDefault, file);
|
||||
}
|
||||
file.close();
|
||||
|
||||
if ( mSettings.setFromLLSD(appDefault) )
|
||||
{
|
||||
LL_INFOS("AutoReplace") << "settings loaded from '" << defaultName.c_str() << "'" << LL_ENDL;
|
||||
gotSettings = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "invalid settings found in '" << defaultName.c_str() << "'" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! gotSettings )
|
||||
{
|
||||
if (mSettings.setFromLLSD(mSettings.getExampleLLSD()))
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "no settings found; loaded example." << LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "no settings found and example invalid!" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLAutoReplace::saveToUserSettings()
|
||||
{
|
||||
std::string filename=getUserSettingsFileName();
|
||||
llofstream file;
|
||||
file.open(filename.c_str());
|
||||
LLSDSerialize::toPrettyXML(mSettings.asLLSD(), file);
|
||||
file.close();
|
||||
LL_INFOS("AutoReplace") << "settings saved to '" << filename << "'" << LL_ENDL;
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// LLAutoReplaceSettings
|
||||
// ================================================================
|
||||
|
||||
const std::string LLAutoReplaceSettings::AUTOREPLACE_LIST_NAME = "name"; ///< key for looking up list names
|
||||
const std::string LLAutoReplaceSettings::AUTOREPLACE_LIST_REPLACEMENTS = "replacements"; ///< key for looking up replacement map
|
||||
|
||||
LLAutoReplaceSettings::LLAutoReplaceSettings()
|
||||
{
|
||||
}
|
||||
|
||||
LLAutoReplaceSettings::LLAutoReplaceSettings(const LLAutoReplaceSettings& settings)
|
||||
{
|
||||
// copy all values through fundamental type intermediates for thread safety
|
||||
mLists = LLSD::emptyArray();
|
||||
|
||||
for ( LLSD::array_const_iterator list = settings.mLists.beginArray(), listEnd = settings.mLists.endArray();
|
||||
list != listEnd;
|
||||
list++
|
||||
)
|
||||
{
|
||||
if ( (*list).isMap() ) // can fail due to LLSD-30: ignore it
|
||||
{
|
||||
LLSD listMap = LLSD::emptyMap();
|
||||
std::string listName = (*list)[AUTOREPLACE_LIST_NAME];
|
||||
listMap[AUTOREPLACE_LIST_NAME] = listName;
|
||||
listMap[AUTOREPLACE_LIST_REPLACEMENTS] = LLSD::emptyMap();
|
||||
|
||||
for ( LLSD::map_const_iterator
|
||||
entry = (*list)[AUTOREPLACE_LIST_REPLACEMENTS].beginMap(),
|
||||
entriesEnd = (*list)[AUTOREPLACE_LIST_REPLACEMENTS].endMap();
|
||||
entry != entriesEnd;
|
||||
entry++
|
||||
)
|
||||
{
|
||||
std::string keyword = entry->first;
|
||||
std::string replacement = entry->second.asString();
|
||||
listMap[AUTOREPLACE_LIST_REPLACEMENTS].insert(keyword, LLSD(replacement));
|
||||
}
|
||||
|
||||
mLists.append(listMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLAutoReplaceSettings::set(const LLAutoReplaceSettings& newSettings)
|
||||
{
|
||||
mLists = newSettings.mLists;
|
||||
}
|
||||
|
||||
bool LLAutoReplaceSettings::setFromLLSD(const LLSD& settingsFromLLSD)
|
||||
{
|
||||
bool settingsValid = true;
|
||||
|
||||
if ( settingsFromLLSD.isArray() )
|
||||
{
|
||||
for ( LLSD::array_const_iterator
|
||||
list = settingsFromLLSD.beginArray(),
|
||||
listEnd = settingsFromLLSD.endArray();
|
||||
settingsValid && list != listEnd;
|
||||
list++
|
||||
)
|
||||
{
|
||||
if ( (*list).isDefined() ) // can be undef due to LLSD-30: ignore it
|
||||
{
|
||||
settingsValid = listIsValid(*list);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
settingsValid = false;
|
||||
LL_WARNS("AutoReplace") << "settings are not an array" << LL_ENDL;
|
||||
}
|
||||
|
||||
if ( settingsValid )
|
||||
{
|
||||
mLists = settingsFromLLSD;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "invalid settings discarded; using hard coded example" << LL_ENDL;
|
||||
}
|
||||
|
||||
return settingsValid;
|
||||
}
|
||||
|
||||
bool LLAutoReplaceSettings::listNameMatches( const LLSD& list, const std::string name )
|
||||
{
|
||||
return list.isMap()
|
||||
&& list.has(AUTOREPLACE_LIST_NAME)
|
||||
&& list[AUTOREPLACE_LIST_NAME].asString() == name;
|
||||
}
|
||||
|
||||
const LLSD* LLAutoReplaceSettings::getListEntries(std::string listName)
|
||||
{
|
||||
const LLSD* returnedEntries = NULL;
|
||||
for( LLSD::array_const_iterator list = mLists.beginArray(), endList = mLists.endArray();
|
||||
returnedEntries == NULL && list != endList;
|
||||
list++
|
||||
)
|
||||
{
|
||||
const LLSD& thisList = *list;
|
||||
if ( listNameMatches(thisList, listName) )
|
||||
{
|
||||
returnedEntries = &thisList[AUTOREPLACE_LIST_REPLACEMENTS];
|
||||
}
|
||||
}
|
||||
return returnedEntries;
|
||||
}
|
||||
|
||||
std::string LLAutoReplaceSettings::replacementFor(std::string keyword, std::string listName)
|
||||
{
|
||||
std::string replacement;
|
||||
bool foundList = false;
|
||||
for( LLSD::array_const_iterator list = mLists.beginArray(), endList = mLists.endArray();
|
||||
! foundList && list != endList;
|
||||
list++
|
||||
)
|
||||
{
|
||||
const LLSD& thisList = *list;
|
||||
if ( listNameMatches(thisList, listName) )
|
||||
{
|
||||
foundList = true; // whether there is a replacement or not, we're done
|
||||
if ( thisList.isMap()
|
||||
&& thisList.has(AUTOREPLACE_LIST_REPLACEMENTS)
|
||||
&& thisList[AUTOREPLACE_LIST_REPLACEMENTS].has(keyword)
|
||||
)
|
||||
{
|
||||
replacement = thisList[AUTOREPLACE_LIST_REPLACEMENTS][keyword].asString();
|
||||
LL_DEBUGS("AutoReplace")<<"'"<<keyword<<"' -> '"<<replacement<<"'"<<LL_ENDL;
|
||||
}
|
||||
}
|
||||
if (!foundList)
|
||||
{
|
||||
LL_WARNS("AutoReplace")<<"failed to find list '"<<listName<<"'"<<LL_ENDL;
|
||||
}
|
||||
}
|
||||
if (replacement.empty())
|
||||
{
|
||||
LL_WARNS("AutoReplace")<<"failed to find '"<<keyword<<"'"<<LL_ENDL;
|
||||
}
|
||||
return replacement;
|
||||
}
|
||||
|
||||
LLSD LLAutoReplaceSettings::getListNames()
|
||||
{
|
||||
LL_DEBUGS("AutoReplace")<<"====="<<LL_ENDL;
|
||||
LLSD toReturn = LLSD::emptyArray();
|
||||
S32 counter=0;
|
||||
for( LLSD::array_const_iterator list = mLists.beginArray(), endList = mLists.endArray();
|
||||
list != endList;
|
||||
list++
|
||||
)
|
||||
{
|
||||
const LLSD& thisList = *list;
|
||||
if ( thisList.isMap() )
|
||||
{
|
||||
if ( thisList.has(AUTOREPLACE_LIST_NAME) )
|
||||
{
|
||||
std::string name = thisList[AUTOREPLACE_LIST_NAME].asString();
|
||||
LL_DEBUGS("AutoReplace")<<counter<<" '"<<name<<"'"<<LL_ENDL;
|
||||
toReturn.append(LLSD(name));
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_ERRS("AutoReplace") <<counter<<" ! MISSING "<<AUTOREPLACE_LIST_NAME<< LL_ENDL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace")<<counter<<" ! not a map: "/*<<LLSD::typeString(thisList.type())*/<< LL_ENDL;
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
LL_DEBUGS("AutoReplace")<<"^^^^^^"<<LL_ENDL;
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
bool LLAutoReplaceSettings::listIsValid(const LLSD& list)
|
||||
{
|
||||
bool listValid = true;
|
||||
if ( ! list.isMap() )
|
||||
{
|
||||
listValid = false;
|
||||
LL_WARNS("AutoReplace") << "list is not a map" << LL_ENDL;
|
||||
}
|
||||
else if ( ! list.has(AUTOREPLACE_LIST_NAME)
|
||||
|| ! list[AUTOREPLACE_LIST_NAME].isString()
|
||||
|| list[AUTOREPLACE_LIST_NAME].asString().empty()
|
||||
)
|
||||
{
|
||||
listValid = false;
|
||||
LL_WARNS("AutoReplace")
|
||||
<< "list found without " << AUTOREPLACE_LIST_NAME
|
||||
<< " (or it is empty)"
|
||||
<< LL_ENDL;
|
||||
}
|
||||
else if ( ! list.has(AUTOREPLACE_LIST_REPLACEMENTS) || ! list[AUTOREPLACE_LIST_REPLACEMENTS].isMap() )
|
||||
{
|
||||
listValid = false;
|
||||
LL_WARNS("AutoReplace") << "list '" << list[AUTOREPLACE_LIST_NAME].asString() << "' without " << AUTOREPLACE_LIST_REPLACEMENTS << LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( LLSD::map_const_iterator
|
||||
entry = list[AUTOREPLACE_LIST_REPLACEMENTS].beginMap(),
|
||||
entriesEnd = list[AUTOREPLACE_LIST_REPLACEMENTS].endMap();
|
||||
listValid && entry != entriesEnd;
|
||||
entry++
|
||||
)
|
||||
{
|
||||
if ( ! entry->second.isString() )
|
||||
{
|
||||
listValid = false;
|
||||
LL_WARNS("AutoReplace")
|
||||
<< "non-string replacement value found in list '"
|
||||
<< list[AUTOREPLACE_LIST_NAME].asString() << "'"
|
||||
<< LL_ENDL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return listValid;
|
||||
}
|
||||
|
||||
const LLSD* LLAutoReplaceSettings::exportList(std::string listName)
|
||||
{
|
||||
const LLSD* exportedList = NULL;
|
||||
for ( LLSD::array_const_iterator list = mLists.beginArray(), listEnd = mLists.endArray();
|
||||
exportedList == NULL && list != listEnd;
|
||||
list++
|
||||
)
|
||||
{
|
||||
if ( listNameMatches(*list, listName) )
|
||||
{
|
||||
const LLSD& namedList = (*list);
|
||||
exportedList = &namedList;
|
||||
}
|
||||
}
|
||||
return exportedList;
|
||||
}
|
||||
|
||||
bool LLAutoReplaceSettings::listNameIsUnique(const LLSD& newList)
|
||||
{
|
||||
bool nameIsUnique = true;
|
||||
// this must always be called with a valid list, so it is safe to assume it has a name
|
||||
std::string newListName = newList[AUTOREPLACE_LIST_NAME].asString();
|
||||
for ( LLSD::array_const_iterator list = mLists.beginArray(), listEnd = mLists.endArray();
|
||||
nameIsUnique && list != listEnd;
|
||||
list++
|
||||
)
|
||||
{
|
||||
if ( listNameMatches(*list, newListName) )
|
||||
{
|
||||
LL_WARNS("AutoReplace")<<"duplicate list name '"<<newListName<<"'"<<LL_ENDL;
|
||||
nameIsUnique = false;
|
||||
}
|
||||
}
|
||||
return nameIsUnique;
|
||||
}
|
||||
|
||||
/* static */
|
||||
void LLAutoReplaceSettings::createEmptyList(LLSD& emptyList)
|
||||
{
|
||||
emptyList = LLSD::emptyMap();
|
||||
emptyList[AUTOREPLACE_LIST_NAME] = "Empty";
|
||||
emptyList[AUTOREPLACE_LIST_REPLACEMENTS] = LLSD::emptyMap();
|
||||
}
|
||||
|
||||
/* static */
|
||||
void LLAutoReplaceSettings::setListName(LLSD& list, const std::string& newName)
|
||||
{
|
||||
list[AUTOREPLACE_LIST_NAME] = newName;
|
||||
}
|
||||
|
||||
/* static */
|
||||
std::string LLAutoReplaceSettings::getListName(LLSD& list)
|
||||
{
|
||||
std::string name;
|
||||
if ( list.isMap() && list.has(AUTOREPLACE_LIST_NAME) && list[AUTOREPLACE_LIST_NAME].isString() )
|
||||
{
|
||||
name = list[AUTOREPLACE_LIST_NAME].asString();
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
LLAutoReplaceSettings::AddListResult LLAutoReplaceSettings::addList(const LLSD& newList)
|
||||
{
|
||||
AddListResult result;
|
||||
if ( listIsValid( newList ) )
|
||||
{
|
||||
if ( listNameIsUnique( newList ) )
|
||||
{
|
||||
mLists.append(newList);
|
||||
result = AddListOk;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "attempt to add duplicate name" << LL_ENDL;
|
||||
result = AddListDuplicateName;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "attempt to add invalid list" << LL_ENDL;
|
||||
result = AddListInvalidList;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
LLAutoReplaceSettings::AddListResult LLAutoReplaceSettings::replaceList(const LLSD& newList)
|
||||
{
|
||||
AddListResult result = AddListInvalidList;
|
||||
if ( listIsValid( newList ) )
|
||||
{
|
||||
std::string listName = newList[AUTOREPLACE_LIST_NAME].asString();
|
||||
bool listFound = false;
|
||||
S32 search_index;
|
||||
LLSD targetList;
|
||||
// The following is working around the fact that LLSD arrays containing maps also seem to have undefined entries... see LLSD-30
|
||||
for ( search_index = 0, targetList = mLists[0];
|
||||
!listFound && search_index < mLists.size();
|
||||
search_index += 1, targetList = mLists[search_index]
|
||||
)
|
||||
{
|
||||
if ( targetList.isMap() )
|
||||
{
|
||||
if ( listNameMatches( targetList, listName) )
|
||||
{
|
||||
LL_DEBUGS("AutoReplace")<<"list to replace found at "<<search_index<<LL_ENDL;
|
||||
mLists.erase(search_index);
|
||||
mLists.insert(search_index, newList);
|
||||
listFound = true;
|
||||
result = AddListOk;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! listFound )
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "attempt to replace unconfigured list" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "attempt to add invalid list" << LL_ENDL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool LLAutoReplaceSettings::removeReplacementList(std::string listName)
|
||||
{
|
||||
bool found = false;
|
||||
for( S32 index = 0; !found && mLists[index].isDefined(); index++ )
|
||||
{
|
||||
if( listNameMatches(mLists.get(index), listName) )
|
||||
{
|
||||
LL_DEBUGS("AutoReplace")<<"list '"<<listName<<"'"<<LL_ENDL;
|
||||
mLists.erase(index);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
/// Move the named list up in the priority order
|
||||
bool LLAutoReplaceSettings::increaseListPriority(std::string listName)
|
||||
{
|
||||
LL_DEBUGS("AutoReplace")<<listName<<LL_ENDL;
|
||||
bool found = false;
|
||||
S32 search_index, previous_index;
|
||||
LLSD targetList;
|
||||
// The following is working around the fact that LLSD arrays containing maps also seem to have undefined entries... see LLSD-30
|
||||
previous_index = -1;
|
||||
for ( search_index = 0, targetList = mLists[0];
|
||||
!found && search_index < mLists.size();
|
||||
search_index += 1, targetList = mLists[search_index]
|
||||
)
|
||||
{
|
||||
if ( targetList.isMap() )
|
||||
{
|
||||
if ( listNameMatches( targetList, listName) )
|
||||
{
|
||||
LL_DEBUGS("AutoReplace")<<"found at "<<search_index<<", previous is "<<previous_index<<LL_ENDL;
|
||||
found = true;
|
||||
if (previous_index >= 0)
|
||||
{
|
||||
LL_DEBUGS("AutoReplace") << "erase "<<search_index<<LL_ENDL;
|
||||
mLists.erase(search_index);
|
||||
LL_DEBUGS("AutoReplace") << "insert at "<<previous_index<<LL_ENDL;
|
||||
mLists.insert(previous_index, targetList);
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "attempted to move top list up" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
previous_index = search_index;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//LL_DEBUGS("AutoReplace") << search_index<<" is "<<LLSD::typeString(targetList.type())<<LL_ENDL;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
/// Move the named list down in the priority order
|
||||
bool LLAutoReplaceSettings::decreaseListPriority(std::string listName)
|
||||
{
|
||||
LL_DEBUGS("AutoReplace")<<listName<<LL_ENDL;
|
||||
S32 found_index = -1;
|
||||
S32 search_index;
|
||||
for ( search_index = 0;
|
||||
found_index == -1 && search_index < mLists.size();
|
||||
search_index++
|
||||
)
|
||||
{
|
||||
if ( listNameMatches( mLists[search_index], listName) )
|
||||
{
|
||||
LL_DEBUGS("AutoReplace")<<"found at index "<<search_index<<LL_ENDL;
|
||||
found_index = search_index;
|
||||
}
|
||||
}
|
||||
if (found_index != -1)
|
||||
{
|
||||
S32 next_index;
|
||||
for ( next_index = found_index+1;
|
||||
next_index < mLists.size() && ! mLists[next_index].isMap();
|
||||
next_index++
|
||||
)
|
||||
{
|
||||
// skipping over any undefined slots (see LLSD-30)
|
||||
LL_WARNS("AutoReplace")<<next_index<<" ! not a map: "/*<<LLSD::typeString(mLists[next_index].type())*/<< LL_ENDL;
|
||||
}
|
||||
if ( next_index < mLists.size() )
|
||||
{
|
||||
LLSD next_list = mLists[next_index];
|
||||
LL_DEBUGS("AutoReplace") << "erase "<<next_index<<LL_ENDL;
|
||||
mLists.erase(next_index);
|
||||
LL_DEBUGS("AutoReplace") << "insert at "<<found_index<<LL_ENDL;
|
||||
mLists.insert(found_index, next_list);
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "attempted to move bottom list down" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "not found" << LL_ENDL;
|
||||
}
|
||||
return (found_index != -1);
|
||||
}
|
||||
|
||||
|
||||
std::string LLAutoReplaceSettings::replaceWord(const std::string currentWord)
|
||||
{
|
||||
std::string returnedWord = currentWord; // in case no replacement is found
|
||||
static LLCachedControl<bool> autoreplace_enabled(gSavedSettings, "AutoReplace", false);
|
||||
if ( autoreplace_enabled )
|
||||
{
|
||||
LL_DEBUGS("AutoReplace")<<"checking '"<<currentWord<<"'"<< LL_ENDL;
|
||||
//loop through lists in order
|
||||
bool found = false;
|
||||
for( LLSD::array_const_iterator list = mLists.beginArray(), endLists = mLists.endArray();
|
||||
! found && list != endLists;
|
||||
list++
|
||||
)
|
||||
{
|
||||
const LLSD& checkList = *list;
|
||||
const LLSD& replacements = checkList[AUTOREPLACE_LIST_REPLACEMENTS];
|
||||
|
||||
if ( replacements.has(currentWord) )
|
||||
{
|
||||
found = true;
|
||||
LL_DEBUGS("AutoReplace")
|
||||
<< " found in list '" << checkList[AUTOREPLACE_LIST_NAME].asString()
|
||||
<< " => '" << replacements[currentWord].asString() << "'"
|
||||
<< LL_ENDL;
|
||||
returnedWord = replacements[currentWord].asString();
|
||||
}
|
||||
}
|
||||
}
|
||||
return returnedWord;
|
||||
}
|
||||
|
||||
bool LLAutoReplaceSettings::addEntryToList(LLWString keyword, LLWString replacement, std::string listName)
|
||||
{
|
||||
bool added = false;
|
||||
|
||||
if ( ! keyword.empty() && ! replacement.empty() )
|
||||
{
|
||||
bool isOneWord = true;
|
||||
for (size_t character = 0; isOneWord && character < keyword.size(); character++ )
|
||||
{
|
||||
if ( ! LLWStringUtil::isPartOfWord(keyword[character]) )
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "keyword '" << wstring_to_utf8str(keyword) << "' not a single word (len "<<keyword.size()<<" '"<<character<<"')" << LL_ENDL;
|
||||
isOneWord = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ( isOneWord )
|
||||
{
|
||||
bool listFound = false;
|
||||
for( LLSD::array_iterator list = mLists.beginArray(), endLists = mLists.endArray();
|
||||
! listFound && list != endLists;
|
||||
list++
|
||||
)
|
||||
{
|
||||
if ( listNameMatches(*list, listName) )
|
||||
{
|
||||
listFound = true;
|
||||
(*list)[AUTOREPLACE_LIST_REPLACEMENTS][wstring_to_utf8str(keyword)]=wstring_to_utf8str(replacement);
|
||||
}
|
||||
}
|
||||
if (listFound)
|
||||
{
|
||||
added = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "list '" << listName << "' not found" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return added;
|
||||
}
|
||||
|
||||
bool LLAutoReplaceSettings::removeEntryFromList(std::string keyword, std::string listName)
|
||||
{
|
||||
bool found = false;
|
||||
for( LLSD::array_iterator list = mLists.beginArray(), endLists = mLists.endArray();
|
||||
! found && list != endLists;
|
||||
list++
|
||||
)
|
||||
{
|
||||
if ( listNameMatches(*list, listName) )
|
||||
{
|
||||
found = true;
|
||||
(*list)[AUTOREPLACE_LIST_REPLACEMENTS].erase(keyword);
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
LL_WARNS("AutoReplace") << "list '" << listName << "' not found" << LL_ENDL;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
LLSD LLAutoReplaceSettings::getExampleLLSD()
|
||||
{
|
||||
LL_DEBUGS("AutoReplace")<<LL_ENDL;
|
||||
LLSD example = LLSD::emptyArray();
|
||||
|
||||
example[0] = LLSD::emptyMap();
|
||||
example[0][AUTOREPLACE_LIST_NAME] = "Example List 1";
|
||||
example[0][AUTOREPLACE_LIST_REPLACEMENTS] = LLSD::emptyMap();
|
||||
example[0][AUTOREPLACE_LIST_REPLACEMENTS]["keyword1"] = "replacement string 1";
|
||||
example[0][AUTOREPLACE_LIST_REPLACEMENTS]["keyword2"] = "replacement string 2";
|
||||
|
||||
example[1] = LLSD::emptyMap();
|
||||
example[1][AUTOREPLACE_LIST_NAME] = "Example List 2";
|
||||
example[1][AUTOREPLACE_LIST_REPLACEMENTS] = LLSD::emptyMap();
|
||||
example[1][AUTOREPLACE_LIST_REPLACEMENTS]["mistake1"] = "correction 1";
|
||||
example[1][AUTOREPLACE_LIST_REPLACEMENTS]["mistake2"] = "correction 2";
|
||||
|
||||
return example;
|
||||
}
|
||||
|
||||
const LLSD& LLAutoReplaceSettings::asLLSD()
|
||||
{
|
||||
return mLists;
|
||||
}
|
||||
|
||||
LLAutoReplaceSettings::~LLAutoReplaceSettings()
|
||||
{
|
||||
}
|
||||
227
indra/newview/llautoreplace.h
Normal file
227
indra/newview/llautoreplace.h
Normal file
@@ -0,0 +1,227 @@
|
||||
/**
|
||||
* @file llautoreplace.h
|
||||
* @brief Auto Replace Manager
|
||||
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2012, Linden Research, 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; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
#ifndef LLAUTOREPLACE_H
|
||||
#define LLAUTOREPLACE_H
|
||||
|
||||
#include "lllineeditor.h"
|
||||
|
||||
class LLAutoReplace;
|
||||
|
||||
/** The configuration data for the LLAutoReplace object
|
||||
*
|
||||
* This is a separate class so that the LLFloaterAutoReplaceSettings
|
||||
* can have a copy of the configuration to manipulate before committing
|
||||
* the changes back to the LLAutoReplace singleton that provides the
|
||||
* autoreplace callback.
|
||||
*/
|
||||
class LLAutoReplaceSettings
|
||||
{
|
||||
public:
|
||||
LLAutoReplaceSettings();
|
||||
~LLAutoReplaceSettings();
|
||||
|
||||
/// Constructor for creating a tempory copy of the current settings
|
||||
LLAutoReplaceSettings(const LLAutoReplaceSettings& settings);
|
||||
|
||||
/// Replace the current settings with new ones and save them to the user settings file
|
||||
void set(const LLAutoReplaceSettings& newSettings);
|
||||
|
||||
/// Load the current settings read from an LLSD file
|
||||
bool setFromLLSD(const LLSD& settingsFromLLSD);
|
||||
///< @returns whether or not the settingsFromLLSD were valid
|
||||
|
||||
// ================================================================
|
||||
///@{ @name List Operations
|
||||
// ================================================================
|
||||
|
||||
/// @returns the configured list names as an LLSD Array of strings
|
||||
LLSD getListNames();
|
||||
|
||||
/// Status values returned from the addList method
|
||||
typedef enum
|
||||
{
|
||||
AddListOk,
|
||||
AddListDuplicateName,
|
||||
AddListInvalidList,
|
||||
} AddListResult;
|
||||
|
||||
/// Inserts a new list at the end of the priority order
|
||||
AddListResult addList(const LLSD& newList);
|
||||
|
||||
/// Inserts a list in place of an existing list of the same name
|
||||
AddListResult replaceList(const LLSD& newList);
|
||||
|
||||
/// Removes the named list, @returns false if not found
|
||||
bool removeReplacementList(std::string listName);
|
||||
|
||||
/// Move the named list up in the priority order
|
||||
bool increaseListPriority(std::string listName);
|
||||
///< @returns false if the list is not found
|
||||
|
||||
/// Move the named list down in the priority order
|
||||
bool decreaseListPriority(std::string listName);
|
||||
///< @returns false if the list is not found
|
||||
|
||||
/// Get a copy of just one list (for saving to an export file)
|
||||
const LLSD* exportList(std::string listName);
|
||||
/// @returns an LLSD map
|
||||
|
||||
/// Checks for required elements, and that each has the correct type.
|
||||
bool listIsValid(const LLSD& listSettings);
|
||||
|
||||
/// Checks for required elements, and that each has the correct type.
|
||||
bool listNameIs(const LLSD& listSettings);
|
||||
|
||||
/// Checks to see if a new lists name conflicts with one in the settings
|
||||
bool listNameIsUnique(const LLSD& newList);
|
||||
/// @note must be called with LLSD that has passed listIsValid
|
||||
|
||||
/// Initializes emptyList to an empty list named 'Empty'
|
||||
static void createEmptyList(LLSD& emptyList);
|
||||
|
||||
/// Resets the name of a list to a new value
|
||||
static void setListName(LLSD& list, const std::string& newName);
|
||||
|
||||
/// Gets the name of a list
|
||||
static std::string getListName(LLSD& list);
|
||||
|
||||
///@}
|
||||
// ================================================================
|
||||
///@{ @name Replacement Entry Operations
|
||||
// ================================================================
|
||||
|
||||
/// Get the replacements specified by a given list
|
||||
const LLSD* getListEntries(std::string listName);
|
||||
///< @returns an LLSD Map of keyword -> replacement test pairs
|
||||
|
||||
/// Get the replacement for the keyword from the specified list
|
||||
std::string replacementFor(std::string keyword, std::string listName);
|
||||
|
||||
/// Adds a keywword/replacement pair to the named list
|
||||
bool addEntryToList(LLWString keyword, LLWString replacement, std::string listName);
|
||||
|
||||
/// Removes the keywword and its replacement from the named list
|
||||
bool removeEntryFromList(std::string keyword, std::string listName);
|
||||
|
||||
/**
|
||||
* Look for currentWord in the lists in order, returning any substitution found
|
||||
* If no configured substitution is found, returns currentWord
|
||||
*/
|
||||
std::string replaceWord(const std::string currentWord /**< word to search for */ );
|
||||
|
||||
/// Provides a hard-coded example of settings
|
||||
LLSD getExampleLLSD();
|
||||
|
||||
/// Get the actual settings as LLSD
|
||||
const LLSD& asLLSD();
|
||||
///< @note for use only in AutoReplace::saveToUserSettings
|
||||
|
||||
private:
|
||||
/// Efficiently and safely compare list names
|
||||
bool listNameMatches( const LLSD& list, const std::string name );
|
||||
|
||||
/// The actual llsd data structure
|
||||
LLSD mLists;
|
||||
|
||||
static const std::string AUTOREPLACE_LIST_NAME; ///< key for looking up list names
|
||||
static const std::string AUTOREPLACE_LIST_REPLACEMENTS; ///< key for looking up replacement map
|
||||
|
||||
/**<
|
||||
* LLSD structure of the lists
|
||||
* - The configuration is an array (mLists),
|
||||
* - Each entry in the array is a replacement list
|
||||
* - Each replacement list is a map with three keys:
|
||||
* @verbatim
|
||||
* "name" String the name of the list
|
||||
* "replacements" Map keyword -> replacement pairs
|
||||
*
|
||||
* <llsd>
|
||||
* <array>
|
||||
* <map>
|
||||
* <key>name</key> <string>List 1</string>
|
||||
* <key>data</key>
|
||||
* <map>
|
||||
* <key>keyword1</key> <string>replacement1</string>
|
||||
* <key>keyword2</key> <string>replacement2</string>
|
||||
* </map>
|
||||
* </map>
|
||||
* <map>
|
||||
* <key>name</key> <string>List 2</string>
|
||||
* <key>data</key>
|
||||
* <map>
|
||||
* <key>keyword1</key> <string>replacement1</string>
|
||||
* <key>keyword2</key> <string>replacement2</string>
|
||||
* </map>
|
||||
* </map>
|
||||
* </array>
|
||||
* </llsd>
|
||||
* @endverbatim
|
||||
*/
|
||||
};
|
||||
|
||||
/** Provides a facility to auto-replace text dynamically as it is entered.
|
||||
*
|
||||
* When the end of a word is detected (defined as any punctuation character,
|
||||
* or any whitespace except newline or return), the preceding word is used
|
||||
* as a lookup key in an ordered list of maps. If a match is found in any
|
||||
* map, the replacement start index and length are returned along with the
|
||||
* new replacement string.
|
||||
*
|
||||
* See the autoreplaceCallback method for how to add autoreplace functionality
|
||||
* to a text entry tool.
|
||||
*/
|
||||
class LLAutoReplace : public LLSingleton<LLAutoReplace>
|
||||
{
|
||||
public:
|
||||
/// Callback that provides the hook for use in text entry methods
|
||||
void autoreplaceCallback(S32& replacement_start, S32& replacement_length, LLWString& replacement_string, S32& cursor_pos, const LLWString& input_text);
|
||||
|
||||
/// Get a copy of the current settings
|
||||
LLAutoReplaceSettings getSettings();
|
||||
|
||||
/// Commit new settings after making changes
|
||||
void setSettings(const LLAutoReplaceSettings& settings);
|
||||
|
||||
private:
|
||||
friend class LLSingleton<LLAutoReplace>;
|
||||
LLAutoReplace();
|
||||
/*virtual*/ void initSingleton();
|
||||
|
||||
LLAutoReplaceSettings mSettings; ///< configuration information
|
||||
|
||||
/// Read settings from persistent storage
|
||||
void loadFromSettings();
|
||||
|
||||
/// Make the newSettings active and write them to user storage
|
||||
void saveToUserSettings();
|
||||
|
||||
/// Compute the user settings file name
|
||||
std::string getUserSettingsFileName();
|
||||
|
||||
/// Compute the (read-ony) application settings file name
|
||||
std::string getAppSettingsFileName();
|
||||
|
||||
/// basename for the settings files
|
||||
static const char* SETTINGS_FILE_NAME;
|
||||
};
|
||||
|
||||
#endif /* LLAUTOREPLACE_H */
|
||||
@@ -44,6 +44,7 @@
|
||||
#include "llfocusmgr.h"
|
||||
|
||||
#include "llagent.h"
|
||||
#include "llautoreplace.h"
|
||||
#include "llbutton.h"
|
||||
#include "llcombobox.h"
|
||||
#include "llcommandhandler.h" // secondlife:///app/chat/ support
|
||||
@@ -149,6 +150,7 @@ BOOL LLChatBar::postBuild()
|
||||
mInputEditor = findChild<LLLineEditor>("Chat Editor");
|
||||
if (mInputEditor)
|
||||
{
|
||||
mInputEditor->setAutoreplaceCallback(boost::bind(&LLAutoReplace::autoreplaceCallback, LLAutoReplace::getInstance(), _1, _2, _3, _4, _5));
|
||||
mInputEditor->setKeystrokeCallback(boost::bind(&LLChatBar::onInputEditorKeystroke,this));
|
||||
mInputEditor->setFocusLostCallback(boost::bind(&LLChatBar::onInputEditorFocusLost));
|
||||
mInputEditor->setFocusReceivedCallback(boost::bind(&LLChatBar::onInputEditorGainFocus));
|
||||
|
||||
@@ -145,6 +145,11 @@ void LLDropTarget::setControlName(const std::string& control_name, LLView* conte
|
||||
else
|
||||
{
|
||||
mControl = gSavedPerAccountSettings.getControl(control_name);
|
||||
if (!mControl)
|
||||
{
|
||||
llerrs << "Could not find control \"" << control_name << "\" in gSavedPerAccountSettings" << llendl;
|
||||
return; // Though this should never happen.
|
||||
}
|
||||
const LLUUID id(mControl->getValue().asString());
|
||||
if (id.isNull())
|
||||
text = LLTrans::getString("CurrentlyNotSet");
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
// LLEmote()
|
||||
// Class Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
LLEmote::LLEmote(const LLUUID &id) : LLMotion(id)
|
||||
LLEmote::LLEmote(LLUUID const& id, LLMotionController* controller) : LLMotion(id, controller)
|
||||
{
|
||||
mCharacter = NULL;
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ class LLEmote :
|
||||
{
|
||||
public:
|
||||
// Constructor
|
||||
LLEmote(const LLUUID &id);
|
||||
LLEmote(LLUUID const& id, LLMotionController* controller);
|
||||
|
||||
// Destructor
|
||||
virtual ~LLEmote();
|
||||
@@ -67,7 +67,7 @@ public:
|
||||
|
||||
// static constructor
|
||||
// all subclasses must implement such a function and register it
|
||||
static LLMotion *create(const LLUUID &id) { return new LLEmote(id); }
|
||||
static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLEmote(id, controller); }
|
||||
|
||||
public:
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
@@ -50,7 +50,6 @@
|
||||
#include "llviewerstats.h"
|
||||
#include "llviewerregion.h"
|
||||
#include "sgversion.h"
|
||||
#include "llviewerbuild.h"
|
||||
#include "lluictrlfactory.h"
|
||||
#include "lluri.h"
|
||||
#include "llweb.h"
|
||||
@@ -141,7 +140,7 @@ LLFloaterAbout::LLFloaterAbout()
|
||||
+ " (64 bit)"
|
||||
#endif
|
||||
+ llformat(" %d.%d.%d (%d) %s %s (%s)\n",
|
||||
gVersionMajor, gVersionMinor, gVersionPatch, LL_VIEWER_BUILD,
|
||||
gVersionMajor, gVersionMinor, gVersionPatch, gVersionBuild,
|
||||
__DATE__, __TIME__,
|
||||
gVersionChannel));
|
||||
support_widget->appendColoredText(version, FALSE, FALSE, gColors.getColor("TextFgReadOnlyColor"));
|
||||
|
||||
632
indra/newview/llfloaterautoreplacesettings.cpp
Normal file
632
indra/newview/llfloaterautoreplacesettings.cpp
Normal file
@@ -0,0 +1,632 @@
|
||||
/**
|
||||
* @file llfloaterautoreplacesettings.cpp
|
||||
* @brief Auto Replace List floater
|
||||
*
|
||||
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2012, Linden Research, 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; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llfloaterautoreplacesettings.h"
|
||||
|
||||
#include "statemachine/aifilepicker.h"
|
||||
#include "llscrolllistctrl.h"
|
||||
#include "lluictrlfactory.h"
|
||||
|
||||
#include "llautoreplace.h"
|
||||
#include "llsdserialize.h"
|
||||
#include "llsdutil.h"
|
||||
|
||||
#include <boost/tokenizer.hpp>
|
||||
|
||||
#include "llnotificationsutil.h"
|
||||
|
||||
|
||||
LLFloaterAutoReplaceSettings::LLFloaterAutoReplaceSettings(const LLSD& key)
|
||||
: LLFloater(/*key*/)
|
||||
, mSelectedListName("")
|
||||
, mListNames(NULL)
|
||||
, mReplacementsList(NULL)
|
||||
, mKeyword(NULL)
|
||||
, mPreviousKeyword("")
|
||||
, mReplacement(NULL)
|
||||
{
|
||||
LLUICtrlFactory::getInstance()->buildFloater(this, "floater_autoreplace.xml");
|
||||
}
|
||||
|
||||
BOOL LLFloaterAutoReplaceSettings::postBuild(void)
|
||||
{
|
||||
// get copies of the current settings that we will operate on
|
||||
mEnabled = gSavedSettings.getBOOL("AutoReplace");
|
||||
LL_DEBUGS("AutoReplace") << ( mEnabled ? "enabled" : "disabled") << LL_ENDL;
|
||||
|
||||
mSettings = LLAutoReplace::getInstance()->getSettings();
|
||||
|
||||
// global checkbox for whether or not autoreplace is active
|
||||
LLUICtrl* enabledCheckbox = getChild<LLUICtrl>("autoreplace_enable");
|
||||
enabledCheckbox->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onAutoReplaceToggled, this));
|
||||
enabledCheckbox->setValue(LLSD(mEnabled));
|
||||
|
||||
// top row list creation and deletion
|
||||
getChild<LLUICtrl>("autoreplace_import_list")->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onImportList,this));
|
||||
getChild<LLUICtrl>("autoreplace_export_list")->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onExportList,this));
|
||||
getChild<LLUICtrl>("autoreplace_new_list")->setCommitCallback( boost::bind(&LLFloaterAutoReplaceSettings::onNewList,this));
|
||||
getChild<LLUICtrl>("autoreplace_delete_list")->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onDeleteList,this));
|
||||
|
||||
// the list of keyword->replacement lists
|
||||
mListNames = getChild<LLScrollListCtrl>("autoreplace_list_name");
|
||||
mListNames->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onSelectList, this));
|
||||
mListNames->setCommitOnSelectionChange(true);
|
||||
|
||||
// list ordering
|
||||
getChild<LLUICtrl>("autoreplace_list_up")->setCommitCallback( boost::bind(&LLFloaterAutoReplaceSettings::onListUp,this));
|
||||
getChild<LLUICtrl>("autoreplace_list_down")->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onListDown,this));
|
||||
|
||||
// keyword->replacement entry add / delete
|
||||
getChild<LLUICtrl>("autoreplace_add_entry")->setCommitCallback( boost::bind(&LLFloaterAutoReplaceSettings::onAddEntry,this));
|
||||
getChild<LLUICtrl>("autoreplace_delete_entry")->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onDeleteEntry,this));
|
||||
|
||||
// entry edits
|
||||
mKeyword = getChild<LLLineEditor>("autoreplace_keyword");
|
||||
mReplacement = getChild<LLLineEditor>("autoreplace_replacement");
|
||||
getChild<LLUICtrl>("autoreplace_save_entry")->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onSaveEntry, this));
|
||||
|
||||
// dialog termination ( Save Changes / Cancel )
|
||||
getChild<LLUICtrl>("autoreplace_save_changes")->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onSaveChanges, this));
|
||||
getChild<LLUICtrl>("autoreplace_cancel")->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::close, this, false));
|
||||
|
||||
// the list of keyword->replacement pairs
|
||||
mReplacementsList = getChild<LLScrollListCtrl>("autoreplace_list_replacements");
|
||||
mReplacementsList->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onSelectEntry, this));
|
||||
mReplacementsList->setCommitOnSelectionChange(true);
|
||||
|
||||
center();
|
||||
|
||||
mSelectedListName.clear();
|
||||
updateListNames();
|
||||
updateListNamesControls();
|
||||
updateReplacementsList();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void LLFloaterAutoReplaceSettings::updateListNames()
|
||||
{
|
||||
mListNames->deleteAllItems(); // start from scratch
|
||||
|
||||
LLSD listNames = mSettings.getListNames(); // Array of Strings
|
||||
|
||||
for ( LLSD::array_const_iterator entry = listNames.beginArray(), end = listNames.endArray();
|
||||
entry != end;
|
||||
++entry
|
||||
)
|
||||
{
|
||||
const std::string& listName = entry->asString();
|
||||
mListNames->addSimpleElement(listName);
|
||||
}
|
||||
|
||||
if (!mSelectedListName.empty())
|
||||
{
|
||||
mListNames->setSelectedByValue( LLSD(mSelectedListName), true );
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterAutoReplaceSettings::updateListNamesControls()
|
||||
{
|
||||
if ( mSelectedListName.empty() )
|
||||
{
|
||||
// There is no selected list
|
||||
|
||||
// Disable all controls that operate on the selected list
|
||||
getChild<LLButton>("autoreplace_export_list")->setEnabled(false);
|
||||
getChild<LLButton>("autoreplace_delete_list")->setEnabled(false);
|
||||
getChild<LLButton>("autoreplace_list_up")->setEnabled(false);
|
||||
getChild<LLButton>("autoreplace_list_down")->setEnabled(false);
|
||||
|
||||
mReplacementsList->deleteAllItems();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Enable the controls that operate on the selected list
|
||||
getChild<LLButton>("autoreplace_export_list")->setEnabled(true);
|
||||
getChild<LLButton>("autoreplace_delete_list")->setEnabled(true);
|
||||
getChild<LLButton>("autoreplace_list_up")->setEnabled(!selectedListIsFirst());
|
||||
getChild<LLButton>("autoreplace_list_down")->setEnabled(!selectedListIsLast());
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterAutoReplaceSettings::onSelectList()
|
||||
{
|
||||
std::string previousSelectedListName = mSelectedListName;
|
||||
// only one selection allowed
|
||||
LLSD selected = mListNames->getSelectedValue();
|
||||
if (selected.isDefined())
|
||||
{
|
||||
mSelectedListName = selected.asString();
|
||||
LL_DEBUGS("AutoReplace")<<"selected list '"<<mSelectedListName<<"'"<<LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
mSelectedListName.clear();
|
||||
LL_DEBUGS("AutoReplace")<<"unselected"<<LL_ENDL;
|
||||
}
|
||||
|
||||
updateListNamesControls();
|
||||
|
||||
if ( previousSelectedListName != mSelectedListName )
|
||||
{
|
||||
updateReplacementsList();
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterAutoReplaceSettings::onSelectEntry()
|
||||
{
|
||||
LLSD selectedRow = mReplacementsList->getSelectedValue();
|
||||
if (selectedRow.isDefined())
|
||||
{
|
||||
mPreviousKeyword = selectedRow.asString();
|
||||
LL_DEBUGS("AutoReplace")<<"selected entry '"<<mPreviousKeyword<<"'"<<LL_ENDL;
|
||||
mKeyword->setValue(selectedRow);
|
||||
std::string replacement = mSettings.replacementFor(mPreviousKeyword, mSelectedListName );
|
||||
mReplacement->setValue(replacement);
|
||||
enableReplacementEntry();
|
||||
mReplacement->setFocus(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// no entry selection, so the entry panel should be off
|
||||
disableReplacementEntry();
|
||||
LL_DEBUGS("AutoReplace")<<"no row selected"<<LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterAutoReplaceSettings::updateReplacementsList()
|
||||
{
|
||||
// start from scratch, since this should only be called when the list changes
|
||||
mReplacementsList->deleteAllItems();
|
||||
|
||||
if ( mSelectedListName.empty() )
|
||||
{
|
||||
mReplacementsList->setEnabled(false);
|
||||
getChild<LLButton>("autoreplace_add_entry")->setEnabled(false);
|
||||
disableReplacementEntry();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Populate the keyword->replacement list from the selected list
|
||||
const LLSD* mappings = mSettings.getListEntries(mSelectedListName);
|
||||
for ( LLSD::map_const_iterator entry = mappings->beginMap(), end = mappings->endMap();
|
||||
entry != end;
|
||||
entry++
|
||||
)
|
||||
{
|
||||
LLSD row;
|
||||
row["id"] = entry->first;
|
||||
row["columns"][0]["column"] = "Keyword";
|
||||
row["columns"][0]["value"] = entry->first;
|
||||
row["columns"][1]["column"] = "Replacement";
|
||||
row["columns"][1]["value"] = entry->second;
|
||||
|
||||
mReplacementsList->addElement(row, ADD_BOTTOM);
|
||||
}
|
||||
|
||||
mReplacementsList->deselectAllItems(false /* don't call commit */);
|
||||
mReplacementsList->setEnabled(true);
|
||||
|
||||
getChild<LLButton>("autoreplace_add_entry")->setEnabled(true);
|
||||
disableReplacementEntry();
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterAutoReplaceSettings::enableReplacementEntry()
|
||||
{
|
||||
LL_DEBUGS("AutoReplace")<<LL_ENDL;
|
||||
mKeyword->setEnabled(true);
|
||||
mReplacement->setEnabled(true);
|
||||
getChild<LLButton>("autoreplace_save_entry")->setEnabled(true);
|
||||
getChild<LLButton>("autoreplace_delete_entry")->setEnabled(true);
|
||||
}
|
||||
|
||||
void LLFloaterAutoReplaceSettings::disableReplacementEntry()
|
||||
{
|
||||
LL_DEBUGS("AutoReplace")<<LL_ENDL;
|
||||
mPreviousKeyword.clear();
|
||||
mKeyword->clear();
|
||||
mKeyword->setEnabled(false);
|
||||
mReplacement->clear();
|
||||
mReplacement->setEnabled(false);
|
||||
getChild<LLButton>("autoreplace_save_entry")->setEnabled(false);
|
||||
getChild<LLButton>("autoreplace_delete_entry")->setEnabled(false);
|
||||
}
|
||||
|
||||
// called when the global settings checkbox is changed
|
||||
void LLFloaterAutoReplaceSettings::onAutoReplaceToggled()
|
||||
{
|
||||
// set our local copy of the flag, copied to the global preference in onOk
|
||||
mEnabled = childGetValue("autoreplace_enable").asBoolean();
|
||||
LL_DEBUGS("AutoReplace")<< "autoreplace_enable " << ( mEnabled ? "on" : "off" ) << LL_ENDL;
|
||||
}
|
||||
|
||||
// called when the List Up button is pressed
|
||||
void LLFloaterAutoReplaceSettings::onListUp()
|
||||
{
|
||||
S32 selectedRow = mListNames->getFirstSelectedIndex();
|
||||
LLSD selectedName = mListNames->getSelectedValue().asString();
|
||||
|
||||
if ( mSettings.increaseListPriority(selectedName) )
|
||||
{
|
||||
updateListNames();
|
||||
updateListNamesControls();
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace")
|
||||
<< "invalid row ("<<selectedRow<<") selected '"<<selectedName<<"'"
|
||||
<<LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
// called when the List Down button is pressed
|
||||
void LLFloaterAutoReplaceSettings::onListDown()
|
||||
{
|
||||
S32 selectedRow = mListNames->getFirstSelectedIndex();
|
||||
std::string selectedName = mListNames->getSelectedValue().asString();
|
||||
|
||||
if ( mSettings.decreaseListPriority(selectedName) )
|
||||
{
|
||||
updateListNames();
|
||||
updateListNamesControls();
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace")
|
||||
<< "invalid row ("<<selectedRow<<") selected '"<<selectedName<<"'"
|
||||
<<LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
// called when the Delete Entry button is pressed
|
||||
void LLFloaterAutoReplaceSettings::onDeleteEntry()
|
||||
{
|
||||
LLSD selectedRow = mReplacementsList->getSelectedValue();
|
||||
if (selectedRow.isDefined())
|
||||
{
|
||||
std::string keyword = selectedRow.asString();
|
||||
mReplacementsList->deleteSelectedItems(); // delete from the control
|
||||
mSettings.removeEntryFromList(keyword, mSelectedListName); // delete from the local settings copy
|
||||
disableReplacementEntry(); // no selection active, so turn off the buttons
|
||||
}
|
||||
}
|
||||
|
||||
// called when the Import List button is pressed
|
||||
void LLFloaterAutoReplaceSettings::onImportList()
|
||||
{
|
||||
AIFilePicker* picker = AIFilePicker::create();
|
||||
picker->open(FFLOAD_XML, "", "autoreplace");
|
||||
picker->run(boost::bind(&LLFloaterAutoReplaceSettings::onImportList_continued, this, picker));
|
||||
}
|
||||
|
||||
void LLFloaterAutoReplaceSettings::onImportList_continued(AIFilePicker* picker)
|
||||
{
|
||||
if (picker->hasFilename())
|
||||
{
|
||||
llifstream file;
|
||||
file.open(picker->getFilename());
|
||||
LLSD newList;
|
||||
if (file.is_open())
|
||||
{
|
||||
LLSDSerialize::fromXMLDocument(newList, file);
|
||||
}
|
||||
file.close();
|
||||
|
||||
switch ( mSettings.addList(newList) )
|
||||
{
|
||||
case LLAutoReplaceSettings::AddListOk:
|
||||
mSelectedListName = LLAutoReplaceSettings::getListName(newList);
|
||||
|
||||
updateListNames();
|
||||
updateListNamesControls();
|
||||
updateReplacementsList();
|
||||
break;
|
||||
|
||||
case LLAutoReplaceSettings::AddListDuplicateName:
|
||||
{
|
||||
std::string newName = LLAutoReplaceSettings::getListName(newList);
|
||||
LL_WARNS("AutoReplace")<<"name '"<<newName<<"' is in use; prompting for new name"<<LL_ENDL;
|
||||
LLSD newPayload;
|
||||
newPayload["list"] = newList;
|
||||
LLSD args;
|
||||
args["DUPNAME"] = newName;
|
||||
|
||||
LLNotificationsUtil::add("RenameAutoReplaceList", args, newPayload,
|
||||
boost::bind(&LLFloaterAutoReplaceSettings::callbackListNameConflict, this, _1, _2));
|
||||
}
|
||||
break;
|
||||
|
||||
case LLAutoReplaceSettings::AddListInvalidList:
|
||||
LLNotificationsUtil::add("InvalidAutoReplaceList");
|
||||
LL_WARNS("AutoReplace") << "imported list was invalid" << LL_ENDL;
|
||||
|
||||
mSelectedListName.clear();
|
||||
updateListNames();
|
||||
updateListNamesControls();
|
||||
updateReplacementsList();
|
||||
break;
|
||||
|
||||
default:
|
||||
LL_ERRS("AutoReplace") << "invalid AddListResult" << LL_ENDL;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_DEBUGS("AutoReplace") << "file selection failed for import list" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterAutoReplaceSettings::onNewList()
|
||||
{
|
||||
LLSD payload;
|
||||
LLSD emptyList;
|
||||
LLAutoReplaceSettings::createEmptyList(emptyList);
|
||||
payload["list"] = emptyList;
|
||||
LLSD args;
|
||||
|
||||
LLNotificationsUtil::add("AddAutoReplaceList", args, payload,
|
||||
boost::bind(&LLFloaterAutoReplaceSettings::callbackNewListName, this, _1, _2));
|
||||
}
|
||||
|
||||
bool LLFloaterAutoReplaceSettings::callbackNewListName(const LLSD& notification, const LLSD& response)
|
||||
{
|
||||
LL_DEBUGS("AutoReplace")<<"called"<<LL_ENDL;
|
||||
|
||||
LLSD newList = notification["payload"]["list"];
|
||||
|
||||
if ( response.has("listname") && response["listname"].isString() )
|
||||
{
|
||||
std::string newName = response["listname"].asString();
|
||||
LLAutoReplaceSettings::setListName(newList, newName);
|
||||
|
||||
switch ( mSettings.addList(newList) )
|
||||
{
|
||||
case LLAutoReplaceSettings::AddListOk:
|
||||
LL_INFOS("AutoReplace") << "added new list '"<<newName<<"'"<<LL_ENDL;
|
||||
mSelectedListName = newName;
|
||||
updateListNames();
|
||||
updateListNamesControls();
|
||||
updateReplacementsList();
|
||||
break;
|
||||
|
||||
case LLAutoReplaceSettings::AddListDuplicateName:
|
||||
{
|
||||
LL_WARNS("AutoReplace")<<"name '"<<newName<<"' is in use; prompting for new name"<<LL_ENDL;
|
||||
LLSD newPayload;
|
||||
newPayload["list"] = notification["payload"]["list"];
|
||||
LLSD args;
|
||||
args["DUPNAME"] = newName;
|
||||
|
||||
LLNotificationsUtil::add("RenameAutoReplaceList", args, newPayload,
|
||||
boost::bind(&LLFloaterAutoReplaceSettings::callbackListNameConflict, this, _1, _2));
|
||||
}
|
||||
break;
|
||||
|
||||
case LLAutoReplaceSettings::AddListInvalidList:
|
||||
LLNotificationsUtil::add("InvalidAutoReplaceList");
|
||||
|
||||
mSelectedListName.clear();
|
||||
updateListNames();
|
||||
updateListNamesControls();
|
||||
updateReplacementsList();
|
||||
break;
|
||||
|
||||
default:
|
||||
LL_ERRS("AutoReplace") << "invalid AddListResult" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_ERRS("AutoReplace") << "adding notification response" << LL_ENDL;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// callback for the RenameAutoReplaceList notification
|
||||
bool LLFloaterAutoReplaceSettings::callbackListNameConflict(const LLSD& notification, const LLSD& response)
|
||||
{
|
||||
LLSD newList = notification["payload"]["list"];
|
||||
std::string listName = LLAutoReplaceSettings::getListName(newList);
|
||||
|
||||
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
|
||||
switch ( option )
|
||||
{
|
||||
case 0:
|
||||
// Replace current list
|
||||
if ( LLAutoReplaceSettings::AddListOk == mSettings.replaceList(newList) )
|
||||
{
|
||||
LL_INFOS("AutoReplace") << "replaced list '"<<listName<<"'"<<LL_ENDL;
|
||||
mSelectedListName = listName;
|
||||
updateListNames();
|
||||
updateListNamesControls();
|
||||
updateReplacementsList();
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace")<<"failed to replace list '"<<listName<<"'"<<LL_ENDL;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
// Use New Name
|
||||
LL_INFOS("AutoReplace")<<"option 'use new name' selected"<<LL_ENDL;
|
||||
callbackNewListName(notification, response);
|
||||
break;
|
||||
|
||||
default:
|
||||
LL_ERRS("AutoReplace")<<"invalid selected option "<<option<<LL_ENDL;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void LLFloaterAutoReplaceSettings::onDeleteList()
|
||||
{
|
||||
std::string listName = mListNames->getSelectedValue().asString();
|
||||
if ( ! listName.empty() )
|
||||
{
|
||||
if ( mSettings.removeReplacementList(listName) )
|
||||
{
|
||||
LL_INFOS("AutoReplace")<<"deleted list '"<<listName<<"'"<<LL_ENDL;
|
||||
mReplacementsList->deleteSelectedItems(); // remove from the scrolling list
|
||||
mSelectedListName.clear();
|
||||
updateListNames();
|
||||
updateListNamesControls();
|
||||
updateReplacementsList();
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("AutoReplace")<<"failed to delete list '"<<listName<<"'"<<LL_ENDL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_DEBUGS("AutoReplace")<<"no list selected for delete"<<LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterAutoReplaceSettings::onExportList()
|
||||
{
|
||||
std::string listName=mListNames->getFirstSelected()->getColumn(0)->getValue().asString();
|
||||
std::string listFileName = listName + ".xml";
|
||||
AIFilePicker* picker = AIFilePicker::create();
|
||||
picker->open(listFileName, FFSAVE_XML, "", "autoreplace");
|
||||
picker->run(boost::bind(&LLFloaterAutoReplaceSettings::onExportList_continued, this, picker, mSettings.exportList(listName)));
|
||||
}
|
||||
void LLFloaterAutoReplaceSettings::onExportList_continued(AIFilePicker* picker, const LLSD* list)
|
||||
{
|
||||
if (picker->hasFilename())
|
||||
{
|
||||
llofstream file;
|
||||
file.open(picker->getFilename());
|
||||
LLSDSerialize::toPrettyXML(*list, file);
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterAutoReplaceSettings::onAddEntry()
|
||||
{
|
||||
mPreviousKeyword.clear();
|
||||
mReplacementsList->deselectAllItems(false /* don't call commit */);
|
||||
mKeyword->clear();
|
||||
mReplacement->clear();
|
||||
enableReplacementEntry();
|
||||
mKeyword->setFocus(true);
|
||||
}
|
||||
|
||||
void LLFloaterAutoReplaceSettings::onSaveEntry()
|
||||
{
|
||||
LL_DEBUGS("AutoReplace")<<"called"<<LL_ENDL;
|
||||
|
||||
if ( ! mPreviousKeyword.empty() )
|
||||
{
|
||||
// delete any existing value for the key that was editted
|
||||
LL_INFOS("AutoReplace")
|
||||
<< "list '" << mSelectedListName << "' "
|
||||
<< "removed '" << mPreviousKeyword
|
||||
<< "'" << LL_ENDL;
|
||||
mSettings.removeEntryFromList( mPreviousKeyword, mSelectedListName );
|
||||
}
|
||||
|
||||
LLWString keyword = mKeyword->getWText();
|
||||
LLWString replacement = mReplacement->getWText();
|
||||
if ( mSettings.addEntryToList(keyword, replacement, mSelectedListName) )
|
||||
{
|
||||
// insert the new keyword->replacement pair
|
||||
LL_INFOS("AutoReplace")
|
||||
<< "list '" << mSelectedListName << "' "
|
||||
<< "added '" << wstring_to_utf8str(keyword)
|
||||
<< "' -> '" << wstring_to_utf8str(replacement)
|
||||
<< "'" << LL_ENDL;
|
||||
|
||||
updateReplacementsList();
|
||||
}
|
||||
else
|
||||
{
|
||||
LLNotificationsUtil::add("InvalidAutoReplaceEntry");
|
||||
LL_WARNS("AutoReplace")<<"invalid entry "
|
||||
<< "keyword '" << wstring_to_utf8str(keyword)
|
||||
<< "' replacement '" << wstring_to_utf8str(replacement)
|
||||
<< "'" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterAutoReplaceSettings::onSaveChanges()
|
||||
{
|
||||
// put our local copy of the settings into the active copy
|
||||
LLAutoReplace::getInstance()->setSettings( mSettings );
|
||||
// save our local copy of the global feature enable/disable value
|
||||
gSavedSettings.setBOOL("AutoReplace", mEnabled);
|
||||
close();
|
||||
}
|
||||
|
||||
bool LLFloaterAutoReplaceSettings::selectedListIsFirst()
|
||||
{
|
||||
bool isFirst = false;
|
||||
|
||||
if (!mSelectedListName.empty())
|
||||
{
|
||||
LLSD lists = mSettings.getListNames(); // an Array of Strings
|
||||
LLSD first = lists.get(0);
|
||||
if ( first.isString() && first.asString() == mSelectedListName )
|
||||
{
|
||||
isFirst = true;
|
||||
}
|
||||
}
|
||||
return isFirst;
|
||||
}
|
||||
|
||||
bool LLFloaterAutoReplaceSettings::selectedListIsLast()
|
||||
{
|
||||
bool isLast = false;
|
||||
|
||||
if (!mSelectedListName.empty())
|
||||
{
|
||||
LLSD last;
|
||||
LLSD lists = mSettings.getListNames(); // an Array of Strings
|
||||
for ( LLSD::array_const_iterator list = lists.beginArray(), listEnd = lists.endArray();
|
||||
list != listEnd;
|
||||
list++
|
||||
)
|
||||
{
|
||||
last = *list;
|
||||
}
|
||||
if ( last.isString() && last.asString() == mSelectedListName )
|
||||
{
|
||||
isLast = true;
|
||||
}
|
||||
}
|
||||
return isLast;
|
||||
}
|
||||
|
||||
/* TBD
|
||||
mOldText = getChild<LLLineEditor>("autoreplace_old_text");
|
||||
mNewText = getChild<LLLineEditor>("autoreplace_new_text");
|
||||
*/
|
||||
111
indra/newview/llfloaterautoreplacesettings.h
Normal file
111
indra/newview/llfloaterautoreplacesettings.h
Normal file
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* @file llfloaterautoreplacesettings.h
|
||||
* @brief Auto Replace List floater
|
||||
* @copyright Copyright (c) 2011 LordGregGreg Back
|
||||
*
|
||||
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2012, Linden Research, 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; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LLFLOATERAUTOREPLACESETTINGS_H
|
||||
#define LLFLOATERAUTOREPLACESETTINGS_H
|
||||
|
||||
#include "llfloater.h"
|
||||
#include "llautoreplace.h"
|
||||
|
||||
class AIFilePicker;
|
||||
class LLLineEditor;
|
||||
class LLScrollListCtrl;
|
||||
|
||||
class LLFloaterAutoReplaceSettings : public LLFloater, public LLFloaterSingleton<LLFloaterAutoReplaceSettings>
|
||||
{
|
||||
public:
|
||||
LLFloaterAutoReplaceSettings(const LLSD& key = LLSD());
|
||||
|
||||
/*virtual*/ BOOL postBuild();
|
||||
|
||||
private:
|
||||
|
||||
/** @{ @name Local Copies of Settings
|
||||
* These are populated in the postBuild method with the values
|
||||
* current when the floater is instantiated, and then either
|
||||
* discarded when Cancel is pressed, or copied back to the active
|
||||
* settings if Ok is pressed.
|
||||
*/
|
||||
bool mEnabled; ///< the global preference for AutoReplace
|
||||
LLAutoReplaceSettings mSettings; ///< settings being modified
|
||||
/** @} */
|
||||
|
||||
/// convenience variable - the name of the currently selected list (if any)
|
||||
std::string mSelectedListName;
|
||||
/// the scrolling list of list names (one column, no headings, order manually controlled)
|
||||
LLScrollListCtrl* mListNames;
|
||||
/// the scroling list of keyword->replacement pairs
|
||||
LLScrollListCtrl* mReplacementsList;
|
||||
|
||||
/// the keyword for the entry editing pane
|
||||
LLLineEditor* mKeyword;
|
||||
/// saved keyword value
|
||||
std::string mPreviousKeyword;
|
||||
/// the replacement for the entry editing pane
|
||||
LLLineEditor* mReplacement;
|
||||
|
||||
/// callback for when the feature enable/disable checkbox changes
|
||||
void onAutoReplaceToggled();
|
||||
/// callback for when an entry in the list of list names is selected
|
||||
void onSelectList();
|
||||
|
||||
void onImportList();
|
||||
void onImportList_continued(AIFilePicker* picker);
|
||||
void onExportList();
|
||||
void onExportList_continued(AIFilePicker* picker, const LLSD* list);
|
||||
void onNewList();
|
||||
void onDeleteList();
|
||||
|
||||
void onListUp();
|
||||
void onListDown();
|
||||
|
||||
void onSelectEntry();
|
||||
void onAddEntry();
|
||||
void onDeleteEntry();
|
||||
void onSaveEntry();
|
||||
|
||||
void onSaveChanges();
|
||||
|
||||
/// updates the contents of the mListNames
|
||||
void updateListNames();
|
||||
/// updates the controls associated with mListNames (depends on whether a name is selected or not)
|
||||
void updateListNamesControls();
|
||||
/// updates the contents of the mReplacementsList
|
||||
void updateReplacementsList();
|
||||
/// enables the components that should only be active when a keyword is selected
|
||||
void enableReplacementEntry();
|
||||
/// disables the components that should only be active when a keyword is selected
|
||||
void disableReplacementEntry();
|
||||
|
||||
/// called from the AddAutoReplaceList notification dialog
|
||||
bool callbackNewListName(const LLSD& notification, const LLSD& response);
|
||||
/// called from the RenameAutoReplaceList notification dialog
|
||||
bool callbackListNameConflict(const LLSD& notification, const LLSD& response);
|
||||
|
||||
bool selectedListIsFirst();
|
||||
bool selectedListIsLast();
|
||||
};
|
||||
|
||||
#endif // LLFLOATERAUTOREPLACESETTINGS_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -10,6 +10,10 @@
|
||||
// Copyright: See COPYING file that comes with this distribution
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef LL_LLFLOATERAVATARLIST_H
|
||||
#define LL_LLFLOATERAVATARLIST_H
|
||||
|
||||
#include "llavatarname.h"
|
||||
#include "llavatarpropertiesprocessor.h"
|
||||
#include "llfloater.h"
|
||||
@@ -76,7 +80,7 @@ enum ACTIVITY_TYPE
|
||||
* Update world position.
|
||||
* Affects age.
|
||||
*/
|
||||
void setPosition(LLVector3d position, bool this_sim, bool drawn, bool chatrange, bool shoutrange);
|
||||
void setPosition(const LLVector3d& position, bool this_sim, bool drawn, bool chatrange, bool shoutrange);
|
||||
|
||||
const LLVector3d& getPosition() const { return mPosition; }
|
||||
|
||||
@@ -86,7 +90,7 @@ enum ACTIVITY_TYPE
|
||||
* This is only used for determining whether the avatar is still around.
|
||||
* @see getEntryAgeSeconds
|
||||
*/
|
||||
bool getAlive();
|
||||
bool getAlive() const;
|
||||
|
||||
/**
|
||||
* @brief Returns the age of this entry in seconds
|
||||
@@ -107,14 +111,14 @@ enum ACTIVITY_TYPE
|
||||
void setActivity(ACTIVITY_TYPE activity);
|
||||
|
||||
/**
|
||||
* @brief Returns the activity type
|
||||
* @brief Returns the activity type, updates mActivityType if necessary
|
||||
*/
|
||||
const ACTIVITY_TYPE getActivity();
|
||||
|
||||
/**
|
||||
* @brief Sets the 'focus' status on this entry (camera focused on this avatar)
|
||||
*/
|
||||
void setFocus(BOOL value) { mFocused = value; }
|
||||
void setFocus(bool value) { mFocused = value; }
|
||||
|
||||
bool isFocused() const { return mFocused; }
|
||||
|
||||
@@ -130,7 +134,7 @@ enum ACTIVITY_TYPE
|
||||
bool isInList() const { return mIsInList; }
|
||||
/**
|
||||
* @brief Returns whether the item is dead and shouldn't appear in the list
|
||||
* @returns TRUE if dead
|
||||
* @returns true if dead
|
||||
*/
|
||||
bool isDead() const;
|
||||
|
||||
@@ -207,7 +211,6 @@ public:
|
||||
/*virtual*/ void onOpen();
|
||||
/*virtual*/ BOOL postBuild();
|
||||
/*virtual*/ void draw();
|
||||
static void createInstance(bool visible);
|
||||
/**
|
||||
* @brief Toggles interface visibility
|
||||
* There is only one instance of the avatar scanner at any time.
|
||||
@@ -234,20 +237,20 @@ public:
|
||||
* @brief Returns the entry for an avatar, if preset
|
||||
* @returns Pointer to avatar entry, NULL if not found.
|
||||
*/
|
||||
LLAvatarListEntry* getAvatarEntry(LLUUID avatar);
|
||||
LLAvatarListEntry* getAvatarEntry(const LLUUID& avatar) const;
|
||||
|
||||
/**
|
||||
* @brief Returns a string with the selected names in the list
|
||||
*/
|
||||
std::string getSelectedNames(const std::string& separator = ", ");
|
||||
std::string getSelectedName();
|
||||
LLUUID getSelectedID();
|
||||
uuid_vec_t getSelectedIDs();
|
||||
std::string getSelectedNames(const std::string& separator = ", ") const;
|
||||
std::string getSelectedName() const;
|
||||
LLUUID getSelectedID() const;
|
||||
uuid_vec_t getSelectedIDs() const;
|
||||
|
||||
static void lookAtAvatar(LLUUID &uuid);
|
||||
static bool lookAtAvatar(const LLUUID& uuid);
|
||||
|
||||
static void sound_trigger_hook(LLMessageSystem* msg,void **);
|
||||
void sendKeys();
|
||||
void sendKeys() const;
|
||||
|
||||
typedef boost::shared_ptr<LLAvatarListEntry> LLAvatarListEntryPtr;
|
||||
typedef std::vector< LLAvatarListEntryPtr > av_list_t;
|
||||
@@ -264,6 +267,7 @@ public:
|
||||
LIST_POSITION,
|
||||
LIST_ALTITUDE,
|
||||
LIST_ACTIVITY,
|
||||
LIST_VOICE,
|
||||
LIST_AGE,
|
||||
LIST_TIME,
|
||||
LIST_CLIENT,
|
||||
@@ -285,16 +289,16 @@ public:
|
||||
* @brief Focus camera on previous avatar
|
||||
* @param marked_only Whether to choose only marked avatars
|
||||
*/
|
||||
void focusOnPrev(BOOL marked_only);
|
||||
void focusOnPrev(bool marked_only);
|
||||
|
||||
/**
|
||||
* @brief Focus camera on next avatar
|
||||
* @param marked_only Whether to choose only marked avatars
|
||||
*/
|
||||
void focusOnNext(BOOL marked_only);
|
||||
void focusOnNext(bool marked_only);
|
||||
|
||||
void refreshTracker();
|
||||
void trackAvatar(const LLAvatarListEntry* entry);
|
||||
void trackAvatar(const LLAvatarListEntry* entry) const;
|
||||
|
||||
/**
|
||||
* @brief Handler for the "refresh" button click.
|
||||
@@ -321,7 +325,8 @@ public:
|
||||
void onClickEject();
|
||||
void onClickEjectFromEstate();
|
||||
void onClickBanFromEstate();
|
||||
void onAvatarSortingChanged();
|
||||
|
||||
void onAvatarSortingChanged() { mDirtyAvatarSorting = true; }
|
||||
|
||||
/**
|
||||
* @brief Called via notification feedback.
|
||||
@@ -335,7 +340,7 @@ public:
|
||||
|
||||
static void callbackIdle(void *userdata);
|
||||
|
||||
void doCommand(avlist_command_t cmd, bool single = false);
|
||||
void doCommand(avlist_command_t cmd, bool single = false) const;
|
||||
|
||||
/**
|
||||
* @brief Cleanup avatar list, removing dead entries from it.
|
||||
@@ -355,7 +360,7 @@ private:
|
||||
bool mDirtyAvatarSorting;
|
||||
|
||||
/**
|
||||
* @brief TRUE when Updating
|
||||
* @brief true when Updating
|
||||
*/
|
||||
const LLCachedControl<bool> mUpdate;
|
||||
|
||||
@@ -373,3 +378,5 @@ private:
|
||||
*/
|
||||
LLUUID mFocusedAvatar;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -427,7 +427,7 @@ public:
|
||||
|
||||
// in case of invalid characters, the avatar picker returns a 400
|
||||
// just set it to process so it displays 'not found'
|
||||
if ((200 <= status && status < 300) || status == 400)
|
||||
if (isGoodStatus(status) || status == 400)
|
||||
{
|
||||
if (LLFloaterAvatarPicker::instanceExists())
|
||||
{
|
||||
|
||||
@@ -375,6 +375,10 @@ BOOL LLFloaterBvhPreview::postBuild()
|
||||
}
|
||||
}
|
||||
|
||||
if (motionp && mInWorld)
|
||||
{
|
||||
gAgentAvatarp->removeMotion(mMotionID);
|
||||
}
|
||||
//setEnabled(FALSE);
|
||||
mMotionID.setNull();
|
||||
mAnimPreview = NULL;
|
||||
|
||||
@@ -102,13 +102,6 @@ LLFloaterChat::~LLFloaterChat()
|
||||
// Children all cleaned up by default view destructor.
|
||||
}
|
||||
|
||||
void LLFloaterChat::setVisible(BOOL visible)
|
||||
{
|
||||
LLFloater::setVisible( visible );
|
||||
|
||||
gSavedSettings.setBOOL("ShowChatHistory", visible);
|
||||
}
|
||||
|
||||
void LLFloaterChat::draw()
|
||||
{
|
||||
// enable say and shout only when text available
|
||||
@@ -140,6 +133,11 @@ BOOL LLFloaterChat::postBuild()
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void LLFloaterChat::onOpen()
|
||||
{
|
||||
gSavedSettings.setBOOL("ShowChatHistory", true);
|
||||
}
|
||||
|
||||
// public virtual
|
||||
void LLFloaterChat::onClose(bool app_quitting)
|
||||
{
|
||||
|
||||
@@ -59,9 +59,9 @@ public:
|
||||
LLFloaterChat(const LLSD& seed);
|
||||
~LLFloaterChat();
|
||||
|
||||
virtual void setVisible( BOOL b );
|
||||
virtual void draw();
|
||||
virtual BOOL postBuild();
|
||||
virtual void onOpen();
|
||||
virtual void onClose(bool app_quitting);
|
||||
virtual void onFocusReceived();
|
||||
virtual void handleVisibilityChange(BOOL cur_visibility);
|
||||
|
||||
@@ -78,9 +78,14 @@ BOOL LLFloaterMyFriends::postBuild()
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void LLFloaterMyFriends::onOpen()
|
||||
{
|
||||
gSavedSettings.setBOOL("ShowContacts", true);
|
||||
}
|
||||
|
||||
void LLFloaterMyFriends::onClose(bool app_quitting)
|
||||
{
|
||||
if (!app_quitting) gSavedSettings.setBOOL("ShowContacts", false);
|
||||
setVisible(FALSE);
|
||||
}
|
||||
|
||||
@@ -122,6 +127,7 @@ LLFloaterChatterBox::LLFloaterChatterBox(const LLSD& seed) :
|
||||
removeFloater(floater_contacts);
|
||||
// reparent to floater view
|
||||
gFloaterView->addChild(floater_contacts);
|
||||
if (gSavedSettings.getBOOL("ShowContacts")) floater_contacts->open();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -136,11 +142,13 @@ LLFloaterChatterBox::LLFloaterChatterBox(const LLSD& seed) :
|
||||
removeFloater(floater_chat);
|
||||
// reparent to floater view
|
||||
gFloaterView->addChild(floater_chat);
|
||||
if (gSavedSettings.getBOOL("ShowChatHistory")) floater_chat->open();
|
||||
}
|
||||
else
|
||||
{
|
||||
addFloater(floater_chat, FALSE);
|
||||
}
|
||||
if (gSavedSettings.getBOOL("ShowCommunicate")) open(); // After all floaters have been added, so we may not be hidden anyhow.
|
||||
gSavedSettings.getControl("ShowLocalChatFloaterBar")->getSignal()->connect(boost::bind(handleLocalChatBar, floater_chat, _2));
|
||||
mTabContainer->lockTabs();
|
||||
}
|
||||
@@ -228,7 +236,7 @@ void LLFloaterChatterBox::onOpen()
|
||||
void LLFloaterChatterBox::onClose(bool app_quitting)
|
||||
{
|
||||
setVisible(FALSE);
|
||||
gSavedSettings.setBOOL("ShowCommunicate", FALSE);
|
||||
if (!app_quitting) gSavedSettings.setBOOL("ShowCommunicate", false);
|
||||
}
|
||||
|
||||
void LLFloaterChatterBox::setMinimized(BOOL minimized)
|
||||
|
||||
@@ -126,7 +126,8 @@ public:
|
||||
|
||||
virtual BOOL postBuild();
|
||||
|
||||
void onClose(bool app_quitting);
|
||||
virtual void onOpen();
|
||||
virtual void onClose(bool app_quitting);
|
||||
|
||||
static void* createFriendsPanel(void* data);
|
||||
static void* createGroupsPanel(void* data);
|
||||
|
||||
@@ -2161,7 +2161,7 @@ void LLPanelLandOptions::refreshSearch()
|
||||
|
||||
bool can_change =
|
||||
LLViewerParcelMgr::isParcelModifiableByAgent(
|
||||
parcel, GP_LAND_CHANGE_IDENTITY)
|
||||
parcel, GP_LAND_FIND_PLACES)
|
||||
&& region
|
||||
&& !(region->getRegionFlag(REGION_FLAGS_BLOCK_PARCEL_SEARCH));
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#ifndef LL_LLFLOATERMESSAGELOG_H
|
||||
#define LL_LLFLOATERMESSAGELOG_H
|
||||
|
||||
// <edit>
|
||||
#include "llfloater.h"
|
||||
#include "llmessagelog.h"
|
||||
@@ -94,3 +97,5 @@ public:
|
||||
static void onClickFilterMenu(void* user_data);
|
||||
};
|
||||
// </edit>
|
||||
|
||||
#endif
|
||||
@@ -241,6 +241,22 @@ bool ll_is_degenerate(const LLVector4a& a, const LLVector4a& b, const LLVector4a
|
||||
|
||||
bool validate_face(const LLVolumeFace& face)
|
||||
{
|
||||
|
||||
for (S32 v = 0; v < face.mNumVertices; v++)
|
||||
{
|
||||
if(face.mPositions && !face.mPositions[v].isFinite3())
|
||||
{
|
||||
llwarns << "NaN position data in face found!" << llendl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(face.mNormals && !face.mNormals[v].isFinite3())
|
||||
{
|
||||
llwarns << "NaN normal data in face found!" << llendl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (S32 i = 0; i < face.mNumIndices; ++i)
|
||||
{
|
||||
if (face.mIndices[i] >= face.mNumVertices)
|
||||
@@ -3807,15 +3823,30 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim
|
||||
|
||||
U32 triangle_count = 0;
|
||||
|
||||
for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter)
|
||||
U32 instanced_triangle_count = 0;
|
||||
|
||||
//get the triangle count for the whole scene
|
||||
for (LLModelLoader::scene::iterator iter = mBaseScene.begin(), endIter = mBaseScene.end(); iter != endIter; ++iter)
|
||||
{
|
||||
LLModel* mdl = *iter;
|
||||
for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i)
|
||||
for (LLModelLoader::model_instance_list::iterator instance = iter->second.begin(), end_instance = iter->second.end(); instance != end_instance; ++instance)
|
||||
{
|
||||
triangle_count += mdl->getVolumeFace(i).mNumIndices/3;
|
||||
LLModel* mdl = instance->mModel;
|
||||
if (mdl)
|
||||
{
|
||||
instanced_triangle_count += mdl->getNumTriangles();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//get the triangle count for the non-instanced set of models
|
||||
for (U32 i = 0; i < mBaseModel.size(); ++i)
|
||||
{
|
||||
triangle_count += mBaseModel[i]->getNumTriangles();
|
||||
}
|
||||
|
||||
//get ratio of uninstanced triangles to instanced triangles
|
||||
F32 triangle_ratio = (F32) triangle_count / (F32) instanced_triangle_count;
|
||||
|
||||
U32 base_triangle_count = triangle_count;
|
||||
|
||||
U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0;
|
||||
@@ -3849,6 +3880,8 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim
|
||||
if (which_lod > -1 && which_lod < NUM_LOD)
|
||||
{
|
||||
limit = mFMP->childGetValue("lod_triangle_limit_" + lod_name[which_lod]).asInteger();
|
||||
//convert from "scene wide" to "non-instanced" triangle limit
|
||||
limit = (S32) ( (F32) limit*triangle_ratio );
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -3953,7 +3986,7 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim
|
||||
U32 actual_verts = 0;
|
||||
U32 submeshes = 0;
|
||||
|
||||
mRequestedTriangleCount[lod] = triangle_count;
|
||||
mRequestedTriangleCount[lod] = (S32) ( (F32) triangle_count / triangle_ratio );
|
||||
mRequestedErrorThreshold[lod] = lod_error_threshold;
|
||||
|
||||
glodGroupParameteri(mGroup, GLOD_ADAPT_MODE, lod_mode);
|
||||
@@ -4135,28 +4168,36 @@ void LLModelPreview::updateStatusMessages()
|
||||
//initialize total for this lod to 0
|
||||
total_tris[lod] = total_verts[lod] = total_submeshes[lod] = 0;
|
||||
|
||||
for (U32 i = 0; i < mModel[lod].size(); ++i)
|
||||
{ //for each model in the lod
|
||||
S32 cur_tris = 0;
|
||||
S32 cur_verts = 0;
|
||||
S32 cur_submeshes = mModel[lod][i]->getNumVolumeFaces();
|
||||
for (LLModelLoader::scene::iterator iter = mScene[lod].begin(), endIter = mScene[lod].end(); iter != endIter; ++iter)
|
||||
{
|
||||
for (LLModelLoader::model_instance_list::iterator instance = iter->second.begin(), end_instance = iter->second.end(); instance != end_instance; ++instance)
|
||||
{
|
||||
LLModel* model = instance->mModel;
|
||||
if (model)
|
||||
{
|
||||
//for each model in the lod
|
||||
S32 cur_tris = 0;
|
||||
S32 cur_verts = 0;
|
||||
S32 cur_submeshes = model->getNumVolumeFaces();
|
||||
|
||||
for (S32 j = 0; j < cur_submeshes; ++j)
|
||||
{ //for each submesh (face), add triangles and vertices to current total
|
||||
const LLVolumeFace& face = mModel[lod][i]->getVolumeFace(j);
|
||||
cur_tris += face.mNumIndices/3;
|
||||
cur_verts += face.mNumVertices;
|
||||
for (S32 j = 0; j < cur_submeshes; ++j)
|
||||
{ //for each submesh (face), add triangles and vertices to current total
|
||||
const LLVolumeFace& face = model->getVolumeFace(j);
|
||||
cur_tris += face.mNumIndices/3;
|
||||
cur_verts += face.mNumVertices;
|
||||
}
|
||||
|
||||
//add this model to the lod total
|
||||
total_tris[lod] += cur_tris;
|
||||
total_verts[lod] += cur_verts;
|
||||
total_submeshes[lod] += cur_submeshes;
|
||||
|
||||
//store this model's counts to asset data
|
||||
tris[lod].push_back(cur_tris);
|
||||
verts[lod].push_back(cur_verts);
|
||||
submeshes[lod].push_back(cur_submeshes);
|
||||
}
|
||||
}
|
||||
|
||||
//add this model to the lod total
|
||||
total_tris[lod] += cur_tris;
|
||||
total_verts[lod] += cur_verts;
|
||||
total_submeshes[lod] += cur_submeshes;
|
||||
|
||||
//store this model's counts to asset data
|
||||
tris[lod].push_back(cur_tris);
|
||||
verts[lod].push_back(cur_verts);
|
||||
submeshes[lod].push_back(cur_submeshes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4334,34 +4375,38 @@ void LLModelPreview::updateStatusMessages()
|
||||
}
|
||||
|
||||
//add up physics triangles etc
|
||||
S32 start = 0;
|
||||
S32 end = mModel[LLModel::LOD_PHYSICS].size();
|
||||
|
||||
S32 phys_tris = 0;
|
||||
S32 phys_hulls = 0;
|
||||
S32 phys_points = 0;
|
||||
|
||||
for (S32 i = start; i < end; ++i)
|
||||
{ //add up hulls and points and triangles for selected mesh(es)
|
||||
LLModel* model = mModel[LLModel::LOD_PHYSICS][i];
|
||||
S32 cur_submeshes = model->getNumVolumeFaces();
|
||||
|
||||
LLModel::convex_hull_decomposition& decomp = model->mPhysics.mHull;
|
||||
|
||||
if (!decomp.empty())
|
||||
//get the triangle count for the whole scene
|
||||
for (LLModelLoader::scene::iterator iter = mScene[LLModel::LOD_PHYSICS].begin(), endIter = mScene[LLModel::LOD_PHYSICS].end(); iter != endIter; ++iter)
|
||||
{
|
||||
for (LLModelLoader::model_instance_list::iterator instance = iter->second.begin(), end_instance = iter->second.end(); instance != end_instance; ++instance)
|
||||
{
|
||||
phys_hulls += decomp.size();
|
||||
for (U32 i = 0; i < decomp.size(); ++i)
|
||||
LLModel* model = instance->mModel;
|
||||
if (model)
|
||||
{
|
||||
phys_points += decomp[i].size();
|
||||
}
|
||||
}
|
||||
else
|
||||
{ //choose physics shape OR decomposition, can't use both
|
||||
for (S32 j = 0; j < cur_submeshes; ++j)
|
||||
{ //for each submesh (face), add triangles and vertices to current total
|
||||
const LLVolumeFace& face = model->getVolumeFace(j);
|
||||
phys_tris += face.mNumIndices/3;
|
||||
S32 cur_submeshes = model->getNumVolumeFaces();
|
||||
|
||||
LLModel::convex_hull_decomposition& decomp = model->mPhysics.mHull;
|
||||
|
||||
if (!decomp.empty())
|
||||
{
|
||||
phys_hulls += decomp.size();
|
||||
for (U32 i = 0; i < decomp.size(); ++i)
|
||||
{
|
||||
phys_points += decomp[i].size();
|
||||
}
|
||||
}
|
||||
else
|
||||
{ //choose physics shape OR decomposition, can't use both
|
||||
for (S32 j = 0; j < cur_submeshes; ++j)
|
||||
{ //for each submesh (face), add triangles and vertices to current total
|
||||
const LLVolumeFace& face = model->getVolumeFace(j);
|
||||
phys_tris += face.mNumIndices/3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4523,7 +4568,7 @@ void LLModelPreview::updateLodControls(S32 lod)
|
||||
if (!lod_combo) return;
|
||||
|
||||
S32 lod_mode = lod_combo->getCurrentIndex();
|
||||
if (lod_mode == 0) // LoD from file
|
||||
if (lod_mode == LOD_FROM_FILE) // LoD from file
|
||||
{
|
||||
fmp->mLODMode[lod] = 0;
|
||||
for (U32 i = 0; i < num_file_controls; ++i)
|
||||
@@ -4536,7 +4581,7 @@ void LLModelPreview::updateLodControls(S32 lod)
|
||||
mFMP->childHide(lod_controls[i] + lod_name[lod]);
|
||||
}
|
||||
}
|
||||
else if (lod_mode == 2) // use LoD above
|
||||
else if (lod_mode == USE_LOD_ABOVE) // use LoD above
|
||||
{
|
||||
fmp->mLODMode[lod] = 2;
|
||||
for (U32 i = 0; i < num_file_controls; ++i)
|
||||
|
||||
@@ -298,6 +298,15 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex
|
||||
typedef boost::signals2::signal<void (void)> model_loaded_signal_t;
|
||||
typedef boost::signals2::signal<void (bool)> model_updated_signal_t;
|
||||
|
||||
public:
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LOD_FROM_FILE = 0,
|
||||
GENERATE,
|
||||
USE_LOD_ABOVE,
|
||||
} eLoDMode;
|
||||
|
||||
public:
|
||||
LLModelPreview(S32 width, S32 height, LLFloater* fmp);
|
||||
virtual ~LLModelPreview();
|
||||
|
||||
@@ -1,154 +0,0 @@
|
||||
/**
|
||||
* @file llfloaterpermissionsmgr.cpp
|
||||
* @brief for user control of script permissions
|
||||
*
|
||||
* $LicenseInfo:firstyear=2003&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2003-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llfloaterpermissionsmgr.h"
|
||||
|
||||
#include "llscrollcontainer.h"
|
||||
#include "lltextbox.h"
|
||||
#include "llbutton.h"
|
||||
#include "llagent.h"
|
||||
#include "llviewerobjectlist.h"
|
||||
#include "llviewerregion.h"
|
||||
#include "llstl.h"
|
||||
|
||||
// constants
|
||||
const S32 MIN_PERM_MGR_WIDTH = 100;
|
||||
const S32 MIN_PERM_MGR_HEIGHT = 100;
|
||||
const S32 VPAD = 8;
|
||||
const S32 HPAD = 8;
|
||||
const S32 LINE = 16;
|
||||
|
||||
// statics
|
||||
LLFloaterPermissionsMgr* LLFloaterPermissionsMgr::sInstance = NULL;
|
||||
|
||||
LLFloaterPermissionsMgr* LLFloaterPermissionsMgr::show()
|
||||
{
|
||||
if (!sInstance)
|
||||
{
|
||||
sInstance = new LLFloaterPermissionsMgr();
|
||||
|
||||
sInstance->open(); /* Flawfinder: ignore */
|
||||
gFloaterView->adjustToFitScreen(sInstance, TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
sInstance->open(); /* Flawfinder: ignore */
|
||||
}
|
||||
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
void LLFloaterPermissionsMgr::processPermissionsList(LLMessageSystem* msg, void**)
|
||||
{
|
||||
}
|
||||
|
||||
LLFloaterPermissionsMgr::LLFloaterPermissionsMgr() :
|
||||
LLFloater(std::string("floater_perm_mgr"), std::string("PermissionsManagerRect"), std::string("Permissions Manager"),
|
||||
TRUE, MIN_PERM_MGR_WIDTH, MIN_PERM_MGR_HEIGHT)
|
||||
{
|
||||
S32 y = getRect().getHeight() - VPAD - LINE;
|
||||
LLRect scrollable_container_rect(0, y, getRect().getWidth(), 0);
|
||||
LLRect permissions_rect(0, 0, getRect().getWidth() - HPAD - HPAD, 0);
|
||||
mPermissions = new LLPermissionsView(permissions_rect);
|
||||
mScroller = new LLScrollContainer(
|
||||
std::string("permissions container"),
|
||||
scrollable_container_rect,
|
||||
mPermissions
|
||||
);
|
||||
mScroller->setFollowsAll();
|
||||
mScroller->setReserveScrollCorner(TRUE);
|
||||
addChild(mScroller);
|
||||
}
|
||||
|
||||
LLFloaterPermissionsMgr::~LLFloaterPermissionsMgr()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// LLPermissionsView
|
||||
//
|
||||
|
||||
LLPermissionsView::LLPermissionsView(const LLRect &rect) : LLView(std::string("permissions_view"), rect, TRUE, FOLLOWS_NONE)
|
||||
{
|
||||
}
|
||||
|
||||
void LLPermissionsView::clearPermissionsData()
|
||||
{
|
||||
deleteAllChildren();
|
||||
}
|
||||
|
||||
void LLPermissionsView::addPermissionsData(const std::string& object_name, const LLUUID& object_id, U32 permissions_flags)
|
||||
{
|
||||
// grow to make room for new element
|
||||
reshape(getRect().getWidth(), getRect().getHeight() + LINE + VPAD + BTN_HEIGHT + VPAD);
|
||||
S32 y = getRect().getHeight() - LINE - VPAD;
|
||||
LLRect label_rect(HPAD, y + LINE, getRect().getWidth(), y);
|
||||
LLTextBox* text = new LLTextBox(std::string("perm_label"), label_rect, object_name);
|
||||
text->setFollows(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_BOTTOM);
|
||||
addChild(text);
|
||||
|
||||
y -= LINE + VPAD;
|
||||
|
||||
LLRect btn_rect(HPAD, y + BTN_HEIGHT, 120, y);
|
||||
LLButton* button = new LLButton(std::string("Revoke permissions"), btn_rect, LLStringUtil::null, boost::bind(&LLPermissionsView::revokePermissions, object_id, permissions_flags));
|
||||
button->setFollows(FOLLOWS_LEFT | FOLLOWS_BOTTOM);
|
||||
addChild(button);
|
||||
|
||||
/*btn_rect.set(HPAD + 120 + HPAD, y + BTN_HEIGHT, HPAD + 120 + HPAD + 120, y);
|
||||
button = new LLButton(std::string("Find in world"), btn_rect, LLStringUtil::null, boost::bind(&LLPermissionsView::findObject, object_id, permissions_flags));
|
||||
button->setFollows(FOLLOWS_LEFT | FOLLOWS_BOTTOM);
|
||||
addChild(button);*/
|
||||
}
|
||||
|
||||
void LLPermissionsView::revokePermissions(const LLUUID& object_id, U32 permission_flags)
|
||||
{
|
||||
LLViewerObject* objectp = gObjectList.findObject(object_id);
|
||||
if (objectp)
|
||||
{
|
||||
LLMessageSystem* msg = gMessageSystem;
|
||||
msg->newMessageFast(_PREHASH_RevokePermissions);
|
||||
msg->nextBlockFast(_PREHASH_AgentData);
|
||||
msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
|
||||
msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
|
||||
msg->nextBlockFast(_PREHASH_Data);
|
||||
msg->addUUIDFast(_PREHASH_ObjectID, object_id);
|
||||
msg->addU32Fast(_PREHASH_ObjectPermissions, permission_flags);
|
||||
msg->sendReliable(objectp->getRegion()->getHost());
|
||||
}
|
||||
}
|
||||
|
||||
/*void LLPermissionsView::findObject(const LLUUID& object_id, U32 permission_flags)
|
||||
{
|
||||
}*/
|
||||
@@ -1,82 +0,0 @@
|
||||
/**
|
||||
* @file llfloaterpermissionsmgr.h
|
||||
* @brief for user control of script permissions
|
||||
*
|
||||
* $LicenseInfo:firstyear=2003&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2003-2009, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLFLOATERPERMISSIONSMGR_H
|
||||
#define LL_LLFLOATERPERMISSIONSMGR_H
|
||||
|
||||
#include "llfloater.h"
|
||||
#include <vector>
|
||||
|
||||
class LLScrollContainer;
|
||||
class LLPermissionsView;
|
||||
|
||||
class LLFloaterPermissionsMgr
|
||||
: public LLFloater
|
||||
{
|
||||
public:
|
||||
static LLFloaterPermissionsMgr* show();
|
||||
|
||||
// Message system callbacks
|
||||
static void processPermissionsList(LLMessageSystem* msg, void**);
|
||||
|
||||
virtual void onClose(bool app_quitting) { setVisible(FALSE); }
|
||||
|
||||
private:
|
||||
// Must construct by calling show().
|
||||
LLFloaterPermissionsMgr();
|
||||
virtual ~LLFloaterPermissionsMgr();
|
||||
|
||||
public:
|
||||
LLPermissionsView* mPermissions;
|
||||
|
||||
protected:
|
||||
LLScrollContainer* mScroller;
|
||||
|
||||
static LLFloaterPermissionsMgr* sInstance;
|
||||
};
|
||||
|
||||
class LLPermissionsView : public LLView
|
||||
{
|
||||
public:
|
||||
LLPermissionsView(const LLRect& rect);
|
||||
virtual ~LLPermissionsView() {};
|
||||
|
||||
public:
|
||||
void clearPermissionsData();
|
||||
void addPermissionsData(const std::string& object_name, const LLUUID& object_id, U32 permissions_flags);
|
||||
|
||||
static void revokePermissions(const LLUUID& object_id, U32 permission_flags);
|
||||
//static void findObject(const LLUUID& object_id, U32 permission_flags);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
196
indra/newview/llfloaterregionrestarting.cpp
Normal file
196
indra/newview/llfloaterregionrestarting.cpp
Normal file
@@ -0,0 +1,196 @@
|
||||
/**
|
||||
* @file llfloaterregionrestarting.cpp
|
||||
* @brief Shows countdown timer during region restart
|
||||
*
|
||||
* $LicenseInfo:firstyear=2006&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, 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
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llfloaterregionrestarting.h"
|
||||
|
||||
#include "lluictrlfactory.h"
|
||||
#include "llagent.h"
|
||||
#include "llagentcamera.h"
|
||||
#include "llenvmanager.h"
|
||||
#include "llviewercontrol.h"
|
||||
#include "llviewerwindow.h"
|
||||
|
||||
// <singu> For emergency teleports
|
||||
#include "llinventorymodel.h"
|
||||
void emergency_teleport()
|
||||
{
|
||||
static const LLCachedControl<std::string> landmark(gSavedPerAccountSettings, "EmergencyTeleportLandmark");
|
||||
if (landmark().empty()) return;
|
||||
const LLUUID id(landmark);
|
||||
if (id.isNull()) return;
|
||||
if (LLViewerInventoryItem* item = gInventory.getItem(id))
|
||||
gAgent.teleportViaLandmark(item->getAssetUUID());
|
||||
}
|
||||
// </singu>
|
||||
|
||||
enum shake_state
|
||||
{
|
||||
SHAKE_START,
|
||||
SHAKE_LEFT,
|
||||
SHAKE_UP,
|
||||
SHAKE_RIGHT,
|
||||
SHAKE_DOWN,
|
||||
SHAKE_DONE
|
||||
};
|
||||
static shake_state sShakeState;
|
||||
|
||||
LLFloaterRegionRestarting::LLFloaterRegionRestarting(const LLSD& key) :
|
||||
LLEventTimer(1)
|
||||
, mRestartSeconds(NULL)
|
||||
, mSeconds(key["SECONDS"].asInteger())
|
||||
, mShakeIterations()
|
||||
, mShakeMagnitude()
|
||||
{
|
||||
//buildFromFile("floater_region_restarting.xml");
|
||||
LLUICtrlFactory::getInstance()->buildFloater(this, "floater_region_restarting.xml");
|
||||
|
||||
LLStringUtil::format_map_t args;
|
||||
args["[NAME]"] = key["NAME"].asString();
|
||||
getChild<LLTextBox>("region_name")->setValue(getString("RegionName", args));
|
||||
mRestartSeconds = getChild<LLTextBox>("restart_seconds");
|
||||
center();
|
||||
|
||||
refresh();
|
||||
|
||||
mRegionChangedConnection = LLEnvManagerNew::instance().setRegionChangeCallback(boost::bind(&LLFloaterRegionRestarting::close, this, false));
|
||||
if (mSeconds <= 20) emergency_teleport(); // <singu/> For emergency teleports
|
||||
}
|
||||
|
||||
LLFloaterRegionRestarting::~LLFloaterRegionRestarting()
|
||||
{
|
||||
mRegionChangedConnection.disconnect();
|
||||
}
|
||||
|
||||
BOOL LLFloaterRegionRestarting::postBuild()
|
||||
{
|
||||
setBackgroundColor(gColors.getColor("NotifyCautionBoxColor"));
|
||||
sShakeState = SHAKE_START;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL LLFloaterRegionRestarting::tick()
|
||||
{
|
||||
refresh();
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void LLFloaterRegionRestarting::refresh()
|
||||
{
|
||||
LLStringUtil::format_map_t args;
|
||||
args["[SECONDS]"] = llformat("%d", mSeconds);
|
||||
mRestartSeconds->setValue(getString("RestartSeconds", args));
|
||||
|
||||
if (mSeconds == 20) emergency_teleport(); // <singu/> For emergency teleports
|
||||
if (!mSeconds) return; // Zero means we're done.
|
||||
--mSeconds;
|
||||
}
|
||||
|
||||
void LLFloaterRegionRestarting::draw()
|
||||
{
|
||||
LLFloater::draw();
|
||||
|
||||
static const LLCachedControl<bool> alchemyRegionShake(gSavedSettings, "AlchemyRegionRestartShake", true);
|
||||
if (!alchemyRegionShake || isMinimized()) // If we're minimized, leave the user alone
|
||||
return;
|
||||
|
||||
const F32 SHAKE_INTERVAL = 0.025;
|
||||
const F32 SHAKE_TOTAL_DURATION = 1.8; // the length of the default alert tone for this
|
||||
const F32 SHAKE_INITIAL_MAGNITUDE = 1.5;
|
||||
const F32 SHAKE_HORIZONTAL_BIAS = 0.25;
|
||||
F32 time_shaking;
|
||||
|
||||
if (SHAKE_START == sShakeState)
|
||||
{
|
||||
mShakeTimer.setTimerExpirySec(SHAKE_INTERVAL);
|
||||
sShakeState = SHAKE_LEFT;
|
||||
mShakeIterations = 0;
|
||||
mShakeMagnitude = SHAKE_INITIAL_MAGNITUDE;
|
||||
}
|
||||
|
||||
if (SHAKE_DONE != sShakeState && mShakeTimer.hasExpired())
|
||||
{
|
||||
gAgentCamera.unlockView();
|
||||
|
||||
switch(sShakeState)
|
||||
{
|
||||
case SHAKE_LEFT:
|
||||
gAgentCamera.setPanLeftKey(mShakeMagnitude * SHAKE_HORIZONTAL_BIAS);
|
||||
sShakeState = SHAKE_UP;
|
||||
break;
|
||||
|
||||
case SHAKE_UP:
|
||||
gAgentCamera.setPanUpKey(mShakeMagnitude);
|
||||
sShakeState = SHAKE_RIGHT;
|
||||
break;
|
||||
|
||||
case SHAKE_RIGHT:
|
||||
gAgentCamera.setPanRightKey(mShakeMagnitude * SHAKE_HORIZONTAL_BIAS);
|
||||
sShakeState = SHAKE_DOWN;
|
||||
break;
|
||||
|
||||
case SHAKE_DOWN:
|
||||
gAgentCamera.setPanDownKey(mShakeMagnitude);
|
||||
mShakeIterations++;
|
||||
time_shaking = SHAKE_INTERVAL * (mShakeIterations * 4 /* left, up, right, down */);
|
||||
if (SHAKE_TOTAL_DURATION <= time_shaking)
|
||||
{
|
||||
sShakeState = SHAKE_DONE;
|
||||
mShakeMagnitude = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sShakeState = SHAKE_LEFT;
|
||||
F32 percent_done_shaking = (SHAKE_TOTAL_DURATION - time_shaking) / SHAKE_TOTAL_DURATION;
|
||||
mShakeMagnitude = SHAKE_INITIAL_MAGNITUDE * (percent_done_shaking * percent_done_shaking); // exponential decay
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
mShakeTimer.setTimerExpirySec(SHAKE_INTERVAL);
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterRegionRestarting::onClose(bool app_quitting)
|
||||
{
|
||||
if (sShakeState != SHAKE_DONE && sShakeState != SHAKE_START) // Finish shake if needed
|
||||
{
|
||||
gAgentCamera.resetView(TRUE, TRUE);
|
||||
sShakeState = SHAKE_DONE;
|
||||
}
|
||||
LLFloater::onClose(app_quitting);
|
||||
}
|
||||
|
||||
void LLFloaterRegionRestarting::updateTime(const U32& time)
|
||||
{
|
||||
mSeconds = time;
|
||||
if (mSeconds <= 20) emergency_teleport(); // <singu/> For emergency teleports
|
||||
sShakeState = SHAKE_START;
|
||||
}
|
||||
59
indra/newview/llfloaterregionrestarting.h
Normal file
59
indra/newview/llfloaterregionrestarting.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* @file llfloaterregionrestarting.h
|
||||
* @brief Shows countdown timer during region restart
|
||||
*
|
||||
* $LicenseInfo:firstyear=2006&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, 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
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLFLOATERREGIONRESTARTING_H
|
||||
#define LL_LLFLOATERREGIONRESTARTING_H
|
||||
|
||||
#include "llfloater.h"
|
||||
#include "lleventtimer.h"
|
||||
|
||||
class LLFloaterRegionRestarting : public LLFloater, public LLEventTimer
|
||||
, public LLFloaterSingleton<LLFloaterRegionRestarting>
|
||||
{
|
||||
friend class LLFloaterReg;
|
||||
|
||||
public:
|
||||
void updateTime(const U32& time);
|
||||
|
||||
LLFloaterRegionRestarting(const LLSD& key);
|
||||
private:
|
||||
virtual ~LLFloaterRegionRestarting();
|
||||
virtual BOOL postBuild();
|
||||
virtual BOOL tick();
|
||||
virtual void refresh();
|
||||
virtual void draw();
|
||||
virtual void onClose(bool app_quitting);
|
||||
|
||||
class LLTextBox* mRestartSeconds;
|
||||
U32 mSeconds;
|
||||
U32 mShakeIterations;
|
||||
F32 mShakeMagnitude;
|
||||
LLTimer mShakeTimer;
|
||||
|
||||
boost::signals2::connection mRegionChangedConnection;
|
||||
};
|
||||
|
||||
#endif // LL_LLFLOATERREGIONRESTARTING_H
|
||||
@@ -109,7 +109,7 @@ F32 FALL_TIME = 0.6f;
|
||||
S32 BORDER_WIDTH = 6;
|
||||
|
||||
const S32 MAX_POSTCARD_DATASIZE = 1024 * 1024; // one megabyte
|
||||
const S32 MAX_TEXTURE_SIZE = 512 ; //max upload texture size 512 * 512
|
||||
const S32 MAX_TEXTURE_SIZE = 1024; //max upload texture size 1024 * 1024
|
||||
|
||||
static std::string snapshotKeepAspectName();
|
||||
|
||||
@@ -1185,7 +1185,7 @@ LLSnapshotLivePreview::EAspectSizeProblem LLSnapshotLivePreview::generateFormatt
|
||||
if (mSnapshotType == SNAPSHOT_TEXTURE)
|
||||
{
|
||||
// 'scaled' must be a power of two.
|
||||
scaled->biasedScaleToPowerOfTwo(mWidth, mHeight, 512);
|
||||
scaled->biasedScaleToPowerOfTwo(mWidth, mHeight, 1024);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2488,8 +2488,7 @@ void LLFloaterSnapshot::Impl::updateResolution(LLUICtrl* ctrl, void* data, bool
|
||||
LLSpinCtrl* width_spinner = view->getChild<LLSpinCtrl>("snapshot_width");
|
||||
LLSpinCtrl* height_spinner = view->getChild<LLSpinCtrl>("snapshot_height");
|
||||
|
||||
if (gSavedSettings.getS32("LastSnapshotType") == LLSnapshotLivePreview::SNAPSHOT_TEXTURE ||
|
||||
gSavedSettings.getBOOL("RenderUIInSnapshot") ||
|
||||
if ( gSavedSettings.getBOOL("RenderUIInSnapshot") ||
|
||||
gSavedSettings.getBOOL("RenderHUDInSnapshot"))
|
||||
{
|
||||
// Disable without making label gray.
|
||||
|
||||
@@ -1,332 +0,0 @@
|
||||
/**
|
||||
* @file llfloaterteleport.cpp
|
||||
* @brief floater code for agentd teleports.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2008&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2008, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
//Teleport floater used for agent domain TP. URI text floater.
|
||||
//Copyright International Business Machines Corporation 2008-9
|
||||
//Contributed to Linden Research, Inc. under the Second Life Viewer Contribution
|
||||
//Agreement and licensed as above.
|
||||
#include "llviewerprecompiledheaders.h" // must be first include
|
||||
|
||||
#include "llfloaterteleport.h"
|
||||
|
||||
#include "llagent.h" //for hack in teleport start
|
||||
#include "llchat.h"
|
||||
#include "llcombobox.h"
|
||||
#include "llfloaterchat.h"
|
||||
#include "llsdserialize.h"
|
||||
#include "llsdutil.h"
|
||||
#include "llsdutil_math.h"
|
||||
#include "lluictrlfactory.h" // builds floaters from XML
|
||||
#include "llurlhistory.h"
|
||||
#include "lluserauth.h" // for saving placeavatarresponder result
|
||||
#include "llviewercontrol.h" // for gSavedSettings
|
||||
#include "llviewerdisplay.h" // for gTeleportDisplay
|
||||
#include "llviewermessage.h" // for send_agent_movement_complete attempt
|
||||
#include "llviewerregion.h"
|
||||
#include "llviewerwindow.h" // for hack in teleport start
|
||||
#include "llvoavatar.h"
|
||||
#include "llworld.h"
|
||||
#include "pipeline.h" // for gPipeline
|
||||
|
||||
class AIHTTPTimeoutPolicy;
|
||||
extern AIHTTPTimeoutPolicy placeAvatarTeleportResponder_timeout;
|
||||
|
||||
// OGPX HTTP responder for PlaceAvatar cap used for Teleport
|
||||
// very similar to the responder in Login, but not as many fields are returned in the TP version
|
||||
// OGPX TODO: should this be combined with the Login responder for rez_avatar/place?
|
||||
// OGPX TODO: mResult should not get replaced in result(), instead
|
||||
// should replace individual LLSD fields in mResult.
|
||||
class LLPlaceAvatarTeleportResponder : public LLHTTPClient::ResponderWithResult
|
||||
{
|
||||
public:
|
||||
LLPlaceAvatarTeleportResponder()
|
||||
{
|
||||
}
|
||||
|
||||
~LLPlaceAvatarTeleportResponder()
|
||||
{
|
||||
}
|
||||
|
||||
/*virtual*/ void error(U32 statusNum, const std::string& reason)
|
||||
{
|
||||
LL_INFOS("OGPX") << "LLPlaceAvatarTeleportResponder error in TP "
|
||||
<< statusNum << " " << reason << LL_ENDL;
|
||||
|
||||
LLSD args;
|
||||
args["REASON"] = reason;
|
||||
|
||||
|
||||
LLNotificationsUtil::add("CouldNotTeleportReason", args);
|
||||
|
||||
gAgent.setTeleportState( LLAgent::TELEPORT_NONE );
|
||||
|
||||
}
|
||||
|
||||
/*virtual*/ void result(const LLSD& content)
|
||||
{
|
||||
|
||||
LLSD result;
|
||||
result["agent_id"] = content["agent_id"]; // need this for send_complete_agent_movement
|
||||
result["region_x"] = content["region_x"]; // need these for making the first region
|
||||
result["region_y"] = content["region_y"];
|
||||
result["login"] = "true"; // this gets checked in idle_startup()
|
||||
result["session_id"] = content["session_id"];
|
||||
result["secure_session_id"] = content["secure_session_id"];
|
||||
result["circuit_code"] = content["circuit_code"];
|
||||
result["sim_port"] = content["sim_port"];
|
||||
result["sim_host"] = content["sim_host"];
|
||||
result["look_at"] = content["look_at"];
|
||||
// maintaining result seed_capability name for compatibility with legacy login
|
||||
result["seed_capability"] = content["region_seed_capability"];
|
||||
result["position"] = content["position"]; // save this for agentmovementcomplete type processing
|
||||
|
||||
// Even though we have the pretty print of the complete content returned, we still find it handy
|
||||
// when scanning SecondLife.log to have these laid out in this way. So they are still here.
|
||||
LL_DEBUGS("OGPX") << " Teleport placeAvatar responder " << LL_ENDL;
|
||||
LL_DEBUGS("OGPX") << "agent_id: " << content["agent_id"] << LL_ENDL;
|
||||
LL_DEBUGS("OGPX") << "region_x: " << content["region_x"] << LL_ENDL;
|
||||
LL_DEBUGS("OGPX") << "session_id: " << content["session_id"] << LL_ENDL;
|
||||
LL_DEBUGS("OGPX") << "sim_port: " << content["sim_port"] << LL_ENDL;
|
||||
LL_DEBUGS("OGPX") << "sim_host: " << content["sim_host"] << LL_ENDL;
|
||||
LL_DEBUGS("OGPX") << "look_at: " << content["look_at"] << LL_ENDL;
|
||||
LL_DEBUGS("OGPX") << "position: " << content["position"] << LL_ENDL;
|
||||
LL_DEBUGS("OGPX") << "seed_capability: " << content["region_seed_capability"] << LL_ENDL;
|
||||
|
||||
LL_INFOS("OGPX") << " All the LLSD PlaceAvatarTeleportResponder content: \n " << ll_pretty_print_sd(content) << LL_ENDL; // OGPX
|
||||
|
||||
|
||||
// check "connect" to make sure place_avatar fully successful
|
||||
if (!content["connect"].asBoolean())
|
||||
{
|
||||
// place_avatar failed somewhere
|
||||
LL_INFOS("OGPX") << "TP failed, connect false in TP PlaceAvatarResponder " << LL_ENDL;
|
||||
|
||||
LLSD args;
|
||||
args["REASON"] = "Place Avatar Failed";
|
||||
|
||||
//gViewerWindow->alertXml("CouldNotTeleportReason", args);
|
||||
LLNotificationsUtil::add("CouldNotTeleportReason",args);
|
||||
|
||||
gAgent.setTeleportState( LLAgent::TELEPORT_NONE );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
U64 region_handle;
|
||||
region_handle = to_region_handle_global(content["region_x"].asInteger(), content["region_y"].asInteger());
|
||||
|
||||
LLHost sim_host;
|
||||
U32 sim_port = strtoul(result["sim_port"].asString().c_str(), NULL, 10);
|
||||
sim_host.setHostByName(result["sim_host"].asString().c_str());
|
||||
sim_host.setPort(sim_port);
|
||||
|
||||
if (sim_host.isOk())
|
||||
{
|
||||
LLMessageSystem* msg = gMessageSystem;
|
||||
gMessageSystem->enableCircuit(sim_host, TRUE);
|
||||
msg->newMessageFast(_PREHASH_UseCircuitCode);
|
||||
msg->nextBlockFast(_PREHASH_CircuitCode);
|
||||
msg->addU32Fast(_PREHASH_Code, msg->getOurCircuitCode());
|
||||
msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
|
||||
msg->addUUIDFast(_PREHASH_ID, gAgent.getID());
|
||||
msg->sendReliable(sim_host);
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_INFOS("OGPX") << "TP failed, could not resolve hostname for UDP messages." << LL_ENDL;
|
||||
LLSD args;
|
||||
args["REASON"] = "Failed to resolve host.";
|
||||
//gViewerWindow->alertXml("CouldNotTeleportReason", args);
|
||||
LLNotificationsUtil::add("CouldNotTeleportReason", args);
|
||||
gAgent.setTeleportState( LLAgent::TELEPORT_NONE );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Viewer trusts the simulator.
|
||||
LLViewerRegion* regionp = LLWorld::getInstance()->addRegion(region_handle, sim_host);
|
||||
regionp->setSeedCapability(content["seed_capability"].asString().c_str());
|
||||
// process_agent_movement_complete needs the region to still be the old region gAgent.setRegion(regionp);
|
||||
|
||||
// placing these in result so they can be set properly in LLUserAuth result
|
||||
// ...they are only passed in on login, and not on TP
|
||||
result["session_id"] = gAgent.getSessionID();
|
||||
result["agent_id"] = gAgent.getID();
|
||||
result["circuit_code"].asString() = gMessageSystem->mOurCircuitCode; // this is what startup sets, is this proper to do?
|
||||
|
||||
// grab the skeleton and root.
|
||||
result["inventory-skeleton"] = LLUserAuth::getInstance()->mResult["inventory-skeleton"];
|
||||
result["inventory-root"] = LLUserAuth::getInstance()->mResult["inventory-root"];
|
||||
|
||||
LL_DEBUGS("OGPX") << "session_id: " << result["session_id"] << LL_ENDL;
|
||||
|
||||
|
||||
|
||||
// results need to be stored so process_agent_movement_complete() can pull them
|
||||
LLUserAuth::getInstance()->mAuthResponse = LLUserAuth::E_OK;
|
||||
|
||||
// OGPX TODO: This just reeks of causing problems, because we are using
|
||||
// ... mResult to store things that we get from other caps....So slamming a
|
||||
// ... completely new result in on teleport is going to cause issues.
|
||||
// ... It makes changing the things we save in mResult error prone.
|
||||
// ... Question is, how should we really be storing the seemingly random things
|
||||
// ... that we get back from (now) various different caps that used to all come back
|
||||
// ... in the result of XMLRPC authenticate?
|
||||
LLUserAuth::getInstance()->mResult = result;
|
||||
|
||||
|
||||
|
||||
// ... new sim not sending me much without sending it CompleteAgentMovement msg.
|
||||
//gAgent.setTeleportState( LLAgent::TELEPORT_MOVING ); // process_agent_mv_complete looks for TELEPORT_MOVING
|
||||
LLVector3 position = ll_vector3_from_sd(result["position"]);
|
||||
gAgent.setHomePosRegion(region_handle, position); // taken from teleport_finish (not sure regular code path gets this)
|
||||
|
||||
send_complete_agent_movement(sim_host);
|
||||
|
||||
// Turn off progress msg (also need to do this in all the possible failure places)
|
||||
// I think we leave this, as the scene is still changing during the
|
||||
// processing of agentmovementcomeplete message. TELEPORT_NONE resets it anyway
|
||||
// gViewerWindow->setShowProgress(FALSE);
|
||||
|
||||
}
|
||||
|
||||
/*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return placeAvatarTeleportResponder_timeout; }
|
||||
/*virtual*/ char const* getName(void) const { return "LLPlaceAvatarTeleportResponder"; }
|
||||
};
|
||||
|
||||
// Statics
|
||||
LLFloaterTeleport* LLFloaterTeleport::sInstance = NULL;
|
||||
|
||||
LLFloaterTeleport::LLFloaterTeleport()
|
||||
: LLFloater("floater_teleport")
|
||||
{
|
||||
if(!sInstance)
|
||||
{
|
||||
LLUICtrlFactory::getInstance()->buildFloater(this, "floater_teleport.xml");
|
||||
|
||||
LLComboBox* regioncombo = getChild<LLComboBox>("teleport_edit");
|
||||
regioncombo->setAllowTextEntry(TRUE, 256, FALSE); // URL bar needs to allow user text input
|
||||
|
||||
// iterate on uri list adding to combobox (couldn't figure out how to add them all in one call)
|
||||
LLSD regionuri_history = LLURLHistory::getURLHistory("regionuri");
|
||||
LLSD::array_iterator iter_history = regionuri_history.beginArray();
|
||||
LLSD::array_iterator iter_end = regionuri_history.endArray();
|
||||
for(; iter_history != iter_end; ++iter_history)
|
||||
{
|
||||
regioncombo->addSimpleElement((*iter_history).asString());
|
||||
}
|
||||
|
||||
// select which is displayed if we have a current URL.
|
||||
regioncombo->setSelectedByValue(LLSD(gSavedSettings.getString("CmdLineRegionURI")),TRUE);
|
||||
|
||||
// TODO : decide if 'enter' when selecting something from the combox box should *not* be sent
|
||||
// to the floater (p.s. and figure out how to change it)
|
||||
|
||||
childSetAction("teleport_btn", onClickTeleport, this);
|
||||
childSetAction("cancel_btn", onClickCancel, this);
|
||||
|
||||
setDefaultBtn("teleport_btn");
|
||||
}
|
||||
else
|
||||
{
|
||||
sInstance->show(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFloaterTeleport::show(void*)
|
||||
{
|
||||
if (!sInstance)
|
||||
{
|
||||
sInstance = new LLFloaterTeleport();
|
||||
}
|
||||
|
||||
sInstance->open();
|
||||
}
|
||||
|
||||
LLFloaterTeleport::~LLFloaterTeleport()
|
||||
{
|
||||
sInstance=NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// static
|
||||
void LLFloaterTeleport::onClickTeleport(void* userdata)
|
||||
{
|
||||
std::string placeAvatarCap = LLAppViewer::instance()->getPlaceAvatarCap();
|
||||
LLSD args;
|
||||
|
||||
LLFloaterTeleport* self = (LLFloaterTeleport*)userdata;
|
||||
std::string text = self->childGetText("teleport_edit");
|
||||
if (text.find("://",0) == std::string::npos)
|
||||
{
|
||||
// if there is no uri, prepend it with http://
|
||||
text = "http://"+text;
|
||||
LL_DEBUGS("OGPX") << "Teleport URI was prepended, now " << text << LL_ENDL;
|
||||
}
|
||||
|
||||
LL_DEBUGS("OGPX") << "onClickTeleport! from using place_avatar cap "<< placeAvatarCap << " contains "<< text << LL_ENDL;
|
||||
LLStringUtil::trim(text); // trim extra spacing
|
||||
gAgent.setTeleportSourceURL(gSavedSettings.getString("CmdLineRegionURI")); // grab src region name
|
||||
gSavedSettings.setString("CmdLineRegionURI",text); // save the dst region
|
||||
args["public_region_seed_capability"] = text;
|
||||
args["position"] = ll_sd_from_vector3(LLVector3(128, 128, 50)); // default to middle of region above base terrain
|
||||
LL_INFOS("OGPX") << " args to placeavatar cap " << placeAvatarCap << " on teleport: " << LLSDOStreamer<LLSDXMLFormatter>(args) << LL_ENDL;
|
||||
LLHTTPClient::post(placeAvatarCap, args, new LLPlaceAvatarTeleportResponder());
|
||||
gAgent.setTeleportMessage(
|
||||
LLAgent::sTeleportProgressMessages["requesting"]);
|
||||
gViewerWindow->setShowProgress(TRUE);
|
||||
gAgent.teleportCore();
|
||||
gAgent.setTeleportState( LLAgent::TELEPORT_PLACE_AVATAR ); // teleportcore() sets tp state to legacy path, so reset. ick!
|
||||
gTeleportDisplayTimer.reset();
|
||||
|
||||
|
||||
|
||||
self->setVisible(FALSE);
|
||||
if ( LLURLHistory::appendToURLCollection("regionuri",text))
|
||||
{
|
||||
// since URL history only populated on create of sInstance, add to combo list directly
|
||||
LLComboBox* regioncombo = self->getChild<LLComboBox>("teleport_edit");
|
||||
// BUG : this should add the new item to the combo box, but doesn't
|
||||
regioncombo->addSimpleElement(text);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void LLFloaterTeleport::onClickCancel(void *userdata)
|
||||
{
|
||||
LLFloaterTeleport* self = (LLFloaterTeleport*)userdata;
|
||||
LL_INFOS("OGPX") << "Teleport Cancel " << self->getName() << LL_ENDL;
|
||||
self->setVisible(FALSE);
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
/**
|
||||
* @file llfloaterteleport.h
|
||||
* @brief floater header for agentd teleports.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2008&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2008, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
// Teleport floater for agent domain TPs using URIs.
|
||||
//Copyright International Business Machines Corporation 2008-9
|
||||
//Contributed to Linden Research, Inc. under the Second Life Viewer Contribution
|
||||
//Agreement and licensed as above.
|
||||
#ifndef LL_FLOATER_TELEPORT_H
|
||||
#define LL_FLOATER_TELEPORT_H
|
||||
#include "llfloater.h"
|
||||
|
||||
class LLFloaterTeleport : public LLFloater
|
||||
{
|
||||
public:
|
||||
LLFloaterTeleport();
|
||||
|
||||
virtual ~LLFloaterTeleport();
|
||||
|
||||
// by convention, this shows the floater and does instance management
|
||||
static void show(void*);
|
||||
|
||||
private:
|
||||
// when a line editor loses keyboard focus, it is committed.
|
||||
// commit callbacks are named onCommitWidgetName by convention.
|
||||
static void onCommitTeleport(LLUICtrl* ctrl, void *userdata);
|
||||
|
||||
// by convention, button callbacks are named onClickButtonLabel
|
||||
static void onClickTeleport(void* userdata);
|
||||
static void onClickCancel(void *userdata);
|
||||
|
||||
// no pointers to widgets here - they are referenced by name
|
||||
|
||||
// assuming we just need one, which is typical
|
||||
static LLFloaterTeleport* sInstance;
|
||||
|
||||
};
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user