diff options
Diffstat (limited to 'indra')
212 files changed, 18730 insertions, 6202 deletions
diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index 279d577a27..9b836aac5f 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -37,6 +37,7 @@ set(cmake_SOURCE_FILES GLOD.cmake GStreamer010Plugin.cmake GooglePerfTools.cmake + Hunspell.cmake JPEG.cmake LLAddBuildTest.cmake LLAudio.cmake diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake index 966300f1c7..9f05c4cff2 100644 --- a/indra/cmake/Copy3rdPartyLibs.cmake +++ b/indra/cmake/Copy3rdPartyLibs.cmake @@ -41,6 +41,7 @@ if(WINDOWS) libeay32.dll libcollada14dom22-d.dll glod.dll + libhunspell.dll ) set(release_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}") @@ -53,6 +54,7 @@ if(WINDOWS) libeay32.dll libcollada14dom22.dll glod.dll + libhunspell.dll ) if(USE_TCMALLOC) @@ -212,11 +214,12 @@ elseif(DARWIN) libexpat.1.5.2.dylib libexpat.dylib libGLOD.dylib - libllqtwebkit.dylib - libminizip.a + libllqtwebkit.dylib + libminizip.a libndofdev.dylib + libhunspell-1.3.0.dylib libexception_handler.dylib - libcollada14dom.dylib + libcollada14dom.dylib ) # fmod is statically linked on darwin @@ -257,14 +260,15 @@ elseif(LINUX) libdb-5.1.so libexpat.so libexpat.so.1 - libglod.so + libglod.so libgmock_main.so libgmock.so.0 libgmodule-2.0.so libgobject-2.0.so libgtest_main.so libgtest.so.0 - libminizip.so + libhunspell-1.3.so.0.0.0 + libminizip.so libopenal.so libopenjpeg.so libssl.so diff --git a/indra/cmake/FindHUNSPELL.cmake b/indra/cmake/FindHUNSPELL.cmake new file mode 100644 index 0000000000..6faf22959c --- /dev/null +++ b/indra/cmake/FindHUNSPELL.cmake @@ -0,0 +1,38 @@ +# -*- cmake -*- + +# - Find HUNSPELL +# This module defines +# HUNSPELL_INCLUDE_DIR, where to find libhunspell.h, etc. +# HUNSPELL_LIBRARY, the library needed to use HUNSPELL. +# HUNSPELL_FOUND, If false, do not try to use HUNSPELL. + +find_path(HUNSPELL_INCLUDE_DIR hunspell.h + PATH_SUFFIXES hunspell + ) + +set(HUNSPELL_NAMES ${HUNSPELL_NAMES} libhunspell-1.3.0 libhunspell) +find_library(HUNSPELL_LIBRARY + NAMES ${HUNSPELL_NAMES} + ) + +if (HUNSPELL_LIBRARY AND HUNSPELL_INCLUDE_DIR) + set(HUNSPELL_FOUND "YES") +else (HUNSPELL_LIBRARY AND HUNSPELL_INCLUDE_DIR) + set(HUNSPELL_FOUND "NO") +endif (HUNSPELL_LIBRARY AND HUNSPELL_INCLUDE_DIR) + + +if (HUNSPELL_FOUND) + if (NOT HUNSPELL_FIND_QUIETLY) + message(STATUS "Found Hunspell: Library in '${HUNSPELL_LIBRARY}' and header in '${HUNSPELL_INCLUDE_DIR}' ") + endif (NOT HUNSPELL_FIND_QUIETLY) +else (HUNSPELL_FOUND) + if (HUNSPELL_FIND_REQUIRED) + message(FATAL_ERROR " * * *\nCould not find HUNSPELL library! * * *") + endif (HUNSPELL_FIND_REQUIRED) +endif (HUNSPELL_FOUND) + +mark_as_advanced( + HUNSPELL_LIBRARY + HUNSPELL_INCLUDE_DIR + ) diff --git a/indra/cmake/Hunspell.cmake b/indra/cmake/Hunspell.cmake new file mode 100644 index 0000000000..0c9cf93316 --- /dev/null +++ b/indra/cmake/Hunspell.cmake @@ -0,0 +1,22 @@ +# -*- cmake -*- +include(Prebuilt) + +set(HUNSPELL_FIND_QUIETLY ON) +set(HUNSPELL_FIND_REQUIRED ON) + +if (STANDALONE) + include(FindHUNSPELL) +else (STANDALONE) + use_prebuilt_binary(libhunspell) + if (WINDOWS) + set(HUNSPELL_LIBRARY libhunspell) + elseif(DARWIN) + set(HUNSPELL_LIBRARY hunspell-1.3.0) + elseif(LINUX) + set(HUNSPELL_LIBRARY hunspell-1.3) + else() + message(FATAL_ERROR "Invalid platform") + endif() + set(HUNSPELL_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/hunspell) + use_prebuilt_binary(dictionaries) +endif (STANDALONE) diff --git a/indra/cmake/ViewerMiscLibs.cmake b/indra/cmake/ViewerMiscLibs.cmake index df013b1665..f907181929 100644 --- a/indra/cmake/ViewerMiscLibs.cmake +++ b/indra/cmake/ViewerMiscLibs.cmake @@ -2,6 +2,7 @@ include(Prebuilt) if (NOT STANDALONE) + use_prebuilt_binary(libhunspell) use_prebuilt_binary(libuuid) use_prebuilt_binary(slvoice) use_prebuilt_binary(fontconfig) diff --git a/indra/integration_tests/llui_libtest/CMakeLists.txt b/indra/integration_tests/llui_libtest/CMakeLists.txt index 633ad84159..91c9f20c10 100644 --- a/indra/integration_tests/llui_libtest/CMakeLists.txt +++ b/indra/integration_tests/llui_libtest/CMakeLists.txt @@ -18,6 +18,7 @@ include(LLWindow) include(LLUI) include(LLVFS) # ugh, needed for LLDir include(LLXML) +include(Hunspell) include(Linking) # include(Tut) @@ -31,6 +32,7 @@ include_directories( ${LLVFS_INCLUDE_DIRS} ${LLWINDOW_INCLUDE_DIRS} ${LLXML_INCLUDE_DIRS} + ${LIBS_PREBUILD_DIR}/include/hunspell ) set(llui_libtest_SOURCE_FILES @@ -78,6 +80,7 @@ target_link_libraries(llui_libtest ${LLIMAGEJ2COJ_LIBRARIES} ${OS_LIBRARIES} ${GOOGLE_PERFTOOLS_LIBRARIES} + ${HUNSPELL_LIBRARY} ) if (WINDOWS) diff --git a/indra/llcommon/llsd.cpp b/indra/llcommon/llsd.cpp index e295e3c621..8276ec836a 100644 --- a/indra/llcommon/llsd.cpp +++ b/indra/llcommon/llsd.cpp @@ -269,6 +269,7 @@ namespace virtual LLSD::UUID asUUID() const { return LLUUID(mValue); } virtual LLSD::Date asDate() const { return LLDate(mValue); } virtual LLSD::URI asURI() const { return LLURI(mValue); } + virtual int size() const { return mValue.size(); } }; LLSD::Integer ImplString::asInteger() const diff --git a/indra/llcommon/llstrider.h b/indra/llcommon/llstrider.h index f4c43bac61..ed9284d2c5 100644 --- a/indra/llcommon/llstrider.h +++ b/indra/llcommon/llstrider.h @@ -44,6 +44,15 @@ public: const LLStrider<Object>& operator = (Object *first) { mObjectp = first; return *this;} void setStride (S32 skipBytes) { mSkip = (skipBytes ? skipBytes : sizeof(Object));} + LLStrider<Object> operator+(const S32& index) + { + LLStrider<Object> ret; + ret.mBytep = mBytep + mSkip*index; + ret.mSkip = mSkip; + + return ret; + } + void skip(const U32 index) { mBytep += mSkip*index;} U32 getSkip() const { return mSkip; } Object* get() { return mObjectp; } @@ -51,6 +60,7 @@ public: Object& operator *() { return *mObjectp; } Object* operator ++(int) { Object* old = mObjectp; mBytep += mSkip; return old; } Object* operator +=(int i) { mBytep += mSkip*i; return mObjectp; } + Object& operator[](U32 index) { return *(Object*)(mBytep + (mSkip * index)); } }; diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index 09733e8e2a..119efc7957 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -183,6 +183,9 @@ public: static bool isPunct(char a) { return ispunct((unsigned char)a) != 0; } static bool isPunct(llwchar a) { return iswpunct(a) != 0; } + static bool isAlpha(char a) { return isalpha((unsigned char)a) != 0; } + static bool isAlpha(llwchar a) { return iswalpha(a) != 0; } + static bool isAlnum(char a) { return isalnum((unsigned char)a) != 0; } static bool isAlnum(llwchar a) { return iswalnum(a) != 0; } diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h index bfb30f900f..9af16a0ed8 100644 --- a/indra/llcommon/llversionviewer.h +++ b/indra/llcommon/llversionviewer.h @@ -29,7 +29,7 @@ const S32 LL_VERSION_MAJOR = 3; const S32 LL_VERSION_MINOR = 3; -const S32 LL_VERSION_PATCH = 3; +const S32 LL_VERSION_PATCH = 5; const S32 LL_VERSION_BUILD = 0; const char * const LL_CHANNEL = "Second Life Developer"; diff --git a/indra/llinventory/llparcel.h b/indra/llinventory/llparcel.h index e36d0b20d2..f0b2caca3d 100644 --- a/indra/llinventory/llparcel.h +++ b/indra/llinventory/llparcel.h @@ -45,7 +45,7 @@ const S32 PARCEL_UNIT_AREA = 16; const F32 PARCEL_HEIGHT = 50.f; //Height above ground which parcel boundries exist for explicitly banned avatars -const F32 BAN_HEIGHT = 768.f; +const F32 BAN_HEIGHT = 5000.f; // Maximum number of entries in an access list const S32 PARCEL_MAX_ACCESS_LIST = 300; diff --git a/indra/llmath/llmath.h b/indra/llmath/llmath.h index 9297bcbac2..b93f89d674 100644 --- a/indra/llmath/llmath.h +++ b/indra/llmath/llmath.h @@ -85,7 +85,7 @@ const F32 F_ALMOST_ONE = 1.0f - F_ALMOST_ZERO; const F32 FP_MAG_THRESHOLD = 0.0000001f; // TODO: Replace with logic like is_approx_equal -inline BOOL is_approx_zero( F32 f ) { return (-F_APPROXIMATELY_ZERO < f) && (f < F_APPROXIMATELY_ZERO); } +inline bool is_approx_zero( F32 f ) { return (-F_APPROXIMATELY_ZERO < f) && (f < F_APPROXIMATELY_ZERO); } // These functions work by interpreting sign+exp+mantissa as an unsigned // integer. @@ -111,13 +111,13 @@ inline BOOL is_approx_zero( F32 f ) { return (-F_APPROXIMATELY_ZERO < f) && (f < // WARNING: Infinity is comparable with F32_MAX and negative // infinity is comparable with F32_MIN -inline BOOL is_approx_equal(F32 x, F32 y) +inline bool is_approx_equal(F32 x, F32 y) { const S32 COMPARE_MANTISSA_UP_TO_BIT = 0x02; return (std::abs((S32) ((U32&)x - (U32&)y) ) < COMPARE_MANTISSA_UP_TO_BIT); } -inline BOOL is_approx_equal(F64 x, F64 y) +inline bool is_approx_equal(F64 x, F64 y) { const S64 COMPARE_MANTISSA_UP_TO_BIT = 0x02; return (std::abs((S32) ((U64&)x - (U64&)y) ) < COMPARE_MANTISSA_UP_TO_BIT); diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index 76cf9de613..2e6f9e2f71 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -54,6 +54,7 @@ class LLVolumeTriangle; #include "llstrider.h" #include "v4coloru.h" #include "llrefcount.h" +#include "llpointer.h" #include "llfile.h" //============================================================================ @@ -919,6 +920,10 @@ public: LLVector2* mTexCoords; U16* mIndices; + //vertex buffer filled in by LLFace to cache this volume face geometry in vram + // (declared as a LLPointer to LLRefCount to avoid dependency on LLVertexBuffer) + mutable LLPointer<LLRefCount> mVertexBuffer; + std::vector<S32> mEdge; //list of skin weights for rigged volumes diff --git a/indra/llmessage/llsdmessagereader.cpp b/indra/llmessage/llsdmessagereader.cpp index 3d8ca2ad9f..a6fccd2a56 100644 --- a/indra/llmessage/llsdmessagereader.cpp +++ b/indra/llmessage/llsdmessagereader.cpp @@ -276,7 +276,7 @@ S32 getElementSize(const LLSD& llsd) case LLSD::TypeReal: return sizeof(F64); case LLSD::TypeString: - return llsd.asString().size(); + return llsd.size(); case LLSD::TypeUUID: return sizeof(LLUUID); case LLSD::TypeDate: diff --git a/indra/llrender/llcubemap.cpp b/indra/llrender/llcubemap.cpp index 45a3b18179..362452d837 100644 --- a/indra/llrender/llcubemap.cpp +++ b/indra/llrender/llcubemap.cpp @@ -81,7 +81,7 @@ void LLCubeMap::initGL() { U32 texname = 0; - LLImageGL::generateTextures(1, &texname); + LLImageGL::generateTextures(LLTexUnit::TT_CUBE_MAP, GL_RGB8, 1, &texname); for (int i = 0; i < 6; i++) { diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp index fccbf37a8d..4dc2fcd714 100644 --- a/indra/llrender/llfontgl.cpp +++ b/indra/llrender/llfontgl.cpp @@ -422,6 +422,16 @@ S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y } // font metrics - override for LLFontFreetype that returns units of virtual pixels +F32 LLFontGL::getAscenderHeight() const +{ + return mFontFreetype->getAscenderHeight() / sScaleY; +} + +F32 LLFontGL::getDescenderHeight() const +{ + return mFontFreetype->getDescenderHeight() / sScaleY; +} + S32 LLFontGL::getLineHeight() const { return llceil(mFontFreetype->getAscenderHeight() / sScaleY) + llceil(mFontFreetype->getDescenderHeight() / sScaleY); diff --git a/indra/llrender/llfontgl.h b/indra/llrender/llfontgl.h index 74bdbb43e7..5ed5d2c4eb 100644 --- a/indra/llrender/llfontgl.h +++ b/indra/llrender/llfontgl.h @@ -115,6 +115,8 @@ public: S32 renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style = NORMAL, ShadowType shadow = NO_SHADOW) const; // font metrics - override for LLFontFreetype that returns units of virtual pixels + F32 getAscenderHeight() const; + F32 getDescenderHeight() const; S32 getLineHeight() const; S32 getWidth(const std::string& utf8text) const; diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index 628a8d6131..0b56b3889c 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -249,6 +249,12 @@ PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample = NULL; PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv = NULL; PFNGLSAMPLEMASKIPROC glSampleMaski = NULL; +//transform feedback (4.0 core) +PFNGLBEGINTRANSFORMFEEDBACKPROC glBeginTransformFeedback = NULL; +PFNGLENDTRANSFORMFEEDBACKPROC glEndTransformFeedback = NULL; +PFNGLTRANSFORMFEEDBACKVARYINGSPROC glTransformFeedbackVaryings = NULL; +PFNGLBINDBUFFERRANGEPROC glBindBufferRange = NULL; + //GL_ARB_debug_output PFNGLDEBUGMESSAGECONTROLARBPROC glDebugMessageControlARB = NULL; PFNGLDEBUGMESSAGEINSERTARBPROC glDebugMessageInsertARB = NULL; @@ -421,6 +427,7 @@ LLGLManager::LLGLManager() : mHasDrawBuffers(FALSE), mHasTextureRectangle(FALSE), mHasTextureMultisample(FALSE), + mHasTransformFeedback(FALSE), mMaxSampleMaskWords(0), mMaxColorTextureSamples(0), mMaxDepthTextureSamples(0), @@ -558,7 +565,8 @@ bool LLGLManager::initGL() parse_gl_version( &mDriverVersionMajor, &mDriverVersionMinor, &mDriverVersionRelease, - &mDriverVersionVendorString ); + &mDriverVersionVendorString, + &mGLVersionString); mGLVersion = mDriverVersionMajor + mDriverVersionMinor * .1f; @@ -938,7 +946,6 @@ void LLGLManager::initExtensions() mHasMultitexture = glh_init_extensions("GL_ARB_multitexture"); mHasATIMemInfo = ExtensionExists("GL_ATI_meminfo", gGLHExts.mSysExts); mHasNVXMemInfo = ExtensionExists("GL_NVX_gpu_memory_info", gGLHExts.mSysExts); - mHasMipMapGeneration = glh_init_extensions("GL_SGIS_generate_mipmap"); mHasSeparateSpecularColor = glh_init_extensions("GL_EXT_separate_specular_color"); mHasAnisotropic = glh_init_extensions("GL_EXT_texture_filter_anisotropic"); glh_init_extensions("GL_ARB_texture_cube_map"); @@ -963,11 +970,14 @@ void LLGLManager::initExtensions() ExtensionExists("GL_EXT_packed_depth_stencil", gGLHExts.mSysExts); #endif + mHasMipMapGeneration = mHasFramebufferObject || mGLVersion >= 1.4f; + mHasDrawBuffers = ExtensionExists("GL_ARB_draw_buffers", gGLHExts.mSysExts); mHasBlendFuncSeparate = ExtensionExists("GL_EXT_blend_func_separate", gGLHExts.mSysExts); mHasTextureRectangle = ExtensionExists("GL_ARB_texture_rectangle", gGLHExts.mSysExts); mHasTextureMultisample = ExtensionExists("GL_ARB_texture_multisample", gGLHExts.mSysExts); mHasDebugOutput = ExtensionExists("GL_ARB_debug_output", gGLHExts.mSysExts); + mHasTransformFeedback = mGLVersion >= 4.f ? TRUE : FALSE; #if !LL_DARWIN mHasPointParameters = !mIsATI && ExtensionExists("GL_ARB_point_parameters", gGLHExts.mSysExts); #endif @@ -1207,7 +1217,14 @@ void LLGLManager::initExtensions() glTexImage3DMultisample = (PFNGLTEXIMAGE3DMULTISAMPLEPROC) GLH_EXT_GET_PROC_ADDRESS("glTexImage3DMultisample"); glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC) GLH_EXT_GET_PROC_ADDRESS("glGetMultisamplefv"); glSampleMaski = (PFNGLSAMPLEMASKIPROC) GLH_EXT_GET_PROC_ADDRESS("glSampleMaski"); - } + } + if (mHasTransformFeedback) + { + glBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC) GLH_EXT_GET_PROC_ADDRESS("glBeginTransformFeedback"); + glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC) GLH_EXT_GET_PROC_ADDRESS("glEndTransformFeedback"); + glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC) GLH_EXT_GET_PROC_ADDRESS("glTransformFeedbackVaryings"); + glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC) GLH_EXT_GET_PROC_ADDRESS("glBindBufferRange"); + } if (mHasDebugOutput) { glDebugMessageControlARB = (PFNGLDEBUGMESSAGECONTROLARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDebugMessageControlARB"); @@ -1964,6 +1981,7 @@ LLGLState::LLGLState(LLGLenum state, S32 enabled) : case GL_COLOR_MATERIAL: case GL_FOG: case GL_LINE_STIPPLE: + case GL_POLYGON_STIPPLE: mState = 0; break; } @@ -2052,7 +2070,7 @@ void LLGLManager::initGLStates() //////////////////////////////////////////////////////////////////////////////// -void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific ) +void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific, std::string* version_string ) { // GL_VERSION returns a null-terminated string with the format: // <major>.<minor>[.<release>] [<vendor specific>] @@ -2068,6 +2086,8 @@ void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor return; } + version_string->assign(version); + std::string ver_copy( version ); S32 len = (S32)strlen( version ); /* Flawfinder: ignore */ S32 i = 0; @@ -2429,3 +2449,65 @@ LLGLSquashToFarClip::~LLGLSquashToFarClip() gGL.matrixMode(LLRender::MM_MODELVIEW); } + + +LLGLSyncFence::LLGLSyncFence() +{ +#ifdef GL_ARB_sync + mSync = 0; +#endif +} + +LLGLSyncFence::~LLGLSyncFence() +{ +#ifdef GL_ARB_sync + if (mSync) + { + glDeleteSync(mSync); + } +#endif +} + +void LLGLSyncFence::placeFence() +{ +#ifdef GL_ARB_sync + if (mSync) + { + glDeleteSync(mSync); + } + mSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); +#endif +} + +bool LLGLSyncFence::isCompleted() +{ + bool ret = true; +#ifdef GL_ARB_sync + if (mSync) + { + GLenum status = glClientWaitSync(mSync, 0, 1); + if (status == GL_TIMEOUT_EXPIRED) + { + ret = false; + } + } +#endif + return ret; +} + +void LLGLSyncFence::wait() +{ +#ifdef GL_ARB_sync + if (mSync) + { + while (glClientWaitSync(mSync, 0, FENCE_WAIT_TIME_NANOSECONDS) == GL_TIMEOUT_EXPIRED) + { //track the number of times we've waited here + static S32 waits = 0; + waits++; + } + } +#endif +} + + + diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h index 5a33c98708..964495a3ab 100644 --- a/indra/llrender/llgl.h +++ b/indra/llrender/llgl.h @@ -104,6 +104,7 @@ public: BOOL mHasDepthClamp; BOOL mHasTextureRectangle; BOOL mHasTextureMultisample; + BOOL mHasTransformFeedback; S32 mMaxSampleMaskWords; S32 mMaxColorTextureSamples; S32 mMaxDepthTextureSamples; @@ -141,6 +142,7 @@ public: S32 mGLSLVersionMajor; S32 mGLSLVersionMinor; std::string mDriverVersionVendorString; + std::string mGLVersionString; S32 mVRAM; // VRAM in MB S32 mGLMaxVertexRange; @@ -417,13 +419,38 @@ public: virtual void updateGL() = 0; }; +const U32 FENCE_WAIT_TIME_NANOSECONDS = 1000; //1 ms + +class LLGLFence +{ +public: + virtual void placeFence() = 0; + virtual bool isCompleted() = 0; + virtual void wait() = 0; +}; + +class LLGLSyncFence : public LLGLFence +{ +public: +#ifdef GL_ARB_sync + GLsync mSync; +#endif + + LLGLSyncFence(); + virtual ~LLGLSyncFence(); + + void placeFence(); + bool isCompleted(); + void wait(); +}; + extern LLMatrix4 gGLObliqueProjectionInverse; #include "llglstates.h" void init_glstates(); -void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific ); +void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific, std::string* version_string ); extern BOOL gClothRipple; extern BOOL gHeadlessClient; diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h index d61ec707f0..a0727b8686 100644 --- a/indra/llrender/llglheaders.h +++ b/indra/llrender/llglheaders.h @@ -528,6 +528,13 @@ extern PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample; extern PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv; extern PFNGLSAMPLEMASKIPROC glSampleMaski; +//transform feedback (4.0 core) +extern PFNGLBEGINTRANSFORMFEEDBACKPROC glBeginTransformFeedback; +extern PFNGLENDTRANSFORMFEEDBACKPROC glEndTransformFeedback; +extern PFNGLTRANSFORMFEEDBACKVARYINGSPROC glTransformFeedbackVaryings; +extern PFNGLBINDBUFFERRANGEPROC glBindBufferRange; + + #elif LL_WINDOWS //---------------------------------------------------------------------------- // LL_WINDOWS @@ -759,6 +766,12 @@ extern PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample; extern PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv; extern PFNGLSAMPLEMASKIPROC glSampleMaski; +//transform feedback (4.0 core) +extern PFNGLBEGINTRANSFORMFEEDBACKPROC glBeginTransformFeedback; +extern PFNGLENDTRANSFORMFEEDBACKPROC glEndTransformFeedback; +extern PFNGLTRANSFORMFEEDBACKVARYINGSPROC glTransformFeedbackVaryings; +extern PFNGLBINDBUFFERRANGEPROC glBindBufferRange; + //GL_ARB_debug_output extern PFNGLDEBUGMESSAGECONTROLARBPROC glDebugMessageControlARB; extern PFNGLDEBUGMESSAGEINSERTARBPROC glDebugMessageInsertARB; diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp index 4b7e639aed..7cbf39096e 100644 --- a/indra/llrender/llglslshader.cpp +++ b/indra/llrender/llglslshader.cpp @@ -129,7 +129,9 @@ void LLGLSLShader::unload() } BOOL LLGLSLShader::createShader(vector<string> * attributes, - vector<string> * uniforms) + vector<string> * uniforms, + U32 varying_count, + const char** varyings) { //reloading, reset matrix hash values for (U32 i = 0; i < LLRender::NUM_MATRIX_MODES; ++i) @@ -172,6 +174,13 @@ BOOL LLGLSLShader::createShader(vector<string> * attributes, mFeatures.mIndexedTextureChannels = llmin(mFeatures.mIndexedTextureChannels, 1); } +#ifdef GL_INTERLEAVED_ATTRIBS + if (varying_count > 0 && varyings) + { + glTransformFeedbackVaryings(mProgramObject, varying_count, varyings, GL_INTERLEAVED_ATTRIBS); + } +#endif + // Map attributes and uniforms if (success) { diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h index 7873fe3c4e..5c68cb46eb 100644 --- a/indra/llrender/llglslshader.h +++ b/indra/llrender/llglslshader.h @@ -76,7 +76,9 @@ public: void unload(); BOOL createShader(std::vector<std::string> * attributes, - std::vector<std::string> * uniforms); + std::vector<std::string> * uniforms, + U32 varying_count = 0, + const char** varyings = NULL); BOOL attachObject(std::string object); void attachObject(GLhandleARB object); void attachObjects(GLhandleARB* objects = NULL, S32 count = 0); diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index c04a3f6b41..659d3ca409 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -42,6 +42,10 @@ //---------------------------------------------------------------------------- const F32 MIN_TEXTURE_LIFETIME = 10.f; +//which power of 2 is i? +//assumes i is a power of 2 > 0 +U32 wpo2(U32 i); + //statics U32 LLImageGL::sUniqueCount = 0; @@ -50,7 +54,8 @@ S32 LLImageGL::sGlobalTextureMemoryInBytes = 0; S32 LLImageGL::sBoundTextureMemoryInBytes = 0; S32 LLImageGL::sCurBoundTextureMemory = 0; S32 LLImageGL::sCount = 0; -std::list<U32> LLImageGL::sDeadTextureList; +LLImageGL::dead_texturelist_t LLImageGL::sDeadTextureList[LLTexUnit::TT_NONE]; +U32 LLImageGL::sCurTexName = 1; BOOL LLImageGL::sGlobalUseAnisotropic = FALSE; F32 LLImageGL::sLastFrameTime = 0.f; @@ -416,6 +421,7 @@ void LLImageGL::init(BOOL usemipmaps) mTarget = GL_TEXTURE_2D; mBindTarget = LLTexUnit::TT_TEXTURE; mHasMipMaps = false; + mMipLevels = -1; mIsResident = 0; @@ -606,8 +612,24 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) is_compressed = true; } + + + if (mUseMipMaps) + { + //set has mip maps to true before binding image so tex parameters get set properly + gGL.getTexUnit(0)->unbind(mBindTarget); + mHasMipMaps = true; + mTexOptionsDirty = true; + setFilteringOption(LLTexUnit::TFO_ANISOTROPIC); + } + else + { + mHasMipMaps = false; + } + llverify(gGL.getTexUnit(0)->bind(this)); + if (mUseMipMaps) { if (data_hasmips) @@ -620,6 +642,9 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) S32 w = getWidth(d); S32 h = getHeight(d); S32 gl_level = d-mCurrentDiscardLevel; + + mMipLevels = llmax(mMipLevels, gl_level); + if (d > mCurrentDiscardLevel) { data_in -= dataFormatBytes(mFormatPrimary, w, h); // see above comment @@ -662,10 +687,6 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) { if (mAutoGenMips) { - if (!gGLManager.mHasFramebufferObject) - { - glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_GENERATE_MIPMAP_SGIS, TRUE); - } stop_glerror(); { // LLFastTimer t2(FTM_TEMP4); @@ -679,6 +700,11 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) S32 w = getWidth(mCurrentDiscardLevel); S32 h = getHeight(mCurrentDiscardLevel); + mMipLevels = wpo2(llmax(w, h)); + + //use legacy mipmap generation mode + glTexParameteri(mTarget, GL_GENERATE_MIPMAP, GL_TRUE); + LLImageGL::setManualImage(mTarget, 0, mFormatInternal, w, h, mFormatPrimary, mFormatType, @@ -694,16 +720,10 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) stop_glerror(); } } - - if (gGLManager.mHasFramebufferObject) - { - glGenerateMipmap(LLTexUnit::getInternalType(mBindTarget)); - } } else { // Create mips by hand - // about 30% faster than autogen on ATI 9800, 50% slower on nVidia 4800 // ~4x faster than gluBuild2DMipmaps S32 width = getWidth(mCurrentDiscardLevel); S32 height = getHeight(mCurrentDiscardLevel); @@ -713,6 +733,9 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) const U8* cur_mip_data = 0; S32 prev_mip_size = 0; S32 cur_mip_size = 0; + + mMipLevels = nummips; + for (int m=0; m<nummips; m++) { if (m==0) @@ -777,10 +800,10 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) { llerrs << "Compressed Image has mipmaps but data does not (can not auto generate compressed mips)" << llendl; } - mHasMipMaps = true; } else { + mMipLevels = 0; S32 w = getWidth(); S32 h = getHeight(); if (is_compressed) @@ -812,7 +835,6 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) } } - mHasMipMaps = false; } stop_glerror(); mGLTextureCreated = true; @@ -1025,23 +1047,65 @@ BOOL LLImageGL::setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_ } // static -void LLImageGL::generateTextures(S32 numTextures, U32 *textures) +void LLImageGL::generateTextures(LLTexUnit::eTextureType type, U32 format, S32 numTextures, U32 *textures) { - glGenTextures(numTextures, (GLuint*)textures); + bool empty = true; + + dead_texturelist_t::iterator iter = sDeadTextureList[type].find(format); + + if (iter != sDeadTextureList[type].end()) + { + empty = iter->second.empty(); + } + + for (S32 i = 0; i < numTextures; ++i) + { + if (!empty) + { + textures[i] = iter->second.front(); + iter->second.pop_front(); + empty = iter->second.empty(); + } + else + { + textures[i] = sCurTexName++; + } + } } // static -void LLImageGL::deleteTextures(S32 numTextures, U32 *textures, bool immediate) +void LLImageGL::deleteTextures(LLTexUnit::eTextureType type, U32 format, S32 mip_levels, S32 numTextures, U32 *textures, bool immediate) { - for (S32 i = 0; i < numTextures; i++) + if (gGLManager.mInited) { - sDeadTextureList.push_back(textures[i]); - } + if (format == 0 || type == LLTexUnit::TT_CUBE_MAP || mip_levels == -1) + { //unknown internal format or unknown number of mip levels, not safe to reuse + glDeleteTextures(numTextures, textures); + } + else + { + for (S32 i = 0; i < numTextures; ++i) + { //remove texture from VRAM by setting its size to zero + for (S32 j = 0; j <= mip_levels; j++) + { + gGL.getTexUnit(0)->bindManual(type, textures[i]); + + glTexImage2D(LLTexUnit::getInternalType(type), j, format, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + } + + llassert(std::find(sDeadTextureList[type][format].begin(), + sDeadTextureList[type][format].end(), textures[i]) == + sDeadTextureList[type][format].end()); - if (immediate) + sDeadTextureList[type][format].push_back(textures[i]); + } + } + } + + /*if (immediate) { LLImageGL::deleteDeadTextures(); - } + }*/ } // static @@ -1166,10 +1230,11 @@ BOOL LLImageGL::createGLTexture() if(mTexName) { - glDeleteTextures(1, (reinterpret_cast<GLuint*>(&mTexName))) ; + LLImageGL::deleteTextures(mBindTarget, mFormatInternal, mMipLevels, 1, (reinterpret_cast<GLuint*>(&mTexName))) ; } - glGenTextures(1, (GLuint*)&mTexName); + + LLImageGL::generateTextures(mBindTarget, mFormatInternal, 1, &mTexName); stop_glerror(); if (!mTexName) { @@ -1282,7 +1347,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_ } else { - LLImageGL::generateTextures(1, &mTexName); + LLImageGL::generateTextures(mBindTarget, mFormatInternal, 1, &mTexName); stop_glerror(); { llverify(gGL.getTexUnit(0)->bind(this)); @@ -1327,7 +1392,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_ { sGlobalTextureMemoryInBytes -= mTextureMemory; - LLImageGL::deleteTextures(1, &old_name); + LLImageGL::deleteTextures(mBindTarget, mFormatInternal, mMipLevels, 1, &old_name); stop_glerror(); } @@ -1456,7 +1521,7 @@ void LLImageGL::deleteDeadTextures() { bool reset = false; - while (!sDeadTextureList.empty()) + /*while (!sDeadTextureList.empty()) { GLuint tex = sDeadTextureList.front(); sDeadTextureList.pop_front(); @@ -1478,7 +1543,7 @@ void LLImageGL::deleteDeadTextures() glDeleteTextures(1, &tex); stop_glerror(); - } + }*/ if (reset) { @@ -1496,7 +1561,7 @@ void LLImageGL::destroyGLTexture() mTextureMemory = 0; } - LLImageGL::deleteTextures(1, &mTexName); + LLImageGL::deleteTextures(mBindTarget, mFormatInternal, mMipLevels, 1, &mTexName); mCurrentDiscardLevel = -1 ; //invalidate mCurrentDiscardLevel. mTexName = 0; mGLTextureCreated = FALSE ; diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h index f34b9fa91a..e118c28c1b 100644 --- a/indra/llrender/llimagegl.h +++ b/indra/llrender/llimagegl.h @@ -45,8 +45,16 @@ class LLImageGL : public LLRefCount { friend class LLTexUnit; public: - static std::list<U32> sDeadTextureList; + static U32 sCurTexName; + //previously used but now available texture names + // sDeadTextureList[<usage>][<internal format>] + typedef std::map<U32, std::list<U32> > dead_texturelist_t; + static dead_texturelist_t sDeadTextureList[LLTexUnit::TT_NONE]; + + // These 2 functions replace glGenTextures() and glDeleteTextures() + static void generateTextures(LLTexUnit::eTextureType type, U32 format, S32 numTextures, U32 *textures); + static void deleteTextures(LLTexUnit::eTextureType type, U32 format, S32 mip_levels, S32 numTextures, U32 *textures, bool immediate = false); static void deleteDeadTextures(); // Size calculation @@ -96,10 +104,6 @@ public: void setComponents(S32 ncomponents) { mComponents = (S8)ncomponents ;} void setAllowCompression(bool allow) { mAllowCompression = allow; } - // These 3 functions currently wrap glGenTextures(), glDeleteTextures(), and glTexImage2D() - // for tracking purposes and will be deprecated in the future - static void generateTextures(S32 numTextures, U32 *textures); - static void deleteTextures(S32 numTextures, U32 *textures, bool immediate = false); static void setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels, bool allow_compression = true); BOOL createGLTexture() ; @@ -217,7 +221,8 @@ protected: LLGLenum mTarget; // Normally GL_TEXTURE2D, sometimes something else (ex. cube maps) LLTexUnit::eTextureType mBindTarget; // Normally TT_TEXTURE, sometimes something else (ex. cube maps) bool mHasMipMaps; - + S32 mMipLevels; + LLGLboolean mIsResident; S8 mComponents; diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index 93bac4c779..348c1eb1b7 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -408,12 +408,14 @@ void LLTexUnit::unbind(eTextureType type) if (mIndex < 0) return; + //always flush and activate for consistency + // some code paths assume unbind always flushes and sets the active texture + gGL.flush(); + activate(); + // Disabled caching of binding state. if (mCurrTexType == type) { - gGL.flush(); - - activate(); mCurrTexture = 0; if (LLGLSLShader::sNoFixedFunction && type == LLTexUnit::TT_TEXTURE) { @@ -464,11 +466,25 @@ void LLTexUnit::setTextureFilteringOption(LLTexUnit::eTextureFilterOptions optio } else if (option >= TFO_BILINEAR) { - glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_LINEAR); + if (mHasMipMaps) + { + glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); + } + else + { + glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } } else { - glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_NEAREST); + if (mHasMipMaps) + { + glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); + } + else + { + glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } } if (gGLManager.mHasAnisotropic) diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp index 780f1dc484..99f0da330c 100644 --- a/indra/llrender/llrendertarget.cpp +++ b/indra/llrender/llrendertarget.cpp @@ -55,7 +55,6 @@ bool LLRenderTarget::sUseFBO = false; LLRenderTarget::LLRenderTarget() : mResX(0), mResY(0), - mTex(0), mFBO(0), mDepth(0), mStencil(0), @@ -135,7 +134,7 @@ bool LLRenderTarget::addColorAttachment(U32 color_fmt) } U32 tex; - LLImageGL::generateTextures(1, &tex); + LLImageGL::generateTextures(mUsage, color_fmt, 1, &tex); gGL.getTexUnit(0)->bindManual(mUsage, tex); stop_glerror(); @@ -193,6 +192,7 @@ bool LLRenderTarget::addColorAttachment(U32 color_fmt) } mTex.push_back(tex); + mInternalFormat.push_back(color_fmt); if (gDebugGL) { //bind and unbind to validate target @@ -217,7 +217,7 @@ bool LLRenderTarget::allocateDepth() } else { - LLImageGL::generateTextures(1, &mDepth); + LLImageGL::generateTextures(mUsage, GL_DEPTH_COMPONENT24, 1, &mDepth); gGL.getTexUnit(0)->bindManual(mUsage, mDepth); U32 internal_type = LLTexUnit::getInternalType(mUsage); @@ -294,7 +294,7 @@ void LLRenderTarget::release() } else { - LLImageGL::deleteTextures(1, &mDepth, true); + LLImageGL::deleteTextures(mUsage, 0, 0, 1, &mDepth, true); stop_glerror(); } mDepth = 0; @@ -326,8 +326,9 @@ void LLRenderTarget::release() if (mTex.size() > 0) { sBytesAllocated -= mResX*mResY*4*mTex.size(); - LLImageGL::deleteTextures(mTex.size(), &mTex[0], true); + LLImageGL::deleteTextures(mUsage, mInternalFormat[0], 0, mTex.size(), &mTex[0], true); mTex.clear(); + mInternalFormat.clear(); } mResX = mResY = 0; diff --git a/indra/llrender/llrendertarget.h b/indra/llrender/llrendertarget.h index 2735ab21c5..8360458840 100644 --- a/indra/llrender/llrendertarget.h +++ b/indra/llrender/llrendertarget.h @@ -142,6 +142,7 @@ protected: U32 mResX; U32 mResY; std::vector<U32> mTex; + std::vector<U32> mInternalFormat; U32 mFBO; U32 mDepth; bool mStencil; diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index 5a6e6cab3e..d3b2d9fa74 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -1026,6 +1026,9 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("size"); mReservedUniforms.push_back("falloff"); + mReservedUniforms.push_back("box_center"); + mReservedUniforms.push_back("box_size"); + mReservedUniforms.push_back("minLuminance"); mReservedUniforms.push_back("maxExtractAlpha"); diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h index f792faa8f0..7a16b7c20f 100644 --- a/indra/llrender/llshadermgr.h +++ b/indra/llrender/llshadermgr.h @@ -97,6 +97,8 @@ public: LIGHT_CENTER, LIGHT_SIZE, LIGHT_FALLOFF, + BOX_CENTER, + BOX_SIZE, GLOW_MIN_LUMINANCE, GLOW_MAX_EXTRACT_ALPHA, diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index 823c6b9dc5..953546a36f 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -41,9 +41,7 @@ #if LL_DARWIN #define LL_VBO_POOLING 1 #else -#define LL_VBO_POOLING 0 #endif - //Next Highest Power Of Two //helper function, returns first number > v that is a power of 2, or v if v is already a power of 2 U32 nhpo2(U32 v) @@ -71,6 +69,7 @@ U32 wpo2(U32 i) const U32 LL_VBO_BLOCK_SIZE = 2048; +const U32 LL_VBO_POOL_MAX_SEED_SIZE = 256*1024; U32 vbo_block_size(U32 size) { //what block size will fit size? @@ -83,6 +82,7 @@ U32 vbo_block_index(U32 size) return vbo_block_size(size)/LL_VBO_BLOCK_SIZE; } +const U32 LL_VBO_POOL_SEED_COUNT = vbo_block_index(LL_VBO_POOL_MAX_SEED_SIZE); //============================================================================ @@ -95,6 +95,11 @@ LLVBOPool LLVertexBuffer::sDynamicIBOPool(GL_DYNAMIC_DRAW_ARB, GL_ELEMENT_ARRAY_ U32 LLVBOPool::sBytesPooled = 0; U32 LLVBOPool::sIndexBytesPooled = 0; +U32 LLVBOPool::sCurGLName = 1; + +std::list<U32> LLVertexBuffer::sAvailableVAOName; +U32 LLVertexBuffer::sCurVAOName = 1; + U32 LLVertexBuffer::sAllocatedIndexBytes = 0; U32 LLVertexBuffer::sIndexCount = 0; @@ -119,69 +124,55 @@ bool LLVertexBuffer::sUseStreamDraw = true; bool LLVertexBuffer::sUseVAO = false; bool LLVertexBuffer::sPreferStreamDraw = false; -const U32 FENCE_WAIT_TIME_NANOSECONDS = 10000; //1 ms -class LLGLSyncFence : public LLGLFence +U32 LLVBOPool::genBuffer() { -public: -#ifdef GL_ARB_sync - GLsync mSync; -#endif - - LLGLSyncFence() - { -#ifdef GL_ARB_sync - mSync = 0; -#endif - } + U32 ret = 0; - virtual ~LLGLSyncFence() + if (mGLNamePool.empty()) { -#ifdef GL_ARB_sync - if (mSync) - { - glDeleteSync(mSync); - } -#endif + ret = sCurGLName++; } - - void placeFence() + else { -#ifdef GL_ARB_sync - if (mSync) - { - glDeleteSync(mSync); - } - mSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); -#endif + ret = mGLNamePool.front(); + mGLNamePool.pop_front(); } - void wait() + return ret; +} + +void LLVBOPool::deleteBuffer(U32 name) +{ + if (gGLManager.mInited) { -#ifdef GL_ARB_sync - if (mSync) - { - while (glClientWaitSync(mSync, 0, FENCE_WAIT_TIME_NANOSECONDS) == GL_TIMEOUT_EXPIRED) - { //track the number of times we've waited here - static S32 waits = 0; - waits++; - } - } -#endif - } + LLVertexBuffer::unbind(); + + glBindBufferARB(mType, name); + glBufferDataARB(mType, 0, NULL, mUsage); + llassert(std::find(mGLNamePool.begin(), mGLNamePool.end(), name) == mGLNamePool.end()); + + mGLNamePool.push_back(name); + + glBindBufferARB(mType, 0); + } +} -}; +LLVBOPool::LLVBOPool(U32 vboUsage, U32 vboType) +: mUsage(vboUsage), mType(vboType) +{ + mMissCount.resize(LL_VBO_POOL_SEED_COUNT); + std::fill(mMissCount.begin(), mMissCount.end(), 0); +} -volatile U8* LLVBOPool::allocate(U32& name, U32 size) +volatile U8* LLVBOPool::allocate(U32& name, U32 size, bool for_seed) { llassert(vbo_block_size(size) == size); volatile U8* ret = NULL; -#if LL_VBO_POOLING - U32 i = vbo_block_index(size); if (mFreeList.size() <= i) @@ -189,12 +180,18 @@ volatile U8* LLVBOPool::allocate(U32& name, U32 size) mFreeList.resize(i+1); } - if (mFreeList[i].empty()) + if (mFreeList[i].empty() || for_seed) { //make a new buffer - glGenBuffersARB(1, &name); + name = genBuffer(); + glBindBufferARB(mType, name); + if (!for_seed && i < LL_VBO_POOL_SEED_COUNT) + { //record this miss + mMissCount[i]++; + } + if (mType == GL_ARRAY_BUFFER_ARB) { LLVertexBuffer::sAllocatedBytes += size; @@ -215,6 +212,25 @@ volatile U8* LLVBOPool::allocate(U32& name, U32 size) } glBindBufferARB(mType, 0); + + if (for_seed) + { //put into pool for future use + llassert(mFreeList.size() > i); + + Record rec; + rec.mGLName = name; + rec.mClientData = ret; + + if (mType == GL_ARRAY_BUFFER_ARB) + { + sBytesPooled += size; + } + else + { + sIndexBytesPooled += size; + } + mFreeList[i].push_back(rec); + } } else { @@ -232,33 +248,6 @@ volatile U8* LLVBOPool::allocate(U32& name, U32 size) mFreeList[i].pop_front(); } -#else //no pooling - - glGenBuffersARB(1, &name); - glBindBufferARB(mType, name); - - if (mType == GL_ARRAY_BUFFER_ARB) - { - LLVertexBuffer::sAllocatedBytes += size; - } - else - { - LLVertexBuffer::sAllocatedIndexBytes += size; - } - - if (LLVertexBuffer::sDisableVBOMapping || mUsage != GL_DYNAMIC_DRAW_ARB) - { - glBufferDataARB(mType, size, 0, mUsage); - ret = (U8*) ll_aligned_malloc_16(size); - } - else - { //always use a true hint of static draw when allocating non-client-backed buffers - glBufferDataARB(mType, size, 0, GL_STATIC_DRAW_ARB); - } - - glBindBufferARB(mType, 0); - -#endif return ret; } @@ -267,50 +256,47 @@ void LLVBOPool::release(U32 name, volatile U8* buffer, U32 size) { llassert(vbo_block_size(size) == size); -#if LL_VBO_POOLING - - U32 i = vbo_block_index(size); - - llassert(mFreeList.size() > i); + deleteBuffer(name); + ll_aligned_free_16((U8*) buffer); - Record rec; - rec.mGLName = name; - rec.mClientData = buffer; - - if (buffer == NULL) + if (mType == GL_ARRAY_BUFFER_ARB) { - glDeleteBuffersARB(1, &rec.mGLName); + LLVertexBuffer::sAllocatedBytes -= size; } else { - if (mType == GL_ARRAY_BUFFER_ARB) - { - sBytesPooled += size; - } - else - { - sIndexBytesPooled += size; - } - mFreeList[i].push_back(rec); + LLVertexBuffer::sAllocatedIndexBytes -= size; } -#else //no pooling - glDeleteBuffersARB(1, &name); - ll_aligned_free_16((U8*) buffer); +} - if (mType == GL_ARRAY_BUFFER_ARB) +void LLVBOPool::seedPool() +{ + U32 dummy_name = 0; + + if (mFreeList.size() < LL_VBO_POOL_SEED_COUNT) { - LLVertexBuffer::sAllocatedBytes -= size; + mFreeList.resize(LL_VBO_POOL_SEED_COUNT); } - else + + for (U32 i = 0; i < LL_VBO_POOL_SEED_COUNT; i++) { - LLVertexBuffer::sAllocatedIndexBytes -= size; + if (mMissCount[i] > mFreeList[i].size()) + { + U32 size = i*LL_VBO_BLOCK_SIZE; + + S32 count = mMissCount[i] - mFreeList[i].size(); + for (U32 j = 0; j < count; ++j) + { + allocate(dummy_name, size, true); + } + } } -#endif } + void LLVBOPool::cleanup() { - U32 size = 1; + U32 size = LL_VBO_BLOCK_SIZE; for (U32 i = 0; i < mFreeList.size(); ++i) { @@ -320,8 +306,8 @@ void LLVBOPool::cleanup() { Record& r = l.front(); - glDeleteBuffersARB(1, &r.mGLName); - + deleteBuffer(r.mGLName); + if (r.mClientData) { ll_aligned_free_16((void*) r.mClientData); @@ -341,8 +327,11 @@ void LLVBOPool::cleanup() } } - size *= 2; + size += LL_VBO_BLOCK_SIZE; } + + //reset miss counts + std::fill(mMissCount.begin(), mMissCount.end(), 0); } @@ -376,6 +365,41 @@ U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] = GL_LINE_LOOP, }; +//static +U32 LLVertexBuffer::getVAOName() +{ + U32 ret = 0; + + if (!sAvailableVAOName.empty()) + { + ret = sAvailableVAOName.front(); + sAvailableVAOName.pop_front(); + } + else + { +#ifdef GL_ARB_vertex_array_object + glGenVertexArrays(1, &ret); +#endif + } + + return ret; +} + +//static +void LLVertexBuffer::releaseVAOName(U32 name) +{ + sAvailableVAOName.push_back(name); +} + + +//static +void LLVertexBuffer::seedPools() +{ + sStreamVBOPool.seedPool(); + sDynamicVBOPool.seedPool(); + sStreamIBOPool.seedPool(); + sDynamicIBOPool.seedPool(); +} //static void LLVertexBuffer::setupClientArrays(U32 data_mask) @@ -985,7 +1009,7 @@ LLVertexBuffer::~LLVertexBuffer() if (mGLArray) { #if GL_ARB_vertex_array_object - glDeleteVertexArrays(1, &mGLArray); + releaseVAOName(mGLArray); #endif } @@ -1211,10 +1235,10 @@ void LLVertexBuffer::updateNumVerts(S32 nverts) llassert(nverts >= 0); - if (nverts >= 65535) + if (nverts > 65536) { llwarns << "Vertex buffer overflow!" << llendl; - nverts = 65535; + nverts = 65536; } U32 needed_size = calcOffsets(mTypeMask, mOffsets, nverts); @@ -1270,7 +1294,7 @@ void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create) if (gGLManager.mHasVertexArrayObject && useVBOs() && (LLRender::sGLCoreProfile || sUseVAO)) { #if GL_ARB_vertex_array_object - glGenVertexArrays(1, &mGLArray); + mGLArray = getVAOName(); #endif setupVertexArray(); } @@ -2140,6 +2164,16 @@ void LLVertexBuffer::flush() } } +// bind for transform feedback (quick 'n dirty) +void LLVertexBuffer::bindForFeedback(U32 channel, U32 type, U32 index, U32 count) +{ +#ifdef GL_TRANSFORM_FEEDBACK_BUFFER + U32 offset = mOffsets[type] + sTypeSize[type]*index; + U32 size= (sTypeSize[type]*count); + glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, channel, mGLBuffer, offset, size); +#endif +} + // Set for rendering void LLVertexBuffer::setBuffer(U32 data_mask) { @@ -2291,10 +2325,10 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) stop_glerror(); volatile U8* base = useVBOs() ? (U8*) mAlignedOffset : mMappedData; - /*if ((data_mask & mTypeMask) != data_mask) + if (gDebugGL && ((data_mask & mTypeMask) != data_mask)) { llerrs << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << llendl; - }*/ + } if (LLGLSLShader::sNoFixedFunction) { diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h index 7477dec3ad..11fa4ab6a0 100644 --- a/indra/llrender/llvertexbuffer.h +++ b/indra/llrender/llvertexbuffer.h @@ -57,23 +57,28 @@ public: static U32 sBytesPooled; static U32 sIndexBytesPooled; - LLVBOPool(U32 vboUsage, U32 vboType) - : mUsage(vboUsage) - , mType(vboType) - {} + static U32 sCurGLName; + LLVBOPool(U32 vboUsage, U32 vboType); + const U32 mUsage; const U32 mType; //size MUST be a power of 2 - volatile U8* allocate(U32& name, U32 size); + volatile U8* allocate(U32& name, U32 size, bool for_seed = false); //size MUST be the size provided to allocate that returned the given name void release(U32 name, volatile U8* buffer, U32 size); + //batch allocate buffers to be provided to the application on demand + void seedPool(); + //destroy all records in mFreeList void cleanup(); + U32 genBuffer(); + void deleteBuffer(U32 name); + class Record { public: @@ -81,17 +86,15 @@ public: volatile U8* mClientData; }; + std::list<U32> mGLNamePool; + typedef std::list<Record> record_list_t; std::vector<record_list_t> mFreeList; -}; + std::vector<U32> mMissCount; -class LLGLFence -{ -public: - virtual void placeFence() = 0; - virtual void wait() = 0; }; + //============================================================================ // base class class LLPrivateMemoryPool; @@ -125,13 +128,22 @@ public: static LLVBOPool sStreamIBOPool; static LLVBOPool sDynamicIBOPool; + static std::list<U32> sAvailableVAOName; + static U32 sCurVAOName; + static bool sUseStreamDraw; static bool sUseVAO; static bool sPreferStreamDraw; + static void seedPools(); + + static U32 getVAOName(); + static void releaseVAOName(U32 name); + static void initClass(bool use_vbo, bool no_vbo_mapping); static void cleanupClass(); static void setupClientArrays(U32 data_mask); + static void pushPositions(U32 mode, const LLVector4a* pos, U32 count); static void drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm); static void drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp); @@ -208,7 +220,6 @@ protected: void destroyGLIndices(); void updateNumVerts(S32 nverts); void updateNumIndices(S32 nindices); - bool useVBOs() const; void unmapBuffer(); public: @@ -218,6 +229,8 @@ public: volatile U8* mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range); volatile U8* mapIndexBuffer(S32 index, S32 count, bool map_range); + void bindForFeedback(U32 channel, U32 type, U32 index, U32 count); + // set for rendering virtual void setBuffer(U32 data_mask); // calls setupVertexBuffer() if data_mask is not 0 void flush(); //flush pending data to GL memory @@ -240,12 +253,14 @@ public: bool getNormalStrider(LLStrider<LLVector3>& strider, S32 index=0, S32 count = -1, bool map_range = false); bool getBinormalStrider(LLStrider<LLVector3>& strider, S32 index=0, S32 count = -1, bool map_range = false); bool getColorStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false); + bool getTextureIndexStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false); bool getEmissiveStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false); bool getWeightStrider(LLStrider<F32>& strider, S32 index=0, S32 count = -1, bool map_range = false); bool getWeight4Strider(LLStrider<LLVector4>& strider, S32 index=0, S32 count = -1, bool map_range = false); bool getClothWeightStrider(LLStrider<LLVector4>& strider, S32 index=0, S32 count = -1, bool map_range = false); + bool useVBOs() const; bool isEmpty() const { return mEmpty; } bool isLocked() const { return mVertexLocked || mIndexLocked; } S32 getNumVerts() const { return mNumVerts; } diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 20c3456a56..cca4ca3981 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -23,6 +23,7 @@ include_directories( ${LLWINDOW_INCLUDE_DIRS} ${LLVFS_INCLUDE_DIRS} ${LLXML_INCLUDE_DIRS} + ${LIBS_PREBUILD_DIR}/include/hunspell ) set(llui_SOURCE_FILES @@ -84,6 +85,7 @@ set(llui_SOURCE_FILES llsearcheditor.cpp llslider.cpp llsliderctrl.cpp + llspellcheck.cpp llspinctrl.cpp llstatbar.cpp llstatgraph.cpp @@ -191,6 +193,8 @@ set(llui_HEADER_FILES llscrolllistitem.h llsliderctrl.h llslider.h + llspellcheck.h + llspellcheckmenuhandler.h llspinctrl.h llstatbar.h llstatgraph.h @@ -260,6 +264,7 @@ target_link_libraries(llui ${LLXUIXML_LIBRARIES} ${LLXML_LIBRARIES} ${LLMATH_LIBRARIES} + ${HUNSPELL_LIBRARY} ${LLCOMMON_LIBRARIES} # must be after llimage, llwindow, llrender ) diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index d0fbf4b913..48d49af588 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -45,6 +45,7 @@ #include "llkeyboard.h" #include "llrect.h" #include "llresmgr.h" +#include "llspellcheck.h" #include "llstring.h" #include "llwindow.h" #include "llui.h" @@ -65,6 +66,7 @@ const S32 SCROLL_INCREMENT_ADD = 0; // make space for typing const S32 SCROLL_INCREMENT_DEL = 4; // make space for baskspacing const F32 AUTO_SCROLL_TIME = 0.05f; const F32 TRIPLE_CLICK_INTERVAL = 0.3f; // delay between double and triple click. *TODO: make this equal to the double click interval? +const F32 SPELLCHECK_DELAY = 0.5f; // delay between the last keypress and spell checking the word the cursor is on const std::string PASSWORD_ASTERISK( "\xE2\x80\xA2" ); // U+2022 BULLET @@ -88,6 +90,7 @@ LLLineEditor::Params::Params() background_image_focused("background_image_focused"), select_on_focus("select_on_focus", false), revert_on_esc("revert_on_esc", true), + spellcheck("spellcheck", false), commit_on_focus_lost("commit_on_focus_lost", true), ignore_tab("ignore_tab", true), is_password("is_password", false), @@ -134,6 +137,9 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p) mIgnoreArrowKeys( FALSE ), mIgnoreTab( p.ignore_tab ), mDrawAsterixes( p.is_password ), + mSpellCheck( p.spellcheck ), + mSpellCheckStart(-1), + mSpellCheckEnd(-1), mSelectAllonFocusReceived( p.select_on_focus ), mSelectAllonCommit( TRUE ), mPassDelete(FALSE), @@ -151,7 +157,8 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p) mHighlightColor(p.highlight_color()), mPreeditBgColor(p.preedit_bg_color()), mGLFont(p.font), - mContextMenuHandle() + mContextMenuHandle(), + mAutoreplaceCallback() { llassert( mMaxLengthBytes > 0 ); @@ -177,6 +184,12 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p) updateTextPadding(); setCursor(mText.length()); + if (mSpellCheck) + { + LLSpellChecker::setSettingsChangeCallback(boost::bind(&LLLineEditor::onSpellCheckSettingsChange, this)); + } + mSpellCheckTimer.reset(); + setPrevalidateInput(p.prevalidate_input_callback()); setPrevalidate(p.prevalidate_callback()); @@ -195,7 +208,6 @@ LLLineEditor::~LLLineEditor() gFocusMgr.releaseFocusIfNeeded( this ); } - void LLLineEditor::onFocusReceived() { gEditMenuHandler = this; @@ -519,6 +531,99 @@ void LLLineEditor::selectAll() updatePrimary(); } +bool LLLineEditor::getSpellCheck() const +{ + return (LLSpellChecker::getUseSpellCheck()) && (!mReadOnly) && (mSpellCheck); +} + +const std::string& LLLineEditor::getSuggestion(U32 index) const +{ + return (index < mSuggestionList.size()) ? mSuggestionList[index] : LLStringUtil::null; +} + +U32 LLLineEditor::getSuggestionCount() const +{ + return mSuggestionList.size(); +} + +void LLLineEditor::replaceWithSuggestion(U32 index) +{ + for (std::list<std::pair<U32, U32> >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it) + { + if ( (it->first <= (U32)mCursorPos) && (it->second >= (U32)mCursorPos) ) + { + deselect(); + + // Delete the misspelled word + mText.erase(it->first, it->second - it->first); + + // Insert the suggestion in its place + LLWString suggestion = utf8str_to_wstring(mSuggestionList[index]); + mText.insert(it->first, suggestion); + setCursor(it->first + (S32)suggestion.length()); + + break; + } + } + mSpellCheckStart = mSpellCheckEnd = -1; +} + +void LLLineEditor::addToDictionary() +{ + if (canAddToDictionary()) + { + LLSpellChecker::instance().addToCustomDictionary(getMisspelledWord(mCursorPos)); + } +} + +bool LLLineEditor::canAddToDictionary() const +{ + return (getSpellCheck()) && (isMisspelledWord(mCursorPos)); +} + +void LLLineEditor::addToIgnore() +{ + if (canAddToIgnore()) + { + LLSpellChecker::instance().addToIgnoreList(getMisspelledWord(mCursorPos)); + } +} + +bool LLLineEditor::canAddToIgnore() const +{ + return (getSpellCheck()) && (isMisspelledWord(mCursorPos)); +} + +std::string LLLineEditor::getMisspelledWord(U32 pos) const +{ + for (std::list<std::pair<U32, U32> >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it) + { + if ( (it->first <= pos) && (it->second >= pos) ) + { + return wstring_to_utf8str(mText.getWString().substr(it->first, it->second - it->first)); + } + } + return LLStringUtil::null; +} + +bool LLLineEditor::isMisspelledWord(U32 pos) const +{ + for (std::list<std::pair<U32, U32> >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it) + { + if ( (it->first <= pos) && (it->second >= pos) ) + { + return true; + } + } + return false; +} + +void LLLineEditor::onSpellCheckSettingsChange() +{ + // Recheck the spelling on every change + mMisspellRanges.clear(); + mSpellCheckStart = mSpellCheckEnd = -1; +} BOOL LLLineEditor::handleDoubleClick(S32 x, S32 y, MASK mask) { @@ -866,6 +971,12 @@ void LLLineEditor::addChar(const llwchar uni_char) LLUI::reportBadKeystroke(); } + if (!mReadOnly && mAutoreplaceCallback != NULL) + { + // call callback + mAutoreplaceCallback(mText, mCursorPos); + } + getWindow()->hideCursorUntilMouseMove(); } @@ -1058,9 +1169,8 @@ void LLLineEditor::cut() LLUI::reportBadKeystroke(); } else - if( mKeystrokeCallback ) { - mKeystrokeCallback( this ); + onKeystroke(); } } } @@ -1187,9 +1297,8 @@ void LLLineEditor::pasteHelper(bool is_primary) LLUI::reportBadKeystroke(); } else - if( mKeystrokeCallback ) { - mKeystrokeCallback( this ); + onKeystroke(); } } } @@ -1442,9 +1551,10 @@ BOOL LLLineEditor::handleKeyHere(KEY key, MASK mask ) // Notify owner if requested if (!need_to_rollback && handled) { - if (mKeystrokeCallback) + onKeystroke(); + if ( (!selection_modified) && (KEY_BACKSPACE == key) ) { - mKeystrokeCallback(this); + mSpellCheckTimer.setTimerExpirySec(SPELLCHECK_DELAY); } } } @@ -1497,12 +1607,11 @@ BOOL LLLineEditor::handleUnicodeCharHere(llwchar uni_char) // Notify owner if requested if( !need_to_rollback && handled ) { - if( mKeystrokeCallback ) - { - // HACK! The only usage of this callback doesn't do anything with the character. - // We'll have to do something about this if something ever changes! - Doug - mKeystrokeCallback( this ); - } + // HACK! The only usage of this callback doesn't do anything with the character. + // We'll have to do something about this if something ever changes! - Doug + onKeystroke(); + + mSpellCheckTimer.setTimerExpirySec(SPELLCHECK_DELAY); } } return handled; @@ -1531,9 +1640,7 @@ void LLLineEditor::doDelete() if (!prevalidateInput(text_to_delete)) { - if( mKeystrokeCallback ) - mKeystrokeCallback( this ); - + onKeystroke(); return; } setCursor(getCursor() + 1); @@ -1549,10 +1656,9 @@ void LLLineEditor::doDelete() } else { - if( mKeystrokeCallback ) - { - mKeystrokeCallback( this ); - } + onKeystroke(); + + mSpellCheckTimer.setTimerExpirySec(SPELLCHECK_DELAY); } } } @@ -1624,6 +1730,10 @@ void LLLineEditor::draw() background.stretch( -mBorderThickness ); S32 lineeditor_v_pad = (background.getHeight() - mGLFont->getLineHeight()) / 2; + if (mSpellCheck) + { + lineeditor_v_pad += 1; + } drawBackground(); @@ -1698,14 +1808,14 @@ void LLLineEditor::draw() { S32 select_left; S32 select_right; - if( mSelectionStart < getCursor() ) + if (mSelectionStart < mSelectionEnd) { select_left = mSelectionStart; - select_right = getCursor(); + select_right = mSelectionEnd; } else { - select_left = getCursor(); + select_left = mSelectionEnd; select_right = mSelectionStart; } @@ -1749,7 +1859,7 @@ void LLLineEditor::draw() if( (rendered_pixels_right < (F32)mTextRightEdge) && (rendered_text < text_len) ) { // unselected, right side - mGLFont->render( + rendered_text += mGLFont->render( mText, mScrollHPos + rendered_text, rendered_pixels_right, text_bottom, text_color, @@ -1763,7 +1873,7 @@ void LLLineEditor::draw() } else { - mGLFont->render( + rendered_text = mGLFont->render( mText, mScrollHPos, rendered_pixels_right, text_bottom, text_color, @@ -1778,6 +1888,101 @@ void LLLineEditor::draw() mBorder->setVisible(FALSE); // no more programmatic art. #endif + if ( (getSpellCheck()) && (mText.length() > 2) ) + { + // Calculate start and end indices for the first and last visible word + U32 start = prevWordPos(mScrollHPos), end = nextWordPos(mScrollHPos + rendered_text); + + if ( (mSpellCheckStart != start) || (mSpellCheckEnd != end) ) + { + const LLWString& text = mText.getWString().substr(start, end); + + // Find the start of the first word + U32 word_start = 0, word_end = 0; + while ( (word_start < text.length()) && (!LLStringOps::isAlpha(text[word_start])) ) + { + word_start++; + } + + // Iterate over all words in the text block and check them one by one + mMisspellRanges.clear(); + while (word_start < text.length()) + { + // Find the end of the current word (special case handling for "'" when it's used as a contraction) + word_end = word_start + 1; + while ( (word_end < text.length()) && + ((LLWStringUtil::isPartOfWord(text[word_end])) || + ((L'\'' == text[word_end]) && (word_end + 1 < text.length()) && + (LLStringOps::isAlnum(text[word_end - 1])) && (LLStringOps::isAlnum(text[word_end + 1])))) ) + { + word_end++; + } + if (word_end > text.length()) + { + break; + } + + // Don't process words shorter than 3 characters + std::string word = wstring_to_utf8str(text.substr(word_start, word_end - word_start)); + if ( (word.length() >= 3) && (!LLSpellChecker::instance().checkSpelling(word)) ) + { + mMisspellRanges.push_back(std::pair<U32, U32>(start + word_start, start + word_end)); + } + + // Find the start of the next word + word_start = word_end + 1; + while ( (word_start < text.length()) && (!LLWStringUtil::isPartOfWord(text[word_start])) ) + { + word_start++; + } + } + + mSpellCheckStart = start; + mSpellCheckEnd = end; + } + + // Draw squiggly lines under any (visible) misspelled words + for (std::list<std::pair<U32, U32> >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it) + { + // Skip over words that aren't (partially) visible + if ( ((it->first < start) && (it->second < start)) || (it->first > end) ) + { + continue; + } + + // Skip the current word if the user is still busy editing it + if ( (!mSpellCheckTimer.hasExpired()) && (it->first <= (U32)mCursorPos) && (it->second >= (U32)mCursorPos) ) + { + continue; + } + + S32 pxWidth = getRect().getWidth(); + S32 pxStart = findPixelNearestPos(it->first - getCursor()); + if (pxStart > pxWidth) + { + continue; + } + S32 pxEnd = findPixelNearestPos(it->second - getCursor()); + if (pxEnd > pxWidth) + { + pxEnd = pxWidth; + } + + S32 pxBottom = (S32)(text_bottom + mGLFont->getDescenderHeight()); + + gGL.color4ub(255, 0, 0, 200); + while (pxStart + 1 < pxEnd) + { + gl_line_2d(pxStart, pxBottom, pxStart + 2, pxBottom - 2); + if (pxStart + 3 < pxEnd) + { + gl_line_2d(pxStart + 2, pxBottom - 3, pxStart + 4, pxBottom - 1); + } + pxStart += 4; + } + } + } + // If we're editing... if( hasFocus()) { @@ -2109,6 +2314,15 @@ void LLLineEditor::setSelectAllonFocusReceived(BOOL b) mSelectAllonFocusReceived = b; } +void LLLineEditor::onKeystroke() +{ + if (mKeystrokeCallback) + { + mKeystrokeCallback(this); + } + + mSpellCheckStart = mSpellCheckEnd = -1; +} void LLLineEditor::setKeystrokeCallback(callback_t callback, void* user_data) { @@ -2231,10 +2445,9 @@ void LLLineEditor::updatePreedit(const LLWString &preedit_string, // Update of the preedit should be caused by some key strokes. mKeystrokeTimer.reset(); - if( mKeystrokeCallback ) - { - mKeystrokeCallback( this ); - } + onKeystroke(); + + mSpellCheckTimer.setTimerExpirySec(SPELLCHECK_DELAY); } BOOL LLLineEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect *bounds, LLRect *control) const @@ -2386,7 +2599,38 @@ void LLLineEditor::showContextMenu(S32 x, S32 y) S32 screen_x, screen_y; localPointToScreen(x, y, &screen_x, &screen_y); - menu->show(screen_x, screen_y); + + setCursorAtLocalPos(x); + if (hasSelection()) + { + if ( (mCursorPos < llmin(mSelectionStart, mSelectionEnd)) || (mCursorPos > llmax(mSelectionStart, mSelectionEnd)) ) + { + deselect(); + } + else + { + setCursor(llmax(mSelectionStart, mSelectionEnd)); + } + } + + bool use_spellcheck = getSpellCheck(), is_misspelled = false; + if (use_spellcheck) + { + mSuggestionList.clear(); + + // If the cursor is on a misspelled word, retrieve suggestions for it + std::string misspelled_word = getMisspelledWord(mCursorPos); + if ((is_misspelled = !misspelled_word.empty()) == true) + { + LLSpellChecker::instance().getSuggestions(misspelled_word, mSuggestionList); + } + } + + menu->setItemVisible("Suggestion Separator", (use_spellcheck) && (!mSuggestionList.empty())); + menu->setItemVisible("Add to Dictionary", (use_spellcheck) && (is_misspelled)); + menu->setItemVisible("Add to Ignore", (use_spellcheck) && (is_misspelled)); + menu->setItemVisible("Spellcheck Separator", (use_spellcheck) && (is_misspelled)); + menu->show(screen_x, screen_y, this); } } diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h index 2518dbe3c7..71dd53f608 100644 --- a/indra/llui/lllineeditor.h +++ b/indra/llui/lllineeditor.h @@ -40,6 +40,7 @@ #include "llframetimer.h" #include "lleditmenuhandler.h" +#include "llspellcheckmenuhandler.h" #include "lluictrl.h" #include "lluiimage.h" #include "lluistring.h" @@ -54,7 +55,7 @@ class LLButton; class LLContextMenu; class LLLineEditor -: public LLUICtrl, public LLEditMenuHandler, protected LLPreeditor +: public LLUICtrl, public LLEditMenuHandler, protected LLPreeditor, public LLSpellCheckMenuHandler { public: @@ -86,6 +87,7 @@ public: Optional<bool> select_on_focus, revert_on_esc, + spellcheck, commit_on_focus_lost, ignore_tab, is_password; @@ -146,6 +148,24 @@ public: virtual void deselect(); virtual BOOL canDeselect() const; + // LLSpellCheckMenuHandler overrides + /*virtual*/ bool getSpellCheck() const; + + /*virtual*/ const std::string& getSuggestion(U32 index) const; + /*virtual*/ U32 getSuggestionCount() const; + /*virtual*/ void replaceWithSuggestion(U32 index); + + /*virtual*/ void addToDictionary(); + /*virtual*/ bool canAddToDictionary() const; + + /*virtual*/ void addToIgnore(); + /*virtual*/ bool canAddToIgnore() const; + + // Spell checking helper functions + std::string getMisspelledWord(U32 pos) const; + bool isMisspelledWord(U32 pos) const; + void onSpellCheckSettingsChange(); + // view overrides virtual void draw(); virtual void reshape(S32 width,S32 height,BOOL called_from_parent=TRUE); @@ -169,6 +189,9 @@ public: virtual BOOL setTextArg( const std::string& key, const LLStringExplicit& text ); virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); + typedef boost::function<void(LLUIString&, S32&)> autoreplace_callback_t; + autoreplace_callback_t mAutoreplaceCallback; + void setAutoreplaceCallback(autoreplace_callback_t cb) { mAutoreplaceCallback = cb; } void setLabel(const LLStringExplicit &new_label) { mLabel = new_label; } const std::string& getLabel() { return mLabel.getString(); } @@ -223,6 +246,7 @@ public: void setSelectAllonFocusReceived(BOOL b); void setSelectAllonCommit(BOOL b) { mSelectAllonCommit = b; } + void onKeystroke(); typedef boost::function<void (LLLineEditor* caller, void* user_data)> callback_t; void setKeystrokeCallback(callback_t callback, void* user_data); @@ -322,6 +346,13 @@ protected: S32 mLastSelectionStart; S32 mLastSelectionEnd; + bool mSpellCheck; + S32 mSpellCheckStart; + S32 mSpellCheckEnd; + LLTimer mSpellCheckTimer; + std::list<std::pair<U32, U32> > mMisspellRanges; + std::vector<std::string> mSuggestionList; + LLTextValidate::validate_func_t mPrevalidateFunc; LLTextValidate::validate_func_t mPrevalidateInputFunc; diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index ff6928ffda..efb9848a90 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -3854,7 +3854,7 @@ void LLContextMenu::setVisible(BOOL visible) } // Takes cursor position in screen space? -void LLContextMenu::show(S32 x, S32 y) +void LLContextMenu::show(S32 x, S32 y, LLView* spawning_view) { if (getChildList()->empty()) { @@ -3908,6 +3908,14 @@ void LLContextMenu::show(S32 x, S32 y) setRect(rect); arrange(); + if (spawning_view) + { + mSpawningViewHandle = spawning_view->getHandle(); + } + else + { + mSpawningViewHandle.markDead(); + } LLView::setVisible(TRUE); } diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index 36f3ba34b9..67b3e1fbe6 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -670,7 +670,7 @@ public: virtual void draw (); - virtual void show (S32 x, S32 y); + virtual void show (S32 x, S32 y, LLView* spawning_view = NULL); virtual void hide (); virtual BOOL handleHover ( S32 x, S32 y, MASK mask ); @@ -683,10 +683,14 @@ public: LLHandle<LLContextMenu> getHandle() { return getDerivedHandle<LLContextMenu>(); } + LLView* getSpawningView() const { return mSpawningViewHandle.get(); } + void setSpawningView(LLHandle<LLView> spawning_view) { mSpawningViewHandle = spawning_view; } + protected: BOOL mHoveredAnyItem; LLMenuItemGL* mHoverItem; LLRootHandle<LLContextMenu> mHandle; + LLHandle<LLView> mSpawningViewHandle; }; diff --git a/indra/llui/llscrollcontainer.cpp b/indra/llui/llscrollcontainer.cpp index 9b7e30bb04..2fd187a526 100644 --- a/indra/llui/llscrollcontainer.cpp +++ b/indra/llui/llscrollcontainer.cpp @@ -389,12 +389,11 @@ void LLScrollContainer::calcVisibleSize( S32 *visible_width, S32 *visible_height { *show_h_scrollbar = TRUE; *visible_height -= scrollbar_size; - + // Note: Do *not* recompute *show_v_scrollbar here because with // The view inside the scroll container should not be extended // to container's full height to ensure the correct computation // of *show_v_scrollbar after subtracting horizontal scrollbar_size. - // Must retest now that visible_height has changed if( !*show_v_scrollbar && ((doc_height - *visible_height) > 1) ) { *show_v_scrollbar = TRUE; diff --git a/indra/llui/llspellcheck.cpp b/indra/llui/llspellcheck.cpp new file mode 100644 index 0000000000..a189375fbe --- /dev/null +++ b/indra/llui/llspellcheck.cpp @@ -0,0 +1,505 @@ +/** + * @file llspellcheck.cpp + * @brief Spell checking functionality + * + * $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$ + */ + +#include "linden_common.h" + +#include "lldir.h" +#include "llsdserialize.h" + +#include "llspellcheck.h" +#if LL_WINDOWS + #include <hunspell/hunspelldll.h> + #pragma comment(lib, "libhunspell.lib") +#else + #include <hunspell/hunspell.hxx> +#endif + +static const std::string DICT_DIR = "dictionaries"; +static const std::string DICT_FILE_CUSTOM = "user_custom.dic"; +static const std::string DICT_FILE_IGNORE = "user_ignore.dic"; + +static const std::string DICT_FILE_MAIN = "dictionaries.xml"; +static const std::string DICT_FILE_USER = "user_dictionaries.xml"; + +LLSD LLSpellChecker::sDictMap; +LLSpellChecker::settings_change_signal_t LLSpellChecker::sSettingsChangeSignal; + +LLSpellChecker::LLSpellChecker() + : mHunspell(NULL) +{ + // Load initial dictionary information + refreshDictionaryMap(); +} + +LLSpellChecker::~LLSpellChecker() +{ + delete mHunspell; +} + +bool LLSpellChecker::checkSpelling(const std::string& word) const +{ + if ( (!mHunspell) || (word.length() < 3) || (0 != mHunspell->spell(word.c_str())) ) + { + return true; + } + if (mIgnoreList.size() > 0) + { + std::string word_lower(word); + LLStringUtil::toLower(word_lower); + return (mIgnoreList.end() != std::find(mIgnoreList.begin(), mIgnoreList.end(), word_lower)); + } + return false; +} + +S32 LLSpellChecker::getSuggestions(const std::string& word, std::vector<std::string>& suggestions) const +{ + suggestions.clear(); + if ( (!mHunspell) || (word.length() < 3) ) + { + return 0; + } + + char** suggestion_list; int suggestion_cnt = 0; + if ( (suggestion_cnt = mHunspell->suggest(&suggestion_list, word.c_str())) != 0 ) + { + for (int suggestion_index = 0; suggestion_index < suggestion_cnt; suggestion_index++) + { + suggestions.push_back(suggestion_list[suggestion_index]); + } + mHunspell->free_list(&suggestion_list, suggestion_cnt); + } + return suggestions.size(); +} + +// static +const LLSD LLSpellChecker::getDictionaryData(const std::string& dict_language) +{ + for (LLSD::array_const_iterator it = sDictMap.beginArray(); it != sDictMap.endArray(); ++it) + { + const LLSD& dict_entry = *it; + if (dict_language == dict_entry["language"].asString()) + { + return dict_entry; + } + } + return LLSD(); +} + +// static +bool LLSpellChecker::hasDictionary(const std::string& dict_language, bool check_installed) +{ + const LLSD dict_info = getDictionaryData(dict_language); + return dict_info.has("language") && ( (!check_installed) || (dict_info["installed"].asBoolean()) ); +} + +// static +void LLSpellChecker::setDictionaryData(const LLSD& dict_info) +{ + const std::string dict_language = dict_info["language"].asString(); + if (dict_language.empty()) + { + return; + } + + for (LLSD::array_iterator it = sDictMap.beginArray(); it != sDictMap.endArray(); ++it) + { + LLSD& dict_entry = *it; + if (dict_language == dict_entry["language"].asString()) + { + dict_entry = dict_info; + return; + } + } + sDictMap.append(dict_info); + return; +} + +// static +void LLSpellChecker::refreshDictionaryMap() +{ + const std::string app_path = getDictionaryAppPath(); + const std::string user_path = getDictionaryUserPath(); + + // Load dictionary information (file name, friendly name, ...) + llifstream user_file(user_path + DICT_FILE_MAIN, std::ios::binary); + if ( (!user_file.is_open()) || (0 == LLSDSerialize::fromXMLDocument(sDictMap, user_file)) || (0 == sDictMap.size()) ) + { + llifstream app_file(app_path + DICT_FILE_MAIN, std::ios::binary); + if ( (!app_file.is_open()) || (0 == LLSDSerialize::fromXMLDocument(sDictMap, app_file)) || (0 == sDictMap.size()) ) + { + return; + } + } + + // Load user installed dictionary information + llifstream custom_file(user_path + DICT_FILE_USER, std::ios::binary); + if (custom_file.is_open()) + { + LLSD custom_dict_map; + LLSDSerialize::fromXMLDocument(custom_dict_map, custom_file); + for (LLSD::array_iterator it = custom_dict_map.beginArray(); it != custom_dict_map.endArray(); ++it) + { + LLSD& dict_info = *it; + dict_info["user_installed"] = true; + setDictionaryData(dict_info); + } + custom_file.close(); + } + + // Look for installed dictionaries + std::string tmp_app_path, tmp_user_path; + for (LLSD::array_iterator it = sDictMap.beginArray(); it != sDictMap.endArray(); ++it) + { + LLSD& sdDict = *it; + tmp_app_path = (sdDict.has("name")) ? app_path + sdDict["name"].asString() : LLStringUtil::null; + tmp_user_path = (sdDict.has("name")) ? user_path + sdDict["name"].asString() : LLStringUtil::null; + sdDict["installed"] = + (!tmp_app_path.empty()) && ((gDirUtilp->fileExists(tmp_user_path + ".dic")) || (gDirUtilp->fileExists(tmp_app_path + ".dic"))); + } + + sSettingsChangeSignal(); +} + +void LLSpellChecker::addToCustomDictionary(const std::string& word) +{ + if (mHunspell) + { + mHunspell->add(word.c_str()); + } + addToDictFile(getDictionaryUserPath() + DICT_FILE_CUSTOM, word); + sSettingsChangeSignal(); +} + +void LLSpellChecker::addToIgnoreList(const std::string& word) +{ + std::string word_lower(word); + LLStringUtil::toLower(word_lower); + if (mIgnoreList.end() == std::find(mIgnoreList.begin(), mIgnoreList.end(), word_lower)) + { + mIgnoreList.push_back(word_lower); + addToDictFile(getDictionaryUserPath() + DICT_FILE_IGNORE, word_lower); + sSettingsChangeSignal(); + } +} + +void LLSpellChecker::addToDictFile(const std::string& dict_path, const std::string& word) +{ + std::vector<std::string> word_list; + + if (gDirUtilp->fileExists(dict_path)) + { + llifstream file_in(dict_path, std::ios::in); + if (file_in.is_open()) + { + std::string word; int line_num = 0; + while (getline(file_in, word)) + { + // Skip over the first line since that's just a line count + if (0 != line_num) + { + word_list.push_back(word); + } + line_num++; + } + } + else + { + // TODO: show error message? + return; + } + } + + word_list.push_back(word); + + llofstream file_out(dict_path, std::ios::out | std::ios::trunc); + if (file_out.is_open()) + { + file_out << word_list.size() << std::endl; + for (std::vector<std::string>::const_iterator itWord = word_list.begin(); itWord != word_list.end(); ++itWord) + { + file_out << *itWord << std::endl; + } + file_out.close(); + } +} + +bool LLSpellChecker::isActiveDictionary(const std::string& dict_language) const +{ + return + (mDictLanguage == dict_language) || + (mDictSecondary.end() != std::find(mDictSecondary.begin(), mDictSecondary.end(), dict_language)); +} + +void LLSpellChecker::setSecondaryDictionaries(dict_list_t dict_list) +{ + if (!getUseSpellCheck()) + { + return; + } + + // Check if we're only adding secondary dictionaries, or removing them + dict_list_t dict_add(llmax(dict_list.size(), mDictSecondary.size())), dict_rem(llmax(dict_list.size(), mDictSecondary.size())); + dict_list.sort(); + mDictSecondary.sort(); + dict_list_t::iterator end_added = std::set_difference(dict_list.begin(), dict_list.end(), mDictSecondary.begin(), mDictSecondary.end(), dict_add.begin()); + dict_list_t::iterator end_removed = std::set_difference(mDictSecondary.begin(), mDictSecondary.end(), dict_list.begin(), dict_list.end(), dict_rem.begin()); + + if (end_removed != dict_rem.begin()) // We can't remove secondary dictionaries so we need to recreate the Hunspell instance + { + mDictSecondary = dict_list; + + std::string dict_language = mDictLanguage; + initHunspell(dict_language); + } + else if (end_added != dict_add.begin()) // Add the new secondary dictionaries one by one + { + const std::string app_path = getDictionaryAppPath(); + const std::string user_path = getDictionaryUserPath(); + for (dict_list_t::const_iterator it_added = dict_add.begin(); it_added != end_added; ++it_added) + { + const LLSD dict_entry = getDictionaryData(*it_added); + if ( (!dict_entry.isDefined()) || (!dict_entry["installed"].asBoolean()) ) + { + continue; + } + + const std::string strFileDic = dict_entry["name"].asString() + ".dic"; + if (gDirUtilp->fileExists(user_path + strFileDic)) + { + mHunspell->add_dic((user_path + strFileDic).c_str()); + } + else if (gDirUtilp->fileExists(app_path + strFileDic)) + { + mHunspell->add_dic((app_path + strFileDic).c_str()); + } + } + mDictSecondary = dict_list; + sSettingsChangeSignal(); + } +} + +void LLSpellChecker::initHunspell(const std::string& dict_language) +{ + if (mHunspell) + { + delete mHunspell; + mHunspell = NULL; + mDictLanguage.clear(); + mDictFile.clear(); + mIgnoreList.clear(); + } + + const LLSD dict_entry = (!dict_language.empty()) ? getDictionaryData(dict_language) : LLSD(); + if ( (!dict_entry.isDefined()) || (!dict_entry["installed"].asBoolean()) || (!dict_entry["is_primary"].asBoolean())) + { + sSettingsChangeSignal(); + return; + } + + const std::string app_path = getDictionaryAppPath(); + const std::string user_path = getDictionaryUserPath(); + if (dict_entry.has("name")) + { + const std::string filename_aff = dict_entry["name"].asString() + ".aff"; + const std::string filename_dic = dict_entry["name"].asString() + ".dic"; + if ( (gDirUtilp->fileExists(user_path + filename_aff)) && (gDirUtilp->fileExists(user_path + filename_dic)) ) + { + mHunspell = new Hunspell((user_path + filename_aff).c_str(), (user_path + filename_dic).c_str()); + } + else if ( (gDirUtilp->fileExists(app_path + filename_aff)) && (gDirUtilp->fileExists(app_path + filename_dic)) ) + { + mHunspell = new Hunspell((app_path + filename_aff).c_str(), (app_path + filename_dic).c_str()); + } + if (!mHunspell) + { + return; + } + + mDictLanguage = dict_language; + mDictFile = dict_entry["name"].asString(); + + if (gDirUtilp->fileExists(user_path + DICT_FILE_CUSTOM)) + { + mHunspell->add_dic((user_path + DICT_FILE_CUSTOM).c_str()); + } + + if (gDirUtilp->fileExists(user_path + DICT_FILE_IGNORE)) + { + llifstream file_in(user_path + DICT_FILE_IGNORE, std::ios::in); + if (file_in.is_open()) + { + std::string word; int idxLine = 0; + while (getline(file_in, word)) + { + // Skip over the first line since that's just a line count + if (0 != idxLine) + { + LLStringUtil::toLower(word); + mIgnoreList.push_back(word); + } + idxLine++; + } + } + } + + for (dict_list_t::const_iterator it = mDictSecondary.begin(); it != mDictSecondary.end(); ++it) + { + const LLSD dict_entry = getDictionaryData(*it); + if ( (!dict_entry.isDefined()) || (!dict_entry["installed"].asBoolean()) ) + { + continue; + } + + const std::string filename_dic = dict_entry["name"].asString() + ".dic"; + if (gDirUtilp->fileExists(user_path + filename_dic)) + { + mHunspell->add_dic((user_path + filename_dic).c_str()); + } + else if (gDirUtilp->fileExists(app_path + filename_dic)) + { + mHunspell->add_dic((app_path + filename_dic).c_str()); + } + } + } + + sSettingsChangeSignal(); +} + +// static +const std::string LLSpellChecker::getDictionaryAppPath() +{ + std::string dict_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, DICT_DIR, ""); + return dict_path; +} + +// static +const std::string LLSpellChecker::getDictionaryUserPath() +{ + std::string dict_path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, DICT_DIR, ""); + if (!gDirUtilp->fileExists(dict_path)) + { + LLFile::mkdir(dict_path); + } + return dict_path; +} + +// static +bool LLSpellChecker::getUseSpellCheck() +{ + return (LLSpellChecker::instanceExists()) && (LLSpellChecker::instance().mHunspell); +} + +// static +bool LLSpellChecker::canRemoveDictionary(const std::string& dict_language) +{ + // Only user-installed inactive dictionaries can be removed + const LLSD dict_info = getDictionaryData(dict_language); + return + (dict_info["user_installed"].asBoolean()) && + ( (!getUseSpellCheck()) || (!LLSpellChecker::instance().isActiveDictionary(dict_language)) ); +} + +// static +void LLSpellChecker::removeDictionary(const std::string& dict_language) +{ + if (!canRemoveDictionary(dict_language)) + { + return; + } + + LLSD dict_map = loadUserDictionaryMap(); + for (LLSD::array_const_iterator it = dict_map.beginArray(); it != dict_map.endArray(); ++it) + { + const LLSD& dict_info = *it; + if (dict_info["language"].asString() == dict_language) + { + const std::string dict_dic = getDictionaryUserPath() + dict_info["name"].asString() + ".dic"; + if (gDirUtilp->fileExists(dict_dic)) + { + LLFile::remove(dict_dic); + } + const std::string dict_aff = getDictionaryUserPath() + dict_info["name"].asString() + ".aff"; + if (gDirUtilp->fileExists(dict_aff)) + { + LLFile::remove(dict_aff); + } + dict_map.erase(it - dict_map.beginArray()); + break; + } + } + saveUserDictionaryMap(dict_map); + + refreshDictionaryMap(); +} + +// static +LLSD LLSpellChecker::loadUserDictionaryMap() +{ + LLSD dict_map; + llifstream dict_file(getDictionaryUserPath() + DICT_FILE_USER, std::ios::binary); + if (dict_file.is_open()) + { + LLSDSerialize::fromXMLDocument(dict_map, dict_file); + dict_file.close(); + } + return dict_map; +} + +// static +void LLSpellChecker::saveUserDictionaryMap(const LLSD& dict_map) +{ + llofstream dict_file(getDictionaryUserPath() + DICT_FILE_USER, std::ios::trunc); + if (dict_file.is_open()) + { + LLSDSerialize::toPrettyXML(dict_map, dict_file); + dict_file.close(); + } +} + +// static +boost::signals2::connection LLSpellChecker::setSettingsChangeCallback(const settings_change_signal_t::slot_type& cb) +{ + return sSettingsChangeSignal.connect(cb); +} + +// static +void LLSpellChecker::setUseSpellCheck(const std::string& dict_language) +{ + if ( (((dict_language.empty()) && (getUseSpellCheck())) || (!dict_language.empty())) && + (LLSpellChecker::instance().mDictLanguage != dict_language) ) + { + LLSpellChecker::instance().initHunspell(dict_language); + } +} + +// static +void LLSpellChecker::initClass() +{ + if (sDictMap.isUndefined()) + { + refreshDictionaryMap(); + } +} diff --git a/indra/llui/llspellcheck.h b/indra/llui/llspellcheck.h new file mode 100644 index 0000000000..4ab80195ea --- /dev/null +++ b/indra/llui/llspellcheck.h @@ -0,0 +1,93 @@ +/** + * @file llspellcheck.h + * @brief Spell checking functionality + * + * $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$ + */ + +#ifndef LLSPELLCHECK_H +#define LLSPELLCHECK_H + +#include "llsingleton.h" +#include "llui.h" +#include <boost/signals2.hpp> + +class Hunspell; + +class LLSpellChecker : public LLSingleton<LLSpellChecker>, public LLInitClass<LLSpellChecker> +{ + friend class LLSingleton<LLSpellChecker>; + friend class LLInitClass<LLSpellChecker>; +protected: + LLSpellChecker(); + ~LLSpellChecker(); + +public: + void addToCustomDictionary(const std::string& word); + void addToIgnoreList(const std::string& word); + bool checkSpelling(const std::string& word) const; + S32 getSuggestions(const std::string& word, std::vector<std::string>& suggestions) const; +protected: + void addToDictFile(const std::string& dict_path, const std::string& word); + void initHunspell(const std::string& dict_language); + +public: + typedef std::list<std::string> dict_list_t; + + const std::string& getPrimaryDictionary() const { return mDictLanguage; } + const dict_list_t& getSecondaryDictionaries() const { return mDictSecondary; } + bool isActiveDictionary(const std::string& dict_language) const; + void setSecondaryDictionaries(dict_list_t dict_list); + + static bool canRemoveDictionary(const std::string& dict_language); + static const std::string getDictionaryAppPath(); + static const std::string getDictionaryUserPath(); + static const LLSD getDictionaryData(const std::string& dict_language); + static const LLSD& getDictionaryMap() { return sDictMap; } + static bool getUseSpellCheck(); + static bool hasDictionary(const std::string& dict_language, bool check_installed = false); + static void refreshDictionaryMap(); + static void removeDictionary(const std::string& dict_language); + static void setUseSpellCheck(const std::string& dict_language); +protected: + static LLSD loadUserDictionaryMap(); + static void setDictionaryData(const LLSD& dict_info); + static void saveUserDictionaryMap(const LLSD& dict_map); + +public: + typedef boost::signals2::signal<void()> settings_change_signal_t; + static boost::signals2::connection setSettingsChangeCallback(const settings_change_signal_t::slot_type& cb); +protected: + static void initClass(); + +protected: + Hunspell* mHunspell; + std::string mDictLanguage; + std::string mDictFile; + dict_list_t mDictSecondary; + std::vector<std::string> mIgnoreList; + + static LLSD sDictMap; + static settings_change_signal_t sSettingsChangeSignal; +}; + +#endif // LLSPELLCHECK_H diff --git a/indra/llui/llspellcheckmenuhandler.h b/indra/llui/llspellcheckmenuhandler.h new file mode 100644 index 0000000000..d5c95bad39 --- /dev/null +++ b/indra/llui/llspellcheckmenuhandler.h @@ -0,0 +1,46 @@ +/** + * @file llspellcheckmenuhandler.h + * @brief Interface used by spell check menu handling + * + * $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$ + */ + +#ifndef LLSPELLCHECKMENUHANDLER_H +#define LLSPELLCHECKMENUHANDLER_H + +class LLSpellCheckMenuHandler +{ +public: + virtual bool getSpellCheck() const { return false; } + + virtual const std::string& getSuggestion(U32 index) const { return LLStringUtil::null; } + virtual U32 getSuggestionCount() const { return 0; } + virtual void replaceWithSuggestion(U32 index){} + + virtual void addToDictionary() {} + virtual bool canAddToDictionary() const { return false; } + + virtual void addToIgnore() {} + virtual bool canAddToIgnore() const { return false; } +}; + +#endif // LLSPELLCHECKMENUHANDLER_H diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 7aeeae298f..3815eec447 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -32,6 +32,7 @@ #include "lllocalcliprect.h" #include "llmenugl.h" #include "llscrollcontainer.h" +#include "llspellcheck.h" #include "llstl.h" #include "lltextparser.h" #include "lltextutil.h" @@ -155,6 +156,7 @@ LLTextBase::Params::Params() plain_text("plain_text",false), track_end("track_end", false), read_only("read_only", false), + spellcheck("spellcheck", false), v_pad("v_pad", 0), h_pad("h_pad", 0), clip("clip", true), @@ -181,6 +183,9 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p) mFontShadow(p.font_shadow), mPopupMenu(NULL), mReadOnly(p.read_only), + mSpellCheck(p.spellcheck), + mSpellCheckStart(-1), + mSpellCheckEnd(-1), mCursorColor(p.cursor_color), mFgColor(p.text_color), mBorderVisible( p.border_visible ), @@ -246,6 +251,12 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p) addChild(mDocumentView); } + if (mSpellCheck) + { + LLSpellChecker::setSettingsChangeCallback(boost::bind(&LLTextBase::onSpellCheckSettingsChange, this)); + } + mSpellCheckTimer.reset(); + createDefaultSegment(); updateRects(); @@ -280,12 +291,23 @@ bool LLTextBase::truncate() if (getLength() >= S32(mMaxTextByteLength / 4)) { // Have to check actual byte size - LLWString text(getWText()); - S32 utf8_byte_size = wstring_utf8_length(text); + S32 utf8_byte_size = 0; + LLSD value = getViewModel()->getValue(); + if (value.type() == LLSD::TypeString) + { + // save a copy for strings. + utf8_byte_size = value.size(); + } + else + { + // non string LLSDs need explicit conversion to string + utf8_byte_size = value.asString().size(); + } + if ( utf8_byte_size > mMaxTextByteLength ) { // Truncate safely in UTF-8 - std::string temp_utf8_text = wstring_to_utf8str(text); + std::string temp_utf8_text = value.asString(); temp_utf8_text = utf8str_truncate( temp_utf8_text, mMaxTextByteLength ); LLWString text = utf8str_to_wstring( temp_utf8_text ); // remove extra bit of current string, to preserve formatting, etc. @@ -530,8 +552,92 @@ void LLTextBase::drawText() return; } + // Perform spell check if needed + if ( (getSpellCheck()) && (getWText().length() > 2) ) + { + // Calculate start and end indices for the spell checking range + S32 start = line_start, end = getLineEnd(last_line); + + if ( (mSpellCheckStart != start) || (mSpellCheckEnd != end) ) + { + const LLWString& wstrText = getWText(); + mMisspellRanges.clear(); + + segment_set_t::const_iterator seg_it = getSegIterContaining(start); + while (mSegments.end() != seg_it) + { + LLTextSegmentPtr text_segment = *seg_it; + if ( (text_segment.isNull()) || (text_segment->getStart() >= end) ) + { + break; + } + + if (!text_segment->canEdit()) + { + ++seg_it; + continue; + } + + // Combine adjoining text segments into one + U32 seg_start = text_segment->getStart(), seg_end = llmin(text_segment->getEnd(), end); + while (mSegments.end() != ++seg_it) + { + text_segment = *seg_it; + if ( (text_segment.isNull()) || (!text_segment->canEdit()) || (text_segment->getStart() >= end) ) + { + break; + } + seg_end = llmin(text_segment->getEnd(), end); + } + + // Find the start of the first word + U32 word_start = seg_start, word_end = -1; + while ( (word_start < wstrText.length()) && (!LLStringOps::isAlpha(wstrText[word_start])) ) + { + word_start++; + } + + // Iterate over all words in the text block and check them one by one + while (word_start < seg_end) + { + // Find the end of the current word (special case handling for "'" when it's used as a contraction) + word_end = word_start + 1; + while ( (word_end < seg_end) && + ((LLWStringUtil::isPartOfWord(wstrText[word_end])) || + ((L'\'' == wstrText[word_end]) && + (LLStringOps::isAlnum(wstrText[word_end - 1])) && (LLStringOps::isAlnum(wstrText[word_end + 1])))) ) + { + word_end++; + } + if (word_end > seg_end) + { + break; + } + + // Don't process words shorter than 3 characters + std::string word = wstring_to_utf8str(wstrText.substr(word_start, word_end - word_start)); + if ( (word.length() >= 3) && (!LLSpellChecker::instance().checkSpelling(word)) ) + { + mMisspellRanges.push_back(std::pair<U32, U32>(word_start, word_end)); + } + + // Find the start of the next word + word_start = word_end + 1; + while ( (word_start < seg_end) && (!LLWStringUtil::isPartOfWord(wstrText[word_start])) ) + { + word_start++; + } + } + } + + mSpellCheckStart = start; + mSpellCheckEnd = end; + } + } + LLTextSegmentPtr cur_segment = *seg_iter; + std::list<std::pair<U32, U32> >::const_iterator misspell_it = std::lower_bound(mMisspellRanges.begin(), mMisspellRanges.end(), std::pair<U32, U32>(line_start, 0)); for (S32 cur_line = first_line; cur_line < last_line; cur_line++) { S32 next_line = cur_line + 1; @@ -566,7 +672,8 @@ void LLTextBase::drawText() cur_segment = *seg_iter; } - S32 clipped_end = llmin( line_end, cur_segment->getEnd() ) - cur_segment->getStart(); + S32 seg_end = llmin(line_end, cur_segment->getEnd()); + S32 clipped_end = seg_end - cur_segment->getStart(); if (mUseEllipses // using ellipses && clipped_end == line_end // last segment on line @@ -578,6 +685,46 @@ void LLTextBase::drawText() text_rect.mRight -= 2; } + // Draw squiggly lines under any visible misspelled words + while ( (mMisspellRanges.end() != misspell_it) && (misspell_it->first < seg_end) && (misspell_it->second > seg_start) ) + { + // Skip the current word if the user is still busy editing it + if ( (!mSpellCheckTimer.hasExpired()) && (misspell_it->first <= (U32)mCursorPos) && (misspell_it->second >= (U32)mCursorPos) ) + { + ++misspell_it; + continue; + } + + U32 misspell_start = llmax<U32>(misspell_it->first, seg_start), misspell_end = llmin<U32>(misspell_it->second, seg_end); + S32 squiggle_start = 0, squiggle_end = 0, pony = 0; + cur_segment->getDimensions(seg_start - cur_segment->getStart(), misspell_start - seg_start, squiggle_start, pony); + cur_segment->getDimensions(misspell_start - cur_segment->getStart(), misspell_end - misspell_start, squiggle_end, pony); + squiggle_start += text_rect.mLeft; + + pony = (squiggle_end + 3) / 6; + squiggle_start += squiggle_end / 2 - pony * 3; + squiggle_end = squiggle_start + pony * 6; + + S32 squiggle_bottom = text_rect.mBottom + (S32)cur_segment->getStyle()->getFont()->getDescenderHeight(); + + gGL.color4ub(255, 0, 0, 200); + while (squiggle_start + 1 < squiggle_end) + { + gl_line_2d(squiggle_start, squiggle_bottom, squiggle_start + 2, squiggle_bottom - 2); + if (squiggle_start + 3 < squiggle_end) + { + gl_line_2d(squiggle_start + 2, squiggle_bottom - 3, squiggle_start + 4, squiggle_bottom - 1); + } + squiggle_start += 4; + } + + if (misspell_it->second > seg_end) + { + break; + } + ++misspell_it; + } + text_rect.mLeft = (S32)(cur_segment->draw(seg_start - cur_segment->getStart(), clipped_end, selection_left, selection_right, text_rect)); seg_start = clipped_end + cur_segment->getStart(); @@ -592,8 +739,7 @@ void LLTextBase::drawText() S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::segment_vec_t* segments ) { - LLWString text(getWText()); - S32 old_len = text.length(); // length() returns character length + S32 old_len = getLength(); // length() returns character length S32 insert_len = wstr.length(); pos = getEditableIndex(pos, true); @@ -653,8 +799,7 @@ S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::s } } - text.insert(pos, wstr); - getViewModel()->setDisplay(text); + getViewModel()->getEditableDisplay().insert(pos, wstr); if ( truncate() ) { @@ -669,7 +814,6 @@ S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::s S32 LLTextBase::removeStringNoUndo(S32 pos, S32 length) { - LLWString text(getWText()); segment_set_t::iterator seg_iter = getSegIterContaining(pos); while(seg_iter != mSegments.end()) { @@ -715,8 +859,7 @@ S32 LLTextBase::removeStringNoUndo(S32 pos, S32 length) ++seg_iter; } - text.erase(pos, length); - getViewModel()->setDisplay(text); + getViewModel()->getEditableDisplay().erase(pos, length); // recreate default segment in case we erased everything createDefaultSegment(); @@ -733,9 +876,7 @@ S32 LLTextBase::overwriteCharNoUndo(S32 pos, llwchar wc) { return 0; } - LLWString text(getWText()); - text[pos] = wc; - getViewModel()->setDisplay(text); + getViewModel()->getEditableDisplay()[pos] = wc; onValueChange(pos, pos + 1); needsReflow(pos); @@ -1103,6 +1244,99 @@ void LLTextBase::deselect() mIsSelecting = FALSE; } +bool LLTextBase::getSpellCheck() const +{ + return (LLSpellChecker::getUseSpellCheck()) && (!mReadOnly) && (mSpellCheck); +} + +const std::string& LLTextBase::getSuggestion(U32 index) const +{ + return (index < mSuggestionList.size()) ? mSuggestionList[index] : LLStringUtil::null; +} + +U32 LLTextBase::getSuggestionCount() const +{ + return mSuggestionList.size(); +} + +void LLTextBase::replaceWithSuggestion(U32 index) +{ + for (std::list<std::pair<U32, U32> >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it) + { + if ( (it->first <= (U32)mCursorPos) && (it->second >= (U32)mCursorPos) ) + { + deselect(); + + // Delete the misspelled word + removeStringNoUndo(it->first, it->second - it->first); + + // Insert the suggestion in its place + LLWString suggestion = utf8str_to_wstring(mSuggestionList[index]); + insertStringNoUndo(it->first, utf8str_to_wstring(mSuggestionList[index])); + setCursorPos(it->first + (S32)suggestion.length()); + + break; + } + } + mSpellCheckStart = mSpellCheckEnd = -1; +} + +void LLTextBase::addToDictionary() +{ + if (canAddToDictionary()) + { + LLSpellChecker::instance().addToCustomDictionary(getMisspelledWord(mCursorPos)); + } +} + +bool LLTextBase::canAddToDictionary() const +{ + return (getSpellCheck()) && (isMisspelledWord(mCursorPos)); +} + +void LLTextBase::addToIgnore() +{ + if (canAddToIgnore()) + { + LLSpellChecker::instance().addToIgnoreList(getMisspelledWord(mCursorPos)); + } +} + +bool LLTextBase::canAddToIgnore() const +{ + return (getSpellCheck()) && (isMisspelledWord(mCursorPos)); +} + +std::string LLTextBase::getMisspelledWord(U32 pos) const +{ + for (std::list<std::pair<U32, U32> >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it) + { + if ( (it->first <= pos) && (it->second >= pos) ) + { + return wstring_to_utf8str(getWText().substr(it->first, it->second - it->first)); + } + } + return LLStringUtil::null; +} + +bool LLTextBase::isMisspelledWord(U32 pos) const +{ + for (std::list<std::pair<U32, U32> >::const_iterator it = mMisspellRanges.begin(); it != mMisspellRanges.end(); ++it) + { + if ( (it->first <= pos) && (it->second >= pos) ) + { + return true; + } + } + return false; +} + +void LLTextBase::onSpellCheckSettingsChange() +{ + // Recheck the spelling on every change + mMisspellRanges.clear(); + mSpellCheckStart = mSpellCheckEnd = -1; +} // Sets the scrollbar from the cursor position void LLTextBase::updateScrollFromCursor() @@ -1685,6 +1919,8 @@ static LLUIImagePtr image_from_icon_name(const std::string& icon_name) } } +static LLFastTimer::DeclareTimer FTM_PARSE_HTML("Parse HTML"); + void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Params& input_params) { LLStyle::Params style_params(input_params); @@ -1693,15 +1929,13 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para S32 part = (S32)LLTextParser::WHOLE; if (mParseHTML && !style_params.is_link) // Don't search for URLs inside a link segment (STORM-358). { + LLFastTimer _(FTM_PARSE_HTML); S32 start=0,end=0; LLUrlMatch match; std::string text = new_text; while ( LLUrlRegistry::instance().findUrl(text, match, boost::bind(&LLTextBase::replaceUrl, this, _1, _2, _3)) ) { - - LLTextUtil::processUrlMatch(&match,this); - start = match.getStart(); end = match.getEnd()+1; @@ -1737,6 +1971,8 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para } } + LLTextUtil::processUrlMatch(&match,this); + // move on to the rest of the text after the Url if (end < (S32)text.length()) { @@ -1760,8 +1996,11 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para } } +static LLFastTimer::DeclareTimer FTM_APPEND_TEXT("Append Text"); + void LLTextBase::appendText(const std::string &new_text, bool prepend_newline, const LLStyle::Params& input_params) { + LLFastTimer _(FTM_APPEND_TEXT); if (new_text.empty()) return; diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index 0549141b72..90b147cee1 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -30,6 +30,7 @@ #include "v4color.h" #include "lleditmenuhandler.h" +#include "llspellcheckmenuhandler.h" #include "llstyle.h" #include "llkeywords.h" #include "llpanel.h" @@ -230,7 +231,8 @@ typedef LLPointer<LLTextSegment> LLTextSegmentPtr; /// class LLTextBase : public LLUICtrl, - protected LLEditMenuHandler + protected LLEditMenuHandler, + public LLSpellCheckMenuHandler { public: friend class LLTextSegment; @@ -259,6 +261,7 @@ public: border_visible, track_end, read_only, + spellcheck, allow_scroll, plain_text, wrap, @@ -311,6 +314,24 @@ public: /*virtual*/ BOOL canDeselect() const; /*virtual*/ void deselect(); + // LLSpellCheckMenuHandler overrides + /*virtual*/ bool getSpellCheck() const; + + /*virtual*/ const std::string& getSuggestion(U32 index) const; + /*virtual*/ U32 getSuggestionCount() const; + /*virtual*/ void replaceWithSuggestion(U32 index); + + /*virtual*/ void addToDictionary(); + /*virtual*/ bool canAddToDictionary() const; + + /*virtual*/ void addToIgnore(); + /*virtual*/ bool canAddToIgnore() const; + + // Spell checking helper functions + std::string getMisspelledWord(U32 pos) const; + bool isMisspelledWord(U32 pos) const; + void onSpellCheckSettingsChange(); + // used by LLTextSegment layout code bool getWordWrap() { return mWordWrap; } bool getUseEllipses() { return mUseEllipses; } @@ -540,6 +561,14 @@ protected: BOOL mIsSelecting; // Are we in the middle of a drag-select? + // spell checking + bool mSpellCheck; + S32 mSpellCheckStart; + S32 mSpellCheckEnd; + LLTimer mSpellCheckTimer; + std::list<std::pair<U32, U32> > mMisspellRanges; + std::vector<std::string> mSuggestionList; + // configuration S32 mHPad; // padding on left of text S32 mVPad; // padding above text diff --git a/indra/llui/lltextbox.cpp b/indra/llui/lltextbox.cpp index 6a905b7ec0..11cfa1d263 100644 --- a/indra/llui/lltextbox.cpp +++ b/indra/llui/lltextbox.cpp @@ -150,7 +150,7 @@ S32 LLTextBox::getTextPixelHeight() LLSD LLTextBox::getValue() const { - return LLSD(getText()); + return getViewModel()->getValue(); } BOOL LLTextBox::setTextArg( const std::string& key, const LLStringExplicit& text ) diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 9720dded6c..144b6960a1 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -54,6 +54,7 @@ #include "llwindow.h" #include "lltextparser.h" #include "llscrollcontainer.h" +#include "llspellcheck.h" #include "llpanel.h" #include "llurlregistry.h" #include "lltooltip.h" @@ -77,6 +78,7 @@ template class LLTextEditor* LLView::getChild<class LLTextEditor>( const S32 UI_TEXTEDITOR_LINE_NUMBER_MARGIN = 32; const S32 UI_TEXTEDITOR_LINE_NUMBER_DIGITS = 4; const S32 SPACES_PER_TAB = 4; +const F32 SPELLCHECK_DELAY = 0.5f; // delay between the last keypress and spell checking the word the cursor is on /////////////////////////////////////////////////////////////////// @@ -1953,7 +1955,38 @@ void LLTextEditor::showContextMenu(S32 x, S32 y) S32 screen_x, screen_y; localPointToScreen(x, y, &screen_x, &screen_y); - mContextMenu->show(screen_x, screen_y); + + setCursorAtLocalPos(x, y, false); + if (hasSelection()) + { + if ( (mCursorPos < llmin(mSelectionStart, mSelectionEnd)) || (mCursorPos > llmax(mSelectionStart, mSelectionEnd)) ) + { + deselect(); + } + else + { + setCursorPos(llmax(mSelectionStart, mSelectionEnd)); + } + } + + bool use_spellcheck = getSpellCheck(), is_misspelled = false; + if (use_spellcheck) + { + mSuggestionList.clear(); + + // If the cursor is on a misspelled word, retrieve suggestions for it + std::string misspelled_word = getMisspelledWord(mCursorPos); + if ((is_misspelled = !misspelled_word.empty()) == true) + { + LLSpellChecker::instance().getSuggestions(misspelled_word, mSuggestionList); + } + } + + mContextMenu->setItemVisible("Suggestion Separator", (use_spellcheck) && (!mSuggestionList.empty())); + mContextMenu->setItemVisible("Add to Dictionary", (use_spellcheck) && (is_misspelled)); + mContextMenu->setItemVisible("Add to Ignore", (use_spellcheck) && (is_misspelled)); + mContextMenu->setItemVisible("Spellcheck Separator", (use_spellcheck) && (is_misspelled)); + mContextMenu->show(screen_x, screen_y, this); } @@ -2838,6 +2871,9 @@ void LLTextEditor::setKeystrokeCallback(const keystroke_signal_t::slot_type& cal void LLTextEditor::onKeyStroke() { mKeystrokeSignal(this); + + mSpellCheckStart = mSpellCheckEnd = -1; + mSpellCheckTimer.setTimerExpirySec(SPELLCHECK_DELAY); } //virtual diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp index b5e27616b7..87bf518aa1 100644 --- a/indra/llui/llui.cpp +++ b/indra/llui/llui.cpp @@ -831,7 +831,11 @@ void gl_stippled_line_3d( const LLVector3& start, const LLVector3& end, const LL gGL.flush(); glLineWidth(2.5f); - glLineStipple(2, 0x3333 << shift); + + if (!LLGLSLShader::sNoFixedFunction) + { + glLineStipple(2, 0x3333 << shift); + } gGL.begin(LLRender::LINES); { diff --git a/indra/llui/llviewmodel.h b/indra/llui/llviewmodel.h index 763af5d8a2..ef2e314799 100644 --- a/indra/llui/llviewmodel.h +++ b/indra/llui/llviewmodel.h @@ -102,6 +102,7 @@ public: // New functions /// Get the stored value in string form const LLWString& getDisplay() const { return mDisplay; } + LLWString& getEditableDisplay() { mDirty = true; mUpdateFromDisplay = true; return mDisplay; } /** * Set the display string directly (see LLTextEditor). What the user is diff --git a/indra/llwindow/llkeyboard.cpp b/indra/llwindow/llkeyboard.cpp index 53cecf9d4a..8b356ba138 100644 --- a/indra/llwindow/llkeyboard.cpp +++ b/indra/llwindow/llkeyboard.cpp @@ -46,7 +46,7 @@ LLKeyStringTranslatorFunc* LLKeyboard::mStringTranslator = NULL; // Used for l10 // Class Implementation // -LLKeyboard::LLKeyboard() : mCallbacks(NULL), mNumpadDistinct(ND_NUMLOCK_OFF) +LLKeyboard::LLKeyboard() : mCallbacks(NULL) { S32 i; diff --git a/indra/llwindow/llkeyboard.h b/indra/llwindow/llkeyboard.h index ba472cfde5..c155c1b362 100644 --- a/indra/llwindow/llkeyboard.h +++ b/indra/llwindow/llkeyboard.h @@ -63,14 +63,6 @@ class LLWindowCallbacks; class LLKeyboard { public: - typedef enum e_numpad_distinct - { - ND_NEVER, - ND_NUMLOCK_OFF, - ND_NUMLOCK_ON - } ENumpadDistinct; - -public: LLKeyboard(); virtual ~LLKeyboard(); @@ -107,8 +99,6 @@ public: static BOOL keyFromString(const std::string& str, KEY *key); // False on failure static std::string stringFromKey(KEY key); static std::string stringFromAccelerator( MASK accel_mask, KEY key ); - e_numpad_distinct getNumpadDistinct() { return mNumpadDistinct; } - void setNumpadDistinct(e_numpad_distinct val) { mNumpadDistinct = val; } void setCallbacks(LLWindowCallbacks *cbs) { mCallbacks = cbs; } F32 getKeyElapsedTime( KEY key ); // Returns time in seconds since key was pressed. @@ -135,8 +125,6 @@ protected: static LLKeyStringTranslatorFunc* mStringTranslator; // Used for l10n + PC/Mac/Linux accelerator labeling - e_numpad_distinct mNumpadDistinct; - EKeyboardInsertMode mInsertMode; static std::map<KEY,std::string> sKeysToNames; diff --git a/indra/llwindow/llkeyboardmacosx.cpp b/indra/llwindow/llkeyboardmacosx.cpp index ecc2631669..7f8f303517 100644 --- a/indra/llwindow/llkeyboardmacosx.cpp +++ b/indra/llwindow/llkeyboardmacosx.cpp @@ -299,28 +299,11 @@ void LLKeyboardMacOSX::scanKeyboard() BOOL LLKeyboardMacOSX::translateNumpadKey( const U16 os_key, KEY *translated_key ) { - if(mNumpadDistinct == ND_NUMLOCK_ON) - { - std::map<U16, KEY>::iterator iter= mTranslateNumpadMap.find(os_key); - if(iter != mTranslateNumpadMap.end()) - { - *translated_key = iter->second; - return TRUE; - } - } return translateKey(os_key, translated_key); } U16 LLKeyboardMacOSX::inverseTranslateNumpadKey(const KEY translated_key) { - if(mNumpadDistinct == ND_NUMLOCK_ON) - { - std::map<KEY, U16>::iterator iter= mInvTranslateNumpadMap.find(translated_key); - if(iter != mInvTranslateNumpadMap.end()) - { - return iter->second; - } - } return inverseTranslateKey(translated_key); } diff --git a/indra/llwindow/llkeyboardsdl.cpp b/indra/llwindow/llkeyboardsdl.cpp index 4bb9603368..7c9aa1d340 100644 --- a/indra/llwindow/llkeyboardsdl.cpp +++ b/indra/llwindow/llkeyboardsdl.cpp @@ -312,29 +312,11 @@ void LLKeyboardSDL::scanKeyboard() BOOL LLKeyboardSDL::translateNumpadKey( const U16 os_key, KEY *translated_key) { - if(mNumpadDistinct == ND_NUMLOCK_ON) - { - std::map<U16, KEY>::iterator iter= mTranslateNumpadMap.find(os_key); - if(iter != mTranslateNumpadMap.end()) - { - *translated_key = iter->second; - return TRUE; - } - } - BOOL success = translateKey(os_key, translated_key); - return success; + return translateKey(os_key, translated_key); } U16 LLKeyboardSDL::inverseTranslateNumpadKey(const KEY translated_key) { - if(mNumpadDistinct == ND_NUMLOCK_ON) - { - std::map<KEY, U16>::iterator iter= mInvTranslateNumpadMap.find(translated_key); - if(iter != mInvTranslateNumpadMap.end()) - { - return iter->second; - } - } return inverseTranslateKey(translated_key); } diff --git a/indra/llwindow/llkeyboardwin32.cpp b/indra/llwindow/llkeyboardwin32.cpp index df78816bd6..be3fe5deb0 100644 --- a/indra/llwindow/llkeyboardwin32.cpp +++ b/indra/llwindow/llkeyboardwin32.cpp @@ -299,69 +299,13 @@ void LLKeyboardWin32::scanKeyboard() BOOL LLKeyboardWin32::translateExtendedKey(const U16 os_key, const MASK mask, KEY *translated_key) { - if(mNumpadDistinct == ND_NUMLOCK_ON) - { - std::map<U16, KEY>::iterator iter = mTranslateNumpadMap.find(os_key); - if (iter != mTranslateNumpadMap.end()) - { - *translated_key = iter->second; - return TRUE; - } - } - - BOOL success = translateKey(os_key, translated_key); - if(mNumpadDistinct != ND_NEVER) { - if(!success) return success; - if(mask & MASK_EXTENDED) - { - // this is where we'd create new keycodes for extended keys - // the set of extended keys includes the 'normal' arrow keys and - // the pgup/dn/insert/home/end/delete cluster above the arrow keys - // see http://windowssdk.msdn.microsoft.com/en-us/library/ms646280.aspx - - // only process the return key if numlock is off - if(((mNumpadDistinct == ND_NUMLOCK_OFF && - !(GetKeyState(VK_NUMLOCK) & 1)) - || mNumpadDistinct == ND_NUMLOCK_ON) && - *translated_key == KEY_RETURN) { - *translated_key = KEY_PAD_RETURN; - } - } - else - { - // the non-extended keys, those are in the numpad - switch (*translated_key) - { - case KEY_LEFT: - *translated_key = KEY_PAD_LEFT; break; - case KEY_RIGHT: - *translated_key = KEY_PAD_RIGHT; break; - case KEY_UP: - *translated_key = KEY_PAD_UP; break; - case KEY_DOWN: - *translated_key = KEY_PAD_DOWN; break; - case KEY_HOME: - *translated_key = KEY_PAD_HOME; break; - case KEY_END: - *translated_key = KEY_PAD_END; break; - case KEY_PAGE_UP: - *translated_key = KEY_PAD_PGUP; break; - case KEY_PAGE_DOWN: - *translated_key = KEY_PAD_PGDN; break; - case KEY_INSERT: - *translated_key = KEY_PAD_INS; break; - case KEY_DELETE: - *translated_key = KEY_PAD_DEL; break; - } - } - } - return success; + return translateKey(os_key, translated_key); } U16 LLKeyboardWin32::inverseTranslateExtendedKey(const KEY translated_key) { // if numlock is on, then we need to translate KEY_PAD_FOO to the corresponding number pad number - if((mNumpadDistinct == ND_NUMLOCK_ON) && (GetKeyState(VK_NUMLOCK) & 1)) + if(GetKeyState(VK_NUMLOCK) & 1) { std::map<KEY, U16>::iterator iter = mInvTranslateNumpadMap.find(translated_key); if (iter != mInvTranslateNumpadMap.end()) diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index e07fbddb94..6f0d90be06 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -367,6 +367,10 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, U32 fsaa_samples) : LLWindow(callbacks, fullscreen, flags) { + + //MAINT-516 -- force a load of opengl32.dll just in case windows went sideways + LoadLibrary(L"opengl32.dll"); + mFSAASamples = fsaa_samples; mIconResource = gIconResource; mOverrideAspectRatio = 0.f; diff --git a/indra/llxml/llcontrol.cpp b/indra/llxml/llcontrol.cpp index 0809d95628..53d9380f4f 100644 --- a/indra/llxml/llcontrol.cpp +++ b/indra/llxml/llcontrol.cpp @@ -201,7 +201,8 @@ void LLControlVariable::setValue(const LLSD& new_value, bool saved_value) } LLSD storable_value = getComparableValue(new_value); - bool value_changed = llsd_compare(getValue(), storable_value) == FALSE; + LLSD original_value = getValue(); + bool value_changed = llsd_compare(original_value, storable_value) == FALSE; if(saved_value) { // If we're going to save this value, return to default but don't fire @@ -237,7 +238,7 @@ void LLControlVariable::setValue(const LLSD& new_value, bool saved_value) if(value_changed) { - mCommitSignal(this, storable_value); + firePropertyChanged(original_value); } } @@ -249,12 +250,13 @@ void LLControlVariable::setDefaultValue(const LLSD& value) // *NOTE: Default values are not saved, only read. LLSD comparable_value = getComparableValue(value); - bool value_changed = (llsd_compare(getValue(), comparable_value) == FALSE); + LLSD original_value = getValue(); + bool value_changed = (llsd_compare(original_value, comparable_value) == FALSE); resetToDefault(false); mValues[0] = comparable_value; if(value_changed) { - firePropertyChanged(); + firePropertyChanged(original_value); } } @@ -277,6 +279,8 @@ void LLControlVariable::resetToDefault(bool fire_signal) { //The first setting is always the default //Pop to it and fire off the listener + LLSD originalValue = mValues.back(); + while(mValues.size() > 1) { mValues.pop_back(); @@ -284,7 +288,7 @@ void LLControlVariable::resetToDefault(bool fire_signal) if(fire_signal) { - firePropertyChanged(); + firePropertyChanged(originalValue); } } diff --git a/indra/llxml/llcontrol.h b/indra/llxml/llcontrol.h index 597031ec70..9a3a40e476 100644 --- a/indra/llxml/llcontrol.h +++ b/indra/llxml/llcontrol.h @@ -98,7 +98,7 @@ class LLControlVariable : public LLRefCount public: typedef boost::signals2::signal<bool(LLControlVariable* control, const LLSD&), boost_boolean_combiner> validate_signal_t; - typedef boost::signals2::signal<void(LLControlVariable* control, const LLSD&)> commit_signal_t; + typedef boost::signals2::signal<void(LLControlVariable* control, const LLSD&, const LLSD&)> commit_signal_t; private: std::string mName; @@ -146,11 +146,11 @@ public: void setHiddenFromSettingsEditor(bool hide); void setComment(const std::string& comment); - void firePropertyChanged() +private: + void firePropertyChanged(const LLSD &pPreviousValue) { - mCommitSignal(this, mValues.back()); + mCommitSignal(this, mValues.back(), pPreviousValue); } -private: LLSD getComparableValue(const LLSD& value); bool llsd_compare(const LLSD& a, const LLSD & b); }; diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index c16ad14379..9783601696 100755 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -13,6 +13,7 @@ include(EXPAT) include(FMOD) include(OPENAL) include(FindOpenGL) +include(Hunspell) include(JsonCpp) include(LLAudio) include(LLCharacter) @@ -70,6 +71,7 @@ include_directories( ${LLLOGIN_INCLUDE_DIRS} ${UPDATER_INCLUDE_DIRS} ${LIBS_PREBUILT_DIR}/include/collada + ${LIBS_PREBUILD_DIR}/include/hunspell ${OPENAL_LIB_INCLUDE_DIRS} ${LIBS_PREBUILT_DIR}/include/collada/1.4 ) @@ -96,6 +98,7 @@ set(viewer_SOURCE_FILES llassetuploadresponders.cpp llattachmentsmgr.cpp llaudiosourcevo.cpp + llautoreplace.cpp llavataractions.cpp llavatariconctrl.cpp llavatarlist.cpp @@ -167,6 +170,7 @@ set(viewer_SOURCE_FILES llfloaterabout.cpp llfloaterbvhpreview.cpp llfloaterauction.cpp + llfloaterautoreplacesettings.cpp llfloateravatar.cpp llfloateravatarpicker.cpp llfloateravatartextures.cpp @@ -210,7 +214,6 @@ set(viewer_SOURCE_FILES llfloatermemleak.cpp llfloatermodelpreview.cpp llfloatermodeluploadbase.cpp - llfloatermodelwizard.cpp llfloaternamedesc.cpp llfloaternotificationsconsole.cpp llfloaterobjectweights.cpp @@ -232,6 +235,7 @@ set(viewer_SOURCE_FILES llfloatersidepanelcontainer.cpp llfloatersnapshot.cpp llfloatersounddevices.cpp + llfloaterspellchecksettings.cpp llfloatertelehub.cpp llfloatertestinspectors.cpp llfloatertestlistview.cpp @@ -654,6 +658,7 @@ set(viewer_HEADER_FILES llassetuploadresponders.h llattachmentsmgr.h llaudiosourcevo.h + llautoreplace.h llavataractions.h llavatariconctrl.h llavatarlist.h @@ -725,6 +730,7 @@ set(viewer_HEADER_FILES llfloaterabout.h llfloaterbvhpreview.h llfloaterauction.h + llfloaterautoreplacesettings.h llfloateravatar.h llfloateravatarpicker.h llfloateravatartextures.h @@ -768,7 +774,6 @@ set(viewer_HEADER_FILES llfloatermemleak.h llfloatermodelpreview.h llfloatermodeluploadbase.h - llfloatermodelwizard.h llfloaternamedesc.h llfloaternotificationsconsole.h llfloaterobjectweights.h @@ -790,6 +795,7 @@ set(viewer_HEADER_FILES llfloatersidepanelcontainer.h llfloatersnapshot.h llfloatersounddevices.h + llfloaterspellchecksettings.h llfloatertelehub.h llfloatertestinspectors.h llfloatertestlistview.h @@ -1572,6 +1578,9 @@ if (WINDOWS) ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/msvcp100.dll ${SHARED_LIB_STAGING_DIR}/Debug/msvcr100d.dll ${SHARED_LIB_STAGING_DIR}/Debug/msvcp100d.dll + ${SHARED_LIB_STAGING_DIR}/Release/libhunspell.dll + ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/libhunspell.dll + ${SHARED_LIB_STAGING_DIR}/Debug/libhunspell.dll ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/SLVoice.exe ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/vivoxsdk.dll ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/ortp.dll @@ -1750,6 +1759,7 @@ target_link_libraries(${VIEWER_BINARY_NAME} ${LLMATH_LIBRARIES} ${LLCOMMON_LIBRARIES} ${NDOF_LIBRARY} + ${HUNSPELL_LIBRARY} ${viewer_LIBRARIES} ${BOOST_PROGRAM_OPTIONS_LIBRARY} ${BOOST_REGEX_LIBRARY} diff --git a/indra/newview/app_settings/autoreplace.xml b/indra/newview/app_settings/autoreplace.xml new file mode 100644 index 0000000000..09d19f7b04 --- /dev/null +++ b/indra/newview/app_settings/autoreplace.xml @@ -0,0 +1,8330 @@ +<llsd> + <array> + <map> + <key>name</key> + <string>Abbreviations</string> + <key>replacements</key> + <map> + <key>afaic</key> + <string>As far as I am concerned</string> + <key>afaik</key> + <string>As far as I know</string> + <key>afk</key> + <string>away from keyboard</string> + <key>atm</key> + <string>at the moment</string> + <key>bbiab</key> + <string>be back in a bit</string> + <key>bbl</key> + <string>be back later</string> + <key>brb</key> + <string>be right back</string> + <key>btw</key> + <string>by the way</string> + <key>fyi</key> + <string>For your information</string> + <key>fwiw</key> + <string>For what its worth</string> + <key>gtg</key> + <string>got to go</string> + <key>idk</key> + <string>I don't know</string> + <key>iirc</key> + <string>if I recall correctly</string> + <key>imho</key> + <string>in my humble opinion</string> + <key>imo</key> + <string>in my opinion</string> + <key>irl</key> + <string>in real life</string> + <key>np</key> + <string>no problem</string> + <key>nsfw</key> + <string>not safe for work</string> + <key>nvm</key> + <string>nevermind</string> + <key>tc</key> + <string>take care</string> + <key>thx</key> + <string>thanks</string> + <key>ttfn</key> + <string>ta-ta for now</string> + <key>ttyl</key> + <string>talk to you later</string> + <key>ty</key> + <string>thank you</string> + <key>tyvm</key> + <string>thank you very much</string> + <key>wb</key> + <string>welcome back</string> + <key>yw</key> + <string>you're welcome</string> + <key>yvw</key> + <string>you're very welcome</string> + </map> + </map> + <map> + <key>name</key> + <string>Spelling Corrections</string> + <key>replacements</key> + <map> + <key>Amercia</key> + <string>America</string> + <key>Bernouilli</key> + <string>Bernoulli</string> + <key>Blitzkreig</key> + <string>Blitzkrieg</string> + <key>Bonnano</key> + <string>Bonanno</string> + <key>Brasillian</key> + <string>Brazilian</string> + <key>Britian</key> + <string>Britain</string> + <key>Brittish</key> + <string>British</string> + <key>Buddah</key> + <string>Buddha</string> + <key>Buddist</key> + <string>Buddhist</string> + <key>Cambrige</key> + <string>Cambridge</string> + <key>Capetown</key> + <string>Cape Town</string> + <key>Carmalite</key> + <string>Carmelite</string> + <key>Carnagie</key> + <string>Carnegie</string> + <key>Carnagie-Mellon</key> + <string>Carnegie-Mellon</string> + <key>Carnigie</key> + <string>Carnegie</string> + <key>Carnigie-Mellon</key> + <string>Carnegie-Mellon</string> + <key>Carribbean</key> + <string>Caribbean</string> + <key>Carribean</key> + <string>Caribbean</string> + <key>Carthagian</key> + <string>Carthaginian</string> + <key>Cataline</key> + <string>Catiline</string> + <key>Ceasar</key> + <string>Caesar</string> + <key>Celcius</key> + <string>Celsius</string> + <key>Champange</key> + <string>Champagne</string> + <key>Cincinatti</key> + <string>Cincinnati</string> + <key>Cincinnatti</key> + <string>Cincinnati</string> + <key>Conneticut</key> + <string>Connecticut</string> + <key>Dardenelles</key> + <string>Dardanelles</string> + <key>Dravadian</key> + <string>Dravidian</string> + <key>Enlish</key> + <string>English</string> + <key>Europian</key> + <string>European</string> + <key>Europians</key> + <string>Europeans</string> + <key>Eurpean</key> + <string>European</string> + <key>Eurpoean</key> + <string>European</string> + <key>Farenheit</key> + <string>Fahrenheit</string> + <key>Febuary</key> + <string>February</string> + <key>Feburary</key> + <string>February</string> + <key>Flemmish</key> + <string>Flemish</string> + <key>Formalhaut</key> + <string>Fomalhaut</string> + <key>Foundland</key> + <string>Newfoundland</string> + <key>Fransiscan</key> + <string>Franciscan</string> + <key>Fransiscans</key> + <string>Franciscans</string> + <key>Galations</key> + <string>Galatians</string> + <key>Gameboy</key> + <string>Game Boy</string> + <key>Ghandi</key> + <string>Gandhi</string> + <key>Godounov</key> + <string>Godunov</string> + <key>Gothenberg</key> + <string>Gothenburg</string> + <key>Gottleib</key> + <string>Gottlieb</string> + <key>Guaduloupe</key> + <string>Guadalupe</string> + <key>Guadulupe</key> + <string>Guadalupe</string> + <key>Guatamala</key> + <string>Guatemala</string> + <key>Guatamalan</key> + <string>Guatemalan</string> + <key>Guilia</key> + <string>Giulia</string> + <key>Guilio</key> + <string>Giulio</string> + <key>Guiness</key> + <string>Guinness</string> + <key>Guiseppe</key> + <string>Giuseppe</string> + <key>Habsbourg</key> + <string>Habsburg</string> + <key>Hallowean</key> + <string>Halloween</string> + <key>Heidelburg</key> + <string>Heidelberg</string> + <key>Ihaca</key> + <string>Ithaca</string> + <key>Israelies</key> + <string>Israelis</string> + <key>Janurary</key> + <string>January</string> + <key>Januray</key> + <string>January</string> + <key>Japanes</key> + <string>Japanese</string> + <key>Johanine</key> + <string>Johannine</string> + <key>Jospeh</key> + <string>Joseph</string> + <key>Juadaism</key> + <string>Judaism</string> + <key>Juadism</key> + <string>Judaism</string> + <key>Lybia</key> + <string>Libya</string> + <key>Malcom</key> + <string>Malcolm</string> + <key>Massachussets</key> + <string>Massachusetts</string> + <key>Massachussetts</key> + <string>Massachusetts</string> + <key>Mediteranean</key> + <string>Mediterranean</string> + <key>Michagan</key> + <string>Michigan</string> + <key>Misouri</key> + <string>Missouri</string> + <key>Missisipi</key> + <string>Mississippi</string> + <key>Missisippi</key> + <string>Mississippi</string> + <key>Monserrat</key> + <string>Montserrat</string> + <key>Montnana</key> + <string>Montana</string> + <key>Morisette</key> + <string>Morissette</string> + <key>Morrisette</key> + <string>Morissette</string> + <key>Mythraic</key> + <string>Mithraic</string> + <key>Naploeon</key> + <string>Napoleon</string> + <key>Napolean</key> + <string>Napoleon</string> + <key>Napoleonian</key> + <string>Napoleonic</string> + <key>Nazereth</key> + <string>Nazareth</string> + <key>Newyorker</key> + <string>New Yorker</string> + <key>Novermber</key> + <string>November</string> + <key>Nullabour</key> + <string>Nullarbor</string> + <key>Nuremburg</key> + <string>Nuremberg</string> + <key>Palistian</key> + <string>Palestinian</string> + <key>Palistinian</key> + <string>Palestinian</string> + <key>Palistinians</key> + <string>Palestinians</string> + <key>Papanicalou</key> + <string>Papanicolaou</string> + <key>Peloponnes</key> + <string>Peloponnesus</string> + <key>Pennyslvania</key> + <string>Pennsylvania</string> + <key>Pharoah</key> + <string>Pharaoh</string> + <key>Philipines</key> + <string>Philippines</string> + <key>Phillipine</key> + <string>Philippine</string> + <key>Phillipines</key> + <string>Philippines</string> + <key>Phillippines</key> + <string>Philippines</string> + <key>Phonecian</key> + <string>Phoenecian</string> + <key>Portugese</key> + <string>Portuguese</string> + <key>Postdam</key> + <string>Potsdam</string> + <key>Premonasterians</key> + <string>Premonstratensians</string> + <key>Pucini</key> + <string>Puccini</string> + <key>Puertorrican</key> + <string>Puerto Rican</string> + <key>Puertorricans</key> + <string>Puerto Ricans</string> + <key>Queenland</key> + <string>Queensland</string> + <key>Rockerfeller</key> + <string>Rockefeller</string> + <key>Russion</key> + <string>Russian</string> + <key>Sanhedrim</key> + <string>Sanhedrin</string> + <key>Saterday</key> + <string>Saturday</string> + <key>Saterdays</key> + <string>Saturdays</string> + <key>Sionist</key> + <string>Zionist</string> + <key>Sionists</key> + <string>Zionists</string> + <key>Sixtin</key> + <string>Sistine</string> + <key>Skagerak</key> + <string>Skagerrak</string> + <key>Tolkein</key> + <string>Tolkien</string> + <key>Tuscon</key> + <string>Tucson</string> + <key>Ukranian</key> + <string>Ukrainian</string> + <key>UnitesStates</key> + <string>UnitedStates</string> + <key>Yementite</key> + <string>Yemenite</string> + <key>abandonned</key> + <string>abandoned</string> + <key>aberation</key> + <string>aberration</string> + <key>abilties</key> + <string>abilities</string> + <key>abilty</key> + <string>ability</string> + <key>abondon</key> + <string>abandon</string> + <key>abondoned</key> + <string>abandoned</string> + <key>abondoning</key> + <string>abandoning</string> + <key>abondons</key> + <string>abandons</string> + <key>aborigene</key> + <string>aborigine</string> + <key>abortificant</key> + <string>abortifacient</string> + <key>abreviate</key> + <string>abbreviate</string> + <key>abreviated</key> + <string>abbreviated</string> + <key>abreviation</key> + <string>abbreviation</string> + <key>abritrary</key> + <string>arbitrary</string> + <key>absail</key> + <string>abseil</string> + <key>absailing</key> + <string>abseiling</string> + <key>absense</key> + <string>absence</string> + <key>absolutly</key> + <string>absolutely</string> + <key>absorbsion</key> + <string>absorption</string> + <key>absorbtion</key> + <string>absorption</string> + <key>abundacies</key> + <string>abundances</string> + <key>abundancies</key> + <string>abundances</string> + <key>abundunt</key> + <string>abundant</string> + <key>abutts</key> + <string>abuts</string> + <key>acadamy</key> + <string>academy</string> + <key>acadmic</key> + <string>academic</string> + <key>accademic</key> + <string>academic</string> + <key>accademy</key> + <string>academy</string> + <key>acccused</key> + <string>accused</string> + <key>accelleration</key> + <string>acceleration</string> + <key>accension</key> + <string>ascension</string> + <key>acceptence</key> + <string>acceptance</string> + <key>acceptible</key> + <string>acceptable</string> + <key>accessable</key> + <string>accessible</string> + <key>accidentaly</key> + <string>accidentally</string> + <key>accidently</key> + <string>accidentally</string> + <key>acclimitization</key> + <string>acclimatization</string> + <key>accomadate</key> + <string>accommodate</string> + <key>accomadated</key> + <string>accommodated</string> + <key>accomadates</key> + <string>accommodates</string> + <key>accomadating</key> + <string>accommodating</string> + <key>accomadation</key> + <string>accommodation</string> + <key>accomadations</key> + <string>accommodations</string> + <key>accomdate</key> + <string>accommodate</string> + <key>accomodate</key> + <string>accommodate</string> + <key>accomodated</key> + <string>accommodated</string> + <key>accomodates</key> + <string>accommodates</string> + <key>accomodating</key> + <string>accommodating</string> + <key>accomodation</key> + <string>accommodation</string> + <key>accomodations</key> + <string>accommodations</string> + <key>accompanyed</key> + <string>accompanied</string> + <key>accordeon</key> + <string>accordion</string> + <key>accordian</key> + <string>accordion</string> + <key>accoring</key> + <string>according</string> + <key>accoustic</key> + <string>acoustic</string> + <key>accquainted</key> + <string>acquainted </string> + <key>accrediation</key> + <string>accreditation</string> + <key>accredidation</key> + <string>accreditation</string> + <key>accross</key> + <string>across</string> + <key>accussed</key> + <string>accused</string> + <key>acedemic</key> + <string>academic</string> + <key>acheive</key> + <string>achieve</string> + <key>acheived</key> + <string>achieved</string> + <key>acheivement</key> + <string>achievement</string> + <key>acheivements</key> + <string>achievements</string> + <key>acheives</key> + <string>achieves</string> + <key>acheiving</key> + <string>achieving</string> + <key>acheivment</key> + <string>achievement</string> + <key>acheivments</key> + <string>achievements</string> + <key>achievment</key> + <string>achievement</string> + <key>achievments</key> + <string>achievements</string> + <key>achivement</key> + <string>achievement</string> + <key>achivements</key> + <string>achievements</string> + <key>acknowldeged</key> + <string>acknowledged</string> + <key>acknowledgeing</key> + <string>acknowledging</string> + <key>ackward</key> + <string>awkward</string> + <key>acommodate</key> + <string>accommodate</string> + <key>acomplish</key> + <string>accomplish</string> + <key>acomplished</key> + <string>accomplished</string> + <key>acomplishment</key> + <string>accomplishment</string> + <key>acomplishments</key> + <string>accomplishments</string> + <key>acording</key> + <string>according</string> + <key>acordingly</key> + <string>accordingly</string> + <key>acquaintence</key> + <string>acquaintance</string> + <key>acquaintences</key> + <string>acquaintances</string> + <key>acquiantence</key> + <string>acquaintance</string> + <key>acquiantences</key> + <string>acquaintances</string> + <key>acquited</key> + <string>acquitted</string> + <key>activites</key> + <string>activities</string> + <key>activly</key> + <string>actively</string> + <key>actualy</key> + <string>actually</string> + <key>acuracy</key> + <string>accuracy</string> + <key>acused</key> + <string>accused</string> + <key>acustom</key> + <string>accustom</string> + <key>acustommed</key> + <string>accustomed</string> + <key>adavanced</key> + <string>advanced</string> + <key>adbandon</key> + <string>abandon</string> + <key>additinally</key> + <string>additionally</string> + <key>additionaly</key> + <string>additionally</string> + <key>additonal</key> + <string>additional</string> + <key>additonally</key> + <string>additionally</string> + <key>addmission</key> + <string>admission</string> + <key>addopt</key> + <string>adopt</string> + <key>addopted</key> + <string>adopted</string> + <key>addoptive</key> + <string>adoptive</string> + <key>addres</key> + <string>address</string> + <key>addresable</key> + <string>addressable</string> + <key>addresed</key> + <string>addressed</string> + <key>addresing</key> + <string>addressing</string> + <key>addressess</key> + <string>addresses</string> + <key>addtion</key> + <string>addition</string> + <key>addtional</key> + <string>additional</string> + <key>adecuate</key> + <string>adequate</string> + <key>adequit</key> + <string>adequate</string> + <key>adhearing</key> + <string>adhering</string> + <key>adherance</key> + <string>adherence</string> + <key>admendment</key> + <string>amendment</string> + <key>admininistrative</key> + <string>administrative</string> + <key>adminstered</key> + <string>administered</string> + <key>adminstrate</key> + <string>administrate</string> + <key>adminstration</key> + <string>administration</string> + <key>adminstrative</key> + <string>administrative</string> + <key>adminstrator</key> + <string>administrator</string> + <key>admissability</key> + <string>admissibility</string> + <key>admissable</key> + <string>admissible</string> + <key>admited</key> + <string>admitted</string> + <key>admitedly</key> + <string>admittedly</string> + <key>adn</key> + <string>and</string> + <key>adolecent</key> + <string>adolescent</string> + <key>adquire</key> + <string>acquire</string> + <key>adquired</key> + <string>acquired</string> + <key>adquires</key> + <string>acquires</string> + <key>adquiring</key> + <string>acquiring</string> + <key>adres</key> + <string>address</string> + <key>adresable</key> + <string>addressable</string> + <key>adresing</key> + <string>addressing</string> + <key>adress</key> + <string>address</string> + <key>adressable</key> + <string>addressable</string> + <key>adressed</key> + <string>addressed</string> + <key>adressing</key> + <string>addressing</string> + <key>adventrous</key> + <string>adventurous</string> + <key>advertisment</key> + <string>advertisement</string> + <key>advertisments</key> + <string>advertisements</string> + <key>advesary</key> + <string>adversary</string> + <key>adviced</key> + <string>advised</string> + <key>aeriel</key> + <string>aerial</string> + <key>aeriels</key> + <string>aerials</string> + <key>afair</key> + <string>affair</string> + <key>afficianados</key> + <string>aficionados</string> + <key>afficionado</key> + <string>aficionado</string> + <key>afficionados</key> + <string>aficionados</string> + <key>affilate</key> + <string>affiliate</string> + <key>affilliate</key> + <string>affiliate</string> + <key>affort</key> + <string>afford</string> + <key>aforememtioned</key> + <string>aforementioned</string> + <key>againnst</key> + <string>against</string> + <key>agains</key> + <string>against</string> + <key>agaisnt</key> + <string>against</string> + <key>aganist</key> + <string>against</string> + <key>aggaravates</key> + <string>aggravates</string> + <key>aggreed</key> + <string>agreed</string> + <key>aggreement</key> + <string>agreement</string> + <key>aggregious</key> + <string>egregious</string> + <key>aggresive</key> + <string>aggressive</string> + <key>agian</key> + <string>again</string> + <key>agianst</key> + <string>against</string> + <key>agin</key> + <string>again</string> + <key>agina</key> + <string>again</string> + <key>aginst</key> + <string>against</string> + <key>agravate</key> + <string>aggravate</string> + <key>agre</key> + <string>agree</string> + <key>agred</key> + <string>agreed</string> + <key>agreeement</key> + <string>agreement</string> + <key>agreemnt</key> + <string>agreement</string> + <key>agregate</key> + <string>aggregate</string> + <key>agregates</key> + <string>aggregates</string> + <key>agreing</key> + <string>agreeing</string> + <key>agression</key> + <string>aggression</string> + <key>agressive</key> + <string>aggressive</string> + <key>agressively</key> + <string>aggressively</string> + <key>agressor</key> + <string>aggressor</string> + <key>agricuture</key> + <string>agriculture</string> + <key>agrieved</key> + <string>aggrieved</string> + <key>ahev</key> + <string>have</string> + <key>ahppen</key> + <string>happen</string> + <key>ahve</key> + <string>have</string> + <key>aicraft</key> + <string>aircraft</string> + <key>aiport</key> + <string>airport</string> + <key>airbourne</key> + <string>airborne</string> + <key>aircaft</key> + <string>aircraft</string> + <key>aircrafts</key> + <string>aircraft</string> + <key>airporta</key> + <string>airports</string> + <key>airrcraft</key> + <string>aircraft</string> + <key>aisian</key> + <string>asian</string> + <key>albiet</key> + <string>albeit</string> + <key>alchohol</key> + <string>alcohol</string> + <key>alchoholic</key> + <string>alcoholic</string> + <key>alchol</key> + <string>alcohol</string> + <key>alcholic</key> + <string>alcoholic</string> + <key>alcohal</key> + <string>alcohol</string> + <key>alcoholical</key> + <string>alcoholic</string> + <key>aledge</key> + <string>allege</string> + <key>aledged</key> + <string>alleged</string> + <key>aledges</key> + <string>alleges</string> + <key>alege</key> + <string>allege</string> + <key>aleged</key> + <string>alleged</string> + <key>alegience</key> + <string>allegiance</string> + <key>algebraical</key> + <string>algebraic</string> + <key>algorhitms</key> + <string>algorithms</string> + <key>algoritm</key> + <string>algorithm</string> + <key>algoritms</key> + <string>algorithms</string> + <key>alientating</key> + <string>alienating</string> + <key>alledge</key> + <string>allege</string> + <key>alledged</key> + <string>alleged</string> + <key>alledgedly</key> + <string>allegedly</string> + <key>alledges</key> + <string>alleges</string> + <key>allegedely</key> + <string>allegedly</string> + <key>allegedy</key> + <string>allegedly</string> + <key>allegely</key> + <string>allegedly</string> + <key>allegence</key> + <string>allegiance</string> + <key>allegience</key> + <string>allegiance</string> + <key>allign</key> + <string>align</string> + <key>alligned</key> + <string>aligned</string> + <key>alliviate</key> + <string>alleviate</string> + <key>allopone</key> + <string>allophone</string> + <key>allopones</key> + <string>allophones</string> + <key>allready</key> + <string>already</string> + <key>allthough</key> + <string>although</string> + <key>alltime</key> + <string>all-time</string> + <key>alltogether</key> + <string>altogether</string> + <key>almsot</key> + <string>almost</string> + <key>alochol</key> + <string>alcohol</string> + <key>alomst</key> + <string>almost</string> + <key>alot</key> + <string>a lot</string> + <key>alotted</key> + <string>allotted</string> + <key>alowed</key> + <string>allowed</string> + <key>alowing</key> + <string>allowing</string> + <key>alreayd</key> + <string>already</string> + <key>alse</key> + <string>else</string> + <key>alsot</key> + <string>also</string> + <key>alternitives</key> + <string>alternatives</string> + <key>altho</key> + <string>although</string> + <key>althought</key> + <string>although</string> + <key>altough</key> + <string>although</string> + <key>alusion</key> + <string>allusion</string> + <key>alwasy</key> + <string>always</string> + <key>alwyas</key> + <string>always</string> + <key>amalgomated</key> + <string>amalgamated</string> + <key>amatuer</key> + <string>amateur</string> + <key>amature</key> + <string>armature</string> + <key>amendmant</key> + <string>amendment</string> + <key>amerliorate</key> + <string>ameliorate</string> + <key>amke</key> + <string>make</string> + <key>amking</key> + <string>making</string> + <key>ammend</key> + <string>amend</string> + <key>ammended</key> + <string>amended</string> + <key>ammendment</key> + <string>amendment</string> + <key>ammendments</key> + <string>amendments</string> + <key>ammount</key> + <string>amount</string> + <key>ammused</key> + <string>amused</string> + <key>amoung</key> + <string>among</string> + <key>amoungst</key> + <string>amongst</string> + <key>amung</key> + <string>among</string> + <key>amunition</key> + <string>ammunition</string> + <key>analagous</key> + <string>analogous</string> + <key>analitic</key> + <string>analytic</string> + <key>analogeous</key> + <string>analogous</string> + <key>anarchim</key> + <string>anarchism</string> + <key>anarchistm</key> + <string>anarchism</string> + <key>anbd</key> + <string>and</string> + <key>ancestory</key> + <string>ancestry</string> + <key>ancilliary</key> + <string>ancillary</string> + <key>androgenous</key> + <string>androgynous</string> + <key>androgeny</key> + <string>androgyny</string> + <key>anihilation</key> + <string>annihilation</string> + <key>aniversary</key> + <string>anniversary</string> + <key>annoint</key> + <string>anoint</string> + <key>annointed</key> + <string>anointed</string> + <key>annointing</key> + <string>anointing</string> + <key>annoints</key> + <string>anoints</string> + <key>annouced</key> + <string>announced</string> + <key>annualy</key> + <string>annually</string> + <key>annuled</key> + <string>annulled</string> + <key>anohter</key> + <string>another</string> + <key>anomolies</key> + <string>anomalies</string> + <key>anomolous</key> + <string>anomalous</string> + <key>anomoly</key> + <string>anomaly</string> + <key>anonimity</key> + <string>anonymity</string> + <key>anounced</key> + <string>announced</string> + <key>anouncement</key> + <string>announcement</string> + <key>ansalisation</key> + <string>nasalisation</string> + <key>ansalization</key> + <string>nasalization</string> + <key>ansestors</key> + <string>ancestors</string> + <key>antartic</key> + <string>antarctic</string> + <key>anthromorphization</key> + <string>anthropomorphization</string> + <key>anthropolgist</key> + <string>anthropologist</string> + <key>anthropolgy</key> + <string>anthropology</string> + <key>anual</key> + <string>annual</string> + <key>anulled</key> + <string>annulled</string> + <key>anwsered</key> + <string>answered</string> + <key>anyhwere</key> + <string>anywhere</string> + <key>anyother</key> + <string>any other</string> + <key>anytying</key> + <string>anything</string> + <key>aparent</key> + <string>apparent</string> + <key>aparment</key> + <string>apartment</string> + <key>apenines</key> + <string>apennines</string> + <key>aplication</key> + <string>application</string> + <key>aplied</key> + <string>applied</string> + <key>apolegetics</key> + <string>apologetics</string> + <key>apon</key> + <string>apron</string> + <key>apparant</key> + <string>apparent</string> + <key>apparantly</key> + <string>apparently</string> + <key>appart</key> + <string>apart</string> + <key>appartment</key> + <string>apartment</string> + <key>appartments</key> + <string>apartments</string> + <key>appealling</key> + <string>appealing</string> + <key>appeareance</key> + <string>appearance</string> + <key>appearence</key> + <string>appearance</string> + <key>appearences</key> + <string>appearances</string> + <key>apperance</key> + <string>appearance</string> + <key>apperances</key> + <string>appearances</string> + <key>appereance</key> + <string>appearance</string> + <key>appereances</key> + <string>appearances</string> + <key>applicaiton</key> + <string>application</string> + <key>applicaitons</key> + <string>applications</string> + <key>appologies</key> + <string>apologies</string> + <key>appology</key> + <string>apology</string> + <key>apprearance</key> + <string>appearance</string> + <key>apprieciate</key> + <string>appreciate</string> + <key>approachs</key> + <string>approaches</string> + <key>appropiate</key> + <string>appropriate</string> + <key>appropraite</key> + <string>appropriate</string> + <key>appropropiate</key> + <string>appropriate</string> + <key>approproximate</key> + <string>approximate</string> + <key>approxamately</key> + <string>approximately</string> + <key>approxiately</key> + <string>approximately</string> + <key>approximitely</key> + <string>approximately</string> + <key>aprehensive</key> + <string>apprehensive</string> + <key>apropriate</key> + <string>appropriate</string> + <key>aproximate</key> + <string>approximate</string> + <key>aproximately</key> + <string>approximately</string> + <key>aquaduct</key> + <string>aqueduct</string> + <key>aquaintance</key> + <string>acquaintance</string> + <key>aquainted</key> + <string>acquainted</string> + <key>aquiantance</key> + <string>acquaintance</string> + <key>aquire</key> + <string>acquire</string> + <key>aquired</key> + <string>acquired</string> + <key>aquiring</key> + <string>acquiring</string> + <key>aquisition</key> + <string>acquisition</string> + <key>aquitted</key> + <string>acquitted</string> + <key>aranged</key> + <string>arranged</string> + <key>arangement</key> + <string>arrangement</string> + <key>arbitarily</key> + <string>arbitrarily</string> + <key>arbitary</key> + <string>arbitrary</string> + <key>archaelogists</key> + <string>archaeologists</string> + <key>archaelogy</key> + <string>archaeology</string> + <key>archaoelogy</key> + <string>archaeology</string> + <key>archaology</key> + <string>archaeology</string> + <key>archeaologist</key> + <string>archaeologist</string> + <key>archeaologists</key> + <string>archaeologists</string> + <key>archetect</key> + <string>architect</string> + <key>archetects</key> + <string>architects</string> + <key>archetectural</key> + <string>architectural</string> + <key>archetecturally</key> + <string>architecturally</string> + <key>archetecture</key> + <string>architecture</string> + <key>archiac</key> + <string>archaic</string> + <key>archictect</key> + <string>architect</string> + <key>archimedian</key> + <string>archimedean</string> + <key>architecht</key> + <string>architect</string> + <key>architechturally</key> + <string>architecturally</string> + <key>architechture</key> + <string>architecture</string> + <key>architechtures</key> + <string>architectures</string> + <key>architectual</key> + <string>architectural</string> + <key>archtype</key> + <string>archetype</string> + <key>archtypes</key> + <string>archetypes</string> + <key>aready</key> + <string>already</string> + <key>areodynamics</key> + <string>aerodynamics</string> + <key>argubly</key> + <string>arguably</string> + <key>arguement</key> + <string>argument</string> + <key>arguements</key> + <string>arguments</string> + <key>arised</key> + <string>arose</string> + <key>arival</key> + <string>arrival</string> + <key>armamant</key> + <string>armament</string> + <key>armistace</key> + <string>armistice</string> + <key>arogant</key> + <string>arrogant</string> + <key>arogent</key> + <string>arrogant</string> + <key>aroud</key> + <string>around</string> + <key>arrangment</key> + <string>arrangement</string> + <key>arrangments</key> + <string>arrangements</string> + <key>arround</key> + <string>around</string> + <key>artical</key> + <string>article</string> + <key>artice</key> + <string>article</string> + <key>articel</key> + <string>article</string> + <key>artifical</key> + <string>artificial</string> + <key>artifically</key> + <string>artificially</string> + <key>artillary</key> + <string>artillery</string> + <key>arund</key> + <string>around</string> + <key>asetic</key> + <string>ascetic</string> + <key>asfar</key> + <string>as far</string> + <key>asign</key> + <string>assign</string> + <key>aslo</key> + <string>also</string> + <key>asociated</key> + <string>associated</string> + <key>asorbed</key> + <string>absorbed</string> + <key>asphyxation</key> + <string>asphyxiation</string> + <key>assasin</key> + <string>assassin</string> + <key>assasinate</key> + <string>assassinate</string> + <key>assasinated</key> + <string>assassinated</string> + <key>assasinates</key> + <string>assassinates</string> + <key>assasination</key> + <string>assassination</string> + <key>assasinations</key> + <string>assassinations</string> + <key>assasined</key> + <string>assassinated</string> + <key>assasins</key> + <string>assassins</string> + <key>assassintation</key> + <string>assassination</string> + <key>assemple</key> + <string>assemble</string> + <key>assertation</key> + <string>assertion</string> + <key>asside</key> + <string>aside</string> + <key>assisnate</key> + <string>assassinate</string> + <key>assit</key> + <string>assist</string> + <key>assitant</key> + <string>assistant</string> + <key>assocation</key> + <string>association</string> + <key>assoicate</key> + <string>associate</string> + <key>assoicated</key> + <string>associated</string> + <key>assoicates</key> + <string>associates</string> + <key>assosication</key> + <string>assassination</string> + <key>asssassans</key> + <string>assassins</string> + <key>assualt</key> + <string>assault</string> + <key>assualted</key> + <string>assaulted</string> + <key>assymetric</key> + <string>asymmetric</string> + <key>assymetrical</key> + <string>asymmetrical</string> + <key>asteriod</key> + <string>asteroid</string> + <key>asthetic</key> + <string>aesthetic</string> + <key>asthetical</key> + <string>aesthetical</string> + <key>asthetically</key> + <string>aesthetically</string> + <key>asume</key> + <string>assume</string> + <key>aswell</key> + <string>as well</string> + <key>atain</key> + <string>attain</string> + <key>atempting</key> + <string>attempting</string> + <key>atheistical</key> + <string>atheistic</string> + <key>athenean</key> + <string>athenian</string> + <key>atheneans</key> + <string>athenians</string> + <key>athiesm</key> + <string>atheism</string> + <key>athiest</key> + <string>atheist</string> + <key>atorney</key> + <string>attorney</string> + <key>atribute</key> + <string>attribute</string> + <key>atributed</key> + <string>attributed</string> + <key>atributes</key> + <string>attributes</string> + <key>attaindre</key> + <string>attainder</string> + <key>attemp</key> + <string>attempt</string> + <key>attemped</key> + <string>attempted</string> + <key>attemt</key> + <string>attempt</string> + <key>attemted</key> + <string>attempted</string> + <key>attemting</key> + <string>attempting</string> + <key>attemts</key> + <string>attempts</string> + <key>attendence</key> + <string>attendance</string> + <key>attendent</key> + <string>attendant</string> + <key>attendents</key> + <string>attendants</string> + <key>attened</key> + <string>attended</string> + <key>attension</key> + <string>attention</string> + <key>attitide</key> + <string>attitude</string> + <key>attributred</key> + <string>attributed</string> + <key>attrocities</key> + <string>atrocities</string> + <key>audeince</key> + <string>audience</string> + <key>auromated</key> + <string>automated</string> + <key>austrailia</key> + <string>Australia</string> + <key>austrailian</key> + <string>Australian</string> + <key>auther</key> + <string>author</string> + <key>authobiographic</key> + <string>autobiographic</string> + <key>authobiography</key> + <string>autobiography</string> + <key>authorative</key> + <string>authoritative</string> + <key>authorites</key> + <string>authorities</string> + <key>authorithy</key> + <string>authority</string> + <key>authoritiers</key> + <string>authorities</string> + <key>authoritive</key> + <string>authoritative</string> + <key>authrorities</key> + <string>authorities</string> + <key>autochtonous</key> + <string>autochthonous</string> + <key>autoctonous</key> + <string>autochthonous</string> + <key>automaticly</key> + <string>automatically</string> + <key>automibile</key> + <string>automobile</string> + <key>automonomous</key> + <string>autonomous</string> + <key>autor</key> + <string>author</string> + <key>autority</key> + <string>authority</string> + <key>auxilary</key> + <string>auxiliary</string> + <key>auxillaries</key> + <string>auxiliaries</string> + <key>auxillary</key> + <string>auxiliary</string> + <key>auxilliaries</key> + <string>auxiliaries</string> + <key>auxilliary</key> + <string>auxiliary</string> + <key>availabe</key> + <string> available</string> + <key>availablity</key> + <string>availability</string> + <key>availaible</key> + <string>available</string> + <key>availble</key> + <string>available</string> + <key>availiable</key> + <string>available</string> + <key>availible</key> + <string>available</string> + <key>avalable</key> + <string>available</string> + <key>avalance</key> + <string>avalanche</string> + <key>avaliable</key> + <string>available</string> + <key>avation</key> + <string>aviation</string> + <key>avengence</key> + <string>a vengeance</string> + <key>averageed</key> + <string>averaged</string> + <key>avilable</key> + <string>available</string> + <key>awared</key> + <string>awarded</string> + <key>awya</key> + <string>away</string> + <key>baceause</key> + <string>because</string> + <key>backgorund</key> + <string>background</string> + <key>backrounds</key> + <string>backgrounds</string> + <key>bakc</key> + <string>back</string> + <key>banannas</key> + <string>bananas</string> + <key>bandwith</key> + <string>bandwidth</string> + <key>bankrupcy</key> + <string>bankruptcy</string> + <key>banruptcy</key> + <string>bankruptcy</string> + <key>baout</key> + <string>about</string> + <key>basicaly</key> + <string>basically</string> + <key>basicly</key> + <string>basically</string> + <key>bcak</key> + <string>back</string> + <key>beachead</key> + <string>beachhead</string> + <key>beacuse</key> + <string>because</string> + <key>beastiality</key> + <string>bestiality</string> + <key>beatiful</key> + <string>beautiful</string> + <key>beaurocracy</key> + <string>bureaucracy</string> + <key>beaurocratic</key> + <string>bureaucratic</string> + <key>beautyfull</key> + <string>beautiful</string> + <key>becamae</key> + <string>became</string> + <key>becames</key> + <string>becomes</string> + <key>becasue</key> + <string>because</string> + <key>beccause</key> + <string>because</string> + <key>becomeing</key> + <string>becoming</string> + <key>becomming</key> + <string>becoming</string> + <key>becouse</key> + <string>because</string> + <key>becuase</key> + <string>because</string> + <key>bedore</key> + <string>before</string> + <key>befoer</key> + <string>before</string> + <key>beggin</key> + <string>begin</string> + <key>begginer</key> + <string>beginner</string> + <key>begginers</key> + <string>beginners</string> + <key>beggining</key> + <string>beginning</string> + <key>begginings</key> + <string>beginnings</string> + <key>beggins</key> + <string>begins</string> + <key>begining</key> + <string>beginning</string> + <key>beginnig</key> + <string>beginning</string> + <key>behavour</key> + <string>behavior</string> + <key>beleagured</key> + <string>beleaguered</string> + <key>beleif</key> + <string>belief</string> + <key>beleive</key> + <string>believe</string> + <key>beleived</key> + <string>believed</string> + <key>beleives</key> + <string>believes</string> + <key>beleiving</key> + <string>believing</string> + <key>beligum</key> + <string>belgium</string> + <key>belive</key> + <string>believe</string> + <key>belived</key> + <string>believed</string> + <key>belives</key> + <string>believes</string> + <key>belligerant</key> + <string>belligerent</string> + <key>bellweather</key> + <string>bellwether</string> + <key>bemusemnt</key> + <string>bemusement</string> + <key>beneficary</key> + <string>beneficiary</string> + <key>beng</key> + <string>being</string> + <key>benificial</key> + <string>beneficial</string> + <key>benifit</key> + <string>benefit</string> + <key>benifits</key> + <string>benefits</string> + <key>bergamont</key> + <string>bergamot</string> + <key>beseige</key> + <string>besiege</string> + <key>beseiged</key> + <string>besieged</string> + <key>beseiging</key> + <string>besieging</string> + <key>betwen</key> + <string>between</string> + <key>beween</key> + <string>between</string> + <key>bewteen</key> + <string>between</string> + <key>bilateraly</key> + <string>bilaterally</string> + <key>billingualism</key> + <string>bilingualism</string> + <key>binominal</key> + <string>binomial</string> + <key>bizzare</key> + <string>bizarre</string> + <key>blaim</key> + <string>blame</string> + <key>blaimed</key> + <string>blamed</string> + <key>blessure</key> + <string>blessing</string> + <key>bodydbuilder</key> + <string>bodybuilder</string> + <key>bombardement</key> + <string>bombardment</string> + <key>bombarment</key> + <string>bombardment</string> + <key>bondary</key> + <string>boundary</string> + <key>borke</key> + <string>broke</string> + <key>boundry</key> + <string>boundary</string> + <key>bouyancy</key> + <string>buoyancy</string> + <key>bouyant</key> + <string>buoyant</string> + <key>boyant</key> + <string>buoyant</string> + <key>breakthough</key> + <string>breakthrough</string> + <key>breakthroughts</key> + <string>breakthroughs</string> + <key>breif</key> + <string>brief</string> + <key>breifly</key> + <string>briefly</string> + <key>brethen</key> + <string>brethren</string> + <key>bretheren</key> + <string>brethren</string> + <key>briliant</key> + <string>brilliant</string> + <key>brillant</key> + <string>brilliant</string> + <key>brimestone</key> + <string>brimstone</string> + <key>broacasted</key> + <string>broadcast</string> + <key>broadacasting</key> + <string>broadcasting</string> + <key>broady</key> + <string>broadly</string> + <key>buisness</key> + <string>business</string> + <key>buisnessman</key> + <string>businessman</string> + <key>buoancy</key> + <string>buoyancy</string> + <key>burried</key> + <string>buried</string> + <key>busineses</key> + <string>businesses</string> + <key>busness</key> + <string>business</string> + <key>bussiness</key> + <string>business</string> + <key>caculater</key> + <string>calculator</string> + <key>cacuses</key> + <string>caucuses</string> + <key>cahracters</key> + <string>characters</string> + <key>calaber</key> + <string>caliber</string> + <key>calculater</key> + <string>calculator</string> + <key>calculs</key> + <string>calculus</string> + <key>calenders</key> + <string>calendars</string> + <key>caligraphy</key> + <string>calligraphy</string> + <key>caluclate</key> + <string>calculate</string> + <key>caluclated</key> + <string>calculated</string> + <key>caluculate</key> + <string>calculate</string> + <key>caluculated</key> + <string>calculated</string> + <key>calulate</key> + <string>calculate</string> + <key>calulated</key> + <string>calculated</string> + <key>calulater</key> + <string>calculator</string> + <key>camoflage</key> + <string>camouflage</string> + <key>campain</key> + <string>campaign</string> + <key>campains</key> + <string>campaigns</string> + <key>candadate</key> + <string>candidate</string> + <key>candiate</key> + <string>candidate</string> + <key>candidiate</key> + <string>candidate</string> + <key>cannister</key> + <string>canister</string> + <key>cannisters</key> + <string>canisters</string> + <key>cannnot</key> + <string>cannot</string> + <key>cannonical</key> + <string>canonical</string> + <key>cannotation</key> + <string>connotation</string> + <key>cannotations</key> + <string>connotations</string> + <key>cant</key> + <string>can't</string> + <key>caost</key> + <string>coast</string> + <key>caperbility</key> + <string>capability</string> + <key>capible</key> + <string>capable</string> + <key>captial</key> + <string>capital</string> + <key>captued</key> + <string>captured</string> + <key>capturd</key> + <string>captured</string> + <key>carachter</key> + <string>character</string> + <key>caracterized</key> + <string>characterized</string> + <key>carcas</key> + <string>carcass</string> + <key>carefull</key> + <string>careful</string> + <key>careing</key> + <string>caring</string> + <key>carismatic</key> + <string>charismatic</string> + <key>carnege</key> + <string>carnage</string> + <key>carnige</key> + <string>carnage</string> + <key>carniverous</key> + <string>carnivorous</string> + <key>carreer</key> + <string>career</string> + <key>carrers</key> + <string>careers</string> + <key>cartdridge</key> + <string>cartridge</string> + <key>carthographer</key> + <string>cartographer</string> + <key>cartilege</key> + <string>cartilage</string> + <key>cartilidge</key> + <string>cartilage</string> + <key>cartrige</key> + <string>cartridge</string> + <key>casette</key> + <string>cassette</string> + <key>casion</key> + <string>caisson</string> + <key>cassawory</key> + <string>cassowary</string> + <key>cassowarry</key> + <string>cassowary</string> + <key>casulaties</key> + <string>casualties</string> + <key>casulaty</key> + <string>casualty</string> + <key>catagories</key> + <string>categories</string> + <key>catagorized</key> + <string>categorized</string> + <key>catagory</key> + <string>category</string> + <key>catapillar</key> + <string>caterpillar</string> + <key>catapillars</key> + <string>caterpillars</string> + <key>catapiller</key> + <string>caterpillar</string> + <key>catapillers</key> + <string>caterpillars</string> + <key>catepillar</key> + <string>caterpillar</string> + <key>catepillars</key> + <string>caterpillars</string> + <key>catergorize</key> + <string>categorize</string> + <key>catergorized</key> + <string>categorized</string> + <key>caterpilar</key> + <string>caterpillar</string> + <key>caterpilars</key> + <string>caterpillars</string> + <key>caterpiller</key> + <string>caterpillar</string> + <key>caterpillers</key> + <string>caterpillars</string> + <key>cathlic</key> + <string>catholic</string> + <key>catholocism</key> + <string>catholicism</string> + <key>catterpilar</key> + <string>caterpillar</string> + <key>catterpilars</key> + <string>caterpillars</string> + <key>catterpillar</key> + <string>caterpillar</string> + <key>catterpillars</key> + <string>caterpillars</string> + <key>cattleship</key> + <string>battleship</string> + <key>causalities</key> + <string>casualties</string> + <key>cellpading</key> + <string>cellpadding</string> + <key>cementary</key> + <string>cemetery</string> + <key>cemetarey</key> + <string>cemetery</string> + <key>cemetaries</key> + <string>cemeteries</string> + <key>cemetary</key> + <string>cemetery</string> + <key>cencus</key> + <string>census</string> + <key>censur</key> + <string>censor</string> + <key>cententenial</key> + <string>centennial</string> + <key>centruies</key> + <string>centuries</string> + <key>centruy</key> + <string>century</string> + <key>ceratin</key> + <string>certain</string> + <key>cerimonial</key> + <string>ceremonial</string> + <key>cerimonies</key> + <string>ceremonies</string> + <key>cerimonious</key> + <string>ceremonious</string> + <key>cerimony</key> + <string>ceremony</string> + <key>ceromony</key> + <string>ceremony</string> + <key>certainity</key> + <string>certainty</string> + <key>certian</key> + <string>certain</string> + <key>chalenging</key> + <string>challenging</string> + <key>challange</key> + <string>challenge</string> + <key>challanged</key> + <string>challenged</string> + <key>challege</key> + <string>challenge</string> + <key>changable</key> + <string>changeable</string> + <key>charachter</key> + <string>character</string> + <key>charachters</key> + <string>characters</string> + <key>charactersistic</key> + <string>characteristic</string> + <key>charactor</key> + <string>character </string> + <key>charactors</key> + <string>characters</string> + <key>charasmatic</key> + <string>charismatic</string> + <key>charaterized</key> + <string>characterized</string> + <key>chariman</key> + <string>chairman</string> + <key>charistics</key> + <string>characteristics</string> + <key>cheif</key> + <string>chief</string> + <key>cheifs</key> + <string>chiefs</string> + <key>chemcial</key> + <string>chemical</string> + <key>chemcially</key> + <string>chemically</string> + <key>chemestry</key> + <string>chemistry</string> + <key>chemicaly</key> + <string>chemically</string> + <key>childbird</key> + <string>childbirth</string> + <key>childen</key> + <string>children</string> + <key>choosen</key> + <string>chosen</string> + <key>chracter</key> + <string>character</string> + <key>chuch</key> + <string>church</string> + <key>churchs</key> + <string>churches</string> + <key>circulaton</key> + <string>circulation</string> + <key>circumsicion</key> + <string>circumcision</string> + <key>circut</key> + <string>circuit</string> + <key>ciricuit</key> + <string>circuit</string> + <key>ciriculum</key> + <string>curriculum</string> + <key>civillian</key> + <string>civilian</string> + <key>claer</key> + <string>clear</string> + <key>claerer</key> + <string>clearer</string> + <key>claerly</key> + <string>clearly</string> + <key>claimes</key> + <string>claims</string> + <key>clas</key> + <string>class</string> + <key>clasic</key> + <string>classic</string> + <key>clasical</key> + <string>classical</string> + <key>clasically</key> + <string>classically</string> + <key>cleareance</key> + <string>clearance</string> + <key>clera</key> + <string>clear</string> + <key>clincial</key> + <string>clinical</string> + <key>clinicaly</key> + <string>clinically</string> + <key>cmo</key> + <string>com</string> + <key>cmoputer</key> + <string>computer</string> + <key>co-incided</key> + <string>coincided</string> + <key>coctail</key> + <string>cocktail</string> + <key>coform</key> + <string>conform</string> + <key>cognizent</key> + <string>cognizant</string> + <key>coincedentally</key> + <string>coincidentally</string> + <key>colaborations</key> + <string>collaborations</string> + <key>colateral</key> + <string>collateral</string> + <key>colelctive</key> + <string>collective</string> + <key>collaberative</key> + <string>collaborative</string> + <key>collecton</key> + <string>collection</string> + <key>collegue</key> + <string>colleague</string> + <key>collegues</key> + <string>colleagues</string> + <key>collonade</key> + <string>colonnade</string> + <key>collonies</key> + <string>colonies</string> + <key>collony</key> + <string>colony </string> + <key>collosal</key> + <string>colossal</string> + <key>colonizators</key> + <string>colonizers</string> + <key>comander</key> + <string>commander</string> + <key>comando</key> + <string>commando</string> + <key>comandos</key> + <string>commandos</string> + <key>comany</key> + <string>company</string> + <key>comapany</key> + <string>company</string> + <key>comback</key> + <string>comeback</string> + <key>combanations</key> + <string>combinations</string> + <key>combinatins</key> + <string>combinations</string> + <key>combusion</key> + <string>combustion</string> + <key>comdemnation</key> + <string>condemnation</string> + <key>comemmorates</key> + <string>commemorates</string> + <key>comemoretion</key> + <string>commemoration</string> + <key>comision</key> + <string>commission</string> + <key>comisioned</key> + <string>commissioned</string> + <key>comisioner</key> + <string>commissioner</string> + <key>comisioning</key> + <string>commissioning</string> + <key>comisions</key> + <string>commissions</string> + <key>comission</key> + <string>commission</string> + <key>comissioned</key> + <string>commissioned</string> + <key>comissioner</key> + <string>commissioner</string> + <key>comissioning</key> + <string>commissioning</string> + <key>comissions</key> + <string>commissions</string> + <key>comited</key> + <string>committed</string> + <key>comiting</key> + <string>committing</string> + <key>comitted</key> + <string>committed</string> + <key>comittee</key> + <string>committee</string> + <key>comitting</key> + <string>committing</string> + <key>commandoes</key> + <string>commandos</string> + <key>commedic</key> + <string>comedic</string> + <key>commemerative</key> + <string>commemorative</string> + <key>commemmorate</key> + <string>commemorate</string> + <key>commemmorating</key> + <string>commemorating</string> + <key>commerical</key> + <string>commercial</string> + <key>commerically</key> + <string>commercially</string> + <key>commericial</key> + <string>commercial</string> + <key>commericially</key> + <string>commercially</string> + <key>commerorative</key> + <string>commemorative</string> + <key>comming</key> + <string>coming</string> + <key>comminication</key> + <string>communication</string> + <key>commision</key> + <string>commission</string> + <key>commisioned</key> + <string>commissioned</string> + <key>commisioner</key> + <string>commissioner</string> + <key>commisioning</key> + <string>commissioning</string> + <key>commisions</key> + <string>commissions</string> + <key>commited</key> + <string>committed</string> + <key>commitee</key> + <string>committee</string> + <key>commiting</key> + <string>committing</string> + <key>committe</key> + <string>committee</string> + <key>committment</key> + <string>commitment</string> + <key>committments</key> + <string>commitments</string> + <key>commmemorated</key> + <string>commemorated</string> + <key>commongly</key> + <string>commonly</string> + <key>commonweath</key> + <string>commonwealth</string> + <key>commuications</key> + <string>communications</string> + <key>commuinications</key> + <string>communications</string> + <key>communciation</key> + <string>communication</string> + <key>communiation</key> + <string>communication</string> + <key>communites</key> + <string>communities</string> + <key>compability</key> + <string>compatibility</string> + <key>comparision</key> + <string>comparison</string> + <key>comparisions</key> + <string>comparisons</string> + <key>comparitive</key> + <string>comparative</string> + <key>comparitively</key> + <string>comparatively</string> + <key>compatabilities</key> + <string>compatibilities</string> + <key>compatability</key> + <string>compatibility</string> + <key>compatable</key> + <string>compatible</string> + <key>compatablities</key> + <string>compatibilities</string> + <key>compatablity</key> + <string>compatibility</string> + <key>compatiable</key> + <string>compatible</string> + <key>compatiblities</key> + <string>compatibilities</string> + <key>compatiblity</key> + <string>compatibility</string> + <key>compeitions</key> + <string>competitions</string> + <key>compensantion</key> + <string>compensation</string> + <key>competance</key> + <string>competence</string> + <key>competant</key> + <string>competent</string> + <key>competative</key> + <string>competitive</string> + <key>competion</key> + <string>competition</string> + <key>competitiion</key> + <string>competition</string> + <key>competive</key> + <string>competitive</string> + <key>competiveness</key> + <string>competitiveness</string> + <key>comphrehensive</key> + <string>comprehensive</string> + <key>compitent</key> + <string>competent</string> + <key>completedthe</key> + <string>completed the</string> + <key>completelyl</key> + <string>completely</string> + <key>completetion</key> + <string>completion</string> + <key>complier</key> + <string>compiler</string> + <key>componant</key> + <string>component</string> + <key>comprable</key> + <string>comparable</string> + <key>comprimise</key> + <string>compromise</string> + <key>compulsary</key> + <string>compulsory</string> + <key>compulsery</key> + <string>compulsory</string> + <key>computarized</key> + <string>computerized</string> + <key>concensus</key> + <string>consensus</string> + <key>concider</key> + <string>consider</string> + <key>concidered</key> + <string>considered</string> + <key>concidering</key> + <string>considering</string> + <key>conciders</key> + <string>considers</string> + <key>concieted</key> + <string>conceited</string> + <key>concieved</key> + <string>conceived</string> + <key>concious</key> + <string>conscious</string> + <key>conciously</key> + <string>consciously</string> + <key>conciousness</key> + <string>consciousness</string> + <key>condamned</key> + <string>condemned</string> + <key>condemmed</key> + <string>condemned</string> + <key>condidtion</key> + <string>condition</string> + <key>condidtions</key> + <string>conditions</string> + <key>conditionsof</key> + <string>conditions of</string> + <key>conected</key> + <string>connected</string> + <key>conection</key> + <string>connection</string> + <key>conesencus</key> + <string>consensus</string> + <key>confidental</key> + <string>confidential</string> + <key>confidentally</key> + <string>confidentially</string> + <key>confids</key> + <string>confides</string> + <key>configureable</key> + <string>configurable</string> + <key>confortable</key> + <string>comfortable</string> + <key>congradulations</key> + <string>congratulations</string> + <key>congresional</key> + <string>congressional</string> + <key>conived</key> + <string>connived</string> + <key>conjecutre</key> + <string>conjecture</string> + <key>conjuction</key> + <string>conjunction</string> + <key>conotations</key> + <string>connotations</string> + <key>conquerd</key> + <string>conquered</string> + <key>conquerer</key> + <string>conqueror</string> + <key>conquerers</key> + <string>conquerors</string> + <key>conqured</key> + <string>conquered</string> + <key>conscent</key> + <string>consent</string> + <key>consciouness</key> + <string>consciousness</string> + <key>consdider</key> + <string>consider</string> + <key>consdidered</key> + <string>considered</string> + <key>consdiered</key> + <string>considered</string> + <key>consectutive</key> + <string>consecutive</string> + <key>consenquently</key> + <string>consequently</string> + <key>consentrate</key> + <string>concentrate</string> + <key>consentrated</key> + <string>concentrated</string> + <key>consentrates</key> + <string>concentrates</string> + <key>consept</key> + <string>concept</string> + <key>consequentually</key> + <string>consequently</string> + <key>consequeseces</key> + <string>consequences</string> + <key>consern</key> + <string>concern</string> + <key>conserned</key> + <string>concerned</string> + <key>conserning</key> + <string>concerning</string> + <key>conservitive</key> + <string>conservative</string> + <key>consiciousness</key> + <string>consciousness</string> + <key>consicousness</key> + <string>consciousness</string> + <key>considerd</key> + <string>considered</string> + <key>consideres</key> + <string>considered</string> + <key>consious</key> + <string>conscious</string> + <key>consistant</key> + <string>consistent</string> + <key>consistantly</key> + <string>consistently</string> + <key>consituencies</key> + <string>constituencies</string> + <key>consituency</key> + <string>constituency</string> + <key>consituted</key> + <string>constituted</string> + <key>consitution</key> + <string>constitution</string> + <key>consitutional</key> + <string>constitutional</string> + <key>consolodate</key> + <string>consolidate</string> + <key>consolodated</key> + <string>consolidated</string> + <key>consonent</key> + <string>consonant</string> + <key>consonents</key> + <string>consonants</string> + <key>consorcium</key> + <string>consortium</string> + <key>conspiracys</key> + <string>conspiracies</string> + <key>conspiriator</key> + <string>conspirator</string> + <key>constaints</key> + <string>constraints</string> + <key>constanly</key> + <string>constantly</string> + <key>constarnation</key> + <string>consternation</string> + <key>constatn</key> + <string>constant</string> + <key>constinually</key> + <string>continually</string> + <key>constituant</key> + <string>constituent</string> + <key>constituants</key> + <string>constituents</string> + <key>constituion</key> + <string>constitution</string> + <key>constituional</key> + <string>constitutional</string> + <key>consttruction</key> + <string>construction</string> + <key>constuction</key> + <string>construction</string> + <key>consulant</key> + <string>consultant</string> + <key>consumate</key> + <string>consummate</string> + <key>consumated</key> + <string>consummated</string> + <key>contaiminate</key> + <string>contaminate</string> + <key>containes</key> + <string>contains</string> + <key>contamporaries</key> + <string>contemporaries</string> + <key>contamporary</key> + <string>contemporary</string> + <key>contempoary</key> + <string>contemporary</string> + <key>contemporaneus</key> + <string>contemporaneous</string> + <key>contempory</key> + <string>contemporary</string> + <key>contendor</key> + <string>contender</string> + <key>contibute</key> + <string>contribute </string> + <key>contibuted</key> + <string>contributed </string> + <key>contibutes</key> + <string>contributes </string> + <key>contigent</key> + <string>contingent</string> + <key>contined</key> + <string>continued</string> + <key>continous</key> + <string>continuous</string> + <key>continously</key> + <string>continuously</string> + <key>continueing</key> + <string>continuing</string> + <key>contravercial</key> + <string>controversial</string> + <key>contraversy</key> + <string>controversy</string> + <key>contributer</key> + <string>contributor</string> + <key>contributers</key> + <string>contributors</string> + <key>contritutions</key> + <string>contributions</string> + <key>controled</key> + <string>controlled</string> + <key>controling</key> + <string>controlling</string> + <key>controll</key> + <string>control</string> + <key>controlls</key> + <string>controls</string> + <key>controvercial</key> + <string>controversial</string> + <key>controvercy</key> + <string>controversy</string> + <key>controveries</key> + <string>controversies</string> + <key>controversal</key> + <string>controversial</string> + <key>controversey</key> + <string>controversy</string> + <key>controvertial</key> + <string>controversial</string> + <key>controvery</key> + <string>controversy</string> + <key>contruction</key> + <string>construction</string> + <key>conveinent</key> + <string>convenient</string> + <key>convenant</key> + <string>covenant</string> + <key>convential</key> + <string>conventional</string> + <key>convertables</key> + <string>convertibles</string> + <key>convertion</key> + <string>conversion</string> + <key>conveyer</key> + <string>conveyor</string> + <key>conviced</key> + <string>convinced</string> + <key>convienient</key> + <string>convenient</string> + <key>coordiantion</key> + <string>coordination</string> + <key>coorperations</key> + <string>corporations</string> + <key>copmetitors</key> + <string>competitors</string> + <key>coputer</key> + <string>computer</string> + <key>copywrite</key> + <string>copyright</string> + <key>coridal</key> + <string>cordial</string> + <key>cornmitted</key> + <string>committed</string> + <key>corosion</key> + <string>corrosion</string> + <key>corparate</key> + <string>corporate</string> + <key>corperations</key> + <string>corporations</string> + <key>correcters</key> + <string>correctors</string> + <key>correponding</key> + <string>corresponding</string> + <key>correposding</key> + <string>corresponding</string> + <key>correspondant</key> + <string>correspondent</string> + <key>correspondants</key> + <string>correspondents</string> + <key>corridoors</key> + <string>corridors</string> + <key>corrispond</key> + <string>correspond</string> + <key>corrispondant</key> + <string>correspondent</string> + <key>corrispondants</key> + <string>correspondents</string> + <key>corrisponded</key> + <string>corresponded</string> + <key>corrisponding</key> + <string>corresponding</string> + <key>corrisponds</key> + <string>corresponds</string> + <key>costitution</key> + <string>constitution</string> + <key>coucil</key> + <string>council</string> + <key>counries</key> + <string>countries</string> + <key>countains</key> + <string>contains</string> + <key>countires</key> + <string>countries</string> + <key>coururier</key> + <string>courier</string> + <key>coverted</key> + <string>converted</string> + <key>cpoy</key> + <string>copy</string> + <key>creaeted</key> + <string>created</string> + <key>creedence</key> + <string>credence</string> + <key>critereon</key> + <string>criterion</string> + <key>criterias</key> + <string>criteria</string> + <key>criticists</key> + <string>critics</string> + <key>critising</key> + <string>criticising</string> + <key>critisising</key> + <string>criticising</string> + <key>critisism</key> + <string>criticism</string> + <key>critisisms</key> + <string>criticisms</string> + <key>critisize</key> + <string>criticise</string> + <key>critisized</key> + <string>criticised</string> + <key>critisizes</key> + <string>criticises</string> + <key>critisizing</key> + <string>criticising</string> + <key>critized</key> + <string>criticized</string> + <key>critizing</key> + <string>criticizing</string> + <key>crockodiles</key> + <string>crocodiles</string> + <key>crowm</key> + <string>crown</string> + <key>crtical</key> + <string>critical</string> + <key>crticised</key> + <string>criticised</string> + <key>crucifiction</key> + <string>crucifixion</string> + <key>crusies</key> + <string>cruises</string> + <key>crystalisation</key> + <string>crystallisation</string> + <key>culiminating</key> + <string>culminating</string> + <key>cumulatative</key> + <string>cumulative</string> + <key>curch</key> + <string>church</string> + <key>curcuit</key> + <string>circuit</string> + <key>currenly</key> + <string>currently</string> + <key>curriculem</key> + <string>curriculum</string> + <key>cxan</key> + <string>cyan</string> + <key>cyclinder</key> + <string>cylinder</string> + <key>dacquiri</key> + <string>daiquiri</string> + <key>dael</key> + <string>deal</string> + <key>dalmation</key> + <string>dalmatian</string> + <key>damenor</key> + <string>demeanor</string> + <key>dammage</key> + <string>damage</string> + <key>daugher</key> + <string>daughter</string> + <key>debateable</key> + <string>debatable</string> + <key>decendant</key> + <string>descendant</string> + <key>decendants</key> + <string>descendants</string> + <key>decendent</key> + <string>descendant</string> + <key>decendents</key> + <string>descendants</string> + <key>decideable</key> + <string>decidable</string> + <key>decidely</key> + <string>decidedly</string> + <key>decieved</key> + <string>deceived</string> + <key>decison</key> + <string>decision</string> + <key>decomissioned</key> + <string>decommissioned</string> + <key>decomposit</key> + <string>decompose</string> + <key>decomposited</key> + <string>decomposed</string> + <key>decompositing</key> + <string>decomposing</string> + <key>decomposits</key> + <string>decomposes</string> + <key>decress</key> + <string>decrees</string> + <key>decribe</key> + <string>describe</string> + <key>decribed</key> + <string>described</string> + <key>decribes</key> + <string>describes</string> + <key>decribing</key> + <string>describing</string> + <key>dectect</key> + <string>detect</string> + <key>defendent</key> + <string>defendant</string> + <key>defendents</key> + <string>defendants</string> + <key>deffensively</key> + <string>defensively</string> + <key>deffine</key> + <string>define</string> + <key>deffined</key> + <string>defined</string> + <key>definance</key> + <string>defiance</string> + <key>definate</key> + <string>definite</string> + <key>definately</key> + <string>definitely</string> + <key>definatly</key> + <string>definitely</string> + <key>definetly</key> + <string>definitely</string> + <key>definining</key> + <string>defining</string> + <key>definit</key> + <string>definite</string> + <key>definitly</key> + <string>definitely</string> + <key>definiton</key> + <string>definition</string> + <key>defintion</key> + <string>definition</string> + <key>degrate</key> + <string>degrade</string> + <key>delagates</key> + <string>delegates</string> + <key>delapidated</key> + <string>dilapidated</string> + <key>delerious</key> + <string>delirious</string> + <key>delevopment</key> + <string>development</string> + <key>deliberatly</key> + <string>deliberately</string> + <key>delusionally</key> + <string>delusively</string> + <key>demenor</key> + <string>demeanor</string> + <key>demographical</key> + <string>demographic</string> + <key>demolision</key> + <string>demolition</string> + <key>demorcracy</key> + <string>democracy</string> + <key>demostration</key> + <string>demonstration</string> + <key>denegrating</key> + <string>denigrating</string> + <key>densly</key> + <string>densely</string> + <key>deparment</key> + <string>department</string> + <key>deparmental</key> + <string>departmental</string> + <key>deparments</key> + <string>departments</string> + <key>dependance</key> + <string>dependence</string> + <key>dependancy</key> + <string>dependency</string> + <key>dependant</key> + <string>dependent</string> + <key>deram</key> + <string>dream</string> + <key>deriviated</key> + <string>derived</string> + <key>derivitive</key> + <string>derivative</string> + <key>derogitory</key> + <string>derogatory</string> + <key>descendands</key> + <string>descendants</string> + <key>descibed</key> + <string>described</string> + <key>descision</key> + <string>decision</string> + <key>descisions</key> + <string>decisions</string> + <key>descriibes</key> + <string>describes</string> + <key>descripters</key> + <string>descriptors</string> + <key>descripton</key> + <string>description</string> + <key>desctruction</key> + <string>destruction</string> + <key>descuss</key> + <string>discuss</string> + <key>desgined</key> + <string>designed</string> + <key>deside</key> + <string>decide</string> + <key>desigining</key> + <string>designing</string> + <key>desinations</key> + <string>destinations</string> + <key>desintegrated</key> + <string>disintegrated</string> + <key>desintegration</key> + <string>disintegration</string> + <key>desireable</key> + <string>desirable</string> + <key>desitned</key> + <string>destined</string> + <key>desktiop</key> + <string>desktop</string> + <key>desorder</key> + <string>disorder</string> + <key>desoriented</key> + <string>disoriented</string> + <key>desparate</key> + <string>desperate</string> + <key>despict</key> + <string>depict</string> + <key>despiration</key> + <string>desperation</string> + <key>dessicated</key> + <string>desiccated</string> + <key>dessigned</key> + <string>designed</string> + <key>destablized</key> + <string>destabilized</string> + <key>destory</key> + <string>destroy</string> + <key>detailled</key> + <string>detailed</string> + <key>detatched</key> + <string>detached</string> + <key>deteoriated</key> + <string>deteriorated</string> + <key>deteriate</key> + <string>deteriorate</string> + <key>deterioriating</key> + <string>deteriorating</string> + <key>determinining</key> + <string>determining</string> + <key>detremental</key> + <string>detrimental</string> + <key>devasted</key> + <string>devastated</string> + <key>develope</key> + <string>develop</string> + <key>developement</key> + <string>development</string> + <key>developped</key> + <string>developed</string> + <key>develpment</key> + <string>development</string> + <key>devels</key> + <string>delves</string> + <key>devestated</key> + <string>devastated</string> + <key>devestating</key> + <string>devastating</string> + <key>devide</key> + <string>divide</string> + <key>devided</key> + <string>divided</string> + <key>devistating</key> + <string>devastating</string> + <key>devolopement</key> + <string>development</string> + <key>diablical</key> + <string>diabolical</string> + <key>diamons</key> + <string>diamonds</string> + <key>diaster</key> + <string>disaster</string> + <key>dichtomy</key> + <string>dichotomy</string> + <key>diconnects</key> + <string>disconnects</string> + <key>dicover</key> + <string>discover</string> + <key>dicovered</key> + <string>discovered</string> + <key>dicovering</key> + <string>discovering</string> + <key>dicovers</key> + <string>discovers</string> + <key>dicovery</key> + <string>discovery</string> + <key>dicussed</key> + <string>discussed</string> + <key>didnt</key> + <string>didn't</string> + <key>diea</key> + <string>idea</string> + <key>dieing</key> + <string>dying</string> + <key>dieties</key> + <string>deities</string> + <key>diety</key> + <string>deity</string> + <key>diferent</key> + <string>different</string> + <key>diferrent</key> + <string>different</string> + <key>differentiatiations</key> + <string>differentiations</string> + <key>differnt</key> + <string>different</string> + <key>difficulity</key> + <string>difficulty</string> + <key>diffrent</key> + <string>different</string> + <key>dificulties</key> + <string>difficulties</string> + <key>dificulty</key> + <string>difficulty</string> + <key>dimenions</key> + <string>dimensions</string> + <key>dimention</key> + <string>dimension</string> + <key>dimentional</key> + <string>dimensional</string> + <key>dimentions</key> + <string>dimensions</string> + <key>dimesnional</key> + <string>dimensional</string> + <key>diminuitive</key> + <string>diminutive</string> + <key>dimunitive</key> + <string>diminutive</string> + <key>diosese</key> + <string>diocese</string> + <key>diphtong</key> + <string>diphthong</string> + <key>diphtongs</key> + <string>diphthongs</string> + <key>diplomancy</key> + <string>diplomacy</string> + <key>dipthong</key> + <string>diphthong</string> + <key>dipthongs</key> + <string>diphthongs</string> + <key>dirived</key> + <string>derived</string> + <key>disagreeed</key> + <string>disagreed</string> + <key>disapeared</key> + <string>disappeared</string> + <key>disapointing</key> + <string>disappointing</string> + <key>disappearred</key> + <string>disappeared</string> + <key>disaproval</key> + <string>disapproval</string> + <key>disasterous</key> + <string>disastrous</string> + <key>disatisfaction</key> + <string>dissatisfaction</string> + <key>disatisfied</key> + <string>dissatisfied</string> + <key>disatrous</key> + <string>disastrous</string> + <key>discontentment</key> + <string>discontent</string> + <key>discribe</key> + <string>describe</string> + <key>discribed</key> + <string>described</string> + <key>discribes</key> + <string>describes</string> + <key>discribing</key> + <string>describing</string> + <key>disctinction</key> + <string>distinction</string> + <key>disctinctive</key> + <string>distinctive</string> + <key>disemination</key> + <string>dissemination</string> + <key>disenchanged</key> + <string>disenchanted</string> + <key>disiplined</key> + <string>disciplined</string> + <key>disobediance</key> + <string>disobedience</string> + <key>disobediant</key> + <string>disobedient</string> + <key>disolved</key> + <string>dissolved</string> + <key>disover</key> + <string>discover</string> + <key>dispair</key> + <string>despair</string> + <key>disparingly</key> + <string>disparagingly</string> + <key>dispence</key> + <string>dispense</string> + <key>dispenced</key> + <string>dispensed</string> + <key>dispencing</key> + <string>dispensing</string> + <key>dispicable</key> + <string>despicable</string> + <key>dispite</key> + <string>despite</string> + <key>dispostion</key> + <string>disposition</string> + <key>disproportiate</key> + <string>disproportionate</string> + <key>disputandem</key> + <string>disputandum</string> + <key>disricts</key> + <string>districts</string> + <key>dissagreement</key> + <string>disagreement</string> + <key>dissapear</key> + <string>disappear</string> + <key>dissapearance</key> + <string>disappearance</string> + <key>dissapeared</key> + <string>disappeared</string> + <key>dissapearing</key> + <string>disappearing</string> + <key>dissapears</key> + <string>disappears</string> + <key>dissappear</key> + <string>disappear</string> + <key>dissappears</key> + <string>disappears</string> + <key>dissappointed</key> + <string>disappointed</string> + <key>dissarray</key> + <string>disarray</string> + <key>dissobediance</key> + <string>disobedience</string> + <key>dissobediant</key> + <string>disobedient</string> + <key>dissobedience</key> + <string>disobedience</string> + <key>dissobedient</key> + <string>disobedient</string> + <key>distiction</key> + <string>distinction</string> + <key>distingish</key> + <string>distinguish</string> + <key>distingished</key> + <string>distinguished</string> + <key>distingishes</key> + <string>distinguishes</string> + <key>distingishing</key> + <string>distinguishing</string> + <key>distingquished</key> + <string>distinguished</string> + <key>distrubution</key> + <string>distribution</string> + <key>distruction</key> + <string>destruction</string> + <key>distructive</key> + <string>destructive</string> + <key>ditributed</key> + <string>distributed</string> + <key>diversed</key> + <string>diverged</string> + <key>divice</key> + <string>device</string> + <key>divison</key> + <string>division</string> + <key>divisons</key> + <string>divisions</string> + <key>doccument</key> + <string>document</string> + <key>doccumented</key> + <string>documented</string> + <key>doccuments</key> + <string>documents</string> + <key>docrines</key> + <string>doctrines</string> + <key>doctines</key> + <string>doctrines</string> + <key>documenatry</key> + <string>documentary</string> + <key>doens</key> + <string>does</string> + <key>doesnt</key> + <string>doesn't</string> + <key>doign</key> + <string>doing</string> + <key>dominaton</key> + <string>domination</string> + <key>dominent</key> + <string>dominant</string> + <key>dominiant</key> + <string>dominant</string> + <key>donig</key> + <string>doing</string> + <key>dont</key> + <string>don't</string> + <key>dosen't</key> + <string>doesn't</string> + <key>doub</key> + <string>doubt</string> + <key>doulbe</key> + <string>double</string> + <key>dowloads</key> + <string>downloads</string> + <key>dramtic</key> + <string>dramatic</string> + <key>draughtman</key> + <string>draughtsman</string> + <key>dreasm</key> + <string>dreams</string> + <key>driectly</key> + <string>directly</string> + <key>drnik</key> + <string>drink</string> + <key>druming</key> + <string>drumming</string> + <key>drummless</key> + <string>drumless</string> + <key>dupicate</key> + <string>duplicate</string> + <key>durig</key> + <string>during</string> + <key>durring</key> + <string>during</string> + <key>duting</key> + <string>during</string> + <key>dyas</key> + <string>dryas</string> + <key>eahc</key> + <string>each</string> + <key>ealier</key> + <string>earlier</string> + <key>earlies</key> + <string>earliest</string> + <key>earnt</key> + <string>earned</string> + <key>ecclectic</key> + <string>eclectic</string> + <key>eceonomy</key> + <string>economy</string> + <key>ecidious</key> + <string>deciduous</string> + <key>eclispe</key> + <string>eclipse</string> + <key>ecomonic</key> + <string>economic</string> + <key>ect</key> + <string>etc</string> + <key>eearly</key> + <string>early</string> + <key>efel</key> + <string>evil</string> + <key>effeciency</key> + <string>efficiency</string> + <key>effecient</key> + <string>efficient</string> + <key>effeciently</key> + <string>efficiently</string> + <key>efficency</key> + <string>efficiency</string> + <key>efficent</key> + <string>efficient</string> + <key>efficently</key> + <string>efficiently</string> + <key>efford</key> + <string>effort</string> + <key>effords</key> + <string>efforts</string> + <key>effulence</key> + <string>effluence</string> + <key>eigth</key> + <string>eight</string> + <key>eiter</key> + <string>either</string> + <key>elction</key> + <string>election</string> + <key>electic</key> + <string>electric</string> + <key>electon</key> + <string>electron</string> + <key>electrial</key> + <string>electrical</string> + <key>electricly</key> + <string>electrically</string> + <key>electricty</key> + <string>electricity</string> + <key>elementay</key> + <string>elementary</string> + <key>eleminated</key> + <string>eliminated</string> + <key>eleminating</key> + <string>eliminating</string> + <key>eles</key> + <string>eels</string> + <key>eletricity</key> + <string>electricity</string> + <key>elicided</key> + <string>elicited</string> + <key>eligable</key> + <string>eligible</string> + <key>elimentary</key> + <string>elementary</string> + <key>ellected</key> + <string>elected</string> + <key>elphant</key> + <string>elephant</string> + <key>embarass</key> + <string>embarrass</string> + <key>embarassed</key> + <string>embarrassed</string> + <key>embarassing</key> + <string>embarrassing</string> + <key>embarassment</key> + <string>embarrassment</string> + <key>embargos</key> + <string>embargoes</string> + <key>embarras</key> + <string>embarrass</string> + <key>embarrased</key> + <string>embarrassed</string> + <key>embarrasing</key> + <string>embarrassing</string> + <key>embarrasment</key> + <string>embarrassment</string> + <key>embezelled</key> + <string>embezzled</string> + <key>emblamatic</key> + <string>emblematic</string> + <key>eminate</key> + <string>emanate</string> + <key>eminated</key> + <string>emanated</string> + <key>emision</key> + <string>emission</string> + <key>emited</key> + <string>emitted</string> + <key>emiting</key> + <string>emitting</string> + <key>emition</key> + <string>emission</string> + <key>emmediately</key> + <string>immediately</string> + <key>emmigrated</key> + <string>immigrated</string> + <key>emminently</key> + <string>eminently</string> + <key>emmisaries</key> + <string>emissaries</string> + <key>emmisarries</key> + <string>emissaries</string> + <key>emmisarry</key> + <string>emissary</string> + <key>emmisary</key> + <string>emissary</string> + <key>emmision</key> + <string>emission</string> + <key>emmisions</key> + <string>emissions</string> + <key>emmited</key> + <string>emitted</string> + <key>emmiting</key> + <string>emitting</string> + <key>emmitted</key> + <string>emitted</string> + <key>emmitting</key> + <string>emitting</string> + <key>emnity</key> + <string>enmity</string> + <key>emperical</key> + <string>empirical</string> + <key>emphaised</key> + <string>emphasised</string> + <key>emphsis</key> + <string>emphasis</string> + <key>emphysyma</key> + <string>emphysema</string> + <key>emprisoned</key> + <string>imprisoned</string> + <key>enameld</key> + <string>enameled</string> + <key>enchancement</key> + <string>enhancement</string> + <key>encouraing</key> + <string>encouraging</string> + <key>encryptiion</key> + <string>encryption</string> + <key>encylopedia</key> + <string>encyclopedia</string> + <key>endevors</key> + <string>endeavors</string> + <key>endevour</key> + <string>endeavour</string> + <key>endig</key> + <string>ending</string> + <key>endolithes</key> + <string>endoliths</string> + <key>enduce</key> + <string>induce</string> + <key>ened</key> + <string>need</string> + <key>enflamed</key> + <string>inflamed</string> + <key>enforceing</key> + <string>enforcing</string> + <key>engagment</key> + <string>engagement</string> + <key>engeneer</key> + <string>engineer</string> + <key>engeneering</key> + <string>engineering</string> + <key>engieneer</key> + <string>engineer</string> + <key>engieneers</key> + <string>engineers</string> + <key>enlargment</key> + <string>enlargement</string> + <key>enlargments</key> + <string>enlargements</string> + <key>enourmous</key> + <string>enormous</string> + <key>enourmously</key> + <string>enormously</string> + <key>ensconsed</key> + <string>ensconced</string> + <key>entaglements</key> + <string>entanglements</string> + <key>enteratinment</key> + <string>entertainment</string> + <key>enthusiatic</key> + <string>enthusiastic</string> + <key>entitity</key> + <string>entity</string> + <key>entitlied</key> + <string>entitled</string> + <key>entrepeneur</key> + <string>entrepreneur</string> + <key>entrepeneurs</key> + <string>entrepreneurs</string> + <key>enviorment</key> + <string>environment</string> + <key>enviormental</key> + <string>environmental</string> + <key>enviormentally</key> + <string>environmentally</string> + <key>enviorments</key> + <string>environments</string> + <key>enviornment</key> + <string>environment</string> + <key>enviornmental</key> + <string>environmental</string> + <key>enviornmentalist</key> + <string>environmentalist</string> + <key>enviornmentally</key> + <string>environmentally</string> + <key>enviornments</key> + <string>environments</string> + <key>enviroment</key> + <string>environment</string> + <key>enviromental</key> + <string>environmental</string> + <key>enviromentalist</key> + <string>environmentalist</string> + <key>enviromentally</key> + <string>environmentally</string> + <key>enviroments</key> + <string>environments</string> + <key>envolutionary</key> + <string>evolutionary</string> + <key>envrionments</key> + <string>environments</string> + <key>enxt</key> + <string>next</string> + <key>epidsodes</key> + <string>episodes</string> + <key>epsiode</key> + <string>episode</string> + <key>equialent</key> + <string>equivalent</string> + <key>equilibium</key> + <string>equilibrium</string> + <key>equilibrum</key> + <string>equilibrium</string> + <key>equiped</key> + <string>equipped</string> + <key>equippment</key> + <string>equipment</string> + <key>equitorial</key> + <string>equatorial</string> + <key>equivelant</key> + <string>equivalent</string> + <key>equivelent</key> + <string>equivalent</string> + <key>equivilant</key> + <string>equivalent</string> + <key>equivilent</key> + <string>equivalent</string> + <key>equivlalent</key> + <string>equivalent</string> + <key>erally</key> + <string>really</string> + <key>eratic</key> + <string>erratic</string> + <key>eratically</key> + <string>erratically</string> + <key>eraticly</key> + <string>erratically</string> + <key>errupted</key> + <string>erupted</string> + <key>esential</key> + <string>essential</string> + <key>esitmated</key> + <string>estimated</string> + <key>esle</key> + <string>else</string> + <key>especialy</key> + <string>especially</string> + <key>essencial</key> + <string>essential</string> + <key>essense</key> + <string>essence</string> + <key>essentail</key> + <string>essential</string> + <key>essentialy</key> + <string>essentially</string> + <key>essentual</key> + <string>essential</string> + <key>essesital</key> + <string>essential</string> + <key>estabishes</key> + <string>establishes</string> + <key>establising</key> + <string>establishing</string> + <key>ethnocentricm</key> + <string>ethnocentrism</string> + <key>ethose</key> + <string>those</string> + <key>evenhtually</key> + <string>eventually</string> + <key>eventally</key> + <string>eventually</string> + <key>eventhough</key> + <string>even though</string> + <key>eventially</key> + <string>eventually</string> + <key>eventualy</key> + <string>eventually</string> + <key>everthing</key> + <string>everything</string> + <key>everytime</key> + <string>every time</string> + <key>everyting</key> + <string>everything</string> + <key>eveyr</key> + <string>every</string> + <key>evidentally</key> + <string>evidently</string> + <key>exagerate</key> + <string>exaggerate</string> + <key>exagerated</key> + <string>exaggerated</string> + <key>exagerates</key> + <string>exaggerates</string> + <key>exagerating</key> + <string>exaggerating</string> + <key>exagerrate</key> + <string>exaggerate</string> + <key>exagerrated</key> + <string>exaggerated</string> + <key>exagerrates</key> + <string>exaggerates</string> + <key>exagerrating</key> + <string>exaggerating</string> + <key>examinated</key> + <string>examined</string> + <key>exampt</key> + <string>exempt</string> + <key>exapansion</key> + <string>expansion</string> + <key>excact</key> + <string>exact</string> + <key>excange</key> + <string>exchange</string> + <key>excecute</key> + <string>execute</string> + <key>excecuted</key> + <string>executed</string> + <key>excecutes</key> + <string>executes</string> + <key>excecuting</key> + <string>executing</string> + <key>excecution</key> + <string>execution</string> + <key>excedded</key> + <string>exceeded</string> + <key>excelent</key> + <string>excellent</string> + <key>excell</key> + <string>excel</string> + <key>excellance</key> + <string>excellence</string> + <key>excellant</key> + <string>excellent</string> + <key>excells</key> + <string>excels</string> + <key>excercise</key> + <string>exercise</string> + <key>exchanching</key> + <string>exchanging</string> + <key>excisted</key> + <string>existed</string> + <key>exculsivly</key> + <string>exclusively</string> + <key>execising</key> + <string>exercising</string> + <key>exection</key> + <string>execution</string> + <key>exectued</key> + <string>executed</string> + <key>exeedingly</key> + <string>exceedingly</string> + <key>exelent</key> + <string>excellent</string> + <key>exellent</key> + <string>excellent</string> + <key>exemple</key> + <string>example</string> + <key>exept</key> + <string>except</string> + <key>exeptional</key> + <string>exceptional</string> + <key>exerbate</key> + <string>exacerbate</string> + <key>exerbated</key> + <string>exacerbated</string> + <key>exerciese</key> + <string>exercises</string> + <key>exerpt</key> + <string>excerpt</string> + <key>exerpts</key> + <string>excerpts</string> + <key>exersize</key> + <string>exercise</string> + <key>exerternal</key> + <string>external</string> + <key>exhalted</key> + <string>exalted</string> + <key>exhibtion</key> + <string>exhibition</string> + <key>exibition</key> + <string>exhibition</string> + <key>exibitions</key> + <string>exhibitions</string> + <key>exicting</key> + <string>exciting</string> + <key>exinct</key> + <string>extinct</string> + <key>existance</key> + <string>existence</string> + <key>existant</key> + <string>existent</string> + <key>existince</key> + <string>existence</string> + <key>exliled</key> + <string>exiled</string> + <key>exludes</key> + <string>excludes</string> + <key>exmaple</key> + <string>example</string> + <key>exonorate</key> + <string>exonerate</string> + <key>exoskelaton</key> + <string>exoskeleton</string> + <key>expalin</key> + <string>explain</string> + <key>expatriot</key> + <string>expatriate</string> + <key>expeced</key> + <string>expected</string> + <key>expecially</key> + <string>especially</string> + <key>expeditonary</key> + <string>expeditionary</string> + <key>expeiments</key> + <string>experiments</string> + <key>expell</key> + <string>expel</string> + <key>expells</key> + <string>expels</string> + <key>experiance</key> + <string>experience</string> + <key>experianced</key> + <string>experienced</string> + <key>expiditions</key> + <string>expeditions</string> + <key>expierence</key> + <string>experience</string> + <key>explaination</key> + <string>explanation</string> + <key>explaning</key> + <string>explaining</string> + <key>explictly</key> + <string>explicitly</string> + <key>exploititive</key> + <string>exploitative</string> + <key>explotation</key> + <string>exploitation</string> + <key>expropiated</key> + <string>expropriated</string> + <key>expropiation</key> + <string>expropriation</string> + <key>exressed</key> + <string>expressed</string> + <key>extemely</key> + <string>extremely</string> + <key>extention</key> + <string>extension</string> + <key>extentions</key> + <string>extensions</string> + <key>extered</key> + <string>exerted</string> + <key>extermist</key> + <string>extremist</string> + <key>extint</key> + <string>extinct</string> + <key>extradiction</key> + <string>extradition</string> + <key>extraterrestial</key> + <string>extraterrestrial</string> + <key>extraterrestials</key> + <string>extraterrestrials</string> + <key>extravagent</key> + <string>extravagant</string> + <key>extrememly</key> + <string>extremely</string> + <key>extremeophile</key> + <string>extremophile</string> + <key>extremly</key> + <string>extremely</string> + <key>extrordinarily</key> + <string>extraordinarily</string> + <key>extrordinary</key> + <string>extraordinary</string> + <key>eyar</key> + <string>year</string> + <key>eyars</key> + <string>years</string> + <key>eyasr</key> + <string>years</string> + <key>faciliate</key> + <string>facilitate</string> + <key>faciliated</key> + <string>facilitated</string> + <key>faciliates</key> + <string>facilitates</string> + <key>facilites</key> + <string>facilities</string> + <key>facillitate</key> + <string>facilitate</string> + <key>facinated</key> + <string>fascinated</string> + <key>facist</key> + <string>fascist</string> + <key>familes</key> + <string>families</string> + <key>familliar</key> + <string>familiar</string> + <key>famoust</key> + <string>famous</string> + <key>fanatism</key> + <string>fanaticism</string> + <key>fatc</key> + <string>fact</string> + <key>faught</key> + <string>fought</string> + <key>favoutrable</key> + <string>favourable</string> + <key>feasable</key> + <string>feasible</string> + <key>fedreally</key> + <string>federally</string> + <key>feromone</key> + <string>pheromone</string> + <key>fertily</key> + <string>fertility</string> + <key>fianite</key> + <string>finite</string> + <key>fianlly</key> + <string>finally</string> + <key>ficticious</key> + <string>fictitious</string> + <key>fictious</key> + <string>fictitious</string> + <key>fidn</key> + <string>find</string> + <key>fiercly</key> + <string>fiercely</string> + <key>fightings</key> + <string>fighting</string> + <key>filiament</key> + <string>filament</string> + <key>fimilies</key> + <string>families</string> + <key>finacial</key> + <string>financial</string> + <key>finaly</key> + <string>finally</string> + <key>financialy</key> + <string>financially</string> + <key>firends</key> + <string>friends</string> + <key>firts</key> + <string>first</string> + <key>fisionable</key> + <string>fissionable</string> + <key>flamable</key> + <string>flammable</string> + <key>flawess</key> + <string>flawless</string> + <key>fleed</key> + <string>fled</string> + <key>florescent</key> + <string>fluorescent</string> + <key>flourescent</key> + <string>fluorescent</string> + <key>flourine</key> + <string>fluorine</string> + <key>fluorish</key> + <string>flourish</string> + <key>follwoing</key> + <string>following</string> + <key>folowing</key> + <string>following</string> + <key>fomed</key> + <string>formed</string> + <key>fomr</key> + <string>from</string> + <key>fonetic</key> + <string>phonetic</string> + <key>fontrier</key> + <string>fontier</string> + <key>foootball</key> + <string>football</string> + <key>forbad</key> + <string>forbade</string> + <key>forbiden</key> + <string>forbidden</string> + <key>foreward</key> + <string>foreword</string> + <key>forfiet</key> + <string>forfeit</string> + <key>forhead</key> + <string>forehead</string> + <key>foriegn</key> + <string>foreign</string> + <key>formallize</key> + <string>formalize</string> + <key>formallized</key> + <string>formalized</string> + <key>formaly</key> + <string>formally</string> + <key>formelly</key> + <string>formerly</string> + <key>formidible</key> + <string>formidable</string> + <key>formost</key> + <string>foremost</string> + <key>forsaw</key> + <string>foresaw</string> + <key>forseeable</key> + <string>foreseeable</string> + <key>fortelling</key> + <string>foretelling</string> + <key>forunner</key> + <string>forerunner</string> + <key>foucs</key> + <string>focus</string> + <key>foudn</key> + <string>found</string> + <key>fougth</key> + <string>fought</string> + <key>foundaries</key> + <string>foundries</string> + <key>foundary</key> + <string>foundry</string> + <key>fourties</key> + <string>forties</string> + <key>fourty</key> + <string>forty</string> + <key>fouth</key> + <string>fourth</string> + <key>foward</key> + <string>forward</string> + <key>freind</key> + <string>friend</string> + <key>freindly</key> + <string>friendly</string> + <key>frequentily</key> + <string>frequently</string> + <key>frome</key> + <string>from</string> + <key>fromed</key> + <string>formed</string> + <key>froniter</key> + <string>frontier</string> + <key>fucntion</key> + <string>function</string> + <key>fucntioning</key> + <string>functioning</string> + <key>fufill</key> + <string>fulfill</string> + <key>fufilled</key> + <string>fulfilled</string> + <key>fulfiled</key> + <string>fulfilled</string> + <key>fullfill</key> + <string>fulfill</string> + <key>fullfilled</key> + <string>fulfilled</string> + <key>fundametal</key> + <string>fundamental</string> + <key>fundametals</key> + <string>fundamentals</string> + <key>funguses</key> + <string>fungi</string> + <key>funtion</key> + <string>function</string> + <key>furuther</key> + <string>further</string> + <key>futher</key> + <string>further</string> + <key>futhermore</key> + <string>furthermore</string> + <key>galatic</key> + <string>galactic</string> + <key>gallaxies</key> + <string>galaxies</string> + <key>galvinized</key> + <string>galvanized</string> + <key>ganerate</key> + <string>generate</string> + <key>ganes</key> + <string>games</string> + <key>ganster</key> + <string>gangster</string> + <key>garantee</key> + <string>guarantee</string> + <key>garanteed</key> + <string>guaranteed</string> + <key>garantees</key> + <string>guarantees</string> + <key>garnison</key> + <string>garrison</string> + <key>gaurantee</key> + <string>guarantee</string> + <key>gauranteed</key> + <string>guaranteed</string> + <key>gaurantees</key> + <string>guarantees</string> + <key>gaurd</key> + <string>guard</string> + <key>gaurentee</key> + <string>guarantee</string> + <key>gaurenteed</key> + <string>guaranteed</string> + <key>gaurentees</key> + <string>guarantees</string> + <key>geneological</key> + <string>genealogical</string> + <key>geneologies</key> + <string>genealogies</string> + <key>geneology</key> + <string>genealogy</string> + <key>generaly</key> + <string>generally</string> + <key>generatting</key> + <string>generating</string> + <key>genialia</key> + <string>genitalia</string> + <key>geographicial</key> + <string>geographical</string> + <key>geometrician</key> + <string>geometer</string> + <key>geometricians</key> + <string>geometers</string> + <key>gerat</key> + <string>great</string> + <key>glight</key> + <string>flight</string> + <key>gnawwed</key> + <string>gnawed</string> + <key>godess</key> + <string>goddess</string> + <key>godesses</key> + <string>goddesses</string> + <key>gogin</key> + <string>going</string> + <key>goign</key> + <string>going</string> + <key>gonig</key> + <string>going</string> + <key>gouvener</key> + <string>governor</string> + <key>govement</key> + <string>government</string> + <key>govenment</key> + <string>government</string> + <key>govenrment</key> + <string>government</string> + <key>goverance</key> + <string>governance</string> + <key>goverment</key> + <string>government</string> + <key>govermental</key> + <string>governmental</string> + <key>governer</key> + <string>governor</string> + <key>governmnet</key> + <string>government</string> + <key>govorment</key> + <string>government</string> + <key>govormental</key> + <string>governmental</string> + <key>govornment</key> + <string>government</string> + <key>gracefull</key> + <string>graceful</string> + <key>graet</key> + <string>great</string> + <key>grafitti</key> + <string>graffiti</string> + <key>gramatically</key> + <string>grammatically</string> + <key>grammaticaly</key> + <string>grammatically</string> + <key>grammer</key> + <string>grammar</string> + <key>grat</key> + <string>great</string> + <key>gratuitious</key> + <string>gratuitous</string> + <key>greatful</key> + <string>grateful</string> + <key>greatfully</key> + <string>gratefully</string> + <key>greif</key> + <string>grief</string> + <key>gridles</key> + <string>griddles</string> + <key>gropu</key> + <string>group</string> + <key>grwo</key> + <string>grow</string> + <key>guage</key> + <string>gauge</string> + <key>guarentee</key> + <string>guarantee</string> + <key>guarenteed</key> + <string>guaranteed</string> + <key>guarentees</key> + <string>guarantees</string> + <key>guerilla</key> + <string>guerrilla</string> + <key>guerillas</key> + <string>guerrillas</string> + <key>guerrila</key> + <string>guerrilla</string> + <key>guerrilas</key> + <string>guerrillas</string> + <key>guidence</key> + <string>guidance</string> + <key>gunanine</key> + <string>guanine</string> + <key>gurantee</key> + <string>guarantee</string> + <key>guranteed</key> + <string>guaranteed</string> + <key>gurantees</key> + <string>guarantees</string> + <key>guttaral</key> + <string>guttural</string> + <key>gutteral</key> + <string>guttural</string> + <key>habaeus</key> + <string>habeas</string> + <key>habeus</key> + <string>habeas</string> + <key>haemorrage</key> + <string>haemorrhage</string> + <key>haev</key> + <string>have</string> + <key>halp</key> + <string>help</string> + <key>hapen</key> + <string>happen</string> + <key>hapened</key> + <string>happened</string> + <key>hapening</key> + <string>happening</string> + <key>happend</key> + <string>happened</string> + <key>happended</key> + <string>happened</string> + <key>happenned</key> + <string>happened</string> + <key>harased</key> + <string>harassed</string> + <key>harases</key> + <string>harasses</string> + <key>harasment</key> + <string>harassment</string> + <key>harasments</key> + <string>harassments</string> + <key>harassement</key> + <string>harassment</string> + <key>harras</key> + <string>harass</string> + <key>harrased</key> + <string>harassed</string> + <key>harrases</key> + <string>harasses</string> + <key>harrasing</key> + <string>harassing</string> + <key>harrasment</key> + <string>harassment</string> + <key>harrasments</key> + <string>harassments</string> + <key>harrassed</key> + <string>harassed</string> + <key>harrasses</key> + <string>harassed</string> + <key>harrassing</key> + <string>harassing</string> + <key>harrassment</key> + <string>harassment</string> + <key>harrassments</key> + <string>harassments</string> + <key>hasnt</key> + <string>hasn't</string> + <key>haviest</key> + <string>heaviest</string> + <key>headquarer</key> + <string>headquarter</string> + <key>headquater</key> + <string>headquarter</string> + <key>headquatered</key> + <string>headquartered</string> + <key>headquaters</key> + <string>headquarters</string> + <key>healthercare</key> + <string>healthcare</string> + <key>heared</key> + <string>heard</string> + <key>heathy</key> + <string>healthy</string> + <key>heigher</key> + <string>higher</string> + <key>heirarchy</key> + <string>hierarchy</string> + <key>heiroglyphics</key> + <string>hieroglyphics</string> + <key>helment</key> + <string>helmet</string> + <key>helpfull</key> + <string>helpful</string> + <key>helpped</key> + <string>helped</string> + <key>hemmorhage</key> + <string>hemorrhage</string> + <key>herad</key> + <string>heard</string> + <key>heridity</key> + <string>heredity</string> + <key>heroe</key> + <string>hero</string> + <key>heros</key> + <string>heroes</string> + <key>hertiage</key> + <string>heritage</string> + <key>hertzs</key> + <string>hertz</string> + <key>hesistant</key> + <string>hesitant</string> + <key>heterogenous</key> + <string>heterogeneous</string> + <key>hieght</key> + <string>height</string> + <key>hierachical</key> + <string>hierarchical</string> + <key>hierachies</key> + <string>hierarchies</string> + <key>hierachy</key> + <string>hierarchy</string> + <key>hierarcical</key> + <string>hierarchical</string> + <key>hierarcy</key> + <string>hierarchy</string> + <key>hieroglph</key> + <string>hieroglyph</string> + <key>hieroglphs</key> + <string>hieroglyphs</string> + <key>higer</key> + <string>higher</string> + <key>higest</key> + <string>highest</string> + <key>higway</key> + <string>highway</string> + <key>hillarious</key> + <string>hilarious</string> + <key>himselv</key> + <string>himself</string> + <key>hinderance</key> + <string>hindrance</string> + <key>hinderence</key> + <string>hindrance</string> + <key>hindrence</key> + <string>hindrance</string> + <key>hipopotamus</key> + <string>hippopotamus</string> + <key>hismelf</key> + <string>himself</string> + <key>histocompatability</key> + <string>histocompatibility</string> + <key>historicians</key> + <string>historians</string> + <key>hitsingles</key> + <string>hit singles</string> + <key>holliday</key> + <string>holiday</string> + <key>homestate</key> + <string>home state</string> + <key>homogeneize</key> + <string>homogenize</string> + <key>homogeneized</key> + <string>homogenized</string> + <key>honory</key> + <string>honorary</string> + <key>horrifing</key> + <string>horrifying</string> + <key>hosited</key> + <string>hoisted</string> + <key>hospitible</key> + <string>hospitable</string> + <key>hounour</key> + <string>honour</string> + <key>housr</key> + <string>hours</string> + <key>howver</key> + <string>however</string> + <key>hsitorians</key> + <string>historians</string> + <key>hstory</key> + <string>history</string> + <key>hten</key> + <string>then</string> + <key>htere</key> + <string>there</string> + <key>htey</key> + <string>they</string> + <key>htikn</key> + <string>think</string> + <key>hting</key> + <string>thing</string> + <key>htink</key> + <string>think</string> + <key>htis</key> + <string>this</string> + <key>humer</key> + <string>humor</string> + <key>humerous</key> + <string>humorous</string> + <key>huminoid</key> + <string>humanoid</string> + <key>humoural</key> + <string>humoral</string> + <key>humurous</key> + <string>humorous</string> + <key>husban</key> + <string>husband</string> + <key>hvae</key> + <string>have</string> + <key>hvaing</key> + <string>having</string> + <key>hvea</key> + <string>have</string> + <key>hwihc</key> + <string>which</string> + <key>hwile</key> + <string>while</string> + <key>hwole</key> + <string>whole</string> + <key>hydogen</key> + <string>hydrogen</string> + <key>hydropile</key> + <string>hydrophile</string> + <key>hydropilic</key> + <string>hydrophilic</string> + <key>hydropobe</key> + <string>hydrophobe</string> + <key>hydropobic</key> + <string>hydrophobic</string> + <key>hygeine</key> + <string>hygiene</string> + <key>hypocracy</key> + <string>hypocrisy</string> + <key>hypocrasy</key> + <string>hypocrisy</string> + <key>hypocricy</key> + <string>hypocrisy</string> + <key>hypocrit</key> + <string>hypocrite</string> + <key>hypocrits</key> + <string>hypocrites</string> + <key>i</key> + <string>I</string> + <key>iconclastic</key> + <string>iconoclastic</string> + <key>idaeidae</key> + <string>idea</string> + <key>idaes</key> + <string>ideas</string> + <key>idealogies</key> + <string>ideologies</string> + <key>idealogy</key> + <string>ideology</string> + <key>identicial</key> + <string>identical</string> + <key>identifers</key> + <string>identifiers</string> + <key>ideosyncratic</key> + <string>idiosyncratic</string> + <key>idesa</key> + <string>ideas</string> + <key>idiosyncracy</key> + <string>idiosyncrasy</string> + <key>illegimacy</key> + <string>illegitimacy</string> + <key>illegitmate</key> + <string>illegitimate</string> + <key>illess</key> + <string>illness</string> + <key>illiegal</key> + <string>illegal</string> + <key>illution</key> + <string>illusion</string> + <key>ilness</key> + <string>illness</string> + <key>ilogical</key> + <string>illogical</string> + <key>imagenary</key> + <string>imaginary</string> + <key>imagin</key> + <string>imagine</string> + <key>imaginery</key> + <string>imaginary</string> + <key>imcomplete</key> + <string>incomplete</string> + <key>imediately</key> + <string>immediately</string> + <key>imense</key> + <string>immense</string> + <key>immediatley</key> + <string>immediately</string> + <key>immediatly</key> + <string>immediately</string> + <key>immidately</key> + <string>immediately</string> + <key>immidiately</key> + <string>immediately</string> + <key>immitate</key> + <string>imitate</string> + <key>immitated</key> + <string>imitated</string> + <key>immitating</key> + <string>imitating</string> + <key>immitator</key> + <string>imitator</string> + <key>immunosupressant</key> + <string>immunosuppressant</string> + <key>impecabbly</key> + <string>impeccably</string> + <key>impedence</key> + <string>impedance</string> + <key>implamenting</key> + <string>implementing</string> + <key>impliment</key> + <string>implement</string> + <key>implimented</key> + <string>implemented</string> + <key>imploys</key> + <string>employs</string> + <key>importamt</key> + <string>important</string> + <key>imprioned</key> + <string>imprisoned</string> + <key>imprisonned</key> + <string>imprisoned</string> + <key>improvision</key> + <string>improvisation</string> + <key>improvments</key> + <string>improvements</string> + <key>inablility</key> + <string>inability</string> + <key>inaccessable</key> + <string>inaccessible</string> + <key>inadiquate</key> + <string>inadequate</string> + <key>inadquate</key> + <string>inadequate</string> + <key>inadvertant</key> + <string>inadvertent</string> + <key>inadvertantly</key> + <string>inadvertently</string> + <key>inagurated</key> + <string>inaugurated</string> + <key>inaguration</key> + <string>inauguration</string> + <key>inappropiate</key> + <string>inappropriate</string> + <key>inaugures</key> + <string>inaugurates</string> + <key>inbalance</key> + <string>imbalance</string> + <key>inbalanced</key> + <string>imbalanced</string> + <key>inbetween</key> + <string>between</string> + <key>incarcirated</key> + <string>incarcerated</string> + <key>incidentially</key> + <string>incidentally</string> + <key>incidently</key> + <string>incidentally</string> + <key>inclreased</key> + <string>increased</string> + <key>includ</key> + <string>include</string> + <key>includng</key> + <string>including</string> + <key>incompatabilities</key> + <string>incompatibilities</string> + <key>incompatability</key> + <string>incompatibility</string> + <key>incompatable</key> + <string>incompatible</string> + <key>incompatablities</key> + <string>incompatibilities</string> + <key>incompatablity</key> + <string>incompatibility</string> + <key>incompatiblities</key> + <string>incompatibilities</string> + <key>incompatiblity</key> + <string>incompatibility</string> + <key>incompetance</key> + <string>incompetence</string> + <key>incompetant</key> + <string>incompetent</string> + <key>incomptable</key> + <string>incompatible</string> + <key>incomptetent</key> + <string>incompetent</string> + <key>inconsistant</key> + <string>inconsistent</string> + <key>incoroporated</key> + <string>incorporated</string> + <key>incorperation</key> + <string>incorporation</string> + <key>incorportaed</key> + <string>incorporated</string> + <key>incorprates</key> + <string>incorporates</string> + <key>incorruptable</key> + <string>incorruptible</string> + <key>incramentally</key> + <string>incrementally</string> + <key>increadible</key> + <string>incredible</string> + <key>incredable</key> + <string>incredible</string> + <key>inctroduce</key> + <string>introduce</string> + <key>inctroduced</key> + <string>introduced</string> + <key>incuding</key> + <string>including</string> + <key>incunabla</key> + <string>incunabula</string> + <key>indefinately</key> + <string>indefinitely</string> + <key>indefineable</key> + <string>undefinable</string> + <key>indefinitly</key> + <string>indefinitely</string> + <key>indentical</key> + <string>identical</string> + <key>indepedantly</key> + <string>independently</string> + <key>indepedence</key> + <string>independence</string> + <key>independance</key> + <string>independence</string> + <key>independant</key> + <string>independent</string> + <key>independantly</key> + <string>independently</string> + <key>independece</key> + <string>independence</string> + <key>independendet</key> + <string>independent</string> + <key>indespensable</key> + <string>indispensable</string> + <key>indespensible</key> + <string>indispensable</string> + <key>indictement</key> + <string>indictment</string> + <key>indigineous</key> + <string>indigenous</string> + <key>indipendence</key> + <string>independence</string> + <key>indipendent</key> + <string>independent</string> + <key>indipendently</key> + <string>independently</string> + <key>indispensible</key> + <string>indispensable</string> + <key>indisputible</key> + <string>indisputable</string> + <key>indisputibly</key> + <string>indisputably</string> + <key>indite</key> + <string>indict</string> + <key>individualy</key> + <string>individually</string> + <key>indpendent</key> + <string>independent</string> + <key>indpendently</key> + <string>independently</string> + <key>indulgue</key> + <string>indulge</string> + <key>indutrial</key> + <string>industrial</string> + <key>indviduals</key> + <string>individuals</string> + <key>inefficienty</key> + <string>inefficiently</string> + <key>inevatible</key> + <string>inevitable</string> + <key>inevitible</key> + <string>inevitable</string> + <key>inevititably</key> + <string>inevitably</string> + <key>infalability</key> + <string>infallibility</string> + <key>infallable</key> + <string>infallible</string> + <key>infectuous</key> + <string>infectious</string> + <key>infered</key> + <string>inferred</string> + <key>infilitrate</key> + <string>infiltrate</string> + <key>infilitrated</key> + <string>infiltrated</string> + <key>infilitration</key> + <string>infiltration</string> + <key>infinit</key> + <string>infinite</string> + <key>inflamation</key> + <string>inflammation</string> + <key>influencial</key> + <string>influential</string> + <key>influented</key> + <string>influenced</string> + <key>infomation</key> + <string>information</string> + <key>informtion</key> + <string>information</string> + <key>infrantryman</key> + <string>infantryman</string> + <key>infrigement</key> + <string>infringement</string> + <key>ingenius</key> + <string>ingenious</string> + <key>ingreediants</key> + <string>ingredients</string> + <key>inhabitans</key> + <string>inhabitants</string> + <key>inherantly</key> + <string>inherently</string> + <key>inheritence</key> + <string>inheritance</string> + <key>inital</key> + <string>initial</string> + <key>initally</key> + <string>initially</string> + <key>initation</key> + <string>initiation</string> + <key>initiaitive</key> + <string>initiative</string> + <key>inlcuding</key> + <string>including</string> + <key>inmigrant</key> + <string>immigrant</string> + <key>inmigrants</key> + <string>immigrants</string> + <key>innoculated</key> + <string>inoculated</string> + <key>inocence</key> + <string>innocence</string> + <key>inofficial</key> + <string>unofficial</string> + <key>inot</key> + <string>into</string> + <key>inpeach</key> + <string>impeach</string> + <key>inpolite</key> + <string>impolite</string> + <key>inprisonment</key> + <string>imprisonment</string> + <key>inproving</key> + <string>improving</string> + <key>insectiverous</key> + <string>insectivorous</string> + <key>insensative</key> + <string>insensitive</string> + <key>inseperable</key> + <string>inseparable</string> + <key>insistance</key> + <string>insistence</string> + <key>insitution</key> + <string>institution</string> + <key>insitutions</key> + <string>institutions</string> + <key>inspite</key> + <string>in spite</string> + <key>instade</key> + <string>instead</string> + <key>instatance</key> + <string>instance</string> + <key>institue</key> + <string>institute</string> + <key>instuction</key> + <string>instruction</string> + <key>instuments</key> + <string>instruments</string> + <key>instutionalized</key> + <string>institutionalized</string> + <key>instutions</key> + <string>intuitions</string> + <key>insurence</key> + <string>insurance</string> + <key>intelectual</key> + <string>intellectual</string> + <key>inteligence</key> + <string>intelligence</string> + <key>inteligent</key> + <string>intelligent</string> + <key>intenational</key> + <string>international</string> + <key>intented</key> + <string>intended</string> + <key>intepretation</key> + <string>interpretation</string> + <key>intepretator</key> + <string>interpretor</string> + <key>interational</key> + <string>international</string> + <key>interbread</key> + <string>interbreed</string> + <key>interchangable</key> + <string>interchangeable</string> + <key>interchangably</key> + <string>interchangeably</string> + <key>intercontinetal</key> + <string>intercontinental</string> + <key>intered</key> + <string>interred</string> + <key>interelated</key> + <string>interrelated</string> + <key>interferance</key> + <string>interference</string> + <key>interfereing</key> + <string>interfering</string> + <key>intergrated</key> + <string>integrated</string> + <key>intergration</key> + <string>integration</string> + <key>interm</key> + <string>interim</string> + <key>internation</key> + <string>international</string> + <key>interpet</key> + <string>interpret</string> + <key>interrim</key> + <string>interim</string> + <key>interrugum</key> + <string>interregnum</string> + <key>intertaining</key> + <string>entertaining</string> + <key>interupt</key> + <string>interrupt</string> + <key>intervines</key> + <string>intervenes</string> + <key>intevene</key> + <string>intervene</string> + <key>intial</key> + <string>initial</string> + <key>intially</key> + <string>initially</string> + <key>intrduced</key> + <string>introduced</string> + <key>intrest</key> + <string>interest</string> + <key>introdued</key> + <string>introduced</string> + <key>intruduced</key> + <string>introduced</string> + <key>intrument</key> + <string>instrument</string> + <key>intrumental</key> + <string>instrumental</string> + <key>intruments</key> + <string>instruments</string> + <key>intrusted</key> + <string>entrusted</string> + <key>intutive</key> + <string>intuitive</string> + <key>intutively</key> + <string>intuitively</string> + <key>inudstry</key> + <string>industry</string> + <key>inventer</key> + <string>inventor</string> + <key>invertibrates</key> + <string>invertebrates</string> + <key>investingate</key> + <string>investigate</string> + <key>involvment</key> + <string>involvement</string> + <key>irelevent</key> + <string>irrelevant</string> + <key>iresistable</key> + <string>irresistible</string> + <key>iresistably</key> + <string>irresistibly</string> + <key>iresistible</key> + <string>irresistible</string> + <key>iresistibly</key> + <string>irresistibly</string> + <key>iritable</key> + <string>irritable</string> + <key>iritated</key> + <string>irritated</string> + <key>ironicly</key> + <string>ironically</string> + <key>irregardless</key> + <string>regardless</string> + <key>irrelevent</key> + <string>irrelevant</string> + <key>irreplacable</key> + <string>irreplaceable</string> + <key>irresistable</key> + <string>irresistible</string> + <key>irresistably</key> + <string>irresistibly</string> + <key>isnt</key> + <string>isn't</string> + <key>issueing</key> + <string>issuing</string> + <key>itnroduced</key> + <string>introduced</string> + <key>iunior</key> + <string>junior</string> + <key>iwll</key> + <string>will</string> + <key>iwth</key> + <string>with</string> + <key>jaques</key> + <string>jacques</string> + <key>jeapardy</key> + <string>jeopardy</string> + <key>jewllery</key> + <string>jewellery</string> + <key>jouney</key> + <string>journey</string> + <key>journied</key> + <string>journeyed</string> + <key>journies</key> + <string>journeys</string> + <key>jstu</key> + <string>just</string> + <key>jsut</key> + <string>just</string> + <key>judical</key> + <string>judicial</string> + <key>judisuary</key> + <string>judiciary</string> + <key>juducial</key> + <string>judicial</string> + <key>juristiction</key> + <string>jurisdiction</string> + <key>juristictions</key> + <string>jurisdictions</string> + <key>kindergarden</key> + <string>kindergarten</string> + <key>klenex</key> + <string>kleenex</string> + <key>knifes</key> + <string>knives</string> + <key>knive</key> + <string>knife</string> + <key>knowlege</key> + <string>knowledge</string> + <key>knowlegeable</key> + <string>knowledgeable</string> + <key>knwo</key> + <string>know</string> + <key>knwos</key> + <string>knows</string> + <key>konw</key> + <string>know</string> + <key>konws</key> + <string>knows</string> + <key>kwno</key> + <string>know</string> + <key>labatory</key> + <string>laboratory</string> + <key>labratory</key> + <string>laboratory</string> + <key>laguage</key> + <string>language</string> + <key>laguages</key> + <string>languages</string> + <key>larg</key> + <string>large</string> + <key>largst</key> + <string>largest</string> + <key>larrry</key> + <string>larry</string> + <key>lastr</key> + <string>last</string> + <key>lattitude</key> + <string>latitude</string> + <key>launhed</key> + <string>launched</string> + <key>lavae</key> + <string>larvae</string> + <key>layed</key> + <string>laid</string> + <key>lazyness</key> + <string>laziness</string> + <key>leage</key> + <string>league</string> + <key>leanr</key> + <string>learn</string> + <key>leathal</key> + <string>lethal</string> + <key>lefted</key> + <string>left</string> + <key>legitamate</key> + <string>legitimate</string> + <key>legitmate</key> + <string>legitimate</string> + <key>leibnitz</key> + <string>leibniz</string> + <key>lenght</key> + <string>length</string> + <key>leran</key> + <string>learn</string> + <key>lerans</key> + <string>learns</string> + <key>leutenant</key> + <string>lieutenant</string> + <key>levetate</key> + <string>levitate</string> + <key>levetated</key> + <string>levitated</string> + <key>levetates</key> + <string>levitates</string> + <key>levetating</key> + <string>levitating</string> + <key>levle</key> + <string>level</string> + <key>liasion</key> + <string>liaison</string> + <key>liason</key> + <string>liaison</string> + <key>liasons</key> + <string>liaisons</string> + <key>libary</key> + <string>library</string> + <key>libell</key> + <string>libel</string> + <key>libguistic</key> + <string>linguistic</string> + <key>libguistics</key> + <string>linguistics</string> + <key>libitarianisn</key> + <string>libertarianism</string> + <key>lieing</key> + <string>lying</string> + <key>liek</key> + <string>like</string> + <key>liekd</key> + <string>liked</string> + <key>liesure</key> + <string>leisure</string> + <key>lieuenant</key> + <string>lieutenant</string> + <key>lieved</key> + <string>lived</string> + <key>liftime</key> + <string>lifetime</string> + <key>lightyear</key> + <string>light year</string> + <key>lightyears</key> + <string>light years</string> + <key>likelyhood</key> + <string>likelihood</string> + <key>linnaena</key> + <string>linnaean</string> + <key>lippizaner</key> + <string>lipizzaner</string> + <key>liquify</key> + <string>liquefy</string> + <key>liscense</key> + <string>license</string> + <key>lisence</key> + <string>license</string> + <key>lisense</key> + <string>license</string> + <key>listners</key> + <string>listeners</string> + <key>litature</key> + <string>literature</string> + <key>literaly</key> + <string>literally</string> + <key>literture</key> + <string>literature</string> + <key>littel</key> + <string>little</string> + <key>litterally</key> + <string>literally</string> + <key>liuke</key> + <string>like</string> + <key>livley</key> + <string>lively</string> + <key>lmits</key> + <string>limits</string> + <key>loev</key> + <string>love</string> + <key>lonelyness</key> + <string>loneliness</string> + <key>longitudonal</key> + <string>longitudinal</string> + <key>lonley</key> + <string>lonely</string> + <key>lonly</key> + <string>lonely</string> + <key>loosing</key> + <string>losing</string> + <key>lotharingen</key> + <string>lothringen</string> + <key>lsat</key> + <string>last</string> + <key>lukid</key> + <string>likud</string> + <key>lveo</key> + <string>love</string> + <key>lvoe</key> + <string>love</string> + <key>maching</key> + <string>machine</string> + <key>mackeral</key> + <string>mackerel</string> + <key>magasine</key> + <string>magazine</string> + <key>magincian</key> + <string>magician</string> + <key>magnificient</key> + <string>magnificent</string> + <key>magolia</key> + <string>magnolia</string> + <key>mailny</key> + <string>mainly</string> + <key>maintainance</key> + <string>maintenance</string> + <key>maintainence</key> + <string>maintenance</string> + <key>maintance</key> + <string>maintenance</string> + <key>maintenence</key> + <string>maintenance</string> + <key>maintinaing</key> + <string>maintaining</string> + <key>maintioned</key> + <string>mentioned</string> + <key>majoroty</key> + <string>majority</string> + <key>maked</key> + <string>marked</string> + <key>makse</key> + <string>makes</string> + <key>maltesian</key> + <string>Maltese</string> + <key>mamal</key> + <string>mammal</string> + <key>mamalian</key> + <string>mammalian</string> + <key>managable</key> + <string>manageable</string> + <key>managment</key> + <string>management</string> + <key>maneouvre</key> + <string>manoeuvre</string> + <key>maneouvred</key> + <string>manoeuvred</string> + <key>maneouvres</key> + <string>manoeuvres</string> + <key>maneouvring</key> + <string>manoeuvring</string> + <key>manisfestations</key> + <string>manifestations</string> + <key>manoeuverability</key> + <string>maneuverability</string> + <key>manouver</key> + <string>maneuver</string> + <key>manouverability</key> + <string>maneuverability</string> + <key>manouverable</key> + <string>maneuverable</string> + <key>manouvers</key> + <string>maneuvers</string> + <key>mantained</key> + <string>maintained</string> + <key>manuever</key> + <string>maneuver</string> + <key>manuevers</key> + <string>maneuvers</string> + <key>manufacturedd</key> + <string>manufactured</string> + <key>manufature</key> + <string>manufacture</string> + <key>manufatured</key> + <string>manufactured</string> + <key>manufaturing</key> + <string>manufacturing</string> + <key>manuver</key> + <string>maneuver</string> + <key>mariage</key> + <string>marriage</string> + <key>marjority</key> + <string>majority</string> + <key>markes</key> + <string>marks</string> + <key>marketting</key> + <string>marketing</string> + <key>marmelade</key> + <string>marmalade</string> + <key>marrage</key> + <string>marriage</string> + <key>marraige</key> + <string>marriage</string> + <key>marrtyred</key> + <string>martyred</string> + <key>marryied</key> + <string>married</string> + <key>massmedia</key> + <string>mass media</string> + <key>masterbation</key> + <string>masturbation</string> + <key>mataphysical</key> + <string>metaphysical</string> + <key>materalists</key> + <string>materialist</string> + <key>mathamatics</key> + <string>mathematics</string> + <key>mathematican</key> + <string>mathematician</string> + <key>mathematicas</key> + <string>mathematics</string> + <key>matheticians</key> + <string>mathematicians</string> + <key>mathmatically</key> + <string>mathematically</string> + <key>mathmatician</key> + <string>mathematician</string> + <key>mathmaticians</key> + <string>mathematicians</string> + <key>mccarthyst</key> + <string>mccarthyist</string> + <key>mchanics</key> + <string>mechanics</string> + <key>meaninng</key> + <string>meaning</string> + <key>mear</key> + <string>wear</string> + <key>mechandise</key> + <string>merchandise</string> + <key>medacine</key> + <string>medicine</string> + <key>medeival</key> + <string>medieval</string> + <key>medevial</key> + <string>medieval</string> + <key>mediciney</key> + <string>mediciny</string> + <key>medievel</key> + <string>medieval</string> + <key>mediterainnean</key> + <string>mediterranean</string> + <key>meerkrat</key> + <string>meerkat</string> + <key>melieux</key> + <string>milieux</string> + <key>membranaphone</key> + <string>membranophone</string> + <key>memeber</key> + <string>member</string> + <key>menally</key> + <string>mentally</string> + <key>meranda</key> + <string>Miranda</string> + <key>mercentile</key> + <string>mercantile</string> + <key>messanger</key> + <string>messenger</string> + <key>messenging</key> + <string>messaging</string> + <key>metalic</key> + <string>metallic</string> + <key>metalurgic</key> + <string>metallurgic</string> + <key>metalurgical</key> + <string>metallurgical</string> + <key>metalurgy</key> + <string>metallurgy</string> + <key>metamorphysis</key> + <string>metamorphosis</string> + <key>metaphoricial</key> + <string>metaphorical</string> + <key>meterologist</key> + <string>meteorologist</string> + <key>meterology</key> + <string>meteorology</string> + <key>methaphor</key> + <string>metaphor</string> + <key>methaphors</key> + <string>metaphors</string> + <key>micoscopy</key> + <string>microscopy</string> + <key>midwifes</key> + <string>midwives</string> + <key>mileau</key> + <string>milieu</string> + <key>milennia</key> + <string>millennia</string> + <key>milennium</key> + <string>millennium</string> + <key>mileu</key> + <string>milieu</string> + <key>miliary</key> + <string>military</string> + <key>milion</key> + <string>million</string> + <key>miliraty</key> + <string>military</string> + <key>millenia</key> + <string>millennia</string> + <key>millenial</key> + <string>millennial</string> + <key>millenialism</key> + <string>millennialism</string> + <key>millenium</key> + <string>millennium</string> + <key>millepede</key> + <string>millipede</string> + <key>millioniare</key> + <string>millionaire</string> + <key>millitary</key> + <string>military</string> + <key>millon</key> + <string>million</string> + <key>miltary</key> + <string>military</string> + <key>minature</key> + <string>miniature</string> + <key>minerial</key> + <string>mineral</string> + <key>miniscule</key> + <string>minuscule</string> + <key>ministery</key> + <string>ministry</string> + <key>minstries</key> + <string>ministries</string> + <key>minstry</key> + <string>ministry</string> + <key>minumum</key> + <string>minimum</string> + <key>mirrorred</key> + <string>mirrored</string> + <key>miscelaneous</key> + <string>miscellaneous</string> + <key>miscellanious</key> + <string>miscellaneous</string> + <key>miscellanous</key> + <string>miscellaneous</string> + <key>mischeivous</key> + <string>mischievous</string> + <key>mischevious</key> + <string>mischievous</string> + <key>mischievious</key> + <string>mischievous</string> + <key>misdameanor</key> + <string>misdemeanor</string> + <key>misdameanors</key> + <string>misdemeanors</string> + <key>misdemenor</key> + <string>misdemeanor</string> + <key>misdemenors</key> + <string>misdemeanors</string> + <key>misfourtunes</key> + <string>misfortunes</string> + <key>misile</key> + <string>missile</string> + <key>mispell</key> + <string>misspell</string> + <key>mispelled</key> + <string>misspelled</string> + <key>mispelling</key> + <string>misspelling</string> + <key>missen</key> + <string>mizzen</string> + <key>missle</key> + <string>missile</string> + <key>missonary</key> + <string>missionary</string> + <key>misterious</key> + <string>mysterious</string> + <key>mistery</key> + <string>mystery</string> + <key>misteryous</key> + <string>mysterious</string> + <key>mkae</key> + <string>make</string> + <key>mkaes</key> + <string>makes</string> + <key>mkaing</key> + <string>making</string> + <key>mkea</key> + <string>make</string> + <key>moderm</key> + <string>modem</string> + <key>modle</key> + <string>model</string> + <key>moent</key> + <string>moment</string> + <key>moeny</key> + <string>money</string> + <key>mohammedans</key> + <string>muslims</string> + <key>moil</key> + <string>soil</string> + <key>moleclues</key> + <string>molecules</string> + <key>momento</key> + <string>memento</string> + <key>monestaries</key> + <string>monasteries</string> + <key>monestary</key> + <string>monastery</string> + <key>monickers</key> + <string>monikers</string> + <key>monolite</key> + <string>monolithic</string> + <key>montains</key> + <string>mountains</string> + <key>montanous</key> + <string>mountainous</string> + <key>monts</key> + <string>months</string> + <key>montypic</key> + <string>monotypic</string> + <key>moreso</key> + <string>more so</string> + <key>morgage</key> + <string>mortgage</string> + <key>morroccan</key> + <string>moroccan</string> + <key>morrocco</key> + <string>morocco</string> + <key>morroco</key> + <string>morocco</string> + <key>mortage</key> + <string>mortgage</string> + <key>mosture</key> + <string>moisture</string> + <key>motiviated</key> + <string>motivated</string> + <key>mounth</key> + <string>month</string> + <key>movei</key> + <string>movie</string> + <key>movment</key> + <string>movement</string> + <key>mroe</key> + <string>more</string> + <key>mucuous</key> + <string>mucous</string> + <key>muder</key> + <string>murder</string> + <key>mudering</key> + <string>murdering</string> + <key>muhammadan</key> + <string>muslim</string> + <key>multicultralism</key> + <string>multiculturalism</string> + <key>multipled</key> + <string>multiplied</string> + <key>multiplers</key> + <string>multipliers</string> + <key>munbers</key> + <string>numbers</string> + <key>muncipalities</key> + <string>municipalities</string> + <key>muncipality</key> + <string>municipality</string> + <key>munnicipality</key> + <string>municipality</string> + <key>muscels</key> + <string>muscles</string> + <key>muscial</key> + <string>musical</string> + <key>muscician</key> + <string>musician</string> + <key>muscicians</key> + <string>musicians</string> + <key>mutiliated</key> + <string>mutilated</string> + <key>myraid</key> + <string>myriad</string> + <key>mysef</key> + <string>myself</string> + <key>mysogynist</key> + <string>misogynist</string> + <key>mysogyny</key> + <string>misogyny</string> + <key>mysterous</key> + <string>mysterious</string> + <key>naieve</key> + <string>naive</string> + <key>naturaly</key> + <string>naturally</string> + <key>naturely</key> + <string>naturally</string> + <key>naturual</key> + <string>natural</string> + <key>naturually</key> + <string>naturally</string> + <key>neccesarily</key> + <string>necessarily</string> + <key>neccesary</key> + <string>necessary</string> + <key>neccessarily</key> + <string>necessarily</string> + <key>neccessary</key> + <string>necessary</string> + <key>neccessities</key> + <string>necessities</string> + <key>necesarily</key> + <string>necessarily</string> + <key>necesary</key> + <string>necessary</string> + <key>necessiate</key> + <string>necessitate</string> + <key>neglible</key> + <string>negligible</string> + <key>negligable</key> + <string>negligible</string> + <key>negociate</key> + <string>negotiate</string> + <key>negociation</key> + <string>negotiation</string> + <key>negociations</key> + <string>negotiations</string> + <key>negotation</key> + <string>negotiation</string> + <key>neice</key> + <string>niece</string> + <key>neigborhood</key> + <string>neighborhood</string> + <key>neigbour</key> + <string>neighbour</string> + <key>neigbourhood</key> + <string>neighbourhood</string> + <key>neolitic</key> + <string>neolithic</string> + <key>nessasarily</key> + <string>necessarily</string> + <key>nessecary</key> + <string>necessary</string> + <key>nestin</key> + <string>nesting</string> + <key>neverthless</key> + <string>nevertheless</string> + <key>newletters</key> + <string>newsletters</string> + <key>nickle</key> + <string>nickel</string> + <key>nightfa;;</key> + <string>nightfall</string> + <key>nightime</key> + <string>nighttime</string> + <key>nineth</key> + <string>ninth</string> + <key>ninteenth</key> + <string>nineteenth</string> + <key>ninties</key> + <string>1990s</string> + <key>ninty</key> + <string>ninety</string> + <key>nkow</key> + <string>know</string> + <key>nkwo</key> + <string>know</string> + <key>nmae</key> + <string>name</string> + <key>noncombatents</key> + <string>noncombatants</string> + <key>nonsence</key> + <string>nonsense</string> + <key>nontheless</key> + <string>nonetheless</string> + <key>noone</key> + <string>no one</string> + <key>norhern</key> + <string>northern</string> + <key>northen</key> + <string>northern</string> + <key>northereastern</key> + <string>northeastern</string> + <key>notabley</key> + <string>notably</string> + <key>noteable</key> + <string>notable</string> + <key>noteably</key> + <string>notably</string> + <key>noteriety</key> + <string>notoriety</string> + <key>noth</key> + <string>north</string> + <key>nothern</key> + <string>northern</string> + <key>noticable</key> + <string>noticeable</string> + <key>noticably</key> + <string>noticeably</string> + <key>noticeing</key> + <string>noticing</string> + <key>noticible</key> + <string>noticeable</string> + <key>notwhithstanding</key> + <string>notwithstanding</string> + <key>noveau</key> + <string>nouveau</string> + <key>nowdays</key> + <string>nowadays</string> + <key>nowe</key> + <string>now</string> + <key>nto</key> + <string>not</string> + <key>nucular</key> + <string>nuclear</string> + <key>nuculear</key> + <string>nuclear</string> + <key>nuisanse</key> + <string>nuisance</string> + <key>numberous</key> + <string>numerous</string> + <key>nusance</key> + <string>nuisance</string> + <key>nutritent</key> + <string>nutrient</string> + <key>nutritents</key> + <string>nutrients</string> + <key>nuturing</key> + <string>nurturing</string> + <key>obediance</key> + <string>obedience</string> + <key>obediant</key> + <string>obedient</string> + <key>obession</key> + <string>obsession</string> + <key>obssessed</key> + <string>obsessed</string> + <key>obstacal</key> + <string>obstacle</string> + <key>obstancles</key> + <string>obstacles</string> + <key>obstruced</key> + <string>obstructed</string> + <key>ocasion</key> + <string>occasion</string> + <key>ocasional</key> + <string>occasional</string> + <key>ocasionally</key> + <string>occasionally</string> + <key>ocasionaly</key> + <string>occasionally</string> + <key>ocasioned</key> + <string>occasioned</string> + <key>ocasions</key> + <string>occasions</string> + <key>ocassion</key> + <string>occasion</string> + <key>ocassional</key> + <string>occasional</string> + <key>ocassionally</key> + <string>occasionally</string> + <key>ocassionaly</key> + <string>occasionally</string> + <key>ocassioned</key> + <string>occasioned</string> + <key>ocassions</key> + <string>occasions</string> + <key>occaison</key> + <string>occasion</string> + <key>occassion</key> + <string>occasion</string> + <key>occassional</key> + <string>occasional</string> + <key>occassionally</key> + <string>occasionally</string> + <key>occassionaly</key> + <string>occasionally</string> + <key>occassioned</key> + <string>occasioned</string> + <key>occassions</key> + <string>occasions</string> + <key>occationally</key> + <string>occasionally</string> + <key>occour</key> + <string>occur</string> + <key>occurance</key> + <string>occurrence</string> + <key>occurances</key> + <string>occurrences</string> + <key>occured</key> + <string>occurred</string> + <key>occurence</key> + <string>occurrence</string> + <key>occurences</key> + <string>occurrences</string> + <key>occuring</key> + <string>occurring</string> + <key>occurr</key> + <string>occur</string> + <key>occurrance</key> + <string>occurrence</string> + <key>occurrances</key> + <string>occurrences</string> + <key>octohedra</key> + <string>octahedra</string> + <key>octohedral</key> + <string>octahedral</string> + <key>octohedron</key> + <string>octahedron</string> + <key>ocuntries</key> + <string>countries</string> + <key>ocuntry</key> + <string>country</string> + <key>ocurr</key> + <string>occur</string> + <key>ocurrance</key> + <string>occurrence</string> + <key>ocurred</key> + <string>occurred</string> + <key>ocurrence</key> + <string>occurrence</string> + <key>offcers</key> + <string>officers</string> + <key>offcially</key> + <string>officially</string> + <key>offereings</key> + <string>offerings</string> + <key>offical</key> + <string>official</string> + <key>offically</key> + <string>officially</string> + <key>officals</key> + <string>officials</string> + <key>officaly</key> + <string>officially</string> + <key>officialy</key> + <string>officially</string> + <key>offred</key> + <string>offered</string> + <key>oftenly</key> + <string>often</string> + <key>oging</key> + <string>going</string> + <key>omision</key> + <string>omission</string> + <key>omited</key> + <string>omitted</string> + <key>omiting</key> + <string>omitting</string> + <key>omlette</key> + <string>omelette</string> + <key>ommision</key> + <string>omission</string> + <key>ommited</key> + <string>omitted</string> + <key>ommiting</key> + <string>omitting</string> + <key>ommitted</key> + <string>omitted</string> + <key>ommitting</key> + <string>omitting</string> + <key>omniverous</key> + <string>omnivorous</string> + <key>omniverously</key> + <string>omnivorously</string> + <key>omre</key> + <string>more</string> + <key>onot</key> + <string>note</string> + <key>onxy</key> + <string>onyx</string> + <key>onyl</key> + <string>only</string> + <key>openess</key> + <string>openness</string> + <key>oponent</key> + <string>opponent</string> + <key>oportunity</key> + <string>opportunity</string> + <key>opose</key> + <string>oppose</string> + <key>oposite</key> + <string>opposite</string> + <key>oposition</key> + <string>opposition</string> + <key>oppenly</key> + <string>openly</string> + <key>oppinion</key> + <string>opinion</string> + <key>opponant</key> + <string>opponent</string> + <key>oppononent</key> + <string>opponent</string> + <key>oppositition</key> + <string>opposition</string> + <key>oppossed</key> + <string>opposed</string> + <key>opprotunity</key> + <string>opportunity</string> + <key>opression</key> + <string>oppression</string> + <key>opressive</key> + <string>oppressive</string> + <key>opthalmic</key> + <string>ophthalmic</string> + <key>opthalmologist</key> + <string>ophthalmologist</string> + <key>opthalmology</key> + <string>ophthalmology</string> + <key>opthamologist</key> + <string>ophthalmologist</string> + <key>optmizations</key> + <string>optimizations</string> + <key>optomism</key> + <string>optimism</string> + <key>orded</key> + <string>ordered</string> + <key>organim</key> + <string>organism</string> + <key>organistion</key> + <string>organisation</string> + <key>organiztion</key> + <string>organization</string> + <key>orgin</key> + <string>origin</string> + <key>orginal</key> + <string>original</string> + <key>orginally</key> + <string>originally</string> + <key>orginize</key> + <string>organise</string> + <key>oridinarily</key> + <string>ordinarily</string> + <key>origanaly</key> + <string>originally</string> + <key>originall</key> + <string>original</string> + <key>originaly</key> + <string>originally</string> + <key>originially</key> + <string>originally</string> + <key>originnally</key> + <string>originally</string> + <key>origional</key> + <string>original</string> + <key>orignally</key> + <string>originally</string> + <key>orignially</key> + <string>originally</string> + <key>otehr</key> + <string>other</string> + <key>oublisher</key> + <string>publisher</string> + <key>ouevre</key> + <string>oeuvre</string> + <key>oustanding</key> + <string>outstanding</string> + <key>overshaddowed</key> + <string>overshadowed</string> + <key>overthere</key> + <string>over there</string> + <key>overwelming</key> + <string>overwhelming</string> + <key>overwheliming</key> + <string>overwhelming</string> + <key>owrk</key> + <string>work</string> + <key>owudl</key> + <string>would</string> + <key>oxigen</key> + <string>oxygen</string> + <key>oximoron</key> + <string>oxymoron</string> + <key>p0enis</key> + <string>penis</string> + <key>paide</key> + <string>paid</string> + <key>paitience</key> + <string>patience</string> + <key>palce</key> + <string>place</string> + <key>paleolitic</key> + <string>paleolithic</string> + <key>paliamentarian</key> + <string>parliamentarian</string> + <key>pallete</key> + <string>palette</string> + <key>pamflet</key> + <string>pamphlet</string> + <key>pamplet</key> + <string>pamphlet</string> + <key>pantomine</key> + <string>pantomime</string> + <key>paralel</key> + <string>parallel</string> + <key>paralell</key> + <string>parallel</string> + <key>paralelly</key> + <string>parallelly</string> + <key>paralely</key> + <string>parallelly</string> + <key>parallely</key> + <string>parallelly</string> + <key>paranthesis</key> + <string>parenthesis</string> + <key>paraphenalia</key> + <string>paraphernalia</string> + <key>parellels</key> + <string>parallels</string> + <key>parituclar</key> + <string>particular</string> + <key>parliment</key> + <string>parliament</string> + <key>parrakeets</key> + <string>parakeets</string> + <key>parralel</key> + <string>parallel</string> + <key>parrallel</key> + <string>parallel</string> + <key>parrallell</key> + <string>parallel</string> + <key>parrallelly</key> + <string>parallelly</string> + <key>parrallely</key> + <string>parallelly</string> + <key>partialy</key> + <string>partially</string> + <key>particually</key> + <string>particularly</string> + <key>particualr</key> + <string>particular</string> + <key>particuarly</key> + <string>particularly</string> + <key>particularily</key> + <string>particularly</string> + <key>particulary</key> + <string>particularly</string> + <key>pary</key> + <string>party</string> + <key>pased</key> + <string>passed</string> + <key>pasengers</key> + <string>passengers</string> + <key>passerbys</key> + <string>passersby</string> + <key>pasttime</key> + <string>pastime</string> + <key>pastural</key> + <string>pastoral</string> + <key>paticular</key> + <string>particular</string> + <key>pattented</key> + <string>patented</string> + <key>pavillion</key> + <string>pavilion</string> + <key>payed</key> + <string>paid</string> + <key>pblisher</key> + <string>publisher</string> + <key>pbulisher</key> + <string>publisher</string> + <key>peacefuland</key> + <string>peaceful and</string> + <key>peageant</key> + <string>pageant</string> + <key>peculure</key> + <string>peculiar</string> + <key>pedestrain</key> + <string>pedestrian</string> + <key>peformed</key> + <string>performed</string> + <key>peice</key> + <string>piece</string> + <key>penatly</key> + <string>penalty</string> + <key>penerator</key> + <string>penetrator</string> + <key>penisula</key> + <string>peninsula</string> + <key>penisular</key> + <string>peninsular</string> + <key>penninsula</key> + <string>peninsula</string> + <key>penninsular</key> + <string>peninsular</string> + <key>pennisula</key> + <string>peninsula</string> + <key>pensinula</key> + <string>peninsula</string> + <key>peom</key> + <string>poem</string> + <key>peoms</key> + <string>poems</string> + <key>peopel</key> + <string>people</string> + <key>peotry</key> + <string>poetry</string> + <key>perade</key> + <string>parade</string> + <key>percepted</key> + <string>perceived</string> + <key>percieve</key> + <string>perceive</string> + <key>percieved</key> + <string>perceived</string> + <key>perenially</key> + <string>perennially</string> + <key>perfomance</key> + <string>performance</string> + <key>perfomers</key> + <string>performers</string> + <key>performence</key> + <string>performance</string> + <key>performes</key> + <string>performed</string> + <key>perhasp</key> + <string>perhaps</string> + <key>perheaps</key> + <string>perhaps</string> + <key>perhpas</key> + <string>perhaps</string> + <key>peripathetic</key> + <string>peripatetic</string> + <key>peristent</key> + <string>persistent</string> + <key>perjery</key> + <string>perjury</string> + <key>perjorative</key> + <string>pejorative</string> + <key>permanant</key> + <string>permanent</string> + <key>permenant</key> + <string>permanent</string> + <key>permenantly</key> + <string>permanently</string> + <key>permissable</key> + <string>permissible</string> + <key>perogative</key> + <string>prerogative</string> + <key>peronal</key> + <string>personal</string> + <key>perosnality</key> + <string>personality</string> + <key>perphas</key> + <string>perhaps</string> + <key>perpindicular</key> + <string>perpendicular</string> + <key>perseverence</key> + <string>perseverance</string> + <key>persistance</key> + <string>persistence</string> + <key>persistant</key> + <string>persistent</string> + <key>personel</key> + <string>personnel</string> + <key>personell</key> + <string>personnel</string> + <key>personnell</key> + <string>personnel</string> + <key>persuded</key> + <string>persuaded</string> + <key>persue</key> + <string>pursue</string> + <key>persued</key> + <string>pursued</string> + <key>persuing</key> + <string>pursuing</string> + <key>persuit</key> + <string>pursuit</string> + <key>persuits</key> + <string>pursuits</string> + <key>pertubation</key> + <string>perturbation</string> + <key>pertubations</key> + <string>perturbations</string> + <key>pessiary</key> + <string>pessary</string> + <key>petetion</key> + <string>petition</string> + <key>phenomenom</key> + <string>phenomenon</string> + <key>phenomenonal</key> + <string>phenomenal</string> + <key>phenomenonly</key> + <string>phenomenally</string> + <key>phenomonenon</key> + <string>phenomenon</string> + <key>phenomonon</key> + <string>phenomenon</string> + <key>phenonmena</key> + <string>phenomena</string> + <key>philisopher</key> + <string>philosopher</string> + <key>philisophical</key> + <string>philosophical</string> + <key>philisophy</key> + <string>philosophy</string> + <key>phillosophically</key> + <string>philosophically</string> + <key>philospher</key> + <string>philosopher</string> + <key>philosphies</key> + <string>philosophies</string> + <key>philosphy</key> + <string>philosophy</string> + <key>phongraph</key> + <string>phonograph</string> + <key>phylosophical</key> + <string>philosophical</string> + <key>physicaly</key> + <string>physically</string> + <key>piblisher</key> + <string>publisher</string> + <key>pich</key> + <string>pitch</string> + <key>pilgrimmage</key> + <string>pilgrimage</string> + <key>pilgrimmages</key> + <string>pilgrimages</string> + <key>pinapple</key> + <string>pineapple</string> + <key>pinnaple</key> + <string>pineapple</string> + <key>pinoneered</key> + <string>pioneered</string> + <key>plagarism</key> + <string>plagiarism</string> + <key>planation</key> + <string>plantation</string> + <key>planed</key> + <string>planned</string> + <key>plantiff</key> + <string>plaintiff</string> + <key>plateu</key> + <string>plateau</string> + <key>plausable</key> + <string>plausible</string> + <key>playright</key> + <string>playwright</string> + <key>playwrite</key> + <string>playwright</string> + <key>playwrites</key> + <string>playwrights</string> + <key>pleasent</key> + <string>pleasant</string> + <key>plebicite</key> + <string>plebiscite</string> + <key>plesant</key> + <string>pleasant</string> + <key>poenis</key> + <string>penis</string> + <key>poeoples</key> + <string>peoples</string> + <key>poety</key> + <string>poetry</string> + <key>poisin</key> + <string>poison</string> + <key>polical</key> + <string>political</string> + <key>polinator</key> + <string>pollinator</string> + <key>polinators</key> + <string>pollinators</string> + <key>politican</key> + <string>politician</string> + <key>politicans</key> + <string>politicians</string> + <key>poltical</key> + <string>political</string> + <key>polute</key> + <string>pollute</string> + <key>poluted</key> + <string>polluted</string> + <key>polutes</key> + <string>pollutes</string> + <key>poluting</key> + <string>polluting</string> + <key>polution</key> + <string>pollution</string> + <key>polyphonyic</key> + <string>polyphonic</string> + <key>polysaccaride</key> + <string>polysaccharide</string> + <key>polysaccharid</key> + <string>polysaccharide</string> + <key>pomegranite</key> + <string>pomegranate</string> + <key>pomotion</key> + <string>promotion</string> + <key>poportional</key> + <string>proportional</string> + <key>popoulation</key> + <string>population</string> + <key>popularaty</key> + <string>popularity</string> + <key>populare</key> + <string>popular</string> + <key>populer</key> + <string>popular</string> + <key>portait</key> + <string>portrait</string> + <key>portayed</key> + <string>portrayed</string> + <key>portraing</key> + <string>portraying</string> + <key>portuguease</key> + <string>portuguese</string> + <key>portugues</key> + <string>Portuguese</string> + <key>posess</key> + <string>possess</string> + <key>posessed</key> + <string>possessed</string> + <key>posesses</key> + <string>possesses</string> + <key>posessing</key> + <string>possessing</string> + <key>posession</key> + <string>possession</string> + <key>posessions</key> + <string>possessions</string> + <key>posion</key> + <string>poison</string> + <key>positon</key> + <string>position</string> + <key>possable</key> + <string>possible</string> + <key>possably</key> + <string>possibly</string> + <key>posseses</key> + <string>possesses</string> + <key>possesing</key> + <string>possessing</string> + <key>possesion</key> + <string>possession</string> + <key>possessess</key> + <string>possesses</string> + <key>possibile</key> + <string>possible</string> + <key>possibilty</key> + <string>possibility</string> + <key>possiblility</key> + <string>possibility</string> + <key>possiblilty</key> + <string>possibility</string> + <key>possiblities</key> + <string>possibilities</string> + <key>possiblity</key> + <string>possibility</string> + <key>possition</key> + <string>position</string> + <key>posthomous</key> + <string>posthumous</string> + <key>postion</key> + <string>position</string> + <key>postive</key> + <string>positive</string> + <key>potatos</key> + <string>potatoes</string> + <key>potrait</key> + <string>portrait</string> + <key>potrayed</key> + <string>portrayed</string> + <key>poulations</key> + <string>populations</string> + <key>poverful</key> + <string>powerful</string> + <key>poweful</key> + <string>powerful</string> + <key>powerfull</key> + <string>powerful</string> + <key>ppublisher</key> + <string>publisher</string> + <key>practial</key> + <string>practical</string> + <key>practially</key> + <string>practically</string> + <key>practicaly</key> + <string>practically</string> + <key>practicioner</key> + <string>practitioner</string> + <key>practicioners</key> + <string>practitioners</string> + <key>practicly</key> + <string>practically</string> + <key>practioner</key> + <string>practitioner</string> + <key>practioners</key> + <string>practitioners</string> + <key>prairy</key> + <string>prairie</string> + <key>prarie</key> + <string>prairie</string> + <key>praries</key> + <string>prairies</string> + <key>pratice</key> + <string>practice</string> + <key>preample</key> + <string>preamble</string> + <key>precedessor</key> + <string>predecessor</string> + <key>preceed</key> + <string>precede</string> + <key>preceeded</key> + <string>preceded</string> + <key>preceeding</key> + <string>preceding</string> + <key>preceeds</key> + <string>precedes</string> + <key>precentage</key> + <string>percentage</string> + <key>precice</key> + <string>precise</string> + <key>precisly</key> + <string>precisely</string> + <key>precurser</key> + <string>precursor</string> + <key>predecesors</key> + <string>predecessors</string> + <key>predicatble</key> + <string>predictable</string> + <key>predicitons</key> + <string>predictions</string> + <key>predomiantly</key> + <string>predominately</string> + <key>prefered</key> + <string>preferred</string> + <key>prefering</key> + <string>preferring</string> + <key>preferrably</key> + <string>preferably</string> + <key>pregancies</key> + <string>pregnancies</string> + <key>preiod</key> + <string>period</string> + <key>preliferation</key> + <string>proliferation</string> + <key>premeire</key> + <string>premiere</string> + <key>premeired</key> + <string>premiered</string> + <key>premillenial</key> + <string>premillennial</string> + <key>preminence</key> + <string>preeminence</string> + <key>premission</key> + <string>permission</string> + <key>preocupation</key> + <string>preoccupation</string> + <key>prepair</key> + <string>prepare</string> + <key>prepartion</key> + <string>preparation</string> + <key>prepatory</key> + <string>preparatory</string> + <key>preperation</key> + <string>preparation</string> + <key>preperations</key> + <string>preparations</string> + <key>preriod</key> + <string>period</string> + <key>presedential</key> + <string>presidential</string> + <key>presense</key> + <string>presence</string> + <key>presidenital</key> + <string>presidential</string> + <key>presidental</key> + <string>presidential</string> + <key>presitgious</key> + <string>prestigious</string> + <key>prespective</key> + <string>perspective</string> + <key>prestigeous</key> + <string>prestigious</string> + <key>prestigous</key> + <string>prestigious</string> + <key>presumabely</key> + <string>presumably</string> + <key>presumibly</key> + <string>presumably</string> + <key>pretection</key> + <string>protection</string> + <key>prevelant</key> + <string>prevalent</string> + <key>preverse</key> + <string>perverse</string> + <key>previvous</key> + <string>previous</string> + <key>pricipal</key> + <string>principal</string> + <key>priciple</key> + <string>principle</string> + <key>priestood</key> + <string>priesthood</string> + <key>primarly</key> + <string>primarily</string> + <key>primative</key> + <string>primitive</string> + <key>primatively</key> + <string>primitively</string> + <key>primatives</key> + <string>primitives</string> + <key>primordal</key> + <string>primordial</string> + <key>priveledges</key> + <string>privileges</string> + <key>privelege</key> + <string>privilege</string> + <key>priveleged</key> + <string>privileged</string> + <key>priveleges</key> + <string>privileges</string> + <key>privelige</key> + <string>privilege</string> + <key>priveliged</key> + <string>privileged</string> + <key>priveliges</key> + <string>privileges</string> + <key>privelleges</key> + <string>privileges</string> + <key>privilage</key> + <string>privilege</string> + <key>priviledge</key> + <string>privilege</string> + <key>priviledges</key> + <string>privileges</string> + <key>privledge</key> + <string>privilege</string> + <key>privte</key> + <string>private</string> + <key>probabilaty</key> + <string>probability</string> + <key>probablistic</key> + <string>probabilistic</string> + <key>probablly</key> + <string>probably</string> + <key>probalibity</key> + <string>probability</string> + <key>probaly</key> + <string>probably</string> + <key>probelm</key> + <string>problem</string> + <key>proccess</key> + <string>process</string> + <key>proccessing</key> + <string>processing</string> + <key>procede</key> + <string>proceed</string> + <key>proceded</key> + <string>proceeded</string> + <key>procedes</key> + <string>proceeds</string> + <key>procedger</key> + <string>procedure</string> + <key>proceding</key> + <string>proceeding</string> + <key>procedings</key> + <string>proceedings</string> + <key>proceedure</key> + <string>procedure</string> + <key>proces</key> + <string>process</string> + <key>processer</key> + <string>processor</string> + <key>proclaimation</key> + <string>proclamation</string> + <key>proclamed</key> + <string>proclaimed</string> + <key>proclaming</key> + <string>proclaiming</string> + <key>proclomation</key> + <string>proclamation</string> + <key>profesion</key> + <string>profession</string> + <key>profesor</key> + <string>professor</string> + <key>professer</key> + <string>professor</string> + <key>proffesed</key> + <string>professed</string> + <key>proffesion</key> + <string>profession</string> + <key>proffesional</key> + <string>professional</string> + <key>proffesor</key> + <string>professor</string> + <key>profilic</key> + <string>prolific</string> + <key>progessed</key> + <string>progressed</string> + <key>programable</key> + <string>programmable</string> + <key>progrom</key> + <string>program</string> + <key>progroms</key> + <string>programs</string> + <key>prohabition</key> + <string>prohibition</string> + <key>prologomena</key> + <string>prolegomena</string> + <key>prominance</key> + <string>prominence</string> + <key>prominant</key> + <string>prominent</string> + <key>prominantly</key> + <string>prominently</string> + <key>prominately</key> + <string>prominently</string> + <key>promiscous</key> + <string>promiscuous</string> + <key>promotted</key> + <string>promoted</string> + <key>pronomial</key> + <string>pronominal</string> + <key>pronouced</key> + <string>pronounced</string> + <key>pronounched</key> + <string>pronounced</string> + <key>pronounciation</key> + <string>pronunciation</string> + <key>proove</key> + <string>prove</string> + <key>prooved</key> + <string>proved</string> + <key>prophacy</key> + <string>prophecy</string> + <key>propietary</key> + <string>proprietary</string> + <key>propmted</key> + <string>prompted</string> + <key>propoganda</key> + <string>propaganda</string> + <key>propogate</key> + <string>propagate</string> + <key>propogates</key> + <string>propagates</string> + <key>propogation</key> + <string>propagation</string> + <key>propostion</key> + <string>proposition</string> + <key>propotions</key> + <string>proportions</string> + <key>propper</key> + <string>proper</string> + <key>propperly</key> + <string>properly</string> + <key>proprietory</key> + <string>proprietary</string> + <key>proseletyzing</key> + <string>proselytizing</string> + <key>protaganist</key> + <string>protagonist</string> + <key>protaganists</key> + <string>protagonists</string> + <key>protocal</key> + <string>protocol</string> + <key>protoganist</key> + <string>protagonist</string> + <key>protrayed</key> + <string>portrayed</string> + <key>protruberance</key> + <string>protuberance</string> + <key>protruberances</key> + <string>protuberances</string> + <key>prouncements</key> + <string>pronouncements</string> + <key>provacative</key> + <string>provocative</string> + <key>provded</key> + <string>provided</string> + <key>provicial</key> + <string>provincial</string> + <key>provinicial</key> + <string>provincial</string> + <key>provisiosn</key> + <string>provision</string> + <key>provisonal</key> + <string>provisional</string> + <key>proximty</key> + <string>proximity</string> + <key>pseudononymous</key> + <string>pseudonymous</string> + <key>pseudonyn</key> + <string>pseudonym</string> + <key>psuedo</key> + <string>pseudo</string> + <key>psycology</key> + <string>psychology</string> + <key>psyhic</key> + <string>psychic</string> + <key>pubilsher</key> + <string>publisher</string> + <key>pubisher</key> + <string>publisher</string> + <key>publiaher</key> + <string>publisher</string> + <key>publically</key> + <string>publicly</string> + <key>publicaly</key> + <string>publicly</string> + <key>publicher</key> + <string>publisher</string> + <key>publihser</key> + <string>publisher</string> + <key>publisehr</key> + <string>publisher</string> + <key>publiser</key> + <string>publisher</string> + <key>publisger</key> + <string>publisher</string> + <key>publisheed</key> + <string>published</string> + <key>publisherr</key> + <string>publisher</string> + <key>publishher</key> + <string>publisher</string> + <key>publishor</key> + <string>publisher</string> + <key>publishre</key> + <string>publisher</string> + <key>publissher</key> + <string>publisher</string> + <key>publlisher</key> + <string>publisher</string> + <key>publsiher</key> + <string>publisher</string> + <key>publusher</key> + <string>publisher</string> + <key>puchasing</key> + <string>purchasing</string> + <key>pulisher</key> + <string>publisher</string> + <key>pumkin</key> + <string>pumpkin</string> + <key>puplisher</key> + <string>publisher</string> + <key>puritannical</key> + <string>puritanical</string> + <key>purposedly</key> + <string>purposely</string> + <key>purpotedly</key> + <string>purportedly</string> + <key>pursuade</key> + <string>persuade</string> + <key>pursuaded</key> + <string>persuaded</string> + <key>pursuades</key> + <string>persuades</string> + <key>pususading</key> + <string>persuading</string> + <key>puting</key> + <string>putting</string> + <key>pwoer</key> + <string>power</string> + <key>pyscic</key> + <string>psychic</string> + <key>qtuie</key> + <string>quiet</string> + <key>quantaty</key> + <string>quantity</string> + <key>quantitiy</key> + <string>quantity</string> + <key>quarantaine</key> + <string>quarantine</string> + <key>questonable</key> + <string>questionable</string> + <key>quicklyu</key> + <string>quickly</string> + <key>quinessential</key> + <string>quintessential</string> + <key>quitted</key> + <string>quit</string> + <key>quizes</key> + <string>quizzes</string> + <key>qutie</key> + <string>quiet</string> + <key>rabinnical</key> + <string>rabbinical</string> + <key>racaus</key> + <string>raucous</string> + <key>radiactive</key> + <string>radioactive</string> + <key>radify</key> + <string>ratify</string> + <key>raelly</key> + <string>really</string> + <key>rarified</key> + <string>rarefied</string> + <key>reaccurring</key> + <string>recurring</string> + <key>reacing</key> + <string>reaching</string> + <key>reacll</key> + <string>recall</string> + <key>readmition</key> + <string>readmission</string> + <key>realitvely</key> + <string>relatively</string> + <key>realsitic</key> + <string>realistic</string> + <key>realtions</key> + <string>relations</string> + <key>realy</key> + <string>really</string> + <key>realyl</key> + <string>really</string> + <key>reasearch</key> + <string>research</string> + <key>rebiulding</key> + <string>rebuilding</string> + <key>rebllions</key> + <string>rebellions</string> + <key>rebounce</key> + <string>rebound</string> + <key>reccomend</key> + <string>recommend</string> + <key>reccomendations</key> + <string>recommendations</string> + <key>reccomended</key> + <string>recommended</string> + <key>reccomending</key> + <string>recommending</string> + <key>reccommend</key> + <string>recommend</string> + <key>reccommended</key> + <string>recommended</string> + <key>reccommending</key> + <string>recommending</string> + <key>reccuring</key> + <string>recurring</string> + <key>receeded</key> + <string>receded</string> + <key>receeding</key> + <string>receding</string> + <key>receivedfrom</key> + <string>received from</string> + <key>recepient</key> + <string>recipient</string> + <key>recepients</key> + <string>recipients</string> + <key>receving</key> + <string>receiving</string> + <key>rechargable</key> + <string>rechargeable</string> + <key>reched</key> + <string>reached</string> + <key>recide</key> + <string>reside</string> + <key>recided</key> + <string>resided</string> + <key>recident</key> + <string>resident</string> + <key>recidents</key> + <string>residents</string> + <key>reciding</key> + <string>residing</string> + <key>reciepents</key> + <string>recipients</string> + <key>reciept</key> + <string>receipt</string> + <key>recieve</key> + <string>receive</string> + <key>recieved</key> + <string>received</string> + <key>reciever</key> + <string>receiver</string> + <key>recievers</key> + <string>receivers</string> + <key>recieves</key> + <string>receives</string> + <key>recieving</key> + <string>receiving</string> + <key>recipiant</key> + <string>recipient</string> + <key>recipiants</key> + <string>recipients</string> + <key>recived</key> + <string>received</string> + <key>recivership</key> + <string>receivership</string> + <key>recogise</key> + <string>recognise</string> + <key>recogize</key> + <string>recognize</string> + <key>recomend</key> + <string>recommend</string> + <key>recomended</key> + <string>recommended</string> + <key>recomending</key> + <string>recommending</string> + <key>recomends</key> + <string>recommends</string> + <key>recommedations</key> + <string>recommendations</string> + <key>reconaissance</key> + <string>reconnaissance</string> + <key>reconcilation</key> + <string>reconciliation</string> + <key>reconized</key> + <string>recognized</string> + <key>reconnaisance</key> + <string>reconnaissance</string> + <key>reconnaissence</key> + <string>reconnaissance</string> + <key>recontructed</key> + <string>reconstructed</string> + <key>recordproducer</key> + <string>record producer</string> + <key>recquired</key> + <string>required</string> + <key>recrational</key> + <string>recreational</string> + <key>recrod</key> + <string>record</string> + <key>recuiting</key> + <string>recruiting</string> + <key>recuring</key> + <string>recurring</string> + <key>recurrance</key> + <string>recurrence</string> + <key>rediculous</key> + <string>ridiculous</string> + <key>reedeming</key> + <string>redeeming</string> + <key>reenforced</key> + <string>reinforced</string> + <key>refect</key> + <string>reflect</string> + <key>refedendum</key> + <string>referendum</string> + <key>referal</key> + <string>referral</string> + <key>referece</key> + <string>reference</string> + <key>refereces</key> + <string>references</string> + <key>refered</key> + <string>referred</string> + <key>referemce</key> + <string>reference</string> + <key>referemces</key> + <string>references</string> + <key>referencs</key> + <string>references</string> + <key>referenece</key> + <string>reference</string> + <key>refereneced</key> + <string>referenced</string> + <key>refereneces</key> + <string>references</string> + <key>referiang</key> + <string>referring</string> + <key>refering</key> + <string>referring</string> + <key>refernce</key> + <string>references</string> + <key>refernces</key> + <string>references</string> + <key>referrence</key> + <string>reference</string> + <key>referrences</key> + <string>references</string> + <key>referrs</key> + <string>refers</string> + <key>reffered</key> + <string>referred</string> + <key>refference</key> + <string>reference</string> + <key>reffering</key> + <string>referring</string> + <key>refrence</key> + <string>reference</string> + <key>refrences</key> + <string>references</string> + <key>refrers</key> + <string>refers</string> + <key>refridgeration</key> + <string>refrigeration</string> + <key>refridgerator</key> + <string>refrigerator</string> + <key>refromist</key> + <string>reformist</string> + <key>refusla</key> + <string>refusal</string> + <key>regardes</key> + <string>regards</string> + <key>regluar</key> + <string>regular</string> + <key>reguarly</key> + <string>regularly</string> + <key>regulaion</key> + <string>regulation</string> + <key>regulaotrs</key> + <string>regulators</string> + <key>regularily</key> + <string>regularly</string> + <key>rehersal</key> + <string>rehearsal</string> + <key>reicarnation</key> + <string>reincarnation</string> + <key>reigining</key> + <string>reigning</string> + <key>reknown</key> + <string>renown</string> + <key>reknowned</key> + <string>renowned</string> + <key>rela</key> + <string>real</string> + <key>relaly</key> + <string>really</string> + <key>relatiopnship</key> + <string>relationship</string> + <key>relativly</key> + <string>relatively</string> + <key>relected</key> + <string>reelected</string> + <key>releive</key> + <string>relieve</string> + <key>releived</key> + <string>relieved</string> + <key>releiver</key> + <string>reliever</string> + <key>releses</key> + <string>releases</string> + <key>relevence</key> + <string>relevance</string> + <key>relevent</key> + <string>relevant</string> + <key>reliablity</key> + <string>reliability</string> + <key>relient</key> + <string>reliant</string> + <key>religeous</key> + <string>religious</string> + <key>religous</key> + <string>religious</string> + <key>religously</key> + <string>religiously</string> + <key>relinqushment</key> + <string>relinquishment</string> + <key>relitavely</key> + <string>relatively</string> + <key>relized</key> + <string>realized</string> + <key>relpacement</key> + <string>replacement</string> + <key>remaing</key> + <string>remaining</string> + <key>remeber</key> + <string>remember</string> + <key>rememberable</key> + <string>memorable</string> + <key>rememberance</key> + <string>remembrance</string> + <key>remembrence</key> + <string>remembrance</string> + <key>remenant</key> + <string>remnant</string> + <key>remenicent</key> + <string>reminiscent</string> + <key>reminent</key> + <string>remnant</string> + <key>reminescent</key> + <string>reminiscent</string> + <key>reminscent</key> + <string>reminiscent</string> + <key>reminsicent</key> + <string>reminiscent</string> + <key>rendevous</key> + <string>rendezvous</string> + <key>rendezous</key> + <string>rendezvous</string> + <key>renedered</key> + <string>rende</string> + <key>renewl</key> + <string>renewal</string> + <key>rennovate</key> + <string>renovate</string> + <key>rennovated</key> + <string>renovated</string> + <key>rennovating</key> + <string>renovating</string> + <key>rennovation</key> + <string>renovation</string> + <key>rentors</key> + <string>renters</string> + <key>reoccurrence</key> + <string>recurrence</string> + <key>reorganision</key> + <string>reorganisation</string> + <key>repatition</key> + <string>repetition</string> + <key>repectively</key> + <string>respectively</string> + <key>repeition</key> + <string>repetition</string> + <key>repentence</key> + <string>repentance</string> + <key>repentent</key> + <string>repentant</string> + <key>repeteadly</key> + <string>repeatedly</string> + <key>repetion</key> + <string>repetition</string> + <key>repid</key> + <string>rapid</string> + <key>reponse</key> + <string>response</string> + <key>reponsible</key> + <string>responsible</string> + <key>reportadly</key> + <string>reportedly</string> + <key>represantative</key> + <string>representative</string> + <key>representive</key> + <string>representative</string> + <key>representives</key> + <string>representatives</string> + <key>reproducable</key> + <string>reproducible</string> + <key>reprtoire</key> + <string>repertoire</string> + <key>repsectively</key> + <string>respectively</string> + <key>reptition</key> + <string>repetition</string> + <key>requirment</key> + <string>requirement</string> + <key>requred</key> + <string>required</string> + <key>resaurant</key> + <string>restaurant</string> + <key>resembelance</key> + <string>resemblance</string> + <key>resembes</key> + <string>resembles</string> + <key>resemblence</key> + <string>resemblance</string> + <key>resevoir</key> + <string>reservoir</string> + <key>residental</key> + <string>residential</string> + <key>resignement</key> + <string>resignment</string> + <key>resistable</key> + <string>resistible</string> + <key>resistence</key> + <string>resistance</string> + <key>resistent</key> + <string>resistant</string> + <key>respectivly</key> + <string>respectively</string> + <key>responce</key> + <string>response</string> + <key>responibilities</key> + <string>responsibilities</string> + <key>responisble</key> + <string>responsible</string> + <key>responnsibilty</key> + <string>responsibility</string> + <key>responsability</key> + <string>responsibility</string> + <key>responsibile</key> + <string>responsible</string> + <key>responsibilites</key> + <string>responsibilities</string> + <key>responsiblities</key> + <string>responsibilities</string> + <key>responsiblity</key> + <string>responsibility</string> + <key>ressemblance</key> + <string>resemblance</string> + <key>ressemble</key> + <string>resemble</string> + <key>ressembled</key> + <string>resembled</string> + <key>ressemblence</key> + <string>resemblance</string> + <key>ressembling</key> + <string>resembling</string> + <key>resssurecting</key> + <string>resurrecting</string> + <key>ressurect</key> + <string>resurrect</string> + <key>ressurected</key> + <string>resurrected</string> + <key>ressurection</key> + <string>resurrection</string> + <key>ressurrection</key> + <string>resurrection</string> + <key>restarant</key> + <string>restaurant</string> + <key>restarants</key> + <string>restaurants</string> + <key>restaraunt</key> + <string>restaurant</string> + <key>restaraunteur</key> + <string>restaurateur</string> + <key>restaraunteurs</key> + <string>restaurateurs</string> + <key>restaraunts</key> + <string>restaurants</string> + <key>restauranteurs</key> + <string>restaurateurs</string> + <key>restauration</key> + <string>restoration</string> + <key>restauraunt</key> + <string>restaurant</string> + <key>resteraunt</key> + <string>restaurant</string> + <key>resteraunts</key> + <string>restaurants</string> + <key>resticted</key> + <string>restricted</string> + <key>restraunt</key> + <string>restraint</string> + <key>resturant</key> + <string>restaurant</string> + <key>resturants</key> + <string>restaurants</string> + <key>resturaunt</key> + <string>restaurant</string> + <key>resturaunts</key> + <string>restaurants</string> + <key>resurecting</key> + <string>resurrecting</string> + <key>retalitated</key> + <string>retaliated</string> + <key>retalitation</key> + <string>retaliation</string> + <key>retreive</key> + <string>retrieve</string> + <key>returnd</key> + <string>returned</string> + <key>revaluated</key> + <string>reevaluated</string> + <key>reveiw</key> + <string>review</string> + <key>reveral</key> + <string>reversal</string> + <key>reversable</key> + <string>reversible</string> + <key>revolutionar</key> + <string>revolutionary</string> + <key>rewitten</key> + <string>rewritten</string> + <key>rewriet</key> + <string>rewrite</string> + <key>rference</key> + <string>reference</string> + <key>rferences</key> + <string>references</string> + <key>rhymme</key> + <string>rhyme</string> + <key>rhythem</key> + <string>rhythm</string> + <key>rhythim</key> + <string>rhythm</string> + <key>rhytmic</key> + <string>rhythmic</string> + <key>rigourous</key> + <string>rigorous</string> + <key>rininging</key> + <string>ringing</string> + <key>rised</key> + <string>rose</string> + <key>rococco</key> + <string>rococo</string> + <key>rocord</key> + <string>record</string> + <key>roomate</key> + <string>roommate</string> + <key>rougly</key> + <string>roughly</string> + <key>rucuperate</key> + <string>recuperate</string> + <key>rudimentatry</key> + <string>rudimentary</string> + <key>rulle</key> + <string>rule</string> + <key>runing</key> + <string>running</string> + <key>runnung</key> + <string>running</string> + <key>russina</key> + <string>Russian</string> + <key>rwite</key> + <string>write</string> + <key>rythem</key> + <string>rhythm</string> + <key>rythim</key> + <string>rhythm</string> + <key>rythm</key> + <string>rhythm</string> + <key>rythmic</key> + <string>rhythmic</string> + <key>rythyms</key> + <string>rhythms</string> + <key>sacrafice</key> + <string>sacrifice</string> + <key>sacreligious</key> + <string>sacrilegious</string> + <key>sacrifical</key> + <string>sacrificial</string> + <key>saftey</key> + <string>safety</string> + <key>safty</key> + <string>safety</string> + <key>salery</key> + <string>salary</string> + <key>sanctionning</key> + <string>sanctioning</string> + <key>sandwhich</key> + <string>sandwich</string> + <key>santioned</key> + <string>sanctioned</string> + <key>sargant</key> + <string>sergeant</string> + <key>sargeant</key> + <string>sergeant</string> + <key>satelite</key> + <string>satellite</string> + <key>satelites</key> + <string>satellites</string> + <key>satisfactority</key> + <string>satisfactorily</string> + <key>satric</key> + <string>satiric</string> + <key>satrical</key> + <string>satirical</string> + <key>satrically</key> + <string>satirically</string> + <key>sattelite</key> + <string>satellite</string> + <key>sattelites</key> + <string>satellites</string> + <key>saught</key> + <string>sought</string> + <key>saveing</key> + <string>saving</string> + <key>saxaphone</key> + <string>saxophone</string> + <key>scaleable</key> + <string>scalable</string> + <key>scandanavia</key> + <string>Scandinavia</string> + <key>scaricity</key> + <string>scarcity</string> + <key>scavanged</key> + <string>scavenged</string> + <key>schedual</key> + <string>schedule</string> + <key>scholarhip</key> + <string>scholarship</string> + <key>scholarstic</key> + <string>scholastic</string> + <key>scientfic</key> + <string>scientific</string> + <key>scientifc</key> + <string>scientific</string> + <key>scientis</key> + <string>scientist</string> + <key>scince</key> + <string>science</string> + <key>scinece</key> + <string>science</string> + <key>scirpt</key> + <string>script</string> + <key>scoll</key> + <string>scroll</string> + <key>screenwrighter</key> + <string>screenwriter</string> + <key>scrutinity</key> + <string>scrutiny</string> + <key>scuptures</key> + <string>sculptures</string> + <key>seach</key> + <string>search</string> + <key>seached</key> + <string>searched</string> + <key>seaches</key> + <string>searches</string> + <key>secratary</key> + <string>secretary</string> + <key>secretery</key> + <string>secretary</string> + <key>sedereal</key> + <string>sidereal</string> + <key>seeked</key> + <string>sought</string> + <key>segementation</key> + <string>segmentation</string> + <key>seguoys</key> + <string>segues</string> + <key>seige</key> + <string>siege</string> + <key>seing</key> + <string>seeing</string> + <key>seinor</key> + <string>senior</string> + <key>seldomly</key> + <string>seldom</string> + <key>senarios</key> + <string>scenarios</string> + <key>senstive</key> + <string>sensitive</string> + <key>sensure</key> + <string>censure</string> + <key>seperate</key> + <string>separate</string> + <key>seperated</key> + <string>separated</string> + <key>seperately</key> + <string>separately</string> + <key>seperates</key> + <string>separates</string> + <key>seperating</key> + <string>separating</string> + <key>seperation</key> + <string>separation</string> + <key>seperatism</key> + <string>separatism</string> + <key>seperatist</key> + <string>separatist</string> + <key>sepina</key> + <string>subpoena</string> + <key>sergent</key> + <string>sergeant</string> + <key>settelement</key> + <string>settlement</string> + <key>settlment</key> + <string>settlement</string> + <key>severeal</key> + <string>several</string> + <key>severley</key> + <string>severely</string> + <key>severly</key> + <string>severely</string> + <key>sevice</key> + <string>service</string> + <key>shadasloo</key> + <string>shadaloo</string> + <key>shaddow</key> + <string>shadow</string> + <key>shadoloo</key> + <string>shadaloo</string> + <key>shamen</key> + <string>shaman</string> + <key>sheat</key> + <string>sheath</string> + <key>sheild</key> + <string>shield</string> + <key>sherif</key> + <string>sheriff</string> + <key>shineing</key> + <string>shining</string> + <key>shiped</key> + <string>shipped</string> + <key>shiping</key> + <string>shipping</string> + <key>shopkeeepers</key> + <string>shopkeepers</string> + <key>shorly</key> + <string>shortly</string> + <key>shortwhile</key> + <string>short while</string> + <key>shoudl</key> + <string>should</string> + <key>shoudln</key> + <string>shouldn't</string> + <key>shouldnt</key> + <string>shouldn't</string> + <key>shreak</key> + <string>shriek</string> + <key>shrinked</key> + <string>shrunk</string> + <key>sicne</key> + <string>since</string> + <key>sideral</key> + <string>sidereal</string> + <key>siezure</key> + <string>seizure</string> + <key>siezures</key> + <string>seizures</string> + <key>siginificant</key> + <string>significant</string> + <key>signficant</key> + <string>significant</string> + <key>signficiant</key> + <string>significant</string> + <key>signfies</key> + <string>signifies</string> + <key>signifantly</key> + <string>significantly</string> + <key>significently</key> + <string>significantly</string> + <key>signifigant</key> + <string>significant</string> + <key>signifigantly</key> + <string>significantly</string> + <key>signitories</key> + <string>signatories</string> + <key>signitory</key> + <string>signatory</string> + <key>similarily</key> + <string>similarly</string> + <key>similiar</key> + <string>similar</string> + <key>similiarity</key> + <string>similarity</string> + <key>similiarly</key> + <string>similarly</string> + <key>simmilar</key> + <string>similar</string> + <key>simpley</key> + <string>simply</string> + <key>simplier</key> + <string>simpler</string> + <key>simultanous</key> + <string>simultaneous</string> + <key>simultanously</key> + <string>simultaneously</string> + <key>sincerley</key> + <string>sincerely</string> + <key>singsog</key> + <string>singsong</string> + <key>sinse</key> + <string>since</string> + <key>skateing</key> + <string>skating</string> + <key>slaugterhouses</key> + <string>slaughterhouses</string> + <key>slighly</key> + <string>slightly</string> + <key>slowy</key> + <string>slowly</string> + <key>smae</key> + <string>same</string> + <key>smealting</key> + <string>smelting</string> + <key>smoe</key> + <string>some</string> + <key>sneeks</key> + <string>sneaks</string> + <key>snese</key> + <string>sneeze</string> + <key>socalism</key> + <string>socialism</string> + <key>socities</key> + <string>societies</string> + <key>soem</key> + <string>some</string> + <key>sofware</key> + <string>software</string> + <key>sohw</key> + <string>show</string> + <key>soilders</key> + <string>soldiers</string> + <key>solatary</key> + <string>solitary</string> + <key>soley</key> + <string>solely</string> + <key>soliders</key> + <string>soldiers</string> + <key>soliliquy</key> + <string>soliloquy</string> + <key>soluable</key> + <string>soluble</string> + <key>somene</key> + <string>someone</string> + <key>somtimes</key> + <string>sometimes</string> + <key>somwhere</key> + <string>somewhere</string> + <key>sophicated</key> + <string>sophisticated</string> + <key>sophmore</key> + <string>sophomore</string> + <key>sorceror</key> + <string>sorcerer</string> + <key>sorrounding</key> + <string>surrounding</string> + <key>sotry</key> + <string>story</string> + <key>sotyr</key> + <string>story</string> + <key>soudn</key> + <string>sound</string> + <key>soudns</key> + <string>sounds</string> + <key>sould</key> + <string>could</string> + <key>sountrack</key> + <string>soundtrack</string> + <key>sourth</key> + <string>south</string> + <key>sourthern</key> + <string>southern</string> + <key>souvenier</key> + <string>souvenir</string> + <key>souveniers</key> + <string>souvenirs</string> + <key>soveits</key> + <string>soviets</string> + <key>sovereignity</key> + <string>sovereignty</string> + <key>soverign</key> + <string>sovereign</string> + <key>soverignity</key> + <string>sovereignty</string> + <key>soverignty</key> + <string>sovereignty</string> + <key>spainish</key> + <string>Spanish</string> + <key>speach</key> + <string>speech</string> + <key>specfic</key> + <string>specific</string> + <key>speciallized</key> + <string>specialized</string> + <key>specifiying</key> + <string>specifying</string> + <key>speciman</key> + <string>specimen</string> + <key>spectauclar</key> + <string>spectacular</string> + <key>spectaulars</key> + <string>spectaculars</string> + <key>spectum</key> + <string>spectrum</string> + <key>speices</key> + <string>species</string> + <key>spendour</key> + <string>splendour</string> + <key>spermatozoan</key> + <string>spermatozoon</string> + <key>spoace</key> + <string>space</string> + <key>sponser</key> + <string>sponsor</string> + <key>sponsered</key> + <string>sponsored</string> + <key>spontanous</key> + <string>spontaneous</string> + <key>sponzored</key> + <string>sponsored</string> + <key>spoonfulls</key> + <string>spoonfuls</string> + <key>sppeches</key> + <string>speeches</string> + <key>spreaded</key> + <string>spread</string> + <key>sprech</key> + <string>speech</string> + <key>spred</key> + <string>spread</string> + <key>spriritual</key> + <string>spiritual</string> + <key>spritual</key> + <string>spiritual</string> + <key>sqaure</key> + <string>square</string> + <key>stablility</key> + <string>stability</string> + <key>stainlees</key> + <string>stainless</string> + <key>staion</key> + <string>station</string> + <key>standars</key> + <string>standards</string> + <key>stange</key> + <string>strange</string> + <key>startegic</key> + <string>strategic</string> + <key>startegies</key> + <string>strategies</string> + <key>startegy</key> + <string>strategy</string> + <key>stateman</key> + <string>statesman</string> + <key>statememts</key> + <string>statements</string> + <key>statment</key> + <string>statement</string> + <key>steriods</key> + <string>steroids</string> + <key>sterotypes</key> + <string>stereotypes</string> + <key>stilus</key> + <string>stylus</string> + <key>stingent</key> + <string>stringent</string> + <key>stiring</key> + <string>stirring</string> + <key>stirrs</key> + <string>stirs</string> + <key>stlye</key> + <string>style</string> + <key>stomache</key> + <string>stomach</string> + <key>stong</key> + <string>strong</string> + <key>stopry</key> + <string>story</string> + <key>storeis</key> + <string>stories</string> + <key>storise</key> + <string>stories</string> + <key>stornegst</key> + <string>strongest</string> + <key>stoyr</key> + <string>story</string> + <key>stpo</key> + <string>stop</string> + <key>stradegies</key> + <string>strategies</string> + <key>stradegy</key> + <string>strategy</string> + <key>strat</key> + <string>start</string> + <key>stratagically</key> + <string>strategically</string> + <key>streemlining</key> + <string>streamlining</string> + <key>stregth</key> + <string>strength</string> + <key>strenghen</key> + <string>strengthen</string> + <key>strenghened</key> + <string>strengthened</string> + <key>strenghening</key> + <string>strengthening</string> + <key>strenght</key> + <string>strength</string> + <key>strenghten</key> + <string>strengthen</string> + <key>strenghtened</key> + <string>strengthened</string> + <key>strenghtening</key> + <string>strengthening</string> + <key>strengtened</key> + <string>strengthened</string> + <key>strenous</key> + <string>strenuous</string> + <key>strictist</key> + <string>strictest</string> + <key>strikely</key> + <string>strikingly</string> + <key>strnad</key> + <string>strand</string> + <key>stroy</key> + <string>story</string> + <key>structual</key> + <string>structural</string> + <key>stubborness</key> + <string>stubbornness</string> + <key>stucture</key> + <string>structure</string> + <key>stuctured</key> + <string>structured</string> + <key>studdy</key> + <string>study</string> + <key>studing</key> + <string>studying</string> + <key>stuggling</key> + <string>struggling</string> + <key>sturcture</key> + <string>structure</string> + <key>subcatagories</key> + <string>subcategories</string> + <key>subcatagory</key> + <string>subcategory</string> + <key>subconsiously</key> + <string>subconsciously</string> + <key>subjudgation</key> + <string>subjugation</string> + <key>submachne</key> + <string>submachine</string> + <key>subpecies</key> + <string>subspecies</string> + <key>subsidary</key> + <string>subsidiary</string> + <key>subsiduary</key> + <string>subsidiary</string> + <key>subsquent</key> + <string>subsequent</string> + <key>subsquently</key> + <string>subsequently</string> + <key>substace</key> + <string>substance</string> + <key>substancial</key> + <string>substantial</string> + <key>substatial</key> + <string>substantial</string> + <key>substituded</key> + <string>substituted</string> + <key>substract</key> + <string>subtract</string> + <key>substracted</key> + <string>subtracted</string> + <key>substracting</key> + <string>subtracting</string> + <key>substraction</key> + <string>subtraction</string> + <key>substracts</key> + <string>subtracts</string> + <key>subtances</key> + <string>substances</string> + <key>subterranian</key> + <string>subterranean</string> + <key>suburburban</key> + <string>suburban</string> + <key>succceeded</key> + <string>succeeded</string> + <key>succcesses</key> + <string>successes</string> + <key>succedded</key> + <string>succeeded</string> + <key>succeded</key> + <string>succeeded</string> + <key>succeds</key> + <string>succeeds</string> + <key>succesful</key> + <string>successful</string> + <key>succesfully</key> + <string>successfully</string> + <key>succesfuly</key> + <string>successfully</string> + <key>succesion</key> + <string>succession</string> + <key>succesive</key> + <string>successive</string> + <key>successfull</key> + <string>successful</string> + <key>successully</key> + <string>successfully</string> + <key>succsess</key> + <string>success</string> + <key>succsessfull</key> + <string>successful</string> + <key>suceed</key> + <string>succeed</string> + <key>suceeded</key> + <string>succeeded</string> + <key>suceeding</key> + <string>succeeding</string> + <key>suceeds</key> + <string>succeeds</string> + <key>sucesful</key> + <string>successful</string> + <key>sucesfully</key> + <string>successfully</string> + <key>sucesfuly</key> + <string>successfully</string> + <key>sucesion</key> + <string>succession</string> + <key>sucess</key> + <string>success</string> + <key>sucesses</key> + <string>successes</string> + <key>sucessful</key> + <string>successful</string> + <key>sucessfull</key> + <string>successful</string> + <key>sucessfully</key> + <string>successfully</string> + <key>sucessfuly</key> + <string>successfully</string> + <key>sucession</key> + <string>succession</string> + <key>sucessive</key> + <string>successive</string> + <key>sucessor</key> + <string>successor</string> + <key>sucessot</key> + <string>successor</string> + <key>sucide</key> + <string>suicide</string> + <key>sucidial</key> + <string>suicidal</string> + <key>sufferage</key> + <string>suffrage</string> + <key>sufferred</key> + <string>suffered</string> + <key>sufferring</key> + <string>suffering</string> + <key>sufficent</key> + <string>sufficient</string> + <key>sufficently</key> + <string>sufficiently</string> + <key>sumary</key> + <string>summary</string> + <key>sunglases</key> + <string>sunglasses</string> + <key>suop</key> + <string>soup</string> + <key>superceeded</key> + <string>superseded</string> + <key>superintendant</key> + <string>superintendent</string> + <key>suphisticated</key> + <string>sophisticated</string> + <key>suplimented</key> + <string>supplemented</string> + <key>supose</key> + <string>suppose</string> + <key>suposed</key> + <string>supposed</string> + <key>suposedly</key> + <string>supposedly</string> + <key>suposes</key> + <string>supposes</string> + <key>suposing</key> + <string>supposing</string> + <key>supplamented</key> + <string>supplemented</string> + <key>suppliementing</key> + <string>supplementing</string> + <key>suppoed</key> + <string>supposed</string> + <key>supposingly</key> + <string>supposedly</string> + <key>suppy</key> + <string>supply</string> + <key>supress</key> + <string>suppress</string> + <key>supressed</key> + <string>suppressed</string> + <key>supresses</key> + <string>suppresses</string> + <key>supressing</key> + <string>suppressing</string> + <key>suprise</key> + <string>surprise</string> + <key>suprised</key> + <string>surprised</string> + <key>suprising</key> + <string>surprising</string> + <key>suprisingly</key> + <string>surprisingly</string> + <key>suprize</key> + <string>surprise</string> + <key>suprized</key> + <string>surprised</string> + <key>suprizing</key> + <string>surprising</string> + <key>suprizingly</key> + <string>surprisingly</string> + <key>surfce</key> + <string>surface</string> + <key>surley</key> + <string>surely</string> + <key>suround</key> + <string>surround</string> + <key>surounded</key> + <string>surrounded</string> + <key>surounding</key> + <string>surrounding</string> + <key>suroundings</key> + <string>surroundings</string> + <key>surounds</key> + <string>surrounds</string> + <key>surplanted</key> + <string>supplanted</string> + <key>surpress</key> + <string>suppress</string> + <key>surpressed</key> + <string>suppressed</string> + <key>surprize</key> + <string>surprise</string> + <key>surprized</key> + <string>surprised</string> + <key>surprizing</key> + <string>surprising</string> + <key>surprizingly</key> + <string>surprisingly</string> + <key>surrended</key> + <string>surrendered</string> + <key>surrepetitious</key> + <string>surreptitious</string> + <key>surrepetitiously</key> + <string>surreptitiously</string> + <key>surreptious</key> + <string>surreptitious</string> + <key>surreptiously</key> + <string>surreptitiously</string> + <key>surronded</key> + <string>surrounded</string> + <key>surrouded</key> + <string>surrounded</string> + <key>surrouding</key> + <string>surrounding</string> + <key>surrundering</key> + <string>surrendering</string> + <key>surveilence</key> + <string>surveillance</string> + <key>surveill</key> + <string>surveil</string> + <key>surveyer</key> + <string>surveyor</string> + <key>surviver</key> + <string>survivor</string> + <key>survivers</key> + <string>survivors</string> + <key>survivied</key> + <string>survived</string> + <key>suseptable</key> + <string>susceptible</string> + <key>suseptible</key> + <string>susceptible</string> + <key>suspention</key> + <string>suspension</string> + <key>swaer</key> + <string>swear</string> + <key>swaers</key> + <string>swears</string> + <key>swepth</key> + <string>swept</string> + <key>swiming</key> + <string>swimming</string> + <key>syas</key> + <string>says</string> + <key>symetrical</key> + <string>symmetrical</string> + <key>symetrically</key> + <string>symmetrically</string> + <key>symetry</key> + <string>symmetry</string> + <key>symettric</key> + <string>symmetric</string> + <key>symmetral</key> + <string>symmetric</string> + <key>symmetricaly</key> + <string>symmetrically</string> + <key>synagouge</key> + <string>synagogue</string> + <key>syncronization</key> + <string>synchronization</string> + <key>synonomous</key> + <string>synonymous</string> + <key>synonymns</key> + <string>synonyms</string> + <key>synphony</key> + <string>symphony</string> + <key>syphyllis</key> + <string>syphilis</string> + <key>sypmtoms</key> + <string>symptoms</string> + <key>syrap</key> + <string>syrup</string> + <key>sysmatically</key> + <string>systematically</string> + <key>sytem</key> + <string>system</string> + <key>sytle</key> + <string>style</string> + <key>tabacco</key> + <string>tobacco</string> + <key>tahn</key> + <string>than</string> + <key>taht</key> + <string>that</string> + <key>talekd</key> + <string>talked</string> + <key>targetted</key> + <string>targeted</string> + <key>targetting</key> + <string>targeting</string> + <key>tast</key> + <string>taste</string> + <key>tath</key> + <string>that</string> + <key>tattooes</key> + <string>tattoos</string> + <key>taxanomic</key> + <string>taxonomic</string> + <key>taxanomy</key> + <string>taxonomy</string> + <key>teached</key> + <string>taught</string> + <key>techician</key> + <string>technician</string> + <key>techicians</key> + <string>technicians</string> + <key>techiniques</key> + <string>techniques</string> + <key>technitian</key> + <string>technician</string> + <key>technnology</key> + <string>technology</string> + <key>technolgy</key> + <string>technology</string> + <key>teh</key> + <string>the</string> + <key>tehy</key> + <string>they</string> + <key>telelevision</key> + <string>television</string> + <key>televsion</key> + <string>television</string> + <key>telphony</key> + <string>telephony</string> + <key>temerature</key> + <string>temperature</string> + <key>tempalte</key> + <string>template</string> + <key>tempaltes</key> + <string>templates</string> + <key>temparate</key> + <string>temperate</string> + <key>temperarily</key> + <string>temporarily</string> + <key>temperment</key> + <string>temperament</string> + <key>tempertaure</key> + <string>temperature</string> + <key>temperture</key> + <string>temperature</string> + <key>temprary</key> + <string>temporary</string> + <key>tenacle</key> + <string>tentacle</string> + <key>tenacles</key> + <string>tentacles</string> + <key>tendacy</key> + <string>tendency</string> + <key>tendancies</key> + <string>tendencies</string> + <key>tendancy</key> + <string>tendency</string> + <key>tennisplayer</key> + <string>tennis player</string> + <key>tepmorarily</key> + <string>temporarily</string> + <key>terrestial</key> + <string>terrestrial</string> + <key>terriories</key> + <string>territories</string> + <key>terriory</key> + <string>territory</string> + <key>territorist</key> + <string>terrorist</string> + <key>territoy</key> + <string>territory</string> + <key>terroist</key> + <string>terrorist</string> + <key>testiclular</key> + <string>testicular</string> + <key>tghe</key> + <string>the</string> + <key>thast</key> + <string>that's</string> + <key>theather</key> + <string>theater</string> + <key>theese</key> + <string>these</string> + <key>theif</key> + <string>thief</string> + <key>theives</key> + <string>thieves</string> + <key>themselfs</key> + <string>themselves</string> + <key>themslves</key> + <string>themselves</string> + <key>ther</key> + <string>there</string> + <key>therafter</key> + <string>thereafter</string> + <key>therby</key> + <string>thereby</string> + <key>theri</key> + <string>their</string> + <key>theyre</key> + <string>they're</string> + <key>thgat</key> + <string>that</string> + <key>thge</key> + <string>the</string> + <key>thier</key> + <string>their</string> + <key>thign</key> + <string>thing</string> + <key>thigns</key> + <string>things</string> + <key>thigsn</key> + <string>things</string> + <key>thikn</key> + <string>think</string> + <key>thikning</key> + <string>thinking</string> + <key>thikns</key> + <string>thinks</string> + <key>thiunk</key> + <string>think</string> + <key>thn</key> + <string>then</string> + <key>thna</key> + <string>than</string> + <key>thne</key> + <string>then</string> + <key>thnig</key> + <string>thing</string> + <key>thnigs</key> + <string>things</string> + <key>thoughout</key> + <string>throughout</string> + <key>threatend</key> + <string>threatened</string> + <key>threatning</key> + <string>threatening</string> + <key>threee</key> + <string>three</string> + <key>threshhold</key> + <string>threshold</string> + <key>thrid</key> + <string>third</string> + <key>throrough</key> + <string>thorough</string> + <key>throughly</key> + <string>thoroughly</string> + <key>throught</key> + <string>throat</string> + <key>througout</key> + <string>throughout</string> + <key>thru</key> + <string>through</string> + <key>thsi</key> + <string>this</string> + <key>thsoe</key> + <string>those</string> + <key>thta</key> + <string>that</string> + <key>thyat</key> + <string>that</string> + <key>tiem</key> + <string>time</string> + <key>tihkn</key> + <string>think</string> + <key>tihs</key> + <string>this</string> + <key>timne</key> + <string>time</string> + <key>tiome</key> + <string>time</string> + <key>tje</key> + <string>the</string> + <key>tjhe</key> + <string>the</string> + <key>tjpanishad</key> + <string>upanishad</string> + <key>tkae</key> + <string>take</string> + <key>tkaes</key> + <string>takes</string> + <key>tkaing</key> + <string>taking</string> + <key>tlaking</key> + <string>talking</string> + <key>tobbaco</key> + <string>tobacco</string> + <key>todays</key> + <string>today's</string> + <key>todya</key> + <string>today</string> + <key>toghether</key> + <string>together</string> + <key>toke</key> + <string>took</string> + <key>tolerence</key> + <string>tolerance</string> + <key>tomatos</key> + <string>tomatoes</string> + <key>tommorow</key> + <string>tomorrow</string> + <key>tommorrow</key> + <string>tomorrow</string> + <key>tongiht</key> + <string>tonight</string> + <key>toriodal</key> + <string>toroidal</string> + <key>tormenters</key> + <string>tormentors</string> + <key>tornadoe</key> + <string>tornado</string> + <key>torpeados</key> + <string>torpedoes</string> + <key>torpedos</key> + <string>torpedoes</string> + <key>tothe</key> + <string>to the</string> + <key>toubles</key> + <string>troubles</string> + <key>tounge</key> + <string>tongue</string> + <key>tourch</key> + <string>torch</string> + <key>towords</key> + <string>towards</string> + <key>towrad</key> + <string>toward</string> + <key>tradionally</key> + <string>traditionally</string> + <key>traditionaly</key> + <string>traditionally</string> + <key>traditionnal</key> + <string>traditional</string> + <key>traditition</key> + <string>tradition</string> + <key>tradtionally</key> + <string>traditionally</string> + <key>trafficed</key> + <string>trafficked</string> + <key>trafficing</key> + <string>trafficking</string> + <key>trafic</key> + <string>traffic</string> + <key>trancendent</key> + <string>transcendent</string> + <key>trancending</key> + <string>transcending</string> + <key>tranform</key> + <string>transform</string> + <key>tranformed</key> + <string>transformed</string> + <key>transcendance</key> + <string>transcendence</string> + <key>transcendant</key> + <string>transcendent</string> + <key>transcendentational</key> + <string>transcendental</string> + <key>transcripting</key> + <string>transcribing</string> + <key>transending</key> + <string>transcending</string> + <key>transesxuals</key> + <string>transsexuals</string> + <key>transfered</key> + <string>transferred</string> + <key>transfering</key> + <string>transferring</string> + <key>transformaton</key> + <string>transformation</string> + <key>transistion</key> + <string>transition</string> + <key>translater</key> + <string>translator</string> + <key>translaters</key> + <string>translators</string> + <key>transmissable</key> + <string>transmissible</string> + <key>transporation</key> + <string>transportation</string> + <key>tremelo</key> + <string>tremolo</string> + <key>tremelos</key> + <string>tremolos</string> + <key>triguered</key> + <string>triggered</string> + <key>triology</key> + <string>trilogy</string> + <key>troling</key> + <string>trolling</string> + <key>troup</key> + <string>troupe</string> + <key>troups</key> + <string>troops</string> + <key>truely</key> + <string>truly</string> + <key>trustworthyness</key> + <string>trustworthiness</string> + <key>turnk</key> + <string>trunk</string> + <key>tust</key> + <string>trust</string> + <key>twelth</key> + <string>twelfth</string> + <key>twon</key> + <string>town</string> + <key>twpo</key> + <string>two</string> + <key>tyhat</key> + <string>that</string> + <key>tyhe</key> + <string>they</string> + <key>typcial</key> + <string>typical</string> + <key>typicaly</key> + <string>typically</string> + <key>tyranies</key> + <string>tyrannies</string> + <key>tyrany</key> + <string>tyranny</string> + <key>tyrranies</key> + <string>tyrannies</string> + <key>tyrrany</key> + <string>tyranny</string> + <key>ubiquitious</key> + <string>ubiquitous</string> + <key>ublisher</key> + <string>publisher</string> + <key>uise</key> + <string>use</string> + <key>ultimely</key> + <string>ultimately</string> + <key>unacompanied</key> + <string>unaccompanied</string> + <key>unahppy</key> + <string>unhappy</string> + <key>unanymous</key> + <string>unanimous</string> + <key>unathorised</key> + <string>unauthorised</string> + <key>unavailible</key> + <string>unavailable</string> + <key>unballance</key> + <string>unbalance</string> + <key>unbeknowst</key> + <string>unbeknownst</string> + <key>unbeleivable</key> + <string>unbelievable</string> + <key>uncertainity</key> + <string>uncertainty</string> + <key>unchallengable</key> + <string>unchallengeable</string> + <key>unchangable</key> + <string>unchangeable</string> + <key>uncompetive</key> + <string>uncompetitive</string> + <key>unconcious</key> + <string>unconscious</string> + <key>unconciousness</key> + <string>unconsciousness</string> + <key>unconfortability</key> + <string>discomfort</string> + <key>uncontitutional</key> + <string>unconstitutional</string> + <key>unconvential</key> + <string>unconventional</string> + <key>undecideable</key> + <string>undecidable</string> + <key>understoon</key> + <string>understood</string> + <key>undesireable</key> + <string>undesirable</string> + <key>undetecable</key> + <string>undetectable</string> + <key>undoubtely</key> + <string>undoubtedly</string> + <key>undreground</key> + <string>underground</string> + <key>uneccesary</key> + <string>unnecessary</string> + <key>unecessary</key> + <string>unnecessary</string> + <key>unequalities</key> + <string>inequalities</string> + <key>unforetunately</key> + <string>unfortunately</string> + <key>unforgetable</key> + <string>unforgettable</string> + <key>unforgiveable</key> + <string>unforgivable</string> + <key>unfortunatley</key> + <string>unfortunately</string> + <key>unfortunatly</key> + <string>unfortunately</string> + <key>unfourtunately</key> + <string>unfortunately</string> + <key>unihabited</key> + <string>uninhabited</string> + <key>unilateraly</key> + <string>unilaterally</string> + <key>unilatreal</key> + <string>unilateral</string> + <key>unilatreally</key> + <string>unilaterally</string> + <key>uninterruped</key> + <string>uninterrupted</string> + <key>uninterupted</key> + <string>uninterrupted</string> + <key>univeral</key> + <string>universal</string> + <key>univeristies</key> + <string>universities</string> + <key>univeristy</key> + <string>university</string> + <key>univerity</key> + <string>university</string> + <key>universtiy</key> + <string>university</string> + <key>univesities</key> + <string>universities</string> + <key>univesity</key> + <string>university</string> + <key>unkown</key> + <string>unknown</string> + <key>unlikey</key> + <string>unlikely</string> + <key>unmanouverable</key> + <string>unmaneuverable</string> + <key>unmistakeably</key> + <string>unmistakably</string> + <key>unneccesarily</key> + <string>unnecessarily</string> + <key>unneccesary</key> + <string>unnecessary</string> + <key>unneccessarily</key> + <string>unnecessarily</string> + <key>unneccessary</key> + <string>unnecessary</string> + <key>unnecesarily</key> + <string>unnecessarily</string> + <key>unnecesary</key> + <string>unnecessary</string> + <key>unoffical</key> + <string>unofficial</string> + <key>unoperational</key> + <string>nonoperational</string> + <key>unoticeable</key> + <string>unnoticeable</string> + <key>unplease</key> + <string>displease</string> + <key>unplesant</key> + <string>unpleasant</string> + <key>unprecendented</key> + <string>unprecedented</string> + <key>unprecidented</key> + <string>unprecedented</string> + <key>unrepentent</key> + <string>unrepentant</string> + <key>unrepetant</key> + <string>unrepentant</string> + <key>unrepetent</key> + <string>unrepentant</string> + <key>unsed</key> + <string>unused</string> + <key>unsubstanciated</key> + <string>unsubstantiated</string> + <key>unsuccesful</key> + <string>unsuccessful</string> + <key>unsuccesfully</key> + <string>unsuccessfully</string> + <key>unsuccessfull</key> + <string>unsuccessful</string> + <key>unsucesful</key> + <string>unsuccessful</string> + <key>unsucesfuly</key> + <string>unsuccessfully</string> + <key>unsucessful</key> + <string>unsuccessful</string> + <key>unsucessfull</key> + <string>unsuccessful</string> + <key>unsucessfully</key> + <string>unsuccessfully</string> + <key>unsuprised</key> + <string>unsurprised</string> + <key>unsuprising</key> + <string>unsurprising</string> + <key>unsuprisingly</key> + <string>unsurprisingly</string> + <key>unsuprized</key> + <string>unsurprised</string> + <key>unsuprizing</key> + <string>unsurprising</string> + <key>unsuprizingly</key> + <string>unsurprisingly</string> + <key>unsurprized</key> + <string>unsurprised</string> + <key>unsurprizing</key> + <string>unsurprising</string> + <key>unsurprizingly</key> + <string>unsurprisingly</string> + <key>untill</key> + <string>until</string> + <key>untranslateable</key> + <string>untranslatable</string> + <key>unuseable</key> + <string>unusable</string> + <key>unusuable</key> + <string>unusable</string> + <key>unviersity</key> + <string>university</string> + <key>unwarrented</key> + <string>unwarranted</string> + <key>unweildly</key> + <string>unwieldy</string> + <key>unwieldly</key> + <string>unwieldy</string> + <key>upcomming</key> + <string>upcoming</string> + <key>upgradded</key> + <string>upgraded</string> + <key>upto</key> + <string>up to</string> + <key>usally</key> + <string>usually</string> + <key>useage</key> + <string>usage</string> + <key>usefull</key> + <string>useful</string> + <key>usefuly</key> + <string>usefully</string> + <key>useing</key> + <string>using</string> + <key>usualy</key> + <string>usually</string> + <key>ususally</key> + <string>usually</string> + <key>vaccum</key> + <string>vacuum</string> + <key>vaccume</key> + <string>vacuum</string> + <key>vacinity</key> + <string>vicinity</string> + <key>vaguaries</key> + <string>vagaries</string> + <key>vaieties</key> + <string>varieties</string> + <key>vailidty</key> + <string>validity</string> + <key>valetta</key> + <string>valletta</string> + <key>valuble</key> + <string>valuable</string> + <key>valueable</key> + <string>valuable</string> + <key>varations</key> + <string>variations</string> + <key>varient</key> + <string>variant</string> + <key>variey</key> + <string>variety</string> + <key>varing</key> + <string>varying</string> + <key>varities</key> + <string>varieties</string> + <key>varity</key> + <string>variety</string> + <key>vasall</key> + <string>vassal</string> + <key>vasalls</key> + <string>vassals</string> + <key>vegatarian</key> + <string>vegetarian</string> + <key>vegitable</key> + <string>vegetable</string> + <key>vegitables</key> + <string>vegetables</string> + <key>vegtable</key> + <string>vegetable</string> + <key>vehicule</key> + <string>vehicle</string> + <key>vell</key> + <string>well</string> + <key>venemous</key> + <string>venomous</string> + <key>vengance</key> + <string>vengeance</string> + <key>vengence</key> + <string>vengeance</string> + <key>verfication</key> + <string>verification</string> + <key>verison</key> + <string>version</string> + <key>verisons</key> + <string>versions</string> + <key>vermillion</key> + <string>vermilion</string> + <key>versitilaty</key> + <string>versatility</string> + <key>versitlity</key> + <string>versatility</string> + <key>vetween</key> + <string>between</string> + <key>veyr</key> + <string>very</string> + <key>vigeur</key> + <string>vigor</string> + <key>vigilence</key> + <string>vigilance</string> + <key>vigourous</key> + <string>vigorous</string> + <key>villian</key> + <string>villain</string> + <key>villification</key> + <string>vilification</string> + <key>villify</key> + <string>vilify</string> + <key>villin</key> + <string>villain</string> + <key>vincinity</key> + <string>vicinity</string> + <key>violentce</key> + <string>violence</string> + <key>virtualy</key> + <string>virtually</string> + <key>virutal</key> + <string>virtual</string> + <key>virutally</key> + <string>virtually</string> + <key>visable</key> + <string>visible</string> + <key>visably</key> + <string>visibly</string> + <key>visting</key> + <string>visiting</string> + <key>vistors</key> + <string>visitors</string> + <key>vitories</key> + <string>victories</string> + <key>volcanoe</key> + <string>volcano</string> + <key>voleyball</key> + <string>volleyball</string> + <key>volontary</key> + <string>voluntary</string> + <key>volonteer</key> + <string>volunteer</string> + <key>volonteered</key> + <string>volunteered</string> + <key>volonteering</key> + <string>volunteering</string> + <key>volonteers</key> + <string>volunteers</string> + <key>volounteer</key> + <string>volunteer</string> + <key>volounteered</key> + <string>volunteered</string> + <key>volounteering</key> + <string>volunteering</string> + <key>volounteers</key> + <string>volunteers</string> + <key>volumne</key> + <string>volume</string> + <key>vreity</key> + <string>variety</string> + <key>vrey</key> + <string>very</string> + <key>vriety</key> + <string>variety</string> + <key>vulnerablility</key> + <string>vulnerability</string> + <key>vyer</key> + <string>very</string> + <key>vyre</key> + <string>very</string> + <key>waht</key> + <string>what</string> + <key>wanna</key> + <string>want to</string> + <key>warantee</key> + <string>warranty</string> + <key>wardobe</key> + <string>wardrobe</string> + <key>warrent</key> + <string>warrant</string> + <key>warrriors</key> + <string>warriors</string> + <key>wasnt</key> + <string>wasn't</string> + <key>wass</key> + <string>was</string> + <key>watn</key> + <string>want</string> + <key>wayword</key> + <string>wayward</string> + <key>weaponary</key> + <string>weaponry</string> + <key>weas</key> + <string>was</string> + <key>wehn</key> + <string>when</string> + <key>weild</key> + <string>wield</string> + <key>weilded</key> + <string>wielded</string> + <key>wendsay</key> + <string>Wednesday</string> + <key>wensday</key> + <string>Wednesday</string> + <key>wereabouts</key> + <string>whereabouts</string> + <key>whant</key> + <string>want</string> + <key>whants</key> + <string>wants</string> + <key>whcih</key> + <string>which</string> + <key>wheras</key> + <string>whereas</string> + <key>wherease</key> + <string>whereas</string> + <key>whereever</key> + <string>wherever</string> + <key>whic</key> + <string>which</string> + <key>whihc</key> + <string>which</string> + <key>whith</key> + <string>with</string> + <key>whlch</key> + <string>which</string> + <key>whn</key> + <string>when</string> + <key>wholey</key> + <string>wholly</string> + <key>wholy</key> + <string>holy</string> + <key>whta</key> + <string>what</string> + <key>whther</key> + <string>whether</string> + <key>wich</key> + <string>which</string> + <key>widesread</key> + <string>widespread</string> + <key>wief</key> + <string>wife</string> + <key>wierd</key> + <string>weird</string> + <key>wiew</key> + <string>view</string> + <key>wih</key> + <string>with</string> + <key>wiht</key> + <string>with</string> + <key>wille</key> + <string>will</string> + <key>willingless</key> + <string>willingness</string> + <key>wirting</key> + <string>writing</string> + <key>withdrawl</key> + <string>withdrawal</string> + <key>witheld</key> + <string>withheld</string> + <key>withh</key> + <string>with</string> + <key>withing</key> + <string>within</string> + <key>withold</key> + <string>withhold</string> + <key>witht</key> + <string>with</string> + <key>witn</key> + <string>with</string> + <key>wiull</key> + <string>will</string> + <key>wnat</key> + <string>want</string> + <key>wnated</key> + <string>wanted</string> + <key>wnats</key> + <string>wants</string> + <key>wohle</key> + <string>whole</string> + <key>wokr</key> + <string>work</string> + <key>wokring</key> + <string>working</string> + <key>wonderfull</key> + <string>wonderful</string> + <key>wont</key> + <string>won't</string> + <key>wordlwide</key> + <string>worldwide</string> + <key>workststion</key> + <string>workstation</string> + <key>worls</key> + <string>world</string> + <key>worstened</key> + <string>worsened</string> + <key>woudl</key> + <string>would</string> + <key>wresters</key> + <string>wrestlers</string> + <key>wriet</key> + <string>write</string> + <key>writen</key> + <string>written</string> + <key>wroet</key> + <string>wrote</string> + <key>wrok</key> + <string>work</string> + <key>wroking</key> + <string>working</string> + <key>wtih</key> + <string>with</string> + <key>wupport</key> + <string>support</string> + <key>xenophoby</key> + <string>xenophobia</string> + <key>yaching</key> + <string>yachting</string> + <key>yaer</key> + <string>year</string> + <key>yaerly</key> + <string>yearly</string> + <key>yaers</key> + <string>years</string> + <key>yatch</key> + <string>yacht</string> + <key>yearm</key> + <string>year</string> + <key>yeasr</key> + <string>years</string> + <key>yeild</key> + <string>yield</string> + <key>yeilding</key> + <string>yielding</string> + <key>yera</key> + <string>year</string> + <key>yeras</key> + <string>years</string> + <key>yersa</key> + <string>years</string> + <key>yotube</key> + <string>YouTube</string> + <key>youre</key> + <string>you're</string> + <key>youseff</key> + <string>yousef</string> + <key>youself</key> + <string>yourself</string> + <key>ytou</key> + <string>you</string> + <key>yuo</key> + <string>you</string> + <key>zeebra</key> + <string>zebra</string> + </map> + </map> + </array> +</llsd> diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index c9b4de0140..5e50bd6e01 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -148,7 +148,7 @@ <key>Value</key> <integer>1</integer> </map> - <key>ApplyTextureImmediately</key> + <key>TextureLivePreview</key> <map> <key>Comment</key> <string>Preview selections in texture picker immediately</string> @@ -335,6 +335,17 @@ <key>Value</key> <integer>1</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>AutoAcceptNewInventory</key> <map> <key>Comment</key> @@ -4293,6 +4304,17 @@ <key>Value</key> <integer>0</integer> </map> + <key>InventoryInboxToggleState</key> + <map> + <key>Comment</key> + <string>Stores the open/closed state of inventory Received items panel</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> <key>InventoryLinking</key> <map> <key>Comment</key> @@ -6356,17 +6378,6 @@ <key>Value</key> <integer>0</integer> </map> - <key>NumpadControl</key> - <map> - <key>Comment</key> - <string>How numpad keys control your avatar. 0 = Like the normal arrow keys, 1 = Numpad moves avatar when numlock is off, 2 = Numpad moves avatar regardless of numlock (use this if you have no numlock)</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>0</integer> - </map> <key>ObjectCacheEnabled</key> <map> <key>Comment</key> @@ -7274,7 +7285,7 @@ <key>WebContentWindowLimit</key> <map> <key>Comment</key> - <string>Maximum number of web brower windows that can be open at once in the Web content floater (0 for no limit)</string> + <string>Maximum number of web browser windows that can be open at once in the Web content floater (0 for no limit)</string> <key>Persist</key> <integer>1</integer> <key>Type</key> @@ -8093,6 +8104,18 @@ <real>0</real> </map> + <key>RenderDepthPrePass</key> + <map> + <key>Comment</key> + <string>EXPERIMENTAL: Prime the depth buffer with simple prim geometry before rendering with textures.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> + <key>RenderDepthOfField</key> <map> <key>Comment</key> @@ -9172,7 +9195,7 @@ <key>RenderUseVAO</key> <map> <key>Comment</key> - <string>Use GL Vertex Array Objects</string> + <string>[EXPERIMENTAL] Use GL Vertex Array Objects</string> <key>Persist</key> <integer>1</integer> <key>Type</key> @@ -9180,7 +9203,19 @@ <key>Value</key> <integer>0</integer> </map> - <key>RenderVBOMappingDisable</key> + <key>RenderUseTransformFeedback</key> + <map> + <key>Comment</key> + <string>[EXPERIMENTAL] Use transform feedback shaders for LoD updates</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> + + <key>RenderVBOMappingDisable</key> <map> <key>Comment</key> <string>Disable VBO glMapBufferARB</string> @@ -10863,7 +10898,8 @@ <string>F32</string> <key>Value</key> <real>0.1</real> - </map> <key>ToolTipFadeTime</key> + </map> + <key>ToolTipFadeTime</key> <map> <key>Comment</key> <string>Seconds over which tooltip fades away</string> @@ -12227,6 +12263,17 @@ <key>Value</key> <integer>1</integer> </map> + <key>RenderSynchronousOcclusion</key> + <map> + <key>Comment</key> + <string>Don't let occlusion queries get more than one frame behind (block until they complete).</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> <key>RenderDelayVBUpdate</key> <map> <key>Comment</key> @@ -12260,6 +12307,28 @@ <key>Value</key> <real>10.0</real> </map> + <key>SpellCheck</key> + <map> + <key>Comment</key> + <string>Enable spellchecking on line and text editors</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>SpellCheckDictionary</key> + <map> + <key>Comment</key> + <string>Current primary and secondary dictionaries used for spell checking</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string>English (United States),Second Life Glossary</string> + </map> <key>UseNewWalkRun</key> <map> <key>Comment</key> diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaNonIndexedNoColorF.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaNonIndexedNoColorF.glsl index cb87b754b4..1113a9845b 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/alphaNonIndexedNoColorF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/alphaNonIndexedNoColorF.glsl @@ -31,6 +31,8 @@ out vec4 frag_color; #define frag_color gl_FragColor #endif +uniform float minimum_alpha; + uniform sampler2DRect depthMap; uniform sampler2D diffuseMap; @@ -70,9 +72,15 @@ void main() vec4 diff= texture2D(diffuseMap,vary_texcoord0.xy); + if (diff.a < minimum_alpha) + { + discard; + } + vec4 col = vec4(vary_ambient + vary_directional.rgb, 1.0); vec4 color = diff * col; + color.rgb = atmosLighting(color.rgb); color.rgb = scaleSoftClip(color.rgb); diff --git a/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl index 75de47614c..bff87cb6aa 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl @@ -55,8 +55,6 @@ uniform float far_clip; uniform vec3 proj_origin; //origin of projection to be used for angular attenuation uniform float sun_wash; -uniform int proj_shadow_idx; -uniform float shadow_fade; uniform vec3 center; uniform vec3 color; @@ -143,7 +141,8 @@ void main() discard; } - vec3 norm = texture2DRect(normalMap, frag.xy).xyz*2.0-1.0; + vec3 norm = texture2DRect(normalMap, frag.xy).xyz; + norm = vec3((norm.xy-0.5)*2.0, norm.z); norm = normalize(norm); float l_dist = -dot(lv, proj_n); diff --git a/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl index 19800a8b8e..f671d5b750 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl @@ -42,12 +42,13 @@ uniform sampler2DRect depthMap; uniform vec3 env_mat[3]; uniform float sun_wash; -uniform vec3 center; uniform vec3 color; uniform float falloff; uniform float size; VARYING vec4 vary_fragcoord; +VARYING vec3 trans_center; + uniform vec2 screen_res; uniform mat4 inv_proj; @@ -74,7 +75,7 @@ void main() frag.xy *= screen_res; vec3 pos = getPosition(frag.xy).xyz; - vec3 lv = center.xyz-pos; + vec3 lv = trans_center.xyz-pos; float dist2 = dot(lv,lv); dist2 /= size; if (dist2 > 1.0) diff --git a/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl b/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl index cb14e6d4e8..9491421236 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl @@ -24,16 +24,22 @@ */ uniform mat4 modelview_projection_matrix; +uniform mat4 modelview_matrix; ATTRIBUTE vec3 position; +uniform vec3 center; +uniform float size; + VARYING vec4 vary_fragcoord; +VARYING vec3 trans_center; void main() { //transform vertex - vec4 pos = modelview_projection_matrix * vec4(position.xyz, 1.0); + vec3 p = position*sqrt(size)+center; + vec4 pos = modelview_projection_matrix * vec4(p.xyz, 1.0); vary_fragcoord = pos; - + trans_center = (modelview_matrix*vec4(center.xyz, 1.0)).xyz; gl_Position = pos; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/shadowCubeV.glsl b/indra/newview/app_settings/shaders/class1/deferred/shadowCubeV.glsl new file mode 100644 index 0000000000..6195e2f1ec --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/shadowCubeV.glsl @@ -0,0 +1,44 @@ +/** + * @file shadowCubeV.glsl + * + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, 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$ + */ + +uniform mat4 modelview_projection_matrix; + +ATTRIBUTE vec3 position; + +VARYING vec4 post_pos; + +uniform vec3 box_center; +uniform vec3 box_size; + +void main() +{ + //transform vertex + vec3 p = position*box_size+box_center; + vec4 pos = modelview_projection_matrix*vec4(p.xyz, 1.0); + + post_pos = pos; + + gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w); +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl index 7ed8ed3370..cca63872de 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl @@ -24,18 +24,21 @@ */ -#extension GL_ARB_texture_rectangle : enable - #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; #else #define frag_color gl_FragColor #endif +//class 1 -- no shadows + +#extension GL_ARB_texture_rectangle : enable + uniform sampler2DRect diffuseRect; uniform sampler2DRect specularRect; uniform sampler2DRect depthMap; uniform sampler2DRect normalMap; +uniform samplerCube environmentMap; uniform sampler2D noiseMap; uniform sampler2D projectionMap; @@ -46,6 +49,7 @@ uniform vec3 proj_n; uniform float proj_focus; //distance from plane to begin blurring uniform float proj_lod; //(number of mips in proj map) uniform float proj_range; //range between near clip and far clip plane of projection +uniform float proj_ambient_lod; uniform float proj_ambiance; uniform float near_clip; uniform float far_clip; @@ -53,19 +57,66 @@ uniform float far_clip; uniform vec3 proj_origin; //origin of projection to be used for angular attenuation uniform float sun_wash; -uniform vec3 center; uniform vec3 color; uniform float falloff; uniform float size; VARYING vec4 vary_fragcoord; +VARYING vec3 trans_center; + uniform vec2 screen_res; uniform mat4 inv_proj; +vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod) +{ + vec4 ret = texture2DLod(projectionMap, tc, lod); + + vec2 dist = tc-vec2(0.5); + + float det = max(1.0-lod/(proj_lod*0.5), 0.0); + + float d = dot(dist,dist); + + ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0)+det, 1.0); + + return ret; +} + +vec4 texture2DLodDiffuse(sampler2D projectionMap, vec2 tc, float lod) +{ + vec4 ret = texture2DLod(projectionMap, tc, lod); + + vec2 dist = vec2(0.5) - abs(tc-vec2(0.5)); + + float det = min(lod/(proj_lod*0.5), 1.0); + + float d = min(dist.x, dist.y); + + float edge = 0.25*det; + + ret *= clamp(d/edge, 0.0, 1.0); + + return ret; +} + +vec4 texture2DLodAmbient(sampler2D projectionMap, vec2 tc, float lod) +{ + vec4 ret = texture2DLod(projectionMap, tc, lod); + + vec2 dist = tc-vec2(0.5); + + float d = dot(dist,dist); + + ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0), 1.0); + + return ret; +} + + vec4 getPosition(vec2 pos_screen) { - float depth = texture2DRect(depthMap, pos_screen.xy).a; + float depth = texture2DRect(depthMap, pos_screen.xy).r; vec2 sc = pos_screen.xy*2.0; sc /= screen_res; sc -= vec2(1.0,1.0); @@ -84,16 +135,16 @@ void main() frag.xy *= screen_res; vec3 pos = getPosition(frag.xy).xyz; - vec3 lv = center.xyz-pos.xyz; + vec3 lv = trans_center.xyz-pos.xyz; float dist2 = dot(lv,lv); dist2 /= size; if (dist2 > 1.0) { discard; } - + vec3 norm = texture2DRect(normalMap, frag.xy).xyz; - norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm + norm = vec3((norm.xy-0.5)*2.0, norm.z); norm = normalize(norm); float l_dist = -dot(lv, proj_n); @@ -107,7 +158,11 @@ void main() proj_tc.xyz /= proj_tc.w; float fa = falloff+1.0; - float dist_atten = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); + float dist_atten = min(1.0-(dist2-1.0*(1.0-fa))/fa, 1.0); + if (dist_atten <= 0.0) + { + discard; + } lv = proj_origin-pos.xyz; lv = normalize(lv); @@ -125,32 +180,32 @@ void main() proj_tc.y > 0.0) { float lit = 0.0; + float amb_da = proj_ambiance; + if (da > 0.0) { float diff = clamp((l_dist-proj_focus)/proj_range, 0.0, 1.0); float lod = diff * proj_lod; - vec4 plcol = texture2DLod(projectionMap, proj_tc.xy, lod); + vec4 plcol = texture2DLodDiffuse(projectionMap, proj_tc.xy, lod); vec3 lcol = color.rgb * plcol.rgb * plcol.a; lit = da * dist_atten * noise; col = lcol*lit*diff_tex; + amb_da += (da*0.5)*proj_ambiance; } - float diff = clamp((proj_range-proj_focus)/proj_range, 0.0, 1.0); - float lod = diff * proj_lod; - vec4 amb_plcol = texture2DLod(projectionMap, proj_tc.xy, lod); - //float amb_da = mix(proj_ambiance, proj_ambiance*max(-da, 0.0), max(da, 0.0)); - float amb_da = proj_ambiance; - + //float diff = clamp((proj_range-proj_focus)/proj_range, 0.0, 1.0); + vec4 amb_plcol = texture2DLodAmbient(projectionMap, proj_tc.xy, proj_lod); + amb_da += (da*da*0.5+0.5)*proj_ambiance; - + amb_da *= dist_atten * noise; - + amb_da = min(amb_da, 1.0-lit); - + col += amb_da*color.rgb*diff_tex.rgb*amb_plcol.rgb*amb_plcol.a; } @@ -168,18 +223,22 @@ void main() { vec3 pfinal = pos + ref * dot(pdelta, proj_n)/ds; - vec3 stc = (proj_mat * vec4(pfinal.xyz, 1.0)).xyz; + vec4 stc = (proj_mat * vec4(pfinal.xyz, 1.0)); if (stc.z > 0.0) { - stc.xy /= stc.z+proj_near; - + stc.xy /= stc.w; + + float fatten = clamp(spec.a*spec.a+spec.a*0.5, 0.25, 1.0); + + stc.xy = (stc.xy - vec2(0.5)) * fatten + vec2(0.5); + if (stc.x < 1.0 && stc.y < 1.0 && stc.x > 0.0 && stc.y > 0.0) { - vec4 scol = texture2DLod(projectionMap, stc.xy, proj_lod-spec.a*proj_lod); + vec4 scol = texture2DLodSpecular(projectionMap, stc.xy, proj_lod-spec.a*proj_lod); col += dist_atten*scol.rgb*color.rgb*scol.a*spec.rgb; } } diff --git a/indra/newview/app_settings/shaders/class1/interface/clipF.glsl b/indra/newview/app_settings/shaders/class1/interface/clipF.glsl new file mode 100644 index 0000000000..ac2bc8703b --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/interface/clipF.glsl @@ -0,0 +1,46 @@ +/** + * @file debugF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, 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$ + */ + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +uniform vec4 color; +uniform vec4 clip_plane; + +VARYING vec3 vary_position; + + +void main() +{ + if (dot(vary_position,clip_plane.xyz)+clip_plane.w < 0.0) + { + discard; + } + + frag_color = color; +} diff --git a/indra/newview/app_settings/shaders/class1/interface/clipV.glsl b/indra/newview/app_settings/shaders/class1/interface/clipV.glsl new file mode 100644 index 0000000000..e376b25a71 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/interface/clipV.glsl @@ -0,0 +1,38 @@ +/** + * @file debugV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, 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$ + */ + +uniform mat4 modelview_projection_matrix; +uniform mat4 modelview_matrix; + +ATTRIBUTE vec3 position; + +VARYING vec3 vary_position; + +void main() +{ + vary_position = (modelview_matrix*vec4(position.xyz,1.0)).xyz; + gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); +} + diff --git a/indra/newview/app_settings/shaders/class1/interface/occlusionCubeV.glsl b/indra/newview/app_settings/shaders/class1/interface/occlusionCubeV.glsl new file mode 100644 index 0000000000..5c479d27a9 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/interface/occlusionCubeV.glsl @@ -0,0 +1,38 @@ +/** + * @file occlusionCubeV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, 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$ + */ + +uniform mat4 modelview_projection_matrix; + +ATTRIBUTE vec3 position; + +uniform vec3 box_center; +uniform vec3 box_size; + +void main() +{ + vec3 p = position*box_size+box_center; + gl_Position = modelview_projection_matrix * vec4(p.xyz, 1.0); +} + diff --git a/indra/newview/app_settings/shaders/class1/transform/binormalV.glsl b/indra/newview/app_settings/shaders/class1/transform/binormalV.glsl new file mode 100644 index 0000000000..44f1aa34a0 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/transform/binormalV.glsl @@ -0,0 +1,36 @@ +/** + * @file binormalV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, 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$ + */ + +uniform mat3 normal_matrix; + +ATTRIBUTE vec3 binormal; + +VARYING vec4 binormal_out; + +void main() +{ + binormal_out = vec4(normal_matrix * binormal, 0.0); +} + diff --git a/indra/newview/app_settings/shaders/class1/transform/colorV.glsl b/indra/newview/app_settings/shaders/class1/transform/colorV.glsl new file mode 100644 index 0000000000..59c4a7d895 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/transform/colorV.glsl @@ -0,0 +1,36 @@ +/** + * @file colorV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, 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$ + */ + +uniform int color_in; + +ATTRIBUTE vec3 position; + +VARYING int color_out; + +void main() +{ + color_out = color_in; +} + diff --git a/indra/newview/app_settings/shaders/class1/transform/normalV.glsl b/indra/newview/app_settings/shaders/class1/transform/normalV.glsl new file mode 100644 index 0000000000..a213aa0ae8 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/transform/normalV.glsl @@ -0,0 +1,36 @@ +/** + * @file normalV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, 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$ + */ + +uniform mat3 normal_matrix; + +ATTRIBUTE vec3 normal; + +VARYING vec4 normal_out; + +void main() +{ + normal_out = vec4(normalize(normal_matrix * normal), 0.0); +} + diff --git a/indra/newview/app_settings/shaders/class1/transform/positionV.glsl b/indra/newview/app_settings/shaders/class1/transform/positionV.glsl new file mode 100644 index 0000000000..01eed18de4 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/transform/positionV.glsl @@ -0,0 +1,40 @@ +/** + * @file positionV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, 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$ + */ + +uniform mat4 modelview_matrix; + +uniform int texture_index_in; + +ATTRIBUTE vec3 position; + +VARYING vec3 position_out; +VARYING int texture_index_out; + +void main() +{ + texture_index_out = texture_index_in; + position_out = (modelview_matrix*vec4(position, 1.0)).xyz; +} + diff --git a/indra/newview/app_settings/shaders/class1/transform/texcoordV.glsl b/indra/newview/app_settings/shaders/class1/transform/texcoordV.glsl new file mode 100644 index 0000000000..0e074f3cec --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/transform/texcoordV.glsl @@ -0,0 +1,35 @@ +/** + * @file texcoordV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, 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$ + */ + + +ATTRIBUTE vec2 texcoord0; + +VARYING vec2 texcoord_out; + +void main() +{ + texcoord_out = texcoord0; +} + diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaNonIndexedNoColorF.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaNonIndexedNoColorF.glsl index ba6f3ace53..2093fc37dc 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/alphaNonIndexedNoColorF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/alphaNonIndexedNoColorF.glsl @@ -31,6 +31,8 @@ out vec4 frag_color; #define frag_color gl_FragColor #endif +uniform float minimum_alpha; + uniform sampler2DRectShadow shadowMap0; uniform sampler2DRectShadow shadowMap1; uniform sampler2DRectShadow shadowMap2; @@ -97,6 +99,13 @@ void main() float shadow = 0.0; vec4 pos = vec4(vary_position, 1.0); + vec4 diff = texture2D(diffuseMap,vary_texcoord0.xy); + + if (diff.a < minimum_alpha) + { + discard; + } + vec4 spos = pos; if (spos.z > -shadow_clip.w) @@ -164,8 +173,6 @@ void main() shadow = 1.0; } - vec4 diff = texture2D(diffuseMap,vary_texcoord0.xy); - vec4 col = vec4(vary_ambient + vary_directional.rgb*shadow, 1.0); vec4 color = diff * col; diff --git a/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl index 99a277fbfc..ab077d9e02 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl @@ -31,8 +31,6 @@ out vec4 frag_color; #define frag_color gl_FragColor #endif -VARYING vec4 vertex_color; - uniform sampler2DRect diffuseRect; uniform sampler2DRect specularRect; uniform sampler2DRect depthMap; @@ -49,6 +47,7 @@ uniform vec3 proj_n; uniform float proj_focus; //distance from plane to begin blurring uniform float proj_lod; //(number of mips in proj map) uniform float proj_range; //range between near clip and far clip plane of projection +uniform float proj_ambient_lod; uniform float proj_ambiance; uniform float near_clip; uniform float far_clip; @@ -58,16 +57,65 @@ uniform float sun_wash; uniform int proj_shadow_idx; uniform float shadow_fade; -VARYING vec4 vary_light; +uniform float size; +uniform vec3 color; +uniform float falloff; +VARYING vec3 trans_center; VARYING vec4 vary_fragcoord; uniform vec2 screen_res; uniform mat4 inv_proj; +vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod) +{ + vec4 ret = texture2DLod(projectionMap, tc, lod); + + vec2 dist = tc-vec2(0.5); + + float det = max(1.0-lod/(proj_lod*0.5), 0.0); + + float d = dot(dist,dist); + + ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0)+det, 1.0); + + return ret; +} + +vec4 texture2DLodDiffuse(sampler2D projectionMap, vec2 tc, float lod) +{ + vec4 ret = texture2DLod(projectionMap, tc, lod); + + vec2 dist = vec2(0.5) - abs(tc-vec2(0.5)); + + float det = min(lod/(proj_lod*0.5), 1.0); + + float d = min(dist.x, dist.y); + + float edge = 0.25*det; + + ret *= clamp(d/edge, 0.0, 1.0); + + return ret; +} + +vec4 texture2DLodAmbient(sampler2D projectionMap, vec2 tc, float lod) +{ + vec4 ret = texture2DLod(projectionMap, tc, lod); + + vec2 dist = tc-vec2(0.5); + + float d = dot(dist,dist); + + ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0), 1.0); + + return ret; +} + + vec4 getPosition(vec2 pos_screen) { - float depth = texture2DRect(depthMap, pos_screen.xy).a; + float depth = texture2DRect(depthMap, pos_screen.xy).r; vec2 sc = pos_screen.xy*2.0; sc /= screen_res; sc -= vec2(1.0,1.0); @@ -85,6 +133,15 @@ void main() frag.xyz = frag.xyz*0.5+0.5; frag.xy *= screen_res; + vec3 pos = getPosition(frag.xy).xyz; + vec3 lv = trans_center.xyz-pos.xyz; + float dist2 = dot(lv,lv); + dist2 /= size; + if (dist2 > 1.0) + { + discard; + } + float shadow = 1.0; if (proj_shadow_idx >= 0) @@ -96,15 +153,6 @@ void main() shadow = min(sh[proj_shadow_idx]+shadow_fade, 1.0); } - vec3 pos = getPosition(frag.xy).xyz; - vec3 lv = vary_light.xyz-pos.xyz; - float dist2 = dot(lv,lv); - dist2 /= vary_light.w; - if (dist2 > 1.0) - { - discard; - } - vec3 norm = texture2DRect(normalMap, frag.xy).xyz; norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm @@ -119,8 +167,12 @@ void main() proj_tc.xyz /= proj_tc.w; - float fa = vertex_color.a+1.0; - float dist_atten = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); + float fa = falloff+1.0; + float dist_atten = min(1.0-(dist2-1.0*(1.0-fa))/fa, 1.0); + if (dist_atten <= 0.0) + { + discard; + } lv = proj_origin-pos.xyz; lv = normalize(lv); @@ -138,37 +190,33 @@ void main() proj_tc.y > 0.0) { float lit = 0.0; + float amb_da = proj_ambiance; + if (da > 0.0) { float diff = clamp((l_dist-proj_focus)/proj_range, 0.0, 1.0); float lod = diff * proj_lod; - vec4 plcol = texture2DLod(projectionMap, proj_tc.xy, lod); + vec4 plcol = texture2DLodDiffuse(projectionMap, proj_tc.xy, lod); - vec3 lcol = vertex_color.rgb * plcol.rgb * plcol.a; + vec3 lcol = color.rgb * plcol.rgb * plcol.a; lit = da * dist_atten * noise; col = lcol*lit*diff_tex*shadow; - } - - float diff = clamp((proj_range-proj_focus)/proj_range, 0.0, 1.0); - float lod = diff * proj_lod; - vec4 amb_plcol = texture2DLod(projectionMap, proj_tc.xy, lod); - //float amb_da = mix(proj_ambiance, proj_ambiance*max(-da, 0.0), max(da, 0.0)); - float amb_da = proj_ambiance; - if (da > 0.0) - { amb_da += (da*0.5)*(1.0-shadow)*proj_ambiance; } + //float diff = clamp((proj_range-proj_focus)/proj_range, 0.0, 1.0); + vec4 amb_plcol = texture2DLodAmbient(projectionMap, proj_tc.xy, proj_lod); + amb_da += (da*da*0.5+0.5)*proj_ambiance; - + amb_da *= dist_atten * noise; - + amb_da = min(amb_da, 1.0-lit); - - col += amb_da*vertex_color.rgb*diff_tex.rgb*amb_plcol.rgb*amb_plcol.a; + + col += amb_da*color.rgb*diff_tex.rgb*amb_plcol.rgb*amb_plcol.a; } @@ -185,19 +233,23 @@ void main() { vec3 pfinal = pos + ref * dot(pdelta, proj_n)/ds; - vec3 stc = (proj_mat * vec4(pfinal.xyz, 1.0)).xyz; + vec4 stc = (proj_mat * vec4(pfinal.xyz, 1.0)); if (stc.z > 0.0) { - stc.xy /= stc.z+proj_near; - + stc.xy /= stc.w; + + float fatten = clamp(spec.a*spec.a+spec.a*0.5, 0.25, 1.0); + + stc.xy = (stc.xy - vec2(0.5)) * fatten + vec2(0.5); + if (stc.x < 1.0 && stc.y < 1.0 && stc.x > 0.0 && stc.y > 0.0) { - vec4 scol = texture2DLod(projectionMap, stc.xy, proj_lod-spec.a*proj_lod); - col += dist_atten*scol.rgb*vertex_color.rgb*scol.a*spec.rgb*shadow; + vec4 scol = texture2DLodSpecular(projectionMap, stc.xy, proj_lod-spec.a*proj_lod); + col += dist_atten*scol.rgb*color.rgb*scol.a*spec.rgb*shadow; } } } diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt index e8a109e661..eeb632acaf 100644 --- a/indra/newview/featuretable.txt +++ b/indra/newview/featuretable.txt @@ -520,6 +520,7 @@ Disregard128DefaultDrawDistance 1 0 list ATIOldDriver RenderAvatarVP 0 0 RenderAvatarCloth 0 0 +RenderVBOEnable 1 0 // ATI cards generally perform better when not using VBOs for streaming data diff --git a/indra/newview/featuretable_xp.txt b/indra/newview/featuretable_xp.txt index 398a64378e..a945f7a693 100644 --- a/indra/newview/featuretable_xp.txt +++ b/indra/newview/featuretable_xp.txt @@ -517,6 +517,7 @@ Disregard128DefaultDrawDistance 1 0 list ATIOldDriver RenderAvatarVP 0 0 RenderAvatarCloth 0 0 +RenderVBOEnable 1 0 // ATI cards generally perform better when not using VBOs for streaming data diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 3367604753..a6776d4c8d 100755 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -81,6 +81,7 @@ #include "llviewermenu.h" #include "llviewerobjectlist.h" #include "llviewerparcelmgr.h" +#include "llviewerregion.h" #include "llviewerstats.h" #include "llviewerwindow.h" #include "llvoavatarself.h" @@ -112,6 +113,105 @@ const F32 MAX_FIDGET_TIME = 20.f; // seconds // The agent instance. LLAgent gAgent; +class LLTeleportRequest +{ +public: + enum EStatus + { + kPending, + kStarted, + kFailed, + kRestartPending + }; + + LLTeleportRequest(); + virtual ~LLTeleportRequest(); + + EStatus getStatus() const {return mStatus;}; + void setStatus(EStatus pStatus) {mStatus = pStatus;}; + + virtual bool canRestartTeleport(); + + virtual void startTeleport() = 0; + virtual void restartTeleport(); + +protected: + +private: + EStatus mStatus; +}; + +class LLTeleportRequestViaLandmark : public LLTeleportRequest +{ +public: + LLTeleportRequestViaLandmark(const LLUUID &pLandmarkId); + virtual ~LLTeleportRequestViaLandmark(); + + virtual bool canRestartTeleport(); + + virtual void startTeleport(); + virtual void restartTeleport(); + +protected: + inline const LLUUID &getLandmarkId() const {return mLandmarkId;}; + +private: + LLUUID mLandmarkId; +}; + +class LLTeleportRequestViaLure : public LLTeleportRequestViaLandmark +{ +public: + LLTeleportRequestViaLure(const LLUUID &pLureId, BOOL pIsLureGodLike); + virtual ~LLTeleportRequestViaLure(); + + virtual bool canRestartTeleport(); + + virtual void startTeleport(); + +protected: + inline BOOL isLureGodLike() const {return mIsLureGodLike;}; + +private: + BOOL mIsLureGodLike; +}; + +class LLTeleportRequestViaLocation : public LLTeleportRequest +{ +public: + LLTeleportRequestViaLocation(const LLVector3d &pPosGlobal); + virtual ~LLTeleportRequestViaLocation(); + + virtual bool canRestartTeleport(); + + virtual void startTeleport(); + virtual void restartTeleport(); + +protected: + inline const LLVector3d &getPosGlobal() const {return mPosGlobal;}; + +private: + LLVector3d mPosGlobal; +}; + + +class LLTeleportRequestViaLocationLookAt : public LLTeleportRequestViaLocation +{ +public: + LLTeleportRequestViaLocationLookAt(const LLVector3d &pPosGlobal); + virtual ~LLTeleportRequestViaLocationLookAt(); + + virtual bool canRestartTeleport(); + + virtual void startTeleport(); + virtual void restartTeleport(); + +protected: + +private: + +}; + //-------------------------------------------------------------------- // Statics // @@ -245,6 +345,17 @@ LLAgent::LLAgent() : mAgentAccess(new LLAgentAccess(gSavedSettings)), mCanEditParcel(false), mTeleportSourceSLURL(new LLSLURL), + mTeleportRequest(), + mTeleportFinishedSlot(), + mTeleportFailedSlot(), + mIsMaturityRatingChangingDuringTeleport(false), + mMaturityRatingChange(0U), + mIsDoSendMaturityPreferenceToServer(false), + mMaturityPreferenceRequestId(0U), + mMaturityPreferenceResponseId(0U), + mMaturityPreferenceNumRetries(0U), + mLastKnownRequestMaturity(SIM_ACCESS_MIN), + mLastKnownResponseMaturity(SIM_ACCESS_MIN), mTeleportState( TELEPORT_NONE ), mRegionp(NULL), @@ -330,9 +441,21 @@ void LLAgent::init() gSavedSettings.getControl("PreferredMaturity")->getValidateSignal()->connect(boost::bind(&LLAgent::validateMaturity, this, _2)); gSavedSettings.getControl("PreferredMaturity")->getSignal()->connect(boost::bind(&LLAgent::handleMaturity, this, _2)); + mLastKnownResponseMaturity = static_cast<U8>(gSavedSettings.getU32("PreferredMaturity")); + mLastKnownRequestMaturity = mLastKnownResponseMaturity; + mIsDoSendMaturityPreferenceToServer = true; LLViewerParcelMgr::getInstance()->addAgentParcelChangedCallback(boost::bind(&LLAgent::parcelChangedCallback)); + if (!mTeleportFinishedSlot.connected()) + { + mTeleportFinishedSlot = LLViewerParcelMgr::getInstance()->setTeleportFinishedCallback(boost::bind(&LLAgent::handleTeleportFinished, this)); + } + if (!mTeleportFailedSlot.connected()) + { + mTeleportFailedSlot = LLViewerParcelMgr::getInstance()->setTeleportFailedCallback(boost::bind(&LLAgent::handleTeleportFailed, this)); + } + mInitialized = TRUE; } @@ -342,6 +465,14 @@ void LLAgent::init() void LLAgent::cleanup() { mRegionp = NULL; + if (mTeleportFinishedSlot.connected()) + { + mTeleportFinishedSlot.disconnect(); + } + if (mTeleportFailedSlot.connected()) + { + mTeleportFailedSlot.disconnect(); + } } //----------------------------------------------------------------------------- @@ -2371,49 +2502,278 @@ bool LLAgent::isAdult() const return mAgentAccess->isAdult(); } -void LLAgent::setTeen(bool teen) -{ - mAgentAccess->setTeen(teen); -} - //static int LLAgent::convertTextToMaturity(char text) { return LLAgentAccess::convertTextToMaturity(text); } -bool LLAgent::sendMaturityPreferenceToServer(int preferredMaturity) +class LLMaturityPreferencesResponder : public LLHTTPClient::Responder { - if (!getRegion()) - return false; +public: + LLMaturityPreferencesResponder(LLAgent *pAgent, U8 pPreferredMaturity, U8 pPreviousMaturity); + virtual ~LLMaturityPreferencesResponder(); + + virtual void result(const LLSD &pContent); + virtual void error(U32 pStatus, const std::string& pReason); + +protected: + +private: + U8 parseMaturityFromServerResponse(const LLSD &pContent); + + LLAgent *mAgent; + U8 mPreferredMaturity; + U8 mPreviousMaturity; +}; + +LLMaturityPreferencesResponder::LLMaturityPreferencesResponder(LLAgent *pAgent, U8 pPreferredMaturity, U8 pPreviousMaturity) + : LLHTTPClient::Responder(), + mAgent(pAgent), + mPreferredMaturity(pPreferredMaturity), + mPreviousMaturity(pPreviousMaturity) +{ +} + +LLMaturityPreferencesResponder::~LLMaturityPreferencesResponder() +{ +} + +void LLMaturityPreferencesResponder::result(const LLSD &pContent) +{ + U8 actualMaturity = parseMaturityFromServerResponse(pContent); + + if (actualMaturity != mPreferredMaturity) + { + llwarns << "while attempting to change maturity preference from '" << LLViewerRegion::accessToString(mPreviousMaturity) + << "' to '" << LLViewerRegion::accessToString(mPreferredMaturity) << "', the server responded with '" + << LLViewerRegion::accessToString(actualMaturity) << "' [value:" << static_cast<U32>(actualMaturity) << ", llsd:" + << pContent << "]" << llendl; + } + mAgent->handlePreferredMaturityResult(actualMaturity); +} + +void LLMaturityPreferencesResponder::error(U32 pStatus, const std::string& pReason) +{ + llwarns << "while attempting to change maturity preference from '" << LLViewerRegion::accessToString(mPreviousMaturity) + << "' to '" << LLViewerRegion::accessToString(mPreferredMaturity) << "', we got an error because '" + << pReason << "' [status:" << pStatus << "]" << llendl; + mAgent->handlePreferredMaturityError(); +} + +U8 LLMaturityPreferencesResponder::parseMaturityFromServerResponse(const LLSD &pContent) +{ + // stinson 05/24/2012 Pathfinding regions have re-defined the response behavior. In the old server code, + // if you attempted to change the preferred maturity to the same value, the response content would be an + // undefined LLSD block. In the new server code with pathfinding, the response content should always be + // defined. Thus, the check for isUndefined() can be replaced with an assert after pathfinding is merged + // into server trunk and fully deployed. + U8 maturity = SIM_ACCESS_MIN; + if (pContent.isUndefined()) + { + maturity = mPreferredMaturity; + } + else + { + llassert(!pContent.isUndefined()); + llassert(pContent.isMap()); - // Update agent access preference on the server - std::string url = getRegion()->getCapability("UpdateAgentInformation"); - if (!url.empty()) + if (!pContent.isUndefined() && pContent.isMap()) + { + // stinson 05/24/2012 Pathfinding regions have re-defined the response syntax. The if statement catches + // the new syntax, and the else statement catches the old syntax. After pathfinding is merged into + // server trunk and fully deployed, we can remove the else statement. + if (pContent.has("access_prefs")) + { + llassert(pContent.has("access_prefs")); + llassert(pContent.get("access_prefs").isMap()); + llassert(pContent.get("access_prefs").has("max")); + llassert(pContent.get("access_prefs").get("max").isString()); + if (pContent.get("access_prefs").isMap() && pContent.get("access_prefs").has("max") && + pContent.get("access_prefs").get("max").isString()) + { + LLSD::String actualPreference = pContent.get("access_prefs").get("max").asString(); + LLStringUtil::trim(actualPreference); + maturity = LLViewerRegion::shortStringToAccess(actualPreference); + } + } + else if (pContent.has("max")) + { + llassert(pContent.get("max").isString()); + if (pContent.get("max").isString()) + { + LLSD::String actualPreference = pContent.get("max").asString(); + LLStringUtil::trim(actualPreference); + maturity = LLViewerRegion::shortStringToAccess(actualPreference); + } + } + } + } + + return maturity; +} + +void LLAgent::handlePreferredMaturityResult(U8 pServerMaturity) +{ + // Update the number of responses received + ++mMaturityPreferenceResponseId; + llassert(mMaturityPreferenceResponseId <= mMaturityPreferenceRequestId); + + // Update the last known server maturity response + mLastKnownResponseMaturity = pServerMaturity; + + // Ignore all responses if we know there are more unanswered requests that are expected + if (mMaturityPreferenceResponseId == mMaturityPreferenceRequestId) { - // Set new access preference - LLSD access_prefs = LLSD::emptyMap(); - if (preferredMaturity == SIM_ACCESS_PG) + // If we received a response that matches the last known request, then we are good + if (mLastKnownRequestMaturity == mLastKnownResponseMaturity) { - access_prefs["max"] = "PG"; + mMaturityPreferenceNumRetries = 0; + reportPreferredMaturitySuccess(); + llassert(static_cast<U8>(gSavedSettings.getU32("PreferredMaturity")) == mLastKnownResponseMaturity); } - else if (preferredMaturity == SIM_ACCESS_MATURE) + // Else, the viewer is out of sync with the server, so let's try to re-sync with the + // server by re-sending our last known request. Cap the re-tries at 3 just to be safe. + else if (++mMaturityPreferenceNumRetries <= 3) { - access_prefs["max"] = "M"; + llinfos << "Retrying attempt #" << mMaturityPreferenceNumRetries << " to set viewer preferred maturity to '" + << LLViewerRegion::accessToString(mLastKnownRequestMaturity) << "'" << llendl; + sendMaturityPreferenceToServer(mLastKnownRequestMaturity); } - if (preferredMaturity == SIM_ACCESS_ADULT) + // Else, the viewer is style out of sync with the server after 3 retries, so inform the user + else { - access_prefs["max"] = "A"; + mMaturityPreferenceNumRetries = 0; + reportPreferredMaturityError(); + } + } +} + +void LLAgent::handlePreferredMaturityError() +{ + // Update the number of responses received + ++mMaturityPreferenceResponseId; + llassert(mMaturityPreferenceResponseId <= mMaturityPreferenceRequestId); + + // Ignore all responses if we know there are more unanswered requests that are expected + if (mMaturityPreferenceResponseId == mMaturityPreferenceRequestId) + { + mMaturityPreferenceNumRetries = 0; + + // If we received a response that matches the last known request, then we are synced with + // the server, but not quite sure why we are + if (mLastKnownRequestMaturity == mLastKnownResponseMaturity) + { + llwarns << "Got an error but maturity preference '" << LLViewerRegion::accessToString(mLastKnownRequestMaturity) + << "' seems to be in sync with the server" << llendl; + reportPreferredMaturitySuccess(); + } + // Else, the more likely case is that the last request does not match the last response, + // so inform the user + else + { + reportPreferredMaturityError(); + } + } +} + +void LLAgent::reportPreferredMaturitySuccess() +{ + // If there is a pending teleport request waiting for the maturity preference to be synced with + // the server, let's start the pending request + if (hasPendingTeleportRequest()) + { + startTeleportRequest(); + } +} + +void LLAgent::reportPreferredMaturityError() +{ + // If there is a pending teleport request waiting for the maturity preference to be synced with + // the server, we were unable to successfully sync with the server on maturity preference, so let's + // just raise the screen. + mIsMaturityRatingChangingDuringTeleport = false; + if (hasPendingTeleportRequest()) + { + setTeleportState(LLAgent::TELEPORT_NONE); + } + + // Get the last known maturity request from the user activity + std::string preferredMaturity = LLViewerRegion::accessToString(mLastKnownRequestMaturity); + LLStringUtil::toLower(preferredMaturity); + + // Get the last known maturity response from the server + std::string actualMaturity = LLViewerRegion::accessToString(mLastKnownResponseMaturity); + LLStringUtil::toLower(actualMaturity); + + // Notify the user + LLSD args = LLSD::emptyMap(); + args["PREFERRED_MATURITY"] = preferredMaturity; + args["ACTUAL_MATURITY"] = actualMaturity; + LLNotificationsUtil::add("MaturityChangeError", args); + + // Check the saved settings to ensure that we are consistent. If we are not consistent, update + // the viewer, but do not send anything to server + U8 localMaturity = static_cast<U8>(gSavedSettings.getU32("PreferredMaturity")); + if (localMaturity != mLastKnownResponseMaturity) + { + bool tmpIsDoSendMaturityPreferenceToServer = mIsDoSendMaturityPreferenceToServer; + mIsDoSendMaturityPreferenceToServer = false; + llinfos << "Setting viewer preferred maturity to '" << LLViewerRegion::accessToString(mLastKnownResponseMaturity) << "'" << llendl; + gSavedSettings.setU32("PreferredMaturity", static_cast<U32>(mLastKnownResponseMaturity)); + mIsDoSendMaturityPreferenceToServer = tmpIsDoSendMaturityPreferenceToServer; + } +} + +bool LLAgent::isMaturityPreferenceSyncedWithServer() const +{ + return (mMaturityPreferenceRequestId == mMaturityPreferenceResponseId); +} + +void LLAgent::sendMaturityPreferenceToServer(U8 pPreferredMaturity) +{ + // Only send maturity preference to the server if enabled + if (mIsDoSendMaturityPreferenceToServer) + { + // Increment the number of requests. The handlers manage a separate count of responses. + ++mMaturityPreferenceRequestId; + + // Update the last know maturity request + mLastKnownRequestMaturity = pPreferredMaturity; + + // Create a response handler + LLHTTPClient::ResponderPtr responderPtr = LLHTTPClient::ResponderPtr(new LLMaturityPreferencesResponder(this, pPreferredMaturity, mLastKnownResponseMaturity)); + + // If we don't have a region, report it as an error + if (getRegion() == NULL) + { + responderPtr->error(0U, "region is not defined"); + } + else + { + // Find the capability to send maturity preference + std::string url = getRegion()->getCapability("UpdateAgentInformation"); + + // If the capability is not defined, report it as an error + if (url.empty()) + { + responderPtr->error(0U, "capability 'UpdateAgentInformation' is not defined for region"); + } + else + { + // Set new access preference + LLSD access_prefs = LLSD::emptyMap(); + access_prefs["max"] = LLViewerRegion::accessToShortString(pPreferredMaturity); + + LLSD body = LLSD::emptyMap(); + body["access_prefs"] = access_prefs; + llinfos << "Sending viewer preferred maturity to '" << LLViewerRegion::accessToString(pPreferredMaturity) + << "' via capability to: " << url << llendl; + LLSD headers; + LLHTTPClient::post(url, body, responderPtr, headers, 30.0f); + } } - - LLSD body = LLSD::emptyMap(); - body["access_prefs"] = access_prefs; - llinfos << "Sending access prefs update to " << (access_prefs["max"].asString()) << " via capability to: " - << url << llendl; - LLHTTPClient::post(url, body, new LLHTTPClient::Responder()); // Ignore response - return true; } - return false; } BOOL LLAgent::getAdminOverride() const @@ -2436,11 +2796,6 @@ void LLAgent::setGodLevel(U8 god_level) mAgentAccess->setGodLevel(god_level); } -void LLAgent::setAOTransition() -{ - mAgentAccess->setTransition(); -} - const LLAgentAccess& LLAgent::getAgentAccess() { return *mAgentAccess; @@ -2451,9 +2806,9 @@ bool LLAgent::validateMaturity(const LLSD& newvalue) return mAgentAccess->canSetMaturity(newvalue.asInteger()); } -void LLAgent::handleMaturity(const LLSD& newvalue) +void LLAgent::handleMaturity(const LLSD &pNewValue) { - sendMaturityPreferenceToServer(newvalue.asInteger()); + sendMaturityPreferenceToServer(static_cast<U8>(pNewValue.asInteger())); } //---------------------------------------------------------------------------- @@ -3388,7 +3743,7 @@ void LLAgent::clearVisualParams(void *data) // protected bool LLAgent::teleportCore(bool is_local) { - if(TELEPORT_NONE != mTeleportState) + if ((TELEPORT_NONE != mTeleportState) && (mTeleportState != TELEPORT_PENDING)) { llwarns << "Attempt to teleport when already teleporting." << llendl; return false; @@ -3466,6 +3821,102 @@ bool LLAgent::teleportCore(bool is_local) return true; } +bool LLAgent::hasRestartableFailedTeleportRequest() +{ + return ((mTeleportRequest != NULL) && (mTeleportRequest->getStatus() == LLTeleportRequest::kFailed) && + mTeleportRequest->canRestartTeleport()); +} + +void LLAgent::restartFailedTeleportRequest() +{ + if (hasRestartableFailedTeleportRequest()) + { + mTeleportRequest->setStatus(LLTeleportRequest::kRestartPending); + startTeleportRequest(); + } +} + +void LLAgent::clearTeleportRequest() +{ + mTeleportRequest.reset(); +} + +void LLAgent::setMaturityRatingChangeDuringTeleport(U8 pMaturityRatingChange) +{ + mIsMaturityRatingChangingDuringTeleport = true; + mMaturityRatingChange = pMaturityRatingChange; +} + +bool LLAgent::hasPendingTeleportRequest() +{ + return ((mTeleportRequest != NULL) && + ((mTeleportRequest->getStatus() == LLTeleportRequest::kPending) || + (mTeleportRequest->getStatus() == LLTeleportRequest::kRestartPending))); +} + +void LLAgent::startTeleportRequest() +{ + if (hasPendingTeleportRequest()) + { + if (!isMaturityPreferenceSyncedWithServer()) + { + gTeleportDisplay = TRUE; + setTeleportState(TELEPORT_PENDING); + } + else + { + switch (mTeleportRequest->getStatus()) + { + case LLTeleportRequest::kPending : + mTeleportRequest->setStatus(LLTeleportRequest::kStarted); + mTeleportRequest->startTeleport(); + break; + case LLTeleportRequest::kRestartPending : + llassert(mTeleportRequest->canRestartTeleport()); + mTeleportRequest->setStatus(LLTeleportRequest::kStarted); + mTeleportRequest->restartTeleport(); + break; + default : + llassert(0); + break; + } + } + } +} + +void LLAgent::handleTeleportFinished() +{ + clearTeleportRequest(); + if (mIsMaturityRatingChangingDuringTeleport) + { + // notify user that the maturity preference has been changed + std::string maturityRating = LLViewerRegion::accessToString(mMaturityRatingChange); + LLStringUtil::toLower(maturityRating); + LLSD args; + args["RATING"] = maturityRating; + LLNotificationsUtil::add("PreferredMaturityChanged", args); + mIsMaturityRatingChangingDuringTeleport = false; + } +} + +void LLAgent::handleTeleportFailed() +{ + if (mTeleportRequest != NULL) + { + mTeleportRequest->setStatus(LLTeleportRequest::kFailed); + } + if (mIsMaturityRatingChangingDuringTeleport) + { + // notify user that the maturity preference has been changed + std::string maturityRating = LLViewerRegion::accessToString(mMaturityRatingChange); + LLStringUtil::toLower(maturityRating); + LLSD args; + args["RATING"] = maturityRating; + LLNotificationsUtil::add("PreferredMaturityChanged", args); + mIsMaturityRatingChangingDuringTeleport = false; + } +} + void LLAgent::teleportRequest( const U64& region_handle, const LLVector3& pos_local, @@ -3498,6 +3949,12 @@ void LLAgent::teleportRequest( // Landmark ID = LLUUID::null means teleport home void LLAgent::teleportViaLandmark(const LLUUID& landmark_asset_id) { + mTeleportRequest = LLTeleportRequestPtr(new LLTeleportRequestViaLandmark(landmark_asset_id)); + startTeleportRequest(); +} + +void LLAgent::doTeleportViaLandmark(const LLUUID& landmark_asset_id) +{ LLViewerRegion *regionp = getRegion(); if(regionp && teleportCore()) { @@ -3513,6 +3970,12 @@ void LLAgent::teleportViaLandmark(const LLUUID& landmark_asset_id) void LLAgent::teleportViaLure(const LLUUID& lure_id, BOOL godlike) { + mTeleportRequest = LLTeleportRequestPtr(new LLTeleportRequestViaLure(lure_id, godlike)); + startTeleportRequest(); +} + +void LLAgent::doTeleportViaLure(const LLUUID& lure_id, BOOL godlike) +{ LLViewerRegion* regionp = getRegion(); if(regionp && teleportCore()) { @@ -3544,24 +4007,33 @@ void LLAgent::teleportViaLure(const LLUUID& lure_id, BOOL godlike) // James Cook, July 28, 2005 void LLAgent::teleportCancel() { - LLViewerRegion* regionp = getRegion(); - if(regionp) + if (!hasPendingTeleportRequest()) { - // send the message - LLMessageSystem* msg = gMessageSystem; - msg->newMessage("TeleportCancel"); - msg->nextBlockFast(_PREHASH_Info); - msg->addUUIDFast(_PREHASH_AgentID, getID()); - msg->addUUIDFast(_PREHASH_SessionID, getSessionID()); - sendReliableMessage(); - } - gTeleportDisplay = FALSE; + LLViewerRegion* regionp = getRegion(); + if(regionp) + { + // send the message + LLMessageSystem* msg = gMessageSystem; + msg->newMessage("TeleportCancel"); + msg->nextBlockFast(_PREHASH_Info); + msg->addUUIDFast(_PREHASH_AgentID, getID()); + msg->addUUIDFast(_PREHASH_SessionID, getSessionID()); + sendReliableMessage(); + } + } + clearTeleportRequest(); gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); } void LLAgent::teleportViaLocation(const LLVector3d& pos_global) { + mTeleportRequest = LLTeleportRequestPtr(new LLTeleportRequestViaLocation(pos_global)); + startTeleportRequest(); +} + +void LLAgent::doTeleportViaLocation(const LLVector3d& pos_global) +{ LLViewerRegion* regionp = getRegion(); U64 handle = to_region_handle(pos_global); LLSimInfo* info = LLWorldMap::getInstance()->simInfoFromHandle(handle); @@ -3604,6 +4076,12 @@ void LLAgent::teleportViaLocation(const LLVector3d& pos_global) // Teleport to global position, but keep facing in the same direction void LLAgent::teleportViaLocationLookAt(const LLVector3d& pos_global) { + mTeleportRequest = LLTeleportRequestPtr(new LLTeleportRequestViaLocationLookAt(pos_global)); + startTeleportRequest(); +} + +void LLAgent::doTeleportViaLocationLookAt(const LLVector3d& pos_global) +{ mbTeleportKeepsLookAt = true; gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); // detach camera form avatar, so it keeps direction U64 region_handle = to_region_handle(pos_global); @@ -4045,5 +4523,149 @@ LLAgentQueryManager::~LLAgentQueryManager() { } -// EOF +//----------------------------------------------------------------------------- +// LLTeleportRequest +//----------------------------------------------------------------------------- + +LLTeleportRequest::LLTeleportRequest() + : mStatus(kPending) +{ +} + +LLTeleportRequest::~LLTeleportRequest() +{ +} +bool LLTeleportRequest::canRestartTeleport() +{ + return false; +} + +void LLTeleportRequest::restartTeleport() +{ + llassert(0); +} + +//----------------------------------------------------------------------------- +// LLTeleportRequestViaLandmark +//----------------------------------------------------------------------------- + +LLTeleportRequestViaLandmark::LLTeleportRequestViaLandmark(const LLUUID &pLandmarkId) + : LLTeleportRequest(), + mLandmarkId(pLandmarkId) +{ +} + +LLTeleportRequestViaLandmark::~LLTeleportRequestViaLandmark() +{ +} + +bool LLTeleportRequestViaLandmark::canRestartTeleport() +{ + return true; +} + +void LLTeleportRequestViaLandmark::startTeleport() +{ + gAgent.doTeleportViaLandmark(getLandmarkId()); +} + +void LLTeleportRequestViaLandmark::restartTeleport() +{ + gAgent.doTeleportViaLandmark(getLandmarkId()); +} + +//----------------------------------------------------------------------------- +// LLTeleportRequestViaLure +//----------------------------------------------------------------------------- + +LLTeleportRequestViaLure::LLTeleportRequestViaLure(const LLUUID &pLureId, BOOL pIsLureGodLike) + : LLTeleportRequestViaLandmark(pLureId), + mIsLureGodLike(pIsLureGodLike) +{ +} + +LLTeleportRequestViaLure::~LLTeleportRequestViaLure() +{ +} + +bool LLTeleportRequestViaLure::canRestartTeleport() +{ + // stinson 05/17/2012 : cannot restart a teleport via lure because of server-side restrictions + // The current scenario is as follows: + // 1. User A initializes a request for User B to teleport via lure + // 2. User B accepts the teleport via lure request + // 3. The server sees the init request from User A and the accept request from User B and matches them up + // 4. The server then removes the paired requests up from the "queue" + // 5. The server then fails User B's teleport for reason of maturity level (for example) + // 6. User B's viewer prompts user to increase their maturity level profile value. + // 7. User B confirms and accepts increase in maturity level + // 8. User B's viewer then attempts to teleport via lure again + // 9. This request will time-out on the viewer-side because User A's initial request has been removed from the "queue" in step 4 + + return false; +} + +void LLTeleportRequestViaLure::startTeleport() +{ + gAgent.doTeleportViaLure(getLandmarkId(), isLureGodLike()); +} + +//----------------------------------------------------------------------------- +// LLTeleportRequestViaLocation +//----------------------------------------------------------------------------- + +LLTeleportRequestViaLocation::LLTeleportRequestViaLocation(const LLVector3d &pPosGlobal) + : LLTeleportRequest(), + mPosGlobal(pPosGlobal) +{ +} + +LLTeleportRequestViaLocation::~LLTeleportRequestViaLocation() +{ +} + +bool LLTeleportRequestViaLocation::canRestartTeleport() +{ + return true; +} + +void LLTeleportRequestViaLocation::startTeleport() +{ + gAgent.doTeleportViaLocation(getPosGlobal()); +} + +void LLTeleportRequestViaLocation::restartTeleport() +{ + gAgent.doTeleportViaLocation(getPosGlobal()); +} + +//----------------------------------------------------------------------------- +// LLTeleportRequestViaLocationLookAt +//----------------------------------------------------------------------------- + +LLTeleportRequestViaLocationLookAt::LLTeleportRequestViaLocationLookAt(const LLVector3d &pPosGlobal) + : LLTeleportRequestViaLocation(pPosGlobal) +{ +} + +LLTeleportRequestViaLocationLookAt::~LLTeleportRequestViaLocationLookAt() +{ +} + +bool LLTeleportRequestViaLocationLookAt::canRestartTeleport() +{ + return true; +} + +void LLTeleportRequestViaLocationLookAt::startTeleport() +{ + gAgent.doTeleportViaLocationLookAt(getPosGlobal()); +} + +void LLTeleportRequestViaLocationLookAt::restartTeleport() +{ + gAgent.doTeleportViaLocationLookAt(getPosGlobal()); +} + +// EOF diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index 740770bbdf..a505d5bbae 100644 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -35,6 +35,8 @@ #include "llcoordframe.h" // for mFrameAgent #include "llvoavatardefines.h" +#include <boost/function.hpp> +#include <boost/shared_ptr.hpp> #include <boost/signals2.hpp> extern const BOOL ANIMATE; @@ -56,6 +58,9 @@ class LLAgentAccess; class LLSLURL; class LLPauseRequestHandle; class LLUIColor; +class LLTeleportRequest; + +typedef boost::shared_ptr<LLTeleportRequest> LLTeleportRequestPtr; //-------------------------------------------------------------------- // Types @@ -539,7 +544,8 @@ public: TELEPORT_MOVING = 3, // Viewer has received destination location from source simulator TELEPORT_START_ARRIVAL = 4, // Transition to ARRIVING. Viewer has received avatar update, etc., from destination simulator TELEPORT_ARRIVING = 5, // Make the user wait while content "pre-caches" - TELEPORT_LOCAL = 6 // Teleporting in-sim without showing the progress screen + TELEPORT_LOCAL = 6, // Teleporting in-sim without showing the progress screen + TELEPORT_PENDING = 7 }; public: @@ -556,9 +562,6 @@ private: // Teleport Actions //-------------------------------------------------------------------- public: - void teleportRequest(const U64& region_handle, - const LLVector3& pos_local, // Go to a named location home - bool look_at_from_camera = false); void teleportViaLandmark(const LLUUID& landmark_id); // Teleport to a landmark void teleportHome() { teleportViaLandmark(LLUUID::null); } // Go home void teleportViaLure(const LLUUID& lure_id, BOOL godlike); // To an invited location @@ -572,6 +575,44 @@ protected: //-------------------------------------------------------------------- // Teleport State //-------------------------------------------------------------------- + +public: + bool hasRestartableFailedTeleportRequest(); + void restartFailedTeleportRequest(); + void clearTeleportRequest(); + void setMaturityRatingChangeDuringTeleport(U8 pMaturityRatingChange); + +private: + friend class LLTeleportRequest; + friend class LLTeleportRequestViaLandmark; + friend class LLTeleportRequestViaLure; + friend class LLTeleportRequestViaLocation; + friend class LLTeleportRequestViaLocationLookAt; + + LLTeleportRequestPtr mTeleportRequest; + boost::signals2::connection mTeleportFinishedSlot; + boost::signals2::connection mTeleportFailedSlot; + + bool mIsMaturityRatingChangingDuringTeleport; + U8 mMaturityRatingChange; + + bool hasPendingTeleportRequest(); + void startTeleportRequest(); + + void teleportRequest(const U64& region_handle, + const LLVector3& pos_local, // Go to a named location home + bool look_at_from_camera = false); + void doTeleportViaLandmark(const LLUUID& landmark_id); // Teleport to a landmark + void doTeleportViaLure(const LLUUID& lure_id, BOOL godlike); // To an invited location + void doTeleportViaLocation(const LLVector3d& pos_global); // To a global location - this will probably need to be deprecated + void doTeleportViaLocationLookAt(const LLVector3d& pos_global);// To a global location, preserving camera rotation + + void handleTeleportFinished(); + void handleTeleportFailed(); + + //-------------------------------------------------------------------- + // Teleport State + //-------------------------------------------------------------------- public: ETeleportState getTeleportState() const { return mTeleportState; } void setTeleportState(ETeleportState state); @@ -614,8 +655,6 @@ public: const LLAgentAccess& getAgentAccess(); BOOL canManageEstate() const; BOOL getAdminOverride() const; - // ! BACKWARDS COMPATIBILITY ! This function can go away after the AO transition (see llstartup.cpp). - void setAOTransition(); private: LLAgentAccess * mAgentAccess; @@ -650,13 +689,28 @@ public: bool isTeen() const; bool isMature() const; bool isAdult() const; - void setTeen(bool teen); void setMaturity(char text); - static int convertTextToMaturity(char text); - bool sendMaturityPreferenceToServer(int preferredMaturity); // ! "U8" instead of "int"? + static int convertTextToMaturity(char text); + +private: + bool mIsDoSendMaturityPreferenceToServer; + unsigned int mMaturityPreferenceRequestId; + unsigned int mMaturityPreferenceResponseId; + unsigned int mMaturityPreferenceNumRetries; + U8 mLastKnownRequestMaturity; + U8 mLastKnownResponseMaturity; + + bool isMaturityPreferenceSyncedWithServer() const; + void sendMaturityPreferenceToServer(U8 pPreferredMaturity); + + friend class LLMaturityPreferencesResponder; + void handlePreferredMaturityResult(U8 pServerMaturity); + void handlePreferredMaturityError(); + void reportPreferredMaturitySuccess(); + void reportPreferredMaturityError(); // Maturity callbacks for PreferredMaturity control variable - void handleMaturity(const LLSD& newvalue); + void handleMaturity(const LLSD &pNewValue); bool validateMaturity(const LLSD& newvalue); diff --git a/indra/newview/llagentaccess.cpp b/indra/newview/llagentaccess.cpp index 08a33ab04a..c4ee321e04 100644 --- a/indra/newview/llagentaccess.cpp +++ b/indra/newview/llagentaccess.cpp @@ -33,8 +33,7 @@ LLAgentAccess::LLAgentAccess(LLControlGroup& savedSettings) : mSavedSettings(savedSettings), mAccess(SIM_ACCESS_PG), mAdminOverride(false), - mGodLevel(GOD_NOT), - mAOTransition(false) + mGodLevel(GOD_NOT) { } @@ -133,18 +132,6 @@ bool LLAgentAccess::isAdult() const return mAccess >= SIM_ACCESS_ADULT; } -void LLAgentAccess::setTeen(bool teen) -{ - if (teen) - { - mAccess = SIM_ACCESS_PG; - } - else - { - mAccess = SIM_ACCESS_MATURE; - } -} - //static int LLAgentAccess::convertTextToMaturity(char text) { @@ -182,16 +169,6 @@ void LLAgentAccess::setMaturity(char text) mSavedSettings.setU32("PreferredMaturity", preferred_access); } -void LLAgentAccess::setTransition() -{ - mAOTransition = true; -} - -bool LLAgentAccess::isInTransition() const -{ - return mAOTransition; -} - bool LLAgentAccess::canSetMaturity(S32 maturity) { if (isGodlike()) // Gods can always set their Maturity level diff --git a/indra/newview/llagentaccess.h b/indra/newview/llagentaccess.h index 2e98e4eea1..4e851b0aa0 100644 --- a/indra/newview/llagentaccess.h +++ b/indra/newview/llagentaccess.h @@ -59,13 +59,10 @@ public: bool isMature() const; bool isAdult() const; - void setTeen(bool teen); void setMaturity(char text); static int convertTextToMaturity(char text); - void setTransition(); // sets the transition bit, which defaults to false - bool isInTransition() const; bool canSetMaturity(S32 maturity); private: @@ -73,13 +70,6 @@ private: U8 mGodLevel; bool mAdminOverride; - // this should be deleted after the 60-day AO transition. - // It should be safe to remove it in Viewer 2009 - // It's set by a special short-term flag in login.cgi - // called ao_transition. When that's gone, this can go, along with - // all of the code that depends on it. - bool mAOTransition; - LLControlGroup& mSavedSettings; }; diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index ed04b5bf38..efa24796e5 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -94,6 +94,7 @@ #include "llupdaterservice.h" #include "llcallfloater.h" #include "llfloatertexturefetchdebugger.h" +#include "llspellcheck.h" // Linden library includes #include "llavatarnamecache.h" @@ -117,6 +118,7 @@ // Third party library includes #include <boost/bind.hpp> #include <boost/foreach.hpp> +#include <boost/algorithm/string.hpp> @@ -625,6 +627,7 @@ LLAppViewer::LLAppViewer() : mPurgeOnExit(false), mSecondInstance(false), mSavedFinalSnapshot(false), + mSavePerAccountSettings(false), // don't save settings on logout unless login succeeded. mForceGraphicsDetail(false), mQuitRequested(false), mLogoutRequestSent(false), @@ -1162,6 +1165,8 @@ void LLAppViewer::checkMemory() static LLFastTimer::DeclareTimer FTM_MESSAGES("System Messages"); static LLFastTimer::DeclareTimer FTM_SLEEP("Sleep"); +static LLFastTimer::DeclareTimer FTM_YIELD("Yield"); + static LLFastTimer::DeclareTimer FTM_TEXTURE_CACHE("Texture Cache"); static LLFastTimer::DeclareTimer FTM_DECODE("Image Decode"); static LLFastTimer::DeclareTimer FTM_VFS("VFS Thread"); @@ -1347,6 +1352,7 @@ bool LLAppViewer::mainLoop() // yield some time to the os based on command line option if(mYieldTime >= 0) { + LLFastTimer t(FTM_YIELD); ms_sleep(mYieldTime); } @@ -1796,6 +1802,13 @@ bool LLAppViewer::cleanup() { llinfos << "Not saving per-account settings; don't know the account name yet." << llendl; } + // Only save per account settings if the previous login succeeded, otherwise + // we might end up with a cleared out settings file in case a previous login + // failed after loading per account settings. + else if (!mSavePerAccountSettings) + { + llinfos << "Not saving per-account settings; last login was not successful." << llendl; + } else { gSavedPerAccountSettings.saveToFile(gSavedSettings.getString("PerAccountSettingsFile"), TRUE); @@ -2550,6 +2563,19 @@ bool LLAppViewer::initConfiguration() //gDirUtilp->setSkinFolder("default"); } + if (gSavedSettings.getBOOL("SpellCheck")) + { + std::list<std::string> dict_list; + std::string dict_setting = gSavedSettings.getString("SpellCheckDictionary"); + boost::split(dict_list, dict_setting, boost::is_any_of(std::string(","))); + if (!dict_list.empty()) + { + LLSpellChecker::setUseSpellCheck(dict_list.front()); + dict_list.pop_front(); + LLSpellChecker::instance().setSecondaryDictionaries(dict_list); + } + } + mYieldTime = gSavedSettings.getS32("YieldTime"); // Read skin/branding settings if specified. @@ -5009,6 +5035,10 @@ void LLAppViewer::handleLoginComplete() mOnLoginCompleted(); writeDebugInfo(); + + // we logged in successfully, so save settings on logout + llinfos << "Login successful, per account settings will be saved on log out." << llendl; + mSavePerAccountSettings=true; } void LLAppViewer::launchUpdater() diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index f7d019ccba..ae3c795d1e 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -247,6 +247,7 @@ private: bool mPurgeOnExit; bool mSavedFinalSnapshot; + bool mSavePerAccountSettings; // only save per account settings if login succeeded bool mForceGraphicsDetail; diff --git a/indra/newview/llautoreplace.cpp b/indra/newview/llautoreplace.cpp new file mode 100644 index 0000000000..0f1ce2bcd0 --- /dev/null +++ b/indra/newview/llautoreplace.cpp @@ -0,0 +1,771 @@ +/** + * @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" + +LLAutoReplace* LLAutoReplace::sInstance; + +const char* LLAutoReplace::SETTINGS_FILE_NAME = "autoreplace.xml"; + +LLAutoReplace::LLAutoReplace() +{ +} + +LLAutoReplace::~LLAutoReplace() +{ + sInstance = NULL; +} + +void LLAutoReplace::autoreplaceCallback(LLUIString& inputText, S32& cursorPos) +{ + static LLCachedControl<bool> perform_autoreplace(gSavedSettings, "AutoReplace"); + if(perform_autoreplace) + { + S32 wordEnd = cursorPos-1; + LLWString text = inputText.getWString(); + + bool atSpace = (text[wordEnd] == ' '); + bool haveWord = (LLWStringUtil::isPartOfWord(text[wordEnd])); + + if (atSpace || haveWord) + { + if (atSpace && wordEnd > 0) + { + // find out if this space immediately follows a word + wordEnd--; + haveWord = (LLWStringUtil::isPartOfWord(text[wordEnd])); + } + if (haveWord) + { + // wordEnd points to the end of a word, now find the start of the word + std::string word; + S32 wordStart = wordEnd; + for ( S32 backOne = wordStart - 1; + backOne >= 0 && LLWStringUtil::isPartOfWord(text[backOne]); + backOne-- + ) + { + wordStart--; // walk wordStart back to the beginning of the word + } + LL_DEBUGS("AutoReplace")<<"wordStart: "<<wordStart<<" wordEnd: "<<wordEnd<<LL_ENDL; + std::string strText = std::string(text.begin(), text.end()); + std::string lastWord = strText.substr(wordStart, wordEnd-wordStart+1); + std::string replacementWord( mSettings.replaceWord( lastWord ) ); + + if ( replacementWord != lastWord ) + { + // The last word is one for which we have a replacement + if (atSpace) + { + // replace the last word in the input + LLWString strNew = utf8str_to_wstring(replacementWord); + LLWString strOld = utf8str_to_wstring(lastWord); + int size_change = strNew.size() - strOld.size(); + + text.replace(wordStart,lastWord.length(),strNew); + inputText = wstring_to_utf8str(text); + cursorPos+=size_change; + } + } + } + } + } +} + +LLAutoReplace* LLAutoReplace::getInstance() +{ + if(!sInstance) + { + sInstance = new LLAutoReplace(); + sInstance->loadFromSettings(); + } + return sInstance; +} + +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(); +} + +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.getAsLLSD(), 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; +} + +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"); + 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 (S32 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::getAsLLSD() +{ + return mLists; +} + +LLAutoReplaceSettings::~LLAutoReplaceSettings() +{ +} diff --git a/indra/newview/llautoreplace.h b/indra/newview/llautoreplace.h new file mode 100644 index 0000000000..30b1fd2c65 --- /dev/null +++ b/indra/newview/llautoreplace.h @@ -0,0 +1,228 @@ +/** + * @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); + + /// 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& getAsLLSD(); + ///< @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 keyword is replaced by the associated value from the map. + * + * See the autoreplaceCallback method for how to add autoreplace functionality + * to a text entry tool. + */ +class LLAutoReplace : public LLSingleton<LLAutoReplace> +{ + public: + LLAutoReplace(); + ~LLAutoReplace(); + + /// @return a pointer to the active instance + static LLAutoReplace* getInstance(); + + /// Callback that provides the hook for use in text entry methods + void autoreplaceCallback(LLUIString& inputText, S32& cursorPos); + + /// 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>; + static LLAutoReplace* sInstance; ///< the active settings instance + + 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 */ diff --git a/indra/newview/llavatariconctrl.cpp b/indra/newview/llavatariconctrl.cpp index b539ac38ed..b539ac38ed 100755..100644 --- a/indra/newview/llavatariconctrl.cpp +++ b/indra/newview/llavatariconctrl.cpp diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index f530d10ddc..84e73e96fa 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -495,7 +495,7 @@ protected: void showInfoCtrl() { - if (mAvatarID.isNull() || mFrom.empty() || SYSTEM_FROM == mFrom) return; + if (mAvatarID.isNull() || mFrom.empty() || CHAT_SOURCE_SYSTEM == mSourceType) return; if (!sInfoCtrl) { @@ -689,8 +689,11 @@ void LLChatHistory::clear() mLastFromID = LLUUID::null; } +static LLFastTimer::DeclareTimer FTM_APPEND_MESSAGE("Append Chat Message"); + void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LLStyle::Params& input_append_params) { + LLFastTimer _(FTM_APPEND_MESSAGE); bool use_plain_text_chat_history = args["use_plain_text_chat_history"].asBoolean(); llassert(mEditor); @@ -783,7 +786,7 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL timestamp_style.color(timestamp_color); timestamp_style.readonly_color(timestamp_color); } - mEditor->appendText("[" + chat.mTimeStr + "] ", mEditor->getText().size() != 0, timestamp_style); + mEditor->appendText("[" + chat.mTimeStr + "] ", mEditor->getLength() != 0, timestamp_style); if (utf8str_trim(chat.mFromName).size() != 0) { @@ -842,7 +845,7 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL else { view = getHeader(chat, style_params, args); - if (mEditor->getText().size() == 0) + if (mEditor->getLength() == 0) p.top_pad = 0; else p.top_pad = mTopHeaderPad; diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp index 21b21c152a..98246162f0 100644 --- a/indra/newview/lldrawable.cpp +++ b/indra/newview/lldrawable.cpp @@ -450,7 +450,7 @@ void LLDrawable::makeStatic(BOOL warning_enabled) { if (isState(ACTIVE)) { - clearState(ACTIVE); + clearState(ACTIVE | ANIMATED_CHILD); if (mParent.notNull() && mParent->isActive() && warning_enabled) { @@ -538,9 +538,9 @@ F32 LLDrawable::updateXform(BOOL undamped) target_rot = new_rot; target_scale = new_scale; } - else + else if (mVObjp->getAngularVelocity().isExactlyZero()) { - // snap to final position + // snap to final position (only if no target omega is applied) dist_squared = 0.0f; if (getVOVolume() && !isRoot()) { //child prim snapping to some position, needs a rebuild @@ -549,15 +549,25 @@ F32 LLDrawable::updateXform(BOOL undamped) } } - if ((mCurrentScale != target_scale) || - (!isRoot() && - (dist_squared >= MIN_INTERPOLATE_DISTANCE_SQUARED || - !mVObjp->getAngularVelocity().isExactlyZero() || - target_pos != mXform.getPosition() || - target_rot != mXform.getRotation()))) - { //child prim moving or scale change requires immediate rebuild + LLVector3 vec = mCurrentScale-target_scale; + + if (vec*vec > MIN_INTERPOLATE_DISTANCE_SQUARED) + { //scale change requires immediate rebuild + mCurrentScale = target_scale; gPipeline.markRebuild(this, LLDrawable::REBUILD_POSITION, TRUE); } + else if (!isRoot() && + (!mVObjp->getAngularVelocity().isExactlyZero() || + dist_squared > 0.f)) + { //child prim moving relative to parent, tag as needing to be rendered atomically and rebuild + dist_squared = 1.f; //keep this object on the move list + if (!isState(LLDrawable::ANIMATED_CHILD)) + { + setState(LLDrawable::ANIMATED_CHILD); + gPipeline.markRebuild(this, LLDrawable::REBUILD_ALL, TRUE); + mVObjp->dirtySpatialGroup(); + } + } else if (!getVOVolume() && !isAvatar()) { movePartition(); @@ -568,9 +578,7 @@ F32 LLDrawable::updateXform(BOOL undamped) mXform.setRotation(target_rot); mXform.setScale(LLVector3(1,1,1)); //no scale in drawable transforms (IT'S A RULE!) mXform.updateMatrix(); - - mCurrentScale = target_scale; - + if (mSpatialBridge) { gPipeline.markMoved(mSpatialBridge, FALSE); @@ -596,7 +604,11 @@ void LLDrawable::moveUpdatePipeline(BOOL moved) // Update the face centers. for (S32 i = 0; i < getNumFaces(); i++) { - getFace(i)->updateCenterAgent(); + LLFace* face = getFace(i); + if (face) + { + face->updateCenterAgent(); + } } } @@ -651,7 +663,6 @@ BOOL LLDrawable::updateMoveUndamped() } mVObjp->clearChanged(LLXform::MOVED); - return TRUE; } @@ -727,7 +738,8 @@ void LLDrawable::updateDistance(LLCamera& camera, bool force_update) for (S32 i = 0; i < getNumFaces(); i++) { LLFace* facep = getFace(i); - if (force_update || facep->getPoolType() == LLDrawPool::POOL_ALPHA) + if (facep && + (force_update || facep->getPoolType() == LLDrawPool::POOL_ALPHA)) { LLVector4a box; box.setSub(facep->mExtents[1], facep->mExtents[0]); @@ -826,13 +838,16 @@ void LLDrawable::shiftPos(const LLVector4a &shift_vector) for (S32 i = 0; i < getNumFaces(); i++) { LLFace *facep = getFace(i); - facep->mCenterAgent += LLVector3(shift_vector.getF32ptr()); - facep->mExtents[0].add(shift_vector); - facep->mExtents[1].add(shift_vector); - - if (!volume && facep->hasGeometry()) + if (facep) { - facep->clearVertexBuffer(); + facep->mCenterAgent += LLVector3(shift_vector.getF32ptr()); + facep->mExtents[0].add(shift_vector); + facep->mExtents[1].add(shift_vector); + + if (!volume && facep->hasGeometry()) + { + facep->clearVertexBuffer(); + } } } @@ -954,7 +969,10 @@ void LLDrawable::setSpatialGroup(LLSpatialGroup *groupp) for (S32 i = 0; i < getNumFaces(); ++i) { LLFace* facep = getFace(i); - facep->clearVertexBuffer(); + if (facep) + { + facep->clearVertexBuffer(); + } } } @@ -1529,10 +1547,10 @@ BOOL LLDrawable::isAnimating() const return TRUE; } - if (!isRoot() && !mVObjp->getAngularVelocity().isExactlyZero()) - { + /*if (!isRoot() && !mVObjp->getAngularVelocity().isExactlyZero()) + { //target omega return TRUE; - } + }*/ return FALSE; } diff --git a/indra/newview/lldrawable.h b/indra/newview/lldrawable.h index 9a66490b03..8c7db61502 100755 --- a/indra/newview/lldrawable.h +++ b/indra/newview/lldrawable.h @@ -288,6 +288,7 @@ public: HAS_ALPHA = 0x04000000, RIGGED = 0x08000000, PARTITION_MOVE = 0x10000000, + ANIMATED_CHILD = 0x20000000, } EDrawableFlags; private: //aligned members @@ -344,12 +345,14 @@ inline LLFace* LLDrawable::getFace(const S32 i) const if ((U32) i >= mFaces.size()) { - llerrs << "Invalid face index." << llendl; + llwarns << "Invalid face index." << llendl; + return NULL; } if (!mFaces[i]) { - llerrs << "Null face found." << llendl; + llwarns << "Null face found." << llendl; + return NULL; } return mFaces[i]; diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index 5b62dbc560..5f2a982ed3 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -405,6 +405,12 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask) { LLDrawInfo& params = **k; + if ((params.mVertexBuffer->getTypeMask() & mask) != mask) + { //FIXME! + llwarns << "Missing required components, skipping render batch." << llendl; + continue; + } + LLRenderPass::applyModelMatrix(params); diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index 0103373fd2..ace3a20bbb 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -261,7 +261,9 @@ void LLDrawPoolAvatar::beginPostDeferredAlpha() sRenderingSkinned = TRUE; gPipeline.bindDeferredShader(*sVertexProgram); - + + sVertexProgram->setMinimumAlpha(0.2f); + sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); } diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index 5477345e69..d32994cd31 100755 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -44,11 +44,14 @@ #include "llsky.h" #include "llviewercamera.h" #include "llviewertexturelist.h" +#include "llvopartgroup.h" #include "llvosky.h" #include "llvovolume.h" #include "pipeline.h" #include "llviewerregion.h" #include "llviewerwindow.h" +#include "llviewershadermgr.h" + #define LL_MAX_INDICES_COUNT 1000000 @@ -56,7 +59,6 @@ BOOL LLFace::sSafeRenderSelect = TRUE; // FALSE #define DOTVEC(a,b) (a.mV[0]*b.mV[0] + a.mV[1]*b.mV[1] + a.mV[2]*b.mV[2]) - /* For each vertex, given: B - binormal @@ -161,7 +163,15 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp) mGeomCount = 0; mGeomIndex = 0; mIndicesCount = 0; - mIndicesIndex = 0; + if (drawablep->getRenderType() == LLPipeline::RENDER_TYPE_PARTICLES || + drawablep->getRenderType() == LLPipeline::RENDER_TYPE_HUD_PARTICLES) + { //indicate to LLParticlePartition that this particle is uninitialized + mIndicesIndex = 0xFFFFFFFF; + } + else + { + mIndicesIndex = 0; + } mIndexInTex = 0; mTexture = NULL; mTEOffset = -1; @@ -177,12 +187,6 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp) mFaceColor = LLColor4(1,0,0,1); - mLastVertexBuffer = mVertexBuffer; - mLastGeomCount = mGeomCount; - mLastGeomIndex = mGeomIndex; - mLastIndicesCount = mIndicesCount; - mLastIndicesIndex = mIndicesIndex; - mImportanceToCamera = 0.f ; mBoundingSphereRadius = 0.0f ; @@ -203,6 +207,15 @@ void LLFace::destroy() mTexture->removeFace(this) ; } + if (mDrawablep.notNull() && + (mDrawablep->getRenderType() == LLPipeline::RENDER_TYPE_PARTICLES || + mDrawablep->getRenderType() == LLPipeline::RENDER_TYPE_HUD_PARTICLES) && + mIndicesIndex != 0xFFFFFFFF) + { + LLVOPartGroup::freeVBSlot(getGeomIndex()/4); + mIndicesIndex = 0xFFFFFFFF; + } + if (mDrawPoolp) { if (this->isState(LLFace::RIGGED) && mDrawPoolp->getType() == LLDrawPool::POOL_AVATAR) @@ -372,7 +385,6 @@ void LLFace::setSize(S32 num_vertices, S32 num_indices, bool align) mGeomCount = num_vertices; mIndicesCount = num_indices; mVertexBuffer = NULL; - mLastVertexBuffer = NULL; } llassert(verify()); @@ -765,12 +777,6 @@ BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f, LLMatrix4a mat_normal; mat_normal.loadu(mat_normal_in); - //if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME)) - //{ //vertex buffer no longer valid - // mVertexBuffer = NULL; - // mLastVertexBuffer = NULL; - //} - //VECTORIZE THIS LLVector4a min,max; @@ -1032,30 +1038,13 @@ bool LLFace::calcAlignedPlanarTE(const LLFace* align_to, LLVector2* res_st_offs void LLFace::updateRebuildFlags() { - if (!mDrawablep->isState(LLDrawable::REBUILD_VOLUME)) - { - BOOL moved = TRUE; - if (mLastVertexBuffer == mVertexBuffer && - !mVertexBuffer->isEmpty()) - { //this face really doesn't need to be regenerated, try real hard not to do so - if (mLastGeomCount == mGeomCount && - mLastGeomIndex == mGeomIndex && - mLastIndicesCount == mIndicesCount && - mLastIndicesIndex == mIndicesIndex) - { //data is in same location in vertex buffer - moved = FALSE; - } - } - mLastMoveTime = gFrameTimeSeconds; - - if (moved) - { - mDrawablep->setState(LLDrawable::REBUILD_VOLUME); - } + if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME)) + { //this rebuild is zero overhead (direct consequence of some change that affects this face) + mLastUpdateTime = gFrameTimeSeconds; } else - { - mLastUpdateTime = gFrameTimeSeconds; + { //this rebuild is overhead (side effect of some change that does not affect this face) + mLastMoveTime = gFrameTimeSeconds; } } @@ -1094,6 +1083,73 @@ bool LLFace::canRenderAsMask() } +static LLFastTimer::DeclareTimer FTM_FACE_GEOM_VOLUME("Volume VB Cache"); + +//static +void LLFace::cacheFaceInVRAM(const LLVolumeFace& vf) +{ + LLFastTimer t(FTM_FACE_GEOM_VOLUME); + U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | + LLVertexBuffer::MAP_BINORMAL | LLVertexBuffer::MAP_NORMAL; + + if (vf.mWeights) + { + mask |= LLVertexBuffer::MAP_WEIGHT4; + } + + LLVertexBuffer* buff = new LLVertexBuffer(mask, GL_STATIC_DRAW_ARB); + vf.mVertexBuffer = buff; + + buff->allocateBuffer(vf.mNumVertices, 0, true); + + LLStrider<LLVector4a> f_vert; + LLStrider<LLVector3> f_binorm; + LLStrider<LLVector3> f_norm; + LLStrider<LLVector2> f_tc; + + buff->getBinormalStrider(f_binorm); + buff->getVertexStrider(f_vert); + buff->getNormalStrider(f_norm); + buff->getTexCoord0Strider(f_tc); + + for (U32 i = 0; i < vf.mNumVertices; ++i) + { + *f_vert++ = vf.mPositions[i]; + (*f_binorm++).set(vf.mBinormals[i].getF32ptr()); + *f_tc++ = vf.mTexCoords[i]; + (*f_norm++).set(vf.mNormals[i].getF32ptr()); + } + + if (vf.mWeights) + { + LLStrider<LLVector4> f_wght; + buff->getWeight4Strider(f_wght); + for (U32 i = 0; i < vf.mNumVertices; ++i) + { + (*f_wght++).set(vf.mWeights[i].getF32ptr()); + } + } + + buff->flush(); +} + +//helper function for pushing primitives for transform shaders and cleaning up +//uninitialized data on the tail, plus tracking number of expected primitives +void push_for_transform(LLVertexBuffer* buff, U32 source_count, U32 dest_count) +{ + if (source_count > 0 && dest_count >= source_count) //protect against possible U32 wrapping + { + //push source primitives + buff->drawArrays(LLRender::POINTS, 0, source_count); + U32 tail = dest_count-source_count; + for (U32 i = 0; i < tail; ++i) + { //copy last source primitive into each element in tail + buff->drawArrays(LLRender::POINTS, source_count-1, 1); + } + gPipeline.mTransformFeedbackPrimitives += dest_count; + } +} + static LLFastTimer::DeclareTimer FTM_FACE_GET_GEOM("Face Geom"); static LLFastTimer::DeclareTimer FTM_FACE_GEOM_POSITION("Position"); static LLFastTimer::DeclareTimer FTM_FACE_GEOM_NORMAL("Normal"); @@ -1111,7 +1167,6 @@ static LLFastTimer::DeclareTimer FTM_FACE_TEX_DEFAULT("Default"); static LLFastTimer::DeclareTimer FTM_FACE_TEX_QUICK("Quick"); static LLFastTimer::DeclareTimer FTM_FACE_TEX_QUICK_NO_XFORM("No Xform"); static LLFastTimer::DeclareTimer FTM_FACE_TEX_QUICK_XFORM("Xform"); - static LLFastTimer::DeclareTimer FTM_FACE_TEX_QUICK_PLANAR("Quick Planar"); BOOL LLFace::getGeometryVolume(const LLVolume& volume, @@ -1144,9 +1199,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, << " VF Num Indices: " << num_indices << " Indices Index: " << mIndicesIndex << " VB Num Indices: " << mVertexBuffer->getNumIndices() << llendl; - llwarns << "Last Indices Count: " << mLastIndicesCount - << " Last Indices Index: " << mLastIndicesIndex - << " Face Index: " << f + llwarns << " Face Index: " << f << " Pool Type: " << mPoolType << llendl; return FALSE; } @@ -1284,17 +1337,10 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, LLMatrix4a mat_normal; mat_normal.loadu(mat_norm_in); - //if it's not fullbright and has no normals, bake sunlight based on face normal - //bool bake_sunlight = !getTextureEntry()->getFullbright() && - // !mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_NORMAL); - F32 r = 0, os = 0, ot = 0, ms = 0, mt = 0, cos_ang = 0, sin_ang = 0; - + bool do_xform = false; if (rebuild_tcoord) { - LLFastTimer t(FTM_FACE_GEOM_TEXTURE); - bool do_xform; - if (tep) { r = tep->getRotation(); @@ -1323,600 +1369,760 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, { do_xform = false; } + } + + static LLCachedControl<bool> use_transform_feedback(gSavedSettings, "RenderUseTransformFeedback"); + +#ifdef GL_TRANSFORM_FEEDBACK_BUFFER + if (use_transform_feedback && + gTransformPositionProgram.mProgramObject && //transform shaders are loaded + mVertexBuffer->useVBOs() && //target buffer is in VRAM + !rebuild_weights && //TODO: add support for weights + !volume.isUnique()) //source volume is NOT flexi + { //use transform feedback to pack vertex buffer + + LLVertexBuffer* buff = (LLVertexBuffer*) vf.mVertexBuffer.get(); + + if (vf.mVertexBuffer.isNull() || buff->getNumVerts() != vf.mNumVertices) + { + mVObjp->getVolume()->genBinormals(f); + LLFace::cacheFaceInVRAM(vf); + buff = (LLVertexBuffer*) vf.mVertexBuffer.get(); + } + + LLGLSLShader* cur_shader = LLGLSLShader::sCurBoundShaderPtr; + + gGL.pushMatrix(); + gGL.loadMatrix((GLfloat*) mat_vert_in.mMatrix); + + if (rebuild_pos) + { + LLFastTimer t(FTM_FACE_GEOM_POSITION); + gTransformPositionProgram.bind(); + + mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_VERTEX, mGeomIndex, mGeomCount); + + U8 index = mTextureIndex < 255 ? mTextureIndex : 0; + + S32 val = 0; + U8* vp = (U8*) &val; + vp[0] = index; + vp[1] = 0; + vp[2] = 0; + vp[3] = 0; + + gTransformPositionProgram.uniform1i("texture_index_in", val); + glBeginTransformFeedback(GL_POINTS); + buff->setBuffer(LLVertexBuffer::MAP_VERTEX); + + push_for_transform(buff, vf.mNumVertices, mGeomCount); + + glEndTransformFeedback(); + } + + if (rebuild_color) + { + LLFastTimer t(FTM_FACE_GEOM_COLOR); + gTransformColorProgram.bind(); + + mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_COLOR, mGeomIndex, mGeomCount); + + S32 val = *((S32*) color.mV); + + gTransformColorProgram.uniform1i("color_in", val); + glBeginTransformFeedback(GL_POINTS); + buff->setBuffer(LLVertexBuffer::MAP_VERTEX); + push_for_transform(buff, vf.mNumVertices, mGeomCount); + glEndTransformFeedback(); + } + + if (rebuild_emissive) + { + LLFastTimer t(FTM_FACE_GEOM_EMISSIVE); + gTransformColorProgram.bind(); + + mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_EMISSIVE, mGeomIndex, mGeomCount); + + U8 glow = (U8) llclamp((S32) (getTextureEntry()->getGlow()*255), 0, 255); + + S32 glow32 = glow | + (glow << 8) | + (glow << 16) | + (glow << 24); + + gTransformColorProgram.uniform1i("color_in", glow32); + glBeginTransformFeedback(GL_POINTS); + buff->setBuffer(LLVertexBuffer::MAP_VERTEX); + push_for_transform(buff, vf.mNumVertices, mGeomCount); + glEndTransformFeedback(); + } + + if (rebuild_normal) + { + LLFastTimer t(FTM_FACE_GEOM_NORMAL); + gTransformNormalProgram.bind(); + + mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_NORMAL, mGeomIndex, mGeomCount); - //bump setup - LLVector4a binormal_dir( -sin_ang, cos_ang, 0.f ); - LLVector4a bump_s_primary_light_ray(0.f, 0.f, 0.f); - LLVector4a bump_t_primary_light_ray(0.f, 0.f, 0.f); + glBeginTransformFeedback(GL_POINTS); + buff->setBuffer(LLVertexBuffer::MAP_NORMAL); + push_for_transform(buff, vf.mNumVertices, mGeomCount); + glEndTransformFeedback(); + } - LLQuaternion bump_quat; - if (mDrawablep->isActive()) + if (rebuild_binormal) { - bump_quat = LLQuaternion(mDrawablep->getRenderMatrix()); + LLFastTimer t(FTM_FACE_GEOM_BINORMAL); + gTransformBinormalProgram.bind(); + + mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_BINORMAL, mGeomIndex, mGeomCount); + + glBeginTransformFeedback(GL_POINTS); + buff->setBuffer(LLVertexBuffer::MAP_BINORMAL); + push_for_transform(buff, vf.mNumVertices, mGeomCount); + glEndTransformFeedback(); } - - if (bump_code) + + if (rebuild_tcoord) { - mVObjp->getVolume()->genBinormals(f); - F32 offset_multiple; - switch( bump_code ) - { - case BE_NO_BUMP: - offset_multiple = 0.f; - break; - case BE_BRIGHTNESS: - case BE_DARKNESS: - if( mTexture.notNull() && mTexture->hasGLTexture()) - { - // Offset by approximately one texel - S32 cur_discard = mTexture->getDiscardLevel(); - S32 max_size = llmax( mTexture->getWidth(), mTexture->getHeight() ); - max_size <<= cur_discard; - const F32 ARTIFICIAL_OFFSET = 2.f; - offset_multiple = ARTIFICIAL_OFFSET / (F32)max_size; - } - else - { - offset_multiple = 1.f/256; - } - break; + LLFastTimer t(FTM_FACE_GEOM_TEXTURE); + gTransformTexCoordProgram.bind(); + + mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_TEXCOORD0, mGeomIndex, mGeomCount); + + glBeginTransformFeedback(GL_POINTS); + buff->setBuffer(LLVertexBuffer::MAP_TEXCOORD0); + push_for_transform(buff, vf.mNumVertices, mGeomCount); + glEndTransformFeedback(); - default: // Standard bumpmap textures. Assumed to be 256x256 - offset_multiple = 1.f / 256; - break; - } + bool do_bump = bump_code && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1); - F32 s_scale = 1.f; - F32 t_scale = 1.f; - if( tep ) + if (do_bump) { - tep->getScale( &s_scale, &t_scale ); - } - // Use the nudged south when coming from above sun angle, such - // that emboss mapping always shows up on the upward faces of cubes when - // it's noon (since a lot of builders build with the sun forced to noon). - LLVector3 sun_ray = gSky.mVOSkyp->mBumpSunDir; - LLVector3 moon_ray = gSky.getMoonDirection(); - LLVector3& primary_light_ray = (sun_ray.mV[VZ] > 0) ? sun_ray : moon_ray; - - bump_s_primary_light_ray.load3((offset_multiple * s_scale * primary_light_ray).mV); - bump_t_primary_light_ray.load3((offset_multiple * t_scale * primary_light_ray).mV); + mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_TEXCOORD1, mGeomIndex, mGeomCount); + glBeginTransformFeedback(GL_POINTS); + buff->setBuffer(LLVertexBuffer::MAP_TEXCOORD0); + push_for_transform(buff, vf.mNumVertices, mGeomCount); + glEndTransformFeedback(); + } } - U8 texgen = getTextureEntry()->getTexGen(); - if (rebuild_tcoord && texgen != LLTextureEntry::TEX_GEN_DEFAULT) - { //planar texgen needs binormals - mVObjp->getVolume()->genBinormals(f); + glBindBufferARB(GL_TRANSFORM_FEEDBACK_BUFFER, 0); + + gGL.popMatrix(); + + if (cur_shader) + { + cur_shader->bind(); } + } + else +#endif + { + //if it's not fullbright and has no normals, bake sunlight based on face normal + //bool bake_sunlight = !getTextureEntry()->getFullbright() && + // !mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_NORMAL); - U8 tex_mode = 0; - - if (isState(TEXTURE_ANIM)) + if (rebuild_tcoord) { - LLVOVolume* vobj = (LLVOVolume*) (LLViewerObject*) mVObjp; - tex_mode = vobj->mTexAnimMode; + LLFastTimer t(FTM_FACE_GEOM_TEXTURE); + + //bump setup + LLVector4a binormal_dir( -sin_ang, cos_ang, 0.f ); + LLVector4a bump_s_primary_light_ray(0.f, 0.f, 0.f); + LLVector4a bump_t_primary_light_ray(0.f, 0.f, 0.f); - if (!tex_mode) + LLQuaternion bump_quat; + if (mDrawablep->isActive()) { - clearState(TEXTURE_ANIM); + bump_quat = LLQuaternion(mDrawablep->getRenderMatrix()); } - else + + if (bump_code) { - os = ot = 0.f; - r = 0.f; - cos_ang = 1.f; - sin_ang = 0.f; - ms = mt = 1.f; + mVObjp->getVolume()->genBinormals(f); + F32 offset_multiple; + switch( bump_code ) + { + case BE_NO_BUMP: + offset_multiple = 0.f; + break; + case BE_BRIGHTNESS: + case BE_DARKNESS: + if( mTexture.notNull() && mTexture->hasGLTexture()) + { + // Offset by approximately one texel + S32 cur_discard = mTexture->getDiscardLevel(); + S32 max_size = llmax( mTexture->getWidth(), mTexture->getHeight() ); + max_size <<= cur_discard; + const F32 ARTIFICIAL_OFFSET = 2.f; + offset_multiple = ARTIFICIAL_OFFSET / (F32)max_size; + } + else + { + offset_multiple = 1.f/256; + } + break; - do_xform = false; + default: // Standard bumpmap textures. Assumed to be 256x256 + offset_multiple = 1.f / 256; + break; + } + + F32 s_scale = 1.f; + F32 t_scale = 1.f; + if( tep ) + { + tep->getScale( &s_scale, &t_scale ); + } + // Use the nudged south when coming from above sun angle, such + // that emboss mapping always shows up on the upward faces of cubes when + // it's noon (since a lot of builders build with the sun forced to noon). + LLVector3 sun_ray = gSky.mVOSkyp->mBumpSunDir; + LLVector3 moon_ray = gSky.getMoonDirection(); + LLVector3& primary_light_ray = (sun_ray.mV[VZ] > 0) ? sun_ray : moon_ray; + + bump_s_primary_light_ray.load3((offset_multiple * s_scale * primary_light_ray).mV); + bump_t_primary_light_ray.load3((offset_multiple * t_scale * primary_light_ray).mV); } - if (getVirtualSize() >= MIN_TEX_ANIM_SIZE) - { //don't override texture transform during tc bake - tex_mode = 0; + U8 texgen = getTextureEntry()->getTexGen(); + if (rebuild_tcoord && texgen != LLTextureEntry::TEX_GEN_DEFAULT) + { //planar texgen needs binormals + mVObjp->getVolume()->genBinormals(f); } - } - LLVector4a scalea; - scalea.load3(scale.mV); + U8 tex_mode = 0; + + if (isState(TEXTURE_ANIM)) + { + LLVOVolume* vobj = (LLVOVolume*) (LLViewerObject*) mVObjp; + tex_mode = vobj->mTexAnimMode; + + if (!tex_mode) + { + clearState(TEXTURE_ANIM); + } + else + { + os = ot = 0.f; + r = 0.f; + cos_ang = 1.f; + sin_ang = 0.f; + ms = mt = 1.f; + + do_xform = false; + } + + if (getVirtualSize() >= MIN_TEX_ANIM_SIZE) + { //don't override texture transform during tc bake + tex_mode = 0; + } + } - bool do_bump = bump_code && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1); - bool do_tex_mat = tex_mode && mTextureMatrix; + LLVector4a scalea; + scalea.load3(scale.mV); - if (!in_atlas && !do_bump) - { //not in atlas or not bump mapped, might be able to do a cheap update - mVertexBuffer->getTexCoord0Strider(tex_coords, mGeomIndex, mGeomCount); + bool do_bump = bump_code && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1); + bool do_tex_mat = tex_mode && mTextureMatrix; - if (texgen != LLTextureEntry::TEX_GEN_PLANAR) - { - LLFastTimer t(FTM_FACE_TEX_QUICK); - if (!do_tex_mat) + if (!in_atlas && !do_bump) + { //not in atlas or not bump mapped, might be able to do a cheap update + mVertexBuffer->getTexCoord0Strider(tex_coords, mGeomIndex, mGeomCount); + + if (texgen != LLTextureEntry::TEX_GEN_PLANAR) { - if (!do_xform) - { - LLFastTimer t(FTM_FACE_TEX_QUICK_NO_XFORM); - S32 tc_size = (num_vertices*2*sizeof(F32)+0xF) & ~0xF; - LLVector4a::memcpyNonAliased16((F32*) tex_coords.get(), (F32*) vf.mTexCoords, tc_size); - } - else + LLFastTimer t(FTM_FACE_TEX_QUICK); + if (!do_tex_mat) { - LLFastTimer t(FTM_FACE_TEX_QUICK_XFORM); - F32* dst = (F32*) tex_coords.get(); - LLVector4a* src = (LLVector4a*) vf.mTexCoords; + if (!do_xform) + { + LLFastTimer t(FTM_FACE_TEX_QUICK_NO_XFORM); + S32 tc_size = (num_vertices*2*sizeof(F32)+0xF) & ~0xF; + LLVector4a::memcpyNonAliased16((F32*) tex_coords.get(), (F32*) vf.mTexCoords, tc_size); + } + else + { + LLFastTimer t(FTM_FACE_TEX_QUICK_XFORM); + F32* dst = (F32*) tex_coords.get(); + LLVector4a* src = (LLVector4a*) vf.mTexCoords; - LLVector4a trans; - trans.splat(-0.5f); + LLVector4a trans; + trans.splat(-0.5f); - LLVector4a rot0; - rot0.set(cos_ang, -sin_ang, cos_ang, -sin_ang); + LLVector4a rot0; + rot0.set(cos_ang, -sin_ang, cos_ang, -sin_ang); - LLVector4a rot1; - rot1.set(sin_ang, cos_ang, sin_ang, cos_ang); + LLVector4a rot1; + rot1.set(sin_ang, cos_ang, sin_ang, cos_ang); - LLVector4a scale; - scale.set(ms, mt, ms, mt); + LLVector4a scale; + scale.set(ms, mt, ms, mt); - LLVector4a offset; - offset.set(os+0.5f, ot+0.5f, os+0.5f, ot+0.5f); + LLVector4a offset; + offset.set(os+0.5f, ot+0.5f, os+0.5f, ot+0.5f); - LLVector4Logical mask; - mask.clear(); - mask.setElement<2>(); - mask.setElement<3>(); + LLVector4Logical mask; + mask.clear(); + mask.setElement<2>(); + mask.setElement<3>(); - U32 count = num_vertices/2 + num_vertices%2; + U32 count = num_vertices/2 + num_vertices%2; - for (S32 i = 0; i < count; i++) + for (S32 i = 0; i < count; i++) + { + LLVector4a res = *src++; + xform4a(res, trans, mask, rot0, rot1, offset, scale); + res.store4a(dst); + dst += 4; + } + } + } + else + { //do tex mat, no texgen, no atlas, no bump + for (S32 i = 0; i < num_vertices; i++) { - LLVector4a res = *src++; - xform4a(res, trans, mask, rot0, rot1, offset, scale); - res.store4a(dst); - dst += 4; + LLVector2 tc(vf.mTexCoords[i]); + //LLVector4a& norm = vf.mNormals[i]; + //LLVector4a& center = *(vf.mCenter); + + LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f); + tmp = tmp * *mTextureMatrix; + tc.mV[0] = tmp.mV[0]; + tc.mV[1] = tmp.mV[1]; + *tex_coords++ = tc; } } } else - { //do tex mat, no texgen, no atlas, no bump - for (S32 i = 0; i < num_vertices; i++) - { - LLVector2 tc(vf.mTexCoords[i]); - //LLVector4a& norm = vf.mNormals[i]; - //LLVector4a& center = *(vf.mCenter); - - LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f); - tmp = tmp * *mTextureMatrix; - tc.mV[0] = tmp.mV[0]; - tc.mV[1] = tmp.mV[1]; - *tex_coords++ = tc; - } - } - } - else - { //no bump, no atlas, tex gen planar - LLFastTimer t(FTM_FACE_TEX_QUICK_PLANAR); - if (do_tex_mat) - { - for (S32 i = 0; i < num_vertices; i++) - { - LLVector2 tc(vf.mTexCoords[i]); - LLVector4a& norm = vf.mNormals[i]; - LLVector4a& center = *(vf.mCenter); - LLVector4a vec = vf.mPositions[i]; - vec.mul(scalea); - planarProjection(tc, norm, center, vec); + { //no bump, no atlas, tex gen planar + LLFastTimer t(FTM_FACE_TEX_QUICK_PLANAR); + if (do_tex_mat) + { + for (S32 i = 0; i < num_vertices; i++) + { + LLVector2 tc(vf.mTexCoords[i]); + LLVector4a& norm = vf.mNormals[i]; + LLVector4a& center = *(vf.mCenter); + LLVector4a vec = vf.mPositions[i]; + vec.mul(scalea); + planarProjection(tc, norm, center, vec); - LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f); - tmp = tmp * *mTextureMatrix; - tc.mV[0] = tmp.mV[0]; - tc.mV[1] = tmp.mV[1]; + LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f); + tmp = tmp * *mTextureMatrix; + tc.mV[0] = tmp.mV[0]; + tc.mV[1] = tmp.mV[1]; - *tex_coords++ = tc; + *tex_coords++ = tc; + } } - } - else - { - for (S32 i = 0; i < num_vertices; i++) - { - LLVector2 tc(vf.mTexCoords[i]); - LLVector4a& norm = vf.mNormals[i]; - LLVector4a& center = *(vf.mCenter); - LLVector4a vec = vf.mPositions[i]; - vec.mul(scalea); - planarProjection(tc, norm, center, vec); + else + { + for (S32 i = 0; i < num_vertices; i++) + { + LLVector2 tc(vf.mTexCoords[i]); + LLVector4a& norm = vf.mNormals[i]; + LLVector4a& center = *(vf.mCenter); + LLVector4a vec = vf.mPositions[i]; + vec.mul(scalea); + planarProjection(tc, norm, center, vec); - xform(tc, cos_ang, sin_ang, os, ot, ms, mt); + xform(tc, cos_ang, sin_ang, os, ot, ms, mt); - *tex_coords++ = tc; + *tex_coords++ = tc; + } } } - } - if (map_range) - { - mVertexBuffer->flush(); + if (map_range) + { + mVertexBuffer->flush(); + } } - } - else - { //either bump mapped or in atlas, just do the whole expensive loop - LLFastTimer t(FTM_FACE_TEX_DEFAULT); - mVertexBuffer->getTexCoord0Strider(tex_coords, mGeomIndex, mGeomCount, map_range); + else + { //either bump mapped or in atlas, just do the whole expensive loop + LLFastTimer t(FTM_FACE_TEX_DEFAULT); + mVertexBuffer->getTexCoord0Strider(tex_coords, mGeomIndex, mGeomCount, map_range); - std::vector<LLVector2> bump_tc; + std::vector<LLVector2> bump_tc; - for (S32 i = 0; i < num_vertices; i++) - { - LLVector2 tc(vf.mTexCoords[i]); + for (S32 i = 0; i < num_vertices; i++) + { + LLVector2 tc(vf.mTexCoords[i]); - LLVector4a& norm = vf.mNormals[i]; + LLVector4a& norm = vf.mNormals[i]; - LLVector4a& center = *(vf.mCenter); + LLVector4a& center = *(vf.mCenter); - if (texgen != LLTextureEntry::TEX_GEN_DEFAULT) - { - LLVector4a vec = vf.mPositions[i]; + if (texgen != LLTextureEntry::TEX_GEN_DEFAULT) + { + LLVector4a vec = vf.mPositions[i]; - vec.mul(scalea); + vec.mul(scalea); - switch (texgen) + switch (texgen) + { + case LLTextureEntry::TEX_GEN_PLANAR: + planarProjection(tc, norm, center, vec); + break; + case LLTextureEntry::TEX_GEN_SPHERICAL: + sphericalProjection(tc, norm, center, vec); + break; + case LLTextureEntry::TEX_GEN_CYLINDRICAL: + cylindricalProjection(tc, norm, center, vec); + break; + default: + break; + } + } + + if (tex_mode && mTextureMatrix) { - case LLTextureEntry::TEX_GEN_PLANAR: - planarProjection(tc, norm, center, vec); + LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f); + tmp = tmp * *mTextureMatrix; + tc.mV[0] = tmp.mV[0]; + tc.mV[1] = tmp.mV[1]; + } + else + { + xform(tc, cos_ang, sin_ang, os, ot, ms, mt); + } + + if(in_atlas) + { + // + //manually calculate tex-coord per vertex for varying address modes. + //should be removed if shader can handle this. + // + + S32 int_part = 0 ; + switch(mTexture->getAddressMode()) + { + case LLTexUnit::TAM_CLAMP: + if(tc.mV[0] < 0.f) + { + tc.mV[0] = 0.f ; + } + else if(tc.mV[0] > 1.f) + { + tc.mV[0] = 1.f; + } + + if(tc.mV[1] < 0.f) + { + tc.mV[1] = 0.f ; + } + else if(tc.mV[1] > 1.f) + { + tc.mV[1] = 1.f; + } break; - case LLTextureEntry::TEX_GEN_SPHERICAL: - sphericalProjection(tc, norm, center, vec); + case LLTexUnit::TAM_MIRROR: + if(tc.mV[0] < 0.f) + { + tc.mV[0] = -tc.mV[0] ; + } + int_part = (S32)tc.mV[0] ; + if(int_part & 1) //odd number + { + tc.mV[0] = int_part + 1 - tc.mV[0] ; + } + else //even number + { + tc.mV[0] -= int_part ; + } + + if(tc.mV[1] < 0.f) + { + tc.mV[1] = -tc.mV[1] ; + } + int_part = (S32)tc.mV[1] ; + if(int_part & 1) //odd number + { + tc.mV[1] = int_part + 1 - tc.mV[1] ; + } + else //even number + { + tc.mV[1] -= int_part ; + } break; - case LLTextureEntry::TEX_GEN_CYLINDRICAL: - cylindricalProjection(tc, norm, center, vec); + case LLTexUnit::TAM_WRAP: + if(tc.mV[0] > 1.f) + tc.mV[0] -= (S32)(tc.mV[0] - 0.00001f) ; + else if(tc.mV[0] < -1.f) + tc.mV[0] -= (S32)(tc.mV[0] + 0.00001f) ; + + if(tc.mV[1] > 1.f) + tc.mV[1] -= (S32)(tc.mV[1] - 0.00001f) ; + else if(tc.mV[1] < -1.f) + tc.mV[1] -= (S32)(tc.mV[1] + 0.00001f) ; + + if(tc.mV[0] < 0.f) + { + tc.mV[0] = 1.0f + tc.mV[0] ; + } + if(tc.mV[1] < 0.f) + { + tc.mV[1] = 1.0f + tc.mV[1] ; + } break; default: break; - } - } + } + + tc.mV[0] = tcoord_xoffset + tcoord_xscale * tc.mV[0] ; + tc.mV[1] = tcoord_yoffset + tcoord_yscale * tc.mV[1] ; + } + - if (tex_mode && mTextureMatrix) - { - LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f); - tmp = tmp * *mTextureMatrix; - tc.mV[0] = tmp.mV[0]; - tc.mV[1] = tmp.mV[1]; + *tex_coords++ = tc; + if (do_bump) + { + bump_tc.push_back(tc); + } } - else + + if (map_range) { - xform(tc, cos_ang, sin_ang, os, ot, ms, mt); + mVertexBuffer->flush(); } - if(in_atlas) + if (do_bump) { - // - //manually calculate tex-coord per vertex for varying address modes. - //should be removed if shader can handle this. - // - - S32 int_part = 0 ; - switch(mTexture->getAddressMode()) + mVertexBuffer->getTexCoord1Strider(tex_coords2, mGeomIndex, mGeomCount, map_range); + + for (S32 i = 0; i < num_vertices; i++) { - case LLTexUnit::TAM_CLAMP: - if(tc.mV[0] < 0.f) - { - tc.mV[0] = 0.f ; - } - else if(tc.mV[0] > 1.f) - { - tc.mV[0] = 1.f; - } - - if(tc.mV[1] < 0.f) - { - tc.mV[1] = 0.f ; - } - else if(tc.mV[1] > 1.f) - { - tc.mV[1] = 1.f; - } - break; - case LLTexUnit::TAM_MIRROR: - if(tc.mV[0] < 0.f) - { - tc.mV[0] = -tc.mV[0] ; - } - int_part = (S32)tc.mV[0] ; - if(int_part & 1) //odd number - { - tc.mV[0] = int_part + 1 - tc.mV[0] ; - } - else //even number + LLVector4a tangent; + tangent.setCross3(vf.mBinormals[i], vf.mNormals[i]); + + LLMatrix4a tangent_to_object; + tangent_to_object.setRows(tangent, vf.mBinormals[i], vf.mNormals[i]); + LLVector4a t; + tangent_to_object.rotate(binormal_dir, t); + LLVector4a binormal; + mat_normal.rotate(t, binormal); + + //VECTORIZE THIS + if (mDrawablep->isActive()) { - tc.mV[0] -= int_part ; + LLVector3 t; + t.set(binormal.getF32ptr()); + t *= bump_quat; + binormal.load3(t.mV); } - if(tc.mV[1] < 0.f) - { - tc.mV[1] = -tc.mV[1] ; - } - int_part = (S32)tc.mV[1] ; - if(int_part & 1) //odd number - { - tc.mV[1] = int_part + 1 - tc.mV[1] ; - } - else //even number - { - tc.mV[1] -= int_part ; - } - break; - case LLTexUnit::TAM_WRAP: - if(tc.mV[0] > 1.f) - tc.mV[0] -= (S32)(tc.mV[0] - 0.00001f) ; - else if(tc.mV[0] < -1.f) - tc.mV[0] -= (S32)(tc.mV[0] + 0.00001f) ; - - if(tc.mV[1] > 1.f) - tc.mV[1] -= (S32)(tc.mV[1] - 0.00001f) ; - else if(tc.mV[1] < -1.f) - tc.mV[1] -= (S32)(tc.mV[1] + 0.00001f) ; - - if(tc.mV[0] < 0.f) - { - tc.mV[0] = 1.0f + tc.mV[0] ; - } - if(tc.mV[1] < 0.f) - { - tc.mV[1] = 1.0f + tc.mV[1] ; - } - break; - default: - break; + binormal.normalize3fast(); + LLVector2 tc = bump_tc[i]; + tc += LLVector2( bump_s_primary_light_ray.dot3(tangent).getF32(), bump_t_primary_light_ray.dot3(binormal).getF32() ); + + *tex_coords2++ = tc; } - - tc.mV[0] = tcoord_xoffset + tcoord_xscale * tc.mV[0] ; - tc.mV[1] = tcoord_yoffset + tcoord_yscale * tc.mV[1] ; - } - - - *tex_coords++ = tc; - if (do_bump) - { - bump_tc.push_back(tc); - } - } - - if (map_range) - { - mVertexBuffer->flush(); - } - if (do_bump) - { - mVertexBuffer->getTexCoord1Strider(tex_coords2, mGeomIndex, mGeomCount, map_range); - - for (S32 i = 0; i < num_vertices; i++) - { - LLVector4a tangent; - tangent.setCross3(vf.mBinormals[i], vf.mNormals[i]); - - LLMatrix4a tangent_to_object; - tangent_to_object.setRows(tangent, vf.mBinormals[i], vf.mNormals[i]); - LLVector4a t; - tangent_to_object.rotate(binormal_dir, t); - LLVector4a binormal; - mat_normal.rotate(t, binormal); - - //VECTORIZE THIS - if (mDrawablep->isActive()) + if (map_range) { - LLVector3 t; - t.set(binormal.getF32ptr()); - t *= bump_quat; - binormal.load3(t.mV); + mVertexBuffer->flush(); } - - binormal.normalize3fast(); - LLVector2 tc = bump_tc[i]; - tc += LLVector2( bump_s_primary_light_ray.dot3(tangent).getF32(), bump_t_primary_light_ray.dot3(binormal).getF32() ); - - *tex_coords2++ = tc; - } - - if (map_range) - { - mVertexBuffer->flush(); } } } - } - if (rebuild_pos) - { - LLFastTimer t(FTM_FACE_GEOM_POSITION); - llassert(num_vertices > 0); + if (rebuild_pos) + { + LLFastTimer t(FTM_FACE_GEOM_POSITION); + llassert(num_vertices > 0); - mVertexBuffer->getVertexStrider(vert, mGeomIndex, mGeomCount, map_range); + mVertexBuffer->getVertexStrider(vert, mGeomIndex, mGeomCount, map_range); - LLMatrix4a mat_vert; - mat_vert.loadu(mat_vert_in); + LLMatrix4a mat_vert; + mat_vert.loadu(mat_vert_in); - LLVector4a* src = vf.mPositions; - volatile F32* dst = (volatile F32*) vert.get(); + LLVector4a* src = vf.mPositions; + volatile F32* dst = (volatile F32*) vert.get(); - volatile F32* end = dst+num_vertices*4; - LLVector4a res; + volatile F32* end = dst+num_vertices*4; + LLVector4a res; - LLVector4a texIdx; + LLVector4a texIdx; - U8 index = mTextureIndex < 255 ? mTextureIndex : 0; + U8 index = mTextureIndex < 255 ? mTextureIndex : 0; - F32 val = 0.f; - U8* vp = (U8*) &val; - vp[0] = index; - vp[1] = 0; - vp[2] = 0; - vp[3] = 0; + F32 val = 0.f; + U8* vp = (U8*) &val; + vp[0] = index; + vp[1] = 0; + vp[2] = 0; + vp[3] = 0; - llassert(index <= LLGLSLShader::sIndexedTextureChannels-1); + llassert(index <= LLGLSLShader::sIndexedTextureChannels-1); - LLVector4Logical mask; - mask.clear(); - mask.setElement<3>(); + LLVector4Logical mask; + mask.clear(); + mask.setElement<3>(); - texIdx.set(0,0,0,val); + texIdx.set(0,0,0,val); - { - LLFastTimer t(FTM_FACE_POSITION_STORE); - LLVector4a tmp; - - do - { - mat_vert.affineTransform(*src++, res); - tmp.setSelectWithMask(mask, texIdx, res); - tmp.store4a((F32*) dst); - dst += 4; + { + LLFastTimer t(FTM_FACE_POSITION_STORE); + LLVector4a tmp; + + do + { + mat_vert.affineTransform(*src++, res); + tmp.setSelectWithMask(mask, texIdx, res); + tmp.store4a((F32*) dst); + dst += 4; + } + while(dst < end); } - while(dst < end); - } - { - LLFastTimer t(FTM_FACE_POSITION_PAD); - S32 aligned_pad_vertices = mGeomCount - num_vertices; - res.set(res[0], res[1], res[2], 0.f); + { + LLFastTimer t(FTM_FACE_POSITION_PAD); + S32 aligned_pad_vertices = mGeomCount - num_vertices; + res.set(res[0], res[1], res[2], 0.f); - while (aligned_pad_vertices > 0) + while (aligned_pad_vertices > 0) + { + --aligned_pad_vertices; + res.store4a((F32*) dst); + dst += 4; + } + } + + if (map_range) { - --aligned_pad_vertices; - res.store4a((F32*) dst); - dst += 4; + mVertexBuffer->flush(); } } - if (map_range) - { - mVertexBuffer->flush(); - } - } - if (rebuild_normal) - { - LLFastTimer t(FTM_FACE_GEOM_NORMAL); - mVertexBuffer->getNormalStrider(norm, mGeomIndex, mGeomCount, map_range); - F32* normals = (F32*) norm.get(); + if (rebuild_normal) + { + LLFastTimer t(FTM_FACE_GEOM_NORMAL); + mVertexBuffer->getNormalStrider(norm, mGeomIndex, mGeomCount, map_range); + F32* normals = (F32*) norm.get(); - for (S32 i = 0; i < num_vertices; i++) - { - LLVector4a normal; - mat_normal.rotate(vf.mNormals[i], normal); - normal.normalize3fast(); - normal.store4a(normals); - normals += 4; - } + for (S32 i = 0; i < num_vertices; i++) + { + LLVector4a normal; + mat_normal.rotate(vf.mNormals[i], normal); + normal.normalize3fast(); + normal.store4a(normals); + normals += 4; + } - if (map_range) - { - mVertexBuffer->flush(); + if (map_range) + { + mVertexBuffer->flush(); + } } - } - if (rebuild_binormal) - { - LLFastTimer t(FTM_FACE_GEOM_BINORMAL); - mVertexBuffer->getBinormalStrider(binorm, mGeomIndex, mGeomCount, map_range); - F32* binormals = (F32*) binorm.get(); + if (rebuild_binormal) + { + LLFastTimer t(FTM_FACE_GEOM_BINORMAL); + mVertexBuffer->getBinormalStrider(binorm, mGeomIndex, mGeomCount, map_range); + F32* binormals = (F32*) binorm.get(); - for (S32 i = 0; i < num_vertices; i++) - { - LLVector4a binormal; - mat_normal.rotate(vf.mBinormals[i], binormal); - binormal.normalize3fast(); - binormal.store4a(binormals); - binormals += 4; - } + for (S32 i = 0; i < num_vertices; i++) + { + LLVector4a binormal; + mat_normal.rotate(vf.mBinormals[i], binormal); + binormal.normalize3fast(); + binormal.store4a(binormals); + binormals += 4; + } - if (map_range) - { - mVertexBuffer->flush(); + if (map_range) + { + mVertexBuffer->flush(); + } } - } - if (rebuild_weights && vf.mWeights) - { - LLFastTimer t(FTM_FACE_GEOM_WEIGHTS); - mVertexBuffer->getWeight4Strider(wght, mGeomIndex, mGeomCount, map_range); - F32* weights = (F32*) wght.get(); - LLVector4a::memcpyNonAliased16(weights, (F32*) vf.mWeights, num_vertices*4*sizeof(F32)); - if (map_range) + if (rebuild_weights && vf.mWeights) { - mVertexBuffer->flush(); + LLFastTimer t(FTM_FACE_GEOM_WEIGHTS); + mVertexBuffer->getWeight4Strider(wght, mGeomIndex, mGeomCount, map_range); + F32* weights = (F32*) wght.get(); + LLVector4a::memcpyNonAliased16(weights, (F32*) vf.mWeights, num_vertices*4*sizeof(F32)); + if (map_range) + { + mVertexBuffer->flush(); + } } - } - if (rebuild_color && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_COLOR) ) - { - LLFastTimer t(FTM_FACE_GEOM_COLOR); - mVertexBuffer->getColorStrider(colors, mGeomIndex, mGeomCount, map_range); + if (rebuild_color && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_COLOR) ) + { + LLFastTimer t(FTM_FACE_GEOM_COLOR); + mVertexBuffer->getColorStrider(colors, mGeomIndex, mGeomCount, map_range); - LLVector4a src; + LLVector4a src; - U32 vec[4]; - vec[0] = vec[1] = vec[2] = vec[3] = color.mAll; + U32 vec[4]; + vec[0] = vec[1] = vec[2] = vec[3] = color.mAll; - src.loadua((F32*) vec); + src.loadua((F32*) vec); - F32* dst = (F32*) colors.get(); - S32 num_vecs = num_vertices/4; - if (num_vertices%4 > 0) - { - ++num_vecs; - } + F32* dst = (F32*) colors.get(); + S32 num_vecs = num_vertices/4; + if (num_vertices%4 > 0) + { + ++num_vecs; + } - for (S32 i = 0; i < num_vecs; i++) - { - src.store4a(dst); - dst += 4; - } + for (S32 i = 0; i < num_vecs; i++) + { + src.store4a(dst); + dst += 4; + } - if (map_range) - { - mVertexBuffer->flush(); + if (map_range) + { + mVertexBuffer->flush(); + } } - } - if (rebuild_emissive) - { - LLFastTimer t(FTM_FACE_GEOM_EMISSIVE); - LLStrider<LLColor4U> emissive; - mVertexBuffer->getEmissiveStrider(emissive, mGeomIndex, mGeomCount, map_range); + if (rebuild_emissive) + { + LLFastTimer t(FTM_FACE_GEOM_EMISSIVE); + LLStrider<LLColor4U> emissive; + mVertexBuffer->getEmissiveStrider(emissive, mGeomIndex, mGeomCount, map_range); - U8 glow = (U8) llclamp((S32) (getTextureEntry()->getGlow()*255), 0, 255); + U8 glow = (U8) llclamp((S32) (getTextureEntry()->getGlow()*255), 0, 255); - LLVector4a src; + LLVector4a src; - U32 glow32 = glow | - (glow << 8) | - (glow << 16) | - (glow << 24); + U32 glow32 = glow | + (glow << 8) | + (glow << 16) | + (glow << 24); - U32 vec[4]; - vec[0] = vec[1] = vec[2] = vec[3] = glow32; + U32 vec[4]; + vec[0] = vec[1] = vec[2] = vec[3] = glow32; - src.loadua((F32*) vec); + src.loadua((F32*) vec); - F32* dst = (F32*) emissive.get(); - S32 num_vecs = num_vertices/4; - if (num_vertices%4 > 0) - { - ++num_vecs; - } + F32* dst = (F32*) emissive.get(); + S32 num_vecs = num_vertices/4; + if (num_vertices%4 > 0) + { + ++num_vecs; + } - for (S32 i = 0; i < num_vecs; i++) - { - src.store4a(dst); - dst += 4; - } + for (S32 i = 0; i < num_vecs; i++) + { + src.store4a(dst); + dst += 4; + } - if (map_range) - { - mVertexBuffer->flush(); + if (map_range) + { + mVertexBuffer->flush(); + } } } + if (rebuild_tcoord) { mTexExtents[0].setVec(0,0); @@ -1933,12 +2139,6 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, } - mLastVertexBuffer = mVertexBuffer; - mLastGeomCount = mGeomCount; - mLastGeomIndex = mGeomIndex; - mLastIndicesCount = mIndicesCount; - mLastIndicesIndex = mIndicesIndex; - return TRUE; } @@ -2517,7 +2717,6 @@ void LLFace::setVertexBuffer(LLVertexBuffer* buffer) void LLFace::clearVertexBuffer() { mVertexBuffer = NULL; - mLastVertexBuffer = NULL; } //static diff --git a/indra/newview/llface.h b/indra/newview/llface.h index feb6244f72..5dca27487f 100755 --- a/indra/newview/llface.h +++ b/indra/newview/llface.h @@ -94,6 +94,8 @@ public: static void initClass(); + static void cacheFaceInVRAM(const LLVolumeFace& vf); + public: LLFace(LLDrawable* drawablep, LLViewerObject* objp) { init(drawablep, objp); } ~LLFace() { destroy(); } @@ -233,7 +235,7 @@ public: //vertex buffer tracking void setVertexBuffer(LLVertexBuffer* buffer); - void clearVertexBuffer(); //sets mVertexBuffer and mLastVertexBuffer to NULL + void clearVertexBuffer(); //sets mVertexBuffer to NULL LLVertexBuffer* getVertexBuffer() const { return mVertexBuffer; } U32 getRiggedVertexBufferDataMask() const; S32 getRiggedIndex(U32 type) const; @@ -266,8 +268,7 @@ public: private: LLPointer<LLVertexBuffer> mVertexBuffer; - LLPointer<LLVertexBuffer> mLastVertexBuffer; - + U32 mState; LLFacePool* mDrawPoolp; U32 mPoolType; @@ -280,12 +281,6 @@ private: U32 mIndicesIndex; // index into draw pool for indices (yeah, I know!) S32 mIndexInTex ; - //previous rebuild's geometry info - U16 mLastGeomCount; - U16 mLastGeomIndex; - U32 mLastIndicesCount; - U32 mLastIndicesIndex; - LLXformMatrix* mXform; LLPointer<LLViewerTexture> mTexture; LLPointer<LLDrawable> mDrawablep; diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index 575b613ccf..4cbc9cab4a 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -1191,7 +1191,7 @@ void LLFavoritesBarCtrl::doToSelected(const LLSD& userdata) } else if (action == "paste") { - pastFromClipboard(); + pasteFromClipboard(); } else if (action == "delete") { @@ -1239,7 +1239,7 @@ BOOL LLFavoritesBarCtrl::isClipboardPasteable() const return TRUE; } -void LLFavoritesBarCtrl::pastFromClipboard() const +void LLFavoritesBarCtrl::pasteFromClipboard() const { LLInventoryModel* model = &gInventory; if(model && isClipboardPasteable()) diff --git a/indra/newview/llfavoritesbar.h b/indra/newview/llfavoritesbar.h index 2f75b3bb0e..447d30f1f4 100644 --- a/indra/newview/llfavoritesbar.h +++ b/indra/newview/llfavoritesbar.h @@ -90,7 +90,7 @@ protected: bool enableSelected(const LLSD& userdata); void doToSelected(const LLSD& userdata); BOOL isClipboardPasteable() const; - void pastFromClipboard() const; + void pasteFromClipboard() const; void showDropDownMenu(); diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index 8986a694f9..4bf5b26b3b 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -59,6 +59,7 @@ LLFilePicker LLFilePicker::sInstance; #define RAW_FILTER L"RAW files (*.raw)\0*.raw\0" #define MODEL_FILTER L"Model files (*.dae)\0*.dae\0" #define SCRIPT_FILTER L"Script files (*.lsl)\0*.lsl\0" +#define DICTIONARY_FILTER L"Dictionary files (*.dic; *.xcu)\0*.dic;*.xcu\0" #endif // @@ -218,6 +219,10 @@ BOOL LLFilePicker::setupFilter(ELoadFilter filter) mOFN.lpstrFilter = SCRIPT_FILTER \ L"\0"; break; + case FFLOAD_DICTIONARY: + mOFN.lpstrFilter = DICTIONARY_FILTER \ + L"\0"; + break; default: res = FALSE; break; @@ -643,6 +648,16 @@ Boolean LLFilePicker::navOpenFilterProc(AEDesc *theItem, void *info, void *callB result = false; } } + else if (filter == FFLOAD_DICTIONARY) + { + if (fileInfo.filetype != 'DIC ' && + fileInfo.filetype != 'XCU ' && + (fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("dic"), kCFCompareCaseInsensitive) != kCFCompareEqualTo) && + fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("xcu"), kCFCompareCaseInsensitive) != kCFCompareEqualTo))) + { + result = false; + } + } if (fileInfo.extension) { @@ -1235,6 +1250,12 @@ static std::string add_script_filter_to_gtkchooser(GtkWindow *picker) LLTrans::getString("script_files") + " (*.lsl)"); } +static std::string add_dictionary_filter_to_gtkchooser(GtkWindow *picker) +{ + return add_simple_mime_filter_to_gtkchooser(picker, "text/plain", + LLTrans::getString("dictionary_files") + " (*.dic; *.xcu)"); +} + BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename ) { BOOL rtn = FALSE; @@ -1371,6 +1392,9 @@ BOOL LLFilePicker::getOpenFile( ELoadFilter filter, bool blocking ) case FFLOAD_SCRIPT: filtername = add_script_filter_to_gtkchooser(picker); break; + case FFLOAD_DICTIONARY: + filtername = add_dictionary_filter_to_gtkchooser(picker); + break; default:; break; } diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h index a4d5d68ff5..55c665b9c7 100644 --- a/indra/newview/llfilepicker.h +++ b/indra/newview/llfilepicker.h @@ -85,6 +85,7 @@ public: FFLOAD_MODEL = 9, FFLOAD_COLLADA = 10, FFLOAD_SCRIPT = 11, + FFLOAD_DICTIONARY = 12 }; enum ESaveFilter diff --git a/indra/newview/llflexibleobject.cpp b/indra/newview/llflexibleobject.cpp index 32a533570a..11edb60712 100644 --- a/indra/newview/llflexibleobject.cpp +++ b/indra/newview/llflexibleobject.cpp @@ -368,7 +368,7 @@ void LLVolumeImplFlexible::doFlexibleUpdate() LLPath *path = &volume->getPath(); if ((mSimulateRes == 0 || !mInitialized) && mVO->mDrawable->isVisible()) { - mVO->markForUpdate(TRUE); + //mVO->markForUpdate(TRUE); if (!doIdleUpdate(gAgent, *LLWorld::getInstance(), 0.0)) { return; // we did not get updated or initialized, proceeding without can be dangerous @@ -729,7 +729,11 @@ BOOL LLVolumeImplFlexible::doUpdateGeometry(LLDrawable *drawable) else if (!mUpdated || rotated) { volume->mDrawable->setState(LLDrawable::REBUILD_POSITION); - volume->dirtyMesh(); + LLSpatialGroup* group = volume->mDrawable->getSpatialGroup(); + if (group) + { + group->dirtyMesh(); + } volume->genBBoxes(isVolumeGlobal()); } @@ -814,15 +818,17 @@ LLQuaternion LLVolumeImplFlexible::getEndRotation() }//------------------------------------------------------------------ -void LLVolumeImplFlexible::updateRelativeXform() +void LLVolumeImplFlexible::updateRelativeXform(bool force_identity) { LLQuaternion delta_rot; LLVector3 delta_pos, delta_scale; LLVOVolume* vo = (LLVOVolume*) mVO; + bool use_identity = vo->mDrawable->isSpatialRoot() || force_identity; + //matrix from local space to parent relative/global space - delta_rot = vo->mDrawable->isSpatialRoot() ? LLQuaternion() : vo->mDrawable->getRotation(); - delta_pos = vo->mDrawable->isSpatialRoot() ? LLVector3(0,0,0) : vo->mDrawable->getPosition(); + delta_rot = use_identity ? LLQuaternion() : vo->mDrawable->getRotation(); + delta_pos = use_identity ? LLVector3(0,0,0) : vo->mDrawable->getPosition(); delta_scale = LLVector3(1,1,1); // Vertex transform (4x4) diff --git a/indra/newview/llflexibleobject.h b/indra/newview/llflexibleobject.h index fef43d464d..371d6a0773 100644 --- a/indra/newview/llflexibleobject.h +++ b/indra/newview/llflexibleobject.h @@ -89,7 +89,7 @@ class LLVolumeImplFlexible : public LLVolumeInterface bool isVolumeGlobal() const { return true; } bool isActive() const { return true; } const LLMatrix4& getWorldMatrix(LLXformMatrix* xform) const; - void updateRelativeXform(); + void updateRelativeXform(bool force_identity); void doFlexibleUpdate(); // Called to update the simulation void doFlexibleRebuild(); // Called to rebuild the geometry void preRebuild(); diff --git a/indra/newview/llfloaterautoreplacesettings.cpp b/indra/newview/llfloaterautoreplacesettings.cpp new file mode 100644 index 0000000000..7d1bcba978 --- /dev/null +++ b/indra/newview/llfloaterautoreplacesettings.cpp @@ -0,0 +1,641 @@ +/** + * @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 "llagentdata.h" +#include "llcommandhandler.h" +#include "llfloater.h" +#include "lluictrlfactory.h" +#include "llagent.h" +#include "llpanel.h" +#include "llbutton.h" +#include "llcolorswatch.h" +#include "llcombobox.h" +#include "llview.h" +#include "llhttpclient.h" +#include "llbufferstream.h" +#include "llcheckboxctrl.h" +#include "llviewercontrol.h" + +#include "llui.h" +#include "llcontrol.h" +#include "llscrollingpanellist.h" +#include "llautoreplace.h" +#include "llfilepicker.h" +#include "llfile.h" +#include "llsdserialize.h" +#include "llsdutil.h" + +#include "llchat.h" +#include "llinventorymodel.h" +#include "llhost.h" +#include "llassetstorage.h" +#include "roles_constants.h" +#include "llviewertexteditor.h" +#include <boost/tokenizer.hpp> + +#include <iosfwd> +#include "llfloaterreg.h" +#include "llinspecttoast.h" +#include "llnotificationhandler.h" +#include "llnotificationmanager.h" +#include "llnotificationsutil.h" + + +LLFloaterAutoReplaceSettings::LLFloaterAutoReplaceSettings(const LLSD& key) + : LLFloater(key) + , mSelectedListName("") + , mListNames(NULL) + , mReplacementsList(NULL) + , mKeyword(NULL) + , mPreviousKeyword("") + , mReplacement(NULL) +{ +} + +void LLFloaterAutoReplaceSettings::onClose(bool app_quitting) +{ + cleanUp(); +} + +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::onCancel, this)); + + // 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() +{ + LLFilePicker& picker = LLFilePicker::instance(); + if( picker.getOpenFile( LLFilePicker::FFLOAD_XML) ) + { + llifstream file; + file.open(picker.getFirstFile().c_str()); + 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"]; + + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + switch ( option ) + { + case 0: + // Replace current list + LL_INFOS("AutoReplace")<<"option 'replace current list' selected"<<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->getFirstSelected()->getColumn(0)->getValue().asString(); + mSettings.removeReplacementList(listName); // remove from the copy of settings + mReplacementsList->deleteSelectedItems(); // remove from the scrolling list + + mSelectedListName.clear(); + updateListNames(); + updateListNamesControls(); + updateReplacementsList(); +} + +void LLFloaterAutoReplaceSettings::onExportList() +{ + std::string listName=mListNames->getFirstSelected()->getColumn(0)->getValue().asString(); + const LLSD* list = mSettings.exportList(listName); + std::string listFileName = listName + ".xml"; + LLFilePicker& picker = LLFilePicker::instance(); + if( picker.getSaveFile( LLFilePicker::FFSAVE_XML, listFileName) ) + { + llofstream file; + file.open(picker.getFirstFile().c_str()); + 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::onCancel() +{ + cleanUp(); + closeFloater(false /* not quitting */); +} + +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); + cleanUp(); + closeFloater(false /* not quitting */); +} + +void LLFloaterAutoReplaceSettings::cleanUp() +{ + +} + +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"); +*/ diff --git a/indra/newview/llfloaterautoreplacesettings.h b/indra/newview/llfloaterautoreplacesettings.h new file mode 100644 index 0000000000..629aea3e3c --- /dev/null +++ b/indra/newview/llfloaterautoreplacesettings.h @@ -0,0 +1,117 @@ +/** + * @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 "llmediactrl.h" +#include "llscrolllistctrl.h" +#include "lllineeditor.h" + +#include "llviewerinventory.h" +#include <boost/bind.hpp> +#include "llautoreplace.h" + +class LLFloaterAutoReplaceSettings : public LLFloater +{ +public: + LLFloaterAutoReplaceSettings(const LLSD& key); + + /*virtual*/ BOOL postBuild(); + /*virtual*/ void onClose(bool app_quitting); + + void setData(void * data); + +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 onExportList(); + void onNewList(); + void onDeleteList(); + + void onListUp(); + void onListDown(); + + void onSelectEntry(); + void onAddEntry(); + void onDeleteEntry(); + void onSaveEntry(); + + void onSaveChanges(); + void onCancel(); + + /// 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(); + + void cleanUp(); +}; + +#endif // LLFLOATERAUTOREPLACESETTINGS_H diff --git a/indra/newview/llfloaterbvhpreview.cpp b/indra/newview/llfloaterbvhpreview.cpp index ac33a05f42..fa0ad20fdb 100644 --- a/indra/newview/llfloaterbvhpreview.cpp +++ b/indra/newview/llfloaterbvhpreview.cpp @@ -1124,9 +1124,13 @@ BOOL LLPreviewAnimation::render() LLVertexBuffer::unbind(); LLGLDepthTest gls_depth(GL_TRUE); - LLDrawPoolAvatar *avatarPoolp = (LLDrawPoolAvatar *)avatarp->mDrawable->getFace(0)->getPool(); - avatarp->dirtyMesh(); - avatarPoolp->renderAvatars(avatarp); // renders only one avatar + LLFace* face = avatarp->mDrawable->getFace(0); + if (face) + { + LLDrawPoolAvatar *avatarPoolp = (LLDrawPoolAvatar *)face->getPool(); + avatarp->dirtyMesh(); + avatarPoolp->renderAvatars(avatarp); // renders only one avatar + } } gGL.color4f(1,1,1,1); diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp index 92ee8ddac6..6b2492d927 100644 --- a/indra/newview/llfloaterimagepreview.cpp +++ b/indra/newview/llfloaterimagepreview.cpp @@ -704,9 +704,13 @@ BOOL LLImagePreviewAvatar::render() // make sure alpha=0 shows avatar material color LLGLDisable no_blend(GL_BLEND); - LLDrawPoolAvatar *avatarPoolp = (LLDrawPoolAvatar *)avatarp->mDrawable->getFace(0)->getPool(); - gPipeline.enableLightsPreview(); - avatarPoolp->renderAvatars(avatarp); // renders only one avatar + LLFace* face = avatarp->mDrawable->getFace(0); + if (face) + { + LLDrawPoolAvatar *avatarPoolp = (LLDrawPoolAvatar *)face->getPool(); + gPipeline.enableLightsPreview(); + avatarPoolp->renderAvatars(avatarp); // renders only one avatar + } } gGL.popUIMatrix(); diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp index ee18c95b34..61da99fe3a 100644 --- a/indra/newview/llfloaterland.cpp +++ b/indra/newview/llfloaterland.cpp @@ -1865,23 +1865,8 @@ BOOL LLPanelLandOptions::postBuild() childSetCommitCallback("ShowDirectoryCheck", onCommitAny, this); - if (gAgent.getAgentAccess().isInTransition()) - { - // during the AO transition, this combo has an Adult item. - // Post-transition, it goes away. We can remove this conditional - // after the transition and just use the "else" clause. - mCategoryCombo = getChild<LLComboBox>( "land category with adult"); - childSetCommitCallback("land category with adult", onCommitAny, this); - } - else - { - // this is the code that should be preserved post-transition - // you could also change the XML to set visibility and enabled true. - mCategoryCombo = getChild<LLComboBox>( "land category"); - childSetCommitCallback("land category", onCommitAny, this); - } - mCategoryCombo->setVisible(true); - mCategoryCombo->setEnabled(true); + mCategoryCombo = getChild<LLComboBox>( "land category"); + childSetCommitCallback("land category", onCommitAny, this); mMatureCtrl = getChild<LLCheckBoxCtrl>( "MatureCheck"); @@ -1901,6 +1886,7 @@ BOOL LLPanelLandOptions::postBuild() mSnapshotCtrl->setCommitCallback( onCommitAny, this ); mSnapshotCtrl->setAllowNoTexture ( TRUE ); mSnapshotCtrl->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER); + mSnapshotCtrl->setDnDFilterPermMask(PERM_COPY | PERM_TRANSFER); mSnapshotCtrl->setNonImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER); } else diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 3b86ca7a7c..35341ef0ea 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -396,7 +396,6 @@ mCalculateBtn(NULL) sInstance = this; mLastMouseX = 0; mLastMouseY = 0; - mGLName = 0; mStatusLock = new LLMutex(NULL); mModelPreview = NULL; @@ -538,11 +537,6 @@ LLFloaterModelPreview::~LLFloaterModelPreview() delete mModelPreview; } - if (mGLName) - { - LLImageGL::deleteTextures(1, &mGLName ); - } - delete mStatusLock; mStatusLock = NULL; } @@ -5054,15 +5048,7 @@ BOOL LLModelPreview::render() LLRect preview_rect; - LLFloaterModelWizard* floater_wizard = dynamic_cast<LLFloaterModelWizard*>(mFMP); - if (floater_wizard) - { - preview_rect = floater_wizard->getPreviewRect(); - } - else - { - preview_rect = mFMP->getChildView("preview_panel")->getRect(); - } + preview_rect = mFMP->getChildView("preview_panel")->getRect(); F32 aspect = (F32) preview_rect.getWidth()/preview_rect.getHeight(); @@ -5606,7 +5592,6 @@ void LLModelPreview::setPreviewLOD(S32 lod) combo_box->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order mFMP->childSetText("lod_file_" + lod_name[mPreviewLOD], mLODFile[mPreviewLOD]); - // the wizard has three lod drop downs LLComboBox* combo_box2 = mFMP->getChild<LLComboBox>("preview_lod_combo2"); combo_box2->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index 64324854a5..ab319c30d5 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -30,12 +30,12 @@ #include "llfloaternamedesc.h" #include "lldynamictexture.h" -#include "llfloatermodelwizard.h" #include "llquaternion.h" #include "llmeshrepository.h" #include "llmodel.h" #include "llthread.h" #include "llviewermenufile.h" +#include "llfloatermodeluploadbase.h" class LLComboBox; class LLJoint; @@ -256,7 +256,6 @@ protected: S32 mLastMouseX; S32 mLastMouseY; LLRect mPreviewRect; - U32 mGLName; static S32 sUploadAmount; std::set<LLPointer<DecompRequest> > mCurRequest; @@ -390,9 +389,7 @@ private: protected: friend class LLModelLoader; friend class LLFloaterModelPreview; - friend class LLFloaterModelWizard; friend class LLFloaterModelPreview::DecompRequest; - friend class LLFloaterModelWizard::DecompRequest; friend class LLPhysicsDecomp; LLFloater* mFMP; diff --git a/indra/newview/llfloatermodelwizard.cpp b/indra/newview/llfloatermodelwizard.cpp deleted file mode 100644 index b517b78e5a..0000000000 --- a/indra/newview/llfloatermodelwizard.cpp +++ /dev/null @@ -1,795 +0,0 @@ -/** - * @file llfloatermodelwizard.cpp - * @author Leyla Farazha - * @brief Implementation of the LLFloaterModelWizard class. - * - * $LicenseInfo:firstyear=2002&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 "llbutton.h" -#include "lldrawable.h" -#include "llcheckboxctrl.h" -#include "llcombobox.h" -#include "llfloater.h" -#include "llfloatermodelwizard.h" -#include "llfloatermodelpreview.h" -#include "llfloaterreg.h" -#include "llsliderctrl.h" -#include "lltoolmgr.h" -#include "llviewerwindow.h" - -LLFloaterModelWizard* LLFloaterModelWizard::sInstance = NULL; - -static const std::string stateNames[]={ - "choose_file", - "optimize", - "physics", - "review", - "upload"}; - -static void swap_controls(LLUICtrl* first_ctrl, LLUICtrl* second_ctrl, bool first_ctr_visible); - -LLFloaterModelWizard::LLFloaterModelWizard(const LLSD& key) - : LLFloaterModelUploadBase(key) - ,mRecalculateGeometryBtn(NULL) - ,mRecalculatePhysicsBtn(NULL) - ,mRecalculatingPhysicsBtn(NULL) - ,mCalculateWeightsBtn(NULL) - ,mCalculatingWeightsBtn(NULL) - ,mChooseFilePreviewPanel(NULL) - ,mOptimizePreviewPanel(NULL) - ,mPhysicsPreviewPanel(NULL) -{ - mLastEnabledState = CHOOSE_FILE; - sInstance = this; - - mCommitCallbackRegistrar.add("Wizard.Choose", boost::bind(&LLFloaterModelWizard::setState, this, CHOOSE_FILE)); - mCommitCallbackRegistrar.add("Wizard.Optimize", boost::bind(&LLFloaterModelWizard::setState, this, OPTIMIZE)); - mCommitCallbackRegistrar.add("Wizard.Physics", boost::bind(&LLFloaterModelWizard::setState, this, PHYSICS)); - mCommitCallbackRegistrar.add("Wizard.Review", boost::bind(&LLFloaterModelWizard::setState, this, REVIEW)); - mCommitCallbackRegistrar.add("Wizard.Upload", boost::bind(&LLFloaterModelWizard::setState, this, UPLOAD)); -} -LLFloaterModelWizard::~LLFloaterModelWizard() -{ - sInstance = NULL; -} -void LLFloaterModelWizard::setState(int state) -{ - - mState = state; - - for(size_t t=0; t<LL_ARRAY_SIZE(stateNames); ++t) - { - LLView *view = getChildView(stateNames[t]+"_panel"); - if (view) - { - view->setVisible(state == (int) t ? TRUE : FALSE); - } - } - - LLView* current_preview_panel = NULL; - - if (state == CHOOSE_FILE) - { - mModelPreview->mViewOption["show_physics"] = false; - - current_preview_panel = mChooseFilePreviewPanel; - - getChildView("close")->setVisible(false); - getChildView("back")->setVisible(true); - getChildView("back")->setEnabled(false); - getChildView("next")->setVisible(true); - getChildView("upload")->setVisible(false); - getChildView("cancel")->setVisible(true); - mCalculateWeightsBtn->setVisible(false); - mCalculatingWeightsBtn->setVisible(false); - } - - if (state == OPTIMIZE) - { - if (mLastEnabledState < state) - { - mModelPreview->genLODs(-1); - } - - mModelPreview->mViewOption["show_physics"] = false; - - current_preview_panel = mOptimizePreviewPanel; - - getChildView("back")->setVisible(true); - getChildView("back")->setEnabled(true); - getChildView("close")->setVisible(false); - getChildView("next")->setVisible(true); - getChildView("upload")->setVisible(false); - getChildView("cancel")->setVisible(true); - mCalculateWeightsBtn->setVisible(false); - mCalculatingWeightsBtn->setVisible(false); - } - - if (state == PHYSICS) - { - if (mLastEnabledState < state) - { - mModelPreview->setPhysicsFromLOD(1); - - // Trigger the recalculate physics when first entering - // the Physics step. - onClickRecalculatePhysics(); - } - - mModelPreview->mViewOption["show_physics"] = true; - - current_preview_panel = mPhysicsPreviewPanel; - - getChildView("next")->setVisible(false); - getChildView("upload")->setVisible(false); - getChildView("close")->setVisible(false); - getChildView("back")->setVisible(true); - getChildView("back")->setEnabled(true); - getChildView("cancel")->setVisible(true); - mCalculateWeightsBtn->setVisible(true); - mCalculatingWeightsBtn->setVisible(false); - } - - if (state == REVIEW) - { - - mModelPreview->mViewOption["show_physics"] = false; - - getChildView("close")->setVisible(false); - getChildView("next")->setVisible(false); - getChildView("back")->setVisible(true); - getChildView("back")->setEnabled(true); - getChildView("upload")->setVisible(true); - getChildView("cancel")->setVisible(true); - mCalculateWeightsBtn->setVisible(false); - mCalculatingWeightsBtn->setVisible(false); - } - - if (state == UPLOAD) - { - getChildView("close")->setVisible(true); - getChildView("next")->setVisible(false); - getChildView("back")->setVisible(false); - getChildView("upload")->setVisible(false); - getChildView("cancel")->setVisible(false); - mCalculateWeightsBtn->setVisible(false); - mCalculatingWeightsBtn->setVisible(false); - } - - if (current_preview_panel) - { - LLRect rect; - current_preview_panel->localRectToOtherView(current_preview_panel->getLocalRect(), &rect, this); - - // Reduce the preview rect by 1 px to fit the borders - rect.stretch(-1); - - if (rect != mPreviewRect) - { - mPreviewRect = rect; - mModelPreview->refresh(); - } - } - updateButtons(); -} - - - -void LLFloaterModelWizard::updateButtons() -{ - if (mLastEnabledState < mState) - { - mLastEnabledState = mState; - } - - for(size_t i=0; i<LL_ARRAY_SIZE(stateNames); ++i) - { - LLButton *button = getChild<LLButton>(stateNames[i]+"_btn"); - - if (i == mState) - { - button->setEnabled(TRUE); - button->setToggleState(TRUE); - } - else if (i <= mLastEnabledState) - { - button->setEnabled(TRUE); - button->setToggleState(FALSE); - } - else - { - button->setEnabled(FALSE); - } - } -} - -void LLFloaterModelWizard::onClickSwitchToAdvanced() -{ - LLFloaterModelPreview* floater_preview = LLFloaterReg::getTypedInstance<LLFloaterModelPreview>("upload_model"); - if (!floater_preview) - { - llwarns << "FLoater model preview not found." << llendl; - return; - } - - // Open floater model preview - floater_preview->openFloater(); - - // Close the wizard - closeFloater(); - - std::string filename = getChild<LLUICtrl>("lod_file")->getValue().asString(); - if (!filename.empty()) - { - // Re-load the model to the floater model preview if it has been loaded - // into the wizard. - floater_preview->loadModel(3, filename); - } -} - -void LLFloaterModelWizard::onClickRecalculateGeometry() -{ - S32 val = getChild<LLUICtrl>("accuracy_slider")->getValue().asInteger(); - - mModelPreview->genLODs(-1, NUM_LOD - val); - - mModelPreview->refresh(); -} - -void LLFloaterModelWizard::onClickRecalculatePhysics() -{ - // Hide the "Recalculate physics" button and show the "Recalculating..." - // button instead. - swap_controls(mRecalculatePhysicsBtn, mRecalculatingPhysicsBtn, false); - - executePhysicsStage("Decompose"); -} - -void LLFloaterModelWizard::onClickCalculateUploadFee() -{ - swap_controls(mCalculateWeightsBtn, mCalculatingWeightsBtn, false); - - mModelPreview->rebuildUploadData(); - - mUploadModelUrl.clear(); - - gMeshRepo.uploadModel(mModelPreview->mUploadData, mModelPreview->mPreviewScale, - true, false, false, mUploadModelUrl, false, getWholeModelFeeObserverHandle()); -} - -void LLFloaterModelWizard::loadModel() -{ - mModelPreview->mLoading = TRUE; - - (new LLMeshFilePicker(mModelPreview, 3))->getFile(); -} - -void LLFloaterModelWizard::onClickCancel() -{ - closeFloater(); -} - -void LLFloaterModelWizard::onClickBack() -{ - setState(llmax((int) CHOOSE_FILE, mState-1)); -} - -void LLFloaterModelWizard::onClickNext() -{ - setState(llmin((int) UPLOAD, mState+1)); -} - -bool LLFloaterModelWizard::onEnableNext() -{ - return true; -} - -bool LLFloaterModelWizard::onEnableBack() -{ - return true; -} - - -//----------------------------------------------------------------------------- -// handleMouseDown() -//----------------------------------------------------------------------------- -BOOL LLFloaterModelWizard::handleMouseDown(S32 x, S32 y, MASK mask) -{ - if (mPreviewRect.pointInRect(x, y)) - { - bringToFront( x, y ); - gFocusMgr.setMouseCapture(this); - gViewerWindow->hideCursor(); - mLastMouseX = x; - mLastMouseY = y; - return TRUE; - } - - return LLFloater::handleMouseDown(x, y, mask); -} - -//----------------------------------------------------------------------------- -// handleMouseUp() -//----------------------------------------------------------------------------- -BOOL LLFloaterModelWizard::handleMouseUp(S32 x, S32 y, MASK mask) -{ - gFocusMgr.setMouseCapture(FALSE); - gViewerWindow->showCursor(); - return LLFloater::handleMouseUp(x, y, mask); -} - -//----------------------------------------------------------------------------- -// handleHover() -//----------------------------------------------------------------------------- -BOOL LLFloaterModelWizard::handleHover (S32 x, S32 y, MASK mask) -{ - MASK local_mask = mask & ~MASK_ALT; - - if (mModelPreview && hasMouseCapture()) - { - if (local_mask == MASK_PAN) - { - // pan here - mModelPreview->pan((F32)(x - mLastMouseX) * -0.005f, (F32)(y - mLastMouseY) * -0.005f); - } - else if (local_mask == MASK_ORBIT) - { - F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f; - F32 pitch_radians = (F32)(y - mLastMouseY) * 0.02f; - - mModelPreview->rotate(yaw_radians, pitch_radians); - } - else - { - - F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f; - F32 zoom_amt = (F32)(y - mLastMouseY) * 0.02f; - - mModelPreview->rotate(yaw_radians, 0.f); - mModelPreview->zoom(zoom_amt); - } - - - mModelPreview->refresh(); - - LLUI::setMousePositionLocal(this, mLastMouseX, mLastMouseY); - } - - if (!mPreviewRect.pointInRect(x, y) || !mModelPreview) - { - return LLFloater::handleHover(x, y, mask); - } - else if (local_mask == MASK_ORBIT) - { - gViewerWindow->setCursor(UI_CURSOR_TOOLCAMERA); - } - else if (local_mask == MASK_PAN) - { - gViewerWindow->setCursor(UI_CURSOR_TOOLPAN); - } - else - { - gViewerWindow->setCursor(UI_CURSOR_TOOLZOOMIN); - } - - return TRUE; -} - -//----------------------------------------------------------------------------- -// handleScrollWheel() -//----------------------------------------------------------------------------- -BOOL LLFloaterModelWizard::handleScrollWheel(S32 x, S32 y, S32 clicks) -{ - if (mPreviewRect.pointInRect(x, y) && mModelPreview) - { - mModelPreview->zoom((F32)clicks * -0.2f); - mModelPreview->refresh(); - } - - return TRUE; -} - - -void LLFloaterModelWizard::initDecompControls() -{ - LLSD key; - - static const LLCDStageData* stage = NULL; - static S32 stage_count = 0; - - if (!stage && LLConvexDecomposition::getInstance() != NULL) - { - stage_count = LLConvexDecomposition::getInstance()->getStages(&stage); - } - - static const LLCDParam* param = NULL; - static S32 param_count = 0; - if (!param && LLConvexDecomposition::getInstance() != NULL) - { - param_count = LLConvexDecomposition::getInstance()->getParameters(¶m); - } - - for (S32 j = stage_count-1; j >= 0; --j) - { - gMeshRepo.mDecompThread->mStageID[stage[j].mName] = j; - // protected against stub by stage_count being 0 for stub above - LLConvexDecomposition::getInstance()->registerCallback(j, LLPhysicsDecomp::llcdCallback); - - for (S32 i = 0; i < param_count; ++i) - { - if (param[i].mStage != j) - { - continue; - } - - std::string name(param[i].mName ? param[i].mName : ""); - std::string description(param[i].mDescription ? param[i].mDescription : ""); - - if (param[i].mType == LLCDParam::LLCD_FLOAT) - { - mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mFloat); - } - else if (param[i].mType == LLCDParam::LLCD_INTEGER) - { - mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue); - } - else if (param[i].mType == LLCDParam::LLCD_BOOLEAN) - { - mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mBool); - } - else if (param[i].mType == LLCDParam::LLCD_ENUM) - { - mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue); - } - } - } - - mDecompParams["Simplify Method"] = 0; // set it to retain % -} - -/*virtual*/ -void LLFloaterModelWizard::onPermissionsReceived(const LLSD& result) -{ - std::string upload_status = result["mesh_upload_status"].asString(); - // BAP HACK: handle "" for case that MeshUploadFlag cap is broken. - mHasUploadPerm = (("" == upload_status) || ("valid" == upload_status)); - - getChildView("warning_label")->setVisible(!mHasUploadPerm); - getChildView("warning_text")->setVisible(!mHasUploadPerm); -} - -/*virtual*/ -void LLFloaterModelWizard::setPermissonsErrorStatus(U32 status, const std::string& reason) -{ - llwarns << "LLFloaterModelWizard::setPermissonsErrorStatus(" << status << " : " << reason << ")" << llendl; -} - -/*virtual*/ -void LLFloaterModelWizard::onModelPhysicsFeeReceived(const LLSD& result, std::string upload_url) -{ - swap_controls(mCalculateWeightsBtn, mCalculatingWeightsBtn, true); - - // Enable the "Upload" buton if we have calculated the upload fee - // and have the permission to upload. - getChildView("upload")->setEnabled(mHasUploadPerm); - - mUploadModelUrl = upload_url; - - S32 fee = result["upload_price"].asInteger(); - childSetTextArg("review_fee", "[FEE]", llformat("%d", fee)); - childSetTextArg("charged_fee", "[FEE]", llformat("%d", fee)); - - setState(REVIEW); -} - -/*virtual*/ -void LLFloaterModelWizard::setModelPhysicsFeeErrorStatus(U32 status, const std::string& reason) -{ - swap_controls(mCalculateWeightsBtn, mCalculatingWeightsBtn, true); - - // Disable the "Review" step if it has been previously enabled. - modelChangedCallback(); - - llwarns << "LLFloaterModelWizard::setModelPhysicsFeeErrorStatus(" << status << " : " << reason << ")" << llendl; - - setState(PHYSICS); -} - -/*virtual*/ -void LLFloaterModelWizard::onModelUploadSuccess() -{ - // success! - setState(UPLOAD); -} - -/*virtual*/ -void LLFloaterModelWizard::onModelUploadFailure() -{ - // Failure. Make the user recalculate fees - setState(PHYSICS); - // Disable the "Review" step if it has been previously enabled. - if (mLastEnabledState > PHYSICS) - { - mLastEnabledState = PHYSICS; - } - - updateButtons(); -} - -//static -void LLFloaterModelWizard::executePhysicsStage(std::string stage_name) -{ - if (sInstance) - { - // Invert the slider value so that "performance" end is giving the least detailed physics, - // and the "accuracy" end is giving the most detailed physics - F64 physics_accuracy = 1 - sInstance->getChild<LLSliderCtrl>("physics_slider")->getValue().asReal(); - - sInstance->mDecompParams["Retain%"] = physics_accuracy; - - if (!sInstance->mCurRequest.empty()) - { - llinfos << "Decomposition request still pending." << llendl; - return; - } - - if (sInstance->mModelPreview) - { - for (S32 i = 0; i < sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS].size(); ++i) - { - LLModel* mdl = sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS][i]; - DecompRequest* request = new DecompRequest(stage_name, mdl); - if(request->isValid()) - { - sInstance->mCurRequest.insert(request); - gMeshRepo.mDecompThread->submitRequest(request); - } - } - } - } -} - -LLFloaterModelWizard::DecompRequest::DecompRequest(const std::string& stage, LLModel* mdl) -{ - mStage = stage; - mContinue = 1; - mModel = mdl; - mDecompID = &mdl->mDecompID; - mParams = sInstance->mDecompParams; - - //copy out positions and indices - assignData(mdl) ; -} - - -S32 LLFloaterModelWizard::DecompRequest::statusCallback(const char* status, S32 p1, S32 p2) -{ - setStatusMessage(llformat("%s: %d/%d", status, p1, p2)); - - return mContinue; -} - -void LLFloaterModelWizard::DecompRequest::completed() -{ //called from the main thread - mModel->setConvexHullDecomposition(mHull); - - if (sInstance) - { - if (sInstance->mModelPreview) - { - sInstance->mModelPreview->mDirty = true; - LLFloaterModelWizard::sInstance->mModelPreview->refresh(); - } - - sInstance->mCurRequest.erase(this); - } - - if (mStage == "Decompose") - { - executePhysicsStage("Simplify"); - } - else - { - // Decomp request is complete so we can enable the "Recalculate physics" button again. - swap_controls(sInstance->mRecalculatePhysicsBtn, sInstance->mRecalculatingPhysicsBtn, true); - } -} - - -BOOL LLFloaterModelWizard::postBuild() -{ - childSetValue("import_scale", (F32) 0.67335826); - - getChild<LLUICtrl>("browse")->setCommitCallback(boost::bind(&LLFloaterModelWizard::loadModel, this)); - //getChild<LLUICtrl>("lod_file")->setCommitCallback(boost::bind(&LLFloaterModelWizard::loadModel, this)); - getChild<LLUICtrl>("cancel")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onClickCancel, this)); - getChild<LLUICtrl>("close")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onClickCancel, this)); - getChild<LLUICtrl>("back")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onClickBack, this)); - getChild<LLUICtrl>("next")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onClickNext, this)); - getChild<LLUICtrl>("preview_lod_combo")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onPreviewLODCommit, this, _1)); - getChild<LLUICtrl>("preview_lod_combo2")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onPreviewLODCommit, this, _1)); - getChild<LLUICtrl>("upload")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onUpload, this)); - getChild<LLUICtrl>("switch_to_advanced")->setCommitCallback(boost::bind(&LLFloaterModelWizard::onClickSwitchToAdvanced, this)); - - mRecalculateGeometryBtn = getChild<LLButton>("recalculate_geometry_btn"); - mRecalculateGeometryBtn->setCommitCallback(boost::bind(&LLFloaterModelWizard::onClickRecalculateGeometry, this)); - - mRecalculatePhysicsBtn = getChild<LLButton>("recalculate_physics_btn"); - mRecalculatePhysicsBtn->setCommitCallback(boost::bind(&LLFloaterModelWizard::onClickRecalculatePhysics, this)); - - mRecalculatingPhysicsBtn = getChild<LLButton>("recalculating_physics_btn"); - - mCalculateWeightsBtn = getChild<LLButton>("calculate"); - mCalculateWeightsBtn->setCommitCallback(boost::bind(&LLFloaterModelWizard::onClickCalculateUploadFee, this)); - - mCalculatingWeightsBtn = getChild<LLButton>("calculating"); - - mChooseFilePreviewPanel = getChild<LLView>("choose_file_preview_panel"); - mOptimizePreviewPanel = getChild<LLView>("optimize_preview_panel"); - mPhysicsPreviewPanel = getChild<LLView>("physics_preview_panel"); - - LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar; - - enable_registrar.add("Next.OnEnable", boost::bind(&LLFloaterModelWizard::onEnableNext, this)); - enable_registrar.add("Back.OnEnable", boost::bind(&LLFloaterModelWizard::onEnableBack, this)); - - mModelPreview = new LLModelPreview(512, 512, this); - mModelPreview->setPreviewTarget(16.f); - mModelPreview->setDetailsCallback(boost::bind(&LLFloaterModelWizard::setDetails, this, _1, _2, _3, _4, _5)); - mModelPreview->setModelLoadedCallback(boost::bind(&LLFloaterModelWizard::modelLoadedCallback, this)); - mModelPreview->setModelUpdatedCallback(boost::bind(&LLFloaterModelWizard::modelChangedCallback, this)); - mModelPreview->mViewOption["show_textures"] = true; - - center(); - - setState(CHOOSE_FILE); - - childSetTextArg("import_dimensions", "[X]", LLStringUtil::null); - childSetTextArg("import_dimensions", "[Y]", LLStringUtil::null); - childSetTextArg("import_dimensions", "[Z]", LLStringUtil::null); - - initDecompControls(); - - requestAgentUploadPermissions(); - - return TRUE; -} - - -void LLFloaterModelWizard::setDetails(F32 x, F32 y, F32 z, F32 streaming_cost, F32 physics_cost) -{ - // iterate through all the panels, setting the dimensions - for(size_t t=0; t<LL_ARRAY_SIZE(stateNames); ++t) - { - LLPanel *panel = getChild<LLPanel>(stateNames[t]+"_panel"); - if (panel) - { - panel->childSetText("dimension_x", llformat("%.1f", x)); - panel->childSetText("dimension_y", llformat("%.1f", y)); - panel->childSetText("dimension_z", llformat("%.1f", z)); - } - } - - childSetTextArg("review_prim_equiv", "[EQUIV]", llformat("%d", mModelPreview->mResourceCost)); -} - -void LLFloaterModelWizard::modelLoadedCallback() -{ - mLastEnabledState = CHOOSE_FILE; - updateButtons(); -} - -void LLFloaterModelWizard::modelChangedCallback() -{ - // Don't allow to proceed to the "Review" step if the model has changed - // but the new upload fee hasn't been calculated yet. - if (mLastEnabledState > PHYSICS) - { - mLastEnabledState = PHYSICS; - } - - getChildView("upload")->setEnabled(false); - - updateButtons(); -} - -void LLFloaterModelWizard::onUpload() -{ - mModelPreview->rebuildUploadData(); - - gMeshRepo.uploadModel(mModelPreview->mUploadData, mModelPreview->mPreviewScale, - true, false, false, mUploadModelUrl, true, - LLHandle<LLWholeModelFeeObserver>(), getWholeModelUploadObserverHandle()); -} - -void LLFloaterModelWizard::onPreviewLODCommit(LLUICtrl* ctrl) -{ - if (!mModelPreview) - { - return; - } - - S32 which_mode = 0; - - LLComboBox* combo = (LLComboBox*) ctrl; - - which_mode = (NUM_LOD-1)-combo->getFirstSelectedIndex(); // combo box list of lods is in reverse order - - mModelPreview->setPreviewLOD(which_mode); -} - -void LLFloaterModelWizard::refresh() -{ - if (mState == CHOOSE_FILE) - { - bool model_loaded = false; - - if (mModelPreview && mModelPreview->getLoadState() == LLModelLoader::DONE) - { - model_loaded = true; - } - - getChildView("next")->setEnabled(model_loaded); - } -} - -void LLFloaterModelWizard::draw() -{ - refresh(); - - LLFloater::draw(); - - if (mModelPreview && mState < REVIEW) - { - mModelPreview->update(); - - gGL.color3f(1.f, 1.f, 1.f); - - gGL.getTexUnit(0)->bind(mModelPreview); - - gGL.begin( LLRender::QUADS ); - { - gGL.texCoord2f(0.f, 1.f); - gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mTop); - gGL.texCoord2f(0.f, 0.f); - gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mBottom); - gGL.texCoord2f(1.f, 0.f); - gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mBottom); - gGL.texCoord2f(1.f, 1.f); - gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mTop); - } - gGL.end(); - - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - } -} - -// static -void swap_controls(LLUICtrl* first_ctrl, LLUICtrl* second_ctrl, bool first_ctr_visible) -{ - first_ctrl->setVisible(first_ctr_visible); - second_ctrl->setVisible(!first_ctr_visible); -} diff --git a/indra/newview/llfloatermodelwizard.h b/indra/newview/llfloatermodelwizard.h deleted file mode 100644 index db9b605777..0000000000 --- a/indra/newview/llfloatermodelwizard.h +++ /dev/null @@ -1,140 +0,0 @@ -/** - * @file llfloatermodelwizard.h - * - * $LicenseInfo:firstyear=2009&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 LLFLOATERMODELWIZARD_H -#define LLFLOATERMODELWIZARD_H - - -#include "llmeshrepository.h" -#include "llmodel.h" -#include "llthread.h" -#include "llfloatermodeluploadbase.h" - - -class LLModelPreview; - - -class LLFloaterModelWizard : public LLFloaterModelUploadBase -{ -public: - - class DecompRequest : public LLPhysicsDecomp::Request - { - public: - S32 mContinue; - LLPointer<LLModel> mModel; - - DecompRequest(const std::string& stage, LLModel* mdl); - virtual S32 statusCallback(const char* status, S32 p1, S32 p2); - virtual void completed(); - - }; - - static LLFloaterModelWizard* sInstance; - - LLFloaterModelWizard(const LLSD& key); - virtual ~LLFloaterModelWizard(); - /*virtual*/ BOOL postBuild(); - void draw(); - void refresh(); - - BOOL handleMouseDown(S32 x, S32 y, MASK mask); - BOOL handleMouseUp(S32 x, S32 y, MASK mask); - BOOL handleHover(S32 x, S32 y, MASK mask); - BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); - - void setDetails(F32 x, F32 y, F32 z, F32 streaming_cost, F32 physics_cost); - void modelLoadedCallback(); - void modelChangedCallback(); - void initDecompControls(); - - // shows warning message if agent has no permissions to upload model - /*virtual*/ void onPermissionsReceived(const LLSD& result); - - // called when error occurs during permissions request - /*virtual*/ void setPermissonsErrorStatus(U32 status, const std::string& reason); - - /*virtual*/ void onModelPhysicsFeeReceived(const LLSD& result, std::string upload_url); - - /*virtual*/ void setModelPhysicsFeeErrorStatus(U32 status, const std::string& reason); - - /*virtual*/ void onModelUploadSuccess(); - - /*virtual*/ void onModelUploadFailure(); - - const LLRect& getPreviewRect() const { return mPreviewRect; } - - LLPhysicsDecomp::decomp_params mDecompParams; - std::set<LLPointer<DecompRequest> > mCurRequest; - std::string mStatusMessage; - static void executePhysicsStage(std::string stage_name); - -private: - enum EWizardState - { - CHOOSE_FILE = 0, - OPTIMIZE, - PHYSICS, - REVIEW, - UPLOAD - }; - - void setState(int state); - void updateButtons(); - void onClickSwitchToAdvanced(); - void onClickRecalculateGeometry(); - void onClickRecalculatePhysics(); - void onClickCalculateUploadFee(); - void onClickCancel(); - void onClickBack(); - void onClickNext(); - bool onEnableNext(); - bool onEnableBack(); - void loadModel(); - void onPreviewLODCommit(LLUICtrl*); - void onUpload(); - - LLModelPreview* mModelPreview; - LLRect mPreviewRect; - int mState; - - S32 mLastMouseX; - S32 mLastMouseY; - - U32 mLastEnabledState; - - LLButton* mRecalculateGeometryBtn; - LLButton* mRecalculatePhysicsBtn; - LLButton* mRecalculatingPhysicsBtn; - LLButton* mCalculateWeightsBtn; - LLButton* mCalculatingWeightsBtn; - - LLView* mChooseFilePreviewPanel; - LLView* mOptimizePreviewPanel; - LLView* mPhysicsPreviewPanel; -}; - - -#endif diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 173b0e538c..5edd920c70 100755 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -35,7 +35,7 @@ #include "llfloaterpreference.h" #include "message.h" - +#include "llfloaterautoreplacesettings.h" #include "llagent.h" #include "llavatarconstants.h" #include "llcheckboxctrl.h" @@ -346,7 +346,9 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key) mCommitCallbackRegistrar.add("Pref.BlockList", boost::bind(&LLFloaterPreference::onClickBlockList, this)); mCommitCallbackRegistrar.add("Pref.Proxy", boost::bind(&LLFloaterPreference::onClickProxySettings, this)); mCommitCallbackRegistrar.add("Pref.TranslationSettings", boost::bind(&LLFloaterPreference::onClickTranslationSettings, this)); - + mCommitCallbackRegistrar.add("Pref.AutoReplace", boost::bind(&LLFloaterPreference::onClickAutoReplace, this)); + mCommitCallbackRegistrar.add("Pref.SpellChecker", boost::bind(&LLFloaterPreference::onClickSpellChecker, this)); + sSkin = gSavedSettings.getString("SkinCurrent"); mCommitCallbackRegistrar.add("Pref.ClickActionChange", boost::bind(&LLFloaterPreference::onClickActionChange, this)); @@ -354,7 +356,7 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key) gSavedSettings.getControl("NameTagShowUsernames")->getCommitSignal()->connect(boost::bind(&handleNameTagOptionChanged, _2)); gSavedSettings.getControl("NameTagShowFriends")->getCommitSignal()->connect(boost::bind(&handleNameTagOptionChanged, _2)); gSavedSettings.getControl("UseDisplayNames")->getCommitSignal()->connect(boost::bind(&handleDisplayNamesOptionChanged, _2)); - + LLAvatarPropertiesProcessor::getInstance()->addObserver( gAgent.getID(), this ); } @@ -435,6 +437,8 @@ BOOL LLFloaterPreference::postBuild() gSavedSettings.getControl("ChatBubbleOpacity")->getSignal()->connect(boost::bind(&LLFloaterPreference::onNameTagOpacityChange, this, _2)); + gSavedSettings.getControl("PreferredMaturity")->getSignal()->connect(boost::bind(&LLFloaterPreference::onChangeMaturity, this)); + LLTabContainer* tabcontainer = getChild<LLTabContainer>("pref core"); if (!tabcontainer->selectTab(gSavedSettings.getS32("LastPrefTab"))) tabcontainer->selectFirstTab(); @@ -604,6 +608,9 @@ void LLFloaterPreference::cancel() // hide translation settings floater LLFloaterReg::hideInstance("prefs_translation"); + // hide translation settings floater + LLFloaterReg::hideInstance("prefs_autoreplace"); + // cancel hardware menu LLFloaterHardwareSettings* hardware_settings = LLFloaterReg::getTypedInstance<LLFloaterHardwareSettings>("prefs_hardware_settings"); if (hardware_settings) @@ -931,7 +938,6 @@ void LLFloaterPreference::refreshSkin(void* data) self->getChild<LLRadioGroup>("skin_selection", true)->setValue(sSkin); } - void LLFloaterPreference::buildPopupLists() { LLScrollListCtrl& disabled_popups = @@ -1515,6 +1521,16 @@ void LLFloaterPreference::onClickTranslationSettings() LLFloaterReg::showInstance("prefs_translation"); } +void LLFloaterPreference::onClickAutoReplace() +{ + LLFloaterReg::showInstance("prefs_autoreplace"); +} + +void LLFloaterPreference::onClickSpellChecker() +{ + LLFloaterReg::showInstance("prefs_spellchecker"); +} + void LLFloaterPreference::onClickActionChange() { mClickActionDirty = true; diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index ec5994e917..b71f7c647b 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -157,6 +157,8 @@ public: void onClickBlockList(); void onClickProxySettings(); void onClickTranslationSettings(); + void onClickAutoReplace(); + void onClickSpellChecker(); void applyUIColor(LLUICtrl* ctrl, const LLSD& param); void getUIColor(LLUICtrl* ctrl, const LLSD& param); diff --git a/indra/newview/llfloaterspellchecksettings.cpp b/indra/newview/llfloaterspellchecksettings.cpp new file mode 100644 index 0000000000..5ecdd11918 --- /dev/null +++ b/indra/newview/llfloaterspellchecksettings.cpp @@ -0,0 +1,491 @@ +/** + * @file llfloaterspellchecksettings.h + * @brief Spell checker settings floater + * +* $LicenseInfo:firstyear=2011&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 "llcombobox.h" +#include "llfilepicker.h" +#include "llfloaterreg.h" +#include "llfloaterspellchecksettings.h" +#include "llscrolllistctrl.h" +#include "llsdserialize.h" +#include "llspellcheck.h" +#include "lltrans.h" +#include "llviewercontrol.h" +#include "llnotificationsutil.h" + +#include <boost/algorithm/string.hpp> + +///---------------------------------------------------------------------------- +/// Class LLFloaterSpellCheckerSettings +///---------------------------------------------------------------------------- +LLFloaterSpellCheckerSettings::LLFloaterSpellCheckerSettings(const LLSD& key) + : LLFloater(key) +{ +} + +void LLFloaterSpellCheckerSettings::draw() +{ + LLFloater::draw(); + + std::vector<LLScrollListItem*> sel_items = getChild<LLScrollListCtrl>("spellcheck_available_list")->getAllSelected(); + bool enable_remove = !sel_items.empty(); + for (std::vector<LLScrollListItem*>::const_iterator sel_it = sel_items.begin(); sel_it != sel_items.end(); ++sel_it) + { + enable_remove &= LLSpellChecker::canRemoveDictionary((*sel_it)->getValue().asString()); + } + getChild<LLUICtrl>("spellcheck_remove_btn")->setEnabled(enable_remove); +} + +BOOL LLFloaterSpellCheckerSettings::postBuild(void) +{ + gSavedSettings.getControl("SpellCheck")->getSignal()->connect(boost::bind(&LLFloaterSpellCheckerSettings::refreshDictionaries, this, false)); + LLSpellChecker::setSettingsChangeCallback(boost::bind(&LLFloaterSpellCheckerSettings::onSpellCheckSettingsChange, this)); + getChild<LLUICtrl>("spellcheck_remove_btn")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::onBtnRemove, this)); + getChild<LLUICtrl>("spellcheck_import_btn")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::onBtnImport, this)); + getChild<LLUICtrl>("spellcheck_main_combo")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::refreshDictionaries, this, false)); + getChild<LLUICtrl>("spellcheck_moveleft_btn")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::onBtnMove, this, "spellcheck_active_list", "spellcheck_available_list")); + getChild<LLUICtrl>("spellcheck_moveright_btn")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerSettings::onBtnMove, this, "spellcheck_available_list", "spellcheck_active_list")); + center(); + return true; +} + +void LLFloaterSpellCheckerSettings::onBtnImport() +{ + LLFloaterReg::showInstance("prefs_spellchecker_import"); +} + +void LLFloaterSpellCheckerSettings::onBtnMove(const std::string& from, const std::string& to) +{ + LLScrollListCtrl* from_ctrl = findChild<LLScrollListCtrl>(from); + LLScrollListCtrl* to_ctrl = findChild<LLScrollListCtrl>(to); + + LLSD row; + row["columns"][0]["column"] = "name"; + + std::vector<LLScrollListItem*> sel_items = from_ctrl->getAllSelected(); + std::vector<LLScrollListItem*>::const_iterator sel_it; + for ( sel_it = sel_items.begin(); sel_it != sel_items.end(); ++sel_it) + { + row["value"] = (*sel_it)->getValue(); + row["columns"][0]["value"] = (*sel_it)->getColumn(0)->getValue(); + to_ctrl->addElement(row); + to_ctrl->setSelectedByValue( (*sel_it)->getValue(), true ); + } + from_ctrl->deleteSelectedItems(); +} + +void LLFloaterSpellCheckerSettings::onClose(bool app_quitting) +{ + if (app_quitting) + { + // don't save anything + return; + } + LLFloaterReg::hideInstance("prefs_spellchecker_import"); + + std::list<std::string> list_dict; + + LLComboBox* dict_combo = findChild<LLComboBox>("spellcheck_main_combo"); + const std::string dict_name = dict_combo->getSelectedItemLabel(); + if (!dict_name.empty()) + { + list_dict.push_back(dict_name); + + LLScrollListCtrl* list_ctrl = findChild<LLScrollListCtrl>("spellcheck_active_list"); + std::vector<LLScrollListItem*> list_items = list_ctrl->getAllData(); + for (std::vector<LLScrollListItem*>::const_iterator item_it = list_items.begin(); item_it != list_items.end(); ++item_it) + { + const std::string language = (*item_it)->getValue().asString(); + if (LLSpellChecker::hasDictionary(language, true)) + { + list_dict.push_back(language); + } + } + } + gSavedSettings.setString("SpellCheckDictionary", boost::join(list_dict, ",")); +} + +void LLFloaterSpellCheckerSettings::onOpen(const LLSD& key) +{ + refreshDictionaries(true); +} + +void LLFloaterSpellCheckerSettings::onBtnRemove() +{ + std::vector<LLScrollListItem*> sel_items = getChild<LLScrollListCtrl>("spellcheck_available_list")->getAllSelected(); + for (std::vector<LLScrollListItem*>::const_iterator sel_it = sel_items.begin(); sel_it != sel_items.end(); ++sel_it) + { + LLSpellChecker::instance().removeDictionary((*sel_it)->getValue().asString()); + } +} + +void LLFloaterSpellCheckerSettings::onSpellCheckSettingsChange() +{ + refreshDictionaries(true); +} + +void LLFloaterSpellCheckerSettings::refreshDictionaries(bool from_settings) +{ + bool enabled = gSavedSettings.getBOOL("SpellCheck"); + getChild<LLUICtrl>("spellcheck_moveleft_btn")->setEnabled(enabled); + getChild<LLUICtrl>("spellcheck_moveright_btn")->setEnabled(enabled); + + // Populate the dictionary combobox + LLComboBox* dict_combo = findChild<LLComboBox>("spellcheck_main_combo"); + std::string dict_cur = dict_combo->getSelectedItemLabel(); + if ((dict_cur.empty() || from_settings) && (LLSpellChecker::getUseSpellCheck())) + { + dict_cur = LLSpellChecker::instance().getPrimaryDictionary(); + } + dict_combo->clearRows(); + + const LLSD& dict_map = LLSpellChecker::getDictionaryMap(); + if (dict_map.size()) + { + for (LLSD::array_const_iterator dict_it = dict_map.beginArray(); dict_it != dict_map.endArray(); ++dict_it) + { + const LLSD& dict = *dict_it; + if ( (dict["installed"].asBoolean()) && (dict["is_primary"].asBoolean()) && (dict.has("language")) ) + { + dict_combo->add(dict["language"].asString()); + } + } + if (!dict_combo->selectByValue(dict_cur)) + { + dict_combo->clear(); + } + } + dict_combo->sortByName(); + dict_combo->setEnabled(enabled); + + // Populate the available and active dictionary list + LLScrollListCtrl* avail_ctrl = findChild<LLScrollListCtrl>("spellcheck_available_list"); + LLScrollListCtrl* active_ctrl = findChild<LLScrollListCtrl>("spellcheck_active_list"); + + LLSpellChecker::dict_list_t active_list; + if ( ((!avail_ctrl->getItemCount()) && (!active_ctrl->getItemCount())) || (from_settings) ) + { + if (LLSpellChecker::getUseSpellCheck()) + { + active_list = LLSpellChecker::instance().getSecondaryDictionaries(); + } + } + else + { + std::vector<LLScrollListItem*> active_items = active_ctrl->getAllData(); + for (std::vector<LLScrollListItem*>::const_iterator item_it = active_items.begin(); item_it != active_items.end(); ++item_it) + { + std::string dict = (*item_it)->getValue().asString(); + if (dict_cur != dict) + { + active_list.push_back(dict); + } + } + } + + LLSD row; + row["columns"][0]["column"] = "name"; + + active_ctrl->clearRows(); + active_ctrl->setEnabled(enabled); + for (LLSpellChecker::dict_list_t::const_iterator it = active_list.begin(); it != active_list.end(); ++it) + { + const std::string language = *it; + const LLSD dict = LLSpellChecker::getDictionaryData(language); + row["value"] = language; + row["columns"][0]["value"] = (!dict["user_installed"].asBoolean()) ? language : language + " " + LLTrans::getString("UserDictionary"); + active_ctrl->addElement(row); + } + active_ctrl->sortByColumnIndex(0, true); + active_list.push_back(dict_cur); + + avail_ctrl->clearRows(); + avail_ctrl->setEnabled(enabled); + for (LLSD::array_const_iterator dict_it = dict_map.beginArray(); dict_it != dict_map.endArray(); ++dict_it) + { + const LLSD& dict = *dict_it; + const std::string language = dict["language"].asString(); + if ( (dict["installed"].asBoolean()) && (active_list.end() == std::find(active_list.begin(), active_list.end(), language)) ) + { + row["value"] = language; + row["columns"][0]["value"] = (!dict["user_installed"].asBoolean()) ? language : language + " " + LLTrans::getString("UserDictionary"); + avail_ctrl->addElement(row); + } + } + avail_ctrl->sortByColumnIndex(0, true); +} + +///---------------------------------------------------------------------------- +/// Class LLFloaterSpellCheckerImport +///---------------------------------------------------------------------------- +LLFloaterSpellCheckerImport::LLFloaterSpellCheckerImport(const LLSD& key) + : LLFloater(key) +{ +} + +BOOL LLFloaterSpellCheckerImport::postBuild(void) +{ + getChild<LLUICtrl>("dictionary_path_browse")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerImport::onBtnBrowse, this)); + getChild<LLUICtrl>("ok_btn")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerImport::onBtnOK, this)); + getChild<LLUICtrl>("cancel_btn")->setCommitCallback(boost::bind(&LLFloaterSpellCheckerImport::onBtnCancel, this)); + center(); + return true; +} + +void LLFloaterSpellCheckerImport::onBtnBrowse() +{ + LLFilePicker& file_picker = LLFilePicker::instance(); + if (!file_picker.getOpenFile(LLFilePicker::FFLOAD_DICTIONARY)) + { + return; + } + + std::string filepath = file_picker.getFirstFile(); + + const std::string extension = gDirUtilp->getExtension(filepath); + if ("xcu" == extension) + { + filepath = parseXcuFile(filepath); + if (filepath.empty()) + { + return; + } + } + + getChild<LLUICtrl>("dictionary_path")->setValue(filepath); + + mDictionaryDir = gDirUtilp->getDirName(filepath); + mDictionaryBasename = gDirUtilp->getBaseFileName(filepath, true); + getChild<LLUICtrl>("dictionary_name")->setValue(mDictionaryBasename); +} + +void LLFloaterSpellCheckerImport::onBtnCancel() +{ + closeFloater(false); +} + +void LLFloaterSpellCheckerImport::onBtnOK() +{ + const std::string dict_dic = mDictionaryDir + gDirUtilp->getDirDelimiter() + mDictionaryBasename + ".dic"; + const std::string dict_aff = mDictionaryDir + gDirUtilp->getDirDelimiter() + mDictionaryBasename + ".aff"; + std::string dict_language = getChild<LLUICtrl>("dictionary_language")->getValue().asString(); + LLStringUtil::trim(dict_language); + + bool imported = false; + if ( dict_language.empty() + || mDictionaryDir.empty() + || mDictionaryBasename.empty() + || ! gDirUtilp->fileExists(dict_dic) + ) + { + LLNotificationsUtil::add("SpellingDictImportRequired"); + } + else + { + std::string settings_dic = LLSpellChecker::getDictionaryUserPath() + mDictionaryBasename + ".dic"; + if ( copyFile( dict_dic, settings_dic ) ) + { + if (gDirUtilp->fileExists(dict_aff)) + { + std::string settings_aff = LLSpellChecker::getDictionaryUserPath() + mDictionaryBasename + ".aff"; + if (copyFile( dict_aff, settings_aff )) + { + imported = true; + } + else + { + LLSD args = LLSD::emptyMap(); + args["FROM_NAME"] = dict_aff; + args["TO_NAME"] = settings_aff; + LLNotificationsUtil::add("SpellingDictImportFailed", args); + } + } + else + { + LLSD args = LLSD::emptyMap(); + args["DIC_NAME"] = dict_dic; + LLNotificationsUtil::add("SpellingDictIsSecondary", args); + + imported = true; + } + } + else + { + LLSD args = LLSD::emptyMap(); + args["FROM_NAME"] = dict_dic; + args["TO_NAME"] = settings_dic; + LLNotificationsUtil::add("SpellingDictImportFailed", args); + } + } + + if ( imported ) + { + LLSD custom_dict_info; + custom_dict_info["is_primary"] = (bool)gDirUtilp->fileExists(dict_aff); + custom_dict_info["name"] = mDictionaryBasename; + custom_dict_info["language"] = dict_language; + + LLSD custom_dict_map; + llifstream custom_file_in(LLSpellChecker::getDictionaryUserPath() + "user_dictionaries.xml"); + if (custom_file_in.is_open()) + { + LLSDSerialize::fromXMLDocument(custom_dict_map, custom_file_in); + custom_file_in.close(); + } + + LLSD::array_iterator it = custom_dict_map.beginArray(); + for (; it != custom_dict_map.endArray(); ++it) + { + LLSD& dict_info = *it; + if (dict_info["name"].asString() == mDictionaryBasename) + { + dict_info = custom_dict_info; + break; + } + } + if (custom_dict_map.endArray() == it) + { + custom_dict_map.append(custom_dict_info); + } + + llofstream custom_file_out(LLSpellChecker::getDictionaryUserPath() + "user_dictionaries.xml", std::ios::trunc); + if (custom_file_out.is_open()) + { + LLSDSerialize::toPrettyXML(custom_dict_map, custom_file_out); + custom_file_out.close(); + } + + LLSpellChecker::refreshDictionaryMap(); + } + + closeFloater(false); +} + +bool LLFloaterSpellCheckerImport::copyFile(const std::string from, const std::string to) +{ + bool copied = false; + LLFILE* in = LLFile::fopen(from, "rb"); /* Flawfinder: ignore */ + if (in) + { + LLFILE* out = LLFile::fopen(to, "wb"); /* Flawfinder: ignore */ + if (out) + { + char buf[16384]; /* Flawfinder: ignore */ + size_t readbytes; + bool write_ok = true; + while(write_ok && (readbytes = fread(buf, 1, 16384, in))) /* Flawfinder: ignore */ + { + if (fwrite(buf, 1, readbytes, out) != readbytes) + { + LL_WARNS("SpellCheck") << "Short write" << LL_ENDL; + write_ok = false; + } + } + if ( write_ok ) + { + copied = true; + } + fclose(out); + } + } + fclose(in); + return copied; +} + +std::string LLFloaterSpellCheckerImport::parseXcuFile(const std::string& file_path) const +{ + LLXMLNodePtr xml_root; + if ( (!LLUICtrlFactory::getLayeredXMLNode(file_path, xml_root)) || (xml_root.isNull()) ) + { + return LLStringUtil::null; + } + + // Bury down to the "Dictionaries" parent node + LLXMLNode* dict_node = NULL; + for (LLXMLNode* outer_node = xml_root->getFirstChild(); outer_node && !dict_node; outer_node = outer_node->getNextSibling()) + { + std::string temp; + if ( (outer_node->getAttributeString("oor:name", temp)) && ("ServiceManager" == temp) ) + { + for (LLXMLNode* inner_node = outer_node->getFirstChild(); inner_node && !dict_node; inner_node = inner_node->getNextSibling()) + { + if ( (inner_node->getAttributeString("oor:name", temp)) && ("Dictionaries" == temp) ) + { + dict_node = inner_node; + break; + } + } + } + } + + if (dict_node) + { + // Iterate over all child nodes until we find one that has a <value>DICT_SPELL</value> node + for (LLXMLNode* outer_node = dict_node->getFirstChild(); outer_node; outer_node = outer_node->getNextSibling()) + { + std::string temp; + LLXMLNodePtr location_node, format_node; + for (LLXMLNode* inner_node = outer_node->getFirstChild(); inner_node; inner_node = inner_node->getNextSibling()) + { + if (inner_node->getAttributeString("oor:name", temp)) + { + if ("Locations" == temp) + { + inner_node->getChild("value", location_node, false); + } + else if ("Format" == temp) + { + inner_node->getChild("value", format_node, false); + } + } + } + if ( (format_node.isNull()) || ("DICT_SPELL" != format_node->getValue()) || (location_node.isNull()) ) + { + continue; + } + + // Found a list of file locations, return the .dic (if present) + std::list<std::string> location_list; + boost::split(location_list, location_node->getValue(), boost::is_any_of(std::string(" "))); + for (std::list<std::string>::iterator it = location_list.begin(); it != location_list.end(); ++it) + { + std::string& location = *it; + if ("\\" != gDirUtilp->getDirDelimiter()) + LLStringUtil::replaceString(location, "\\", gDirUtilp->getDirDelimiter()); + else + LLStringUtil::replaceString(location, "/", gDirUtilp->getDirDelimiter()); + LLStringUtil::replaceString(location, "%origin%", gDirUtilp->getDirName(file_path)); + if ("dic" == gDirUtilp->getExtension(location)) + { + return location; + } + } + } + } + + return LLStringUtil::null; +} diff --git a/indra/newview/llfloaterspellchecksettings.h b/indra/newview/llfloaterspellchecksettings.h new file mode 100644 index 0000000000..eded3a9133 --- /dev/null +++ b/indra/newview/llfloaterspellchecksettings.h @@ -0,0 +1,68 @@ +/** + * @file llfloaterspellchecksettings.h + * @brief Spell checker settings floater + * +* $LicenseInfo:firstyear=2011&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 LLFLOATERSPELLCHECKERSETTINGS_H +#define LLFLOATERSPELLCHECKERSETTINGS_H + +#include "llfloater.h" + +class LLFloaterSpellCheckerSettings : public LLFloater +{ +public: + LLFloaterSpellCheckerSettings(const LLSD& key); + + /*virtual*/ void draw(); + /*virtual*/ BOOL postBuild(); + /*virtual*/ void onOpen(const LLSD& key); + /*virtual*/ void onClose(bool app_quitting); + +protected: + void onBtnImport(); + void onBtnMove(const std::string& from, const std::string& to); + void onBtnRemove(); + void onSpellCheckSettingsChange(); + void refreshDictionaries(bool from_settings); +}; + +class LLFloaterSpellCheckerImport : public LLFloater +{ +public: + LLFloaterSpellCheckerImport(const LLSD& key); + + /*virtual*/ BOOL postBuild(); + +protected: + void onBtnBrowse(); + void onBtnCancel(); + void onBtnOK(); + bool copyFile(const std::string from, const std::string to); + std::string parseXcuFile(const std::string& file_path) const; + + std::string mDictionaryDir; + std::string mDictionaryBasename; +}; + +#endif // LLFLOATERSPELLCHECKERSETTINGS_H diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index 1fa194ab19..9ce64a630f 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -562,7 +562,6 @@ void LLFolderView::reshape(S32 width, S32 height, BOOL called_from_parent) { width = scroll_rect.getWidth(); } - LLView::reshape(width, height, called_from_parent); mReshapeSignal(mSelectedItems, FALSE); } diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp index f67464078b..63eedcdfea 100644 --- a/indra/newview/llimfloater.cpp +++ b/indra/newview/llimfloater.cpp @@ -56,7 +56,7 @@ #include "llrootview.h" #include "llspeakers.h" #include "llviewerchat.h" - +#include "llautoreplace.h" LLIMFloater::LLIMFloater(const LLUUID& session_id) : LLTransientDockableFloater(NULL, true, session_id), @@ -255,6 +255,8 @@ BOOL LLIMFloater::postBuild() mInputEditor->setMaxTextLength(1023); // enable line history support for instant message bar mInputEditor->setEnableLineHistory(TRUE); + // *TODO Establish LineEditor with autoreplace callback + mInputEditor->setAutoreplaceCallback(boost::bind(&LLAutoReplace::autoreplaceCallback, LLAutoReplace::getInstance(), _1, _2)); LLFontGL* font = LLViewerChat::getChatFont(); mInputEditor->setFont(font); diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 8092f3bf36..6e23d7c701 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -822,6 +822,11 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item) { parent_id = findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); new_item->setParent(parent_id); + LLInventoryModel::update_list_t update; + LLInventoryModel::LLCategoryUpdate new_folder(parent_id, 1); + update.push_back(new_folder); + accountForUpdate(update); + } item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, parent_id); if(item_array) diff --git a/indra/newview/llmaniptranslate.cpp b/indra/newview/llmaniptranslate.cpp index 3a88fbd96d..f8088d04b4 100644 --- a/indra/newview/llmaniptranslate.cpp +++ b/indra/newview/llmaniptranslate.cpp @@ -60,6 +60,7 @@ #include "llworld.h" #include "llui.h" #include "pipeline.h" +#include "llviewershadermgr.h" const S32 NUM_AXES = 3; const S32 MOUSE_DRAG_SLOP = 2; // pixels @@ -1580,7 +1581,11 @@ void LLManipTranslate::renderSnapGuides() LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_GREATER); LLGLEnable stipple(GL_LINE_STIPPLE); gGL.flush(); - glLineStipple(1, 0x3333); + + if (!LLGLSLShader::sNoFixedFunction) + { + glLineStipple(1, 0x3333); + } switch (mManipPart) { @@ -1645,17 +1650,28 @@ void LLManipTranslate::highlightIntersection(LLVector3 normal, LLQuaternion grid_rotation, LLColor4 inner_color) { - if (!gSavedSettings.getBOOL("GridCrossSections")) + if (!gSavedSettings.getBOOL("GridCrossSections") || !LLGLSLShader::sNoFixedFunction) { return; } + + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + + U32 types[] = { LLRenderPass::PASS_SIMPLE, LLRenderPass::PASS_ALPHA, LLRenderPass::PASS_FULLBRIGHT, LLRenderPass::PASS_SHINY }; U32 num_types = LL_ARRAY_SIZE(types); GLuint stencil_mask = 0xFFFFFFFF; //stencil in volumes + gGL.flush(); + + if (shader) + { + gClipProgram.bind(); + } + { glStencilMask(stencil_mask); glClearStencil(1); @@ -1666,6 +1682,7 @@ void LLManipTranslate::highlightIntersection(LLVector3 normal, glStencilFunc(GL_ALWAYS, 0, stencil_mask); gGL.setColorMask(false, false); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.diffuseColor4f(1,1,1,1); //setup clip plane @@ -1675,10 +1692,12 @@ void LLManipTranslate::highlightIntersection(LLVector3 normal, normal = -normal; } F32 d = -(selection_center * normal); - F64 plane[] = { normal.mV[0], normal.mV[1], normal.mV[2], d }; - LLGLEnable clip(GL_CLIP_PLANE0); - glClipPlane(GL_CLIP_PLANE0, plane); + glh::vec4f plane(normal.mV[0], normal.mV[1], normal.mV[2], d ); + + gGL.getModelviewMatrix().inverse().mult_vec_matrix(plane); + gClipProgram.uniform4fv("clip_plane", 1, plane.v); + BOOL particles = gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES); BOOL clouds = gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_CLOUDS); @@ -1729,6 +1748,11 @@ void LLManipTranslate::highlightIntersection(LLVector3 normal, F32 sz = mGridSizeMeters; F32 tiles = sz; + if (shader) + { + shader->bind(); + } + //draw volume/plane intersections { gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index c899e8991e..bc7f522848 100755..100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1659,7 +1659,7 @@ void LLMeshUploadThread::requestWholeModelFee() mCurlRequest->process(); //sleep for 10ms to prevent eating a whole core apr_sleep(10000); - } while (mCurlRequest->getQueued() > 0); + } while (!LLApp::isQuitting() && mCurlRequest->getQueued() > 0); delete mCurlRequest; mCurlRequest = NULL; diff --git a/indra/newview/llnearbychatbar.cpp b/indra/newview/llnearbychatbar.cpp index 00ff81724c..f8f0f7d243 100644 --- a/indra/newview/llnearbychatbar.cpp +++ b/indra/newview/llnearbychatbar.cpp @@ -52,6 +52,7 @@ #include "lltranslate.h" #include "llresizehandle.h" +#include "llautoreplace.h" S32 LLNearbyChatBar::sLastSpecialChatChannel = 0; @@ -89,6 +90,7 @@ BOOL LLNearbyChatBar::postBuild() { mChatBox = getChild<LLLineEditor>("chat_box"); + mChatBox->setAutoreplaceCallback(boost::bind(&LLAutoReplace::autoreplaceCallback, LLAutoReplace::getInstance(), _1, _2)); mChatBox->setCommitCallback(boost::bind(&LLNearbyChatBar::onChatBoxCommit, this)); mChatBox->setKeystrokeCallback(&onChatBoxKeystroke, this); mChatBox->setFocusLostCallback(boost::bind(&onChatBoxFocusLost, _1, this)); diff --git a/indra/newview/llnotificationhandlerutil.cpp b/indra/newview/llnotificationhandlerutil.cpp index 7c6287967a..16c51138a9 100644 --- a/indra/newview/llnotificationhandlerutil.cpp +++ b/indra/newview/llnotificationhandlerutil.cpp @@ -128,6 +128,8 @@ const static std::string GRANTED_MODIFY_RIGHTS("GrantedModifyRights"), FRIEND_ONLINE("FriendOnline"), FRIEND_OFFLINE("FriendOffline"), SERVER_OBJECT_MESSAGE("ServerObjectMessage"), TELEPORT_OFFERED("TeleportOffered"), + TELEPORT_OFFERED_MATURITY_EXCEEDED("TeleportOffered_MaturityExceeded"), + TELEPORT_OFFERED_MATURITY_BLOCKED("TeleportOffered_MaturityBlocked"), TELEPORT_OFFER_SENT("TeleportOfferSent"), IM_SYSTEM_MESSAGE_TIP("IMSystemMessageTip"); @@ -149,6 +151,8 @@ bool LLHandlerUtil::canLogToIM(const LLNotificationPtr& notification) || INVENTORY_DECLINED == notification->getName() || USER_GIVE_ITEM == notification->getName() || TELEPORT_OFFERED == notification->getName() + || TELEPORT_OFFERED_MATURITY_EXCEEDED == notification->getName() + || TELEPORT_OFFERED_MATURITY_BLOCKED == notification->getName() || TELEPORT_OFFER_SENT == notification->getName() || IM_SYSTEM_MESSAGE_TIP == notification->getName(); } @@ -169,7 +173,9 @@ bool LLHandlerUtil::canSpawnIMSession(const LLNotificationPtr& notification) { return OFFER_FRIENDSHIP == notification->getName() || USER_GIVE_ITEM == notification->getName() - || TELEPORT_OFFERED == notification->getName(); + || TELEPORT_OFFERED == notification->getName() + || TELEPORT_OFFERED_MATURITY_EXCEEDED == notification->getName() + || TELEPORT_OFFERED_MATURITY_BLOCKED == notification->getName(); } // static @@ -177,7 +183,9 @@ bool LLHandlerUtil::canAddNotifPanelToIM(const LLNotificationPtr& notification) { return OFFER_FRIENDSHIP == notification->getName() || USER_GIVE_ITEM == notification->getName() - || TELEPORT_OFFERED == notification->getName(); + || TELEPORT_OFFERED == notification->getName() + || TELEPORT_OFFERED_MATURITY_EXCEEDED == notification->getName() + || TELEPORT_OFFERED_MATURITY_BLOCKED == notification->getName(); } // static @@ -185,7 +193,9 @@ bool LLHandlerUtil::isNotificationReusable(const LLNotificationPtr& notification { return OFFER_FRIENDSHIP == notification->getName() || USER_GIVE_ITEM == notification->getName() - || TELEPORT_OFFERED == notification->getName(); + || TELEPORT_OFFERED == notification->getName() + || TELEPORT_OFFERED_MATURITY_EXCEEDED == notification->getName() + || TELEPORT_OFFERED_MATURITY_BLOCKED == notification->getName(); } // static @@ -212,7 +222,9 @@ bool LLHandlerUtil::canSpawnToast(const LLNotificationPtr& notification) if(OFFER_FRIENDSHIP == notification->getName() || USER_GIVE_ITEM == notification->getName() - || TELEPORT_OFFERED == notification->getName()) + || TELEPORT_OFFERED == notification->getName() + || TELEPORT_OFFERED_MATURITY_EXCEEDED == notification->getName() + || TELEPORT_OFFERED_MATURITY_BLOCKED == notification->getName()) { // When ANY offer arrives, show toast, unless IM window is already open - EXT-5904 return ! isIMFloaterOpened(notification); diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp index 03404e816b..d58d6d536c 100644 --- a/indra/newview/llpaneleditwearable.cpp +++ b/indra/newview/llpaneleditwearable.cpp @@ -574,6 +574,7 @@ static void init_texture_ctrl(LLPanelEditWearable* self, LLPanel* panel, const L texture_ctrl->setAllowNoTexture(entry->mAllowNoTexture); // Don't allow (no copy) or (notransfer) textures to be selected. texture_ctrl->setImmediateFilterPermMask(PERM_NONE); + texture_ctrl->setDnDFilterPermMask(PERM_NONE); texture_ctrl->setNonImmediateFilterPermMask(PERM_NONE); } } diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 7301b305b2..3e29805446 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -38,6 +38,7 @@ #include "llfontgl.h" // project includes +#include "llagentdata.h" #include "llbutton.h" #include "llcheckboxctrl.h" #include "llcolorswatch.h" @@ -46,6 +47,7 @@ #include "llface.h" #include "lllineeditor.h" #include "llmediaentry.h" +#include "llnotificationsutil.h" #include "llresmgr.h" #include "llselectmgr.h" #include "llspinctrl.h" @@ -104,27 +106,11 @@ BOOL LLPanelFace::postBuild() mTextureCtrl->setOnCancelCallback( boost::bind(&LLPanelFace::onCancelTexture, this, _2) ); mTextureCtrl->setOnSelectCallback( boost::bind(&LLPanelFace::onSelectTexture, this, _2) ); mTextureCtrl->setDragCallback(boost::bind(&LLPanelFace::onDragTexture, this, _2)); + mTextureCtrl->setOnTextureSelectedCallback(boost::bind(&LLPanelFace::onTextureSelectionChanged, this, _1)); mTextureCtrl->setFollowsTop(); mTextureCtrl->setFollowsLeft(); - // Don't allow (no copy) or (no transfer) textures to be selected during immediate mode - mTextureCtrl->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER); - // Allow any texture to be used during non-immediate mode. - mTextureCtrl->setNonImmediateFilterPermMask(PERM_NONE); - LLAggregatePermissions texture_perms; - if (LLSelectMgr::getInstance()->selectGetAggregateTexturePermissions(texture_perms)) - { - BOOL can_copy = - texture_perms.getValue(PERM_COPY) == LLAggregatePermissions::AP_EMPTY || - texture_perms.getValue(PERM_COPY) == LLAggregatePermissions::AP_ALL; - BOOL can_transfer = - texture_perms.getValue(PERM_TRANSFER) == LLAggregatePermissions::AP_EMPTY || - texture_perms.getValue(PERM_TRANSFER) == LLAggregatePermissions::AP_ALL; - mTextureCtrl->setCanApplyImmediately(can_copy && can_transfer); - } - else - { - mTextureCtrl->setCanApplyImmediately(FALSE); - } + mTextureCtrl->setImmediateFilterPermMask(PERM_NONE); + mTextureCtrl->setDnDFilterPermMask(PERM_COPY | PERM_TRANSFER); } mColorSwatch = getChild<LLColorSwatchCtrl>("colorswatch"); @@ -595,28 +581,6 @@ void LLPanelFace::getState() } - LLAggregatePermissions texture_perms; - if(texture_ctrl) - { -// texture_ctrl->setValid( editable ); - - if (LLSelectMgr::getInstance()->selectGetAggregateTexturePermissions(texture_perms)) - { - BOOL can_copy = - texture_perms.getValue(PERM_COPY) == LLAggregatePermissions::AP_EMPTY || - texture_perms.getValue(PERM_COPY) == LLAggregatePermissions::AP_ALL; - BOOL can_transfer = - texture_perms.getValue(PERM_TRANSFER) == LLAggregatePermissions::AP_EMPTY || - texture_perms.getValue(PERM_TRANSFER) == LLAggregatePermissions::AP_ALL; - texture_ctrl->setCanApplyImmediately(can_copy && can_transfer); - } - else - { - texture_ctrl->setCanApplyImmediately(FALSE); - } - } - - // planar align bool align_planar = false; bool identical_planar_aligned = false; @@ -1190,3 +1154,35 @@ void LLPanelFace::onCommitPlanarAlign(LLUICtrl* ctrl, void* userdata) self->sendTextureInfo(); } +void LLPanelFace::onTextureSelectionChanged(LLInventoryItem* itemp) +{ + LLTextureCtrl* texture_ctrl = getChild<LLTextureCtrl>("texture control"); + if (texture_ctrl) + { + LLUUID obj_owner_id; + std::string obj_owner_name; + LLSelectMgr::instance().selectGetOwner(obj_owner_id, obj_owner_name); + + LLSaleInfo sale_info; + LLSelectMgr::instance().selectGetSaleInfo(sale_info); + + bool can_copy = itemp->getPermissions().allowCopyBy(gAgentID); // do we have perm to copy this texture? + bool can_transfer = itemp->getPermissions().allowOperationBy(PERM_TRANSFER, gAgentID); // do we have perm to transfer this texture? + bool is_object_owner = gAgentID == obj_owner_id; // does object for which we are going to apply texture belong to the agent? + bool not_for_sale = !sale_info.isForSale(); // is object for which we are going to apply texture not for sale? + + if (can_copy && can_transfer) + { + texture_ctrl->setCanApply(true, true); + return; + } + + // if texture has (no-transfer) attribute it can be applied only for object which we own and is not for sale + texture_ctrl->setCanApply(false, can_transfer ? true : is_object_owner && not_for_sale); + + if (gSavedSettings.getBOOL("TextureLivePreview")) + { + LLNotificationsUtil::add("LivePreviewUnavailable"); + } + } +} diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h index 42be9b257f..3b5a9b1398 100644 --- a/indra/newview/llpanelface.h +++ b/indra/newview/llpanelface.h @@ -91,6 +91,15 @@ protected: static void onClickAutoFix(void*); static F32 valueGlow(LLViewerObject* object, S32 face); +private: + + /* + * Checks whether the selected texture from the LLFloaterTexturePicker can be applied to the currently selected object. + * If agent selects texture which is not allowed to be applied for the currently selected object, + * all controls of the floater texture picker which allow to apply the texture will be disabled. + */ + void onTextureSelectionChanged(LLInventoryItem* itemp); + }; #endif diff --git a/indra/newview/llpanellandmedia.cpp b/indra/newview/llpanellandmedia.cpp index b3adfac8a2..26cd3ff1c1 100644 --- a/indra/newview/llpanellandmedia.cpp +++ b/indra/newview/llpanellandmedia.cpp @@ -85,6 +85,7 @@ BOOL LLPanelLandMedia::postBuild() mMediaTextureCtrl->setCommitCallback( onCommitAny, this ); mMediaTextureCtrl->setAllowNoTexture ( TRUE ); mMediaTextureCtrl->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER); + mMediaTextureCtrl->setDnDFilterPermMask(PERM_COPY | PERM_TRANSFER); mMediaTextureCtrl->setNonImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER); mMediaAutoScaleCheck = getChild<LLCheckBoxCtrl>("media_auto_scale"); diff --git a/indra/newview/llpanelnearbymedia.cpp b/indra/newview/llpanelnearbymedia.cpp index c01adc3c35..a50d9074f7 100644 --- a/indra/newview/llpanelnearbymedia.cpp +++ b/indra/newview/llpanelnearbymedia.cpp @@ -176,7 +176,7 @@ void LLPanelNearByMedia::handleMediaAutoPlayChanged(const LLSD& newvalue) { // update mParcelAudioAutoStart if AUTO_PLAY_MEDIA_SETTING changes mParcelAudioAutoStart = gSavedSettings.getBOOL(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING) && - gSavedSettings.getBOOL("MediaTentativeAutoPlay"); + gSavedSettings.getBOOL("MediaTentativeAutoPlay"); } /*virtual*/ diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index 1f77e7a602..7dfe529b73 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -245,6 +245,7 @@ BOOL LLPanelObject::postBuild() mCtrlSculptTexture->setDropCallback( boost::bind(&LLPanelObject::onDropSculpt, this, _2 )); // Don't allow (no copy) or (no transfer) textures to be selected during immediate mode mCtrlSculptTexture->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER); + mCtrlSculptTexture->setDnDFilterPermMask(PERM_COPY | PERM_TRANSFER); // Allow any texture to be used during non-immediate mode. mCtrlSculptTexture->setNonImmediateFilterPermMask(PERM_NONE); LLAggregatePermissions texture_perms; diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index eec2c0a521..a55565909f 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -1508,6 +1508,49 @@ struct LLSelectMgrSendFunctor : public LLSelectedObjectFunctor } }; +void LLObjectSelection::applyNoCopyTextureToTEs(LLViewerInventoryItem* item) +{ + if (!item) + { + return; + } + LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture(item->getAssetUUID()); + + for (iterator iter = begin(); iter != end(); ++iter) + { + LLSelectNode* node = *iter; + LLViewerObject* object = (*iter)->getObject(); + if (!object) + { + continue; + } + + S32 num_tes = llmin((S32)object->getNumTEs(), (S32)object->getNumFaces()); + bool texture_copied = false; + for (S32 te = 0; te < num_tes; ++te) + { + if (node->isTESelected(te)) + { + //(no-copy) textures must be moved to the object's inventory only once + // without making any copies + if (!texture_copied) + { + LLToolDragAndDrop::handleDropTextureProtections(object, item, LLToolDragAndDrop::SOURCE_AGENT, LLUUID::null); + texture_copied = true; + } + + // apply texture for the selected faces + LLViewerStats::getInstance()->incStat(LLViewerStats::ST_EDIT_TEXTURE_COUNT ); + object->setTEImage(te, image); + dialog_refresh_all(); + + // send the update to the simulator + object->sendTEUpdate(); + } + } + } +} + //----------------------------------------------------------------------------- // selectionSetImage() //----------------------------------------------------------------------------- @@ -1559,8 +1602,18 @@ void LLSelectMgr::selectionSetImage(const LLUUID& imageid) } return true; } - } setfunc(item, imageid); - getSelection()->applyToTEs(&setfunc); + }; + + if (item && !item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID())) + { + getSelection()->applyNoCopyTextureToTEs(item); + } + else + { + f setfunc(item, imageid); + getSelection()->applyToTEs(&setfunc); + } + struct g : public LLSelectedObjectFunctor { @@ -5583,7 +5636,7 @@ void pushWireframe(LLDrawable* drawable) for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i) { const LLVolumeFace& face = volume->getVolumeFace(i); - LLVertexBuffer::drawElements(LLRender::TRIANGLES, face.mPositions, face.mTexCoords, face.mNumIndices, face.mIndices); + LLVertexBuffer::drawElements(LLRender::TRIANGLES, face.mPositions, NULL, face.mNumIndices, face.mIndices); } } @@ -5610,7 +5663,7 @@ void LLSelectNode::renderOneWireframe(const LLColor4& color) if (shader) { - gHighlightProgram.bind(); + gDebugProgram.bind(); } gGL.matrixMode(LLRender::MM_MODELVIEW); diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index 87ada5ac6b..94606b9fba 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -307,6 +307,15 @@ public: bool applyToRootNodes(LLSelectedNodeFunctor* func, bool firstonly = false); bool applyToNodes(LLSelectedNodeFunctor* func, bool firstonly = false); + /* + * Used to apply (no-copy) textures to the selected object or + * selected face/faces of the object. + * This method moves (no-copy) texture to the object's inventory + * and doesn't make copy of the texture for each face. + * Then this only texture is used for all selected faces. + */ + void applyNoCopyTextureToTEs(LLViewerInventoryItem* item); + ESelectType getSelectType() const { return mSelectType; } private: diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index e6f3b1e04e..45ef8f1a6d 100755 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -85,12 +85,32 @@ static F32 sCurMaxTexPriority = 1.f; class LLOcclusionQueryPool : public LLGLNamePool { +public: + LLOcclusionQueryPool() + { + mCurQuery = 1; + } + protected: + + std::list<GLuint> mAvailableName; + GLuint mCurQuery; + virtual GLuint allocateName() { - GLuint name; - glGenQueriesARB(1, &name); - return name; + GLuint ret = 0; + + if (!mAvailableName.empty()) + { + ret = mAvailableName.front(); + mAvailableName.pop_front(); + } + else + { + ret = mCurQuery++; + } + + return ret; } virtual void releaseName(GLuint name) @@ -98,7 +118,8 @@ protected: #if LL_TRACK_PENDING_OCCLUSION_QUERIES LLSpatialGroup::sPendingQueries.erase(name); #endif - glDeleteQueriesARB(1, &name); + llassert(std::find(mAvailableName.begin(), mAvailableName.end(), name) == mAvailableName.end()); + mAvailableName.push_back(name); } }; @@ -259,79 +280,39 @@ U8* get_box_fan_indices_ptr(LLCamera* camera, const LLVector4a& center) return (U8*) (sOcclusionIndices+cypher*8); } - -static LLFastTimer::DeclareTimer FTM_BUILD_OCCLUSION("Build Occlusion"); - -void LLSpatialGroup::buildOcclusion() +//create a vertex buffer for efficiently rendering cubes +LLVertexBuffer* ll_create_cube_vb(U32 type_mask, U32 usage) { - //if (mOcclusionVerts.isNull()) - { - mOcclusionVerts = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX, - LLVertexBuffer::sUseStreamDraw ? mBufferUsage : 0); //if GL has a hard time with VBOs, don't use them for occlusion culling. - mOcclusionVerts->allocateBuffer(8, 64, true); - - LLStrider<U16> idx; - mOcclusionVerts->getIndexStrider(idx); - for (U32 i = 0; i < 64; i++) - { - *idx++ = sOcclusionIndices[i]; - } - } + LLVertexBuffer* ret = new LLVertexBuffer(type_mask, usage); - LLVector4a fudge; - fudge.splat(SG_OCCLUSION_FUDGE); - - LLVector4a r; - r.setAdd(mBounds[1], fudge); + ret->allocateBuffer(8, 64, true); LLStrider<LLVector3> pos; - - { - LLFastTimer t(FTM_BUILD_OCCLUSION); - mOcclusionVerts->getVertexStrider(pos); - } + LLStrider<U16> idx; - { - LLVector4a* v = (LLVector4a*) pos.get(); + ret->getVertexStrider(pos); + ret->getIndexStrider(idx); - const LLVector4a& c = mBounds[0]; - const LLVector4a& s = r; - - static const LLVector4a octant[] = - { - LLVector4a(-1.f, -1.f, -1.f), - LLVector4a(-1.f, -1.f, 1.f), - LLVector4a(-1.f, 1.f, -1.f), - LLVector4a(-1.f, 1.f, 1.f), - - LLVector4a(1.f, -1.f, -1.f), - LLVector4a(1.f, -1.f, 1.f), - LLVector4a(1.f, 1.f, -1.f), - LLVector4a(1.f, 1.f, 1.f), - }; - - //vertex positions are encoded so the 3 bits of their vertex index - //correspond to their axis facing, with bit position 3,2,1 matching - //axis facing x,y,z, bit set meaning positive facing, bit clear - //meaning negative facing - - for (S32 i = 0; i < 8; ++i) - { - LLVector4a p; - p.setMul(s, octant[i]); - p.add(c); - v[i] = p; - } - } - + pos[0] = LLVector3(-1,-1,-1); + pos[1] = LLVector3(-1,-1, 1); + pos[2] = LLVector3(-1, 1,-1); + pos[3] = LLVector3(-1, 1, 1); + pos[4] = LLVector3( 1,-1,-1); + pos[5] = LLVector3( 1,-1, 1); + pos[6] = LLVector3( 1, 1,-1); + pos[7] = LLVector3( 1, 1, 1); + + for (U32 i = 0; i < 64; i++) { - mOcclusionVerts->flush(); - LLVertexBuffer::unbind(); + idx[i] = sOcclusionIndices[i]; } - clearState(LLSpatialGroup::OCCLUSION_DIRTY); + ret->flush(); + + return ret; } +static LLFastTimer::DeclareTimer FTM_BUILD_OCCLUSION("Build Occlusion"); BOOL earlyFail(LLCamera* camera, LLSpatialGroup* group); @@ -394,8 +375,6 @@ LLSpatialGroup::~LLSpatialGroup() } } - mOcclusionVerts = NULL; - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); clearDrawMap(); clearAtlasList() ; @@ -688,6 +667,11 @@ void LLSpatialGroup::rebuildGeom() if (!isDead()) { mSpatialPartition->rebuildGeom(this); + + if (isState(LLSpatialGroup::MESH_DIRTY)) + { + gPipeline.markMeshDirty(this); + } } } @@ -700,6 +684,9 @@ void LLSpatialGroup::rebuildMesh() } static LLFastTimer::DeclareTimer FTM_REBUILD_VBO("VBO Rebuilt"); +static LLFastTimer::DeclareTimer FTM_ADD_GEOMETRY_COUNT("Add Geometry"); +static LLFastTimer::DeclareTimer FTM_CREATE_VB("Create VB"); +static LLFastTimer::DeclareTimer FTM_GET_GEOMETRY("Get Geometry"); void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group) { @@ -721,27 +708,36 @@ void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group) //get geometry count U32 index_count = 0; U32 vertex_count = 0; - - addGeometryCount(group, vertex_count, index_count); + + { + LLFastTimer t(FTM_ADD_GEOMETRY_COUNT); + addGeometryCount(group, vertex_count, index_count); + } if (vertex_count > 0 && index_count > 0) { //create vertex buffer containing volume geometry for this node - group->mBuilt = 1.f; - if (group->mVertexBuffer.isNull() || - !group->mVertexBuffer->isWriteable() || - (group->mBufferUsage != group->mVertexBuffer->getUsage() && LLVertexBuffer::sEnableVBOs)) { - group->mVertexBuffer = createVertexBuffer(mVertexDataMask, group->mBufferUsage); - group->mVertexBuffer->allocateBuffer(vertex_count, index_count, true); - stop_glerror(); + LLFastTimer t(FTM_CREATE_VB); + group->mBuilt = 1.f; + if (group->mVertexBuffer.isNull() || + !group->mVertexBuffer->isWriteable() || + (group->mBufferUsage != group->mVertexBuffer->getUsage() && LLVertexBuffer::sEnableVBOs)) + { + group->mVertexBuffer = createVertexBuffer(mVertexDataMask, group->mBufferUsage); + group->mVertexBuffer->allocateBuffer(vertex_count, index_count, true); + stop_glerror(); + } + else + { + group->mVertexBuffer->resizeBuffer(vertex_count, index_count); + stop_glerror(); + } } - else + { - group->mVertexBuffer->resizeBuffer(vertex_count, index_count); - stop_glerror(); + LLFastTimer t(FTM_GET_GEOMETRY); + getGeometry(group); } - - getGeometry(group); } else { @@ -933,11 +929,6 @@ void LLSpatialGroup::shift(const LLVector4a &offset) setState(GEOM_DIRTY); gPipeline.markRebuild(this, TRUE); } - - if (mOcclusionVerts.notNull()) - { - setState(OCCLUSION_DIRTY); - } } class LLSpatialSetState : public LLSpatialGroup::OctreeTraveler @@ -1238,8 +1229,6 @@ LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) : mVisible[i] = 0; } - mOcclusionVerts = NULL; - mRadius = 1; mPixelArea = 1024.f; } @@ -1468,10 +1457,14 @@ void LLSpatialGroup::handleChildRemoval(const OctreeNode* parent, const OctreeNo unbound(); } -void LLSpatialGroup::destroyGL() +void LLSpatialGroup::destroyGL(bool keep_occlusion) { setState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::IMAGE_DIRTY); - gPipeline.markRebuild(this, TRUE); + + if (!keep_occlusion) + { //going to need a rebuild + gPipeline.markRebuild(this, TRUE); + } mLastUpdateTime = gFrameTimeSeconds; mVertexBuffer = NULL; @@ -1479,16 +1472,18 @@ void LLSpatialGroup::destroyGL() clearDrawMap(); - for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) + if (!keep_occlusion) { - if (mOcclusionQuery[i]) + for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) { - sQueryPool.release(mOcclusionQuery[i]); - mOcclusionQuery[i] = 0; + if (mOcclusionQuery[i]) + { + sQueryPool.release(mOcclusionQuery[i]); + mOcclusionQuery[i] = 0; + } } } - mOcclusionVerts = NULL; for (LLSpatialGroup::element_iter i = getData().begin(); i != getData().end(); ++i) { @@ -1496,7 +1491,10 @@ void LLSpatialGroup::destroyGL() for (S32 j = 0; j < drawable->getNumFaces(); j++) { LLFace* facep = drawable->getFace(j); - facep->clearVertexBuffer(); + if (facep) + { + facep->clearVertexBuffer(); + } } } } @@ -1559,15 +1557,13 @@ BOOL LLSpatialGroup::rebound() mBounds[1].mul(0.5f); } - setState(OCCLUSION_DIRTY); - clearState(DIRTY); return TRUE; } static LLFastTimer::DeclareTimer FTM_OCCLUSION_READBACK("Readback Occlusion"); -static LLFastTimer::DeclareTimer FTM_OCCLUSION_WAIT("Wait"); +static LLFastTimer::DeclareTimer FTM_OCCLUSION_WAIT("Occlusion Wait"); void LLSpatialGroup::checkOcclusion() { @@ -1587,7 +1583,9 @@ void LLSpatialGroup::checkOcclusion() { glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available); - if (mOcclusionIssued[LLViewerCamera::sCurCameraID] < gFrameCount) + static LLCachedControl<bool> wait_for_query(gSavedSettings, "RenderSynchronousOcclusion"); + + if (wait_for_query && mOcclusionIssued[LLViewerCamera::sCurCameraID] < gFrameCount) { //query was issued last frame, wait until it's available S32 max_loop = 1024; LLFastTimer t(FTM_OCCLUSION_WAIT); @@ -1638,7 +1636,9 @@ void LLSpatialGroup::checkOcclusion() else { assert_states_valid(this); + setOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF); + assert_states_valid(this); } @@ -1693,12 +1693,6 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera) mOcclusionQuery[LLViewerCamera::sCurCameraID] = sQueryPool.allocate(); } - if (mOcclusionVerts.isNull() || isState(LLSpatialGroup::OCCLUSION_DIRTY)) - { - LLFastTimer t(FTM_OCCLUSION_BUILD); - buildOcclusion(); - } - // Depth clamp all water to avoid it being culled as a result of being // behind the far clip plane, and in the case of edge water to avoid // it being culled while still visible. @@ -1729,10 +1723,13 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera) glBeginQueryARB(mode, mOcclusionQuery[LLViewerCamera::sCurCameraID]); } - { - LLFastTimer t(FTM_OCCLUSION_SET_BUFFER); - mOcclusionVerts->setBuffer(LLVertexBuffer::MAP_VERTEX); - } + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + llassert(shader); + + shader->uniform3fv(LLShaderMgr::BOX_CENTER, 1, mBounds[0].getF32ptr()); + shader->uniform3f(LLShaderMgr::BOX_SIZE, mBounds[1][0]+SG_OCCLUSION_FUDGE, + mBounds[1][1]+SG_OCCLUSION_FUDGE, + mBounds[1][2]+SG_OCCLUSION_FUDGE); if (!use_depth_clamp && mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER) { @@ -1741,12 +1738,12 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera) LLGLSquashToFarClip squash(glh_get_current_projection(), 1); if (camera->getOrigin().isExactlyZero()) { //origin is invalid, draw entire box - mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0); - mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8); + gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0); + gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8); } else { - mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0])); + gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0])); } } else @@ -1754,12 +1751,12 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera) LLFastTimer t(FTM_OCCLUSION_DRAW); if (camera->getOrigin().isExactlyZero()) { //origin is invalid, draw entire box - mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0); - mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8); + gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0); + gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8); } else { - mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0])); + gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0])); } } @@ -2483,18 +2480,21 @@ void pushVerts(LLSpatialGroup* group, U32 mask) void pushVerts(LLFace* face, U32 mask) { - llassert(face->verify()); + if (face) + { + llassert(face->verify()); - LLVertexBuffer* buffer = face->getVertexBuffer(); + LLVertexBuffer* buffer = face->getVertexBuffer(); - if (buffer && (face->getGeomCount() >= 3)) - { - buffer->setBuffer(mask); - U16 start = face->getGeomStart(); - U16 end = start + face->getGeomCount()-1; - U32 count = face->getIndicesCount(); - U16 offset = face->getIndicesStart(); - buffer->drawRange(LLRender::TRIANGLES, start, end, count, offset); + if (buffer && (face->getGeomCount() >= 3)) + { + buffer->setBuffer(mask); + U16 start = face->getGeomStart(); + U16 end = start + face->getGeomCount()-1; + U32 count = face->getIndicesCount(); + U16 offset = face->getIndicesStart(); + buffer->drawRange(LLRender::TRIANGLES, start, end, count, offset); + } } } @@ -2631,7 +2631,7 @@ void renderOctree(LLSpatialGroup* group) for (S32 j = 0; j < drawable->getNumFaces(); j++) { LLFace* face = drawable->getFace(j); - if (face->getVertexBuffer()) + if (face && face->getVertexBuffer()) { if (gFrameTimeSeconds - face->mLastUpdateTime < 0.5f) { @@ -2760,19 +2760,6 @@ void renderVisibility(LLSpatialGroup* group, LLCamera* camera) gGL.diffuseColor4f(0.f, 0.75f, 0.f, 0.5f); pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX); } - /*else if (camera && group->mOcclusionVerts.notNull()) - { - LLVertexBuffer::unbind(); - group->mOcclusionVerts->setBuffer(LLVertexBuffer::MAP_VERTEX); - - gGL.diffuseColor4f(1.0f, 0.f, 0.f, 0.5f); - group->mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, group->mBounds[0])); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - - gGL.diffuseColor4f(1.0f, 1.f, 1.f, 1.0f); - group->mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, group->mBounds[0])); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - }*/ } } @@ -3002,15 +2989,17 @@ void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE) for (S32 i = 0; i < drawable->getNumFaces(); i++) { LLFace* facep = drawable->getFace(i); + if (facep) + { + ext = facep->mExtents; - ext = facep->mExtents; - - pos.setAdd(ext[0], ext[1]); - pos.mul(0.5f); - size.setSub(ext[1], ext[0]); - size.mul(0.5f); + pos.setAdd(ext[0], ext[1]); + pos.mul(0.5f); + size.setSub(ext[1], ext[0]); + size.mul(0.5f); - drawBoxOutline(pos,size); + drawBoxOutline(pos,size); + } } //render drawable bounding box @@ -3502,18 +3491,21 @@ void renderPhysicsShapes(LLSpatialGroup* group) for (S32 i = 0; i < drawable->getNumFaces(); ++i) { LLFace* face = drawable->getFace(i); - LLVertexBuffer* buff = face->getVertexBuffer(); - if (buff) + if (face) { - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + LLVertexBuffer* buff = face->getVertexBuffer(); + if (buff) + { + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - buff->setBuffer(LLVertexBuffer::MAP_VERTEX); - gGL.diffuseColor3f(0.2f, 0.5f, 0.3f); - buff->draw(LLRender::TRIANGLES, buff->getNumIndices(), 0); + buff->setBuffer(LLVertexBuffer::MAP_VERTEX); + gGL.diffuseColor3f(0.2f, 0.5f, 0.3f); + buff->draw(LLRender::TRIANGLES, buff->getNumIndices(), 0); - gGL.diffuseColor3f(0.2f, 1.f, 0.3f); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - buff->draw(LLRender::TRIANGLES, buff->getNumIndices(), 0); + gGL.diffuseColor3f(0.2f, 1.f, 0.3f); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + buff->draw(LLRender::TRIANGLES, buff->getNumIndices(), 0); + } } } } @@ -3537,6 +3529,7 @@ void renderTexturePriority(LLDrawable* drawable) //LLViewerTexture* imagep = facep->getTexture(); //if (imagep) + if (facep) { //F32 vsize = imagep->mMaxVirtualSize; @@ -3589,7 +3582,11 @@ void renderPoints(LLDrawable* drawablep) gGL.diffuseColor3f(1,1,1); for (S32 i = 0; i < drawablep->getNumFaces(); i++) { - gGL.vertex3fv(drawablep->getFace(i)->mCenterLocal.mV); + LLFace * face = drawablep->getFace(i); + if (face) + { + gGL.vertex3fv(face->mCenterLocal.mV); + } } gGL.end(); } @@ -3770,7 +3767,11 @@ void renderLights(LLDrawable* drawablep) for (S32 i = 0; i < drawablep->getNumFaces(); i++) { - pushVerts(drawablep->getFace(i), LLVertexBuffer::MAP_VERTEX); + LLFace * face = drawablep->getFace(i); + if (face) + { + pushVerts(face, LLVertexBuffer::MAP_VERTEX); + } } const LLVector4a* ext = drawablep->getSpatialExtents(); @@ -4172,18 +4173,21 @@ public: for (U32 i = 0; i < drawable->getNumFaces(); ++i) { LLFace* facep = drawable->getFace(i); - U8 index = facep->getTextureIndex(); - if (facep->mDrawInfo) + if (facep) { - if (index < 255) + U8 index = facep->getTextureIndex(); + if (facep->mDrawInfo) { - if (facep->mDrawInfo->mTextureList.size() <= index) - { - llerrs << "Face texture index out of bounds." << llendl; - } - else if (facep->mDrawInfo->mTextureList[index] != facep->getTexture()) + if (index < 255) { - llerrs << "Face texture index incorrect." << llendl; + if (facep->mDrawInfo->mTextureList.size() <= index) + { + llerrs << "Face texture index out of bounds." << llendl; + } + else if (facep->mDrawInfo->mTextureList[index] != facep->getTexture()) + { + llerrs << "Face texture index incorrect." << llendl; + } } } } diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h index 680d70803d..7968c28900 100755 --- a/indra/newview/llspatialpartition.h +++ b/indra/newview/llspatialpartition.h @@ -283,11 +283,10 @@ public: SKIP_FRUSTUM_CHECK = 0x00000020, IN_IMAGE_QUEUE = 0x00000040, IMAGE_DIRTY = 0x00000080, - OCCLUSION_DIRTY = 0x00000100, - MESH_DIRTY = 0x00000200, - NEW_DRAWINFO = 0x00000400, - IN_BUILD_Q1 = 0x00000800, - IN_BUILD_Q2 = 0x00001000, + MESH_DIRTY = 0x00000100, + NEW_DRAWINFO = 0x00000200, + IN_BUILD_Q1 = 0x00000400, + IN_BUILD_Q2 = 0x00000800, STATE_MASK = 0x0000FFFF, } eSpatialState; @@ -333,10 +332,9 @@ public: BOOL boundObjects(BOOL empty, LLVector4a& newMin, LLVector4a& newMax); void unbound(); BOOL rebound(); - void buildOcclusion(); //rebuild mOcclusionVerts void checkOcclusion(); //read back last occlusion query (if any) void doOcclusion(LLCamera* camera); //issue occlusion query - void destroyGL(); + void destroyGL(bool keep_occlusion = false); void updateDistance(LLCamera& camera); BOOL needsUpdate(); @@ -435,7 +433,6 @@ public: LLSpatialPartition* mSpatialPartition; LLPointer<LLVertexBuffer> mVertexBuffer; - LLPointer<LLVertexBuffer> mOcclusionVerts; GLuint mOcclusionQuery[LLViewerCamera::NUM_CAMERAS]; U32 mBufferUsage; @@ -677,6 +674,7 @@ class LLParticlePartition : public LLSpatialPartition { public: LLParticlePartition(); + virtual void rebuildGeom(LLSpatialGroup* group); virtual void getGeometry(LLSpatialGroup* group); virtual void addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32& index_count); virtual F32 calcPixelArea(LLSpatialGroup* group, LLCamera& camera); @@ -691,10 +689,14 @@ public: }; //spatial partition for grass (implemented in LLVOGrass.cpp) -class LLGrassPartition : public LLParticlePartition +class LLGrassPartition : public LLSpatialPartition { public: LLGrassPartition(); + virtual void getGeometry(LLSpatialGroup* group); + virtual void addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32& index_count); +protected: + U32 mRenderPass; }; //class for wrangling geometry out of volumes (implemented in LLVOVolume.cpp) diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 6b0fc26db7..ee7a234bbe 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -740,6 +740,7 @@ bool idle_startup() { display_startup(); initialize_edit_menu(); + initialize_spellcheck_menu(); display_startup(); init_menus(); display_startup(); @@ -3215,17 +3216,6 @@ bool process_login_success_response() gSavedSettings.setU32("PreferredMaturity", preferredMaturity); } - // During the AO transition, this flag will be true. Then the flag will - // go away. After the AO transition, this code and all the code that - // uses it can be deleted. - text = response["ao_transition"].asString(); - if (!text.empty()) - { - if (text == "1") - { - gAgent.setAOTransition(); - } - } text = response["start_location"].asString(); if(!text.empty()) diff --git a/indra/newview/lltextureatlas.cpp b/indra/newview/lltextureatlas.cpp index d2e4b01732..f8c1bca8ae 100644 --- a/indra/newview/lltextureatlas.cpp +++ b/indra/newview/lltextureatlas.cpp @@ -116,7 +116,6 @@ LLGLuint LLTextureAtlas::insertSubTexture(LLImageGL* source_gl_tex, S32 discard_ return 0 ; } - glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, TRUE); glTexSubImage2D(GL_TEXTURE_2D, 0, xoffset, yoffset, w, h, mGLTexturep->getPrimaryFormat(), mGLTexturep->getFormatType(), raw_image->getData()); diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index ed9faa0706..6703ef4a41 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -97,6 +97,7 @@ public: LLTextureCtrl* owner, const std::string& label, PermissionMask immediate_filter_perm_mask, + PermissionMask dnd_filter_perm_mask, PermissionMask non_immediate_filter_perm_mask, BOOL can_apply_immediately, LLUIImagePtr fallback_image_name); @@ -134,6 +135,9 @@ public: void onFilterEdit(const std::string& search_string ); + void setCanApply(bool can_preview, bool can_apply); + void setTextureSelectedCallback(texture_selected_callback cb) {mTextureSelectedCallback = cb;} + static void onBtnSetToDefault( void* userdata ); static void onBtnSelect( void* userdata ); static void onBtnCancel( void* userdata ); @@ -175,6 +179,7 @@ protected: LLFilterEditor* mFilterEdit; LLInventoryPanel* mInventoryPanel; PermissionMask mImmediateFilterPermMask; + PermissionMask mDnDFilterPermMask; PermissionMask mNonImmediateFilterPermMask; BOOL mCanApplyImmediately; BOOL mNoCopyTextureSelected; @@ -184,12 +189,18 @@ protected: LLRadioGroup* mModeSelector; LLScrollListCtrl* mLocalScrollCtrl; + +private: + bool mCanApply; + bool mCanPreview; + texture_selected_callback mTextureSelectedCallback; }; LLFloaterTexturePicker::LLFloaterTexturePicker( LLTextureCtrl* owner, const std::string& label, PermissionMask immediate_filter_perm_mask, + PermissionMask dnd_filter_perm_mask, PermissionMask non_immediate_filter_perm_mask, BOOL can_apply_immediately, LLUIImagePtr fallback_image) @@ -205,9 +216,12 @@ LLFloaterTexturePicker::LLFloaterTexturePicker( mActive( TRUE ), mFilterEdit(NULL), mImmediateFilterPermMask(immediate_filter_perm_mask), + mDnDFilterPermMask(dnd_filter_perm_mask), mNonImmediateFilterPermMask(non_immediate_filter_perm_mask), mContextConeOpacity(0.f), - mSelectedItemPinned( FALSE ) + mSelectedItemPinned( FALSE ), + mCanApply(true), + mCanPreview(true) { buildFromFile("floater_texture_ctrl.xml"); mCanApplyImmediately = can_apply_immediately; @@ -319,7 +333,7 @@ BOOL LLFloaterTexturePicker::handleDragAndDrop( if (xfer) item_perm_mask |= PERM_TRANSFER; //PermissionMask filter_perm_mask = getFilterPermMask(); Commented out due to no-copy texture loss. - PermissionMask filter_perm_mask = mImmediateFilterPermMask; + PermissionMask filter_perm_mask = mDnDFilterPermMask; if ( (item_perm_mask & filter_perm_mask) == filter_perm_mask ) { if (drop) @@ -464,7 +478,7 @@ BOOL LLFloaterTexturePicker::postBuild() mNoCopyTextureSelected = FALSE; - getChild<LLUICtrl>("apply_immediate_check")->setValue(gSavedSettings.getBOOL("ApplyTextureImmediately")); + getChild<LLUICtrl>("apply_immediate_check")->setValue(gSavedSettings.getBOOL("TextureLivePreview")); childSetCommitCallback("apply_immediate_check", onApplyImmediateCheck, this); if (!mCanApplyImmediately) @@ -546,7 +560,7 @@ void LLFloaterTexturePicker::draw() // if we're inactive, gray out "apply immediate" checkbox getChildView("show_folders_check")->setEnabled(mActive && mCanApplyImmediately && !mNoCopyTextureSelected); - getChildView("Select")->setEnabled(mActive); + getChildView("Select")->setEnabled(mActive && mCanApply); getChildView("Pipette")->setEnabled(mActive); getChild<LLUICtrl>("Pipette")->setValue(LLToolMgr::getInstance()->getCurrentTool() == LLToolPipette::getInstance()); @@ -702,8 +716,7 @@ PermissionMask LLFloaterTexturePicker::getFilterPermMask() void LLFloaterTexturePicker::commitIfImmediateSet() { - bool apply_immediate = getChild<LLUICtrl>("apply_immediate_check")->getValue().asBoolean(); - if (!mNoCopyTextureSelected && apply_immediate && mOwner) + if (!mNoCopyTextureSelected && mOwner && mCanApply) { mOwner->onFloaterCommit(LLTextureCtrl::TEXTURE_CHANGE); } @@ -713,6 +726,7 @@ void LLFloaterTexturePicker::commitIfImmediateSet() void LLFloaterTexturePicker::onBtnSetToDefault(void* userdata) { LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata; + self->setCanApply(true, true); if (self->mOwner) { self->setImageID( self->mOwner->getDefaultImageAssetID() ); @@ -724,6 +738,7 @@ void LLFloaterTexturePicker::onBtnSetToDefault(void* userdata) void LLFloaterTexturePicker::onBtnWhite(void* userdata) { LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata; + self->setCanApply(true, true); self->setImageID( self->mWhiteImageAssetID ); self->commitIfImmediateSet(); } @@ -804,13 +819,14 @@ void LLFloaterTexturePicker::onSelectionChange(const std::deque<LLFolderViewItem mNoCopyTextureSelected = FALSE; if (itemp) { + mTextureSelectedCallback(itemp); if (!itemp->getPermissions().allowCopyBy(gAgent.getID())) { mNoCopyTextureSelected = TRUE; } mImageAssetID = itemp->getAssetUUID(); mViewModel->setDirty(); // *TODO: shouldn't we be using setValue() here? - if (user_action) + if (user_action && mCanPreview) { // only commit intentional selections, not implicit ones commitIfImmediateSet(); @@ -947,7 +963,7 @@ void LLFloaterTexturePicker::onApplyImmediateCheck(LLUICtrl* ctrl, void *user_da LLFloaterTexturePicker* picker = (LLFloaterTexturePicker*)user_data; LLCheckBoxCtrl* check_box = (LLCheckBoxCtrl*)ctrl; - gSavedSettings.setBOOL("ApplyTextureImmediately", check_box->get()); + gSavedSettings.setBOOL("TextureLivePreview", check_box->get()); picker->updateFilterPermMask(); picker->commitIfImmediateSet(); @@ -958,6 +974,16 @@ void LLFloaterTexturePicker::updateFilterPermMask() //mInventoryPanel->setFilterPermMask( getFilterPermMask() ); Commented out due to no-copy texture loss. } +void LLFloaterTexturePicker::setCanApply(bool can_preview, bool can_apply) +{ + getChildRef<LLUICtrl>("Select").setEnabled(can_apply); + getChildRef<LLUICtrl>("preview_disabled").setVisible(!can_preview); + getChildRef<LLUICtrl>("apply_immediate_check").setVisible(can_preview); + + mCanApply = can_apply; + mCanPreview = can_preview ? gSavedSettings.getBOOL("TextureLivePreview") : false; +} + void LLFloaterTexturePicker::onFilterEdit(const std::string& search_string ) { std::string upper_case_search_string = search_string; @@ -1108,6 +1134,15 @@ void LLTextureCtrl::setCanApplyImmediately(BOOL b) } } +void LLTextureCtrl::setCanApply(bool can_preview, bool can_apply) +{ + LLFloaterTexturePicker* floaterp = dynamic_cast<LLFloaterTexturePicker*>(mFloaterHandle.get()); + if( floaterp ) + { + floaterp->setCanApply(can_preview, can_apply); + } +} + void LLTextureCtrl::setVisible( BOOL visible ) { if( !visible ) @@ -1188,12 +1223,19 @@ void LLTextureCtrl::showPicker(BOOL take_focus) this, mLabel, mImmediateFilterPermMask, + mDnDFilterPermMask, mNonImmediateFilterPermMask, mCanApplyImmediately, mFallbackImage); mFloaterHandle = floaterp->getHandle(); + LLFloaterTexturePicker* texture_floaterp = dynamic_cast<LLFloaterTexturePicker*>(floaterp); + if (texture_floaterp && mOnTextureSelectedCallback) + { + texture_floaterp->setTextureSelectedCallback(mOnTextureSelectedCallback); + } + LLFloater* root_floater = gFloaterView->getParentFloater(this); if (root_floater) root_floater->addDependentFloater(floaterp); @@ -1318,6 +1360,16 @@ void LLTextureCtrl::onFloaterCommit(ETexturePickOp op, LLUUID id) } } +void LLTextureCtrl::setOnTextureSelectedCallback(texture_selected_callback cb) +{ + mOnTextureSelectedCallback = cb; + LLFloaterTexturePicker* floaterp = dynamic_cast<LLFloaterTexturePicker*>(mFloaterHandle.get()); + if (floaterp) + { + floaterp->setTextureSelectedCallback(cb); + } +} + void LLTextureCtrl::setImageAssetName(const std::string& name) { LLPointer<LLUIImage> imagep = LLUI::getUIImage(name); diff --git a/indra/newview/lltexturectrl.h b/indra/newview/lltexturectrl.h index 3abe84dcc3..599d9c70c5 100644 --- a/indra/newview/lltexturectrl.h +++ b/indra/newview/lltexturectrl.h @@ -43,6 +43,7 @@ class LLViewerFetchedTexture; // used for setting drag & drop callbacks. typedef boost::function<BOOL (LLUICtrl*, LLInventoryItem*)> drag_n_drop_callback; +typedef boost::function<void (LLInventoryItem*)> texture_selected_callback; ////////////////////////////////////////////////////////////////////////////////////////// @@ -147,8 +148,12 @@ public: void setCaption(const std::string& caption); void setCanApplyImmediately(BOOL b); + void setCanApply(bool can_preview, bool can_apply); + void setImmediateFilterPermMask(PermissionMask mask) { mImmediateFilterPermMask = mask; } + void setDnDFilterPermMask(PermissionMask mask) + { mDnDFilterPermMask = mask; } void setNonImmediateFilterPermMask(PermissionMask mask) { mNonImmediateFilterPermMask = mask; } PermissionMask getImmediateFilterPermMask() { return mImmediateFilterPermMask; } @@ -172,6 +177,11 @@ public: void setOnSelectCallback(commit_callback_t cb) { mOnSelectCallback = cb; } + /* + * callback for changing texture selection in inventory list of texture floater + */ + void setOnTextureSelectedCallback(texture_selected_callback cb); + void setShowLoadingPlaceholder(BOOL showLoadingPlaceholder); LLViewerFetchedTexture* getTexture() { return mTexturep; } @@ -185,6 +195,7 @@ private: drag_n_drop_callback mDropCallback; commit_callback_t mOnCancelCallback; commit_callback_t mOnSelectCallback; + texture_selected_callback mOnTextureSelectedCallback; LLPointer<LLViewerFetchedTexture> mTexturep; LLUIColor mBorderColor; LLUUID mImageItemID; @@ -198,6 +209,7 @@ private: std::string mLabel; BOOL mAllowNoTexture; // If true, the user can select "none" as an option PermissionMask mImmediateFilterPermMask; + PermissionMask mDnDFilterPermMask; PermissionMask mNonImmediateFilterPermMask; BOOL mCanApplyImmediately; BOOL mCommitOnSelection; diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp index 425bf7ee87..52d085dd2c 100644 --- a/indra/newview/lltextureview.cpp +++ b/indra/newview/lltextureview.cpp @@ -510,7 +510,7 @@ void LLGLTexMemBar::draw() F32 discard_bias = LLViewerTexture::sDesiredDiscardBias; F32 cache_usage = (F32)BYTES_TO_MEGA_BYTES(LLAppViewer::getTextureCache()->getUsage()) ; F32 cache_max_usage = (F32)BYTES_TO_MEGA_BYTES(LLAppViewer::getTextureCache()->getMaxUsage()) ; - S32 line_height = (S32)(LLFontGL::getFontMonospace()->getLineHeight() + .5f); + S32 line_height = LLFontGL::getFontMonospace()->getLineHeight(); S32 v_offset = 0;//(S32)((texture_bar_height + 2.2f) * mTextureView->mNumTextureBars + 2.0f); F32 total_texture_downloaded = (F32)gTotalTextureBytes / (1024 * 1024); F32 total_object_downloaded = (F32)gTotalObjectBytes / (1024 * 1024); diff --git a/indra/newview/lltoastnotifypanel.cpp b/indra/newview/lltoastnotifypanel.cpp index a473ee7ce0..d629f3abac 100644 --- a/indra/newview/lltoastnotifypanel.cpp +++ b/indra/newview/lltoastnotifypanel.cpp @@ -457,7 +457,7 @@ button_name_set_t getButtonDisableList(const std::string& notification_name, con { search_map = user_give_item_disable_map; } - else if("TeleportOffered" == notification_name) + else if(("TeleportOffered" == notification_name) || ("TeleportOffered_MaturityExceeded" == notification_name)) { search_map = teleport_offered_disable_map; } diff --git a/indra/newview/lltooldraganddrop.h b/indra/newview/lltooldraganddrop.h index 245c2a23e6..41aee484db 100644 --- a/indra/newview/lltooldraganddrop.h +++ b/indra/newview/lltooldraganddrop.h @@ -93,6 +93,13 @@ public: static S32 getOperationId() { return sOperationId; } + // deal with permissions of object, etc. returns TRUE if drop can + // proceed, otherwise FALSE. + static BOOL handleDropTextureProtections(LLViewerObject* hit_obj, + LLInventoryItem* item, + LLToolDragAndDrop::ESource source, + const LLUUID& src_id); + protected: enum EDropTarget { @@ -219,13 +226,6 @@ protected: // inventory items to determine if a drop would be ok. static EAcceptance willObjectAcceptInventory(LLViewerObject* obj, LLInventoryItem* item); - // deal with permissions of object, etc. returns TRUE if drop can - // proceed, otherwise FALSE. - static BOOL handleDropTextureProtections(LLViewerObject* hit_obj, - LLInventoryItem* item, - LLToolDragAndDrop::ESource source, - const LLUUID& src_id); - public: // helper functions static BOOL isInventoryDropAcceptable(LLViewerObject* obj, LLInventoryItem* item) { return (ACCEPT_YES_COPY_SINGLE <= willObjectAcceptInventory(obj, item)); } diff --git a/indra/newview/lltoolmorph.cpp b/indra/newview/lltoolmorph.cpp index 718201e381..0d5daf129f 100644 --- a/indra/newview/lltoolmorph.cpp +++ b/indra/newview/lltoolmorph.cpp @@ -225,7 +225,8 @@ BOOL LLVisualParamHint::render() LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight, FALSE); - if (gAgentAvatarp->mDrawable.notNull()) + if (gAgentAvatarp->mDrawable.notNull() && + gAgentAvatarp->mDrawable->getFace(0)) { LLDrawPoolAvatar *avatarPoolp = (LLDrawPoolAvatar *)gAgentAvatarp->mDrawable->getFace(0)->getPool(); LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE); diff --git a/indra/newview/lltracker.cpp b/indra/newview/lltracker.cpp index bf1f8808a7..cbd16e873d 100644 --- a/indra/newview/lltracker.cpp +++ b/indra/newview/lltracker.cpp @@ -251,7 +251,7 @@ void LLTracker::render3D() instance()->mBeaconText->setDoFade(FALSE); } - F32 dist = gFloaterWorldMap->getDistanceToDestination(instance()->mTrackedPositionGlobal, 0.0f); + F32 dist = gFloaterWorldMap->getDistanceToDestination(instance()->getTrackedPositionGlobal(), 0.0f); if (dist < DESTINATION_REACHED_RADIUS) { instance()->stopTrackingAvatar(); diff --git a/indra/newview/llvieweraudio.cpp b/indra/newview/llvieweraudio.cpp index 2447f5dea8..8d8c401dac 100644 --- a/indra/newview/llvieweraudio.cpp +++ b/indra/newview/llvieweraudio.cpp @@ -41,6 +41,7 @@ #include "llstartup.h" #include "llviewerparcelmgr.h" #include "llparcel.h" +#include "llviewermessage.h" ///////////////////////////////////////////////////////// @@ -49,15 +50,22 @@ LLViewerAudio::LLViewerAudio() : mFadeState(FADE_IDLE), mFadeTime(), mIdleListnerActive(false), - mForcedTeleportFade(false) + mForcedTeleportFade(false), + mWasPlaying(false) { mTeleportFailedConnection = LLViewerParcelMgr::getInstance()-> setTeleportFailedCallback(boost::bind(&LLViewerAudio::onTeleportFailed, this)); + mTeleportFinishedConnection = LLViewerParcelMgr::getInstance()-> + setTeleportFinishedCallback(boost::bind(&LLViewerAudio::onTeleportFinished, this, _1, _2)); + mTeleportStartedConnection = LLViewerMessage::getInstance()-> + setTeleportStartedCallback(boost::bind(&LLViewerAudio::onTeleportStarted, this)); } LLViewerAudio::~LLViewerAudio() { mTeleportFailedConnection.disconnect(); + mTeleportFinishedConnection.disconnect(); + mTeleportStartedConnection.disconnect(); } void LLViewerAudio::registerIdleListener() @@ -67,7 +75,6 @@ void LLViewerAudio::registerIdleListener() mIdleListnerActive = true; doOnIdleRepeating(boost::bind(boost::bind(&LLViewerAudio::onIdleUpdate, this))); } - } void LLViewerAudio::startInternetStreamWithAutoFade(std::string streamURI) @@ -245,16 +252,54 @@ F32 LLViewerAudio::getFadeVolume() return fade_volume; } +void LLViewerAudio::onTeleportStarted() +{ + if (!LLViewerAudio::getInstance()->getForcedTeleportFade()) + { + // Even though the music was turned off it was starting up (with autoplay disabled) occasionally + // after a failed teleport or after an intra-parcel teleport. Also, the music sometimes was not + // restarting after a successful intra-parcel teleport. Setting mWasPlaying fixes these issues. + LLViewerAudio::getInstance()->setWasPlaying(!gAudiop->getInternetStreamURL().empty()); + LLViewerAudio::getInstance()->setForcedTeleportFade(true); + LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(LLStringUtil::null); + LLViewerAudio::getInstance()->setNextStreamURI(LLStringUtil::null); + } +} + void LLViewerAudio::onTeleportFailed() { - if (gAudiop) + // Calling audio_update_volume makes sure that the music stream is properly set to be restored to + // its previous value + audio_update_volume(false); + + if (gAudiop && mWasPlaying) + { + LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if (parcel) + { + mNextStreamURI = parcel->getMusicURL(); + llinfos << "Teleport failed -- setting music stream to " << mNextStreamURI << llendl; + } + } + mWasPlaying = false; +} + +void LLViewerAudio::onTeleportFinished(const LLVector3d& pos, const bool& local) +{ + // Calling audio_update_volume makes sure that the music stream is properly set to be restored to + // its previous value + audio_update_volume(false); + + if (gAudiop && local && mWasPlaying) { LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); if (parcel) { mNextStreamURI = parcel->getMusicURL(); + llinfos << "Intraparcel teleport -- setting music stream to " << mNextStreamURI << llendl; } } + mWasPlaying = false; } void init_audio() @@ -360,15 +405,9 @@ void audio_update_volume(bool force_update) // Streaming Music if (gAudiop) { - if (progress_view_visible && !LLViewerAudio::getInstance()->getForcedTeleportFade()) - { - LLViewerAudio::getInstance()->setForcedTeleportFade(true); - LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(LLStringUtil::null); - LLViewerAudio::getInstance()->setNextStreamURI(LLStringUtil::null); - } - - if (!progress_view_visible && LLViewerAudio::getInstance()->getForcedTeleportFade() == true) + if (!progress_view_visible && LLViewerAudio::getInstance()->getForcedTeleportFade()) { + LLViewerAudio::getInstance()->setWasPlaying(!gAudiop->getInternetStreamURL().empty()); LLViewerAudio::getInstance()->setForcedTeleportFade(false); } diff --git a/indra/newview/llvieweraudio.h b/indra/newview/llvieweraudio.h index a3da9fc6b8..8c302c6549 100644 --- a/indra/newview/llvieweraudio.h +++ b/indra/newview/llvieweraudio.h @@ -66,6 +66,7 @@ public: bool getForcedTeleportFade() { return mForcedTeleportFade; }; void setForcedTeleportFade(bool fade) { mForcedTeleportFade = fade;} ; void setNextStreamURI(std::string stream) { mNextStreamURI = stream; } ; + void setWasPlaying(bool playing) { mWasPlaying = playing;} ; private: @@ -76,13 +77,17 @@ private: LLFrameTimer stream_fade_timer; bool mIdleListnerActive; bool mForcedTeleportFade; + bool mWasPlaying; boost::signals2::connection mTeleportFailedConnection; + boost::signals2::connection mTeleportFinishedConnection; + boost::signals2::connection mTeleportStartedConnection; void registerIdleListener(); void deregisterIdleListener() { mIdleListnerActive = false; }; void startFading(); void onTeleportFailed(); - + void onTeleportFinished(const LLVector3d& pos, const bool& local); + void onTeleportStarted(); }; #endif //LL_VIEWER_H diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index f2712e7590..dec1615246 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -71,8 +71,12 @@ #include "llpaneloutfitsinventory.h" #include "llpanellogin.h" #include "llpaneltopinfobar.h" +#include "llspellcheck.h" #include "llupdaterservice.h" +// Third party library includes +#include <boost/algorithm/string.hpp> + #ifdef TOGGLE_HACKED_GODLIKE_VIEWER BOOL gHackGodmode = FALSE; #endif @@ -325,7 +329,7 @@ static bool handleJoystickChanged(const LLSD& newvalue) static bool handleUseOcclusionChanged(const LLSD& newvalue) { - LLPipeline::sUseOcclusion = (newvalue.asBoolean() && gGLManager.mHasOcclusionQuery + LLPipeline::sUseOcclusion = (newvalue.asBoolean() && gGLManager.mHasOcclusionQuery && LLGLSLShader::sNoFixedFunction && LLFeatureManager::getInstance()->isFeatureAvailable("UseOcclusion") && !gUseWireframe) ? 2 : 0; return true; } @@ -337,15 +341,6 @@ static bool handleUploadBakedTexOldChanged(const LLSD& newvalue) } -static bool handleNumpadControlChanged(const LLSD& newvalue) -{ - if (gKeyboard) - { - gKeyboard->setNumpadDistinct(static_cast<LLKeyboard::e_numpad_distinct>(newvalue.asInteger())); - } - return true; -} - static bool handleWLSkyDetailChanged(const LLSD&) { if (gSky.mVOWLSkyp.notNull()) @@ -501,6 +496,25 @@ bool handleForceShowGrid(const LLSD& newvalue) return true; } +bool handleSpellCheckChanged() +{ + if (gSavedSettings.getBOOL("SpellCheck")) + { + std::list<std::string> dict_list; + std::string dict_setting = gSavedSettings.getString("SpellCheckDictionary"); + boost::split(dict_list, dict_setting, boost::is_any_of(std::string(","))); + if (!dict_list.empty()) + { + LLSpellChecker::setUseSpellCheck(dict_list.front()); + dict_list.pop_front(); + LLSpellChecker::instance().setSecondaryDictionaries(dict_list); + return true; + } + } + LLSpellChecker::setUseSpellCheck(LLStringUtil::null); + return true; +} + bool toggle_agent_pause(const LLSD& newvalue) { if ( newvalue.asBoolean() ) @@ -637,7 +651,6 @@ void settings_setup_listeners() gSavedSettings.getControl("RenderUseStreamVBO")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); gSavedSettings.getControl("RenderPreferStreamDraw")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); gSavedSettings.getControl("WLSkyDetail")->getSignal()->connect(boost::bind(&handleWLSkyDetailChanged, _2)); - gSavedSettings.getControl("NumpadControl")->getSignal()->connect(boost::bind(&handleNumpadControlChanged, _2)); gSavedSettings.getControl("JoystickAxis0")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); gSavedSettings.getControl("JoystickAxis1")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); gSavedSettings.getControl("JoystickAxis2")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); @@ -706,6 +719,8 @@ void settings_setup_listeners() gSavedSettings.getControl("UpdaterServiceSetting")->getSignal()->connect(boost::bind(&toggle_updater_service_active, _2)); gSavedSettings.getControl("ForceShowGrid")->getSignal()->connect(boost::bind(&handleForceShowGrid, _2)); gSavedSettings.getControl("RenderTransparentWater")->getSignal()->connect(boost::bind(&handleRenderTransparentWaterChanged, _2)); + gSavedSettings.getControl("SpellCheck")->getSignal()->connect(boost::bind(&handleSpellCheckChanged)); + gSavedSettings.getControl("SpellCheckDictionary")->getSignal()->connect(boost::bind(&handleSpellCheckChanged)); } #if TEST_CACHED_CONTROL diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 0adb187dd2..4571d08050 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -383,15 +383,24 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) const std::string& message = gAgent.getTeleportMessage(); switch( gAgent.getTeleportState() ) { + case LLAgent::TELEPORT_PENDING: + gTeleportDisplayTimer.reset(); + gViewerWindow->setShowProgress(TRUE); + gViewerWindow->setProgressPercent(llmin(teleport_percent, 0.0f)); + gAgent.setTeleportMessage(LLAgent::sTeleportProgressMessages["pending"]); + gViewerWindow->setProgressString(LLAgent::sTeleportProgressMessages["pending"]); + break; + case LLAgent::TELEPORT_START: // Transition to REQUESTED. Viewer has sent some kind // of TeleportRequest to the source simulator gTeleportDisplayTimer.reset(); gViewerWindow->setShowProgress(TRUE); - gViewerWindow->setProgressPercent(0); + gViewerWindow->setProgressPercent(llmin(teleport_percent, 0.0f)); gAgent.setTeleportState( LLAgent::TELEPORT_REQUESTED ); gAgent.setTeleportMessage( LLAgent::sTeleportProgressMessages["requesting"]); + gViewerWindow->setProgressString(LLAgent::sTeleportProgressMessages["requesting"]); break; case LLAgent::TELEPORT_REQUESTED: @@ -622,11 +631,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) LLSpatialGroup::sNoDelete = TRUE; LLTexUnit::sWhiteTexture = LLViewerFetchedTexture::sWhiteImagep->getTexName(); - /*if (LLPipeline::sUseOcclusion && LLPipeline::sRenderDeferred) - { //force occlusion on for all render types if doing deferred render (tighter shadow frustum) - LLPipeline::sUseOcclusion = 3; - }*/ - S32 occlusion = LLPipeline::sUseOcclusion; if (gDepthDirty) { //depth buffer is invalid, don't overwrite occlusion state @@ -755,12 +759,12 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) gTextureList.updateImages(max_image_decode_time); } - { + /*{ LLFastTimer t(FTM_IMAGE_UPDATE_DELETE); //remove dead textures from GL LLImageGL::deleteDeadTextures(); stop_glerror(); - } + }*/ } LLGLState::checkStates(); @@ -889,6 +893,28 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) { LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; LLMemType mt_rg(LLMemType::MTYPE_DISPLAY_RENDER_GEOM); + + if (gSavedSettings.getBOOL("RenderDepthPrePass") && LLGLSLShader::sNoFixedFunction) + { + gGL.setColorMask(false, false); + + U32 types[] = { + LLRenderPass::PASS_SIMPLE, + LLRenderPass::PASS_FULLBRIGHT, + LLRenderPass::PASS_SHINY + }; + + U32 num_types = LL_ARRAY_SIZE(types); + gOcclusionProgram.bind(); + for (U32 i = 0; i < num_types; i++) + { + gPipeline.renderObjects(types[i], LLVertexBuffer::MAP_VERTEX, FALSE); + } + + gOcclusionProgram.unbind(); + } + + gGL.setColorMask(true, false); if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender) { diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index d0e0d0d826..96303151f4 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -30,7 +30,7 @@ #include "llfloaterreg.h" #include "llviewerfloaterreg.h" - +#include "llfloaterautoreplacesettings.h" #include "llcompilequeue.h" #include "llcallfloater.h" #include "llfasttimerview.h" @@ -78,7 +78,6 @@ #include "llfloaterlandholdings.h" #include "llfloatermap.h" #include "llfloatermemleak.h" -#include "llfloatermodelwizard.h" #include "llfloaternamedesc.h" #include "llfloaternotificationsconsole.h" #include "llfloaterobjectweights.h" @@ -100,6 +99,7 @@ #include "llfloatersidepanelcontainer.h" #include "llfloatersnapshot.h" #include "llfloatersounddevices.h" +#include "llfloaterspellchecksettings.h" #include "llfloatertelehub.h" #include "llfloatertestinspectors.h" #include "llfloatertestlistview.h" @@ -254,7 +254,10 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("preferences", "floater_preferences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreference>); LLFloaterReg::add("prefs_proxy", "floater_preferences_proxy.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreferenceProxy>); LLFloaterReg::add("prefs_hardware_settings", "floater_hardware_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHardwareSettings>); + LLFloaterReg::add("prefs_spellchecker_import", "floater_spellcheck_import.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSpellCheckerImport>); LLFloaterReg::add("prefs_translation", "floater_translation_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTranslationSettings>); + LLFloaterReg::add("prefs_spellchecker", "floater_spellcheck.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSpellCheckerSettings>); + LLFloaterReg::add("prefs_autoreplace", "floater_autoreplace.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAutoReplaceSettings>); LLFloaterReg::add("perm_prefs", "floater_perm_prefs.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPerms>); LLFloaterReg::add("picks", "floater_picks.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSidePanelContainer>); LLFloaterReg::add("pref_joystick", "floater_joystick.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterJoystick>); @@ -304,7 +307,6 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("upload_anim_anim", "floater_animation_anim_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAnimPreview>, "upload"); LLFloaterReg::add("upload_image", "floater_image_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterImagePreview>, "upload"); LLFloaterReg::add("upload_model", "floater_model_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterModelPreview>, "upload"); - LLFloaterReg::add("upload_model_wizard", "floater_model_wizard.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterModelWizard>); LLFloaterReg::add("upload_script", "floater_script_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterScriptPreview>, "upload"); LLFloaterReg::add("upload_sound", "floater_sound_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSoundPreview>, "upload"); diff --git a/indra/newview/llviewerjointattachment.cpp b/indra/newview/llviewerjointattachment.cpp index 4e14824e69..3a04bbed4f 100644 --- a/indra/newview/llviewerjointattachment.cpp +++ b/indra/newview/llviewerjointattachment.cpp @@ -127,7 +127,11 @@ void LLViewerJointAttachment::setupDrawable(LLViewerObject *object) { for (S32 face_num = 0; face_num < object->mDrawable->getNumFaces(); face_num++) { - object->mDrawable->getFace(face_num)->setState(LLFace::HUD_RENDER); + LLFace *face = object->mDrawable->getFace(face_num); + if (face) + { + face->setState(LLFace::HUD_RENDER); + } } } @@ -146,7 +150,11 @@ void LLViewerJointAttachment::setupDrawable(LLViewerObject *object) { for (S32 face_num = 0; face_num < childp->mDrawable->getNumFaces(); face_num++) { - childp->mDrawable->getFace(face_num)->setState(LLFace::HUD_RENDER); + LLFace * face = childp->mDrawable->getFace(face_num); + if (face) + { + face->setState(LLFace::HUD_RENDER); + } } } } @@ -254,7 +262,11 @@ void LLViewerJointAttachment::removeObject(LLViewerObject *object) { for (S32 face_num = 0; face_num < object->mDrawable->getNumFaces(); face_num++) { - object->mDrawable->getFace(face_num)->clearState(LLFace::HUD_RENDER); + LLFace * face = object->mDrawable->getFace(face_num); + if (face) + { + face->clearState(LLFace::HUD_RENDER); + } } } } @@ -272,7 +284,11 @@ void LLViewerJointAttachment::removeObject(LLViewerObject *object) { for (S32 face_num = 0; face_num < childp->mDrawable->getNumFaces(); face_num++) { - childp->mDrawable->getFace(face_num)->clearState(LLFace::HUD_RENDER); + LLFace * face = childp->mDrawable->getFace(face_num); + if (face) + { + face->clearState(LLFace::HUD_RENDER); + } } } } diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 34e916fec0..97ddfb48d2 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -86,6 +86,7 @@ #include "llrootview.h" #include "llsceneview.h" #include "llselectmgr.h" +#include "llspellcheckmenuhandler.h" #include "llstatusbar.h" #include "lltextureview.h" #include "lltoolcomp.h" @@ -300,7 +301,6 @@ BOOL enable_buy_land(void*); void handle_test_male(void *); void handle_test_female(void *); -void handle_toggle_pg(void*); void handle_dump_attachments(void *); void handle_dump_avatar_local_textures(void*); void handle_debug_avatar_textures(void*); @@ -1643,23 +1643,6 @@ class LLAdvancedTestFemale : public view_listener_t } }; - - -/////////////// -// TOGGLE PG // -/////////////// - - -class LLAdvancedTogglePG : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - handle_toggle_pg(NULL); - return true; - } -}; - - class LLAdvancedForceParamsToDefault : public view_listener_t { bool handleEvent(const LLSD& userdata) @@ -2039,7 +2022,6 @@ class LLAdvancedCompressImage : public view_listener_t }; - ///////////////////////// // SHOW DEBUG SETTINGS // ///////////////////////// @@ -5122,6 +5104,78 @@ class LLEditDelete : public view_listener_t } }; +void handle_spellcheck_replace_with_suggestion(const LLUICtrl* ctrl, const LLSD& param) +{ + const LLContextMenu* menu = dynamic_cast<const LLContextMenu*>(ctrl->getParent()); + LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast<LLSpellCheckMenuHandler*>(menu->getSpawningView()) : NULL; + if ( (!spellcheck_handler) || (!spellcheck_handler->getSpellCheck()) ) + { + return; + } + + U32 index = 0; + if ( (!LLStringUtil::convertToU32(param.asString(), index)) || (index >= spellcheck_handler->getSuggestionCount()) ) + { + return; + } + + spellcheck_handler->replaceWithSuggestion(index); +} + +bool visible_spellcheck_suggestion(LLUICtrl* ctrl, const LLSD& param) +{ + LLMenuItemGL* item = dynamic_cast<LLMenuItemGL*>(ctrl); + const LLContextMenu* menu = (item) ? dynamic_cast<const LLContextMenu*>(item->getParent()) : NULL; + const LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast<const LLSpellCheckMenuHandler*>(menu->getSpawningView()) : NULL; + if ( (!spellcheck_handler) || (!spellcheck_handler->getSpellCheck()) ) + { + return false; + } + + U32 index = 0; + if ( (!LLStringUtil::convertToU32(param.asString(), index)) || (index >= spellcheck_handler->getSuggestionCount()) ) + { + return false; + } + + item->setLabel(spellcheck_handler->getSuggestion(index)); + return true; +} + +void handle_spellcheck_add_to_dictionary(const LLUICtrl* ctrl) +{ + const LLContextMenu* menu = dynamic_cast<const LLContextMenu*>(ctrl->getParent()); + LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast<LLSpellCheckMenuHandler*>(menu->getSpawningView()) : NULL; + if ( (spellcheck_handler) && (spellcheck_handler->canAddToDictionary()) ) + { + spellcheck_handler->addToDictionary(); + } +} + +bool enable_spellcheck_add_to_dictionary(const LLUICtrl* ctrl) +{ + const LLContextMenu* menu = dynamic_cast<const LLContextMenu*>(ctrl->getParent()); + const LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast<const LLSpellCheckMenuHandler*>(menu->getSpawningView()) : NULL; + return (spellcheck_handler) && (spellcheck_handler->canAddToDictionary()); +} + +void handle_spellcheck_add_to_ignore(const LLUICtrl* ctrl) +{ + const LLContextMenu* menu = dynamic_cast<const LLContextMenu*>(ctrl->getParent()); + LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast<LLSpellCheckMenuHandler*>(menu->getSpawningView()) : NULL; + if ( (spellcheck_handler) && (spellcheck_handler->canAddToIgnore()) ) + { + spellcheck_handler->addToIgnore(); + } +} + +bool enable_spellcheck_add_to_ignore(const LLUICtrl* ctrl) +{ + const LLContextMenu* menu = dynamic_cast<const LLContextMenu*>(ctrl->getParent()); + const LLSpellCheckMenuHandler* spellcheck_handler = (menu) ? dynamic_cast<const LLSpellCheckMenuHandler*>(menu->getSpawningView()) : NULL; + return (spellcheck_handler) && (spellcheck_handler->canAddToIgnore()); +} + bool enable_object_delete() { bool new_value = @@ -5367,6 +5421,14 @@ void toggle_debug_menus(void*) // } // +class LLCommunicateBlockList : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LLFloaterSidePanelContainer::showPanel("people", "panel_block_list_sidetray", LLSD()); + return true; + } +}; class LLWorldSetHomeLocation : public view_listener_t { @@ -6738,15 +6800,6 @@ void handle_test_female(void*) //gGestureList.requestResetFromServer( FALSE ); } -void handle_toggle_pg(void*) -{ - gAgent.setTeen( !gAgent.isTeen() ); - - LLFloaterWorldMap::reloadIcons(NULL); - - llinfos << "PG status set to " << (S32)gAgent.isTeen() << llendl; -} - void handle_dump_attachments(void*) { if(!isAgentAvatarValid()) return; @@ -8072,6 +8125,19 @@ void initialize_edit_menu() } +void initialize_spellcheck_menu() +{ + LLUICtrl::CommitCallbackRegistry::Registrar& commit = LLUICtrl::CommitCallbackRegistry::currentRegistrar(); + LLUICtrl::EnableCallbackRegistry::Registrar& enable = LLUICtrl::EnableCallbackRegistry::currentRegistrar(); + + commit.add("SpellCheck.ReplaceWithSuggestion", boost::bind(&handle_spellcheck_replace_with_suggestion, _1, _2)); + enable.add("SpellCheck.VisibleSuggestion", boost::bind(&visible_spellcheck_suggestion, _1, _2)); + commit.add("SpellCheck.AddToDictionary", boost::bind(&handle_spellcheck_add_to_dictionary, _1)); + enable.add("SpellCheck.EnableAddToDictionary", boost::bind(&enable_spellcheck_add_to_dictionary, _1)); + commit.add("SpellCheck.AddToIgnore", boost::bind(&handle_spellcheck_add_to_ignore, _1)); + enable.add("SpellCheck.EnableAddToIgnore", boost::bind(&enable_spellcheck_add_to_ignore, _1)); +} + void initialize_menus() { // A parameterized event handler used as ctrl-8/9/0 zoom controls below. @@ -8152,6 +8218,9 @@ void initialize_menus() // Me > Movement view_listener_t::addMenu(new LLAdvancedAgentFlyingInfo(), "Agent.getFlying"); + + // Communicate + view_listener_t::addMenu(new LLCommunicateBlockList(), "Communicate.BlockList"); // World menu view_listener_t::addMenu(new LLWorldAlwaysRun(), "World.AlwaysRun"); @@ -8311,7 +8380,6 @@ void initialize_menus() view_listener_t::addMenu(new LLAdvancedTestMale(), "Advanced.TestMale"); view_listener_t::addMenu(new LLAdvancedTestFemale(), "Advanced.TestFemale"); - view_listener_t::addMenu(new LLAdvancedTogglePG(), "Advanced.TogglePG"); // Advanced > Character (toplevel) view_listener_t::addMenu(new LLAdvancedForceParamsToDefault(), "Advanced.ForceParamsToDefault"); diff --git a/indra/newview/llviewermenu.h b/indra/newview/llviewermenu.h index 87cb4efbc4..8c40762865 100644 --- a/indra/newview/llviewermenu.h +++ b/indra/newview/llviewermenu.h @@ -39,6 +39,7 @@ class LLObjectSelection; class LLSelectNode; void initialize_edit_menu(); +void initialize_spellcheck_menu(); void init_menus(); void cleanup_menus(); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index a9bff67f40..0baf119d70 100755 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -42,6 +42,7 @@ #include "llinventorydefines.h" #include "lllslconstants.h" #include "llregionhandle.h" +#include "llsd.h" #include "llsdserialize.h" #include "llteleportflags.h" #include "lltransactionflags.h" @@ -107,6 +108,7 @@ #include "llagentui.h" #include "llpanelblockedlist.h" #include "llpanelplaceprofile.h" +#include "llviewerregion.h" #include <boost/algorithm/string/split.hpp> // #include <boost/regex.hpp> @@ -1992,6 +1994,46 @@ bool lure_callback(const LLSD& notification, const LLSD& response) } static LLNotificationFunctorRegistration lure_callback_reg("TeleportOffered", lure_callback); +bool mature_lure_callback(const LLSD& notification, const LLSD& response) +{ + S32 option = 0; + if (response.isInteger()) + { + option = response.asInteger(); + } + else + { + option = LLNotificationsUtil::getSelectedOption(notification, response); + } + + LLUUID from_id = notification["payload"]["from_id"].asUUID(); + LLUUID lure_id = notification["payload"]["lure_id"].asUUID(); + BOOL godlike = notification["payload"]["godlike"].asBoolean(); + U8 region_access = static_cast<U8>(notification["payload"]["region_maturity"].asInteger()); + + switch(option) + { + case 0: + { + // accept + gSavedSettings.setU32("PreferredMaturity", static_cast<U32>(region_access)); + gAgent.setMaturityRatingChangeDuringTeleport(region_access); + gAgent.teleportViaLure(lure_id, godlike); + } + break; + case 1: + default: + // decline + send_simple_im(from_id, + LLStringUtil::null, + IM_LURE_DECLINED, + lure_id); + break; + } + return false; +} +static LLNotificationFunctorRegistration mature_lure_callback_reg("TeleportOffered_MaturityExceeded", mature_lure_callback); + bool goto_url_callback(const LLSD& notification, const LLSD& response) { std::string url = notification["payload"]["url"].asString(); @@ -2770,7 +2812,11 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) chat.mSourceType = CHAT_SOURCE_OBJECT; - if(SYSTEM_FROM == name) + // To conclude that the source type of message is CHAT_SOURCE_SYSTEM it's not + // enough to check only from name (i.e. fromName = "Second Life"). For example + // source type of messages from objects called "Second Life" should not be CHAT_SOURCE_SYSTEM. + bool chat_from_system = (SYSTEM_FROM == name) && region_id.isNull() && position.isNull(); + if(chat_from_system) { // System's UUID is NULL (fixes EXT-4766) chat.mFromID = LLUUID::null; @@ -2795,7 +2841,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) // Note: lie to Nearby Chat, pretending that this is NOT an IM, because // IMs from obejcts don't open IM sessions. LLNearbyChat* nearby_chat = LLNearbyChat::getInstance(); - if(SYSTEM_FROM != name && nearby_chat) + if(!chat_from_system && nearby_chat) { chat.mOwnerID = from_id; LLSD args; @@ -2814,7 +2860,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) //Object IMs send with from name: 'Second Life' need to be displayed also in notification toasts (EXT-1590) - if (SYSTEM_FROM != name) break; + if (!chat_from_system) break; LLSD substitutions; substitutions["NAME"] = name; @@ -2879,15 +2925,54 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) { LLVector3 pos, look_at; U64 region_handle(0); - U8 region_access(0); + U8 region_access(SIM_ACCESS_MIN); std::string region_info = ll_safe_string((char*)binary_bucket, binary_bucket_size); std::string region_access_str = LLStringUtil::null; std::string region_access_icn = LLStringUtil::null; + std::string region_access_lc = LLStringUtil::null; + + bool canUserAccessDstRegion = true; + bool doesUserRequireMaturityIncrease = false; if (parse_lure_bucket(region_info, region_handle, pos, look_at, region_access)) { region_access_str = LLViewerRegion::accessToString(region_access); region_access_icn = LLViewerRegion::getAccessIcon(region_access); + region_access_lc = region_access_str; + LLStringUtil::toLower(region_access_lc); + + if (!gAgent.isGodlike()) + { + switch (region_access) + { + case SIM_ACCESS_MIN : + case SIM_ACCESS_PG : + break; + case SIM_ACCESS_MATURE : + if (gAgent.isTeen()) + { + canUserAccessDstRegion = false; + } + else if (gAgent.prefersPG()) + { + doesUserRequireMaturityIncrease = true; + } + break; + case SIM_ACCESS_ADULT : + if (!gAgent.isAdult()) + { + canUserAccessDstRegion = false; + } + else if (!gAgent.prefersAdult()) + { + doesUserRequireMaturityIncrease = true; + } + break; + default : + llassert(0); + break; + } + } } LLSD args; @@ -2896,28 +2981,130 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) args["MESSAGE"] = message; args["MATURITY_STR"] = region_access_str; args["MATURITY_ICON"] = region_access_icn; + args["REGION_CONTENT_MATURITY"] = region_access_lc; LLSD payload; payload["from_id"] = from_id; payload["lure_id"] = session_id; payload["godlike"] = FALSE; + payload["region_maturity"] = region_access; + + if (!canUserAccessDstRegion) + { + LLNotification::Params params("TeleportOffered_MaturityBlocked"); + params.substitutions = args; + params.payload = payload; + LLPostponedNotification::add<LLPostponedOfferNotification>( params, from_id, false); + send_simple_im(from_id, LLTrans::getString("TeleportMaturityExceeded"), IM_NOTHING_SPECIAL, session_id); + send_simple_im(from_id, LLStringUtil::null, IM_LURE_DECLINED, session_id); + } + else if (doesUserRequireMaturityIncrease) + { + LLNotification::Params params("TeleportOffered_MaturityExceeded"); + params.substitutions = args; + params.payload = payload; + LLPostponedNotification::add<LLPostponedOfferNotification>( params, from_id, false); + } + else + { + LLNotification::Params params("TeleportOffered"); + params.substitutions = args; + params.payload = payload; + LLPostponedNotification::add<LLPostponedOfferNotification>( params, from_id, false); + } - LLNotification::Params params("TeleportOffered"); - params.substitutions = args; - params.payload = payload; - LLPostponedNotification::add<LLPostponedOfferNotification>( params, from_id, false); } } break; case IM_GODLIKE_LURE_USER: { + LLVector3 pos, look_at; + U64 region_handle(0); + U8 region_access(SIM_ACCESS_MIN); + std::string region_info = ll_safe_string((char*)binary_bucket, binary_bucket_size); + std::string region_access_str = LLStringUtil::null; + std::string region_access_icn = LLStringUtil::null; + std::string region_access_lc = LLStringUtil::null; + + bool canUserAccessDstRegion = true; + bool doesUserRequireMaturityIncrease = false; + + if (parse_lure_bucket(region_info, region_handle, pos, look_at, region_access)) + { + region_access_str = LLViewerRegion::accessToString(region_access); + region_access_icn = LLViewerRegion::getAccessIcon(region_access); + region_access_lc = region_access_str; + LLStringUtil::toLower(region_access_lc); + + if (!gAgent.isGodlike()) + { + switch (region_access) + { + case SIM_ACCESS_MIN : + case SIM_ACCESS_PG : + break; + case SIM_ACCESS_MATURE : + if (gAgent.isTeen()) + { + canUserAccessDstRegion = false; + } + else if (gAgent.prefersPG()) + { + doesUserRequireMaturityIncrease = true; + } + break; + case SIM_ACCESS_ADULT : + if (!gAgent.isAdult()) + { + canUserAccessDstRegion = false; + } + else if (!gAgent.prefersAdult()) + { + doesUserRequireMaturityIncrease = true; + } + break; + default : + llassert(0); + break; + } + } + } + + LLSD args; + // *TODO: Translate -> [FIRST] [LAST] (maybe) + args["NAME_SLURL"] = LLSLURL("agent", from_id, "about").getSLURLString(); + args["MESSAGE"] = message; + args["MATURITY_STR"] = region_access_str; + args["MATURITY_ICON"] = region_access_icn; + args["REGION_CONTENT_MATURITY"] = region_access_lc; LLSD payload; payload["from_id"] = from_id; payload["lure_id"] = session_id; payload["godlike"] = TRUE; - // do not show a message box, because you're about to be - // teleported. - LLNotifications::instance().forceResponse(LLNotification::Params("TeleportOffered").payload(payload), 0); + payload["region_maturity"] = region_access; + + if (!canUserAccessDstRegion) + { + LLNotification::Params params("TeleportOffered_MaturityBlocked"); + params.substitutions = args; + params.payload = payload; + LLPostponedNotification::add<LLPostponedOfferNotification>( params, from_id, false); + send_simple_im(from_id, LLTrans::getString("TeleportMaturityExceeded"), IM_NOTHING_SPECIAL, session_id); + send_simple_im(from_id, LLStringUtil::null, IM_LURE_DECLINED, session_id); + } + else if (doesUserRequireMaturityIncrease) + { + LLNotification::Params params("TeleportOffered_MaturityExceeded"); + params.substitutions = args; + params.payload = payload; + LLPostponedNotification::add<LLPostponedOfferNotification>( params, from_id, false); + } + else + { + // do not show a message box, because you're about to be + // teleported. + LLNotifications::instance().forceResponse(LLNotification::Params("TeleportOffered").payload(payload), 0); + } } break; @@ -3441,6 +3628,9 @@ void process_teleport_start(LLMessageSystem *msg, void**) LL_DEBUGS("Messaging") << "Got TeleportStart with TeleportFlags=" << teleport_flags << ". gTeleportDisplay: " << gTeleportDisplay << ", gAgent.mTeleportState: " << gAgent.getTeleportState() << LL_ENDL; + // *NOTE: The server sends two StartTeleport packets when you are teleporting to a LM + LLViewerMessage::getInstance()->mTeleportStartedSignal(); + if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL) { gViewerWindow->setProgressCancelButtonVisible(FALSE); @@ -3460,11 +3650,17 @@ void process_teleport_start(LLMessageSystem *msg, void**) make_ui_sound("UISndTeleportOut"); LL_INFOS("Messaging") << "Teleport initiated by remote TeleportStart message with TeleportFlags: " << teleport_flags << LL_ENDL; + // Don't call LLFirstUse::useTeleport here because this could be // due to being killed, which would send you home, not to a Telehub } } +boost::signals2::connection LLViewerMessage::setTeleportStartedCallback(teleport_started_callback_t cb) +{ + return mTeleportStartedSignal.connect(cb); +} + void process_teleport_progress(LLMessageSystem* msg, void**) { LLUUID agent_id; @@ -4064,6 +4260,8 @@ void send_agent_update(BOOL force_send, BOOL send_reliable) head_rot_chg = dot(last_head_rot, head_rotation); + //static S32 msg_number = 0; // Used for diagnostic log messages + if (force_send || (cam_center_chg.magVec() > TRANSLATE_THRESHOLD) || (head_rot_chg < THRESHOLD_HEAD_ROT_QDOT) || @@ -4072,19 +4270,20 @@ void send_agent_update(BOOL force_send, BOOL send_reliable) control_flag_change != 0 || flag_change != 0) { -/* + /* Diagnotics to show why we send the AgentUpdate message. Also un-commment the msg_number code above and below this block + msg_number += 1; if (head_rot_chg < THRESHOLD_HEAD_ROT_QDOT) { - //LL_INFOS("Messaging") << "head rot " << head_rotation << LL_ENDL; - LL_INFOS("Messaging") << "head_rot_chg = " << head_rot_chg << LL_ENDL; + //LL_INFOS("Messaging") << " head rot " << head_rotation << LL_ENDL; + LL_INFOS("Messaging") << "msg " << msg_number << ", frame " << LLFrameTimer::getFrameCount() << ", head_rot_chg " << head_rot_chg << LL_ENDL; } if (cam_rot_chg.magVec() > ROTATION_THRESHOLD) { - LL_INFOS("Messaging") << "cam rot " << cam_rot_chg.magVec() << LL_ENDL; + LL_INFOS("Messaging") << "msg " << msg_number << ", frame " << LLFrameTimer::getFrameCount() << ", cam rot " << cam_rot_chg.magVec() << LL_ENDL; } if (cam_center_chg.magVec() > TRANSLATE_THRESHOLD) { - LL_INFOS("Messaging") << "cam center " << cam_center_chg.magVec() << LL_ENDL; + LL_INFOS("Messaging") << "msg " << msg_number << ", frame " << LLFrameTimer::getFrameCount() << ", cam center " << cam_center_chg.magVec() << LL_ENDL; } // if (drag_delta_chg.magVec() > TRANSLATE_THRESHOLD) // { @@ -4092,9 +4291,9 @@ void send_agent_update(BOOL force_send, BOOL send_reliable) // } if (control_flag_change) { - LL_INFOS("Messaging") << "dcf = " << control_flag_change << LL_ENDL; + LL_INFOS("Messaging") << "msg " << msg_number << ", frame " << LLFrameTimer::getFrameCount() << ", dcf = " << control_flag_change << LL_ENDL; } -*/ + */ duplicate_count = 0; } @@ -4129,6 +4328,26 @@ void send_agent_update(BOOL force_send, BOOL send_reliable) if (duplicate_count < DUP_MSGS && !gDisconnected) { + /* More diagnostics to count AgentUpdate messages + static S32 update_sec = 0; + static S32 update_count = 0; + static S32 max_update_count = 0; + S32 cur_sec = lltrunc( LLTimer::getTotalSeconds() ); + update_count += 1; + if (cur_sec != update_sec) + { + if (update_sec != 0) + { + update_sec = cur_sec; + //msg_number = 0; + max_update_count = llmax(max_update_count, update_count); + llinfos << "Sent " << update_count << " AgentUpdate messages per second, max is " << max_update_count << llendl; + } + update_sec = cur_sec; + update_count = 0; + } + */ + LLFastTimer t(FTM_AGENT_UPDATE_SEND); // Build the message msg->newMessageFast(_PREHASH_AgentUpdate); @@ -4297,8 +4516,6 @@ void process_kill_object(LLMessageSystem *mesgsys, void **user_data) LL_DEBUGS("Messaging") << "Kill message for local " << local_id << LL_ENDL; } - LLSelectMgr::getInstance()->removeObjectFromSelections(id); - // ...don't kill the avatar if (!(id == gAgentID)) { @@ -4321,6 +4538,12 @@ void process_kill_object(LLMessageSystem *mesgsys, void **user_data) gObjectList.mNumUnknownKills++; } } + + // We should remove the object from selection after it is marked dead by gObjectList to make LLToolGrab, + // which is using the object, release the mouse capture correctly when the object dies. + // See LLToolGrab::handleHoverActive() and LLToolGrab::handleHoverNonPhysical(). + LLSelectMgr::getInstance()->removeObjectFromSelections(id); + } } @@ -5389,23 +5612,35 @@ static void process_money_balance_reply_extended(LLMessageSystem* msg) } } - - -bool handle_special_notification_callback(const LLSD& notification, const LLSD& response) +bool handle_prompt_for_maturity_level_change_callback(const LLSD& notification, const LLSD& response) { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); if (0 == option) { // set the preference to the maturity of the region we're calling - int preferredMaturity = notification["payload"]["_region_access"].asInteger(); - gSavedSettings.setU32("PreferredMaturity", preferredMaturity); - gAgent.sendMaturityPreferenceToServer(preferredMaturity); + U8 preferredMaturity = static_cast<U8>(notification["payload"]["_region_access"].asInteger()); + gSavedSettings.setU32("PreferredMaturity", static_cast<U32>(preferredMaturity)); + } + + return false; +} - // notify user that the maturity preference has been changed - LLSD args; - args["RATING"] = LLViewerRegion::accessToString(preferredMaturity); - LLNotificationsUtil::add("PreferredMaturityChanged", args); +bool handle_prompt_for_maturity_level_change_and_reteleport_callback(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + + if (0 == option) + { + // set the preference to the maturity of the region we're calling + U8 preferredMaturity = static_cast<U8>(notification["payload"]["_region_access"].asInteger()); + gSavedSettings.setU32("PreferredMaturity", static_cast<U32>(preferredMaturity)); + gAgent.setMaturityRatingChangeDuringTeleport(preferredMaturity); + gAgent.restartFailedTeleportRequest(); + } + else + { + gAgent.clearTeleportRequest(); } return false; @@ -5414,39 +5649,148 @@ bool handle_special_notification_callback(const LLSD& notification, const LLSD& // some of the server notifications need special handling. This is where we do that. bool handle_special_notification(std::string notificationID, LLSD& llsdBlock) { - int regionAccess = llsdBlock["_region_access"].asInteger(); - llsdBlock["REGIONMATURITY"] = LLViewerRegion::accessToString(regionAccess); + U8 regionAccess = static_cast<U8>(llsdBlock["_region_access"].asInteger()); + std::string regionMaturity = LLViewerRegion::accessToString(regionAccess); + LLStringUtil::toLower(regionMaturity); + llsdBlock["REGIONMATURITY"] = regionMaturity; - // we're going to throw the LLSD in there in case anyone ever wants to use it - LLNotificationsUtil::add(notificationID+"_Notify", llsdBlock); + bool returnValue = false; + LLNotificationPtr maturityLevelNotification; + std::string notifySuffix = "_Notify"; + if (regionAccess == SIM_ACCESS_MATURE) + { + if (gAgent.isTeen()) + { + gAgent.clearTeleportRequest(); + maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock); + returnValue = true; + + notifySuffix = "_NotifyAdultsOnly"; + } + else if (gAgent.prefersPG()) + { + maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + returnValue = true; + } + else if (LLStringUtil::compareStrings(notificationID, "RegionEntryAccessBlocked") == 0) + { + maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock); + returnValue = true; + } + } + else if (regionAccess == SIM_ACCESS_ADULT) + { + if (!gAgent.isAdult()) + { + gAgent.clearTeleportRequest(); + maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock); + returnValue = true; + + notifySuffix = "_NotifyAdultsOnly"; + } + else if (gAgent.prefersPG() || gAgent.prefersMature()) + { + maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + returnValue = true; + } + else if (LLStringUtil::compareStrings(notificationID, "RegionEntryAccessBlocked") == 0) + { + maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock); + returnValue = true; + } + } + + if ((maturityLevelNotification == NULL) || maturityLevelNotification->isIgnored()) + { + // Given a simple notification if no maturityLevelNotification is set or it is ignore + LLNotificationsUtil::add(notificationID + notifySuffix, llsdBlock); + } + + return returnValue; +} + +// some of the server notifications need special handling. This is where we do that. +bool handle_teleport_access_blocked(LLSD& llsdBlock) +{ + std::string notificationID("TeleportEntryAccessBlocked"); + U8 regionAccess = static_cast<U8>(llsdBlock["_region_access"].asInteger()); + std::string regionMaturity = LLViewerRegion::accessToString(regionAccess); + LLStringUtil::toLower(regionMaturity); + llsdBlock["REGIONMATURITY"] = regionMaturity; + bool returnValue = false; + LLNotificationPtr maturityLevelNotification; + std::string notifySuffix = "_Notify"; if (regionAccess == SIM_ACCESS_MATURE) { if (gAgent.isTeen()) { - LLNotificationsUtil::add(notificationID+"_KB", llsdBlock); - return true; + gAgent.clearTeleportRequest(); + maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock); + returnValue = true; + + notifySuffix = "_NotifyAdultsOnly"; } else if (gAgent.prefersPG()) { - LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_special_notification_callback); - return true; + if (gAgent.hasRestartableFailedTeleportRequest()) + { + maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_ChangeAndReTeleport", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_and_reteleport_callback); + returnValue = true; + } + else + { + gAgent.clearTeleportRequest(); + maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + returnValue = true; + } + } + else + { + gAgent.clearTeleportRequest(); + maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + returnValue = true; } } else if (regionAccess == SIM_ACCESS_ADULT) { if (!gAgent.isAdult()) { - LLNotificationsUtil::add(notificationID+"_KB", llsdBlock); - return true; + gAgent.clearTeleportRequest(); + maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock); + returnValue = true; + + notifySuffix = "_NotifyAdultsOnly"; } else if (gAgent.prefersPG() || gAgent.prefersMature()) { - LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_special_notification_callback); - return true; + if (gAgent.hasRestartableFailedTeleportRequest()) + { + maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_ChangeAndReTeleport", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_and_reteleport_callback); + returnValue = true; + } + else + { + gAgent.clearTeleportRequest(); + maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + returnValue = true; + } + } + else + { + gAgent.clearTeleportRequest(); + maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + returnValue = true; } } - return false; + + if ((maturityLevelNotification == NULL) || maturityLevelNotification->isIgnored()) + { + // Given a simple notification if no maturityLevelNotification is set or it is ignore + LLNotificationsUtil::add(notificationID + notifySuffix, llsdBlock); + } + + return returnValue; } bool attempt_standard_notification(LLMessageSystem* msgsystem) @@ -5490,16 +5834,20 @@ bool attempt_standard_notification(LLMessageSystem* msgsystem) RegionEntryAccessBlocked RegionEntryAccessBlocked_Notify + RegionEntryAccessBlocked_NotifyAdultsOnly RegionEntryAccessBlocked_Change - RegionEntryAccessBlocked_KB + RegionEntryAccessBlocked_AdultsOnlyContent + RegionEntryAccessBlocked_ChangeAndReTeleport LandClaimAccessBlocked LandClaimAccessBlocked_Notify + LandClaimAccessBlocked_NotifyAdultsOnly LandClaimAccessBlocked_Change - LandClaimAccessBlocked_KB + LandClaimAccessBlocked_AdultsOnlyContent LandBuyAccessBlocked LandBuyAccessBlocked_Notify + LandBuyAccessBlocked_NotifyAdultsOnly LandBuyAccessBlocked_Change - LandBuyAccessBlocked_KB + LandBuyAccessBlocked_AdultsOnlyContent -----------------------------------------------------------------------*/ if (handle_special_notification(notificationID, llsdBlock)) @@ -5551,6 +5899,30 @@ void process_alert_message(LLMessageSystem *msgsystem, void **user_data) } } +bool handle_not_age_verified_alert(const std::string &pAlertName) +{ + LLNotificationPtr notification = LLNotificationsUtil::add(pAlertName); + if ((notification == NULL) || notification->isIgnored()) + { + LLNotificationsUtil::add(pAlertName + "_Notify"); + } + + return true; +} + +bool handle_special_alerts(const std::string &pAlertName) +{ + bool isHandled = false; + + if (LLStringUtil::compareStrings(pAlertName, "NotAgeVerified") == 0) + { + + isHandled = handle_not_age_verified_alert(pAlertName); + } + + return isHandled; +} + void process_alert_core(const std::string& message, BOOL modal) { // HACK -- handle callbacks for specific alerts. It also is localized in notifications.xml @@ -5574,7 +5946,10 @@ void process_alert_core(const std::string& message, BOOL modal) // Allow the server to spawn a named alert so that server alerts can be // translated out of English. std::string alert_name(message.substr(ALERT_PREFIX.length())); - LLNotificationsUtil::add(alert_name); + if (!handle_special_alerts(alert_name)) + { + LLNotificationsUtil::add(alert_name); + } } else if (message.find(NOTIFY_PREFIX) == 0) { @@ -6160,6 +6535,9 @@ void process_teleport_failed(LLMessageSystem *msg, void**) std::string big_reason; LLSD args; + // Let the interested parties know that teleport failed. + LLViewerParcelMgr::getInstance()->onTeleportFailed(); + // if we have additional alert data if (msg->has(_PREHASH_AlertInfo) && msg->getSizeFast(_PREHASH_AlertInfo, _PREHASH_Message) > 0) { @@ -6189,7 +6567,7 @@ void process_teleport_failed(LLMessageSystem *msg, void**) else { // change notification name in this special case - if (handle_special_notification("RegionEntryAccessBlocked", llsd_block)) + if (handle_teleport_access_blocked(llsd_block)) { if( gAgent.getTeleportState() != LLAgent::TELEPORT_NONE ) { @@ -6218,9 +6596,6 @@ void process_teleport_failed(LLMessageSystem *msg, void**) LLNotificationsUtil::add("CouldNotTeleportReason", args); - // Let the interested parties know that teleport failed. - LLViewerParcelMgr::getInstance()->onTeleportFailed(); - if( gAgent.getTeleportState() != LLAgent::TELEPORT_NONE ) { gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); diff --git a/indra/newview/llviewermessage.h b/indra/newview/llviewermessage.h index 46bfb2dad0..594c22ed9c 100644 --- a/indra/newview/llviewermessage.h +++ b/indra/newview/llviewermessage.h @@ -37,6 +37,9 @@ #include "llnotifications.h" #include "llextendedstatus.h" +#include <boost/function.hpp> +#include <boost/signals2.hpp> + // // Forward declarations // @@ -205,6 +208,15 @@ bool highlight_offered_object(const LLUUID& obj_id); void set_dad_inventory_item(LLInventoryItem* inv_item, const LLUUID& into_folder_uuid); void set_dad_inbox_object(const LLUUID& object_id); +class LLViewerMessage : public LLSingleton<LLViewerMessage> +{ +public: + typedef boost::function<void()> teleport_started_callback_t; + typedef boost::signals2::signal<void()> teleport_started_signal_t; + boost::signals2::connection setTeleportStartedCallback(teleport_started_callback_t cb); + + teleport_started_signal_t mTeleportStartedSignal; +}; class LLOfferInfo : public LLNotificationResponderInterface { @@ -253,5 +265,3 @@ private: void process_feature_disabled_message(LLMessageSystem* msg, void**); #endif - - diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index cd300accb7..72fd3c1a4a 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -432,7 +432,9 @@ void LLViewerObject::dump() const llinfos << "PositionAgent: " << getPositionAgent() << llendl; llinfos << "PositionGlobal: " << getPositionGlobal() << llendl; llinfos << "Velocity: " << getVelocity() << llendl; - if (mDrawable.notNull() && mDrawable->getNumFaces()) + if (mDrawable.notNull() && + mDrawable->getNumFaces() && + mDrawable->getFace(0)) { LLFacePool *poolp = mDrawable->getFace(0)->getPool(); if (poolp) @@ -2389,10 +2391,11 @@ void LLViewerObject::interpolateLinearMotion(const F64 & time, const F32 & dt) { // This will put the object underground, but we can't tell if it will stop // at ground level or not min_height = LLWorld::getInstance()->getMinAllowedZ(this, new_pos_global); + // Cap maximum height + new_pos.mV[VZ] = llmin(LLWorld::getInstance()->getRegionMaxHeight(), new_pos.mV[VZ]); } new_pos.mV[VZ] = llmax(min_height, new_pos.mV[VZ]); - new_pos.mV[VZ] = llmin(LLWorld::getInstance()->getRegionMaxHeight(), new_pos.mV[VZ]); // Check to see if it's going off the region LLVector3 temp(new_pos); @@ -2798,6 +2801,23 @@ void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code, LLExtS (object = gObjectList.findObject(ft->mTaskID))) { object->loadTaskInvFile(ft->mFilename); + + LLInventoryObject::object_list_t::iterator it = object->mInventory->begin(); + LLInventoryObject::object_list_t::iterator end = object->mInventory->end(); + std::list<LLUUID>& pending_lst = object->mPendingInventoryItemsIDs; + + for (; it != end && pending_lst.size(); ++it) + { + LLViewerInventoryItem* item = dynamic_cast<LLViewerInventoryItem*>(it->get()); + if(item && item->getType() != LLAssetType::AT_CATEGORY) + { + std::list<LLUUID>::iterator id_it = std::find(pending_lst.begin(), pending_lst.begin(), item->getAssetUUID()); + if (id_it != pending_lst.end()) + { + pending_lst.erase(id_it); + } + } + } } else { @@ -2910,7 +2930,22 @@ void LLViewerObject::updateInventory( bool is_new) { LLMemType mt(LLMemType::MTYPE_OBJECT); - + + std::list<LLUUID>::iterator begin = mPendingInventoryItemsIDs.begin(); + std::list<LLUUID>::iterator end = mPendingInventoryItemsIDs.end(); + + bool is_fetching = std::find(begin, end, item->getAssetUUID()) != end; + bool is_fetched = getInventoryItemByAsset(item->getAssetUUID()) != NULL; + + if (is_fetched || is_fetching) + { + return; + } + else + { + mPendingInventoryItemsIDs.push_back(item->getAssetUUID()); + } + // This slices the object into what we're concerned about on the // viewer. The simulator will take the permissions and transfer // ownership. @@ -4477,7 +4512,11 @@ U32 LLViewerObject::getNumVertices() const num_faces = mDrawable->getNumFaces(); for (i = 0; i < num_faces; i++) { - num_vertices += mDrawable->getFace(i)->getGeomCount(); + LLFace * facep = mDrawable->getFace(i); + if (facep) + { + num_vertices += facep->getGeomCount(); + } } } return num_vertices; @@ -4492,7 +4531,11 @@ U32 LLViewerObject::getNumIndices() const num_faces = mDrawable->getNumFaces(); for (i = 0; i < num_faces; i++) { - num_indices += mDrawable->getFace(i)->getIndicesCount(); + LLFace * facep = mDrawable->getFace(i); + if (facep) + { + num_indices += facep->getIndicesCount(); + } } } return num_indices; diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index c8152e1539..dc102b666f 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -684,6 +684,10 @@ protected: F32 mAppAngle; // Apparent visual arc in degrees F32 mPixelArea; // Apparent area in pixels + // IDs of of all items in the object's content which are added to the object's content, + // but not updated on the server yet. After item was updated, its ID will be removed from this list. + std::list<LLUUID> mPendingInventoryItemsIDs; + // This is the object's inventory from the viewer's perspective. LLInventoryObject::object_list_t* mInventory; class LLInventoryCallbackInfo diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 54ccfb9aae..beb68c1cbb 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -1721,7 +1721,10 @@ void LLViewerObjectList::generatePickList(LLCamera &camera) LLViewerObject* last_objectp = NULL; for (S32 face_num = 0; face_num < drawablep->getNumFaces(); face_num++) { - LLViewerObject* objectp = drawablep->getFace(face_num)->getViewerObject(); + LLFace * facep = drawablep->getFace(face_num); + if (!facep) continue; + + LLViewerObject* objectp = facep->getViewerObject(); if (objectp && objectp != last_objectp) { diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index 9db784101d..ae9c31bfe7 100644 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -82,7 +82,6 @@ LLPointer<LLViewerTexture> sBlockedImage; LLPointer<LLViewerTexture> sPassImage; // Local functions -void optionally_start_music(const std::string& music_url); void callback_start_music(S32 option, void* data); void optionally_prepare_video(const LLParcel *parcelp); void callback_prepare_video(S32 option, void* data); @@ -1589,7 +1588,7 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use if (instance->mTeleportInProgress) { instance->mTeleportInProgress = FALSE; - instance->mTeleportFinishedSignal(gAgent.getPositionGlobal()); + instance->mTeleportFinishedSignal(gAgent.getPositionGlobal(), false); } } } @@ -1773,13 +1772,13 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use }; } -void optionally_start_music(const std::string& music_url) +void LLViewerParcelMgr::optionally_start_music(const std::string& music_url) { if (gSavedSettings.getBOOL("AudioStreamingMusic")) { // only play music when you enter a new parcel if the UI control for this // was not *explicitly* stopped by the user. (part of SL-4878) - LLPanelNearByMedia* nearby_media_panel = gStatusBar->getNearbyMediaPanel();; + LLPanelNearByMedia* nearby_media_panel = gStatusBar->getNearbyMediaPanel(); if ((nearby_media_panel && nearby_media_panel->getParcelAudioAutoStart()) || // or they have expressed no opinion in the UI, but have autoplay on... @@ -2559,7 +2558,7 @@ void LLViewerParcelMgr::onTeleportFinished(bool local, const LLVector3d& new_pos { // Local teleport. We already have the agent parcel data. // Emit the signal immediately. - getInstance()->mTeleportFinishedSignal(new_pos); + getInstance()->mTeleportFinishedSignal(new_pos, local); } else { diff --git a/indra/newview/llviewerparcelmgr.h b/indra/newview/llviewerparcelmgr.h index cac8d8391c..2a11549426 100644 --- a/indra/newview/llviewerparcelmgr.h +++ b/indra/newview/llviewerparcelmgr.h @@ -78,8 +78,8 @@ class LLViewerParcelMgr : public LLSingleton<LLViewerParcelMgr> { public: - typedef boost::function<void (const LLVector3d&)> teleport_finished_callback_t; - typedef boost::signals2::signal<void (const LLVector3d&)> teleport_finished_signal_t; + typedef boost::function<void (const LLVector3d&, const bool& local)> teleport_finished_callback_t; + typedef boost::signals2::signal<void (const LLVector3d&, const bool&)> teleport_finished_signal_t; typedef boost::function<void()> parcel_changed_callback_t; typedef boost::signals2::signal<void()> parcel_changed_signal_t; @@ -275,6 +275,8 @@ public: // *NOTE: Taken out 2005-03-21. Phoenix. //void makeLandmarkAtSelection(); + static void optionally_start_music(const std::string& music_url); + static void processParcelOverlay(LLMessageSystem *msg, void **user_data); static void processParcelProperties(LLMessageSystem *msg, void **user_data); static void processParcelAccessListReply(LLMessageSystem *msg, void **user); diff --git a/indra/newview/llviewerpartsim.cpp b/indra/newview/llviewerpartsim.cpp index 6b3e04348a..345023dbfa 100644 --- a/indra/newview/llviewerpartsim.cpp +++ b/indra/newview/llviewerpartsim.cpp @@ -476,7 +476,7 @@ void LLViewerPartSim::checkParticleCount(U32 size) LLViewerPartSim::LLViewerPartSim() { LLMemType mt(LLMemType::MTYPE_PARTICLES); - sMaxParticleCount = gSavedSettings.getS32("RenderMaxPartCount"); + sMaxParticleCount = llmin(gSavedSettings.getS32("RenderMaxPartCount"), LL_MAX_PARTICLE_COUNT); static U32 id_seed = 0; mID = ++id_seed; } diff --git a/indra/newview/llviewerpartsim.h b/indra/newview/llviewerpartsim.h index 3e20f999c0..c9959c63ec 100644 --- a/indra/newview/llviewerpartsim.h +++ b/indra/newview/llviewerpartsim.h @@ -39,6 +39,8 @@ class LLViewerRegion; class LLViewerTexture; class LLVOPartGroup; +#define LL_MAX_PARTICLE_COUNT 8192 + typedef void (*LLVPCallback)(LLViewerPart &part, const F32 dt); /////////////////// diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index e3cb985ddb..f3771e93d9 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -655,6 +655,31 @@ std::string LLViewerRegion::accessToShortString(U8 sim_access) } // static +U8 LLViewerRegion::shortStringToAccess(const std::string &sim_access) +{ + U8 accessValue; + + if (LLStringUtil::compareStrings(sim_access, "PG") == 0) + { + accessValue = SIM_ACCESS_PG; + } + else if (LLStringUtil::compareStrings(sim_access, "M") == 0) + { + accessValue = SIM_ACCESS_MATURE; + } + else if (LLStringUtil::compareStrings(sim_access, "A") == 0) + { + accessValue = SIM_ACCESS_ADULT; + } + else + { + accessValue = SIM_ACCESS_MIN; + } + + return accessValue; +} + +// static void LLViewerRegion::processRegionInfo(LLMessageSystem* msg, void**) { // send it to 'observers' diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index c483c6ef52..7280c7f2e6 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -202,6 +202,7 @@ public: // Returns "M", "PG", "A" etc. static std::string accessToShortString(U8 sim_access); + static U8 shortStringToAccess(const std::string &sim_access); // Return access icon name static std::string getAccessIcon(U8 sim_access); diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index 10c61c01d5..a6c564a6a1 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -63,8 +63,16 @@ bool LLViewerShaderMgr::sSkipReload = false; LLVector4 gShinyOrigin; +//transform shaders +LLGLSLShader gTransformPositionProgram; +LLGLSLShader gTransformTexCoordProgram; +LLGLSLShader gTransformNormalProgram; +LLGLSLShader gTransformColorProgram; +LLGLSLShader gTransformBinormalProgram; + //utility shaders LLGLSLShader gOcclusionProgram; +LLGLSLShader gOcclusionCubeProgram; LLGLSLShader gCustomAlphaProgram; LLGLSLShader gGlowCombineProgram; LLGLSLShader gSplatTextureRectProgram; @@ -72,6 +80,7 @@ LLGLSLShader gGlowCombineFXAAProgram; LLGLSLShader gTwoTextureAddProgram; LLGLSLShader gOneTextureNoColorProgram; LLGLSLShader gDebugProgram; +LLGLSLShader gClipProgram; LLGLSLShader gAlphaMaskProgram; //object shaders @@ -178,6 +187,7 @@ LLGLSLShader gDeferredSunProgram; LLGLSLShader gDeferredBlurLightProgram; LLGLSLShader gDeferredSoftenProgram; LLGLSLShader gDeferredShadowProgram; +LLGLSLShader gDeferredShadowCubeProgram; LLGLSLShader gDeferredShadowAlphaMaskProgram; LLGLSLShader gDeferredAvatarShadowProgram; LLGLSLShader gDeferredAttachmentShadowProgram; @@ -437,7 +447,8 @@ void LLViewerShaderMgr::setShaders() S32 wl_class = 2; S32 water_class = 2; S32 deferred_class = 0; - + S32 transform_class = gGLManager.mHasTransformFeedback ? 1 : 0; + if (LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") && gSavedSettings.getBOOL("RenderDeferred") && gSavedSettings.getBOOL("RenderAvatarVP") && @@ -475,6 +486,7 @@ void LLViewerShaderMgr::setShaders() gSky.mVOSkyp->forceSkyUpdate(); } + // Load lighting shaders mVertexShaderLevel[SHADER_LIGHTING] = light_class; mVertexShaderLevel[SHADER_INTERFACE] = light_class; @@ -484,6 +496,7 @@ void LLViewerShaderMgr::setShaders() mVertexShaderLevel[SHADER_EFFECT] = effect_class; mVertexShaderLevel[SHADER_WINDLIGHT] = wl_class; mVertexShaderLevel[SHADER_DEFERRED] = deferred_class; + mVertexShaderLevel[SHADER_TRANSFORM] = transform_class; BOOL loaded = loadBasicShaders(); @@ -493,65 +506,109 @@ void LLViewerShaderMgr::setShaders() gPipeline.mVertexShadersLoaded = 1; // Load all shaders to set max levels - loadShadersEnvironment(); - loadShadersWater(); - loadShadersWindLight(); - loadShadersEffects(); - loadShadersInterface(); + loaded = loadShadersEnvironment(); + + if (loaded) + { + loaded = loadShadersWater(); + } + + if (loaded) + { + loaded = loadShadersWindLight(); + } + + if (loaded) + { + loaded = loadShadersEffects(); + } + + if (loaded) + { + loaded = loadShadersInterface(); + } - // Load max avatar shaders to set the max level - mVertexShaderLevel[SHADER_AVATAR] = 3; - mMaxAvatarShaderLevel = 3; - - if (gSavedSettings.getBOOL("RenderAvatarVP") && loadShadersObject()) - { //hardware skinning is enabled and rigged attachment shaders loaded correctly - BOOL avatar_cloth = gSavedSettings.getBOOL("RenderAvatarCloth"); - S32 avatar_class = 1; - - // cloth is a class3 shader - if(avatar_cloth) - { - avatar_class = 3; - } + if (loaded) + { + loaded = loadTransformShaders(); + } - // Set the actual level - mVertexShaderLevel[SHADER_AVATAR] = avatar_class; - loadShadersAvatar(); - if (mVertexShaderLevel[SHADER_AVATAR] != avatar_class) - { - if (mVertexShaderLevel[SHADER_AVATAR] == 0) + if (loaded) + { + // Load max avatar shaders to set the max level + mVertexShaderLevel[SHADER_AVATAR] = 3; + mMaxAvatarShaderLevel = 3; + + if (gSavedSettings.getBOOL("RenderAvatarVP") && loadShadersObject()) + { //hardware skinning is enabled and rigged attachment shaders loaded correctly + BOOL avatar_cloth = gSavedSettings.getBOOL("RenderAvatarCloth"); + S32 avatar_class = 1; + + // cloth is a class3 shader + if(avatar_cloth) { - gSavedSettings.setBOOL("RenderAvatarVP", FALSE); + avatar_class = 3; } - if(llmax(mVertexShaderLevel[SHADER_AVATAR]-1,0) >= 3) + + // Set the actual level + mVertexShaderLevel[SHADER_AVATAR] = avatar_class; + loadShadersAvatar(); + if (mVertexShaderLevel[SHADER_AVATAR] != avatar_class) { - avatar_cloth = true; + if (mVertexShaderLevel[SHADER_AVATAR] == 0) + { + gSavedSettings.setBOOL("RenderAvatarVP", FALSE); + } + if(llmax(mVertexShaderLevel[SHADER_AVATAR]-1,0) >= 3) + { + avatar_cloth = true; + } + else + { + avatar_cloth = false; + } + gSavedSettings.setBOOL("RenderAvatarCloth", avatar_cloth); } - else + } + else + { //hardware skinning not possible, neither is deferred rendering + mVertexShaderLevel[SHADER_AVATAR] = 0; + mVertexShaderLevel[SHADER_DEFERRED] = 0; + + if (gSavedSettings.getBOOL("RenderAvatarVP")) { - avatar_cloth = false; + gSavedSettings.setBOOL("RenderDeferred", FALSE); + gSavedSettings.setBOOL("RenderAvatarCloth", FALSE); + gSavedSettings.setBOOL("RenderAvatarVP", FALSE); } - gSavedSettings.setBOOL("RenderAvatarCloth", avatar_cloth); + + loadShadersAvatar(); // unloads + + loaded = loadShadersObject(); } } - else - { //hardware skinning not possible, neither is deferred rendering - mVertexShaderLevel[SHADER_AVATAR] = 0; - mVertexShaderLevel[SHADER_DEFERRED] = 0; - - if (gSavedSettings.getBOOL("RenderAvatarVP")) - { - gSavedSettings.setBOOL("RenderDeferred", FALSE); - gSavedSettings.setBOOL("RenderAvatarCloth", FALSE); - gSavedSettings.setBOOL("RenderAvatarVP", FALSE); + + if (!loaded) + { //some shader absolutely could not load, try to fall back to a simpler setting + if (gSavedSettings.getBOOL("WindLightUseAtmosShaders")) + { //disable windlight and try again + gSavedSettings.setBOOL("WindLightUseAtmosShaders", FALSE); + reentrance = false; + setShaders(); + return; } - loadShadersAvatar(); // unloads - loadShadersObject(); - } + if (gSavedSettings.getBOOL("VertexShaderEnable")) + { //disable shaders outright and try again + gSavedSettings.setBOOL("VertexShaderEnable", FALSE); + reentrance = false; + setShaders(); + return; + } + } - if (!loadShadersDeferred()) - { + if (loaded && !loadShadersDeferred()) + { //everything else succeeded but deferred failed, disable deferred and try again gSavedSettings.setBOOL("RenderDeferred", FALSE); reentrance = false; setShaders(); @@ -600,7 +657,9 @@ void LLViewerShaderMgr::setShaders() void LLViewerShaderMgr::unloadShaders() { gOcclusionProgram.unload(); + gOcclusionCubeProgram.unload(); gDebugProgram.unload(); + gClipProgram.unload(); gAlphaMaskProgram.unload(); gUIProgram.unload(); gCustomAlphaProgram.unload(); @@ -692,6 +751,12 @@ void LLViewerShaderMgr::unloadShaders() gDeferredSkinnedBumpProgram.unload(); gDeferredSkinnedAlphaProgram.unload(); + gTransformPositionProgram.unload(); + gTransformTexCoordProgram.unload(); + gTransformNormalProgram.unload(); + gTransformColorProgram.unload(); + gTransformBinormalProgram.unload(); + mVertexShaderLevel[SHADER_LIGHTING] = 0; mVertexShaderLevel[SHADER_OBJECT] = 0; mVertexShaderLevel[SHADER_AVATAR] = 0; @@ -700,6 +765,7 @@ void LLViewerShaderMgr::unloadShaders() mVertexShaderLevel[SHADER_INTERFACE] = 0; mVertexShaderLevel[SHADER_EFFECT] = 0; mVertexShaderLevel[SHADER_WINDLIGHT] = 0; + mVertexShaderLevel[SHADER_TRANSFORM] = 0; gPipeline.mVertexShadersLoaded = 0; } @@ -828,7 +894,7 @@ BOOL LLViewerShaderMgr::loadShadersEnvironment() if (mVertexShaderLevel[SHADER_ENVIRONMENT] == 0) { gTerrainProgram.unload(); - return FALSE; + return TRUE; } if (success) @@ -868,7 +934,7 @@ BOOL LLViewerShaderMgr::loadShadersWater() gWaterProgram.unload(); gUnderWaterProgram.unload(); gTerrainWaterProgram.unload(); - return FALSE; + return TRUE; } if (success) @@ -953,7 +1019,7 @@ BOOL LLViewerShaderMgr::loadShadersEffects() gGlowExtractProgram.unload(); gPostColorFilterProgram.unload(); gPostNightVisionProgram.unload(); - return FALSE; + return TRUE; } if (success) @@ -1013,6 +1079,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredBlurLightProgram.unload(); gDeferredSoftenProgram.unload(); gDeferredShadowProgram.unload(); + gDeferredShadowCubeProgram.unload(); gDeferredShadowAlphaMaskProgram.unload(); gDeferredAvatarShadowProgram.unload(); gDeferredAttachmentShadowProgram.unload(); @@ -1200,7 +1267,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredSpotLightProgram.mName = "Deferred SpotLight Shader"; gDeferredSpotLightProgram.mShaderFiles.clear(); gDeferredSpotLightProgram.mShaderFiles.push_back(make_pair("deferred/pointLightV.glsl", GL_VERTEX_SHADER_ARB)); - gDeferredSpotLightProgram.mShaderFiles.push_back(make_pair("deferred/multiSpotLightF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredSpotLightProgram.mShaderFiles.push_back(make_pair("deferred/spotLightF.glsl", GL_FRAGMENT_SHADER_ARB)); gDeferredSpotLightProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; success = gDeferredSpotLightProgram.createShader(NULL, NULL); } @@ -1209,7 +1276,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() { gDeferredMultiSpotLightProgram.mName = "Deferred MultiSpotLight Shader"; gDeferredMultiSpotLightProgram.mShaderFiles.clear(); - gDeferredMultiSpotLightProgram.mShaderFiles.push_back(make_pair("deferred/pointLightV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredMultiSpotLightProgram.mShaderFiles.push_back(make_pair("deferred/multiPointLightV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredMultiSpotLightProgram.mShaderFiles.push_back(make_pair("deferred/multiSpotLightF.glsl", GL_FRAGMENT_SHADER_ARB)); gDeferredMultiSpotLightProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; success = gDeferredMultiSpotLightProgram.createShader(NULL, NULL); @@ -1368,6 +1435,16 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() if (success) { + gDeferredShadowCubeProgram.mName = "Deferred Shadow Cube Shader"; + gDeferredShadowCubeProgram.mShaderFiles.clear(); + gDeferredShadowCubeProgram.mShaderFiles.push_back(make_pair("deferred/shadowCubeV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredShadowCubeProgram.mShaderFiles.push_back(make_pair("deferred/shadowF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredShadowCubeProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + success = gDeferredShadowCubeProgram.createShader(NULL, NULL); + } + + if (success) + { gDeferredShadowAlphaMaskProgram.mName = "Deferred Shadow Alpha Mask Shader"; gDeferredShadowAlphaMaskProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels; gDeferredShadowAlphaMaskProgram.mShaderFiles.clear(); @@ -2410,7 +2487,7 @@ BOOL LLViewerShaderMgr::loadShadersAvatar() gAvatarWaterProgram.unload(); gAvatarEyeballProgram.unload(); gAvatarPickProgram.unload(); - return FALSE; + return TRUE; } if (success) @@ -2504,7 +2581,7 @@ BOOL LLViewerShaderMgr::loadShadersInterface() if (mVertexShaderLevel[SHADER_INTERFACE] == 0) { gHighlightProgram.unload(); - return FALSE; + return TRUE; } if (success) @@ -2647,6 +2724,16 @@ BOOL LLViewerShaderMgr::loadShadersInterface() if (success) { + gOcclusionCubeProgram.mName = "Occlusion Cube Shader"; + gOcclusionCubeProgram.mShaderFiles.clear(); + gOcclusionCubeProgram.mShaderFiles.push_back(make_pair("interface/occlusionCubeV.glsl", GL_VERTEX_SHADER_ARB)); + gOcclusionCubeProgram.mShaderFiles.push_back(make_pair("interface/occlusionF.glsl", GL_FRAGMENT_SHADER_ARB)); + gOcclusionCubeProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE]; + success = gOcclusionCubeProgram.createShader(NULL, NULL); + } + + if (success) + { gDebugProgram.mName = "Debug Shader"; gDebugProgram.mShaderFiles.clear(); gDebugProgram.mShaderFiles.push_back(make_pair("interface/debugV.glsl", GL_VERTEX_SHADER_ARB)); @@ -2657,6 +2744,16 @@ BOOL LLViewerShaderMgr::loadShadersInterface() if (success) { + gClipProgram.mName = "Clip Shader"; + gClipProgram.mShaderFiles.clear(); + gClipProgram.mShaderFiles.push_back(make_pair("interface/clipV.glsl", GL_VERTEX_SHADER_ARB)); + gClipProgram.mShaderFiles.push_back(make_pair("interface/clipF.glsl", GL_FRAGMENT_SHADER_ARB)); + gClipProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE]; + success = gClipProgram.createShader(NULL, NULL); + } + + if (success) + { gAlphaMaskProgram.mName = "Alpha Mask Shader"; gAlphaMaskProgram.mShaderFiles.clear(); gAlphaMaskProgram.mShaderFiles.push_back(make_pair("interface/alphamaskV.glsl", GL_VERTEX_SHADER_ARB)); @@ -2682,7 +2779,7 @@ BOOL LLViewerShaderMgr::loadShadersWindLight() { gWLSkyProgram.unload(); gWLCloudProgram.unload(); - return FALSE; + return TRUE; } if (success) @@ -2712,6 +2809,95 @@ BOOL LLViewerShaderMgr::loadShadersWindLight() return success; } +BOOL LLViewerShaderMgr::loadTransformShaders() +{ + BOOL success = TRUE; + + if (mVertexShaderLevel[SHADER_TRANSFORM] < 1) + { + gTransformPositionProgram.unload(); + gTransformTexCoordProgram.unload(); + gTransformNormalProgram.unload(); + gTransformColorProgram.unload(); + gTransformBinormalProgram.unload(); + return TRUE; + } + + if (success) + { + gTransformPositionProgram.mName = "Position Transform Shader"; + gTransformPositionProgram.mShaderFiles.clear(); + gTransformPositionProgram.mShaderFiles.push_back(make_pair("transform/positionV.glsl", GL_VERTEX_SHADER_ARB)); + gTransformPositionProgram.mShaderLevel = mVertexShaderLevel[SHADER_TRANSFORM]; + + const char* varyings[] = { + "position_out", + "texture_index_out", + }; + + success = gTransformPositionProgram.createShader(NULL, NULL, 2, varyings); + } + + if (success) + { + gTransformTexCoordProgram.mName = "TexCoord Transform Shader"; + gTransformTexCoordProgram.mShaderFiles.clear(); + gTransformTexCoordProgram.mShaderFiles.push_back(make_pair("transform/texcoordV.glsl", GL_VERTEX_SHADER_ARB)); + gTransformTexCoordProgram.mShaderLevel = mVertexShaderLevel[SHADER_TRANSFORM]; + + const char* varyings[] = { + "texcoord_out", + }; + + success = gTransformTexCoordProgram.createShader(NULL, NULL, 1, varyings); + } + + if (success) + { + gTransformNormalProgram.mName = "Normal Transform Shader"; + gTransformNormalProgram.mShaderFiles.clear(); + gTransformNormalProgram.mShaderFiles.push_back(make_pair("transform/normalV.glsl", GL_VERTEX_SHADER_ARB)); + gTransformNormalProgram.mShaderLevel = mVertexShaderLevel[SHADER_TRANSFORM]; + + const char* varyings[] = { + "normal_out", + }; + + success = gTransformNormalProgram.createShader(NULL, NULL, 1, varyings); + } + + if (success) + { + gTransformColorProgram.mName = "Color Transform Shader"; + gTransformColorProgram.mShaderFiles.clear(); + gTransformColorProgram.mShaderFiles.push_back(make_pair("transform/colorV.glsl", GL_VERTEX_SHADER_ARB)); + gTransformColorProgram.mShaderLevel = mVertexShaderLevel[SHADER_TRANSFORM]; + + const char* varyings[] = { + "color_out", + }; + + success = gTransformColorProgram.createShader(NULL, NULL, 1, varyings); + } + + if (success) + { + gTransformBinormalProgram.mName = "Binormal Transform Shader"; + gTransformBinormalProgram.mShaderFiles.clear(); + gTransformBinormalProgram.mShaderFiles.push_back(make_pair("transform/binormalV.glsl", GL_VERTEX_SHADER_ARB)); + gTransformBinormalProgram.mShaderLevel = mVertexShaderLevel[SHADER_TRANSFORM]; + + const char* varyings[] = { + "binormal_out", + }; + + success = gTransformBinormalProgram.createShader(NULL, NULL, 1, varyings); + } + + + return success; +} + std::string LLViewerShaderMgr::getShaderDirPrefix(void) { return gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "shaders/class"); diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h index 95eb551bf1..8f7ff8dd2f 100644 --- a/indra/newview/llviewershadermgr.h +++ b/indra/newview/llviewershadermgr.h @@ -54,6 +54,7 @@ public: BOOL loadShadersWater(); BOOL loadShadersInterface(); BOOL loadShadersWindLight(); + BOOL loadTransformShaders(); std::vector<S32> mVertexShaderLevel; S32 mMaxAvatarShaderLevel; @@ -69,6 +70,7 @@ public: SHADER_WINDLIGHT, SHADER_WATER, SHADER_DEFERRED, + SHADER_TRANSFORM, SHADER_COUNT }; @@ -209,13 +211,24 @@ inline bool operator != (LLViewerShaderMgr::shader_iter const & a, LLViewerShade extern LLVector4 gShinyOrigin; +//transform shaders +extern LLGLSLShader gTransformPositionProgram; +extern LLGLSLShader gTransformTexCoordProgram; +extern LLGLSLShader gTransformNormalProgram; +extern LLGLSLShader gTransformColorProgram; +extern LLGLSLShader gTransformBinormalProgram; + + + //utility shaders extern LLGLSLShader gOcclusionProgram; +extern LLGLSLShader gOcclusionCubeProgram; extern LLGLSLShader gCustomAlphaProgram; extern LLGLSLShader gGlowCombineProgram; extern LLGLSLShader gSplatTextureRectProgram; extern LLGLSLShader gGlowCombineFXAAProgram; extern LLGLSLShader gDebugProgram; +extern LLGLSLShader gClipProgram; extern LLGLSLShader gAlphaMaskProgram; //output tex0[tc0] + tex1[tc1] @@ -328,6 +341,7 @@ extern LLGLSLShader gDeferredBlurLightProgram; extern LLGLSLShader gDeferredAvatarProgram; extern LLGLSLShader gDeferredSoftenProgram; extern LLGLSLShader gDeferredShadowProgram; +extern LLGLSLShader gDeferredShadowCubeProgram; extern LLGLSLShader gDeferredShadowAlphaMaskProgram; extern LLGLSLShader gDeferredPostProgram; extern LLGLSLShader gDeferredCoFProgram; diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index 497e95c5e3..28f4ec72f3 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -789,6 +789,24 @@ void send_stats() system["gpu_class"] = (S32)LLFeatureManager::getInstance()->getGPUClass(); system["gpu_vendor"] = gGLManager.mGLVendorShort; system["gpu_version"] = gGLManager.mDriverVersionVendorString; + system["opengl_version"] = gGLManager.mGLVersionString; + + S32 shader_level = 0; + if (LLPipeline::sRenderDeferred) + { + shader_level = 3; + } + else if (gPipeline.canUseWindLightShadersOnObjects()) + { + shader_level = 2; + } + else if (gPipeline.canUseVertexShaders()) + { + shader_level = 1; + } + + + system["shader_level"] = shader_level; LLSD &download = body["downloads"]; diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index d844aeb12a..7f638a24bf 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -1398,10 +1398,10 @@ void LLViewerFetchedTexture::dump() // ONLY called from LLViewerFetchedTextureList void LLViewerFetchedTexture::destroyTexture() { - if(LLImageGL::sGlobalTextureMemoryInBytes < sMaxDesiredTextureMemInBytes)//not ready to release unused memory. - { - return ; - } + //if(LLImageGL::sGlobalTextureMemoryInBytes < sMaxDesiredTextureMemInBytes)//not ready to release unused memory. + //{ + // return ; + //} if (mNeedsCreateTexture)//return if in the process of generating a new texture. { return ; diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 528e0080b7..9a6c0569a9 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -705,7 +705,7 @@ void LLViewerTextureList::updateImagesDecodePriorities() // Flush formatted images using a lazy flush // const F32 LAZY_FLUSH_TIMEOUT = 30.f; // stop decoding - const F32 MAX_INACTIVE_TIME = 50.f; // actually delete + const F32 MAX_INACTIVE_TIME = 20.f; // actually delete S32 min_refs = 3; // 1 for mImageList, 1 for mUUIDMap, 1 for local reference S32 num_refs = imagep->getNumRefs(); diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 39e330ad66..7afb135470 100755 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -175,6 +175,7 @@ #include "llviewershadermgr.h" #include "llviewerstats.h" #include "llvoavatarself.h" +#include "llvopartgroup.h" #include "llvovolume.h" #include "llworld.h" #include "llworldmapview.h" @@ -613,7 +614,7 @@ public: addText(xpos, ypos, llformat("%d/%d Mesh HTTP Requests/Retries", LLMeshRepository::sHTTPRequestCount, LLMeshRepository::sHTTPRetryCount)); ypos += y_inc; - + addText(xpos, ypos, llformat("%d/%d Mesh LOD Pending/Processing", LLMeshRepository::sLODPending, LLMeshRepository::sLODProcessing)); ypos += y_inc; @@ -1704,9 +1705,6 @@ LLViewerWindow::LLViewerWindow(const Params& p) // Can't have spaces in settings.ini strings, so use underscores instead and convert them. LLStringUtil::replaceChar(mOverlayTitle, '_', ' '); - // sync the keyboard's setting with the saved setting - gSavedSettings.getControl("NumpadControl")->firePropertyChanged(); - mDebugText = new LLDebugText(this); mWorldViewRectScaled = calcScaledRect(mWorldViewRectRaw, mDisplayScale); @@ -1973,12 +1971,12 @@ void LLViewerWindow::shutdownViews() gMorphView->setVisible(FALSE); } llinfos << "Global views cleaned." << llendl ; - + // DEV-40930: Clear sModalStack. Otherwise, any LLModalDialog left open // will crump with LL_ERRS. LLModalDialog::shutdownModals(); llinfos << "LLModalDialog shut down." << llendl; - + // destroy the nav bar, not currently part of gViewerWindow // *TODO: Make LLNavigationBar part of gViewerWindow if (LLNavigationBar::instanceExists()) @@ -1986,17 +1984,17 @@ void LLViewerWindow::shutdownViews() delete LLNavigationBar::getInstance(); } llinfos << "LLNavigationBar destroyed." << llendl ; - + // destroy menus after instantiating navbar above, as it needs // access to gMenuHolder cleanup_menus(); llinfos << "menus destroyed." << llendl ; - + // Delete all child views. delete mRootView; mRootView = NULL; llinfos << "RootView deleted." << llendl ; - + // Automatically deleted as children of mRootView. Fix the globals. gStatusBar = NULL; gIMMgr = NULL; @@ -4660,6 +4658,8 @@ void LLViewerWindow::stopGL(BOOL save_state) LLVOAvatar::destroyGL(); stop_glerror(); + LLVOPartGroup::destroyGL(); + LLViewerDynamicTexture::destroyGL(); stop_glerror(); @@ -4713,7 +4713,8 @@ void LLViewerWindow::restoreGL(const std::string& progress_message) gBumpImageList.restoreGL(); LLViewerDynamicTexture::restoreGL(); LLVOAvatar::restoreGL(); - + LLVOPartGroup::restoreGL(); + gResizeScreenTexture = TRUE; gWindowResized = TRUE; @@ -5196,8 +5197,10 @@ void LLPickInfo::getSurfaceInfo() if (objectp->mDrawable.notNull() && mObjectFace > -1) { LLFace* facep = objectp->mDrawable->getFace(mObjectFace); - - mUVCoords = facep->surfaceToTexture(mSTCoords, mIntersection, mNormal); + if (facep) + { + mUVCoords = facep->surfaceToTexture(mSTCoords, mIntersection, mNormal); + } } // and XY coords: diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index ef511a4629..1b7009a5c2 100755 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -961,7 +961,7 @@ void LLVOAvatar::deleteLayerSetCaches(bool clearAll) } if (mBakedTextureDatas[i].mMaskTexName) { - glDeleteTextures(1, (GLuint*)&(mBakedTextureDatas[i].mMaskTexName)); + LLImageGL::deleteTextures(LLTexUnit::TT_TEXTURE, 0, -1, 1, (GLuint*)&(mBakedTextureDatas[i].mMaskTexName)); mBakedTextureDatas[i].mMaskTexName = 0 ; } } @@ -2094,11 +2094,17 @@ void LLVOAvatar::releaseMeshData() if (mDrawable.notNull()) { LLFace* facep = mDrawable->getFace(0); - facep->setSize(0, 0); - for(S32 i = mNumInitFaces ; i < mDrawable->getNumFaces(); i++) + if (facep) { - facep = mDrawable->getFace(i); facep->setSize(0, 0); + for(S32 i = mNumInitFaces ; i < mDrawable->getNumFaces(); i++) + { + facep = mDrawable->getFace(i); + if (facep) + { + facep->setSize(0, 0); + } + } } } @@ -2183,15 +2189,20 @@ void LLVOAvatar::updateMeshData() part_index-- ; } - LLFace* facep ; + LLFace* facep = NULL; if(f_num < mDrawable->getNumFaces()) { facep = mDrawable->getFace(f_num); } else { - facep = mDrawable->addFace(mDrawable->getFace(0)->getPool(), mDrawable->getFace(0)->getTexture()) ; + facep = mDrawable->getFace(0); + if (facep) + { + facep = mDrawable->addFace(facep->getPool(), facep->getTexture()) ; + } } + if (!facep) continue; // resize immediately facep->setSize(num_vertices, num_indices); @@ -4236,10 +4247,14 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass) mNeedsSkin = FALSE; mLastSkinTime = gFrameTimeSeconds; - LLVertexBuffer* vb = mDrawable->getFace(0)->getVertexBuffer(); - if (vb) + LLFace * face = mDrawable->getFace(0); + if (face) { - vb->flush(); + LLVertexBuffer* vb = face->getVertexBuffer(); + if (vb) + { + vb->flush(); + } } } } @@ -7492,7 +7507,7 @@ void LLVOAvatar::onBakedTextureMasksLoaded( BOOL success, LLViewerFetchedTexture } U32 gl_name; - LLImageGL::generateTextures(1, &gl_name ); + LLImageGL::generateTextures(LLTexUnit::TT_TEXTURE, GL_ALPHA8, 1, &gl_name ); stop_glerror(); gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, gl_name); @@ -7529,7 +7544,7 @@ void LLVOAvatar::onBakedTextureMasksLoaded( BOOL success, LLViewerFetchedTexture maskData->mLastDiscardLevel = discard_level; if (self->mBakedTextureDatas[baked_index].mMaskTexName) { - LLImageGL::deleteTextures(1, &(self->mBakedTextureDatas[baked_index].mMaskTexName)); + LLImageGL::deleteTextures(LLTexUnit::TT_TEXTURE, 0, -1, 1, &(self->mBakedTextureDatas[baked_index].mMaskTexName)); } self->mBakedTextureDatas[baked_index].mMaskTexName = gl_name; found_texture_id = true; @@ -8395,7 +8410,7 @@ BOOL LLVOAvatar::updateLOD() BOOL res = updateJointLODs(); LLFace* facep = mDrawable->getFace(0); - if (!facep->getVertexBuffer()) + if (!facep || !facep->getVertexBuffer()) { dirtyMesh(2); } diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index d2609e5587..98f7245f8d 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -2751,7 +2751,7 @@ void LLVOAvatarSelf::deleteScratchTextures() namep; namep = sScratchTexNames.getNextData() ) { - LLImageGL::deleteTextures(1, (U32 *)namep ); + LLImageGL::deleteTextures(LLTexUnit::TT_TEXTURE, 0, -1, 1, (U32 *)namep ); stop_glerror(); } diff --git a/indra/newview/llvograss.cpp b/indra/newview/llvograss.cpp index 8a79d564d3..44968342bf 100644 --- a/indra/newview/llvograss.cpp +++ b/indra/newview/llvograss.cpp @@ -34,6 +34,7 @@ #include "llagentcamera.h" #include "llnotificationsutil.h" #include "lldrawable.h" +#include "lldrawpoolalpha.h" #include "llface.h" #include "llsky.h" #include "llsurface.h" @@ -380,8 +381,10 @@ BOOL LLVOGrass::updateLOD() { mNumBlades <<= 1; } - - face->setSize(mNumBlades*8, mNumBlades*12); + if (face) + { + face->setSize(mNumBlades*8, mNumBlades*12); + } gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE); } else if (num_blades <= (mNumBlades >> 1)) @@ -391,7 +394,10 @@ BOOL LLVOGrass::updateLOD() mNumBlades >>=1; } - face->setSize(mNumBlades*8, mNumBlades*12); + if (face) + { + face->setSize(mNumBlades*8, mNumBlades*12); + } gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE); return TRUE; } @@ -449,14 +455,16 @@ void LLVOGrass::plantBlades() } LLFace *face = mDrawable->getFace(0); + if (face) + { + face->setTexture(getTEImage(0)); + face->setState(LLFace::GLOBAL); + face->setSize(mNumBlades * 8, mNumBlades * 12); + face->setVertexBuffer(NULL); + face->setTEOffset(0); + face->mCenterLocal = mPosition + mRegionp->getOriginAgent(); + } - face->setTexture(getTEImage(0)); - face->setState(LLFace::GLOBAL); - face->setSize(mNumBlades * 8, mNumBlades * 12); - face->setVertexBuffer(NULL); - face->setTEOffset(0); - face->mCenterLocal = mPosition + mRegionp->getOriginAgent(); - mDepth = (face->mCenterLocal - LLViewerCamera::getInstance()->getOrigin())*LLViewerCamera::getInstance()->getAtAxis(); mDrawable->setPosition(face->mCenterLocal); mDrawable->movePartition(); @@ -486,6 +494,8 @@ void LLVOGrass::getGeometry(S32 idx, LLColor4U color(255,255,255,255); LLFace *face = mDrawable->getFace(idx); + if (!face) + return; F32 width = sSpeciesTable[mSpecies]->mBladeSizeX; F32 height = sSpeciesTable[mSpecies]->mBladeSizeY; @@ -594,6 +604,7 @@ U32 LLVOGrass::getPartitionType() const } LLGrassPartition::LLGrassPartition() +: LLSpatialPartition(LLDrawPoolAlpha::VERTEX_DATA_MASK | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, GL_STREAM_DRAW_ARB) { mDrawableType = LLPipeline::RENDER_TYPE_GRASS; mPartitionType = LLViewerRegion::PARTITION_GRASS; @@ -604,6 +615,143 @@ LLGrassPartition::LLGrassPartition() mBufferUsage = GL_DYNAMIC_DRAW_ARB; } +void LLGrassPartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_count, U32& index_count) +{ + group->mBufferUsage = mBufferUsage; + + mFaceList.clear(); + + LLViewerCamera* camera = LLViewerCamera::getInstance(); + for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) + { + LLDrawable* drawablep = *i; + + if (drawablep->isDead()) + { + continue; + } + + LLAlphaObject* obj = (LLAlphaObject*) drawablep->getVObj().get(); + obj->mDepth = 0.f; + + if (drawablep->isAnimating()) + { + group->mBufferUsage = GL_STREAM_DRAW_ARB; + } + + U32 count = 0; + for (S32 j = 0; j < drawablep->getNumFaces(); ++j) + { + drawablep->updateFaceSize(j); + + LLFace* facep = drawablep->getFace(j); + if ( !facep || !facep->hasGeometry()) + { + continue; + } + + if ((facep->getGeomCount() + vertex_count) <= 65536) + { + count++; + facep->mDistance = (facep->mCenterLocal - camera->getOrigin()) * camera->getAtAxis(); + obj->mDepth += facep->mDistance; + + mFaceList.push_back(facep); + vertex_count += facep->getGeomCount(); + index_count += facep->getIndicesCount(); + llassert(facep->getIndicesCount() < 65536); + } + else + { + facep->clearVertexBuffer(); + } + } + + obj->mDepth /= count; + } +} + +static LLFastTimer::DeclareTimer FTM_REBUILD_GRASS_VB("Grass VB"); + +void LLGrassPartition::getGeometry(LLSpatialGroup* group) +{ + LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); + LLFastTimer ftm(FTM_REBUILD_GRASS_VB); + + std::sort(mFaceList.begin(), mFaceList.end(), LLFace::CompareDistanceGreater()); + + U32 index_count = 0; + U32 vertex_count = 0; + + group->clearDrawMap(); + + LLVertexBuffer* buffer = group->mVertexBuffer; + + LLStrider<U16> indicesp; + LLStrider<LLVector4a> verticesp; + LLStrider<LLVector3> normalsp; + LLStrider<LLVector2> texcoordsp; + LLStrider<LLColor4U> colorsp; + + buffer->getVertexStrider(verticesp); + buffer->getNormalStrider(normalsp); + buffer->getColorStrider(colorsp); + buffer->getTexCoord0Strider(texcoordsp); + buffer->getIndexStrider(indicesp); + + LLSpatialGroup::drawmap_elem_t& draw_vec = group->mDrawMap[mRenderPass]; + + for (std::vector<LLFace*>::iterator i = mFaceList.begin(); i != mFaceList.end(); ++i) + { + LLFace* facep = *i; + LLAlphaObject* object = (LLAlphaObject*) facep->getViewerObject(); + facep->setGeomIndex(vertex_count); + facep->setIndicesIndex(index_count); + facep->setVertexBuffer(buffer); + facep->setPoolType(LLDrawPool::POOL_ALPHA); + object->getGeometry(facep->getTEOffset(), verticesp, normalsp, texcoordsp, colorsp, indicesp); + + vertex_count += facep->getGeomCount(); + index_count += facep->getIndicesCount(); + + S32 idx = draw_vec.size()-1; + + BOOL fullbright = facep->isState(LLFace::FULLBRIGHT); + F32 vsize = facep->getVirtualSize(); + + if (idx >= 0 && draw_vec[idx]->mEnd == facep->getGeomIndex()-1 && + draw_vec[idx]->mTexture == facep->getTexture() && + (U16) (draw_vec[idx]->mEnd - draw_vec[idx]->mStart + facep->getGeomCount()) <= (U32) gGLManager.mGLMaxVertexRange && + //draw_vec[idx]->mCount + facep->getIndicesCount() <= (U32) gGLManager.mGLMaxIndexRange && + draw_vec[idx]->mEnd - draw_vec[idx]->mStart + facep->getGeomCount() < 4096 && + draw_vec[idx]->mFullbright == fullbright) + { + draw_vec[idx]->mCount += facep->getIndicesCount(); + draw_vec[idx]->mEnd += facep->getGeomCount(); + draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, vsize); + } + else + { + U32 start = facep->getGeomIndex(); + U32 end = start + facep->getGeomCount()-1; + U32 offset = facep->getIndicesStart(); + U32 count = facep->getIndicesCount(); + LLDrawInfo* info = new LLDrawInfo(start,end,count,offset,facep->getTexture(), + //facep->getTexture(), + buffer, fullbright); + info->mExtents[0] = group->mObjectExtents[0]; + info->mExtents[1] = group->mObjectExtents[1]; + info->mVSize = vsize; + draw_vec.push_back(info); + //for alpha sorting + facep->setDrawInfo(info); + } + } + + buffer->flush(); + mFaceList.clear(); +} + // virtual void LLVOGrass::updateDrawable(BOOL force_damped) { diff --git a/indra/newview/llvoground.cpp b/indra/newview/llvoground.cpp index 0060f81ab5..6da54435e3 100644 --- a/indra/newview/llvoground.cpp +++ b/indra/newview/llvoground.cpp @@ -82,6 +82,7 @@ LLDrawable *LLVOGround::createDrawable(LLPipeline *pipeline) return mDrawable; } +// TO DO - this always returns TRUE, BOOL LLVOGround::updateGeometry(LLDrawable *drawable) { LLStrider<LLVector3> verticesp; @@ -96,6 +97,8 @@ BOOL LLVOGround::updateGeometry(LLDrawable *drawable) if (drawable->getNumFaces() < 1) drawable->addFace(poolp, NULL); face = drawable->getFace(0); + if (!face) + return TRUE; if (!face->getVertexBuffer()) { diff --git a/indra/newview/llvopartgroup.cpp b/indra/newview/llvopartgroup.cpp index 5c10a80b07..e21358b65a 100644 --- a/indra/newview/llvopartgroup.cpp +++ b/indra/newview/llvopartgroup.cpp @@ -48,6 +48,117 @@ const F32 MAX_PART_LIFETIME = 120.f; extern U64 gFrameTime; +LLPointer<LLVertexBuffer> LLVOPartGroup::sVB = NULL; +S32 LLVOPartGroup::sVBSlotFree[]; +S32* LLVOPartGroup::sVBSlotCursor = NULL; + +//static +void LLVOPartGroup::restoreGL() +{ + for (S32 i = 0; i < LL_MAX_PARTICLE_COUNT; ++i) + { + sVBSlotFree[i] = i; + } + + sVBSlotCursor = sVBSlotFree; + + sVB = new LLVertexBuffer(VERTEX_DATA_MASK, GL_STREAM_DRAW_ARB); + U32 count = LL_MAX_PARTICLE_COUNT; + sVB->allocateBuffer(count*4, count*6, true); + + //indices and texcoords are always the same, set once + LLStrider<U16> indicesp; + + LLStrider<LLVector4a> verticesp; + + sVB->getIndexStrider(indicesp); + sVB->getVertexStrider(verticesp); + + LLVector4a v; + v.set(0,0,0,0); + + + U16 vert_offset = 0; + + for (U32 i = 0; i < LL_MAX_PARTICLE_COUNT; i++) + { + *indicesp++ = vert_offset + 0; + *indicesp++ = vert_offset + 1; + *indicesp++ = vert_offset + 2; + + *indicesp++ = vert_offset + 1; + *indicesp++ = vert_offset + 3; + *indicesp++ = vert_offset + 2; + + *verticesp++ = v; + + vert_offset += 4; + } + + LLStrider<LLVector2> texcoordsp; + sVB->getTexCoord0Strider(texcoordsp); + + for (U32 i = 0; i < LL_MAX_PARTICLE_COUNT; i++) + { + *texcoordsp++ = LLVector2(0.f, 1.f); + *texcoordsp++ = LLVector2(0.f, 0.f); + *texcoordsp++ = LLVector2(1.f, 1.f); + *texcoordsp++ = LLVector2(1.f, 0.f); + } + + sVB->flush(); + +} + +//static +void LLVOPartGroup::destroyGL() +{ + sVB = NULL; +} + +//static +S32 LLVOPartGroup::findAvailableVBSlot() +{ + if (sVBSlotCursor >= sVBSlotFree+LL_MAX_PARTICLE_COUNT) + { //no more available slots + return -1; + } + + S32 ret = *sVBSlotCursor; + sVBSlotCursor++; + + return ret; +} + +bool ll_is_part_idx_allocated(S32 idx, S32* start, S32* end) +{ + while (start < end) + { + if (*start == idx) + { //not allocated (in free list) + return false; + } + ++start; + } + + //allocated (not in free list) + return true; +} + +//static +void LLVOPartGroup::freeVBSlot(S32 idx) +{ + llassert(idx < LL_MAX_PARTICLE_COUNT && idx >= 0); + llassert(sVBSlotCursor > sVBSlotFree); + llassert(ll_is_part_idx_allocated(idx, sVBSlotCursor, sVBSlotFree+LL_MAX_PARTICLE_COUNT)); + + if (sVBSlotCursor > sVBSlotFree) + { + sVBSlotCursor--; + *sVBSlotCursor = idx; + } +} + LLVOPartGroup::LLVOPartGroup(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) : LLAlphaObject(id, pcode, regionp), mViewerPartGroupp(NULL) @@ -62,7 +173,6 @@ LLVOPartGroup::~LLVOPartGroup() { } - BOOL LLVOPartGroup::isActive() const { return FALSE; @@ -287,9 +397,6 @@ void LLVOPartGroup::getGeometry(S32 idx, const LLViewerPart &part = *((LLViewerPart*) (mViewerPartGroupp->mParticles[idx])); - U32 vert_offset = mDrawable->getFace(idx)->getGeomIndex(); - - LLVector4a part_pos_agent; part_pos_agent.load3(part.mPosAgent.mV); LLVector4a camera_agent; @@ -361,33 +468,18 @@ void LLVOPartGroup::getGeometry(S32 idx, verticesp->setAdd(ppamu, right); (*verticesp++).getF32ptr()[3] = 0.f; - //*verticesp++ = part_pos_agent + up - right; - //*verticesp++ = part_pos_agent - up - right; - //*verticesp++ = part_pos_agent + up + right; - //*verticesp++ = part_pos_agent - up + right; - *colorsp++ = part.mColor; *colorsp++ = part.mColor; *colorsp++ = part.mColor; *colorsp++ = part.mColor; - *texcoordsp++ = LLVector2(0.f, 1.f); - *texcoordsp++ = LLVector2(0.f, 0.f); - *texcoordsp++ = LLVector2(1.f, 1.f); - *texcoordsp++ = LLVector2(1.f, 0.f); - - *normalsp++ = normal; - *normalsp++ = normal; - *normalsp++ = normal; - *normalsp++ = normal; - - *indicesp++ = vert_offset + 0; - *indicesp++ = vert_offset + 1; - *indicesp++ = vert_offset + 2; - - *indicesp++ = vert_offset + 1; - *indicesp++ = vert_offset + 3; - *indicesp++ = vert_offset + 2; + if (!(part.mFlags & LLPartData::LL_PART_EMISSIVE_MASK)) + { //not fullbright, needs normal + *normalsp++ = normal; + *normalsp++ = normal; + *normalsp++ = normal; + *normalsp++ = normal; + } } U32 LLVOPartGroup::getPartitionType() const @@ -412,6 +504,49 @@ LLHUDParticlePartition::LLHUDParticlePartition() : mPartitionType = LLViewerRegion::PARTITION_HUD_PARTICLE; } +static LLFastTimer::DeclareTimer FTM_REBUILD_PARTICLE_VBO("Particle VBO"); + +void LLParticlePartition::rebuildGeom(LLSpatialGroup* group) +{ + if (group->isDead() || !group->isState(LLSpatialGroup::GEOM_DIRTY)) + { + return; + } + + if (group->changeLOD()) + { + group->mLastUpdateDistance = group->mDistance; + group->mLastUpdateViewAngle = group->mViewAngle; + } + + LLFastTimer ftm(FTM_REBUILD_PARTICLE_VBO); + + group->clearDrawMap(); + + //get geometry count + U32 index_count = 0; + U32 vertex_count = 0; + + addGeometryCount(group, vertex_count, index_count); + + + if (vertex_count > 0 && index_count > 0) + { + group->mBuilt = 1.f; + //use one vertex buffer for all groups + group->mVertexBuffer = LLVOPartGroup::sVB; + getGeometry(group); + } + else + { + group->mVertexBuffer = NULL; + group->mBufferMap.clear(); + } + + group->mLastUpdateTime = gFrameTimeSeconds; + group->clearState(LLSpatialGroup::GEOM_DIRTY); +} + void LLParticlePartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_count, U32& index_count) { group->mBufferUsage = mBufferUsage; @@ -431,11 +566,6 @@ void LLParticlePartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_co LLAlphaObject* obj = (LLAlphaObject*) drawablep->getVObj().get(); obj->mDepth = 0.f; - if (drawablep->isAnimating()) - { - group->mBufferUsage = GL_STREAM_DRAW_ARB; - } - U32 count = 0; for (S32 j = 0; j < drawablep->getNumFaces(); ++j) { @@ -447,13 +577,14 @@ void LLParticlePartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_co continue; } + vertex_count += facep->getGeomCount(); + index_count += facep->getIndicesCount(); + count++; facep->mDistance = (facep->mCenterLocal - camera->getOrigin()) * camera->getAtAxis(); obj->mDepth += facep->mDistance; mFaceList.push_back(facep); - vertex_count += facep->getGeomCount(); - index_count += facep->getIndicesCount(); llassert(facep->getIndicesCount() < 65536); } @@ -461,15 +592,13 @@ void LLParticlePartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_co } } -static LLFastTimer::DeclareTimer FTM_REBUILD_GRASS_VB("Grass VB"); -static LLFastTimer::DeclareTimer FTM_REBUILD_PARTICLE_VB("Particle VB"); + +static LLFastTimer::DeclareTimer FTM_REBUILD_PARTICLE_GEOM("Particle Geom"); void LLParticlePartition::getGeometry(LLSpatialGroup* group) { LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - LLFastTimer ftm(mDrawableType == LLPipeline::RENDER_TYPE_GRASS ? - FTM_REBUILD_GRASS_VB : - FTM_REBUILD_PARTICLE_VB); + LLFastTimer ftm(FTM_REBUILD_PARTICLE_GEOM); std::sort(mFaceList.begin(), mFaceList.end(), LLFace::CompareDistanceGreater()); @@ -489,21 +618,44 @@ void LLParticlePartition::getGeometry(LLSpatialGroup* group) buffer->getVertexStrider(verticesp); buffer->getNormalStrider(normalsp); buffer->getColorStrider(colorsp); - buffer->getTexCoord0Strider(texcoordsp); - buffer->getIndexStrider(indicesp); - + LLSpatialGroup::drawmap_elem_t& draw_vec = group->mDrawMap[mRenderPass]; for (std::vector<LLFace*>::iterator i = mFaceList.begin(); i != mFaceList.end(); ++i) { LLFace* facep = *i; LLAlphaObject* object = (LLAlphaObject*) facep->getViewerObject(); - facep->setGeomIndex(vertex_count); - facep->setIndicesIndex(index_count); - facep->setVertexBuffer(buffer); - facep->setPoolType(LLDrawPool::POOL_ALPHA); - object->getGeometry(facep->getTEOffset(), verticesp, normalsp, texcoordsp, colorsp, indicesp); + + if (facep->getIndicesStart() == 0xFFFFFFFF) + { //set the indices of this face + S32 idx = LLVOPartGroup::findAvailableVBSlot(); + if (idx >= 0) + { + facep->setGeomIndex(idx*4); + facep->setIndicesIndex(idx*6); + facep->setVertexBuffer(LLVOPartGroup::sVB); + facep->setPoolType(LLDrawPool::POOL_ALPHA); + } + else + { + continue; //out of space in particle buffer + } + } + + S32 geom_idx = (S32) facep->getGeomIndex(); + + LLStrider<U16> cur_idx = indicesp + facep->getIndicesStart(); + LLStrider<LLVector4a> cur_vert = verticesp + geom_idx; + LLStrider<LLVector3> cur_norm = normalsp + geom_idx; + LLStrider<LLVector2> cur_tc = texcoordsp + geom_idx; + LLStrider<LLColor4U> cur_col = colorsp + geom_idx; + + object->getGeometry(facep->getTEOffset(), cur_vert, cur_norm, cur_tc, cur_col, cur_idx); + llassert(facep->getGeomCount() == 4); + llassert(facep->getIndicesCount() == 6); + + vertex_count += facep->getGeomCount(); index_count += facep->getIndicesCount(); @@ -512,18 +664,31 @@ void LLParticlePartition::getGeometry(LLSpatialGroup* group) BOOL fullbright = facep->isState(LLFace::FULLBRIGHT); F32 vsize = facep->getVirtualSize(); - if (idx >= 0 && draw_vec[idx]->mEnd == facep->getGeomIndex()-1 && + bool batched = false; + + if (idx >= 0 && draw_vec[idx]->mTexture == facep->getTexture() && - (U16) (draw_vec[idx]->mEnd - draw_vec[idx]->mStart + facep->getGeomCount()) <= (U32) gGLManager.mGLMaxVertexRange && - //draw_vec[idx]->mCount + facep->getIndicesCount() <= (U32) gGLManager.mGLMaxIndexRange && - draw_vec[idx]->mEnd - draw_vec[idx]->mStart + facep->getGeomCount() < 4096 && draw_vec[idx]->mFullbright == fullbright) { - draw_vec[idx]->mCount += facep->getIndicesCount(); - draw_vec[idx]->mEnd += facep->getGeomCount(); - draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, vsize); + if (draw_vec[idx]->mEnd == facep->getGeomIndex()-1) + { + batched = true; + draw_vec[idx]->mCount += facep->getIndicesCount(); + draw_vec[idx]->mEnd += facep->getGeomCount(); + draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, vsize); + } + else if (draw_vec[idx]->mStart == facep->getGeomIndex()+facep->getGeomCount()+1) + { + batched = true; + draw_vec[idx]->mCount += facep->getIndicesCount(); + draw_vec[idx]->mStart -= facep->getGeomCount(); + draw_vec[idx]->mOffset = facep->getIndicesStart(); + draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, vsize); + } } - else + + + if (!batched) { U32 start = facep->getGeomIndex(); U32 end = start + facep->getGeomCount()-1; @@ -541,7 +706,6 @@ void LLParticlePartition::getGeometry(LLSpatialGroup* group) } } - buffer->flush(); mFaceList.clear(); } diff --git a/indra/newview/llvopartgroup.h b/indra/newview/llvopartgroup.h index e58fed86d9..6160bceb24 100644 --- a/indra/newview/llvopartgroup.h +++ b/indra/newview/llvopartgroup.h @@ -31,18 +31,32 @@ #include "v3math.h" #include "v3color.h" #include "llframetimer.h" +#include "llviewerpartsim.h" +#include "llvertexbuffer.h" class LLViewerPartGroup; class LLVOPartGroup : public LLAlphaObject { public: + + //vertex buffer for holding all particles + static LLPointer<LLVertexBuffer> sVB; + static S32 sVBSlotFree[LL_MAX_PARTICLE_COUNT]; + static S32* sVBSlotCursor; + + static void restoreGL(); + static void destroyGL(); + static S32 findAvailableVBSlot(); + static void freeVBSlot(S32 idx); + enum { - VERTEX_DATA_MASK = (1 << LLVertexBuffer::TYPE_VERTEX) | - (1 << LLVertexBuffer::TYPE_NORMAL) | - (1 << LLVertexBuffer::TYPE_TEXCOORD0) | - (1 << LLVertexBuffer::TYPE_COLOR) + VERTEX_DATA_MASK = LLVertexBuffer::MAP_VERTEX | + LLVertexBuffer::MAP_NORMAL | + LLVertexBuffer::MAP_TEXCOORD0 | + LLVertexBuffer::MAP_COLOR | + LLVertexBuffer::MAP_TEXTURE_INDEX }; LLVOPartGroup(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp); diff --git a/indra/newview/llvosurfacepatch.cpp b/indra/newview/llvosurfacepatch.cpp index bf6158eeaf..94a3111f4c 100644 --- a/indra/newview/llvosurfacepatch.cpp +++ b/indra/newview/llvosurfacepatch.cpp @@ -296,18 +296,20 @@ void LLVOSurfacePatch::updateFaceSize(S32 idx) } LLFace* facep = mDrawable->getFace(idx); - - S32 num_vertices = 0; - S32 num_indices = 0; - - if (mLastStride) + if (facep) { - getGeomSizesMain(mLastStride, num_vertices, num_indices); - getGeomSizesNorth(mLastStride, mLastNorthStride, num_vertices, num_indices); - getGeomSizesEast(mLastStride, mLastEastStride, num_vertices, num_indices); - } + S32 num_vertices = 0; + S32 num_indices = 0; + + if (mLastStride) + { + getGeomSizesMain(mLastStride, num_vertices, num_indices); + getGeomSizesNorth(mLastStride, mLastNorthStride, num_vertices, num_indices); + getGeomSizesEast(mLastStride, mLastEastStride, num_vertices, num_indices); + } - facep->setSize(num_vertices, num_indices); + facep->setSize(num_vertices, num_indices); + } } BOOL LLVOSurfacePatch::updateLOD() @@ -322,30 +324,32 @@ void LLVOSurfacePatch::getGeometry(LLStrider<LLVector3> &verticesp, LLStrider<U16> &indicesp) { LLFace* facep = mDrawable->getFace(0); + if (facep) + { + U32 index_offset = facep->getGeomIndex(); - U32 index_offset = facep->getGeomIndex(); - - updateMainGeometry(facep, - verticesp, - normalsp, - texCoords0p, - texCoords1p, - indicesp, - index_offset); - updateNorthGeometry(facep, - verticesp, - normalsp, - texCoords0p, - texCoords1p, - indicesp, - index_offset); - updateEastGeometry(facep, + updateMainGeometry(facep, verticesp, normalsp, texCoords0p, texCoords1p, indicesp, index_offset); + updateNorthGeometry(facep, + verticesp, + normalsp, + texCoords0p, + texCoords1p, + indicesp, + index_offset); + updateEastGeometry(facep, + verticesp, + normalsp, + texCoords0p, + texCoords1p, + indicesp, + index_offset); + } } void LLVOSurfacePatch::updateMainGeometry(LLFace *facep, @@ -864,7 +868,11 @@ void LLVOSurfacePatch::dirtyGeom() if (mDrawable) { gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE); - mDrawable->getFace(0)->setVertexBuffer(NULL); + LLFace* facep = mDrawable->getFace(0); + if (facep) + { + facep->setVertexBuffer(NULL); + } mDrawable->movePartition(); } } diff --git a/indra/newview/llvotree.cpp b/indra/newview/llvotree.cpp index 4564207da4..3556bde9a8 100644 --- a/indra/newview/llvotree.cpp +++ b/indra/newview/llvotree.cpp @@ -490,11 +490,16 @@ BOOL LLVOTree::updateGeometry(LLDrawable *drawable) if(mTrunkLOD >= sMAX_NUM_TREE_LOD_LEVELS) //do not display the tree. { mReferenceBuffer = NULL ; - mDrawable->getFace(0)->setVertexBuffer(NULL); + LLFace * facep = drawable->getFace(0); + if (facep) + { + facep->setVertexBuffer(NULL); + } return TRUE ; } - if (mReferenceBuffer.isNull() || !mDrawable->getFace(0)->getVertexBuffer()) + if (mDrawable->getFace(0) && + (mReferenceBuffer.isNull() || !mDrawable->getFace(0)->getVertexBuffer())) { const F32 SRR3 = 0.577350269f; // sqrt(1/3) const F32 SRR2 = 0.707106781f; // sqrt(1/2) @@ -507,6 +512,7 @@ BOOL LLVOTree::updateGeometry(LLDrawable *drawable) S32 lod; LLFace *face = drawable->getFace(0); + if (!face) return TRUE; face->mCenterAgent = getPositionAgent(); face->mCenterLocal = face->mCenterAgent; @@ -879,6 +885,7 @@ void LLVOTree::updateMesh() calcNumVerts(vert_count, index_count, mTrunkLOD, stop_depth, mDepth, mTrunkDepth, mBranches); LLFace* facep = mDrawable->getFace(0); + if (!facep) return; LLVertexBuffer* buff = new LLVertexBuffer(LLDrawPoolTree::VERTEX_DATA_MASK, GL_STATIC_DRAW_ARB); buff->allocateBuffer(vert_count, index_count, TRUE); facep->setVertexBuffer(buff); diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 080d1f774a..c4e7ea44b4 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -520,6 +520,7 @@ void LLVOVolume::animateTextures() for (S32 i = start; i <= end; i++) { LLFace* facep = mDrawable->getFace(i); + if (!facep) continue; if(facep->getVirtualSize() <= MIN_TEX_ANIM_SIZE && facep->mTextureMatrix) continue; const LLTextureEntry* te = facep->getTextureEntry(); @@ -638,7 +639,7 @@ BOOL LLVOVolume::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) { LLViewerObject::idleUpdate(agent, world, time); - static LLFastTimer::DeclareTimer ftm("Volume"); + static LLFastTimer::DeclareTimer ftm("Volume Idle"); LLFastTimer t(ftm); if (mDead || mDrawable.isNull()) @@ -682,7 +683,21 @@ void LLVOVolume::updateTextures() const F32 TEXTURE_AREA_REFRESH_TIME = 5.f; // seconds if (mTextureUpdateTimer.getElapsedTimeF32() > TEXTURE_AREA_REFRESH_TIME) { - updateTextureVirtualSize(); + updateTextureVirtualSize(); + + if (mDrawable.notNull() && !isVisible() && !mDrawable->isActive()) + { //delete vertex buffer to free up some VRAM + LLSpatialGroup* group = mDrawable->getSpatialGroup(); + if (group) + { + group->destroyGL(true); + + //flag the group as having changed geometry so it gets a rebuild next time + //it becomes visible + group->setState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::MESH_DIRTY | LLSpatialGroup::NEW_DRAWINFO); + } + } + } } @@ -715,7 +730,18 @@ void LLVOVolume::updateTextureVirtualSize(bool forced) if(!forced) { if(!isVisible()) - { + { //don't load textures for non-visible faces + const S32 num_faces = mDrawable->getNumFaces(); + for (S32 i = 0; i < num_faces; i++) + { + LLFace* face = mDrawable->getFace(i); + if (face) + { + face->setPixelArea(0.f); + face->setVirtualSize(0.f); + } + } + return ; } @@ -743,6 +769,7 @@ void LLVOVolume::updateTextureVirtualSize(bool forced) for (S32 i = 0; i < num_faces; i++) { LLFace* face = mDrawable->getFace(i); + if (!face) continue; const LLTextureEntry *te = face->getTextureEntry(); LLViewerTexture *imagep = face->getTexture(); if (!imagep || !te || @@ -1062,9 +1089,33 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams ¶ms_in, const S32 detail, bo } } + + static LLCachedControl<bool> use_transform_feedback(gSavedSettings, "RenderUseTransformFeedback"); + + bool cache_in_vram = use_transform_feedback && gTransformPositionProgram.mProgramObject && + (!mVolumeImpl || !mVolumeImpl->isVolumeUnique()); + + if (cache_in_vram) + { //this volume might be used as source data for a transform object, put it in vram + LLVolume* volume = getVolume(); + for (S32 i = 0; i < volume->getNumFaces(); ++i) + { + const LLVolumeFace& face = volume->getVolumeFace(i); + if (face.mVertexBuffer.notNull()) + { //already cached + break; + } + volume->genBinormals(i); + LLFace::cacheFaceInVRAM(face); + } + } + + return TRUE; } + + return FALSE; } @@ -1246,7 +1297,8 @@ BOOL LLVOVolume::calcLOD() llround(radius, 0.01f)); - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_LOD_INFO)) + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_LOD_INFO) && + mDrawable->getFace(0)) { //setDebugText(llformat("%.2f:%.2f, %d", debug_distance, radius, cur_detail)); @@ -1325,25 +1377,23 @@ void LLVOVolume::updateFaceFlags() for (S32 i = 0; i < getVolume()->getNumFaces(); i++) { LLFace *face = mDrawable->getFace(i); - if (!face) + if (face) { - return; - } + BOOL fullbright = getTE(i)->getFullbright(); + face->clearState(LLFace::FULLBRIGHT | LLFace::HUD_RENDER | LLFace::LIGHT); - BOOL fullbright = getTE(i)->getFullbright(); - face->clearState(LLFace::FULLBRIGHT | LLFace::HUD_RENDER | LLFace::LIGHT); - - if (fullbright || (mMaterial == LL_MCODE_LIGHT)) - { - face->setState(LLFace::FULLBRIGHT); - } - if (mDrawable->isLight()) - { - face->setState(LLFace::LIGHT); - } - if (isHUDAttachment()) - { - face->setState(LLFace::HUD_RENDER); + if (fullbright || (mMaterial == LL_MCODE_LIGHT)) + { + face->setState(LLFace::FULLBRIGHT); + } + if (mDrawable->isLight()) + { + face->setState(LLFace::LIGHT); + } + if (isHUDAttachment()) + { + face->setState(LLFace::HUD_RENDER); + } } } } @@ -1380,6 +1430,8 @@ void LLVOVolume::regenFaces() for (S32 i = 0; i < mNumFaces; i++) { LLFace* facep = count_changed ? addFace(i) : mDrawable->getFace(i); + if (!facep) continue; + facep->setTEOffset(i); facep->setTexture(getTEImage(i)); facep->setViewerObject(this); @@ -1416,7 +1468,7 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global) BOOL rebuild = mDrawable->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION | LLDrawable::REBUILD_RIGGED); -// bool rigged = false; + // bool rigged = false; LLVolume* volume = mRiggedVolume; if (!volume) { @@ -1471,11 +1523,11 @@ void LLVOVolume::preRebuild() } } -void LLVOVolume::updateRelativeXform() +void LLVOVolume::updateRelativeXform(bool force_identity) { if (mVolumeImpl) { - mVolumeImpl->updateRelativeXform(); + mVolumeImpl->updateRelativeXform(force_identity); return; } @@ -1495,15 +1547,16 @@ void LLVOVolume::updateRelativeXform() mRelativeXform.invert(); mRelativeXformInvTrans.transpose(); } - else if (drawable->isActive()) + else if (drawable->isActive() || force_identity) { // setup relative transforms LLQuaternion delta_rot; LLVector3 delta_pos, delta_scale; //matrix from local space to parent relative/global space - delta_rot = drawable->isSpatialRoot() ? LLQuaternion() : mDrawable->getRotation(); - delta_pos = drawable->isSpatialRoot() ? LLVector3(0,0,0) : mDrawable->getPosition(); + bool use_identity = force_identity || drawable->isSpatialRoot(); + delta_rot = use_identity ? LLQuaternion() : mDrawable->getRotation(); + delta_pos = use_identity ? LLVector3(0,0,0) : mDrawable->getPosition(); delta_scale = mDrawable->getScale(); // Vertex transform (4x4) @@ -1604,7 +1657,11 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) return res; } - dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1)); + LLSpatialGroup* group = drawable->getSpatialGroup(); + if (group) + { + group->dirtyMesh(); + } BOOL compiled = FALSE; @@ -1617,6 +1674,8 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) if (mVolumeChanged || mFaceMappingChanged ) { + dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1)); + compiled = TRUE; if (mVolumeChanged) @@ -1635,6 +1694,8 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) } else if ((mLODChanged) || (mSculptChanged)) { + dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1)); + LLVolume *old_volumep, *new_volumep; F32 old_lod, new_lod; S32 old_num_faces, new_num_faces ; @@ -1716,16 +1777,19 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) void LLVOVolume::updateFaceSize(S32 idx) { LLFace* facep = mDrawable->getFace(idx); - if (idx >= getVolume()->getNumVolumeFaces()) - { - facep->setSize(0,0, true); - } - else + if (facep) { - const LLVolumeFace& vol_face = getVolume()->getVolumeFace(idx); - facep->setSize(vol_face.mNumVertices, vol_face.mNumIndices, - true); // <--- volume faces should be padded for 16-byte alignment + if (idx >= getVolume()->getNumVolumeFaces()) + { + facep->setSize(0,0, true); + } + else + { + const LLVolumeFace& vol_face = getVolume()->getVolumeFace(idx); + facep->setSize(vol_face.mNumVertices, vol_face.mNumIndices, + true); // <--- volume faces should be padded for 16-byte alignment + } } } @@ -3098,6 +3162,7 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const for (S32 i = 0; i < num_faces; ++i) { const LLFace* face = drawablep->getFace(i); + if (!face) continue; const LLTextureEntry* te = face->getTextureEntry(); const LLViewerTexture* img = face->getTexture(); @@ -3369,6 +3434,7 @@ F32 LLVOVolume::getBinRadius() for (S32 i = 0; i < mDrawable->getNumFaces(); i++) { LLFace* face = mDrawable->getFace(i); + if (!face) continue; if (face->getPoolType() == LLDrawPool::POOL_ALPHA && !face->canRenderAsMask()) { @@ -3450,9 +3516,12 @@ LLVector3 LLVOVolume::agentPositionToVolume(const LLVector3& pos) const { LLVector3 ret = pos - getRenderPosition(); ret = ret * ~getRenderRotation(); - LLVector3 objScale = isVolumeGlobal() ? LLVector3(1,1,1) : getScale(); - LLVector3 invObjScale(1.f / objScale.mV[VX], 1.f / objScale.mV[VY], 1.f / objScale.mV[VZ]); - ret.scaleVec(invObjScale); + if (!isVolumeGlobal()) + { + LLVector3 objScale = getScale(); + LLVector3 invObjScale(1.f / objScale.mV[VX], 1.f / objScale.mV[VY], 1.f / objScale.mV[VZ]); + ret.scaleVec(invObjScale); + } return ret; } @@ -3470,8 +3539,12 @@ LLVector3 LLVOVolume::agentDirectionToVolume(const LLVector3& dir) const LLVector3 LLVOVolume::volumePositionToAgent(const LLVector3& dir) const { LLVector3 ret = dir; - LLVector3 objScale = isVolumeGlobal() ? LLVector3(1,1,1) : getScale(); - ret.scaleVec(objScale); + if (!isVolumeGlobal()) + { + LLVector3 objScale = getScale(); + ret.scaleVec(objScale); + } + ret = ret * getRenderRotation(); ret += getRenderPosition(); @@ -3592,7 +3665,8 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e { LLFace* face = mDrawable->getFace(face_hit); - if (pick_transparent || !face->getTexture() || !face->getTexture()->hasGLTexture() || face->getTexture()->getMask(face->surfaceToTexture(tc, p, n))) + if (face && + (pick_transparent || !face->getTexture() || !face->getTexture()->hasGLTexture() || face->getTexture()->getMask(face->surfaceToTexture(tc, p, n)))) { v_end = p; if (face_hitp != NULL) @@ -3902,8 +3976,11 @@ bool can_batch_texture(LLFace* facep) return true; } +static LLFastTimer::DeclareTimer FTM_REGISTER_FACE("Register Face"); + void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, U32 type) { + LLFastTimer t(FTM_REGISTER_FACE); LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); if (facep->getViewerObject()->isSelected() && LLSelectMgr::getInstance()->mHideSelectedObjects) @@ -3935,9 +4012,14 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, const LLMatrix4* model_mat = NULL; LLDrawable* drawable = facep->getDrawable(); - if (drawable->isActive()) + + if (drawable->isState(LLDrawable::ANIMATED_CHILD)) + { + model_mat = &drawable->getWorldMatrix(); + } + else if (drawable->isActive()) { - model_mat = &(drawable->getRenderMatrix()); + model_mat = &drawable->getRenderMatrix(); } else { @@ -3948,6 +4030,8 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, } } + //drawable->getVObj()->setDebugText(llformat("%d", drawable->isState(LLDrawable::ANIMATED_CHILD))); + U8 bump = (type == LLRenderPass::PASS_BUMP || type == LLRenderPass::PASS_POST_BUMP) ? facep->getTextureEntry()->getBumpmap() : 0; LLViewerTexture* tex = facep->getTexture(); @@ -4041,8 +4125,9 @@ void LLVolumeGeometryManager::getGeometry(LLSpatialGroup* group) } -static LLFastTimer::DeclareTimer FTM_REBUILD_VOLUME_VB("Volume"); -static LLFastTimer::DeclareTimer FTM_REBUILD_VBO("VBO Rebuilt"); +static LLFastTimer::DeclareTimer FTM_REBUILD_VOLUME_VB("Volume VB"); +static LLFastTimer::DeclareTimer FTM_REBUILD_VOLUME_FACE_LIST("Build Face List"); +static LLFastTimer::DeclareTimer FTM_REBUILD_VOLUME_GEN_DRAW_INFO("Gen Draw Info"); static LLDrawPoolAvatar* get_avatar_drawpool(LLViewerObject* vobj) { @@ -4073,6 +4158,8 @@ static LLDrawPoolAvatar* get_avatar_drawpool(LLViewerObject* vobj) void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) { + + if (group->changeLOD()) { group->mLastUpdateDistance = group->mDistance; @@ -4084,19 +4171,15 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) { if (group->isState(LLSpatialGroup::MESH_DIRTY) && !LLPipeline::sDelayVBUpdate) { - LLFastTimer ftm(FTM_REBUILD_VBO); - LLFastTimer ftm2(FTM_REBUILD_VOLUME_VB); - rebuildMesh(group); } return; } - group->mBuilt = 1.f; - LLFastTimer ftm(FTM_REBUILD_VBO); - - LLFastTimer ftm2(FTM_REBUILD_VOLUME_VB); + LLFastTimer ftm(FTM_REBUILD_VOLUME_VB); + group->mBuilt = 1.f; + LLVOAvatar* pAvatarVO = NULL; LLSpatialBridge* bridge = group->mSpatialPartition->asBridge(); @@ -4145,359 +4228,375 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) bool emissive = false; - //get all the faces into a list - for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter) { - LLDrawable* drawablep = *drawable_iter; - - if (drawablep->isDead() || drawablep->isState(LLDrawable::FORCE_INVISIBLE) ) + LLFastTimer t(FTM_REBUILD_VOLUME_FACE_LIST); + + //get all the faces into a list + for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter) { - continue; - } + LLDrawable* drawablep = *drawable_iter; + + if (drawablep->isDead() || drawablep->isState(LLDrawable::FORCE_INVISIBLE) ) + { + continue; + } - if (drawablep->isAnimating()) - { //fall back to stream draw for animating verts - useage = GL_STREAM_DRAW_ARB; - } + if (drawablep->isAnimating()) + { //fall back to stream draw for animating verts + useage = GL_STREAM_DRAW_ARB; + } - LLVOVolume* vobj = drawablep->getVOVolume(); + LLVOVolume* vobj = drawablep->getVOVolume(); - if (!vobj) - { - continue; - } + if (!vobj) + { + continue; + } - if (vobj->isMesh() && - (vobj->getVolume() && !vobj->getVolume()->isMeshAssetLoaded() || !gMeshRepo.meshRezEnabled())) - { - continue; - } + if (vobj->isMesh() && + (vobj->getVolume() && !vobj->getVolume()->isMeshAssetLoaded() || !gMeshRepo.meshRezEnabled())) + { + continue; + } - LLVolume* volume = vobj->getVolume(); - if (volume) - { - const LLVector3& scale = vobj->getScale(); - group->mSurfaceArea += volume->getSurfaceArea() * llmax(llmax(scale.mV[0], scale.mV[1]), scale.mV[2]); - } + LLVolume* volume = vobj->getVolume(); + if (volume) + { + const LLVector3& scale = vobj->getScale(); + group->mSurfaceArea += volume->getSurfaceArea() * llmax(llmax(scale.mV[0], scale.mV[1]), scale.mV[2]); + } - llassert_always(vobj); - vobj->updateTextureVirtualSize(true); - vobj->preRebuild(); + llassert_always(vobj); + vobj->updateTextureVirtualSize(true); + vobj->preRebuild(); - drawablep->clearState(LLDrawable::HAS_ALPHA); + drawablep->clearState(LLDrawable::HAS_ALPHA); - bool rigged = vobj->isAttachment() && - vobj->isMesh() && - gMeshRepo.getSkinInfo(vobj->getVolume()->getParams().getSculptID(), vobj); + bool rigged = vobj->isAttachment() && + vobj->isMesh() && + gMeshRepo.getSkinInfo(vobj->getVolume()->getParams().getSculptID(), vobj); - bool bake_sunlight = LLPipeline::sBakeSunlight && drawablep->isStatic(); + bool bake_sunlight = LLPipeline::sBakeSunlight && drawablep->isStatic(); - bool is_rigged = false; + bool is_rigged = false; - //for each face - for (S32 i = 0; i < drawablep->getNumFaces(); i++) - { - LLFace* facep = drawablep->getFace(i); + //for each face + for (S32 i = 0; i < drawablep->getNumFaces(); i++) + { + LLFace* facep = drawablep->getFace(i); + if (!facep) + { + continue; + } - //ALWAYS null out vertex buffer on rebuild -- if the face lands in a render - // batch, it will recover its vertex buffer reference from the spatial group - facep->setVertexBuffer(NULL); + //ALWAYS null out vertex buffer on rebuild -- if the face lands in a render + // batch, it will recover its vertex buffer reference from the spatial group + facep->setVertexBuffer(NULL); - //sum up face verts and indices - drawablep->updateFaceSize(i); + //sum up face verts and indices + drawablep->updateFaceSize(i); - if (rigged) - { - if (!facep->isState(LLFace::RIGGED)) - { //completely reset vertex buffer - facep->clearVertexBuffer(); - } + if (rigged) + { + if (!facep->isState(LLFace::RIGGED)) + { //completely reset vertex buffer + facep->clearVertexBuffer(); + } - facep->setState(LLFace::RIGGED); - is_rigged = true; + facep->setState(LLFace::RIGGED); + is_rigged = true; - //get drawpool of avatar with rigged face - LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj); + //get drawpool of avatar with rigged face + LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj); - //Determine if we've received skininfo that contains an - //alternate bind matrix - if it does then apply the translational component - //to the joints of the avatar. - bool pelvisGotSet = false; + //Determine if we've received skininfo that contains an + //alternate bind matrix - if it does then apply the translational component + //to the joints of the avatar. + bool pelvisGotSet = false; - if ( pAvatarVO ) - { - LLUUID currentId = vobj->getVolume()->getParams().getSculptID(); - const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( currentId, vobj ); - - if ( pSkinData ) + if ( pAvatarVO ) { - const int bindCnt = pSkinData->mAlternateBindMatrix.size(); - if ( bindCnt > 0 ) - { - const int jointCnt = pSkinData->mJointNames.size(); - const F32 pelvisZOffset = pSkinData->mPelvisOffset; - bool fullRig = (jointCnt>=20) ? true : false; - if ( fullRig ) - { - for ( int i=0; i<jointCnt; ++i ) + LLUUID currentId = vobj->getVolume()->getParams().getSculptID(); + const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( currentId, vobj ); + + if ( pSkinData ) + { + const int bindCnt = pSkinData->mAlternateBindMatrix.size(); + if ( bindCnt > 0 ) + { + const int jointCnt = pSkinData->mJointNames.size(); + const F32 pelvisZOffset = pSkinData->mPelvisOffset; + bool fullRig = (jointCnt>=20) ? true : false; + if ( fullRig ) { - std::string lookingForJoint = pSkinData->mJointNames[i].c_str(); - //llinfos<<"joint name "<<lookingForJoint.c_str()<<llendl; - LLJoint* pJoint = pAvatarVO->getJoint( lookingForJoint ); - if ( pJoint && pJoint->getId() != currentId ) - { - pJoint->setId( currentId ); - const LLVector3& jointPos = pSkinData->mAlternateBindMatrix[i].getTranslation(); - //Set the joint position - pJoint->storeCurrentXform( jointPos ); - //If joint is a pelvis then handle old/new pelvis to foot values - if ( lookingForJoint == "mPelvis" ) - { + for ( int i=0; i<jointCnt; ++i ) + { + std::string lookingForJoint = pSkinData->mJointNames[i].c_str(); + //llinfos<<"joint name "<<lookingForJoint.c_str()<<llendl; + LLJoint* pJoint = pAvatarVO->getJoint( lookingForJoint ); + if ( pJoint && pJoint->getId() != currentId ) + { + pJoint->setId( currentId ); + const LLVector3& jointPos = pSkinData->mAlternateBindMatrix[i].getTranslation(); + //Set the joint position pJoint->storeCurrentXform( jointPos ); - if ( !pAvatarVO->hasPelvisOffset() ) - { - pAvatarVO->setPelvisOffset( true, jointPos, pelvisZOffset ); - //Trigger to rebuild viewer AV - pelvisGotSet = true; + //If joint is a pelvis then handle old/new pelvis to foot values + if ( lookingForJoint == "mPelvis" ) + { + pJoint->storeCurrentXform( jointPos ); + if ( !pAvatarVO->hasPelvisOffset() ) + { + pAvatarVO->setPelvisOffset( true, jointPos, pelvisZOffset ); + //Trigger to rebuild viewer AV + pelvisGotSet = true; + } } - } + } } - } - } + } + } } } - } - //If we've set the pelvis to a new position we need to also rebuild some information that the - //viewer does at launch (e.g. body size etc.) - if ( pelvisGotSet ) - { - pAvatarVO->postPelvisSetRecalc(); - } - - if (pool) - { - const LLTextureEntry* te = facep->getTextureEntry(); - - //remove face from old pool if it exists - LLDrawPool* old_pool = facep->getPool(); - if (old_pool && old_pool->getType() == LLDrawPool::POOL_AVATAR) + //If we've set the pelvis to a new position we need to also rebuild some information that the + //viewer does at launch (e.g. body size etc.) + if ( pelvisGotSet ) { - ((LLDrawPoolAvatar*) old_pool)->removeRiggedFace(facep); + pAvatarVO->postPelvisSetRecalc(); } - //add face to new pool - LLViewerTexture* tex = facep->getTexture(); - U32 type = gPipeline.getPoolTypeFromTE(te, tex); - - if (type == LLDrawPool::POOL_ALPHA) + if (pool) { - if (te->getColor().mV[3] > 0.f) + const LLTextureEntry* te = facep->getTextureEntry(); + + //remove face from old pool if it exists + LLDrawPool* old_pool = facep->getPool(); + if (old_pool && old_pool->getType() == LLDrawPool::POOL_AVATAR) + { + ((LLDrawPoolAvatar*) old_pool)->removeRiggedFace(facep); + } + + //add face to new pool + LLViewerTexture* tex = facep->getTexture(); + U32 type = gPipeline.getPoolTypeFromTE(te, tex); + + if (type == LLDrawPool::POOL_ALPHA) + { + if (te->getColor().mV[3] > 0.f) + { + if (te->getFullbright()) + { + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA); + } + else + { + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_ALPHA); + } + } + } + else if (te->getShiny()) { if (te->getFullbright()) { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA); + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY); } else { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_ALPHA); + if (LLPipeline::sRenderDeferred) + { + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE); + } + else + { + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SHINY); + } } } - } - else if (te->getShiny()) - { - if (te->getFullbright()) - { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY); - } else { - if (LLPipeline::sRenderDeferred) + if (te->getFullbright()) { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE); + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT); } else { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SHINY); + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE); } } - } - else - { - if (te->getFullbright()) - { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT); - } - else + + if (te->getGlow()) { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE); + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_GLOW); } - } - if (te->getGlow()) - { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_GLOW); - } - - if (LLPipeline::sRenderDeferred) - { - if (type != LLDrawPool::POOL_ALPHA && !te->getFullbright()) + if (LLPipeline::sRenderDeferred) { - if (te->getBumpmap()) - { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_BUMP); - } - else + if (type != LLDrawPool::POOL_ALPHA && !te->getFullbright()) { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_SIMPLE); + if (te->getBumpmap()) + { + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_BUMP); + } + else + { + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_SIMPLE); + } } } } - } - continue; - } - else - { - if (facep->isState(LLFace::RIGGED)) - { //face is not rigged but used to be, remove from rigged face pool - LLDrawPoolAvatar* pool = (LLDrawPoolAvatar*) facep->getPool(); - if (pool) - { - pool->removeRiggedFace(facep); + continue; + } + else + { + if (facep->isState(LLFace::RIGGED)) + { //face is not rigged but used to be, remove from rigged face pool + LLDrawPoolAvatar* pool = (LLDrawPoolAvatar*) facep->getPool(); + if (pool) + { + pool->removeRiggedFace(facep); + } + facep->clearState(LLFace::RIGGED); } - facep->clearState(LLFace::RIGGED); } - } - if (cur_total > max_total || facep->getIndicesCount() <= 0 || facep->getGeomCount() <= 0) - { - facep->clearVertexBuffer(); - continue; - } - - cur_total += facep->getGeomCount(); - - if (facep->hasGeometry() && facep->getPixelArea() > FORCE_CULL_AREA) - { - const LLTextureEntry* te = facep->getTextureEntry(); - LLViewerTexture* tex = facep->getTexture(); - - if (te->getGlow() >= 1.f/255.f) + if (cur_total > max_total || facep->getIndicesCount() <= 0 || facep->getGeomCount() <= 0) { - emissive = true; + facep->clearVertexBuffer(); + continue; } - if (facep->isState(LLFace::TEXTURE_ANIM)) - { - if (!vobj->mTexAnimMode) - { - facep->clearState(LLFace::TEXTURE_ANIM); - } - } + cur_total += facep->getGeomCount(); - BOOL force_simple = (facep->getPixelArea() < FORCE_SIMPLE_RENDER_AREA); - U32 type = gPipeline.getPoolTypeFromTE(te, tex); - if (type != LLDrawPool::POOL_ALPHA && force_simple) + if (facep->hasGeometry() && facep->getPixelArea() > FORCE_CULL_AREA) { - type = LLDrawPool::POOL_SIMPLE; - } - facep->setPoolType(type); + const LLTextureEntry* te = facep->getTextureEntry(); + LLViewerTexture* tex = facep->getTexture(); - if (vobj->isHUDAttachment()) - { - facep->setState(LLFace::FULLBRIGHT); - } + if (te->getGlow() >= 1.f/255.f) + { + emissive = true; + } - if (vobj->mTextureAnimp && vobj->mTexAnimMode) - { - if (vobj->mTextureAnimp->mFace <= -1) + if (facep->isState(LLFace::TEXTURE_ANIM)) { - S32 face; - for (face = 0; face < vobj->getNumTEs(); face++) + if (!vobj->mTexAnimMode) { - drawablep->getFace(face)->setState(LLFace::TEXTURE_ANIM); + facep->clearState(LLFace::TEXTURE_ANIM); } } - else if (vobj->mTextureAnimp->mFace < vobj->getNumTEs()) + + BOOL force_simple = (facep->getPixelArea() < FORCE_SIMPLE_RENDER_AREA); + U32 type = gPipeline.getPoolTypeFromTE(te, tex); + if (type != LLDrawPool::POOL_ALPHA && force_simple) { - drawablep->getFace(vobj->mTextureAnimp->mFace)->setState(LLFace::TEXTURE_ANIM); + type = LLDrawPool::POOL_SIMPLE; } - } + facep->setPoolType(type); - if (type == LLDrawPool::POOL_ALPHA) - { - if (facep->canRenderAsMask()) - { //can be treated as alpha mask - simple_faces.push_back(facep); - } - else + if (vobj->isHUDAttachment()) { - if (te->getColor().mV[3] > 0.f) - { //only treat as alpha in the pipeline if < 100% transparent - drawablep->setState(LLDrawable::HAS_ALPHA); - } - alpha_faces.push_back(facep); + facep->setState(LLFace::FULLBRIGHT); } - } - else - { - if (drawablep->isState(LLDrawable::REBUILD_VOLUME)) + + if (vobj->mTextureAnimp && vobj->mTexAnimMode) { - facep->mLastUpdateTime = gFrameTimeSeconds; + if (vobj->mTextureAnimp->mFace <= -1) + { + S32 face; + for (face = 0; face < vobj->getNumTEs(); face++) + { + LLFace * facep = drawablep->getFace(face); + if (facep) + { + facep->setState(LLFace::TEXTURE_ANIM); + } + } + } + else if (vobj->mTextureAnimp->mFace < vobj->getNumTEs()) + { + LLFace * facep = drawablep->getFace(vobj->mTextureAnimp->mFace); + if (facep) + { + facep->setState(LLFace::TEXTURE_ANIM); + } + } } - if (gPipeline.canUseWindLightShadersOnObjects() - && LLPipeline::sRenderBump) + if (type == LLDrawPool::POOL_ALPHA) { - if (te->getBumpmap()) - { //needs normal + binormal - bump_faces.push_back(facep); - } - else if (te->getShiny() || !te->getFullbright()) - { //needs normal + if (facep->canRenderAsMask()) + { //can be treated as alpha mask simple_faces.push_back(facep); } - else - { //doesn't need normal - facep->setState(LLFace::FULLBRIGHT); - fullbright_faces.push_back(facep); + else + { + if (te->getColor().mV[3] > 0.f) + { //only treat as alpha in the pipeline if < 100% transparent + drawablep->setState(LLDrawable::HAS_ALPHA); + } + alpha_faces.push_back(facep); } } else { - if (te->getBumpmap() && LLPipeline::sRenderBump) - { //needs normal + binormal - bump_faces.push_back(facep); + if (drawablep->isState(LLDrawable::REBUILD_VOLUME)) + { + facep->mLastUpdateTime = gFrameTimeSeconds; } - else if ((te->getShiny() && LLPipeline::sRenderBump) || - !(te->getFullbright() || bake_sunlight)) - { //needs normal - simple_faces.push_back(facep); + + if (gPipeline.canUseWindLightShadersOnObjects() + && LLPipeline::sRenderBump) + { + if (te->getBumpmap()) + { //needs normal + binormal + bump_faces.push_back(facep); + } + else if (te->getShiny() || !te->getFullbright()) + { //needs normal + simple_faces.push_back(facep); + } + else + { //doesn't need normal + facep->setState(LLFace::FULLBRIGHT); + fullbright_faces.push_back(facep); + } } - else - { //doesn't need normal - facep->setState(LLFace::FULLBRIGHT); - fullbright_faces.push_back(facep); + else + { + if (te->getBumpmap() && LLPipeline::sRenderBump) + { //needs normal + binormal + bump_faces.push_back(facep); + } + else if ((te->getShiny() && LLPipeline::sRenderBump) || + !(te->getFullbright() || bake_sunlight)) + { //needs normal + simple_faces.push_back(facep); + } + else + { //doesn't need normal + facep->setState(LLFace::FULLBRIGHT); + fullbright_faces.push_back(facep); + } } } } + else + { //face has no renderable geometry + facep->clearVertexBuffer(); + } } - else - { //face has no renderable geometry - facep->clearVertexBuffer(); - } - } - if (is_rigged) - { - drawablep->setState(LLDrawable::RIGGED); - } - else - { - drawablep->clearState(LLDrawable::RIGGED); + if (is_rigged) + { + drawablep->setState(LLDrawable::RIGGED); + } + else + { + drawablep->clearState(LLDrawable::RIGGED); + } } } @@ -4564,15 +4663,15 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) } } -static LLFastTimer::DeclareTimer FTM_VOLUME_GEOM("Volume Geometry"); -static LLFastTimer::DeclareTimer FTM_VOLUME_GEOM_PARTIAL("Terse Rebuild"); void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) { llassert(group); if (group && group->isState(LLSpatialGroup::MESH_DIRTY) && !group->isState(LLSpatialGroup::GEOM_DIRTY)) { - LLFastTimer tm(FTM_VOLUME_GEOM); + LLFastTimer ftm(FTM_REBUILD_VOLUME_VB); + LLFastTimer t(FTM_REBUILD_VOLUME_GEN_DRAW_INFO); //make sure getgeometryvolume shows up in the right place in timers + S32 num_mapped_veretx_buffer = LLVertexBuffer::sMappedCount ; group->mBuilt = 1.f; @@ -4581,14 +4680,18 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter) { - LLFastTimer t(FTM_VOLUME_GEOM_PARTIAL); LLDrawable* drawablep = *drawable_iter; - if (!drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) ) + if (!drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) && !drawablep->isState(LLDrawable::RIGGED) ) { LLVOVolume* vobj = drawablep->getVOVolume(); vobj->preRebuild(); + if (drawablep->isState(LLDrawable::ANIMATED_CHILD)) + { + vobj->updateRelativeXform(true); + } + LLVolume* volume = vobj->getVolume(); for (S32 i = 0; i < drawablep->getNumFaces(); ++i) { @@ -4598,6 +4701,7 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) LLVertexBuffer* buff = face->getVertexBuffer(); if (buff) { + llassert(!face->isState(LLFace::RIGGED)); face->getGeometryVolume(*volume, face->getTEOffset(), vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), face->getGeomIndex()); @@ -4608,6 +4712,12 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) } } } + + if (drawablep->isState(LLDrawable::ANIMATED_CHILD)) + { + vobj->updateRelativeXform(); + } + drawablep->clearState(LLDrawable::REBUILD_ALL); } @@ -4636,10 +4746,13 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) for (S32 i = 0; i < drawablep->getNumFaces(); ++i) { LLFace* face = drawablep->getFace(i); - LLVertexBuffer* buff = face->getVertexBuffer(); - if (face && buff && buff->isLocked()) + if (face) { - buff->flush(); + LLVertexBuffer* buff = face->getVertexBuffer(); + if (buff && buff->isLocked()) + { + buff->flush(); + } } } } @@ -4648,7 +4761,7 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) group->clearState(LLSpatialGroup::MESH_DIRTY | LLSpatialGroup::NEW_DRAWINFO); } - llassert(!group || !group->isState(LLSpatialGroup::NEW_DRAWINFO)); +// llassert(!group || !group->isState(LLSpatialGroup::NEW_DRAWINFO)); } struct CompareBatchBreakerModified @@ -4674,8 +4787,20 @@ struct CompareBatchBreakerModified } }; +static LLFastTimer::DeclareTimer FTM_GEN_DRAW_INFO_SORT("Draw Info Face Sort"); +static LLFastTimer::DeclareTimer FTM_GEN_DRAW_INFO_FACE_SIZE("Face Sizing"); +static LLFastTimer::DeclareTimer FTM_GEN_DRAW_INFO_ALLOCATE("Allocate VB"); +static LLFastTimer::DeclareTimer FTM_GEN_DRAW_INFO_FIND_VB("Find VB"); +static LLFastTimer::DeclareTimer FTM_GEN_DRAW_INFO_RESIZE_VB("Resize VB"); + + + + + void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::vector<LLFace*>& faces, BOOL distance_sort, BOOL batch_textures) { + LLFastTimer t(FTM_REBUILD_VOLUME_GEN_DRAW_INFO); + U32 buffer_usage = group->mBufferUsage; #if LL_DARWIN @@ -4693,15 +4818,18 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: U32 max_vertices = (gSavedSettings.getS32("RenderMaxVBOSize")*1024)/LLVertexBuffer::calcVertexSize(group->mSpatialPartition->mVertexDataMask); max_vertices = llmin(max_vertices, (U32) 65535); - if (!distance_sort) - { - //sort faces by things that break batches - std::sort(faces.begin(), faces.end(), CompareBatchBreakerModified()); - } - else { - //sort faces by distance - std::sort(faces.begin(), faces.end(), LLFace::CompareDistanceGreater()); + LLFastTimer t(FTM_GEN_DRAW_INFO_SORT); + if (!distance_sort) + { + //sort faces by things that break batches + std::sort(faces.begin(), faces.end(), CompareBatchBreakerModified()); + } + else + { + //sort faces by distance + std::sort(faces.begin(), faces.end(), LLFace::CompareDistanceGreater()); + } } bool hud_group = group->isHUDGroup() ; @@ -4766,57 +4894,86 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: std::vector<LLViewerTexture*> texture_list; - if (batch_textures) { - U8 cur_tex = 0; - facep->setTextureIndex(cur_tex); - texture_list.push_back(tex); - - //if (can_batch_texture(facep)) + LLFastTimer t(FTM_GEN_DRAW_INFO_FACE_SIZE); + if (batch_textures) { - while (i != faces.end()) + U8 cur_tex = 0; + facep->setTextureIndex(cur_tex); + texture_list.push_back(tex); + + //if (can_batch_texture(facep)) { - facep = *i; - if (facep->getTexture() != tex) + while (i != faces.end()) { - if (distance_sort) - { //textures might be out of order, see if texture exists in current batch - bool found = false; - for (U32 tex_idx = 0; tex_idx < texture_list.size(); ++tex_idx) - { - if (facep->getTexture() == texture_list[tex_idx]) + facep = *i; + if (facep->getTexture() != tex) + { + if (distance_sort) + { //textures might be out of order, see if texture exists in current batch + bool found = false; + for (U32 tex_idx = 0; tex_idx < texture_list.size(); ++tex_idx) { - cur_tex = tex_idx; - found = true; - break; + if (facep->getTexture() == texture_list[tex_idx]) + { + cur_tex = tex_idx; + found = true; + break; + } } - } - if (!found) + if (!found) + { + cur_tex = texture_list.size(); + } + } + else { - cur_tex = texture_list.size(); + cur_tex++; } - } - else - { - cur_tex++; - } - if (!can_batch_texture(facep)) - { //face is bump mapped or has an animated texture matrix -- can't - //batch more than 1 texture at a time - break; + if (!can_batch_texture(facep)) + { //face is bump mapped or has an animated texture matrix -- can't + //batch more than 1 texture at a time + break; + } + + if (cur_tex >= texture_index_channels) + { //cut batches when index channels are depleted + break; + } + + tex = facep->getTexture(); + + texture_list.push_back(tex); } - if (cur_tex >= texture_index_channels) - { //cut batches when index channels are depleted + if (geom_count + facep->getGeomCount() > max_vertices) + { //cut batches on geom count too big break; } - tex = facep->getTexture(); + ++i; + index_count += facep->getIndicesCount(); + geom_count += facep->getGeomCount(); - texture_list.push_back(tex); + facep->setTextureIndex(cur_tex); } + } + + tex = texture_list[0]; + } + else + { + while (i != faces.end() && + (LLPipeline::sTextureBindTest || (distance_sort || (*i)->getTexture() == tex))) + { + facep = *i; + + + //face has no texture index + facep->mDrawInfo = NULL; + facep->setTextureIndex(255); if (geom_count + facep->getGeomCount() > max_vertices) { //cut batches on geom count too big @@ -4826,69 +4983,18 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: ++i; index_count += facep->getIndicesCount(); geom_count += facep->getGeomCount(); - - facep->setTextureIndex(cur_tex); } } - - tex = texture_list[0]; } - else - { - while (i != faces.end() && - (LLPipeline::sTextureBindTest || (distance_sort || (*i)->getTexture() == tex))) - { - facep = *i; - - //face has no texture index - facep->mDrawInfo = NULL; - facep->setTextureIndex(255); - - if (geom_count + facep->getGeomCount() > max_vertices) - { //cut batches on geom count too big - break; - } - - ++i; - index_count += facep->getIndicesCount(); - geom_count += facep->getGeomCount(); - } - } - - //create/delete/resize vertex buffer if needed + //create vertex buffer LLVertexBuffer* buffer = NULL; - { //try to find a buffer to reuse - LLSpatialGroup::buffer_texture_map_t::iterator found_iter = group->mBufferMap[mask].find(*face_iter); - - if (found_iter != group->mBufferMap[mask].end()) - { - if ((U32) buffer_index < found_iter->second.size()) - { - buffer = found_iter->second[buffer_index]; - } - } - } - - if (!buffer || !buffer->isWriteable()) - { //create new buffer if needed + { + LLFastTimer t(FTM_GEN_DRAW_INFO_ALLOCATE); buffer = createVertexBuffer(mask, buffer_usage); buffer->allocateBuffer(geom_count, index_count, TRUE); } - else - { //resize pre-existing buffer - if (LLVertexBuffer::sEnableVBOs && buffer->getUsage() != buffer_usage || - buffer->getTypeMask() != mask) - { - buffer = createVertexBuffer(mask, buffer_usage); - buffer->allocateBuffer(geom_count, index_count, TRUE); - } - else - { - buffer->resizeBuffer(geom_count, index_count); - } - } group->mGeometryBytes += buffer->getSize() + buffer->getIndicesSize(); @@ -4922,10 +5028,22 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: LLVOVolume* vobj = drawablep->getVOVolume(); LLVolume* volume = vobj->getVolume(); + if (drawablep->isState(LLDrawable::ANIMATED_CHILD)) + { + vobj->updateRelativeXform(true); + } + U32 te_idx = facep->getTEOffset(); + llassert(!facep->isState(LLFace::RIGGED)); + facep->getGeometryVolume(*volume, te_idx, - vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), index_offset); + vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), index_offset,true); + + if (drawablep->isState(LLDrawable::ANIMATED_CHILD)) + { + vobj->updateRelativeXform(false); + } } } @@ -5089,6 +5207,7 @@ void LLGeometryManager::addGeometryCount(LLSpatialGroup* group, U32 &vertex_coun mFaceList.clear(); //for each drawable + for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter) { LLDrawable* drawablep = *drawable_iter; @@ -5109,17 +5228,21 @@ void LLGeometryManager::addGeometryCount(LLSpatialGroup* group, U32 &vertex_coun //sum up face verts and indices drawablep->updateFaceSize(i); LLFace* facep = drawablep->getFace(i); - if (facep->hasGeometry() && facep->getPixelArea() > FORCE_CULL_AREA) + if (facep) { - vertex_count += facep->getGeomCount(); - index_count += facep->getIndicesCount(); - llassert(facep->getIndicesCount() < 65536); - //remember face (for sorting) - mFaceList.push_back(facep); - } - else - { - facep->clearVertexBuffer(); + if (facep->hasGeometry() && facep->getPixelArea() > FORCE_CULL_AREA && + facep->getGeomCount() + vertex_count <= 65536) + { + vertex_count += facep->getGeomCount(); + index_count += facep->getIndicesCount(); + + //remember face (for sorting) + mFaceList.push_back(facep); + } + else + { + facep->clearVertexBuffer(); + } } } } diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index 3cf434dc26..c4505b4bd8 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -79,7 +79,7 @@ public: virtual bool isVolumeGlobal() const = 0; // Are we in global space? virtual bool isActive() const = 0; // Is this object currently active? virtual const LLMatrix4& getWorldMatrix(LLXformMatrix* xform) const = 0; - virtual void updateRelativeXform() = 0; + virtual void updateRelativeXform(bool force_identity = false) = 0; virtual U32 getID() const = 0; virtual void preRebuild() = 0; }; @@ -203,7 +203,7 @@ public: LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status); - void updateRelativeXform(); + void updateRelativeXform(bool force_identity = false); /*virtual*/ BOOL updateGeometry(LLDrawable *drawable); /*virtual*/ void updateFaceSize(S32 idx); /*virtual*/ BOOL updateLOD(); diff --git a/indra/newview/llvowater.cpp b/indra/newview/llvowater.cpp index cd78157944..942eff6171 100644 --- a/indra/newview/llvowater.cpp +++ b/indra/newview/llvowater.cpp @@ -146,6 +146,10 @@ BOOL LLVOWater::updateGeometry(LLDrawable *drawable) drawable->addFace(poolp, NULL); } face = drawable->getFace(0); + if (!face) + { + return TRUE; + } // LLVector2 uvs[4]; // LLVector3 vtx[4]; diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index ed636a40b2..49c4f37871 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -51,6 +51,10 @@ // newview includes #include "llagent.h" #include "llagentcamera.h" +#include "llappviewer.h" +#include "lltexturecache.h" +#include "lltexturefetch.h" +#include "llimageworker.h" #include "lldrawable.h" #include "lldrawpoolalpha.h" #include "lldrawpoolavatar.h" @@ -264,6 +268,7 @@ std::string gPoolNames[] = void drawBox(const LLVector3& c, const LLVector3& r); void drawBoxOutline(const LLVector3& pos, const LLVector3& size); U32 nhpo2(U32 v); +LLVertexBuffer* ll_create_cube_vb(U32 type_mask, U32 usage); glh::matrix4f glh_copy_matrix(F32* src) { @@ -403,9 +408,11 @@ LLPipeline::LLPipeline() : mInitialized(FALSE), mVertexShadersEnabled(FALSE), mVertexShadersLoaded(0), + mTransformFeedbackPrimitives(0), mRenderDebugFeatureMask(0), mRenderDebugMask(0), mOldRenderDebugMask(0), + mMeshDirtyQueryObject(0), mGroupQ1Locked(false), mGroupQ2Locked(false), mResetVertexBuffers(false), @@ -504,6 +511,11 @@ void LLPipeline::init() mSpotLightFade[i] = 1.f; } + if (mCubeVB.isNull()) + { + mCubeVB = ll_create_cube_vb(LLVertexBuffer::MAP_VERTEX, GL_STATIC_DRAW_ARB); + } + mDeferredVB = new LLVertexBuffer(DEFERRED_VB_MASK, 0); mDeferredVB->allocateBuffer(8, 0, true); setLightingDetail(-1); @@ -693,6 +705,12 @@ void LLPipeline::destroyGL() { LLVertexBuffer::sEnableVBOs = FALSE; } + + if (mMeshDirtyQueryObject) + { + glDeleteQueriesARB(1, &mMeshDirtyQueryObject); + mMeshDirtyQueryObject = 0; + } } static LLFastTimer::DeclareTimer FTM_RESIZE_SCREEN_TEXTURE("Resize Screen Texture"); @@ -942,6 +960,7 @@ void LLPipeline::refreshCachedSettings() LLPipeline::sUseOcclusion = (!gUseWireframe + && LLGLSLShader::sNoFixedFunction && LLFeatureManager::getInstance()->isFeatureAvailable("UseOcclusion") && gSavedSettings.getBOOL("UseOcclusion") && gGLManager.mHasOcclusionQuery) ? 2 : 0; @@ -1030,13 +1049,13 @@ void LLPipeline::releaseGLBuffers() if (mNoiseMap) { - LLImageGL::deleteTextures(1, &mNoiseMap); + LLImageGL::deleteTextures(LLTexUnit::TT_TEXTURE, GL_RGB16F_ARB, 0, 1, &mNoiseMap); mNoiseMap = 0; } if (mTrueNoiseMap) { - LLImageGL::deleteTextures(1, &mTrueNoiseMap); + LLImageGL::deleteTextures(LLTexUnit::TT_TEXTURE, GL_RGB16F_ARB, 0, 1, &mTrueNoiseMap); mTrueNoiseMap = 0; } @@ -1060,7 +1079,7 @@ void LLPipeline::releaseLUTBuffers() { if (mLightFunc) { - LLImageGL::deleteTextures(1, &mLightFunc); + LLImageGL::deleteTextures(LLTexUnit::TT_TEXTURE, GL_R8, 0, 1, &mLightFunc); mLightFunc = 0; } } @@ -1138,7 +1157,7 @@ void LLPipeline::createGLBuffers() noise[i].mV[2] = ll_frand()*scaler+1.f-scaler/2.f; } - LLImageGL::generateTextures(1, &mNoiseMap); + LLImageGL::generateTextures(LLTexUnit::TT_TEXTURE, GL_RGB16F_ARB, 1, &mNoiseMap); gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mNoiseMap); LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_RGB16F_ARB, noiseRes, noiseRes, GL_RGB, GL_FLOAT, noise, false); @@ -1154,7 +1173,7 @@ void LLPipeline::createGLBuffers() noise[i] = ll_frand()*2.0-1.0; } - LLImageGL::generateTextures(1, &mTrueNoiseMap); + LLImageGL::generateTextures(LLTexUnit::TT_TEXTURE, GL_RGB16F_ARB, 1, &mTrueNoiseMap); gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mTrueNoiseMap); LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_RGB16F_ARB, noiseRes, noiseRes, GL_RGB,GL_FLOAT, noise, false); gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); @@ -1210,7 +1229,7 @@ void LLPipeline::createLUTBuffers() } } - LLImageGL::generateTextures(1, &mLightFunc); + LLImageGL::generateTextures(LLTexUnit::TT_TEXTURE, GL_R8, 1, &mLightFunc); gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mLightFunc); LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_R8, lightResX, lightResY, GL_RED, GL_UNSIGNED_BYTE, ls, false); gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); @@ -1820,6 +1839,16 @@ void LLPipeline::updateMovedList(LLDrawable::drawable_vector_t& moved_list) if (done) { drawablep->clearState(LLDrawable::ON_MOVE_LIST); + if (drawablep->isState(LLDrawable::ANIMATED_CHILD)) + { //will likely not receive any future world matrix updates + // -- this keeps attachments from getting stuck in space and falling off your avatar + drawablep->clearState(LLDrawable::ANIMATED_CHILD); + markRebuild(drawablep, LLDrawable::REBUILD_VOLUME, TRUE); + if (drawablep->getVObj()) + { + drawablep->getVObj()->dirtySpatialGroup(TRUE); + } + } iter = moved_list.erase(curiter); } } @@ -2214,8 +2243,6 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl gGLLastMatrix = NULL; gGL.loadMatrix(gGLLastModelView); - - LLVertexBuffer::unbind(); LLGLDisable blend(GL_BLEND); LLGLDisable test(GL_ALPHA_TEST); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); @@ -2259,7 +2286,16 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl { //if no shader is currently bound, use the occlusion shader instead of fixed function if we can // (shadow render uses a special shader that clamps to clip planes) bound_shader = true; - gOcclusionProgram.bind(); + gOcclusionCubeProgram.bind(); + } + + if (sUseOcclusion > 1) + { + if (mCubeVB.isNull()) + { //cube VB will be used for issuing occlusion queries + mCubeVB = ll_create_cube_vb(LLVertexBuffer::MAP_VERTEX, GL_STATIC_DRAW_ARB); + } + mCubeVB->setBuffer(LLVertexBuffer::MAP_VERTEX); } for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); @@ -2291,7 +2327,7 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl if (bound_shader) { - gOcclusionProgram.unbind(); + gOcclusionCubeProgram.unbind(); } camera.disableUserClipPlane(); @@ -2424,14 +2460,20 @@ void LLPipeline::doOcclusion(LLCamera& camera) { if (LLPipeline::sShadowRender) { - gDeferredShadowProgram.bind(); + gDeferredShadowCubeProgram.bind(); } else { - gOcclusionProgram.bind(); + gOcclusionCubeProgram.bind(); } } + if (mCubeVB.isNull()) + { //cube VB will be used for issuing occlusion queries + mCubeVB = ll_create_cube_vb(LLVertexBuffer::MAP_VERTEX, GL_STATIC_DRAW_ARB); + } + mCubeVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + for (LLCullResult::sg_list_t::iterator iter = sCull->beginOcclusionGroups(); iter != sCull->endOcclusionGroups(); ++iter) { LLSpatialGroup* group = *iter; @@ -2443,11 +2485,11 @@ void LLPipeline::doOcclusion(LLCamera& camera) { if (LLPipeline::sShadowRender) { - gDeferredShadowProgram.unbind(); + gDeferredShadowCubeProgram.unbind(); } else { - gOcclusionProgram.unbind(); + gOcclusionCubeProgram.unbind(); } } @@ -2466,6 +2508,8 @@ BOOL LLPipeline::updateDrawableGeom(LLDrawable* drawablep, BOOL priority) return update_complete; } +static LLFastTimer::DeclareTimer FTM_SEED_VBO_POOLS("Seed VBO Pool"); + void LLPipeline::updateGL() { while (!LLGLUpdate::sGLQ.empty()) @@ -2475,6 +2519,11 @@ void LLPipeline::updateGL() glu->mInQ = FALSE; LLGLUpdate::sGLQ.pop_front(); } + + { //seed VBO Pools + LLFastTimer t(FTM_SEED_VBO_POOLS); + LLVertexBuffer::seedPools(); + } } void LLPipeline::rebuildPriorityGroups() @@ -2838,6 +2887,11 @@ void LLPipeline::processPartitionQ() mPartitionQ.clear(); } +void LLPipeline::markMeshDirty(LLSpatialGroup* group) +{ + mMeshDirtyGroup.push_back(group); +} + void LLPipeline::markRebuild(LLSpatialGroup* group, BOOL priority) { LLMemType mt(LLMemType::MTYPE_PIPELINE); @@ -3189,7 +3243,11 @@ void renderScriptedBeacons(LLDrawable* drawablep) S32 count = drawablep->getNumFaces(); for (face_id = 0; face_id < count; face_id++) { - gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) ); + LLFace * facep = drawablep->getFace(face_id); + if (facep) + { + gPipeline.mHighlightFaces.push_back(facep); + } } } } @@ -3215,7 +3273,11 @@ void renderScriptedTouchBeacons(LLDrawable* drawablep) S32 count = drawablep->getNumFaces(); for (face_id = 0; face_id < count; face_id++) { - gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) ); + LLFace * facep = drawablep->getFace(face_id); + if (facep) + { + gPipeline.mHighlightFaces.push_back(facep); + } } } } @@ -3240,7 +3302,11 @@ void renderPhysicalBeacons(LLDrawable* drawablep) S32 count = drawablep->getNumFaces(); for (face_id = 0; face_id < count; face_id++) { - gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) ); + LLFace * facep = drawablep->getFace(face_id); + if (facep) + { + gPipeline.mHighlightFaces.push_back(facep); + } } } } @@ -3276,7 +3342,11 @@ void renderMOAPBeacons(LLDrawable* drawablep) S32 count = drawablep->getNumFaces(); for (face_id = 0; face_id < count; face_id++) { - gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) ); + LLFace * facep = drawablep->getFace(face_id); + if (facep) + { + gPipeline.mHighlightFaces.push_back(facep); + } } } } @@ -3301,7 +3371,11 @@ void renderParticleBeacons(LLDrawable* drawablep) S32 count = drawablep->getNumFaces(); for (face_id = 0; face_id < count; face_id++) { - gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) ); + LLFace * facep = drawablep->getFace(face_id); + if (facep) + { + gPipeline.mHighlightFaces.push_back(facep); + } } } } @@ -3319,7 +3393,11 @@ void renderSoundHighlights(LLDrawable* drawablep) S32 count = drawablep->getNumFaces(); for (face_id = 0; face_id < count; face_id++) { - gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) ); + LLFace * facep = drawablep->getFace(face_id); + if (facep) + { + gPipeline.mHighlightFaces.push_back(facep); + } } } } @@ -3350,21 +3428,7 @@ void LLPipeline::postSort(LLCamera& camera) rebuildPriorityGroups(); llpushcallstacks ; - const S32 bin_count = 1024*8; - - static LLCullResult::drawinfo_list_t alpha_bins[bin_count]; - static U32 bin_size[bin_count]; - - //clear one bin per frame to avoid memory bloat - static S32 clear_idx = 0; - clear_idx = (1+clear_idx)%bin_count; - alpha_bins[clear_idx].clear(); - - for (U32 j = 0; j < bin_count; j++) - { - bin_size[j] = 0; - } - + //build render map for (LLCullResult::sg_list_t::iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i) { @@ -3436,11 +3500,43 @@ void LLPipeline::postSort(LLCamera& camera) } } } + + //flush particle VB + LLVOPartGroup::sVB->flush(); + + /*bool use_transform_feedback = gTransformPositionProgram.mProgramObject && !mMeshDirtyGroup.empty(); + + if (use_transform_feedback) + { //place a query around potential transform feedback code for synchronization + mTransformFeedbackPrimitives = 0; + + if (!mMeshDirtyQueryObject) + { + glGenQueriesARB(1, &mMeshDirtyQueryObject); + } + + glBeginQueryARB(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, mMeshDirtyQueryObject); + }*/ + + //pack vertex buffers for groups that chose to delay their updates + for (LLSpatialGroup::sg_vector_t::iterator iter = mMeshDirtyGroup.begin(); iter != mMeshDirtyGroup.end(); ++iter) + { + (*iter)->rebuildMesh(); + } + + /*if (use_transform_feedback) + { + glEndQueryARB(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN); + }*/ + + mMeshDirtyGroup.clear(); + if (!sShadowRender) { std::sort(sCull->beginAlphaGroups(), sCull->endAlphaGroups(), LLSpatialGroup::CompareDepthGreater()); } + llpushcallstacks ; // only render if the flag is set. The flag is only set if we are in edit mode or the toggle is set in the menus if (LLFloaterReg::instanceVisible("beacons") && !sShadowRender) @@ -3514,7 +3610,11 @@ void LLPipeline::postSort(LLCamera& camera) { if (object->mDrawable) { - gPipeline.mSelectedFaces.push_back(object->mDrawable->getFace(te)); + LLFace * facep = object->mDrawable->getFace(te); + if (facep) + { + gPipeline.mSelectedFaces.push_back(facep); + } } return true; } @@ -3523,6 +3623,33 @@ void LLPipeline::postSort(LLCamera& camera) } } + /*static LLFastTimer::DeclareTimer FTM_TRANSFORM_WAIT("Transform Fence"); + static LLFastTimer::DeclareTimer FTM_TRANSFORM_DO_WORK("Transform Work"); + if (use_transform_feedback) + { //using transform feedback, wait for transform feedback to complete + LLFastTimer t(FTM_TRANSFORM_WAIT); + + S32 done = 0; + //glGetQueryivARB(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, GL_CURRENT_QUERY, &count); + + glGetQueryObjectivARB(mMeshDirtyQueryObject, GL_QUERY_RESULT_AVAILABLE, &done); + + while (!done) + { + { + LLFastTimer t(FTM_TRANSFORM_DO_WORK); + F32 max_time = llmin(gFrameIntervalSeconds*10.f, 1.f); + //do some useful work while we wait + LLAppViewer::getTextureCache()->update(max_time); // unpauses the texture cache thread + LLAppViewer::getImageDecodeThread()->update(max_time); // unpauses the image thread + LLAppViewer::getTextureFetch()->update(max_time); // unpauses the texture fetch thread + } + glGetQueryObjectivARB(mMeshDirtyQueryObject, GL_QUERY_RESULT_AVAILABLE, &done); + } + + mTransformFeedbackPrimitives = 0; + }*/ + //LLSpatialGroup::sNoDelete = FALSE; llpushcallstacks ; } @@ -6219,7 +6346,10 @@ void LLPipeline::resetVertexBuffers(LLDrawable* drawable) for (S32 i = 0; i < drawable->getNumFaces(); i++) { LLFace* facep = drawable->getFace(i); - facep->clearVertexBuffer(); + if (facep) + { + facep->clearVertexBuffer(); + } } } @@ -6237,6 +6367,8 @@ void LLPipeline::doResetVertexBuffers() mResetVertexBuffers = false; + mCubeVB = NULL; + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); iter != LLWorld::getInstance()->getRegionList().end(); ++iter) { @@ -6255,11 +6387,15 @@ void LLPipeline::doResetVertexBuffers() gSky.resetVertexBuffers(); + LLVOPartGroup::destroyGL(); + LLVertexBuffer::cleanupClass(); //delete all name pool caches LLGLNamePool::cleanupPools(); + + if (LLVertexBuffer::sGLCount > 0) { llwarns << "VBO wipe failed -- " << LLVertexBuffer::sGLCount << " buffers remaining." << llendl; @@ -6279,6 +6415,8 @@ void LLPipeline::doResetVertexBuffers() LLPipeline::sTextureBindTest = gSavedSettings.getBOOL("RenderDebugTextureBind"); LLVertexBuffer::initClass(LLVertexBuffer::sEnableVBOs, LLVertexBuffer::sDisableVBOMapping); + + LLVOPartGroup::restoreGL(); } void LLPipeline::renderObjects(U32 type, U32 mask, BOOL texture, BOOL batch_texture) @@ -7466,12 +7604,17 @@ void LLPipeline::renderDeferredLighting() std::list<LLVector4> light_colors; LLVertexBuffer::unbind(); - LLVector4a* v = (LLVector4a*) vert.get(); { bindDeferredShader(gDeferredLightProgram); - mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + + if (mCubeVB.isNull()) + { + mCubeVB = ll_create_cube_vb(LLVertexBuffer::MAP_VERTEX, GL_STATIC_DRAW_ARB); + } + mCubeVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + LLGLDepthTest depth(GL_TRUE, GL_FALSE); for (LLDrawable::drawable_set_t::iterator iter = mLights.begin(); iter != mLights.end(); ++iter) { @@ -7517,25 +7660,7 @@ void LLPipeline::renderDeferredLighting() } sVisibleLightCount++; - - glh::vec3f tc(c); - mat.mult_matrix_vec(tc); - - //vertex positions are encoded so the 3 bits of their vertex index - //correspond to their axis facing, with bit position 3,2,1 matching - //axis facing x,y,z, bit set meaning positive facing, bit clear - //meaning negative facing - mDeferredVB->getVertexStrider(vert); - v[0].set(c[0]-s,c[1]-s,c[2]-s); // 0 - 0000 - v[1].set(c[0]-s,c[1]-s,c[2]+s); // 1 - 0001 - v[2].set(c[0]-s,c[1]+s,c[2]-s); // 2 - 0010 - v[3].set(c[0]-s,c[1]+s,c[2]+s); // 3 - 0011 - - v[4].set(c[0]+s,c[1]-s,c[2]-s); // 4 - 0100 - v[5].set(c[0]+s,c[1]-s,c[2]+s); // 5 - 0101 - v[6].set(c[0]+s,c[1]+s,c[2]-s); // 6 - 0110 - v[7].set(c[0]+s,c[1]+s,c[2]+s); // 7 - 0111 - + if (camera->getOrigin().mV[0] > c[0] + s + 0.2f || camera->getOrigin().mV[0] < c[0] - s - 0.2f || camera->getOrigin().mV[1] > c[1] + s + 0.2f || @@ -7553,16 +7678,13 @@ void LLPipeline::renderDeferredLighting() } LLFastTimer ftm(FTM_LOCAL_LIGHTS); - //glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], s*s); - gDeferredLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, tc.v); + gDeferredLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, c); gDeferredLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s*s); gDeferredLightProgram.uniform3fv(LLShaderMgr::DIFFUSE_COLOR, 1, col.mV); gDeferredLightProgram.uniform1f(LLShaderMgr::LIGHT_FALLOFF, volume->getLightFalloff()*0.5f); - //gGL.diffuseColor4f(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f); gGL.syncMatrices(); - mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); - glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, - GL_UNSIGNED_SHORT, get_box_fan_indices_ptr(camera, center)); + + mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, center)); stop_glerror(); } } @@ -7575,6 +7697,9 @@ void LLPipeline::renderDeferredLighting() continue; } + glh::vec3f tc(c); + mat.mult_matrix_vec(tc); + fullscreen_lights.push_back(LLVector4(tc.v[0], tc.v[1], tc.v[2], s*s)); light_colors.push_back(LLVector4(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f)); } @@ -7587,7 +7712,7 @@ void LLPipeline::renderDeferredLighting() LLGLDepthTest depth(GL_TRUE, GL_FALSE); bindDeferredShader(gDeferredSpotLightProgram); - mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + mCubeVB->setBuffer(LLVertexBuffer::MAP_VERTEX); gDeferredSpotLightProgram.enableTexture(LLShaderMgr::DEFERRED_PROJECTION); @@ -7605,36 +7730,17 @@ void LLPipeline::renderDeferredLighting() sVisibleLightCount++; - glh::vec3f tc(c); - mat.mult_matrix_vec(tc); - setupSpotLight(gDeferredSpotLightProgram, drawablep); LLColor3 col = volume->getLightColor(); - //vertex positions are encoded so the 3 bits of their vertex index - //correspond to their axis facing, with bit position 3,2,1 matching - //axis facing x,y,z, bit set meaning positive facing, bit clear - //meaning negative facing - mDeferredVB->getVertexStrider(vert); - v[0].set(c[0]-s,c[1]-s,c[2]-s); // 0 - 0000 - v[1].set(c[0]-s,c[1]-s,c[2]+s); // 1 - 0001 - v[2].set(c[0]-s,c[1]+s,c[2]-s); // 2 - 0010 - v[3].set(c[0]-s,c[1]+s,c[2]+s); // 3 - 0011 - - v[4].set(c[0]+s,c[1]-s,c[2]-s); // 4 - 0100 - v[5].set(c[0]+s,c[1]-s,c[2]+s); // 5 - 0101 - v[6].set(c[0]+s,c[1]+s,c[2]-s); // 6 - 0110 - v[7].set(c[0]+s,c[1]+s,c[2]+s); // 7 - 0111 - - gDeferredSpotLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, tc.v); + gDeferredSpotLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, c); gDeferredSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s*s); gDeferredSpotLightProgram.uniform3fv(LLShaderMgr::DIFFUSE_COLOR, 1, col.mV); gDeferredSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_FALLOFF, volume->getLightFalloff()*0.5f); gGL.syncMatrices(); - mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); - glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, - GL_UNSIGNED_SHORT, get_box_fan_indices_ptr(camera, center)); + + mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, center)); } gDeferredSpotLightProgram.disableTexture(LLShaderMgr::DEFERRED_PROJECTION); unbindDeferredShader(gDeferredSpotLightProgram); @@ -7666,8 +7772,6 @@ void LLPipeline::renderDeferredLighting() LLVector4 light[max_count]; LLVector4 col[max_count]; -// glVertexPointer(2, GL_FLOAT, 0, vert); - F32 far_z = 0.f; while (!fullscreen_lights.empty()) @@ -8324,7 +8428,7 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera if (use_shader) { - gDeferredShadowProgram.bind(); + gDeferredShadowCubeProgram.bind(); } updateCull(shadow_cam, result); @@ -8341,17 +8445,10 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera stop_glerror(); gGLLastMatrix = NULL; - { - //LLGLDepthTest depth(GL_TRUE); - //glClear(GL_DEPTH_BUFFER_BIT); - } - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); stop_glerror(); - //glCullFace(GL_FRONT); - LLVertexBuffer::unbind(); { @@ -8359,6 +8456,10 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera { //occlusion program is general purpose depth-only no-textures gOcclusionProgram.bind(); } + else + { + gDeferredShadowProgram.bind(); + } gGL.diffuseColor4f(1,1,1,1); gGL.setColorMask(false, false); @@ -8408,7 +8509,7 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera //glCullFace(GL_BACK); - gDeferredShadowProgram.bind(); + gDeferredShadowCubeProgram.bind(); gGLLastMatrix = NULL; gGL.loadMatrix(gGLModelView); doOcclusion(shadow_cam); diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 5c623fc9f2..6ae482fa06 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -163,6 +163,7 @@ public: void markRebuild(LLSpatialGroup* group, BOOL priority = FALSE); void markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags flag = LLDrawable::REBUILD_ALL, BOOL priority = FALSE); void markPartitionMove(LLDrawable* drawablep); + void markMeshDirty(LLSpatialGroup* group); //get the object between start and end that's closest to start. LLViewerObject* lineSegmentIntersectInWorld(const LLVector3& start, const LLVector3& end, @@ -544,6 +545,9 @@ public: //utility buffer for rendering post effects, gets abused by renderDeferredLighting LLPointer<LLVertexBuffer> mDeferredVB; + //utility buffer for rendering cubes, 8 vertices are corners of a cube [-1, 1] + LLPointer<LLVertexBuffer> mCubeVB; + //sun shadow map LLRenderTarget mShadow[6]; std::vector<LLVector3> mShadowFrustPoints[4]; @@ -595,6 +599,7 @@ public: BOOL mVertexShadersEnabled; S32 mVertexShadersLoaded; // 0 = no, 1 = yes, -1 = failed + U32 mTransformFeedbackPrimitives; //number of primitives expected to be generated by transform feedback protected: BOOL mRenderTypeEnabled[NUM_RENDER_TYPES]; std::stack<std::string> mRenderTypeEnableStack; @@ -652,6 +657,9 @@ protected: LLSpatialGroup::sg_vector_t mGroupQ1; //priority LLSpatialGroup::sg_vector_t mGroupQ2; // non-priority + LLSpatialGroup::sg_vector_t mMeshDirtyGroup; //groups that need rebuildMesh called + U32 mMeshDirtyQueryObject; + LLDrawable::drawable_list_t mPartitionQ; //drawables that need to update their spatial partition radius bool mGroupQ2Locked; diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index eabcc68916..7ca6820318 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -54,6 +54,8 @@ with the same filename but different name <texture name="Arrow_Down" file_name="widgets/Arrow_Down.png" preload="true" /> <texture name="Arrow_Up" file_name="widgets/Arrow_Up.png" preload="true" /> + <texture name="Arrow_Left" file_name="widgets/Arrow_Left.png" preload="true" /> + <texture name="Arrow_Right" file_name="widgets/Arrow_Right.png" preload="true" /> <texture name="AudioMute_Off" file_name="icons/AudioMute_Off.png" preload="false" /> <texture name="AudioMute_Over" file_name="icons/AudioMute_Over.png" preload="false" /> diff --git a/indra/newview/skins/default/textures/widgets/Arrow_Left.png b/indra/newview/skins/default/textures/widgets/Arrow_Left.png Binary files differnew file mode 100644 index 0000000000..a424282839 --- /dev/null +++ b/indra/newview/skins/default/textures/widgets/Arrow_Left.png diff --git a/indra/newview/skins/default/textures/widgets/Arrow_Right.png b/indra/newview/skins/default/textures/widgets/Arrow_Right.png Binary files differnew file mode 100644 index 0000000000..e32bee8f34 --- /dev/null +++ b/indra/newview/skins/default/textures/widgets/Arrow_Right.png diff --git a/indra/newview/skins/default/xui/da/floater_model_wizard.xml b/indra/newview/skins/default/xui/da/floater_model_wizard.xml deleted file mode 100644 index 8ad443581a..0000000000 --- a/indra/newview/skins/default/xui/da/floater_model_wizard.xml +++ /dev/null @@ -1,241 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<floater name="Model Wizard" title="UPLOAD MODEL WIZARD"> - <button label="5. Upload" name="upload_btn"/> - <button label="4. Review" name="review_btn"/> - <button label="3. Physics" name="physics2_btn"/> - <button label="3. Physics" name="physics_btn"/> - <button label="2. Optimize" name="optimize_btn"/> - <button label="1. Choose File" name="choose_file_btn"/> - <panel name="choose_file_panel"> - <panel name="header_panel"> - <text name="header_text"> - Upload Model - </text> - </panel> - <text name="description"> - This wizard will help you import mesh models to Second Life. First specify a file containing the model you wish to import. Second Life supports COLLADA (.dae) files. - </text> - <panel name="content"> - <text name="Cache location"> - Filename: - </text> - <button label="Browse..." label_selected="Browse..." name="browse"/> - <text name="dimensions"> - X: Y: Z: - </text> - <text name="dimension_dividers"> - | | - </text> - </panel> - </panel> - <panel name="optimize_panel"> - <panel name="header_panel"> - <text name="header_text"> - Optimize - </text> - </panel> - <text name="description"> - This wizard has optimized your model to improve performance. You may adjust the results of the optimization process bellow or click Next to continue. - </text> - <panel name="content"> - <text name="high_detail_text"> - Generate Level of Detail: High - </text> - <text name="medium_detail_text"> - Generate Level of Detail: Medium - </text> - <text name="low_detail_text"> - Generate Level of Detail: Low - </text> - <text name="lowest_detail_text"> - Generate Level of Detail: Lowest - </text> - </panel> - <panel name="content2"> - <text name="lod_label"> - Model Preview: - </text> - <combo_box name="preview_lod_combo2" tool_tip="LOD to view in preview render"> - <combo_item name="high"> - High - </combo_item> - <combo_item name="medium"> - Medium - </combo_item> - <combo_item name="low"> - Low - </combo_item> - <combo_item name="lowest"> - Lowest - </combo_item> - </combo_box> - <text name="streaming cost"> - Resource Cost: [COST] - </text> - <text name="dimensions"> - X: Y: Z: - </text> - <text name="dimension_dividers"> - | | - </text> - </panel> - </panel> - <panel name="physics_panel"> - <panel name="header_panel"> - <text name="header_text"> - Physics - </text> - </panel> - <text name="description"> - The wizard will create a physical shape, which determines how the object interacts with other objects and avatars. Set the slider to the detail level most appropriate for how your object will be used: - </text> - <panel name="content"> - <text name="streaming cost"> - Resource Cost: [COST] - </text> - </panel> - </panel> - <panel name="physics2_panel"> - <panel name="header_panel"> - <text name="header_text"> - Physics - </text> - </panel> - <text name="description"> - Preview the physics shape below then click Next to continue. To modify the physics shape, click the Back button. - </text> - <panel name="content"> - <text name="lod_label"> - Model Preview: - </text> - <combo_box name="preview_lod_combo3" tool_tip="LOD to view in preview render"> - <combo_item name="high"> - High - </combo_item> - <combo_item name="medium"> - Medium - </combo_item> - <combo_item name="low"> - Low - </combo_item> - <combo_item name="lowest"> - Lowest - </combo_item> - </combo_box> - <text name="dimensions"> - X: Y: Z: - </text> - <text name="dimension_dividers"> - | | - </text> - <text name="streaming cost"> - Resource Cost: [COST] - </text> - </panel> - </panel> - <panel name="review_panel"> - <panel name="header_panel"> - <text name="header_text"> - Review - </text> - </panel> - <text name="description"> - Review the details below then click. Upload to upload your model. Your L$ balance will be charged when you click Upload. - </text> - <panel name="content"> - <text name="lod_label"> - Model Preview: - </text> - <combo_box name="preview_lod_combo" tool_tip="LOD to view in preview render"> - <combo_item name="high"> - High - </combo_item> - <combo_item name="medium"> - Medium - </combo_item> - <combo_item name="low"> - Low - </combo_item> - <combo_item name="lowest"> - Lowest - </combo_item> - </combo_box> - <text name="dimensions"> - X: Y: Z: - </text> - <text name="dimension_dividers"> - | | - </text> - </panel> - <text name="streaming cost"> - Resource Cost: [COST] - </text> - <text name="physics cost"> - Physics Cost: [COST] - </text> - </panel> - <panel name="upload_panel"> - <panel name="header_panel"> - <text name="header_text"> - Upload Complete! - </text> - </panel> - <text name="description"> - Congratulations! Your model has been sucessfully uploaded. You will find the model in the Objects folder in your inventory. - </text> - </panel> - <button label="<< Back" name="back"/> - <button label="Next >>" name="next"/> - <button label="Upload" name="upload" tool_tip="Upload to simulator"/> - <button label="Cancel" name="cancel"/> - <button label="Close" name="close"/> - <spinner name="import_scale" value="1.0"/> - <string name="status_idle"> - Idle - </string> - <string name="status_reading_file"> - Loading... - </string> - <string name="status_generating_meshes"> - Generating Meshes... - </string> - <string name="status_vertex_number_overflow"> - Error: Vertex number is more than 65534, aborted! - </string> - <string name="high"> - High - </string> - <string name="medium"> - Medium - </string> - <string name="low"> - Low - </string> - <string name="lowest"> - Lowest - </string> - <string name="mesh_status_good"> - Ship it! - </string> - <string name="mesh_status_na"> - N/A - </string> - <string name="mesh_status_none"> - None - </string> - <string name="mesh_status_submesh_mismatch"> - Levels of detail have a different number of textureable faces. - </string> - <string name="mesh_status_mesh_mismatch"> - Levels of detail have a different number of mesh instances. - </string> - <string name="mesh_status_too_many_vertices"> - Level of detail has too many vertices. - </string> - <string name="mesh_status_missing_lod"> - Missing required level of detail. - </string> - <string name="layer_all"> - All - </string> -</floater> diff --git a/indra/newview/skins/default/xui/de/floater_model_wizard.xml b/indra/newview/skins/default/xui/de/floater_model_wizard.xml deleted file mode 100644 index ee26d51d32..0000000000 --- a/indra/newview/skins/default/xui/de/floater_model_wizard.xml +++ /dev/null @@ -1,208 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<floater name="Model Wizard" title="ASSISTENT ZUM HOCHLADEN VON MODELLEN"> - <button label="5. Hochladen" name="upload_btn"/> - <button label="4. Überprüfen" name="review_btn"/> - <button label="3. Physik" name="physics_btn"/> - <button label="2. Optimieren" name="optimize_btn"/> - <button label="1. Datei auswählen" name="choose_file_btn"/> - <panel name="choose_file_panel"> - <panel name="choose_file_header_panel"> - <text name="choose_file_header_text"> - Modelldatei auswählen - </text> - </panel> - <panel name="choose_file_content"> - <text name="advanced_users_text"> - Fortgeschrittene Benutzer: Wenn Sie bereits mit Tools zur Erstellung von 3D-Inhalten vertraut sind, können Sie den erweiterten Uploader verwenden. - </text> - <button label="Auf Erweitert wechseln" name="switch_to_advanced"/> - <text name="Cache location"> - Hochzuladende Modelldatei auswählen - </text> - <button label="Durchsuchen..." label_selected="Durchsuchen..." name="browse"/> - <text name="Model types"> - Second Life unterstützt COLLADA-Dateien (.dae). - </text> - <text name="dimensions"> - X Y Z - </text> - <text name="warning_label"> - ACHTUNG: - </text> - <text name="warning_text"> - Sie können den letzten Schritt nicht abschließen (Modell auf Second Life-Server hochladen). [secondlife:///app/floater/learn_more Weitere Infos], wie Sie Ihr Konto zum Hochladen von Netzmodellen einrichten. - </text> - </panel> - </panel> - <panel name="optimize_panel"> - <panel name="optimize_header_panel"> - <text name="optimize_header_text"> - Modell optimieren - </text> - </panel> - <text name="optimize_description"> - Wir haben das Modell auf Leistung optimiert. Sie können es bei Bedarf weiter anpassen. - </text> - <panel name="optimize_content"> - <text name="high_detail_text"> - Detailstufe generieren: hoch - </text> - <text name="medium_detail_text"> - Detailstufe generieren: mittel - </text> - <text name="low_detail_text"> - Detailstufe generieren: niedrig - </text> - <text name="lowest_detail_text"> - Detailstufe generieren: niedrigste - </text> - </panel> - <panel name="content2"> - <button label="Geometrie neu berechnen" name="recalculate_geometry_btn"/> - <text name="lod_label"> - Geometrievorschau - </text> - <combo_box name="preview_lod_combo" tool_tip="Detailstufe zur Anzeige in Vorschaudarstellung"> - <combo_item name="high"> - Viel Details - </combo_item> - <combo_item name="medium"> - Mittlere Details - </combo_item> - <combo_item name="low"> - Wenig Details - </combo_item> - <combo_item name="lowest"> - Wenigste Details - </combo_item> - </combo_box> - </panel> - </panel> - <panel name="physics_panel"> - <panel name="physics_header_panel"> - <text name="physics_header_text"> - Physik anpassen - </text> - </panel> - <text name="physics_description"> - Wir erstellen eine Form für die Außenhülle des Modells. Passen Sie die Detailstufe der Form wie für den beabsichtigten Zweck erforderlich an. - </text> - <panel name="physics_content"> - <button label="Physik neu berechnen" name="recalculate_physics_btn"/> - <button label="Neu berechnen..." name="recalculating_physics_btn"/> - <text name="lod_label"> - Physikvorschau - </text> - <combo_box name="preview_lod_combo2" tool_tip="Detailstufe zur Anzeige in Vorschaudarstellung"> - <combo_item name="high"> - Viel Details - </combo_item> - <combo_item name="medium"> - Mittlere Details - </combo_item> - <combo_item name="low"> - Wenig Details - </combo_item> - <combo_item name="lowest"> - Wenigste Details - </combo_item> - </combo_box> - </panel> - </panel> - <panel name="review_panel"> - <panel name="review_header_panel"> - <text name="review_header_text"> - Überprüfen - </text> - </panel> - <panel name="review_content"> - <text name="review_prim_equiv"> - Auswirkung auf Parzelle/Region: Prim-Äquivalenzwert [EQUIV] - </text> - <text name="review_fee"> - Die für das Hochladen anfallende Gebühr in Höhe von L$ [FEE] wird von Ihrem Konto abgebucht. - </text> - <text name="review_confirmation"> - Durch Klicken auf „Hochladen“ bestätigen Sie, dass Sie die erforderlichen Rechte für das im Modell enthaltene Material besitzen. - </text> - </panel> - </panel> - <panel name="upload_panel"> - <panel name="upload_header_panel"> - <text name="upload_header_text"> - Upload abgeschlossen - </text> - </panel> - <text name="model_uploaded_text"> - Ihr Modell wurde hochgeladen. - </text> - <text name="inventory_text"> - Sie finden das Modell im Objektordner Ihres Inventars. - </text> - <text name="charged_fee"> - Von Ihrem Konto wurden [FEE] L$ abgebucht. - </text> - </panel> - <button label="<< Zurück" name="back"/> - <button label="Weiter >>" name="next"/> - <button label="Gewichte und Gebühr berechnen >>" name="calculate"/> - <button label="Berechnen..." name="calculating"/> - <button label="Hochladen" name="upload" tool_tip="An Simulator hochladen"/> - <button label="Abbrechen" name="cancel"/> - <button label="Schließen" name="close"/> - <spinner name="import_scale" value="1,0"/> - <string name="status_idle"> - Inaktiv - </string> - <string name="status_parse_error"> - DAE-Parsing-Fehler. Details siehe Protokoll. - </string> - <string name="status_reading_file"> - Laden... - </string> - <string name="status_generating_meshes"> - Netze werden generiert... - </string> - <string name="status_vertex_number_overflow"> - Fehler: Anzahl von Vertices überschreitet 65534. Operation abgebrochen. - </string> - <string name="bad_element"> - Fehler: ungültiges Element. - </string> - <string name="high"> - Hoch - </string> - <string name="medium"> - Mittel - </string> - <string name="low"> - Niedrig - </string> - <string name="lowest"> - Niedrigste - </string> - <string name="mesh_status_good"> - Ausliefern - </string> - <string name="mesh_status_na"> - -- - </string> - <string name="mesh_status_none"> - Keine - </string> - <string name="mesh_status_submesh_mismatch"> - Detailstufen haben unterschiedliche Anzahl texturfähiger Flächen. - </string> - <string name="mesh_status_mesh_mismatch"> - Detailstufen haben unterschiedliche Anzahl von Netzinstanzen. - </string> - <string name="mesh_status_too_many_vertices"> - Detailstufe hat zu viele Vertices. - </string> - <string name="mesh_status_missing_lod"> - Erforderliche Detailstufe fehlt. - </string> - <string name="layer_all"> - Alle - </string> -</floater> diff --git a/indra/newview/skins/default/xui/en/floater_about.xml b/indra/newview/skins/default/xui/en/floater_about.xml index 060d889003..63eb87f27a 100644 --- a/indra/newview/skins/default/xui/en/floater_about.xml +++ b/indra/newview/skins/default/xui/en/floater_about.xml @@ -196,27 +196,26 @@ Dummy Name replaced at run time top="5" width="435" word_wrap="true"> - 3Dconnexion SDK Copyright (C) 1992-2007 3Dconnexion - APR Copyright (C) 2000-2004 The Apache Software Foundation - Collada DOM Copyright 2005 Sony Computer Entertainment Inc. - cURL Copyright (C) 1996-2002, Daniel Stenberg, (daniel@haxx.se) + 3Dconnexion SDK Copyright (C) 1992-2009 3Dconnexion + APR Copyright (C) 2011 The Apache Software Foundation + Collada DOM Copyright 2006 Sony Computer Entertainment Inc. + cURL Copyright (C) 1996-2010, Daniel Stenberg, (daniel@haxx.se) DBus/dbus-glib Copyright (C) 2002, 2003 CodeFactory AB / Copyright (C) 2003, 2004 Red Hat, Inc. expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd. - FreeType Copyright (C) 1996-2002, The FreeType Project (www.freetype.org). + FreeType Copyright (C) 1996-2002, 2006 David Turner, Robert Wilhelm, and Werner Lemberg. GL Copyright (C) 1999-2004 Brian Paul. GLOD Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University and David Luebke, Brenden Schubert, University of Virginia. google-perftools Copyright (c) 2005, Google Inc. Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited. jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW) jpeglib Copyright (C) 1991-1998, Thomas G. Lane. - ogg/vorbis Copyright (C) 2001, Xiphophorus - OpenSSL Copyright (C) 1998-2002 The OpenSSL Project. - PCRE Copyright (c) 1997-2008 University of Cambridge + ogg/vorbis Copyright (C) 2002, Xiphophorus + OpenSSL Copyright (C) 1998-2008 The OpenSSL Project. + PCRE Copyright (c) 1997-2012 University of Cambridge SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) xmlrpc-epi Copyright (C) 2000 Epinions, Inc. - zlib Copyright (C) 1995-2002 Jean-loup Gailly and Mark Adler. - google-perftools Copyright (c) 2005, Google Inc. + zlib Copyright (C) 1995-2012 Jean-loup Gailly and Mark Adler. Second Life Viewer uses Havok (TM) Physics. (c)Copyright 1999-2010 Havok.com Inc. (and its Licensors). All Rights Reserved. See www.havok.com for details. diff --git a/indra/newview/skins/default/xui/en/floater_about_land.xml b/indra/newview/skins/default/xui/en/floater_about_land.xml index fb123ec4d1..793a6e6fa1 100644 --- a/indra/newview/skins/default/xui/en/floater_about_land.xml +++ b/indra/newview/skins/default/xui/en/floater_about_land.xml @@ -1354,79 +1354,13 @@ Only large parcels can be listed in search. top="150" width="430" /> <combo_box - enabled="false" - height="23" - layout="topleft" - left="20" - top="194" - name="land category with adult" - visible="false" - width="140"> - <combo_box.item - label="Any Category" - name="item0" - value="any" /> - <combo_box.item - label="Linden Location" - name="item1" - value="linden" /> - <combo_box.item - label="Adult" - name="item2" - value="adult" /> - <combo_box.item - label="Arts & Culture" - name="item3" - value="arts" /> - <combo_box.item - label="Business" - name="item4" - value="store" /> - <combo_box.item - label="Educational" - name="item5" - value="educational" /> - <combo_box.item - label="Gaming" - name="item6" - value="game" /> - <combo_box.item - label="Hangout" - name="item7" - value="gather" /> - <combo_box.item - label="Newcomer Friendly" - name="item8" - value="newcomer" /> - <combo_box.item - label="Parks & Nature" - name="item9" - value="park" /> - <combo_box.item - label="Residential" - name="item10" - value="home" /> - <combo_box.item - label="Shopping" - name="item11" - value="shopping" /> - <combo_box.item - label="Rental" - name="item13" - value="rental" /> - <combo_box.item - label="Other" - name="item12" - value="other" /> - </combo_box> - <combo_box - enabled="false" + enabled="true" height="23" layout="topleft" left="20" top="194" name="land category" - visible="false" + visible="true" width="140"> <combo_box.item label="Any Category" @@ -1989,11 +1923,11 @@ Only large parcels can be listed in search. <check_box follows="top|left" height="16" - label="Have been age-verified [ESTATE_AGE_LIMIT]" + label="Are age 18 or older [ESTATE_AGE_LIMIT]" layout="topleft" left_delta="0" name="limit_age_verified" - tool_tip="Residents must be age verified to access this parcel. See the [SUPPORT_SITE] for more information." + tool_tip="Residents must be age 18 or older to access this parcel. See the [SUPPORT_SITE] for more information." top_pad="4" width="278" /> <check_box diff --git a/indra/newview/skins/default/xui/en/floater_autoreplace.xml b/indra/newview/skins/default/xui/en/floater_autoreplace.xml new file mode 100644 index 0000000000..0bfefc8abe --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_autoreplace.xml @@ -0,0 +1,289 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + border="true" + can_close="true" + can_minimize="true" + can_resize="false" + help_topic="autoreplace_settings" + save_rect="true" + height="455" + width="490" + name="autoreplace_floater" + title="Auto-Replace Settings"> + <check_box + bottom_delta="30" + left_delta="15" + height="16" + width="100" + follows="left|top" + label="Enable Auto-Replace" + name="autoreplace_enable" + tool_tip="As you enter chat text, replace any of the keywords entered with the corresponding replacement"/> + <view_border + top_pad="15" + left="2" + height="0" + width="491" + follows="left|top" + bevel_style="none" + border_thickness="1" + mouse_opaque="false" + name="divisor1"/> + <button + top_pad="10" + left="10" + height="22" + width="110" + enabled="true" + follows="left|top" + mouse_opaque="true" + halign="center" + scale_image="true" + name="autoreplace_import_list" + label="Import List..." + tool_tip="Load a previously exported list from a file."/> + <button + top_delta="0" + left_pad="10" + height="22" + width="110" + enabled="true" + follows="left|top" + mouse_opaque="true" + halign="center" + scale_image="true" + name="autoreplace_export_list" + label="Export List..." + tool_tip="Save the selected list to a file so you can share it."/> + <button + top_delta="0" + left_pad="10" + height="22" + width="110" + enabled="true" + follows="left|top" + mouse_opaque="true" + halign="center" + scale_image="true" + name="autoreplace_new_list" + label="New List..." + tool_tip="Create a new list."/> + <button + top_delta="0" + left_pad="10" + height="22" + width="110" + enabled="true" + follows="left|top" + mouse_opaque="true" + halign="center" + scale_image="true" + name="autoreplace_delete_list" + label="Delete List" + tool_tip="Delete the selected list."/> + <scroll_list + top_pad="10" + left="10" + height="100" + width="370" + follows="left|top" + column_padding="0" + draw_heading="false" + multi_select="false" + name="autoreplace_list_name" + search_column="0"> + </scroll_list> + <button + top_delta="23" + left_pad="10" + height="22" + width="90" + enabled="true" + follows="left|top" + mouse_opaque="true" + halign="center" + scale_image="true" + name="autoreplace_list_up" + image_overlay="Arrow_Up" + tool_tip="Move this list up in priority."/> + <button + top_pad="10" + left_delta="0" + height="22" + width="90" + enabled="true" + follows="left|top" + mouse_opaque="true" + halign="center" + scale_image="true" + name="autoreplace_list_down" + image_overlay="Arrow_Down" + tool_tip="Move this list down in priority."/> + <view_border + top_pad="36" + left="2" + height="0" + width="491" + follows="left|top" + bevel_style="none" + border_thickness="1" + mouse_opaque="false" + name="divisor2"/> + <scroll_list + top_pad="10" + left="10" + height="120" + width="370" + follows="left|top" + column_padding="0" + draw_heading="true" + multi_select="true" + name="autoreplace_list_replacements" + search_column="0"> + <scroll_list.columns + label="Keyword" + name="keyword" + relative_width="0.30" /> + <scroll_list.columns + label="Replacement" + name="replacement" + relative_width="0.70" /> + </scroll_list> + <button + top_delta="41" + left_pad="10" + height="22" + width="90" + enabled="true" + follows="left|top" + mouse_opaque="true" + halign="center" + scale_image="true" + name="autoreplace_add_entry" + label="Add..."/> + <button + top_pad="10" + left_delta="0" + height="22" + width="90" + enabled="true" + follows="left|top" + mouse_opaque="true" + halign="center" + scale_image="true" + name="autoreplace_delete_entry" + label="Remove"/> + <view_border + top_pad="38" + left="2" + height="0" + width="491" + follows="left|top" + bevel_style="none" + border_thickness="1" + mouse_opaque="false" + name="divisor3"/> + <text + type="string" + follows="left|top" + height="16" + layout="topleft" + left="10" + top_pad="13" + width="50"> + Keyword: + </text> + <line_editor + name="autoreplace_keyword" + follows="left|top" + height="23" + layout="topleft" + left="100" + max_length_bytes="255" + top_delta="-5" + width="150" + /> + <text + type="string" + follows="left|top" + height="16" + layout="topleft" + left="10" + right="90" + top_pad="10" + > + Replacement: + </text> + <line_editor + name="autoreplace_replacement" + follows="left|top" + height="23" + layout="topleft" + left="100" + max_length_bytes="255" + top_delta="-5" + width="280" + /> + <button + top_delta="0" + right="-10" + height="22" + width="90" + enabled="false" + follows="left|top" + mouse_opaque="true" + halign="center" + scale_image="true" + name="autoreplace_save_entry" + label="Save Entry" + tool_tip="Save this entry."/> + <view_border + top_pad="10" + left="2" + height="0" + width="491" + follows="left|top" + bevel_style="none" + border_thickness="1" + mouse_opaque="false" + name="divisor4"/> + <button + top_pad="10" + right="380" + height="22" + width="90" + enabled="true" + follows="left|top" + mouse_opaque="true" + halign="center" + scale_image="true" + name="autoreplace_save_changes" + label="Save Changes" + tool_tip="Save all changes."/> + <button + top_delta="0" + right="480" + height="22" + width="90" + enabled="true" + follows="left|top" + mouse_opaque="true" + halign="center" + scale_image="true" + name="autoreplace_cancel" + label="Cancel" + tool_tip="Discard all changes."/> +</floater> +<!-- + <text + top_pad="10" + left="10" + height="16" + width="260" + follows="left|top" + halign="center" + mouse_opaque="true" + name="autoreplace_text2"> + Entries + </text> +--> diff --git a/indra/newview/skins/default/xui/en/floater_chat_bar.xml b/indra/newview/skins/default/xui/en/floater_chat_bar.xml index 688a01ce7b..405557242f 100644 --- a/indra/newview/skins/default/xui/en/floater_chat_bar.xml +++ b/indra/newview/skins/default/xui/en/floater_chat_bar.xml @@ -46,6 +46,7 @@ left="0" max_length_bytes="1023" name="chat_box" + spellcheck="true" text_pad_left="5" text_pad_right="25" tool_tip="Press Enter to say, Ctrl+Enter to shout" diff --git a/indra/newview/skins/default/xui/en/floater_im_session.xml b/indra/newview/skins/default/xui/en/floater_im_session.xml index ca73883e53..040b66623e 100644 --- a/indra/newview/skins/default/xui/en/floater_im_session.xml +++ b/indra/newview/skins/default/xui/en/floater_im_session.xml @@ -46,7 +46,7 @@ tab_group="2" top="0" height="200" - width="254" + width="244" user_resize="true"> <button height="20" @@ -73,18 +73,20 @@ parse_highlights="true" parse_urls="true" left="1" - width="249"> + width="238"> </chat_history> <line_editor bottom="0" + left="3" follows="left|right|bottom" font="SansSerifSmall" height="20" label="To" layout="bottomleft" name="chat_editor" + spellcheck="true" tab_group="3" - width="249"> + width="236"> </line_editor> </layout_panel> </layout_stack> diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml index 0e211551e6..5e92a12251 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -1,8 +1,16 @@ <?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<floater can_close="true" can_drag_on_left="false" can_minimize="false" - can_resize="false" height="480" min_height="480" min_width="940" - name="Model Preview" title="UPLOAD MODEL" width="940" - help_topic="upload_model" > +<floater + can_close="true" + can_drag_on_left="false" + can_minimize="false" + can_resize="false" + height="480" + min_height="480" + width="980" + min_width="980" + name="Model Preview" + title="UPLOAD MODEL" + help_topic="upload_model" > <string name="status_idle"></string> <string name="status_parse_error">Error: Dae parsing issue - see log for details.</string> @@ -98,7 +106,7 @@ top_pad="15" left="0" height="300" - width="625" + width="635" name="import_tab" tab_position="top"> <!-- LOD PANEL --> @@ -116,13 +124,13 @@ left="3" name="lod_tab_border" top_pad="0" - width="619" /> + width="629" /> <text follows="left|top" height="18" initial_value="Source" layout="topleft" - left="75" + left="85" name="source" text_color="ModelUploaderLabels" top="15" @@ -165,7 +173,7 @@ top_pad="10" valign="top" value="High" - width="65" /> + width="75" /> <combo_box follows="top|left" height="20" @@ -175,10 +183,10 @@ top_delta="-3" width="135"> <item - id="Load from file" + name="Load from file" value="Load from file" /> <item - id="Generate" + name="Generate" value="Generate" /> </combo_box> <line_editor @@ -210,10 +218,10 @@ visible="false" width="135"> <item - id="Triangle Limit" + name="Triangle Limit" value="Triangle Limit" /> <item - id="Error Threshold" + name="Error Threshold" value="Error Threshold" /> </combo_box> <spinner @@ -290,7 +298,7 @@ top_pad="15" valign="top" value="Medium" - width="65" /> + width="75" /> <combo_box follows="top|left" height="20" @@ -300,13 +308,13 @@ top_delta="-3" width="135"> <item - id="Load from file" + name="Load from file" value="Load from file" /> <item - id="Generate" + name="Generate" value="Generate" /> <item - id="Use LoD above" + name="Use LoD above" value="Use LoD above" /> </combo_box> <line_editor @@ -339,10 +347,10 @@ top_delta="0" width="135"> <item - id="Triangle Limit" + name="Triangle Limit" value="Triangle Limit" /> <item - id="Error Threshold" + name="Error Threshold" value="Error Threshold" /> </combo_box> <spinner @@ -418,7 +426,7 @@ top_pad="15" valign="top" value="Low" - width="65" /> + width="75" /> <combo_box follows="top|left" height="20" @@ -428,13 +436,13 @@ top_delta="-3" width="135"> <item - id="Load from file" + name="Load from file" value="Load from file" /> <item - id="Generate" + name="Generate" value="Generate" /> <item - id="Use LoD above" + name="Use LoD above" value="Use LoD above" /> </combo_box> <line_editor @@ -467,10 +475,10 @@ top_delta="0" width="135"> <item - id="Triangle Limit" + name="Triangle Limit" value="Triangle Limit" /> <item - id="Error Threshold" + name="Error Threshold" value="Error Threshold" /> </combo_box> <spinner @@ -546,7 +554,7 @@ top_pad="15" valign="top" value="Lowest" - width="65" /> + width="75" /> <combo_box follows="top|left" height="20" @@ -556,13 +564,13 @@ top_delta="-3" width="135"> <item - id="Load from file" + name="Load from file" value="Load from file" /> <item - id="Generate" + name="Generate" value="Generate" /> <item - id="Use LoD above" + name="Use LoD above" value="Use LoD above" /> </combo_box> <line_editor @@ -595,10 +603,10 @@ top_delta="0" width="135"> <item - id="Triangle Limit" + name="Triangle Limit" value="Triangle Limit" /> <item - id="Error Threshold" + name="Error Threshold" value="Error Threshold" /> </combo_box> <spinner @@ -1201,7 +1209,7 @@ name="calculate_btn" top="3" height="20" - width="150" + width="165" tool_tip="Calculate weights &fee"/> <button follows="top|left" @@ -1234,7 +1242,7 @@ right="-2" top="3" height="20" - width="155"/> + width="275"/> <!-- ========== WEIGHTS ==========--> <text follows="top|left" @@ -1343,7 +1351,7 @@ layout="topleft" name="right_panel" top_pad="5" - width="290"> + width="340"> <combo_box top_pad="3" follows="left|top" diff --git a/indra/newview/skins/default/xui/en/floater_model_wizard.xml b/indra/newview/skins/default/xui/en/floater_model_wizard.xml deleted file mode 100644 index 62b8c5f96e..0000000000 --- a/indra/newview/skins/default/xui/en/floater_model_wizard.xml +++ /dev/null @@ -1,841 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes" ?> -<floater - legacy_header_height="18" - layout="topleft" - name="Model Wizard" - help_topic="model_wizard" - bg_opaque_image_overlay="0.5 0.5 0.5 1" - height="480" - save_rect="true" - title="UPLOAD MODEL WIZARD" - width="535"> - <button - top="32" - tab_stop="false" - left="410" - height="32" - name="upload_btn" - enabled="false" - label="5. Upload" - border="false" - image_unselected="BreadCrumbBtn_Right_Off" - image_selected="BreadCrumbBtn_Right_Press" - image_hover_unselected="BreadCrumbBtn_Right_Over" - image_disabled="BreadCrumbBtn_Right_Disabled" - image_disabled_selected="BreadCrumbBtn_Right_Disabled" - width="110"> - <button.commit_callback - function="Wizard.Upload"/> - </button> - <button - top="32" - left="310" - height="32" - tab_stop="false" - name="review_btn" - label="4. Review" - enabled="false" - border="false" - image_unselected="BreadCrumbBtn_Middle_Off" - image_selected="BreadCrumbBtn_Middle_Press" - image_hover_unselected="BreadCrumbBtn_Middle_Over" - image_disabled="BreadCrumbBtn_Middle_Disabled" - image_disabled_selected="BreadCrumbBtn_Middle_Disabled" - width="110"> - <button.commit_callback - function="Wizard.Review"/> - </button> - <button - top="32" - left="210" - height="32" - name="physics_btn" - label="3. Physics" - tab_stop="false" - enabled="false" - border="false" - image_unselected="BreadCrumbBtn_Middle_Off" - image_selected="BreadCrumbBtn_Middle_Press" - image_hover_unselected="BreadCrumbBtn_Middle_Over" - image_disabled="BreadCrumbBtn_Middle_Disabled" - image_disabled_selected="BreadCrumbBtn_Middle_Disabled" - width="110"> - <button.commit_callback - function="Wizard.Physics"/> - </button> - <button - top="32" - left="115" - name="optimize_btn" - label="2. Optimize" - tab_stop="false" - height="32" - border="false" - image_unselected="BreadCrumbBtn_Middle_Off" - image_selected="BreadCrumbBtn_Middle_Press" - image_hover_unselected="BreadCrumbBtn_Middle_Over" - image_disabled="BreadCrumbBtn_Middle_Disabled" - image_disabled_selected="BreadCrumbBtn_Middle_Disabled" - width="110"> - <button.commit_callback - function="Wizard.Optimize"/> - </button> - <button - top="32" - left="15" - name="choose_file_btn" - tab_stop="false" - enabled="false" - label="1. Choose File" - height="32" - image_unselected="BreadCrumbBtn_Left_Off" - image_selected="BreadCrumbBtn_Left_Press" - image_hover_unselected="BreadCrumbBtn_Left_Over" - image_disabled="BreadCrumbBtn_Left_Disabled" - image_disabled_selected="BreadCrumbBtn_Left_Disabled" - width="110"> - <button.commit_callback - function="Wizard.Choose"/> - </button> - <panel - height="388" - top_pad="0" - name="choose_file_panel" - visible="false" - width="535" - left="0"> - <panel - height="22" - top_pad="15" - width="505" - name="choose_file_header_panel" - bg_opaque_color="DkGray2" - background_visible="true" - background_opaque="true" - left="15"> - <text - width="200" - left="10" - top="3" - name="choose_file_header_text" - text_color="White" - height="10" - font="SansSerifBig" - layout="topleft"> - Choose model file - </text> - </panel> - <panel - top_pad="14" - left="15" - height="310" - width="505" - name="choose_file_content" - bg_opaque_color="DkGray2" - background_visible="true" - background_opaque="true"> - <text - height="32" - left="10" - name="advanced_users_text" - text_color="White" - top="15" - width="320" - word_wrap="true"> - Advanced users: If you are familiar with 3D content creation tools you may wish to use the Advanced Uploader. - </text> - <button - follows="left|top" - height="20" - label="Switch to Advanced" - layout="topleft" - left_delta="0" - name="switch_to_advanced" - top_pad="5" - width="130"> - </button> - <text - type="string" - length="1" - text_color="White" - follows="left|top" - top_pad="30" - height="10" - layout="topleft" - left_delta="0" - name="Cache location" - width="320"> - Choose model file to upload - </text> - <line_editor - border_style="line" - border_thickness="1" - follows="left|top" - font="SansSerifSmall" - height="20" - layout="topleft" - left_delta="0" - max_length="4096" - name="lod_file" - top_pad="5" - width="230" /> - <button - follows="left|top" - height="23" - label="Browse..." - label_selected="Browse..." - layout="topleft" - left_pad="5" - name="browse" - top_delta="-1" - width="85"> - </button> - <text - type="string" - length="1" - text_color="White" - follows="left|top" - top_pad="5" - height="10" - layout="topleft" - left="10" - name="Model types" - width="320"> - Second Life supports COLLADA (.dae) files - </text> - <!-- Placeholder panel for 3D preview render --> - <panel - top="30" - right="-10" - name="choose_file_preview_panel" - bevel_style="none" - highlight_light_color="0.09 0.09 0.09 1" - border="true" - border_style="line" - height="150" - follows="all" - width="150"> - </panel> - <text - top_pad="10" - width="130" - height="14" - left_delta="0" - text_color="White" - word_wrap="true"> - Dimensions (meters): - </text> - <text - top_pad="0" - width="160" - height="15" - font="SansSerifSmallBold" - text_color="White" - name="dimensions" - left_delta="0"> - X Y Z - </text> - <text - top_delta="0" - width="160" - height="15" - name="dimension_x" - left="356"/> - <text - top_delta="0" - width="160" - height="15" - name="dimension_y" - left="403"/> - <text - top_delta="0" - width="160" - height="15" - name="dimension_z" - left="450"/> - <text - height="16" - left="10" - name="warning_label" - text_color="Yellow" - top="200" - visible="false" - width="320"> - WARNING: - </text> - <text - height="50" - left="10" - name="warning_text" - top_pad="0" - visible="false" - width="320" - word_wrap="true"> - You will not be able to complete the final step of uploading this model to the Second Life servers. [secondlife:///app/floater/learn_more Find out how] to set up your account for mesh model uploads. - </text> - </panel> - </panel> - - - <panel - height="388" - top_delta="0" - name="optimize_panel" - visible="true" - width="535" - left="0"> - <panel - height="22" - top_pad="15" - name="optimize_header_panel" - width="505" - bg_opaque_color="DkGray2" - background_visible="true" - background_opaque="true" - left="15"> - <text - width="200" - left="10" - name="optimize_header_text" - top="3" - text_color="White" - height="10" - font="SansSerifBig" - layout="topleft"> - Optimize model - </text> - </panel> - <text - top_pad="14" - width="460" - height="20" - font="SansSerifSmall" - layout="topleft" - name="optimize_description" - word_wrap="true" - left_delta="5"> - We have optimized the model for performance. Adjust it further if you wish. - </text> - <panel - top_delta="40" - visible="false" - left="15" - height="270" - width="505" - name="optimize_content" - bg_opaque_color="DkGray2" - background_visible="true" - background_opaque="true"> - <text - top="20" - width="300" - height="12" - font="SansSerifBold" - left="112">Generating Level of Detail</text> - <progress_bar - name="optimize_progress_bar" - image_fill="model_wizard\progress_light.png" - color_bg="1 1 1 1" - color_bar="1 1 1 0.96" - follows="left|right|top" - width="260" - height="16" - image_bar="model_wizard\progress_bar_bg.png" - top_pad="14" - left="110"/> - <icon - top_pad="10" - left_delta="0" - width="13" - height="12" - image_name="model_wizard\check_mark.png"/> - <text - top_delta="0" - left_delta="18" - name="high_detail_text" - width="200" - height="14">Generate Level of Detail: High</text> - <icon - top_pad="10" - left_delta="-18" - width="13" - height="12" - image_name="model_wizard\check_mark.png"/> - <text - top_delta="0" - left_delta="18" - name="medium_detail_text" - width="200" - height="14">Generate Level of Detail: Medium</text> - <icon - top_pad="10" - left_delta="-18" - width="13" - height="12" - image_name="model_wizard\check_mark.png"/> - <text - top_delta="0" - left_delta="18" - name="low_detail_text" - width="200" - height="14">Generate Level of Detail: Low</text> - <icon - top_pad="10" - left_delta="-18" - width="13" - height="12" - image_name="model_wizard\check_mark.png"/> - <text - top_delta="0" - left_delta="18" - name="lowest_detail_text" - width="200" - height="14">Generate Level of Detail: Lowest</text> - </panel> - <panel - top_delta="0" - left_delta="0" - height="270" - width="505" - name="content2" - bg_opaque_color="DkGray2" - background_visible="true" - background_opaque="true"> - <text top="69" left="10" text_color="White" font="SansSerifSmallBold" width="120" height="16" wrap="true">Performance</text> - <text top="85" left="10" width="120" word_wrap="true" font="SansSerifSmall" height="40">Faster rendering -Less detail -Lower prim weight</text> - <text top="69" left="184" text_color="White" font="SansSerifSmallBold" width="120" height="16" wrap="true">Accuracy</text> - <text top="85" left="184" width="120" word_wrap="true" font="SansSerifSmall" height="40">Slower rendering -More detail -Higher prim weight</text> - - <slider - follows="left|top" - height="20" - increment="1" - layout="topleft" - left="10" - max_val="2" - initial_value="1" - min_val="0" - name="accuracy_slider" - show_text="false" - top="130" - width="290" /> - <text - font="SansSerifSmall" - top_pad="0" - width="5" - left_delta="6" - height="4">' - </text> - <text - font="SansSerifSmall" - top_delta="0" - width="5" - left_delta="137" - height="4">' - </text> - <text - font="SansSerifSmall" - top_delta="0" - width="5" - left_delta="137" - height="4">' - </text> - <button - follows="left|top" - height="20" - label="Recalculate Geometry" - layout="topleft" - left="80" - name="recalculate_geometry_btn" - top_pad="15" - width="150"> - </button> - <text top="10" right="-10" width="185" text_color="White" follows="left|top" height="15" name="lod_label"> - Geometry preview - </text> - <panel - right="-10" - top="32" - name="optimize_preview_panel" - bevel_style="none" - highlight_light_color="0.09 0.09 0.09 1" - border_style="line" - border="true" - height="185" - follows="all" - width="185"> - </panel> - <combo_box left_delta="75" top_pad="10" follows="left|top" list_position="below" height="22" - name="preview_lod_combo" width="110" tool_tip="LOD to view in preview render"> - <combo_item name="high"> - High detail - </combo_item> - <combo_item name="medium"> - Medium detail - </combo_item> - <combo_item name="low"> - Low detail - </combo_item> - <combo_item name="lowest"> - Lowest detail - </combo_item> - </combo_box> - </panel> - </panel> - - <panel - height="388" - top_delta="0" - name="physics_panel" - visible="false" - width="535" - left="0"> - <panel - height="22" - top_pad="15" - name="physics_header_panel" - width="505" - bg_opaque_color="DkGray2" - background_visible="true" - background_opaque="true" - left="15"> - <text - width="200" - left="10" - name="physics_header_text" - top="3" - height="10" - font="SansSerifBig" - text_color="White" - layout="topleft"> - Adjust physics - </text> - </panel> - <text - top_pad="10" - width="474" - height="50" - font="SansSerifSmall" - layout="topleft" - name="physics_description" - word_wrap="true" - left_delta="5"> - We will create a shape for the outer hull of the model. Adjust the shape's detail level as needed for the intended purpose of your model. - </text> - <panel - top_delta="44" - left="15" - height="270" - width="505" - name="physics_content" - bg_opaque_color="DkGray2" - background_visible="true" - background_opaque="true"> - <text top="10" left="10" text_color="White" font="SansSerifSmallBold" width="120" halign="right" height="16" wrap="true">Performance</text> - <text top="26" left="10" width="120" word_wrap="true" font="SansSerifSmall" halign="right" height="40">Faster rendering -Less detail -Lower prim weight</text> - <text top="174" left="10" text_color="White" font="SansSerifSmallBold" width="120" halign="right" height="16" wrap="true">Accuracy</text> - <text top="190" left="10" width="120" word_wrap="true" font="SansSerifSmall" halign="right" height="40">Slower rendering -More detail -Higher prim weight</text> - - <slider - follows="left|top" - height="190" - increment=".1" - layout="topleft" - left="140" - max_val="1" - initial_value="0.5" - min_val="0" - name="physics_slider" - orientation="vertical" - show_text="false" - top="25" - width="22" /> - <text top="10" width="120" word_wrap="true" left_pad="10" height="50">Examples: -Moving objects -Flying objects -Vehicles</text> - <text top="95" width="120" word_wrap="true" left_delta="0" height="50">Examples: -Small static objects -Less detailed objects -Simple furniture</text> - <text top="180" width="120" word_wrap="true" left_delta="0" height="50">Examples: -Static objects -Detailed objects -Buildings</text> - <button - follows="left|top" - height="20" - label="Recalculate physics" - layout="topleft" - left="80" - name="recalculate_physics_btn" - top_pad="10" - width="150"> - </button> - <button - enabled="false" - follows="left|top" - height="20" - label="Recalculating..." - layout="topleft" - left_delta="0" - name="recalculating_physics_btn" - top_delta="0" - visible="false" - width="150"> - </button> - <text top="10" right="-10" width="185" text_color="White" follows="left|top" height="15" name="lod_label"> - Physics preview - </text> - <panel - right="-10" - top="32" - name="physics_preview_panel" - bevel_style="none" - highlight_light_color="0.09 0.09 0.09 1" - border_style="line" - border="true" - height="185" - follows="all" - width="185"> - </panel> - <combo_box left_delta="75" top_pad="10" follows="left|top" list_position="below" height="22" - name="preview_lod_combo2" width="110" tool_tip="LOD to view in preview render"> - <combo_item name="high"> - High detail - </combo_item> - <combo_item name="medium"> - Medium detail - </combo_item> - <combo_item name="low"> - Low detail - </combo_item> - <combo_item name="lowest"> - Lowest detail - </combo_item> - </combo_box> - </panel> - </panel> - - <panel - height="388" - top_delta="0" - name="review_panel" - visible="false" - width="535" - left="0"> - <panel - height="22" - top_pad="15" - name="review_header_panel" - width="505" - bg_opaque_color="DkGray2" - background_visible="true" - background_opaque="true" - left="15"> - <text - width="200" - left="10" - name="review_header_text" - text_color="White" - top="3" - height="10" - font="SansSerifBig" - layout="topleft"> - Review - </text> - </panel> - <panel - top_pad="14" - left="15" - height="310" - width="505" - name="review_content" - bg_opaque_color="DkGray2" - background_visible="true" - background_opaque="true"> - <text - top="20" - width="485" - font="SansSerifMedium" - text_color="White" - left="10" - name="review_prim_equiv" - height="16">Impact to parcel/region: [EQUIV] prim equivalents - </text> - <text - top_pad="20" - width="485" - font="SansSerifMedium" - text_color="White" - left="10" - name="review_fee" - height="16">Your account will be charged an upload fee of L$ [FEE]. - </text> - <text - top_pad="20" - width="485" - font="SansSerifMedium" - text_color="White" - left="10" - name="review_confirmation" - height="32" - word_wrap="true">By clicking the upload button, you confirm that you have the appropriate rights to the material contained in the model. - </text> - </panel> - </panel> - - - - - <panel - height="388" - top_delta="0" - name="upload_panel" - visible="false" - width="535" - left="0"> - <panel - height="22" - top_pad="15" - name="upload_header_panel" - width="505" - bg_opaque_color="DkGray2" - background_visible="true" - background_opaque="true" - left="15"> - <text - width="200" - left="10" - name="upload_header_text" - top="3" - text_color="White" - height="10" - font="SansSerifBig" - layout="topleft"> - Upload complete - </text> - </panel> - <text - top_pad="14" - width="495" - height="16" - font="SansSerifMedium" - layout="topleft" - name="model_uploaded_text" - text_color="White" - word_wrap="true" - left="25"> - Your model has been uploaded. - </text> - <text - top_pad="5" - width="495" - height="16" - font="SansSerifMedium" - layout="topleft" - name="inventory_text" - text_color="White" - word_wrap="true" - left="25"> - You will find it in the Objects folder in your inventory. - </text> - <text - top_pad="20" - width="495" - font="SansSerifMedium" - text_color="White" - left="25" - name="charged_fee" - height="16">Your account has been charged L$ [FEE]. - </text> - </panel> - - - - <button - top="440" - right="-285" - width="90" - height="22" - name="back" - label="<< Back" /> - <button - top_delta="0" - right="-190" - width="90" - height="22" - name="next" - label="Next >> " /> - <button - top_delta="0" - left_delta="0" - width="160" - height="22" - name="calculate" - label="Calculate weights & fee >> " /> - <button - enabled="false" - visible="false" - top_delta="0" - left_delta="0" - width="160" - height="22" - name="calculating" - label="Calculating... " /> - <button - enabled="false" - top_delta="0" - right="-150" - width="90" - height="22" - visible="false" - name="upload" - tool_tip="Upload to simulator" - label="Upload" /> - <button - top_delta="0" - right="-15" - width="90" - height="22" - name="cancel" - label="Cancel" /> - <button - top_delta="0" - right="-15" - width="90" - height="22" - name="close" - visible="false" - label="Close" /> - <spinner visible="false" left="10" height="20" follows="top|left" width="80" top_pad="-50" value="1.0" min_val="0.01" max_val="64.0" name="import_scale"/> - - <string name="status_idle">Idle</string> - <string name="status_parse_error">Dae parsing issue - see log for details.</string> - <string name="status_reading_file">Loading...</string> - <string name="status_generating_meshes">Generating Meshes...</string> - <string name="status_vertex_number_overflow">Error: Vertex number is more than 65534, aborted!</string> - <string name="bad_element">Error: element is invalid</string> - <string name="high">High</string> - <string name="medium">Medium</string> - <string name="low">Low</string> - <string name="lowest">Lowest</string> - <string name="mesh_status_good">Ship it!</string> - <string name="mesh_status_na">N/A</string> - <string name="mesh_status_none">None</string> - <string name="mesh_status_submesh_mismatch">Levels of detail have a different number of textureable faces.</string> - <string name="mesh_status_mesh_mismatch">Levels of detail have a different number of mesh instances.</string> - <string name="mesh_status_too_many_vertices">Level of detail has too many vertices.</string> - <string name="mesh_status_missing_lod">Missing required level of detail.</string> - <string name="layer_all">All</string> - <!-- Text to display in physics layer combo box for "all layers" --> - -</floater> diff --git a/indra/newview/skins/default/xui/en/floater_my_inventory.xml b/indra/newview/skins/default/xui/en/floater_my_inventory.xml index 184f296255..ea44fd493e 100644 --- a/indra/newview/skins/default/xui/en/floater_my_inventory.xml +++ b/indra/newview/skins/default/xui/en/floater_my_inventory.xml @@ -6,7 +6,7 @@ height="570" help_topic="sidebar_inventory" min_width="333" - min_height="440" + min_height="560" name="floater_my_inventory" save_rect="true" save_visibility="true" diff --git a/indra/newview/skins/default/xui/en/floater_preview_notecard.xml b/indra/newview/skins/default/xui/en/floater_preview_notecard.xml index be3b2d179d..2e1c8ce670 100644 --- a/indra/newview/skins/default/xui/en/floater_preview_notecard.xml +++ b/indra/newview/skins/default/xui/en/floater_preview_notecard.xml @@ -70,6 +70,7 @@ max_length="65536" name="Notecard Editor" parse_urls="false" + spellcheck="true" tab_group="1" top="46" width="392" diff --git a/indra/newview/skins/default/xui/en/floater_spellcheck.xml b/indra/newview/skins/default/xui/en/floater_spellcheck.xml new file mode 100644 index 0000000000..76a350dd29 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_spellcheck.xml @@ -0,0 +1,160 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + border="true" + can_close="true" + can_minimize="true" + save_rect="true" + help_topic="spelling_settings" + can_resize="false" + height="315" + width="490" + name="spellcheck_floater" + title="Spell Checker Settings"> + <check_box + bottom_delta="30" + control_name="SpellCheck" + left_delta="15" + height="16" + width="100" + follows="left|top" + label="Enable spell checker" + name="spellcheck_enable" /> + <view_border + top_pad="10" + left="2" + height="0" + width="491" + follows="left|top" + bevel_style="none" + border_thickness="1" + mouse_opaque="false" + name="divisor1"/> + <text + enabled_control="SpellCheck" + follows="top|left" + height="10" + layout="topleft" + left="38" + mouse_opaque="false" + name="spellcheck_main" + top_pad="15" + type="string" + width="90" + > + Main dictionary : + </text> + <combo_box + enabled_control="SpellCheck" + follows="top|left" + height="23" + layout="topleft" + left_pad="10" + name="spellcheck_main_combo" + top_pad="-15" + width="175" + /> + <text + enabled_control="SpellCheck" + follows="top|left" + height="10" + label="Logs:" + layout="topleft" + left="38" + mouse_opaque="false" + name="spellcheck_additional" + top_pad="15" + type="string" + width="190" + > + Additional dictionaries : + </text> + <text + follows="top|left" + height="12" + layout="topleft" + left="55" + length="1" + name="spellcheck_available" + top_pad="10" + type="string" + width="175"> + Available + </text> + <text + follows="top|left" + height="12" + type="string" + left_pad="45" + length="1" + layout="topleft" + name="spellcheck_active" + width="175"> + Active + </text> + <scroll_list + enabled_control="SpellCheck" + follows="top|left" + height="155" + layout="topleft" + left="55" + multi_select="true" + name="spellcheck_available_list" + sort_column="0" + sort_ascending="true" + width="175" /> + <button + enabled_control="SpellCheck" + follows="top|left" + height="26" + image_overlay="Arrow_Right" + hover_glow_amount="0.15" + layout="topleft" + left_pad="10" + name="spellcheck_moveright_btn" + top_delta="50" + width="25"> + </button> + <button + enabled_control="SpellCheck" + follows="top|left" + height="26" + image_overlay="Arrow_Left" + hover_glow_amount="0.15" + layout="topleft" + name="spellcheck_moveleft_btn" + top_delta="30" + width="25"> + </button> + <scroll_list + enabled_control="SpellCheck" + follows="top|left" + height="155" + layout="topleft" + left_pad="10" + multi_select="true" + name="spellcheck_active_list" + sort_column="0" + sort_ascending="true" + top_pad="-105" + width="175" + /> + <button + enabled="false" + follows="left|top" + height="23" + label="Remove" + layout="topleft" + left="55" + name="spellcheck_remove_btn" + top_pad="5" + width="80" /> + <button + follows="left|top" + height="23" + label="Import..." + layout="topleft" + left_pad="15" + name="spellcheck_import_btn" + top_delta="0" + width="80" /> +</floater> diff --git a/indra/newview/skins/default/xui/en/floater_spellcheck_import.xml b/indra/newview/skins/default/xui/en/floater_spellcheck_import.xml new file mode 100644 index 0000000000..b54090015d --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_spellcheck_import.xml @@ -0,0 +1,116 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + border="true" + can_close="true" + can_minimize="true" + bottom="275" + left="300" + can_resize="false" + height="140" + width="400" + name="spellcheck_import" + title="Import Dictionary"> + <text + follows="top|left" + height="16" + layout="topleft" + left="25" + top="15" + type="string" + width="65"> + Dictionary: + </text> + <line_editor + enabled="false" + follows="left|top" + height="23" + layout="topleft" + left_pad="10" + max_length_bytes="255" + name="dictionary_path" + top_delta="-5" + width="200" /> + <button + follows="left|top" + height="23" + label="Browse" + label_selected="Browse" + layout="topleft" + left_pad="5" + name="dictionary_path_browse" + top_delta="0" + width="75" /> + <text + follows="top|left" + height="16" + layout="topleft" + left="25" + top_pad="8" + type="string" + width="65"> + Name: + </text> + <line_editor + enabled="false" + follows="left|top" + height="23" + layout="topleft" + left_pad="10" + max_length_bytes="255" + name="dictionary_name" + top_delta="-5" + width="200" /> + <text + follows="top|left" + height="16" + layout="topleft" + left="25" + top_pad="8" + type="string" + width="65"> + Language: + </text> + <line_editor + follows="left|top" + height="23" + layout="topleft" + left_pad="10" + max_length_bytes="255" + name="dictionary_language" + top_delta="-5" + width="200" /> + <view_border + top_pad="10" + left="2" + height="0" + width="396" + follows="left|top" + bevel_style="none" + border_thickness="1" + mouse_opaque="false" + name="divisor"/> + <button + top_pad="10" + right="280" + height="22" + width="90" + enabled="true" + follows="left|top" + mouse_opaque="true" + halign="center" + scale_image="true" + name="ok_btn" + label="Import" /> + <button + top_delta="0" + right="380" + height="22" + width="90" + enabled="true" + follows="left|top" + mouse_opaque="true" + halign="center" + scale_image="true" + name="cancel_btn" + label="Cancel" /> +</floater> diff --git a/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml b/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml index ffb8b842f0..6021ba0a5a 100644 --- a/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml +++ b/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml @@ -134,6 +134,16 @@ top_delta="-25" name="Pipette" width="28" /> + <text + follows="left|bottom" + height="20" + layout="topleft" + left="8" + name="preview_disabled" + top="266" + value="Preview Disabled" + visible="false" + width="120" /> <filter_editor follows="left|top|right" height="23" diff --git a/indra/newview/skins/default/xui/en/menu_text_editor.xml b/indra/newview/skins/default/xui/en/menu_text_editor.xml index fe8489166b..70b40dd89b 100644 --- a/indra/newview/skins/default/xui/en/menu_text_editor.xml +++ b/indra/newview/skins/default/xui/en/menu_text_editor.xml @@ -2,6 +2,85 @@ <context_menu name="Text editor context menu"> <menu_item_call + label="(unknown)" + layout="topleft" + name="Suggestion 1"> + <menu_item_call.on_click + function="SpellCheck.ReplaceWithSuggestion" + parameter="0" /> + <menu_item_call.on_visible + function="SpellCheck.VisibleSuggestion" + parameter="0" /> + </menu_item_call> + <menu_item_call + label="(unknown)" + layout="topleft" + name="Suggestion 2"> + <menu_item_call.on_click + function="SpellCheck.ReplaceWithSuggestion" + parameter="1" /> + <menu_item_call.on_visible + function="SpellCheck.VisibleSuggestion" + parameter="1" /> + </menu_item_call> + <menu_item_call + label="(unknown)" + layout="topleft" + name="Suggestion 3"> + <menu_item_call.on_click + function="SpellCheck.ReplaceWithSuggestion" + parameter="2" /> + <menu_item_call.on_visible + function="SpellCheck.VisibleSuggestion" + parameter="2" /> + </menu_item_call> + <menu_item_call + label="(unknown)" + layout="topleft" + name="Suggestion 4"> + <menu_item_call.on_click + function="SpellCheck.ReplaceWithSuggestion" + parameter="3" /> + <menu_item_call.on_visible + function="SpellCheck.VisibleSuggestion" + parameter="3" /> + </menu_item_call> + <menu_item_call + label="(unknown)" + layout="topleft" + name="Suggestion 5"> + <menu_item_call.on_click + function="SpellCheck.ReplaceWithSuggestion" + parameter="4" /> + <menu_item_call.on_visible + function="SpellCheck.VisibleSuggestion" + parameter="4" /> + </menu_item_call> + <menu_item_separator + layout="topleft" + name="Suggestion Separator" /> + <menu_item_call + label="Add to Dictionary" + layout="topleft" + name="Add to Dictionary"> + <menu_item_call.on_click + function="SpellCheck.AddToDictionary" /> + <menu_item_call.on_enable + function="SpellCheck.EnableAddToDictionary" /> + </menu_item_call> + <menu_item_call + label="Add to Ignore" + layout="topleft" + name="Add to Ignore"> + <menu_item_call.on_click + function="SpellCheck.AddToIgnore" /> + <menu_item_call.on_enable + function="SpellCheck.EnableAddToIgnore" /> + </menu_item_call> + <menu_item_separator + layout="topleft" + name="Spellcheck Separator" /> + <menu_item_call label="Cut" layout="topleft" name="Cut"> diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index a6898c554f..6bcdc615c3 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -193,6 +193,15 @@ <menu_item_call.on_click function="View.ToggleUI" /> </menu_item_call> + <menu_item_check + label="Show HUD Attachments" + name="Show HUD Attachments" + shortcut="alt|shift|H"> + <menu_item_check.on_check + function="View.CheckHUDAttachments" /> + <menu_item_check.on_click + function="View.ShowHUDAttachments" /> + </menu_item_check> <menu_item_separator/> @@ -291,6 +300,12 @@ function="SideTray.PanelPeopleTab" parameter="nearby_panel" /> </menu_item_call> + <menu_item_call + label="Block List" + name="Block List"> + <menu_item_call.on_click + function="Communicate.BlockList" /> + </menu_item_call> </menu> <menu create_jump_keys="true" @@ -1374,15 +1389,6 @@ function="View.HighlightTransparent" /> </menu_item_check> <menu_item_check - label="Show HUD Attachments" - name="Show HUD Attachments" - shortcut="alt|shift|H"> - <menu_item_check.on_check - function="View.CheckHUDAttachments" /> - <menu_item_check.on_click - function="View.ShowHUDAttachments" /> - </menu_item_check> - <menu_item_check label="Show Mouselook Crosshairs" name="ShowCrosshairs"> <menu_item_check.on_check @@ -3125,12 +3131,6 @@ <menu_item_call.on_click function="Advanced.TestFemale" /> </menu_item_call> - <menu_item_call - label="Toggle PG" - name="Toggle PG"> - <menu_item_call.on_click - function="Advanced.TogglePG" /> - </menu_item_call> <menu_item_check label="Allow Select Avatar" name="Allow Select Avatar"> diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index a26c5bb344..91b4d38e97 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -2359,6 +2359,93 @@ Would you be my friend? </notification> <notification + icon="alertmodal.tga" + label="Add Auto-Replace List" + name="AddAutoReplaceList" + type="alertmodal"> + <tag>addlist</tag> + Name for the new list: + <tag>confirm</tag> + <form name="form"> + <input name="listname" type="text"/> + <button + default="true" + index="0" + name="SetName" + text="OK"/> + </form> + </notification> + + <notification + icon="alertmodal.tga" + label="Rename Auto-Replace List" + name="RenameAutoReplaceList" + type="alertmodal"> + The name '[DUPNAME]' is in use + Enter a new unique name: + <tag>confirm</tag> + <form name="form"> + <input name="listname" type="text"/> + <button + default="false" + index="0" + name="ReplaceList" + text="Replace Current List"/> + <button + default="true" + index="1" + name="SetName" + text="Use New Name"/> + </form> + </notification> + + <notification + icon="alertmodal.tga" + name="InvalidAutoReplaceEntry" + type="alertmodal"> + The keyword must be a single word, and the replacement may not be empty. + <tag>fail</tag> + </notification> + + <notification + icon="alertmodal.tga" + name="InvalidAutoReplaceList" + type="alertmodal"> + That replacement list is not valid. + <tag>fail</tag> + </notification> + + <notification + icon="alertmodal.tga" + name="SpellingDictImportRequired" + type="alertmodal"> + You must specify a file, a name, and a language. + <tag>fail</tag> + </notification> + + <notification + icon="alertmodal.tga" + name="SpellingDictIsSecondary" + type="alertmodal"> +The dictionary [DIC_NAME] does not appear to have an "aff" file; this means that it is a "secondary" dictionary. +It can be used as an additional dictionary, but not as your Main dictionary. + +See https://wiki.secondlife.com/wiki/Adding_Spelling_Dictionaries + <tag>confirm</tag> + </notification> + + <notification + icon="alertmodal.tga" + name="SpellingDictImportFailed" + type="alertmodal"> + Unable to copy + [FROM_NAME] + to + [TO_NAME] + <tag>fail</tag> + </notification> + + <notification icon="alertmodal.tga" label="Save Outfit" name="SaveOutfitAs" @@ -4089,9 +4176,7 @@ Are you sure you want to change the Estate Covenant? name="RegionEntryAccessBlocked" type="alertmodal"> <tag>fail</tag> -You are not allowed in that Region due to your maturity Rating. This may be a result of a lack of information validating your age. - -Please verify you have the latest Viewer installed, and go to the Knowledge Base for details on accessing areas with this maturity rating. + The region you're trying to visit contains content exceeding your current preferences. You can change your preferences using Me > Preferences > General. <usetemplate name="okbutton" yestext="OK"/> @@ -4099,13 +4184,11 @@ Please verify you have the latest Viewer installed, and go to the Knowledge Base <notification icon="alertmodal.tga" - name="RegionEntryAccessBlocked_KB" + name="RegionEntryAccessBlocked_AdultsOnlyContent" type="alertmodal"> <tag>fail</tag> <tag>confirm</tag> -You are not allowed in that region due to your maturity Rating. - -Go to the Knowledge Base for more information about maturity Ratings? + The region you're trying to visit contains [REGIONMATURITY] content, which is accessible to adults only. <url option="0" name="url"> http://wiki.secondlife.com/wiki/Linden_Lab_Official:Maturity_ratings:_an_overview </url> @@ -4113,7 +4196,7 @@ Go to the Knowledge Base for more information about maturity Ratings? name="okcancelignore" yestext="Go to Knowledge Base" notext="Close" - ignoretext="I can't enter this Region, due to restrictions of the maturity Rating"/> + ignoretext="Region crossing: The region you're trying to visit contains content which is accessible to adults only."/> </notification> <notification @@ -4121,47 +4204,156 @@ Go to the Knowledge Base for more information about maturity Ratings? name="RegionEntryAccessBlocked_Notify" type="notifytip"> <tag>fail</tag> -You are not allowed in that region due to your maturity Rating. +The region you're trying to visit contains [REGIONMATURITY] content, but your current preferences are set to exclude [REGIONMATURITY] content. + </notification> + + <notification + icon="notifytip.tga" + name="RegionEntryAccessBlocked_NotifyAdultsOnly" + type="notifytip"> + <tag>fail</tag> + The region you're trying to visit contains [REGIONMATURITY] content, which is accessible to adults only. </notification> <notification icon="alertmodal.tga" name="RegionEntryAccessBlocked_Change" type="alertmodal"> - <tag>fail</tag> + <tag>fail</tag> <tag>confirm</tag> -You are not allowed in that Region due to your maturity Rating preference. - -To enter the desired region, please change your maturity Rating preference. This will allow you to search for and access [REGIONMATURITY] content. To undo any changes, go to Me > Preferences > General. - <form name="form"> +The region you're trying to visit contains [REGIONMATURITY] content, but your current preferences are set to exclude [REGIONMATURITY] content. We can change your preferences, or you can cancel. After your preferences are changed, you may attempt to enter the region again. + <form name="form"> <button index="0" name="OK" - text="Change Preference"/> - <button + text="Change preferences"/> + <button default="true" index="1" name="Cancel" - text="Close"/> - <ignore name="ignore" text="My chosen Rating preference prevents me from entering a Region"/> + text="Cancel"/> + <ignore name="ignore" text="Region crossing: The region you're trying to visit contains content excluded by your preferences."/> </form> </notification> <notification + icon="alertmodal.tga" + name="RegionEntryAccessBlocked_PreferencesOutOfSync" + type="alertmodal"> + <tag>fail</tag> + We are having technical difficulties with your teleport because your preferences are out of sync with the server. + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + + <notification + icon="alertmodal.tga" + name="TeleportEntryAccessBlocked" + type="alertmodal"> + <tag>fail</tag> + The region you're trying to visit contains content exceeding your current preferences. You can change your preferences using Me > Preferences > General. + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + + <notification + icon="alertmodal.tga" + name="TeleportEntryAccessBlocked_AdultsOnlyContent" + type="alertmodal"> + <unique> + <context>REGIONMATURITY</context> + </unique> + <tag>fail</tag> + <tag>confirm</tag> + The region you're trying to visit contains [REGIONMATURITY] content, which is accessible to adults only. + <url option="0" name="url"> + http://wiki.secondlife.com/wiki/Linden_Lab_Official:Maturity_ratings:_an_overview + </url> + <usetemplate + name="okcancelignore" + yestext="Go to Knowledge Base" + notext="Close" + ignoretext="Teleport: The region you're trying to visit contains content which is accessible to adults only."/> + </notification> + + <notification icon="notifytip.tga" - name="PreferredMaturityChanged" + name="TeleportEntryAccessBlocked_Notify" + type="notifytip"> + <unique> + <context>REGIONMATURITY</context> + </unique> + <tag>fail</tag> + The region you're trying to visit contains [REGIONMATURITY] content, but your current preferences are set to exclude [REGIONMATURITY] content. + </notification> + + <notification + icon="notifytip.tga" + name="TeleportEntryAccessBlocked_NotifyAdultsOnly" type="notifytip"> -Your maturity Rating preference is now [RATING]. + <unique> + <context>REGIONMATURITY</context> + </unique> + <tag>fail</tag> + The region you're trying to visit contains [REGIONMATURITY] content, which is accessible to adults only. </notification> <notification icon="alertmodal.tga" - name="LandClaimAccessBlocked" + name="TeleportEntryAccessBlocked_ChangeAndReTeleport" type="alertmodal"> -You cannot claim this land due to your maturity Rating. This may be a result of a lack of information validating your age. + <unique> + <context>REGIONMATURITY</context> + </unique> + <tag>fail</tag> + <tag>confirm</tag> + The region you're trying to visit contains [REGIONMATURITY] content, but your current preferences are set to exclude [REGIONMATURITY] content. We can change your preferences and continue with the teleport, or you can cancel this teleport. + <form name="form"> + <button + index="0" + name="OK" + text="Change and continue"/> + <button + default="true" + index="1" + name="Cancel" + text="Cancel"/> + <ignore name="ignore" text="Teleport (restartable): The region you're trying to visit contains content excluded by your preferences."/> + </form> + </notification> -Please verify you have the latest Viewer installed, and go to the Knowledge Base for details on accessing areas with this maturity rating. - <tag>fail</tag> + <notification + icon="alertmodal.tga" + name="TeleportEntryAccessBlocked_Change" + type="alertmodal"> + <unique> + <context>REGIONMATURITY</context> + </unique> + <tag>fail</tag> + <tag>confirm</tag> + The region you're trying to visit contains [REGIONMATURITY] content, but your current preferences are set to exclude [REGIONMATURITY] content. We can change your preferences, or you can cancel the teleport. After your preferences are changed, you will need to attempt the teleport again. + <form name="form"> + <button + index="0" + name="OK" + text="Change preferences"/> + <button + default="true" + index="1" + name="Cancel" + text="Cancel"/> + <ignore name="ignore" text="Teleport (non-restartable): The region you're trying to visit contains content excluded by your preferences."/> + </form> + </notification> + + <notification + icon="alertmodal.tga" + name="TeleportEntryAccessBlocked_PreferencesOutOfSync" + type="alertmodal"> + <tag>fail</tag> + We are having technical difficulties with your teleport because your preferences are out of sync with the server. <usetemplate name="okbutton" yestext="OK"/> @@ -4169,12 +4361,43 @@ Please verify you have the latest Viewer installed, and go to the Knowledge Base <notification icon="alertmodal.tga" - name="LandClaimAccessBlocked_KB" + name="PreferredMaturityChanged" type="alertmodal"> -You cannot claim this land due to your maturity Rating. +You won't receive any more notifications that you're about to visit a region with [RATING] content. You may change your content preferences in the future by using Me > Preferences > General from the menu bar. + <tag>confirm</tag> + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> -Go to the Knowledge Base for more information about maturity Ratings? - <tag>fail</tag> + <notification + icon="alertmodal.tga" + name="MaturityChangeError" + type="alertmodal"> + We were unable to change your preferences to view [PREFERRED_MATURITY] content at this time. Your preferences have been reset to view [ACTUAL_MATURITY] content. You may attempt to change your preferences again by using Me > Preferences > General from the menu bar. + <tag>confirm</tag> + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + + <notification + icon="alertmodal.tga" + name="LandClaimAccessBlocked" + type="alertmodal"> + The land you're trying to claim has a maturity rating exceeding your current preferences. You can change your preferences using Me > Preferences > General. + <tag>fail</tag> + <usetemplate + name="okbutton" + yestext="OK"/> + </notification> + + <notification + icon="alertmodal.tga" + name="LandClaimAccessBlocked_AdultsOnlyContent" + type="alertmodal"> + Only adults can claim this land. + <tag>fail</tag> <tag>confirm</tag> <url option="0" name="url"> http://wiki.secondlife.com/wiki/Linden_Lab_Official:Maturity_ratings:_an_overview @@ -4183,41 +4406,52 @@ Go to the Knowledge Base for more information about maturity Ratings? name="okcancelignore" yestext="Go to Knowledge Base" notext="Close" - ignoretext="I can't claim this Land, due to restrictions of the maturity Rating"/> + ignoretext="Only adults can claim this land."/> </notification> <notification icon="notifytip.tga" name="LandClaimAccessBlocked_Notify" type="notifytip"> -You cannot claim this land due to your maturity Rating. - <tag>fail</tag> + The land you're trying to claim contains [REGIONMATURITY] content, but your current preferences are set to exclude [REGIONMATURITY] content. + <tag>fail</tag> + </notification> + + <notification + icon="notifytip.tga" + name="LandClaimAccessBlocked_NotifyAdultsOnly" + type="notifytip"> + <tag>fail</tag> + The land you're trying to claim contains [REGIONMATURITY] content, which is accessible to adults only. </notification> <notification icon="alertmodal.tga" name="LandClaimAccessBlocked_Change" type="alertmodal"> -You cannot claim this land due to your maturity Rating preference. - -You can click 'Change Preference' to raise your maturity Rating preference now and allow you to enter. You will be able to search and access [REGIONMATURITY] content from now on. If you later want to change this setting back, go to Me > Preferences > General. + The land you're trying to claim contains [REGIONMATURITY] content, but your current preferences are set to exclude [REGIONMATURITY] content. We can change your preferences, then you can try claiming the land again. <tag>fail</tag> <tag>confirm</tag> - <usetemplate - name="okcancelignore" - yestext="Change Preference" - notext="Close" - ignoretext="My chosen Rating preference prevents me from claiming Land"/> + <form name="form"> + <button + index="0" + name="OK" + text="Change preferences"/> + <button + default="true" + index="1" + name="Cancel" + text="Cancel"/> + <ignore name="ignore" text="The land you're trying to claim contains content excluded by your preferences."/> + </form> </notification> <notification icon="alertmodal.tga" name="LandBuyAccessBlocked" type="alertmodal"> -You cannot buy this land due to your maturity Rating. This may be a result of a lack of information validating your age. - -Please verify you have the latest Viewer installed, and go to the Knowledge Base for details on accessing areas with this maturity rating. - <tag>fail</tag> + The land you're trying to buy has a maturity rating exceeding your current preferences. You can change your preferences using Me > Preferences > General. + <tag>fail</tag> <usetemplate name="okbutton" yestext="OK"/> @@ -4225,11 +4459,9 @@ Please verify you have the latest Viewer installed, and go to the Knowledge Base <notification icon="alertmodal.tga" - name="LandBuyAccessBlocked_KB" + name="LandBuyAccessBlocked_AdultsOnlyContent" type="alertmodal"> -You cannot buy this land due to your maturity Rating. - -Go to the Knowledge Base for more information about maturity Ratings? + Only adults can buy this land. <tag>confirm</tag> <tag>fail</tag> <url option="0" name="url"> @@ -4239,31 +4471,44 @@ Go to the Knowledge Base for more information about maturity Ratings? name="okcancelignore" yestext="Go to Knowledge Base" notext="Close" - ignoretext="I can't buy this Land, due to restrictions of the maturity Rating"/> + ignoretext="Only adults can buy this land."/> </notification> <notification icon="notifytip.tga" name="LandBuyAccessBlocked_Notify" type="notifytip"> -You cannot buy this land due to your maturity Rating. - <tag>fail</tag> + The land you're trying to buy contains [REGIONMATURITY] content, but your current preferences are set to exclude [REGIONMATURITY] content. + <tag>fail</tag> + </notification> + + <notification + icon="notifytip.tga" + name="LandBuyAccessBlocked_NotifyAdultsOnly" + type="notifytip"> + <tag>fail</tag> + The land you're trying to buy contains [REGIONMATURITY] content, which is accessible to adults only. </notification> <notification icon="alertmodal.tga" name="LandBuyAccessBlocked_Change" type="alertmodal"> -You cannot buy this land due to your maturity Rating preference. - -You can click 'Change Preference' to raise your maturity Rating preference now and allow you to enter. You will be able to search and access [REGIONMATURITY] content from now on. If you later want to change this setting back, go to Me > Preferences > General. + The land you're trying to buy contains [REGIONMATURITY] content, but your current preferences are set to exclude [REGIONMATURITY] content. We can change your preferences, then you can try buying the land again. <tag>confirm</tag> <tag>fail</tag> - <usetemplate - name="okcancelignore" - yestext="Change Preference" - notext="Close" - ignoretext="My chosen Rating preference prevents me from buying Land"/> + <form name="form"> + <button + index="0" + name="OK" + text="Change preferences"/> + <button + default="true" + index="1" + name="Cancel" + text="Cancel"/> + <ignore name="ignore" text="The land you're trying to buy contains content excluded by your preferences."/> + </form> </notification> <notification @@ -4418,10 +4663,11 @@ Type a short announcement which will be sent to everyone in this region. label="Changed Region Maturity" name="RegionMaturityChange" type="alertmodal"> -The maturity rating for this region has been updated. -It may take some time for the change to be reflected on the map. - -To enter Adult regions, Residents must be Account Verified, either by age-verification or payment-verification. +The maturity rating for this region has been changed. +It may take some time for this change to be reflected on the map. + <usetemplate + name="okbutton" + yestext="OK"/> </notification> <notification @@ -5127,20 +5373,20 @@ Would you like to automatically wear the clothing you are about to create? icon="alertmodal.tga" name="NotAgeVerified" type="alertmodal"> - <tag>fail</tag> -To access adult content and areas in Second Life you must be at least 18 years old. Please visit our age verification page to confirm you are over 18. -Note this will launch your web browser. - -[_URL] - <tag>confirm</tag> - <url option="0" name="url"> - https://secondlife.com/my/account/verification.php - </url> + The location you're trying to visit is restricted to residents age 18 and over. + <tag>fail</tag> <usetemplate - ignoretext="I have not verified my age" - name="okcancelignore" - notext="Cancel" - yestext="Go to Age Verification"/> + ignoretext="I am not old enough to visit age restricted areas." + name="okignore" + yestext="OK"/> + </notification> + + <notification + icon="notifytip.tga" + name="NotAgeVerified_Notify" + type="notifytip"> + Location restricted to age 18 and over. + <tag>fail</tag> </notification> <notification @@ -5287,7 +5533,7 @@ Terrain.raw downloaded icon="notifytip.tga" name="GestureMissing" type="notifytip"> -Hmm. Gesture [NAME] is missing from the database. +Gesture [NAME] is missing from the database. <tag>fail</tag> </notification> @@ -5825,9 +6071,7 @@ You can only claim public land in the Region you're in. persist="true" type="notify"> <tag>fail</tag> -You aren't allowed in that Region due to your maturity Rating. You may need to validate your age and/or install the latest Viewer. - -Please go to the Knowledge Base for details on accessing areas with this maturity Rating. + The region you're trying to visit contains content exceeding your current preferences. You can change your preferences using Me > Preferences > General. </notification> <notification @@ -5859,11 +6103,11 @@ You do not have proper payment status to enter this region. <notification icon="notify.tga" - name="MustGetAgeRgion" + name="MustGetAgeRegion" persist="true" type="notify"> <tag>fail</tag> -You must be age-verified to enter this region. +You must be age 18 or over to enter this region. </notification> <notification @@ -5872,7 +6116,7 @@ You must be age-verified to enter this region. persist="true" type="notify"> <tag>fail</tag> -You must be age-verified to enter this parcel. + You must be age 18 or over to enter this parcel. </notification> <notification @@ -6147,7 +6391,8 @@ Your object named <nolink>[OBJECTFROMNAME]</nolink> has given you th type="offer"> [NAME_SLURL] has offered to teleport you to their location: -[MESSAGE] - [MATURITY_STR] <icon>[MATURITY_ICON]</icon> +“[MESSAGE]” +<icon>[MATURITY_ICON]</icon> - [MATURITY_STR] <tag>confirm</tag> <form name="form"> <button @@ -6163,6 +6408,42 @@ Your object named <nolink>[OBJECTFROMNAME]</nolink> has given you th <notification icon="notify.tga" + name="TeleportOffered_MaturityExceeded" + type="offer"> +[NAME_SLURL] has offered to teleport you to their location: + +“[MESSAGE]” +<icon>[MATURITY_ICON]</icon> - [MATURITY_STR] + +This region contains [REGION_CONTENT_MATURITY] content, but your current preferences are set to exclude [REGION_CONTENT_MATURITY] content. We can change your preferences and continue with the teleport, or you can cancel this teleport. + <tag>confirm</tag> + <form name="form"> + <button + index="0" + name="Teleport" + text="Change and Continue"/> + <button + index="1" + name="Cancel" + text="Cancel"/> + </form> + </notification> + + <notification + icon="notify.tga" + name="TeleportOffered_MaturityBlocked" + type="notifytip"> +[NAME_SLURL] has offered to teleport you to their location: + +“[MESSAGE]” +<icon>[MATURITY_ICON]</icon> - [MATURITY_STR] + +However, this region contains content accessible to adults only. + <tag>fail</tag> + </notification> + + <notification + icon="notify.tga" name="TeleportOfferSent" type="offer"> Teleport offer sent to [TO_NAME] @@ -7197,6 +7478,18 @@ You locally updated a [RESOLUTION] baked texture for '[BODYREGION]' after [TIME] <notification icon="alertmodal.tga" + name="LivePreviewUnavailable" + type="alert"> + +We cannot display a preview of this texture because it is no-copy and/or no-transfer. + <usetemplate + ignoretext="Warn me that Live Preview mode is not available for no-copy and/or no-transfer textures" + name="okignore" + yestext="OK"/> + </notification> + + <notification + icon="alertmodal.tga" name="ConfirmLeaveCall" type="alert"> Are you sure you want to leave this call? diff --git a/indra/newview/skins/default/xui/en/panel_edit_pick.xml b/indra/newview/skins/default/xui/en/panel_edit_pick.xml index 0faa1598b1..553c112e6f 100644 --- a/indra/newview/skins/default/xui/en/panel_edit_pick.xml +++ b/indra/newview/skins/default/xui/en/panel_edit_pick.xml @@ -134,6 +134,7 @@ top_pad="2" max_length="1023" name="pick_desc" + spellcheck="true" text_color="black" word_wrap="true" /> <text diff --git a/indra/newview/skins/default/xui/en/panel_group_notices.xml b/indra/newview/skins/default/xui/en/panel_group_notices.xml index 607e1bb213..6d5fb51e85 100644 --- a/indra/newview/skins/default/xui/en/panel_group_notices.xml +++ b/indra/newview/skins/default/xui/en/panel_group_notices.xml @@ -141,6 +141,7 @@ Maximum 200 per group daily max_length_bytes="63" name="create_subject" prevalidate_callback="ascii" + spellcheck="true" width="218" /> <text follows="left|top" @@ -161,6 +162,7 @@ Maximum 200 per group daily left_pad="3" max_length="511" name="create_message" + spellcheck="true" top_delta="0" width="218" word_wrap="true" /> @@ -309,6 +311,7 @@ Maximum 200 per group daily left_pad="3" max_length_bytes="63" name="view_subject" + spellcheck="true" top_delta="-1" visible="false" width="200" /> @@ -333,6 +336,7 @@ Maximum 200 per group daily right="-1" max_length="511" name="view_message" + spellcheck="true" top_delta="-40" width="313" word_wrap="true" /> diff --git a/indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml b/indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml index 21c627cdfb..6bc9c48729 100644 --- a/indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml +++ b/indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml @@ -19,6 +19,7 @@ left="0" max_length_bytes="1023" name="chat_box" + spellcheck="true" text_pad_left="5" text_pad_right="25" tool_tip="Press Enter to say, Ctrl+Enter to shout" diff --git a/indra/newview/skins/default/xui/en/panel_preferences_chat.xml b/indra/newview/skins/default/xui/en/panel_preferences_chat.xml index caf7fc85f5..27193a984f 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_chat.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_chat.xml @@ -207,13 +207,36 @@ <button follows="left|top" height="23" - label="Chat Translation Settings" + label="Translation..." layout="topleft" left="30" name="ok_btn" - top="-40" + top="-50" width="170"> <button.commit_callback function="Pref.TranslationSettings" /> </button> -</panel>
\ No newline at end of file + <button + follows="top|left" + height="23" + layout="topleft" + top_pad="-23" + left_pad="5" + name="autoreplace_showgui" + commit_callback.function="Pref.AutoReplace" + label="Auto-Replace..." + width="150"> + </button> + <button + follows="top|left" + height="23" + layout="topleft" + top_pad="-23" + left_pad="5" + name="spellcheck_showgui" + commit_callback.function="Pref.SpellChecker" + label="Spell Checking..." + width="150"> + </button> + +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_region_estate.xml b/indra/newview/skins/default/xui/en/panel_region_estate.xml index bfd796a62b..76a82212ae 100644 --- a/indra/newview/skins/default/xui/en/panel_region_estate.xml +++ b/indra/newview/skins/default/xui/en/panel_region_estate.xml @@ -149,11 +149,11 @@ <check_box follows="top|left" height="16" - label="Have been age-verified" + label="Are age 18 or older" layout="topleft" left_delta="0" name="limit_age_verified" - tool_tip="Residents must be age verified to access this estate. See the [SUPPORT_SITE] for more information." + tool_tip="Residents must be age 18 or older to access this estate. See the [SUPPORT_SITE] for more information." top_pad="2" width="278" /> diff --git a/indra/newview/skins/default/xui/en/sidepanel_inventory.xml b/indra/newview/skins/default/xui/en/sidepanel_inventory.xml index 6ecb57b41d..14bd349480 100644 --- a/indra/newview/skins/default/xui/en/sidepanel_inventory.xml +++ b/indra/newview/skins/default/xui/en/sidepanel_inventory.xml @@ -48,7 +48,7 @@ height="300" width="330" /> </layout_panel> - <layout_panel + <layout_panel width="330" layout="topleft" auto_resize="false" diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 866ea296c3..6dd80dc11a 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -441,6 +441,7 @@ Please try logging in again in a minute.</string> <string name="load_files">Load Files</string> <string name="choose_the_directory">Choose Directory</string> <string name="script_files">Scripts</string> + <string name="dictionary_files">Dictionaries</string> <!-- LSL Usage Hover Tips --> <!-- NOTE: For now these are set as translate="false", until DEV-40761 is implemented (to internationalize the rest of tooltips in the same window). @@ -3758,4 +3759,9 @@ Try enclosing path to the editor with double quotes. <string name="snapshot_quality_high">High</string> <string name="snapshot_quality_very_high">Very High</string> + <string name="TeleportMaturityExceeded">The Resident cannot visit this region.</string> + + <!-- Spell check settings floater --> + <string name="UserDictionary">[User]</string> + </strings> diff --git a/indra/newview/skins/default/xui/en/teleport_strings.xml b/indra/newview/skins/default/xui/en/teleport_strings.xml index dce6b8dd6d..fdf41991cd 100644 --- a/indra/newview/skins/default/xui/en/teleport_strings.xml +++ b/indra/newview/skins/default/xui/en/teleport_strings.xml @@ -45,6 +45,9 @@ Go to 'Welcome Island Public' to repeat the tutorial. <message name="no_inventory_host"> The inventory system is currently unavailable. </message> + <message name="MustGetAgeRegion"> + You must be age 18 or over to enter this region. + </message> </message_set> <message_set name="progress"> <message name="sending_dest"> @@ -80,5 +83,8 @@ Go to 'Welcome Island Public' to repeat the tutorial. <message name="requesting"> Requesting Teleport... </message> - </message_set> + <message name="pending"> + Pending Teleport... + </message> + </message_set> </teleport_messages> diff --git a/indra/newview/skins/default/xui/es/floater_model_wizard.xml b/indra/newview/skins/default/xui/es/floater_model_wizard.xml deleted file mode 100644 index 5bd6b5e0e5..0000000000 --- a/indra/newview/skins/default/xui/es/floater_model_wizard.xml +++ /dev/null @@ -1,208 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<floater name="Model Wizard" title="CARGAR ASISTENTE DE MODELO"> - <button label="5. Subir" name="upload_btn"/> - <button label="4. Revisar" name="review_btn"/> - <button label="3. Física" name="physics_btn"/> - <button label="2. Optimizar" name="optimize_btn"/> - <button label="1. Seleccionar archivo" name="choose_file_btn"/> - <panel name="choose_file_panel"> - <panel name="choose_file_header_panel"> - <text name="choose_file_header_text"> - Elige el archivo de modelo - </text> - </panel> - <panel name="choose_file_content"> - <text name="advanced_users_text"> - Usuarios avanzados: si tienes experiencia con las herramientas de creación de contenidos 3D, quizá te interese utilizar la función de subida avanzada. - </text> - <button label="Cambiar al modo Avanzado" name="switch_to_advanced"/> - <text name="Cache location"> - Elige el archivo de modelo que deseas subir - </text> - <button label="Examinar..." label_selected="Examinar..." name="browse"/> - <text name="Model types"> - Second Life admite los archivos COLLADA (.dae) - </text> - <text name="dimensions"> - X Y Z - </text> - <text name="warning_label"> - ATENCIÓN: - </text> - <text name="warning_text"> - No podrás completar el paso final de la subida de este modelo a los servidores de Second Life. [secondlife:///app/floater/learn_more Averigua cómo] configurar tu cuenta para subir modelos de malla. - </text> - </panel> - </panel> - <panel name="optimize_panel"> - <panel name="optimize_header_panel"> - <text name="optimize_header_text"> - Optimizar el modelo - </text> - </panel> - <text name="optimize_description"> - Hemos optimizado el rendimiento del modelo, pero puedes ajustarlo más si lo deseas. - </text> - <panel name="optimize_content"> - <text name="high_detail_text"> - Generar el nivel de detalle: Alto - </text> - <text name="medium_detail_text"> - Generar el nivel de detalle: Medio - </text> - <text name="low_detail_text"> - Generar el nivel de detalle: Bajo - </text> - <text name="lowest_detail_text"> - Generar el nivel de detalle: Mínimo - </text> - </panel> - <panel name="content2"> - <button label="Recalcular la geometría" name="recalculate_geometry_btn"/> - <text name="lod_label"> - Vista previa de geometría - </text> - <combo_box name="preview_lod_combo" tool_tip="LOD para ver en renderizado de prueba"> - <combo_item name="high"> - Detalle alto - </combo_item> - <combo_item name="medium"> - Detalles medios - </combo_item> - <combo_item name="low"> - Detalle bajo - </combo_item> - <combo_item name="lowest"> - Detalles mínimos - </combo_item> - </combo_box> - </panel> - </panel> - <panel name="physics_panel"> - <panel name="physics_header_panel"> - <text name="physics_header_text"> - Ajustar la física - </text> - </panel> - <text name="physics_description"> - Crearemos una forma para la apariencia exterior del modelo. Ajusta el nivel de detalle de la forma según se necesite para el propósito proyectado del modelo. - </text> - <panel name="physics_content"> - <button label="Recalcular física" name="recalculate_physics_btn"/> - <button label="Recalculando..." name="recalculating_physics_btn"/> - <text name="lod_label"> - Prueba de física - </text> - <combo_box name="preview_lod_combo2" tool_tip="LOD para ver en renderizado de prueba"> - <combo_item name="high"> - Detalle alto - </combo_item> - <combo_item name="medium"> - Detalles medios - </combo_item> - <combo_item name="low"> - Detalle bajo - </combo_item> - <combo_item name="lowest"> - Detalles mínimos - </combo_item> - </combo_box> - </panel> - </panel> - <panel name="review_panel"> - <panel name="review_header_panel"> - <text name="review_header_text"> - Revisar - </text> - </panel> - <panel name="review_content"> - <text name="review_prim_equiv"> - Impacto en la parcela/región: [EQUIV] equivalentes en prim - </text> - <text name="review_fee"> - Cargaremos en tu cuenta el precio de subida de L$ [FEE]. - </text> - <text name="review_confirmation"> - Al pulsar en el botón de subida, confirmas que posees los derechos necesarios sobre el material que contiene el modelo. - </text> - </panel> - </panel> - <panel name="upload_panel"> - <panel name="upload_header_panel"> - <text name="upload_header_text"> - Subida finalizada - </text> - </panel> - <text name="model_uploaded_text"> - Se ha subido tu modelo. - </text> - <text name="inventory_text"> - Puedes buscar la carpeta Objetos en tu inventario. - </text> - <text name="charged_fee"> - Se han cargado [FEE] L$ en tu cuenta. - </text> - </panel> - <button label="<< Atrás" name="back"/> - <button label="Siguiente >>" name="next"/> - <button label="Calcular pesos y precio >>" name="calculate"/> - <button label="Calculando..." name="calculating"/> - <button label="Subir" name="upload" tool_tip="Cargar al simulador"/> - <button label="Cancelar" name="cancel"/> - <button label="Cerrar" name="close"/> - <spinner name="import_scale" value="1.0"/> - <string name="status_idle"> - Inactivo - </string> - <string name="status_parse_error"> - Problema de análisis de DAE - consulta los datos en el registro. - </string> - <string name="status_reading_file"> - Cargando... - </string> - <string name="status_generating_meshes"> - Generando redes... - </string> - <string name="status_vertex_number_overflow"> - Error: El número de intersección es superior a 65534. Cancelado. - </string> - <string name="bad_element"> - Error: el elemento no es válido - </string> - <string name="high"> - Alto - </string> - <string name="medium"> - Media - </string> - <string name="low"> - Bajo - </string> - <string name="lowest"> - Mínimo - </string> - <string name="mesh_status_good"> - Factúralo. - </string> - <string name="mesh_status_na"> - N/A - </string> - <string name="mesh_status_none"> - Ninguno - </string> - <string name="mesh_status_submesh_mismatch"> - Los niveles de detalle poseen un número distinto de caras a las que se pueden aplicar texturas. - </string> - <string name="mesh_status_mesh_mismatch"> - Los niveles de detalle poseen un número distinto de ejemplos de red. - </string> - <string name="mesh_status_too_many_vertices"> - El nivel de detalle posee demasiadas intersecciones. - </string> - <string name="mesh_status_missing_lod"> - Falta un nivel de detalle requerido. - </string> - <string name="layer_all"> - Todo - </string> -</floater> diff --git a/indra/newview/skins/default/xui/fr/floater_model_preview.xml b/indra/newview/skins/default/xui/fr/floater_model_preview.xml index a3b50351ae..0f272891c7 100644 --- a/indra/newview/skins/default/xui/fr/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/fr/floater_model_preview.xml @@ -214,7 +214,7 @@ </panel> </tab_container> <panel name="weights_and_warning_panel"> - <button label="Calculer les poids et les frais." name="calculate_btn" tool_tip="Calculer les poids et les frais."/> + <button label="Calculer les poids et les frais" name="calculate_btn" tool_tip="Calculer les poids et les frais."/> <button label="Annuler" name="cancel_btn"/> <button label="Charger le modèle" name="ok_btn" tool_tip="Charger dans le simulateur"/> <button label="Effacer les paramètres et réinitialiser le formulaire" name="reset_btn"/> diff --git a/indra/newview/skins/default/xui/fr/floater_model_wizard.xml b/indra/newview/skins/default/xui/fr/floater_model_wizard.xml deleted file mode 100644 index 128b9d6fa4..0000000000 --- a/indra/newview/skins/default/xui/fr/floater_model_wizard.xml +++ /dev/null @@ -1,208 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<floater name="Model Wizard" title="ASSISTANT DE CHARGEMENT DE MODÈLE"> - <button label="5. Chargement" name="upload_btn"/> - <button label="4. Vérification" name="review_btn"/> - <button label="3. Propriétés physiques" name="physics_btn"/> - <button label="2. Optimisation" name="optimize_btn"/> - <button label="1. Sélection du fichier" name="choose_file_btn"/> - <panel name="choose_file_panel"> - <panel name="choose_file_header_panel"> - <text name="choose_file_header_text"> - Choisir un fichier de modèle - </text> - </panel> - <panel name="choose_file_content"> - <text name="advanced_users_text"> - Utilisateurs expérimentés : si vous êtes habitué à utiliser des outils de création de contenu en 3D, l'outil de chargement avancé est mis à votre disposition. - </text> - <button label="Passer à Avancé" name="switch_to_advanced"/> - <text name="Cache location"> - Choisir un fichier de modèle à charger - </text> - <button label="Parcourir..." label_selected="Parcourir..." name="browse"/> - <text name="Model types"> - Second Life prend en charge les fichiers COLLADA (.dae). - </text> - <text name="dimensions"> - X Y Z - </text> - <text name="warning_label"> - AVERTISSEMENT : - </text> - <text name="warning_text"> - Vous ne pourrez pas effectuer l'étape de chargement finale du modèle sur les serveurs Second Life. [secondlife:///app/floater/learn_more Découvrez comment] configurer votre compte pour le chargement de modèles de maillage. - </text> - </panel> - </panel> - <panel name="optimize_panel"> - <panel name="optimize_header_panel"> - <text name="optimize_header_text"> - Optimiser le modèle - </text> - </panel> - <text name="optimize_description"> - Le modèle a été optimisé en termes de performances. Vous pouvez l'ajuster si vous le souhaitez. - </text> - <panel name="optimize_content"> - <text name="high_detail_text"> - Générer le niveau de détail : Élevé - </text> - <text name="medium_detail_text"> - Générer le niveau de détail : Moyen - </text> - <text name="low_detail_text"> - Générer le niveau de détail : Faible - </text> - <text name="lowest_detail_text"> - Générer le niveau de détail : Le plus faible - </text> - </panel> - <panel name="content2"> - <button label="Recalcul géométrique" name="recalculate_geometry_btn"/> - <text name="lod_label"> - Aperçu de la géométrie - </text> - <combo_box name="preview_lod_combo" tool_tip="Niveau de détail à afficher en rendu d'aperçu."> - <combo_item name="high"> - Niveau de détail élevé - </combo_item> - <combo_item name="medium"> - Niveau de détail moyen - </combo_item> - <combo_item name="low"> - Niveau de détail faible - </combo_item> - <combo_item name="lowest"> - Niveau de détail le plus faible - </combo_item> - </combo_box> - </panel> - </panel> - <panel name="physics_panel"> - <panel name="physics_header_panel"> - <text name="physics_header_text"> - Ajuster les propriétés physiques - </text> - </panel> - <text name="physics_description"> - Une forme va être créée pour l'enveloppe externe du modèle. Ajustez le niveau de détail de la forme en fonction de l'objectif souhaité pour votre modèle. - </text> - <panel name="physics_content"> - <button label="Recalcul physique" name="recalculate_physics_btn"/> - <button label="Recalcul en cours..." name="recalculating_physics_btn"/> - <text name="lod_label"> - Aperçu des propriétés physiques - </text> - <combo_box name="preview_lod_combo2" tool_tip="Niveau de détail à afficher en rendu d'aperçu."> - <combo_item name="high"> - Niveau de détail élevé - </combo_item> - <combo_item name="medium"> - Niveau de détail moyen - </combo_item> - <combo_item name="low"> - Niveau de détail faible - </combo_item> - <combo_item name="lowest"> - Niveau de détail le plus faible - </combo_item> - </combo_box> - </panel> - </panel> - <panel name="review_panel"> - <panel name="review_header_panel"> - <text name="review_header_text"> - Vérification - </text> - </panel> - <panel name="review_content"> - <text name="review_prim_equiv"> - Impact sur la parcelle/région : équivalent à [EQUIV] prims - </text> - <text name="review_fee"> - Votre compte sera débité de [FEE] L$ de frais de chargement. - </text> - <text name="review_confirmation"> - En cliquant sur le bouton de chargement, vous confirmez que vous disposez des droits appropriés sur le contenu du modèle. - </text> - </panel> - </panel> - <panel name="upload_panel"> - <panel name="upload_header_panel"> - <text name="upload_header_text"> - Chargement terminé - </text> - </panel> - <text name="model_uploaded_text"> - Votre modèle a été chargé. - </text> - <text name="inventory_text"> - Vous le trouverez dans le dossier Objets de votre inventaire. - </text> - <text name="charged_fee"> - Votre compte a été débité de [FEE] L$. - </text> - </panel> - <button label="<< Préc." name="back"/> - <button label="Suiv. >>" name="next"/> - <button label="Calculer les poids et les frais >>" name="calculate"/> - <button label="Calcul en cours..." name="calculating"/> - <button label="Charger" name="upload" tool_tip="Charger dans le simulateur."/> - <button label="Annuler" name="cancel"/> - <button label="Fermer" name="close"/> - <spinner name="import_scale" value="1.0"/> - <string name="status_idle"> - Inactif - </string> - <string name="status_parse_error"> - Problème d'analyse de fichier .dae ; reportez-vous au journal pour plus de détails. - </string> - <string name="status_reading_file"> - Chargement... - </string> - <string name="status_generating_meshes"> - Génération des maillages... - </string> - <string name="status_vertex_number_overflow"> - Erreur : valeur de sommet supérieure à 65534. Opération abandonnée. - </string> - <string name="bad_element"> - Erreur : élément non valide - </string> - <string name="high"> - Élevé - </string> - <string name="medium"> - Moyen - </string> - <string name="low"> - Faible - </string> - <string name="lowest"> - Le plus faible - </string> - <string name="mesh_status_good"> - Bon à publier ! - </string> - <string name="mesh_status_na"> - N/A - </string> - <string name="mesh_status_none"> - Aucun - </string> - <string name="mesh_status_submesh_mismatch"> - Un nombre différent de faces d'application de texture est associé aux niveaux de détail. - </string> - <string name="mesh_status_mesh_mismatch"> - Un nombre différent d'instances de maillage est associé aux niveaux de détail. - </string> - <string name="mesh_status_too_many_vertices"> - Trop de sommets pour le niveau de détail. - </string> - <string name="mesh_status_missing_lod"> - Niveau de détail requis manquant. - </string> - <string name="layer_all"> - Tout - </string> -</floater> diff --git a/indra/newview/skins/default/xui/it/floater_model_wizard.xml b/indra/newview/skins/default/xui/it/floater_model_wizard.xml deleted file mode 100644 index ab5fdb29e4..0000000000 --- a/indra/newview/skins/default/xui/it/floater_model_wizard.xml +++ /dev/null @@ -1,208 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<floater name="Model Wizard" title="PROCEDURA GUIDATA CARICA MODELLO"> - <button label="5. Carica sul server" name="upload_btn"/> - <button label="4. Rivedi" name="review_btn"/> - <button label="3. Fisica" name="physics_btn"/> - <button label="2. Ottimizza" name="optimize_btn"/> - <button label="1. Seleziona file" name="choose_file_btn"/> - <panel name="choose_file_panel"> - <panel name="choose_file_header_panel"> - <text name="choose_file_header_text"> - Seleziona file modello - </text> - </panel> - <panel name="choose_file_content"> - <text name="advanced_users_text"> - Utenti avanzati: Gli utenti che hanno dimestichezza con gli strumenti di creazione 3D possono usare le opzioni di caricamento avanzate. - </text> - <button label="Passa a modalità avanzata" name="switch_to_advanced"/> - <text name="Cache location"> - Scegli il file del modello da caricare - </text> - <button label="Sfoglia..." label_selected="Sfoglia..." name="browse"/> - <text name="Model types"> - Second Life supporta file COLLADA (.dae) - </text> - <text name="dimensions"> - X Y Z - </text> - <text name="warning_label"> - ATTENZIONE: - </text> - <text name="warning_text"> - Non sarà possibile completare il passaggio finale per il caricamento finale di questo modello sui server di Second Life. [secondlife:///app/floater/learn_more Scopri come] impostare l'account per il caricamento di modelli con reticolo. - </text> - </panel> - </panel> - <panel name="optimize_panel"> - <panel name="optimize_header_panel"> - <text name="optimize_header_text"> - Ottimizza modello - </text> - </panel> - <text name="optimize_description"> - Abbiamo ottimizzato il modello per migliorare le prestazioni. Se necessario, può essere regolato ulteriormente. - </text> - <panel name="optimize_content"> - <text name="high_detail_text"> - Genera livello di dettaglio: Alto - </text> - <text name="medium_detail_text"> - Genera livello di dettaglio: Medio - </text> - <text name="low_detail_text"> - Genera livello di dettaglio: Basso - </text> - <text name="lowest_detail_text"> - Genera livello di dettaglio: Bassissimo - </text> - </panel> - <panel name="content2"> - <button label="Ricalcola geometria" name="recalculate_geometry_btn"/> - <text name="lod_label"> - Anteprima geometria - </text> - <combo_box name="preview_lod_combo" tool_tip="Livello di dettaglio per anteprima rendering"> - <combo_item name="high"> - Molti dettagli - </combo_item> - <combo_item name="medium"> - Dettagli medi - </combo_item> - <combo_item name="low"> - Meno dettagli - </combo_item> - <combo_item name="lowest"> - Dettaglio minimo - </combo_item> - </combo_box> - </panel> - </panel> - <panel name="physics_panel"> - <panel name="physics_header_panel"> - <text name="physics_header_text"> - Modifica fisica - </text> - </panel> - <text name="physics_description"> - Verrà creata una forma per lo scafo esterno del modello. Regola il livello di dettaglio della forma in base al fine desiderato del modello. - </text> - <panel name="physics_content"> - <button label="Ricalcola fisica" name="recalculate_physics_btn"/> - <button label="Ricalcolo in corso..." name="recalculating_physics_btn"/> - <text name="lod_label"> - Anteprima fisica - </text> - <combo_box name="preview_lod_combo2" tool_tip="Livello di dettaglio per anteprima rendering"> - <combo_item name="high"> - Molti dettagli - </combo_item> - <combo_item name="medium"> - Dettagli medi - </combo_item> - <combo_item name="low"> - Meno dettagli - </combo_item> - <combo_item name="lowest"> - Dettaglio minimo - </combo_item> - </combo_box> - </panel> - </panel> - <panel name="review_panel"> - <panel name="review_header_panel"> - <text name="review_header_text"> - Rivedi - </text> - </panel> - <panel name="review_content"> - <text name="review_prim_equiv"> - Impatto sul lotto o sulla regione: [EQUIV] prim equivalenti - </text> - <text name="review_fee"> - All'account verrà accreditata una tariffa di caricamento pari a L$ [FEE]. - </text> - <text name="review_confirmation"> - Facendo clic sul pulsante Carica, confermi di possedere i diritti relativi ai materiali contenuti nel modello. - </text> - </panel> - </panel> - <panel name="upload_panel"> - <panel name="upload_header_panel"> - <text name="upload_header_text"> - Caricamento completato - </text> - </panel> - <text name="model_uploaded_text"> - Il modello è stato caricato. - </text> - <text name="inventory_text"> - Puoi trovarlo nella cartella Oggetti nel tuo inventario. - </text> - <text name="charged_fee"> - La somma di L$ [FEE] è stata addebitata sul tuo account. - </text> - </panel> - <button label="<< Indietro" name="back"/> - <button label="Avanti >>" name="next"/> - <button label="Calcolare pesi e tariffa >>" name="calculate"/> - <button label="Calcolo in corso..." name="calculating"/> - <button label="Carica" name="upload" tool_tip="Carica al simulatore"/> - <button label="Annulla" name="cancel"/> - <button label="Chiudi" name="close"/> - <spinner name="import_scale" value="1.0"/> - <string name="status_idle"> - Pausa - </string> - <string name="status_parse_error"> - Problema nell'elaborazione DAE - vedi il registro per informazioni al riguardo. - </string> - <string name="status_reading_file"> - Caricamento in corso... - </string> - <string name="status_generating_meshes"> - Generazione reticoli... - </string> - <string name="status_vertex_number_overflow"> - Errore: numero di vertici maggiore di 65534, annullato. - </string> - <string name="bad_element"> - Errore: elemento non valido - </string> - <string name="high"> - Alto - </string> - <string name="medium"> - Medio - </string> - <string name="low"> - Basso - </string> - <string name="lowest"> - Bassissimo - </string> - <string name="mesh_status_good"> - Invia! - </string> - <string name="mesh_status_na"> - N/D - </string> - <string name="mesh_status_none"> - Nessuno - </string> - <string name="mesh_status_submesh_mismatch"> - Ai vari livelli del dettaglio corrispondono numeri diversi di faccette con texture. - </string> - <string name="mesh_status_mesh_mismatch"> - Ai vari livelli del dettaglio corrispondono numeri diversi istanze di reticoli. - </string> - <string name="mesh_status_too_many_vertices"> - Troppi vertici per il livello di dettaglio. - </string> - <string name="mesh_status_missing_lod"> - Livello di dettaglio minimo mancante. - </string> - <string name="layer_all"> - Tutto - </string> -</floater> diff --git a/indra/newview/skins/default/xui/ja/floater_model_wizard.xml b/indra/newview/skins/default/xui/ja/floater_model_wizard.xml deleted file mode 100644 index 746bd8553c..0000000000 --- a/indra/newview/skins/default/xui/ja/floater_model_wizard.xml +++ /dev/null @@ -1,208 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<floater name="Model Wizard" title="モデルウィザードをアップロード"> - <button label="5. アップロード" name="upload_btn"/> - <button label="4. 確認" name="review_btn"/> - <button label="3. 物理効果" name="physics_btn"/> - <button label="2. 最適化" name="optimize_btn"/> - <button label="1. ファイルを選択" name="choose_file_btn"/> - <panel name="choose_file_panel"> - <panel name="choose_file_header_panel"> - <text name="choose_file_header_text"> - モデルファイルを選択 - </text> - </panel> - <panel name="choose_file_content"> - <text name="advanced_users_text"> - 上級ユーザーの場合:3D コンテンツ制作ツールの使用に慣れている方は、高度なアップローダーもお試しください。 - </text> - <button label="アドバンスモードに切り替える" name="switch_to_advanced"/> - <text name="Cache location"> - アップロードするモデルファイルを選択 - </text> - <button label="参照..." label_selected="参照..." name="browse"/> - <text name="Model types"> - Second Life は COLLADA (.dae) ファイルをサポートします。 - </text> - <text name="dimensions"> - X Y Z - </text> - <text name="warning_label"> - 警告: - </text> - <text name="warning_text"> - このモデルを Second Life サーバーにアップロードするための最終手順を実行できません。[secondlife:///app/floater/learn_more こちらを参照して]、メッシュモデルをアップロードできるようにアカウントを設定してください。 - </text> - </panel> - </panel> - <panel name="optimize_panel"> - <panel name="optimize_header_panel"> - <text name="optimize_header_text"> - モデルを最適化 - </text> - </panel> - <text name="optimize_description"> - モデルはパフォーマンスを重視して最適化されています。必要に応じて調整してください。 - </text> - <panel name="optimize_content"> - <text name="high_detail_text"> - 次の描画詳細度を作成:高 - </text> - <text name="medium_detail_text"> - 次の描画詳細度を作成:中 - </text> - <text name="low_detail_text"> - 次の描画詳細度を作成:低 - </text> - <text name="lowest_detail_text"> - 次の描画詳細度を作成:最低 - </text> - </panel> - <panel name="content2"> - <button label="ジオメトリを再計算" name="recalculate_geometry_btn"/> - <text name="lod_label"> - ジオメトリのプレビュー - </text> - <combo_box name="preview_lod_combo" tool_tip="プレビュー表示の LOD 設定"> - <combo_item name="high"> - 高い詳細度 - </combo_item> - <combo_item name="medium"> - 中の詳細度 - </combo_item> - <combo_item name="low"> - 低い詳細度 - </combo_item> - <combo_item name="lowest"> - 最低の詳細度 - </combo_item> - </combo_box> - </panel> - </panel> - <panel name="physics_panel"> - <panel name="physics_header_panel"> - <text name="physics_header_text"> - 物理作用の調整 - </text> - </panel> - <text name="physics_description"> - モデルの外殻構造のシェイプは弊社が作成します。モデルの目的に応じてシェイプの詳細度を調整してください。 - </text> - <panel name="physics_content"> - <button label="物理作用を再計算" name="recalculate_physics_btn"/> - <button label="再計算中..." name="recalculating_physics_btn"/> - <text name="lod_label"> - 物理作用のプレビュー - </text> - <combo_box name="preview_lod_combo2" tool_tip="プレビュー表示の LOD 設定"> - <combo_item name="high"> - 高い詳細度 - </combo_item> - <combo_item name="medium"> - 中の詳細度 - </combo_item> - <combo_item name="low"> - 低い詳細度 - </combo_item> - <combo_item name="lowest"> - 最低の詳細度 - </combo_item> - </combo_box> - </panel> - </panel> - <panel name="review_panel"> - <panel name="review_header_panel"> - <text name="review_header_text"> - 確認 - </text> - </panel> - <panel name="review_content"> - <text name="review_prim_equiv"> - 区画/リージョンへの負荷:[EQUIV] プリム換算値 - </text> - <text name="review_fee"> - L$ [FEE] のアップロード料金があなたのアカウントに請求されます。 - </text> - <text name="review_confirmation"> - アップロードボタンをクリックすることにより、モデルに含まれるマテリアルの所有権や使用許可の所持を認めたことになります。 - </text> - </panel> - </panel> - <panel name="upload_panel"> - <panel name="upload_header_panel"> - <text name="upload_header_text"> - アップロード完了 - </text> - </panel> - <text name="model_uploaded_text"> - モデルがアップロードされました。 - </text> - <text name="inventory_text"> - それはインベントリの「オブジェクト」フォルダにあります。 - </text> - <text name="charged_fee"> - あなたのアカウントに L$ [FEE] が請求されました。 - </text> - </panel> - <button label="<< 戻る" name="back"/> - <button label="次へ>>" name="next"/> - <button label="ウェイトと料金の計算 >>" name="calculate"/> - <button label="計算中..." name="calculating"/> - <button label="アップロード" name="upload" tool_tip="シミュレーターにアップロード"/> - <button label="取り消し" name="cancel"/> - <button label="閉じる" name="close"/> - <spinner name="import_scale" value="1.0"/> - <string name="status_idle"> - 待機状態 - </string> - <string name="status_parse_error"> - Dae に問題が見つかりました - 詳細についてはログをご参照ください。 - </string> - <string name="status_reading_file"> - ローディング... - </string> - <string name="status_generating_meshes"> - メッシュを作成中 - </string> - <string name="status_vertex_number_overflow"> - エラー:頂点の数が65534を超過したので中止されました。 - </string> - <string name="bad_element"> - エラー:要素が無効です - </string> - <string name="high"> - 高 - </string> - <string name="medium"> - 中 - </string> - <string name="low"> - 低 - </string> - <string name="lowest"> - 最低 - </string> - <string name="mesh_status_good"> - 発送 - </string> - <string name="mesh_status_na"> - 該当なし - </string> - <string name="mesh_status_none"> - なし - </string> - <string name="mesh_status_submesh_mismatch"> - テクスチャ編集可能な面の数は描画詳細度に応じて異なります。 - </string> - <string name="mesh_status_mesh_mismatch"> - メッシュインスタンスの数は描画詳細度に応じて異なります。 - </string> - <string name="mesh_status_too_many_vertices"> - 描画詳細度に対して頂点の数が多すぎます。 - </string> - <string name="mesh_status_missing_lod"> - 必要な描画詳細度が見つかりません。 - </string> - <string name="layer_all"> - 全て - </string> -</floater> diff --git a/indra/newview/skins/default/xui/pt/floater_model_wizard.xml b/indra/newview/skins/default/xui/pt/floater_model_wizard.xml deleted file mode 100644 index 0d07303c91..0000000000 --- a/indra/newview/skins/default/xui/pt/floater_model_wizard.xml +++ /dev/null @@ -1,208 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<floater name="Model Wizard" title="CARREGAR ASSISTENTE DE MODELAGEM"> - <button label="5. Carregar" name="upload_btn"/> - <button label="4. Revisar" name="review_btn"/> - <button label="3. Física" name="physics_btn"/> - <button label="2. Otimizar" name="optimize_btn"/> - <button label="1. Selecionra arquivo" name="choose_file_btn"/> - <panel name="choose_file_panel"> - <panel name="choose_file_header_panel"> - <text name="choose_file_header_text"> - Escolher arquivo de modelo - </text> - </panel> - <panel name="choose_file_content"> - <text name="advanced_users_text"> - Usuários avançados: se você estiver familiarizado com ferramentas de criação de conteúdo 3D, use o Advanced Uploader. - </text> - <button label="Trocar para avançado" name="switch_to_advanced"/> - <text name="Cache location"> - Escolha o arquivo de modelo para upload - </text> - <button label="Procurar..." label_selected="Procurar..." name="browse"/> - <text name="Model types"> - O Second Life oferece suporte a arquivos COLLADA (.dae) - </text> - <text name="dimensions"> - X Y Z - </text> - <text name="warning_label"> - AVISO: - </text> - <text name="warning_text"> - Não será possível concluir a etapa final do upload desse modelo para os servidores do Second Life. [secondlife:///app/floater/learn_more Saiba como] configurar sua conta para uploads de modelos mesh. - </text> - </panel> - </panel> - <panel name="optimize_panel"> - <panel name="optimize_header_panel"> - <text name="optimize_header_text"> - Otimizar modelo - </text> - </panel> - <text name="optimize_description"> - O modelo foi ajustado para desempenho. Faça novos ajustes, se desejar. - </text> - <panel name="optimize_content"> - <text name="high_detail_text"> - Gerar nível de detalhes: Alto - </text> - <text name="medium_detail_text"> - Gerar nível de detalhes: Médio - </text> - <text name="low_detail_text"> - Gerar nível de detalhes: Baixo - </text> - <text name="lowest_detail_text"> - Gerar nível de detalhes: Mais baixo - </text> - </panel> - <panel name="content2"> - <button label="Recalcular geometria" name="recalculate_geometry_btn"/> - <text name="lod_label"> - Visualização da geometria - </text> - <combo_box name="preview_lod_combo" tool_tip="LOD para exibir na renderização de visualização"> - <combo_item name="high"> - Máximo de detalhes - </combo_item> - <combo_item name="medium"> - Detalhes médios - </combo_item> - <combo_item name="low"> - Poucos detalhes - </combo_item> - <combo_item name="lowest"> - Mínimo de detalhes - </combo_item> - </combo_box> - </panel> - </panel> - <panel name="physics_panel"> - <panel name="physics_header_panel"> - <text name="physics_header_text"> - Ajustar físico - </text> - </panel> - <text name="physics_description"> - Criaremos uma forma para o corpo externo do modelo. Ajuste o nível de detalhes como necessário para a finalidade desejada de seu modelo. - </text> - <panel name="physics_content"> - <button label="Recalcular físico" name="recalculate_physics_btn"/> - <button label="Recalculando..." name="recalculating_physics_btn"/> - <text name="lod_label"> - Visualização do físico - </text> - <combo_box name="preview_lod_combo2" tool_tip="LOD para exibir na renderização de visualização"> - <combo_item name="high"> - Máximo de detalhes - </combo_item> - <combo_item name="medium"> - Detalhes médios - </combo_item> - <combo_item name="low"> - Poucos detalhes - </combo_item> - <combo_item name="lowest"> - Mínimo de detalhes - </combo_item> - </combo_box> - </panel> - </panel> - <panel name="review_panel"> - <panel name="review_header_panel"> - <text name="review_header_text"> - Revisar - </text> - </panel> - <panel name="review_content"> - <text name="review_prim_equiv"> - Impacto no lote/região: [EQUIV] equivalentes de prim - </text> - <text name="review_fee"> - Uma tarifa de upload de L$ [FEE] será debitada da sua conta. - </text> - <text name="review_confirmation"> - Ao clicar no botão de upload, você confirma que detém os direitos apropriados sobre o material contido no modelo. - </text> - </panel> - </panel> - <panel name="upload_panel"> - <panel name="upload_header_panel"> - <text name="upload_header_text"> - Upload concluído - </text> - </panel> - <text name="model_uploaded_text"> - Seu modelo foi carregado. - </text> - <text name="inventory_text"> - Disponível na pasta Objetos do seu inventário. - </text> - <text name="charged_fee"> - L$ [FEE] foram debitados da sua conta. - </text> - </panel> - <button label="<< Voltar" name="back"/> - <button label="Próximo >>" name="next"/> - <button label="Calcular pesos e tarifa >>" name="calculate"/> - <button label="Calculando..." name="calculating"/> - <button label="Carregar" name="upload" tool_tip="Carregar no simulador"/> - <button label="Cancelar" name="cancel"/> - <button label="Fechar" name="close"/> - <spinner name="import_scale" value="1.0"/> - <string name="status_idle"> - Inativo - </string> - <string name="status_parse_error"> - Dae parsing - erro, detalhes no log. - </string> - <string name="status_reading_file"> - Carregando... - </string> - <string name="status_generating_meshes"> - Gerando meshes... - </string> - <string name="status_vertex_number_overflow"> - Erro: Número de Vertex acima de 65534. Abortado. - </string> - <string name="bad_element"> - Erro: elemento inválido - </string> - <string name="high"> - Alto - </string> - <string name="medium"> - Médio - </string> - <string name="low"> - Baixo - </string> - <string name="lowest"> - Mais baixo - </string> - <string name="mesh_status_good"> - Entregar! - </string> - <string name="mesh_status_na"> - N/D - </string> - <string name="mesh_status_none"> - Nenhum - </string> - <string name="mesh_status_submesh_mismatch"> - Cada nível de detalhamento têm um número de faces para textura. - </string> - <string name="mesh_status_mesh_mismatch"> - Cada nível de detalhamento têm um número de faces para textura. - </string> - <string name="mesh_status_too_many_vertices"> - O nível de detalhamento possui vértices demais. - </string> - <string name="mesh_status_missing_lod"> - Falta o nível de detalhamento necessário. - </string> - <string name="layer_all"> - Tudo - </string> -</floater> diff --git a/indra/newview/skins/default/xui/ru/floater_model_wizard.xml b/indra/newview/skins/default/xui/ru/floater_model_wizard.xml deleted file mode 100644 index c1a63bf7da..0000000000 --- a/indra/newview/skins/default/xui/ru/floater_model_wizard.xml +++ /dev/null @@ -1,208 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<floater name="Model Wizard" title="ПЕРЕДАТЬ МАСТЕР МОДЕЛИРОВАНИЯ"> - <button label="5. Передать" name="upload_btn"/> - <button label="4. Просмотр" name="review_btn"/> - <button label="3. Физика" name="physics_btn"/> - <button label="2. Оптимизировать" name="optimize_btn"/> - <button label="1. Выбрать файл" name="choose_file_btn"/> - <panel name="choose_file_panel"> - <panel name="choose_file_header_panel"> - <text name="choose_file_header_text"> - Выберите файл модели - </text> - </panel> - <panel name="choose_file_content"> - <text name="advanced_users_text"> - Пользователям, работающим в расширенном режиме: если вы умеете создавать трехмерные графические объекты, то, возможно, захотите воспользоваться средством Advanced Uploader, которое предоставляет расширенные возможности передачи объектов. - </text> - <button label="Перейти в расширенный режим" name="switch_to_advanced"/> - <text name="Cache location"> - Выберите файл модели для передачи - </text> - <button label="Обзор..." label_selected="Обзор..." name="browse"/> - <text name="Model types"> - В Second Life поддерживаются файлы COLLADA (.dae) - </text> - <text name="dimensions"> - X Y Z - </text> - <text name="warning_label"> - ВНИМАНИЕ! - </text> - <text name="warning_text"> - Вы не сможете завершить передачу этой модели на серверы Second Life. [secondlife:///app/floater/learn_more Узнайте, как] настроить в вашем аккаунте передачу сеточных моделей. - </text> - </panel> - </panel> - <panel name="optimize_panel"> - <panel name="optimize_header_panel"> - <text name="optimize_header_text"> - Оптимизировать модель - </text> - </panel> - <text name="optimize_description"> - Мы оптимизировали модель для повышения быстродействия. По желанию можно выполнить дополнительную настройку. - </text> - <panel name="optimize_content"> - <text name="high_detail_text"> - Создать уровень детализации: Высокий - </text> - <text name="medium_detail_text"> - Создать уровень детализации: Средний - </text> - <text name="low_detail_text"> - Создать уровень детализации: Низкий - </text> - <text name="lowest_detail_text"> - Создать уровень детализации: Самый низкий - </text> - </panel> - <panel name="content2"> - <button label="Пересчитать геометрию" name="recalculate_geometry_btn"/> - <text name="lod_label"> - Просмотр геометрии - </text> - <combo_box name="preview_lod_combo" tool_tip="Детализация при предварительном просмотре"> - <combo_item name="high"> - Детально - </combo_item> - <combo_item name="medium"> - Средняя детализация - </combo_item> - <combo_item name="low"> - Мало деталей - </combo_item> - <combo_item name="lowest"> - Минимум деталей - </combo_item> - </combo_box> - </panel> - </panel> - <panel name="physics_panel"> - <panel name="physics_header_panel"> - <text name="physics_header_text"> - Настроить физические параметры - </text> - </panel> - <text name="physics_description"> - Мы создадим форму для внешнего каркаса модели. Настройте уровень детализации формы в соответствии с целями, для которых предназначена модель. - </text> - <panel name="physics_content"> - <button label="Пересчитать физические данные" name="recalculate_physics_btn"/> - <button label="Пересчет..." name="recalculating_physics_btn"/> - <text name="lod_label"> - Просмотр физических данных - </text> - <combo_box name="preview_lod_combo2" tool_tip="Уровень детализации при предварительном просмотре"> - <combo_item name="high"> - Детально - </combo_item> - <combo_item name="medium"> - Средняя детализация - </combo_item> - <combo_item name="low"> - Мало деталей - </combo_item> - <combo_item name="lowest"> - Минимум деталей - </combo_item> - </combo_box> - </panel> - </panel> - <panel name="review_panel"> - <panel name="review_header_panel"> - <text name="review_header_text"> - Просмотр - </text> - </panel> - <panel name="review_content"> - <text name="review_prim_equiv"> - Воздействие на участок/регион: эквивалент в примитивах: [EQUIV] - </text> - <text name="review_fee"> - За передачу с вашего счета будет снята плата в размере L$[FEE]. - </text> - <text name="review_confirmation"> - Нажав кнопку «Передать», вы подтверждаете, что у вас есть надлежащие права на все составляющие модели. - </text> - </panel> - </panel> - <panel name="upload_panel"> - <panel name="upload_header_panel"> - <text name="upload_header_text"> - Передача завершена - </text> - </panel> - <text name="model_uploaded_text"> - Ваша модель передана. - </text> - <text name="inventory_text"> - Находится в папке «Объекты» вашего инвентаря. - </text> - <text name="charged_fee"> - С вашего счета снято: L$[FEE]. - </text> - </panel> - <button label="<< Назад" name="back"/> - <button label="Далее >>" name="next"/> - <button label="Рассчитать вес и плату >>" name="calculate"/> - <button label="Расчет..." name="calculating"/> - <button label="Передать" name="upload" tool_tip="Передать в симулятор"/> - <button label="Отмена" name="cancel"/> - <button label="Закрыть" name="close"/> - <spinner name="import_scale" value="1.0"/> - <string name="status_idle"> - Неактивно - </string> - <string name="status_parse_error"> - Проблема при анализе файла DAE – см. подробности в журнале. - </string> - <string name="status_reading_file"> - Загрузка... - </string> - <string name="status_generating_meshes"> - Создаются меши... - </string> - <string name="status_vertex_number_overflow"> - Ошибка. Число вершин превышает 65534. Прервано. - </string> - <string name="bad_element"> - Ошибка: недопустимый элемент - </string> - <string name="high"> - высокий - </string> - <string name="medium"> - средний - </string> - <string name="low"> - низкий - </string> - <string name="lowest"> - самый низкий - </string> - <string name="mesh_status_good"> - Доставлено! - </string> - <string name="mesh_status_na"> - Н/Д - </string> - <string name="mesh_status_none"> - Нет - </string> - <string name="mesh_status_submesh_mismatch"> - Отличается число текстурируемых граней на уровнях детализации. - </string> - <string name="mesh_status_mesh_mismatch"> - Отличается число экземпляров меша на уровнях детализации. - </string> - <string name="mesh_status_too_many_vertices"> - Слишком много вершин на уровне детализации. - </string> - <string name="mesh_status_missing_lod"> - Отсутствует необходимый уровень детализации. - </string> - <string name="layer_all"> - Все - </string> -</floater> diff --git a/indra/newview/skins/default/xui/tr/floater_model_wizard.xml b/indra/newview/skins/default/xui/tr/floater_model_wizard.xml deleted file mode 100644 index 9d8b982c24..0000000000 --- a/indra/newview/skins/default/xui/tr/floater_model_wizard.xml +++ /dev/null @@ -1,208 +0,0 @@ -<?xml version="1.0" encoding="utf-8" standalone="yes"?> -<floater name="Model Wizard" title="KARŞIYA MODEL YÜKLEME SİHİRBAZI"> - <button label="5. Karşıya Yükle" name="upload_btn"/> - <button label="4. İncele" name="review_btn"/> - <button label="3. Fizik" name="physics_btn"/> - <button label="2. Optimize et" name="optimize_btn"/> - <button label="1. Dosya Seç" name="choose_file_btn"/> - <panel name="choose_file_panel"> - <panel name="choose_file_header_panel"> - <text name="choose_file_header_text"> - Model dosyasını seçin - </text> - </panel> - <panel name="choose_file_content"> - <text name="advanced_users_text"> - Gelişmiş kullanıcılar: Eğer 3B içerik oluşturma araçlarını kullanmayı biliyorsanız, Gelişmiş Karşıya Yükleyiciyi kullanmak isteyebilirsiniz. - </text> - <button label="Gelişmişe geç" name="switch_to_advanced"/> - <text name="Cache location"> - Karşıya yüklenecek model dosyasını seçin - </text> - <button label="Gözat..." label_selected="Gözat..." name="browse"/> - <text name="Model types"> - Second Life, COLLADA (.dae) dosyalarını destekler - </text> - <text name="dimensions"> - X Y Z - </text> - <text name="warning_label"> - UYARI: - </text> - <text name="warning_text"> - Bu modelin Second Life sunucularına nihai karşıya yükleme adımını tamamlayamayacaksınız. Hesabınızı örgü modellerinin karşıya yüklenmesi için ayarlamanın [secondlife:///app/floater/learn_more nasıl yapılacağını öğrenin]. - </text> - </panel> - </panel> - <panel name="optimize_panel"> - <panel name="optimize_header_panel"> - <text name="optimize_header_text"> - Modeli optimize et - </text> - </panel> - <text name="optimize_description"> - Modeli performans için optimize ettik. İstiyorsanız daha da ayarlayabilirsiniz. - </text> - <panel name="optimize_content"> - <text name="high_detail_text"> - Ayrıntı Seviyesi Oluştur: Yüksek - </text> - <text name="medium_detail_text"> - Ayrıntı Seviyesi Oluştur: Orta - </text> - <text name="low_detail_text"> - Ayrıntı Seviyesi Oluştur: Düşük - </text> - <text name="lowest_detail_text"> - Ayrıntı Seviyesi Oluştur: En Düşük - </text> - </panel> - <panel name="content2"> - <button label="Geometri hesaplarını tekrar yap" name="recalculate_geometry_btn"/> - <text name="lod_label"> - Geometri önizleme - </text> - <combo_box name="preview_lod_combo" tool_tip="Önizleme işlemesinde görülecek ayrıntı seviyesi"> - <combo_item name="high"> - Çok ayrıntı - </combo_item> - <combo_item name="medium"> - Orta düzey ayrıntı - </combo_item> - <combo_item name="low"> - Az ayrıntı - </combo_item> - <combo_item name="lowest"> - En az ayrıntı - </combo_item> - </combo_box> - </panel> - </panel> - <panel name="physics_panel"> - <panel name="physics_header_panel"> - <text name="physics_header_text"> - Fizik ayarlarını yap - </text> - </panel> - <text name="physics_description"> - Modelin dış gövdesi için bir şekil oluşturacağız. Modelinizin amacına uygun olarak şeklin ayrıntı seviyesini belirleyin. - </text> - <panel name="physics_content"> - <button label="Fizik hesaplarını tekrar yap" name="recalculate_physics_btn"/> - <button label="Tekrar hesaplanıyor..." name="recalculating_physics_btn"/> - <text name="lod_label"> - Fizik önizleme - </text> - <combo_box name="preview_lod_combo2" tool_tip="Önizleme işlemesinde görülecek ayrıntı seviyesi"> - <combo_item name="high"> - Çok ayrıntı - </combo_item> - <combo_item name="medium"> - Orta düzey ayrıntı - </combo_item> - <combo_item name="low"> - Az ayrıntı - </combo_item> - <combo_item name="lowest"> - En az ayrıntı - </combo_item> - </combo_box> - </panel> - </panel> - <panel name="review_panel"> - <panel name="review_header_panel"> - <text name="review_header_text"> - İncele - </text> - </panel> - <panel name="review_content"> - <text name="review_prim_equiv"> - Parsele/bölgeye etkisi: [EQUIV] prim eşdeğerleri - </text> - <text name="review_fee"> - Hesabınızdan L$ [FEE] karşıya yükleme ücreti düşülecektir. - </text> - <text name="review_confirmation"> - Karşıya yükleme düğmesine tıkladığınızda, modelde yer alan malzeme için ilgili haklara sahip olduğunuzu teyid edersiniz. - </text> - </panel> - </panel> - <panel name="upload_panel"> - <panel name="upload_header_panel"> - <text name="upload_header_text"> - Karşıya yükleme bitti - </text> - </panel> - <text name="model_uploaded_text"> - Modeliniz karşıya yüklendi. - </text> - <text name="inventory_text"> - Bunu, envanterinizdeki Nesneler klasöründe bulacaksınız. - </text> - <text name="charged_fee"> - Hesabınızdan L$ [FEE] düşüldü. - </text> - </panel> - <button label="<< Geri" name="back"/> - <button label="Sonraki >>" name="next"/> - <button label="Ağırlıkları ve ücreti hesapla >>" name="calculate"/> - <button label="Hesaplanıyor..." name="calculating"/> - <button label="Karşıya Yükle" name="upload" tool_tip="Simülatöre karşıya yükle"/> - <button label="İptal" name="cancel"/> - <button label="Kapat" name="close"/> - <spinner name="import_scale" value="1.0"/> - <string name="status_idle"> - Boşta - </string> - <string name="status_parse_error"> - Dae ayrıştırma sorunu - ayrıntılar için günlüğe bakın. - </string> - <string name="status_reading_file"> - Yükleniyor... - </string> - <string name="status_generating_meshes"> - Örgüler Oluşturuluyor... - </string> - <string name="status_vertex_number_overflow"> - Hata: Köşe numarası 65534'ten fazla, işlem durduruldu! - </string> - <string name="bad_element"> - Hata: Öğe geçersiz - </string> - <string name="high"> - Yüksek - </string> - <string name="medium"> - Orta - </string> - <string name="low"> - Düşük - </string> - <string name="lowest"> - En Düşük - </string> - <string name="mesh_status_good"> - Uygula! - </string> - <string name="mesh_status_na"> - G/D - </string> - <string name="mesh_status_none"> - Hiçbiri - </string> - <string name="mesh_status_submesh_mismatch"> - Ayrıntı seviyelerinde farklı sayıda dokulanabilir yüz var. - </string> - <string name="mesh_status_mesh_mismatch"> - Ayrıntı seviyelerinde farklı sayıda örgü örneği var. - </string> - <string name="mesh_status_too_many_vertices"> - Ayrıntı seviyesinde fazla sayıda köşe var. - </string> - <string name="mesh_status_missing_lod"> - Gereken ayrıntı seviyesi eksik. - </string> - <string name="layer_all"> - Tümü - </string> -</floater> diff --git a/indra/newview/tests/llagentaccess_test.cpp b/indra/newview/tests/llagentaccess_test.cpp index c970d79975..0141a219c5 100644 --- a/indra/newview/tests/llagentaccess_test.cpp +++ b/indra/newview/tests/llagentaccess_test.cpp @@ -111,18 +111,6 @@ namespace tut ensure("1 isMature", !aa.isMature()); ensure("1 isAdult", !aa.isAdult()); - // this is kinda bad -- setting this forces maturity to MATURE but !teen != Mature anymore - aa.setTeen(false); - ensure("2 isTeen", !aa.isTeen()); - ensure("2 isMature", aa.isMature()); - ensure("2 isAdult", !aa.isAdult()); - - // have to flip it back and make sure it still works - aa.setTeen(true); - ensure("3 isTeen", aa.isTeen()); - ensure("3 isMature", !aa.isMature()); - ensure("3 isAdult", !aa.isAdult()); - // check the conversion routine ensure_equals("1 conversion", SIM_ACCESS_PG, aa.convertTextToMaturity('P')); ensure_equals("2 conversion", SIM_ACCESS_MATURE, aa.convertTextToMaturity('M')); @@ -131,21 +119,21 @@ namespace tut // now try the other method of setting it - PG aa.setMaturity('P'); - ensure("4 isTeen", aa.isTeen()); - ensure("4 isMature", !aa.isMature()); - ensure("4 isAdult", !aa.isAdult()); + ensure("2 isTeen", aa.isTeen()); + ensure("2 isMature", !aa.isMature()); + ensure("2 isAdult", !aa.isAdult()); // Mature aa.setMaturity('M'); - ensure("5 isTeen", !aa.isTeen()); - ensure("5 isMature", aa.isMature()); - ensure("5 isAdult", !aa.isAdult()); + ensure("3 isTeen", !aa.isTeen()); + ensure("3 isMature", aa.isMature()); + ensure("3 isAdult", !aa.isAdult()); // Adult aa.setMaturity('A'); - ensure("6 isTeen", !aa.isTeen()); - ensure("6 isMature", aa.isMature()); - ensure("6 isAdult", aa.isAdult()); + ensure("4 isTeen", !aa.isTeen()); + ensure("4 isMature", aa.isMature()); + ensure("4 isAdult", aa.isAdult()); } @@ -239,18 +227,6 @@ namespace tut cgr.declareU32("PreferredMaturity", SIM_ACCESS_PG, "declared_for_test", FALSE); LLAgentAccess aa(cgr); - ensure("1 transition starts false", !aa.isInTransition()); - aa.setTransition(); - ensure("2 transition now true", aa.isInTransition()); - } - - template<> template<> - void agentaccess_object_t::test<6>() - { - LLControlGroup cgr("test"); - cgr.declareU32("PreferredMaturity", SIM_ACCESS_PG, "declared_for_test", FALSE); - LLAgentAccess aa(cgr); - cgr.setU32("PreferredMaturity", SIM_ACCESS_ADULT); aa.setMaturity('M'); ensure("1 preferred maturity pegged to M when maturity is M", cgr.getU32("PreferredMaturity") == SIM_ACCESS_MATURE); diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 0ca82b2996..d1c952ac3b 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -91,6 +91,13 @@ class ViewerManifest(LLManifest): # ... and the entire windlight directory self.path("windlight") + + # ... and the included spell checking dictionaries + pkgdir = os.path.join(self.args['build'], os.pardir, 'packages') + if self.prefix(src=pkgdir,dst=""): + self.path("dictionaries") + self.end_prefix(pkgdir) + self.end_prefix("app_settings") if self.prefix(src="character"): @@ -393,6 +400,9 @@ class WindowsManifest(ViewerManifest): self.path("ssleay32.dll") self.path("libeay32.dll") + # Hunspell + self.path("libhunspell.dll") + # For google-perftools tcmalloc allocator. try: if self.args['configuration'].lower() == 'debug': @@ -659,6 +669,7 @@ class DarwinManifest(ViewerManifest): # copy additional libs in <bundle>/Contents/MacOS/ self.path("../packages/lib/release/libndofdev.dylib", dst="Resources/libndofdev.dylib") + self.path("../packages/lib/release/libhunspell-1.3.0.dylib", dst="Resources/libhunspell-1.3.0.dylib") self.path("../viewer_components/updater/scripts/darwin/update_install", "MacOS/update_install") @@ -1043,7 +1054,11 @@ class Linux_i686Manifest(LinuxManifest): self.path("libopenjpeg.so*") self.path("libdirectfb-1.4.so.5") self.path("libfusion-1.4.so.5") + self.path("libdirect-1.4.so.5.0.4") self.path("libdirect-1.4.so.5") + self.path("libhunspell-1.3.so") + self.path("libhunspell-1.3.so.0") + self.path("libhunspell-1.3.so.0.0.0") self.path("libalut.so") self.path("libopenal.so", "libopenal.so.1") self.path("libopenal.so", "libvivoxoal.so.1") # vivox's sdk expects this soname |