diff options
83 files changed, 15846 insertions, 8677 deletions
diff --git a/BuildParams b/BuildParams index c051397853..555ed8e7a0 100644 --- a/BuildParams +++ b/BuildParams @@ -136,6 +136,17 @@ viewer-mesh.login_channel = "Project Viewer - Mesh" viewer-mesh.viewer_grid = aditi viewer-mesh.email = shining@lists.lindenlab.com +# ======================================== +# viewer-pathfinding +# ======================================== + +viewer-pathfinding.viewer_channel = "Project Viewer - Pathfinding" +viewer-pathfinding.login_channel = "Project Viewer - Pathfinding" +viewer-pathfinding.viewer_grid = aditi +viewer-pathfinding.build_debug_release_separately = true +viewer-pathfinding.build_CYGWIN_Debug = false +viewer-pathfinding.build_viewer_update_version_manager = false + # ================ # oz # ================ diff --git a/autobuild.xml b/autobuild.xml index 9914be6867..8ba6b5570d 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -1095,14 +1095,14 @@ </map> </map> </map> - <key>llconvexdecomposition</key> + <key>llphysicsextensions</key> <map> <key>license</key> - <string>havok</string> + <string>llphysicsextensions</string> <key>license_file</key> - <string>on_file</string> + <string>LICENSES/llphysicsextensions.txt</string> <key>name</key> - <string>llconvexdecomposition</string> + <string>llphysicsextensions</string> <key>platforms</key> <map> <key>darwin</key> @@ -1110,9 +1110,9 @@ <key>archive</key> <map> <key>hash</key> - <string>362654a472ef7368d4c803ae3fb89d95</string> + <string>a698513105dc85612f3e5cd7162953c0</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/3p-llconvexdecomposition/rev/238959/arch/Darwin/installer/llconvexdecomposition-0.1-darwin-20110819.tar.bz2</string> + <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/stinson_llpathinglibrary/rev/250280/arch/Darwin/installer/llphysicsextensions-0.1-darwin-20120229.tar.bz2</string> </map> <key>name</key> <string>darwin</string> @@ -1122,9 +1122,9 @@ <key>archive</key> <map> <key>hash</key> - <string>c7801d899daec5338fbe95053255b7e7</string> + <string>e5b7bbff4d333f9688e3681be755846e</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/3p-llconvexdecomposition/rev/238959/arch/Linux/installer/llconvexdecomposition-0.1-linux-20110819.tar.bz2</string> + <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/stinson_llpathinglibrary/rev/250280/arch/Linux/installer/llphysicsextensions-0.1-linux-20120229.tar.bz2</string> </map> <key>name</key> <string>linux</string> @@ -1134,57 +1134,9 @@ <key>archive</key> <map> <key>hash</key> - <string>6ecf2f85f03c5ae87fe45769566a5660</string> + <string>ce4852640c532854673688237165f031</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/3p-llconvexdecomposition/rev/238959/arch/CYGWIN/installer/llconvexdecomposition-0.1-windows-20110819.tar.bz2</string> - </map> - <key>name</key> - <string>windows</string> - </map> - </map> - </map> - <key>llconvexdecompositionstub</key> - <map> - <key>license</key> - <string>lgpl</string> - <key>license_file</key> - <string>LICENSES/LLConvexDecompositionStubLicense.txt</string> - <key>name</key> - <string>llconvexdecompositionstub</string> - <key>platforms</key> - <map> - <key>darwin</key> - <map> - <key>archive</key> - <map> - <key>hash</key> - <string>a5f53e09f67271fd50f1131ffdda9d27</string> - <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llconvexdecompositionstub/rev/238958/arch/Darwin/installer/llconvexdecompositionstub-0.3-darwin-20110819.tar.bz2</string> - </map> - <key>name</key> - <string>darwin</string> - </map> - <key>linux</key> - <map> - <key>archive</key> - <map> - <key>hash</key> - <string>0006a964f1497f55a5f181b7042d2d22</string> - <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llconvexdecompositionstub/rev/238958/arch/Linux/installer/llconvexdecompositionstub-0.3-linux-20110819.tar.bz2</string> - </map> - <key>name</key> - <string>linux</string> - </map> - <key>windows</key> - <map> - <key>archive</key> - <map> - <key>hash</key> - <string>b859e7e3bb03ebb467f0309f46422995</string> - <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-llconvexdecompositionstub/rev/238958/arch/CYGWIN/installer/llconvexdecompositionstub-0.3-windows-20110819.tar.bz2</string> + <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/stinson_llpathinglibrary/rev/250280/arch/CYGWIN/installer/llphysicsextensions-0.1-windows-20120229.tar.bz2</string> </map> <key>name</key> <string>windows</string> @@ -1909,10 +1861,6 @@ <map> <key>command</key> <string>xcodebuild</string> - <key>filters</key> - <array> - <string>setenv</string> - </array> <key>options</key> <array> <string>-configuration Debug</string> @@ -1963,10 +1911,6 @@ <map> <key>command</key> <string>xcodebuild</string> - <key>filters</key> - <array> - <string>setenv</string> - </array> <key>options</key> <array> <string>-configuration RelWithDebInfo</string> @@ -2019,10 +1963,6 @@ <map> <key>command</key> <string>xcodebuild</string> - <key>filters</key> - <array> - <string>setenv</string> - </array> <key>options</key> <array> <string>-configuration Release</string> diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index 279d577a27..7fccf3327f 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -42,7 +42,6 @@ set(cmake_SOURCE_FILES LLAudio.cmake LLCharacter.cmake LLCommon.cmake - LLConvexDecomposition.cmake LLCrashLogger.cmake LLDatabase.cmake LLImage.cmake @@ -53,6 +52,7 @@ set(cmake_SOURCE_FILES LLMessage.cmake LLPlugin.cmake LLPrimitive.cmake + LLPhysicsExtensions.cmake LLRender.cmake LLScene.cmake LLTestCommand.cmake diff --git a/indra/cmake/LLConvexDecomposition.cmake b/indra/cmake/LLConvexDecomposition.cmake deleted file mode 100644 index 8e44504782..0000000000 --- a/indra/cmake/LLConvexDecomposition.cmake +++ /dev/null @@ -1,12 +0,0 @@ -# -*- cmake -*- -include(Prebuilt) - -set(LLCONVEXDECOMP_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include) - -if (INSTALL_PROPRIETARY AND NOT STANDALONE) - use_prebuilt_binary(llconvexdecomposition) - set(LLCONVEXDECOMP_LIBRARY llconvexdecomposition) -else (INSTALL_PROPRIETARY AND NOT STANDALONE) - use_prebuilt_binary(llconvexdecompositionstub) - set(LLCONVEXDECOMP_LIBRARY llconvexdecompositionstub) -endif (INSTALL_PROPRIETARY AND NOT STANDALONE) diff --git a/indra/cmake/LLPhysicsExtensions.cmake b/indra/cmake/LLPhysicsExtensions.cmake new file mode 100644 index 0000000000..73d5dd59cf --- /dev/null +++ b/indra/cmake/LLPhysicsExtensions.cmake @@ -0,0 +1,29 @@ +# -*- cmake -*- +include(Prebuilt) + +if (INSTALL_PROPRIETARY AND NOT STANDALONE) + use_prebuilt_binary(llphysicsextensions) + set(LLPHYSICS_EXTENSIONS_LIB_NAME llphysicsextensions) +else (INSTALL_PROPRIETARY AND NOT STANDALONE) + use_prebuilt_binary(llphysicsextensionsstub) + set(LLPHYSICS_EXTENSIONS_LIB_NAME llphysicsextensionsstub) +endif (INSTALL_PROPRIETARY AND NOT STANDALONE) + +set(LLPHYSICS_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/lib/include) + +set(LLPHYSICS_DEBUG_LIBRARY_PATH ${LIBS_PREBUILT_DIR}/lib/debug) +set(LLPHYSICS_RELEASE_LIBRARY_PATH ${LIBS_PREBUILT_DIR}/lib/release) + +find_library(LL_PHYSICS_DEBUG_LIB ${LLPHYSICS_EXTENSIONS_LIB_NAME} PATHS ${LLPHYSICS_DEBUG_LIBRARY_PATH}) +find_library(LL_PHYSICS_RELEASE_LIB ${LLPHYSICS_EXTENSIONS_LIB_NAME} PATHS ${LLPHYSICS_RELEASE_LIBRARY_PATH}) + +set(LLPHYSICS_LIBRARIES + + debug ${LL_PHYSICS_DEBUG_LIB} + optimized ${LL_PHYSICS_RELEASE_LIB} +) + +if (LINUX) + list(INSERT LLPHYSICS_LIBRARIES 0 -Wl,--start-group) + list(APPEND LLPHYSICS_LIBRARIES -Wl,--end-group) +endif (LINUX) diff --git a/indra/llcommon/llpointer.h b/indra/llcommon/llpointer.h index affa040602..88c09c8dca 100644 --- a/indra/llcommon/llpointer.h +++ b/indra/llcommon/llpointer.h @@ -140,6 +140,10 @@ public: } protected: +#ifdef LL_LIBRARY_INCLUDE + void ref(); + void unref(); +#else void ref() { if (mPointer) @@ -162,7 +166,7 @@ protected: } } } - +#endif protected: Type* mPointer; }; diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp index bf62600514..4722421fca 100644 --- a/indra/llcommon/llsdserialize.cpp +++ b/indra/llcommon/llsdserialize.cpp @@ -55,6 +55,10 @@ static const char LEGACY_NON_HEADER[] = "<llsd>"; const std::string LLSD_BINARY_HEADER("LLSD/Binary"); const std::string LLSD_XML_HEADER("LLSD/XML"); +//used to deflate a gzipped asset (currently used for navmeshes) +#define windowBits 15
+#define ENABLE_ZLIB_GZIP 32
+ /** * LLSDSerialize */ @@ -2096,7 +2100,7 @@ bool unzip_llsd(LLSD& data, std::istream& is, S32 size) strm.next_in = in; S32 ret = inflateInit(&strm); - + do { strm.avail_out = CHUNK; @@ -2159,12 +2163,87 @@ bool unzip_llsd(LLSD& data, std::istream& is, S32 size) llwarns << "Failed to unzip LLSD block" << llendl; free(result); return false; - } + } } free(result); return true; } +//This unzip function will only work with a gzip header and trailer - while the contents +//of the actual compressed data is the same for either format (gzip vs zlib ), the headers +//and trailers are different for the formats. +U8* unzip_llsdNavMesh( bool& valid, unsigned int& outsize, std::istream& is, S32 size ) +{ + U8* result = NULL; + U32 cur_size = 0; + z_stream strm; + + const U32 CHUNK = 0x4000; + U8 *in = new U8[size]; + is.read((char*) in, size); + + U8 out[CHUNK]; + + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = size; + strm.next_in = in; + + + S32 ret = inflateInit2(&strm, windowBits | ENABLE_ZLIB_GZIP ); + do + { + strm.avail_out = CHUNK; + strm.next_out = out; + ret = inflate(&strm, Z_NO_FLUSH); + if (ret == Z_STREAM_ERROR) + { + inflateEnd(&strm); + free(result); + delete [] in; + valid = false; + } + + switch (ret) + { + case Z_NEED_DICT: + ret = Z_DATA_ERROR; + case Z_DATA_ERROR: + case Z_MEM_ERROR: + inflateEnd(&strm); + free(result); + delete [] in; + valid = false; + break; + } + + U32 have = CHUNK-strm.avail_out; + + result = (U8*) realloc(result, cur_size + have); + memcpy(result+cur_size, out, have); + cur_size += have; + + } while (ret == Z_OK); + + inflateEnd(&strm); + delete [] in; + + if (ret != Z_STREAM_END) + { + free(result); + valid = false; + return NULL; + } + + //result now points to the decompressed LLSD block + { + outsize= cur_size; + valid = true; + } + + return result; +} diff --git a/indra/llcommon/llsdserialize.h b/indra/llcommon/llsdserialize.h index 99a3ea3cd4..86e3fc864c 100644 --- a/indra/llcommon/llsdserialize.h +++ b/indra/llcommon/llsdserialize.h @@ -793,5 +793,5 @@ public: //dirty little zip functions -- yell at davep LL_COMMON_API std::string zip_llsd(LLSD& data); LL_COMMON_API bool unzip_llsd(LLSD& data, std::istream& is, S32 size); - +LL_COMMON_API U8* unzip_llsdNavMesh( bool& valid, unsigned int& outsize,std::istream& is, S32 size); #endif // LL_LLSDSERIALIZE_H diff --git a/indra/llmath/llmatrix3a.inl b/indra/llmath/llmatrix3a.inl index 37819fea3c..270f1e905b 100644 --- a/indra/llmath/llmatrix3a.inl +++ b/indra/llmath/llmatrix3a.inl @@ -66,7 +66,6 @@ inline void LLMatrix3a::setTranspose(const LLMatrix3a& src) inline const LLVector4a& LLMatrix3a::getColumn(const U32 column) const { - llassert( column < 3 ); return mColumns[column]; } diff --git a/indra/llmath/m3math.h b/indra/llmath/m3math.h index 2be5452f8d..3970a5de31 100644 --- a/indra/llmath/m3math.h +++ b/indra/llmath/m3math.h @@ -27,7 +27,7 @@ #ifndef LL_M3MATH_H #define LL_M3MATH_H -#include "llerror.h" +//#include "llerror.h" #include "stdtypes.h" class LLVector4; diff --git a/indra/llmath/v3color.h b/indra/llmath/v3color.h index 56cb2ae73e..4e77d9e5ff 100644 --- a/indra/llmath/v3color.h +++ b/indra/llmath/v3color.h @@ -30,7 +30,7 @@ class LLColor4; class LLVector4; -#include "llerror.h" +//#include "llerror.h" #include "llmath.h" #include "llsd.h" diff --git a/indra/llmath/v3dmath.h b/indra/llmath/v3dmath.h index 578dcdc8ea..fba549a3b7 100644 --- a/indra/llmath/v3dmath.h +++ b/indra/llmath/v3dmath.h @@ -27,7 +27,7 @@ #ifndef LL_V3DMATH_H #define LL_V3DMATH_H -#include "llerror.h" +//#include "llerror.h" #include "v3math.h" class LLVector3d diff --git a/indra/llmath/v3math.h b/indra/llmath/v3math.h index 0432aeba4c..206a99b567 100644 --- a/indra/llmath/v3math.h +++ b/indra/llmath/v3math.h @@ -27,7 +27,7 @@ #ifndef LL_V3MATH_H #define LL_V3MATH_H -#include "llerror.h" +//#include "llerror.h" #include "llmath.h" #include "llsd.h" diff --git a/indra/llmath/v4color.h b/indra/llmath/v4color.h index b047f86e6e..6946b570ab 100644 --- a/indra/llmath/v4color.h +++ b/indra/llmath/v4color.h @@ -27,7 +27,7 @@ #ifndef LL_V4COLOR_H #define LL_V4COLOR_H -#include "llerror.h" +//#include "llerror.h" //#include "vmath.h" #include "llmath.h" #include "llsd.h" diff --git a/indra/llmath/v4math.h b/indra/llmath/v4math.h index 623c8b2003..f999e0533e 100644 --- a/indra/llmath/v4math.h +++ b/indra/llmath/v4math.h @@ -27,7 +27,7 @@ #ifndef LL_V4MATH_H #define LL_V4MATH_H -#include "llerror.h" +//#include "llerror.h" #include "llmath.h" #include "v3math.h" diff --git a/indra/llmessage/message_prehash.cpp b/indra/llmessage/message_prehash.cpp index e71fb96540..54bd469621 100644 --- a/indra/llmessage/message_prehash.cpp +++ b/indra/llmessage/message_prehash.cpp @@ -999,7 +999,6 @@ char const* const _PREHASH_SnapshotID = LLMessageStringTable::getInstance()->get char const* const _PREHASH_Aspect = LLMessageStringTable::getInstance()->getString("Aspect"); char const* const _PREHASH_ParamSize = LLMessageStringTable::getInstance()->getString("ParamSize"); char const* const _PREHASH_VoteCast = LLMessageStringTable::getInstance()->getString("VoteCast"); -char const* const _PREHASH_CastsShadows = LLMessageStringTable::getInstance()->getString("CastsShadows"); char const* const _PREHASH_EveryoneMask = LLMessageStringTable::getInstance()->getString("EveryoneMask"); char const* const _PREHASH_ObjectSpinUpdate = LLMessageStringTable::getInstance()->getString("ObjectSpinUpdate"); char const* const _PREHASH_MaturePublish = LLMessageStringTable::getInstance()->getString("MaturePublish"); diff --git a/indra/llmessage/message_prehash.h b/indra/llmessage/message_prehash.h index dd2c2dbd64..8a60ba1629 100644 --- a/indra/llmessage/message_prehash.h +++ b/indra/llmessage/message_prehash.h @@ -999,7 +999,6 @@ extern char const* const _PREHASH_SnapshotID; extern char const* const _PREHASH_Aspect; extern char const* const _PREHASH_ParamSize; extern char const* const _PREHASH_VoteCast; -extern char const* const _PREHASH_CastsShadows; extern char const* const _PREHASH_EveryoneMask; extern char const* const _PREHASH_ObjectSpinUpdate; extern char const* const _PREHASH_MaturePublish; diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp index cb32a510b8..768d3a6ae8 100644 --- a/indra/llprimitive/llmodel.cpp +++ b/indra/llprimitive/llmodel.cpp @@ -28,7 +28,7 @@ #include "llmodel.h" #include "llmemory.h" -#include "llconvexdecomposition.h" +#include "LLConvexDecomposition.h" #include "llsdserialize.h" #include "llvector4a.h" #if LL_MSVC diff --git a/indra/llprimitive/object_flags.h b/indra/llprimitive/object_flags.h index 94c559d757..f7f6841b53 100644 --- a/indra/llprimitive/object_flags.h +++ b/indra/llprimitive/object_flags.h @@ -1,80 +1,75 @@ -/** - * @file object_flags.h - * @brief Flags for object creation and transmission - * - * $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 LL_OBJECT_FLAGS_H -#define LL_OBJECT_FLAGS_H - -// downstream flags from sim->viewer -const U32 FLAGS_USE_PHYSICS = 0x00000001; -const U32 FLAGS_CREATE_SELECTED = 0x00000002; -const U32 FLAGS_OBJECT_MODIFY = 0x00000004; -const U32 FLAGS_OBJECT_COPY = 0x00000008; -const U32 FLAGS_OBJECT_ANY_OWNER = 0x00000010; -const U32 FLAGS_OBJECT_YOU_OWNER = 0x00000020; -const U32 FLAGS_SCRIPTED = 0x00000040; -const U32 FLAGS_HANDLE_TOUCH = 0x00000080; -const U32 FLAGS_OBJECT_MOVE = 0x00000100; -const U32 FLAGS_TAKES_MONEY = 0x00000200; -const U32 FLAGS_PHANTOM = 0x00000400; -const U32 FLAGS_INVENTORY_EMPTY = 0x00000800; - -const U32 FLAGS_JOINT_HINGE = 0x00001000; -const U32 FLAGS_JOINT_P2P = 0x00002000; -const U32 FLAGS_JOINT_LP2P = 0x00004000; -// const U32 FLAGS_JOINT_WHEEL = 0x00008000; -const U32 FLAGS_INCLUDE_IN_SEARCH = 0x00008000; - -const U32 FLAGS_ALLOW_INVENTORY_DROP = 0x00010000; -const U32 FLAGS_OBJECT_TRANSFER = 0x00020000; -const U32 FLAGS_OBJECT_GROUP_OWNED = 0x00040000; -//const U32 FLAGS_OBJECT_YOU_OFFICER = 0x00080000; - -const U32 FLAGS_CAMERA_DECOUPLED = 0x00100000; -const U32 FLAGS_ANIM_SOURCE = 0x00200000; -const U32 FLAGS_CAMERA_SOURCE = 0x00400000; - -const U32 FLAGS_CAST_SHADOWS = 0x00800000; - -const U32 FLAGS_OBJECT_OWNER_MODIFY = 0x10000000; - -const U32 FLAGS_TEMPORARY_ON_REZ = 0x20000000; -const U32 FLAGS_TEMPORARY = 0x40000000; -const U32 FLAGS_ZLIB_COMPRESSED = 0x80000000; - -const U32 FLAGS_LOCAL = FLAGS_ANIM_SOURCE | FLAGS_CAMERA_SOURCE; - -typedef enum e_havok_joint_type -{ - HJT_INVALID = 0, - HJT_HINGE = 1, - HJT_POINT = 2, -// HJT_LPOINT = 3, -// HJT_WHEEL = 4, - HJT_EOF = 3 -} EHavokJointType; - -#endif - +/**
+ * @file object_flags.h
+ * @brief Flags for object creation and transmission
+ *
+ * $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 LL_OBJECT_FLAGS_H
+#define LL_OBJECT_FLAGS_H
+
+// downstream flags from sim->viewer
+const U32 FLAGS_USE_PHYSICS = (1U << 0);
+const U32 FLAGS_CREATE_SELECTED = (1U << 1);
+const U32 FLAGS_OBJECT_MODIFY = (1U << 2);
+const U32 FLAGS_OBJECT_COPY = (1U << 3);
+const U32 FLAGS_OBJECT_ANY_OWNER = (1U << 4);
+const U32 FLAGS_OBJECT_YOU_OWNER = (1U << 5);
+const U32 FLAGS_SCRIPTED = (1U << 6);
+const U32 FLAGS_HANDLE_TOUCH = (1U << 7);
+const U32 FLAGS_OBJECT_MOVE = (1U << 8);
+const U32 FLAGS_TAKES_MONEY = (1U << 9);
+const U32 FLAGS_PHANTOM = (1U << 10);
+const U32 FLAGS_INVENTORY_EMPTY = (1U << 11);
+const U32 FLAGS_OBJECT_PERMANENT = (1U << 12);
+const U32 FLAGS_CHARACTER = (1U << 13);
+//const U32 FLAGS_UNUSED_000 = (1U << 14); // was FLAGS_JOINT_LP2P
+const U32 FLAGS_INCLUDE_IN_SEARCH = (1U << 15);
+const U32 FLAGS_ALLOW_INVENTORY_DROP = (1U << 16);
+const U32 FLAGS_OBJECT_TRANSFER = (1U << 17);
+const U32 FLAGS_OBJECT_GROUP_OWNED = (1U << 18);
+//const U32 FLAGS_UNUSED_001 = (1U << 19); // was FLAGS_OBJECT_YOU_OFFICER
+const U32 FLAGS_CAMERA_DECOUPLED = (1U << 20);
+const U32 FLAGS_ANIM_SOURCE = (1U << 21);
+const U32 FLAGS_CAMERA_SOURCE = (1U << 22);
+//const U32 FLAGS_UNUSED_002 = (1U << 23); // was FLAGS_CAST_SHADOWS
+//const U32 FLAGS_UNUSED_003 = (1U << 24);
+//const U32 FLAGS_UNUSED_004 = (1U << 25);
+//const U32 FLAGS_UNUSED_005 = (1U << 26);
+//const U32 FLAGS_UNUSED_006 = (1U << 27);
+const U32 FLAGS_OBJECT_OWNER_MODIFY = (1U << 28);
+const U32 FLAGS_TEMPORARY_ON_REZ = (1U << 29);
+//const U32 FLAGS_UNUSED_007 = (1U << 30); // was FLAGS_TEMPORARY
+//const U32 FLAGS_UNUSED_008 = (1U << 31); // was FLAGS_ZLIB_COMPRESSED
+const U32 FLAGS_LOCAL = FLAGS_ANIM_SOURCE | FLAGS_CAMERA_SOURCE;
+
+typedef enum e_havok_joint_type
+{
+ HJT_INVALID = 0,
+ HJT_HINGE = 1,
+ HJT_POINT = 2,
+// HJT_LPOINT = 3,
+// HJT_WHEEL = 4,
+ HJT_EOF = 3
+} EHavokJointType;
+
+#endif
diff --git a/indra/llrender/CMakeLists.txt b/indra/llrender/CMakeLists.txt index 5c13df9f81..516af93316 100644 --- a/indra/llrender/CMakeLists.txt +++ b/indra/llrender/CMakeLists.txt @@ -36,6 +36,7 @@ set(llrender_SOURCE_FILES llglslshader.cpp llimagegl.cpp llpostprocess.cpp + llrendernavprim.cpp llrendersphere.cpp llshadermgr.cpp lltexture.cpp @@ -59,6 +60,7 @@ set(llrender_HEADER_FILES llimagegl.h llpostprocess.h llrender.h + llrendernavprim.h llrendersphere.h llshadermgr.h lltexture.h diff --git a/indra/llrender/llrendernavprim.cpp b/indra/llrender/llrendernavprim.cpp new file mode 100644 index 0000000000..47cc996043 --- /dev/null +++ b/indra/llrender/llrendernavprim.cpp @@ -0,0 +1,122 @@ +/**
+ * @file LLRenderNavPrim.cpp
+ * @brief Renderable primitives used by the pathing library
+ *
+ * $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 "llrendernavprim.h"
+#include "llerror.h"
+#include "llglheaders.h"
+#include "llvertexbuffer.h"
+#include "llglslshader.h"
+
+//=============================================================================
+LLRenderNavPrim gRenderNav;
+//=============================================================================
+void LLRenderNavPrim::renderSegment( const LLVector3& start, const LLVector3& end, int color, bool overlayMode ) const
+{
+ bool ff = LLGLSLShader::sNoFixedFunction;
+ LLGLSLShader::sNoFixedFunction = false;
+ LLGLEnable smooth(GL_LINE_SMOOTH);
+ LLColor4 colorA( color );
+ glLineWidth(1.5f);
+ gGL.color3fv( colorA.mV );
+
+ gGL.begin(LLRender::LINES);
+ {
+ gGL.vertex3fv( start.mV );
+ gGL.vertex3fv( end.mV );
+ }
+ gGL.end();
+
+ gGL.flush();
+ LLGLSLShader::sNoFixedFunction = ff;
+ LLGLDisable smoothout(GL_LINE_SMOOTH);
+ glLineWidth(1.0f);
+}
+//=============================================================================
+void LLRenderNavPrim::renderTri( const LLVector3& a, const LLVector3& b, const LLVector3& c, int color, bool overlayMode ) const
+{
+ glLineWidth(1.5f);
+ if ( overlayMode )
+ {
+ glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
+ }
+ else
+ {
+ glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
+ }
+ LLGLEnable cull(GL_CULL_FACE);
+ LLColor4 colorA( color );
+ colorA*=1.25f;
+ gGL.color4fv( colorA.mV );
+ bool ff = LLGLSLShader::sNoFixedFunction;
+ LLGLSLShader::sNoFixedFunction = false;
+ gGL.begin(LLRender::TRIANGLES);
+ {
+ gGL.vertex3fv( a.mV );
+ gGL.vertex3fv( b.mV );
+ gGL.vertex3fv( c.mV );
+ }
+ gGL.end();
+ gGL.flush();
+ glLineWidth(1.0f);
+ glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
+ LLGLSLShader::sNoFixedFunction = ff;
+}
+//=============================================================================
+void LLRenderNavPrim::renderNavMeshVB( LLVertexBuffer* pVBO, int vertCnt )
+{
+ LLGLEnable blend( GL_BLEND );
+ LLGLEnable cull( GL_CULL_FACE );
+ glLineWidth(1.5f);
+ bool ff = LLGLSLShader::sNoFixedFunction;
+ LLGLSLShader::sNoFixedFunction = false; + //pass 1 filled
+ pVBO->setBuffer( LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_NORMAL );
+ pVBO->drawArrays( LLRender::TRIANGLES, 0, vertCnt );
+ glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
+ LLGLEnable smooth( GL_LINE_SMOOTH );
+ //pass 2 outlined
+ pVBO->drawArrays( LLRender::TRIANGLES, 0, vertCnt );
+ LLGLSLShader::sNoFixedFunction = ff;
+ glLineWidth(1.0f);
+ glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
+ LLGLDisable smoothout( GL_LINE_SMOOTH );
+}
+//=============================================================================
+void LLRenderNavPrim::renderStar( const LLVector3& center, const float scale, int color ) const
+{
+ for (int k=0; k<3; k++)
+ {
+ LLVector3 star, pt1, pt2;
+ star = LLVector3( 0.0f,0.0f,0.0f);
+ star[k] = 0.5f;
+ pt1 = center + star;
+ pt2 = center - star;
+ renderSegment( pt1, pt2, color, false );
+ }
+}
+//=============================================================================
diff --git a/indra/llrender/llrendernavprim.h b/indra/llrender/llrendernavprim.h new file mode 100644 index 0000000000..d88fe656b7 --- /dev/null +++ b/indra/llrender/llrendernavprim.h @@ -0,0 +1,56 @@ +/**
+ * @file LLRenderNavPrim.h
+ * @brief
+ *
+ * $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 LL_RENDER_NAVPRIM_H
+#define LL_RENDER_NAVPRIM_H
+
+#include "llmath.h"
+#include "v3math.h"
+#include "v4math.h"
+#include "m3math.h"
+#include "m4math.h"
+#include "v4color.h"
+#include "llgl.h"
+
+
+class LLRenderNavPrim
+{
+public:
+ //Draw a line
+ void renderSegment( const LLVector3& start, const LLVector3& end, int color, bool overlayMode ) const;
+ //Draw simple tri
+ void renderTri( const LLVector3& a, const LLVector3& b, const LLVector3& c, int color, bool overlayMode ) const;
+ //Draw the contents of vertex buffer
+ void renderNavMeshVB( LLVertexBuffer* pVBO, int vertCnt );
+ //Draw a star
+ void renderStar( const LLVector3& center, const float scale, int color ) const;
+
+private:
+};
+
+extern LLRenderNavPrim gRenderNav;
+
+#endif
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index eb302392bb..79d1beb33a 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -1,2306 +1,2307 @@ -/** - * @file llvertexbuffer.cpp - * @brief LLVertexBuffer implementation - * - * $LicenseInfo:firstyear=2003&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 <boost/static_assert.hpp> -#include "llsys.h" -#include "llvertexbuffer.h" -// #include "llrender.h" -#include "llglheaders.h" -#include "llmemtype.h" -#include "llrender.h" -#include "llvector4a.h" -#include "llshadermgr.h" -#include "llglslshader.h" -#include "llmemory.h" - -//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) -{ - U32 r = 1; - while (r < v) { - r *= 2; - } - return r; -} - - -//============================================================================ - -//static -LLVBOPool LLVertexBuffer::sStreamVBOPool; -LLVBOPool LLVertexBuffer::sDynamicVBOPool; -LLVBOPool LLVertexBuffer::sStreamIBOPool; -LLVBOPool LLVertexBuffer::sDynamicIBOPool; -U32 LLVBOPool::sBytesPooled = 0; - -LLPrivateMemoryPool* LLVertexBuffer::sPrivatePoolp = NULL ; -U32 LLVertexBuffer::sBindCount = 0; -U32 LLVertexBuffer::sSetCount = 0; -S32 LLVertexBuffer::sCount = 0; -S32 LLVertexBuffer::sGLCount = 0; -S32 LLVertexBuffer::sMappedCount = 0; -BOOL LLVertexBuffer::sDisableVBOMapping = FALSE ; -BOOL LLVertexBuffer::sEnableVBOs = TRUE; -U32 LLVertexBuffer::sGLRenderBuffer = 0; -U32 LLVertexBuffer::sGLRenderArray = 0; -U32 LLVertexBuffer::sGLRenderIndices = 0; -U32 LLVertexBuffer::sLastMask = 0; -BOOL LLVertexBuffer::sVBOActive = FALSE; -BOOL LLVertexBuffer::sIBOActive = FALSE; -U32 LLVertexBuffer::sAllocatedBytes = 0; -BOOL LLVertexBuffer::sMapped = FALSE; -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 -{ -public: -#ifdef GL_ARB_sync - GLsync mSync; -#endif - - LLGLSyncFence() - { -#ifdef GL_ARB_sync - mSync = 0; -#endif - } - - virtual ~LLGLSyncFence() - { -#ifdef GL_ARB_sync - if (mSync) - { - glDeleteSync(mSync); - } -#endif - } - - void placeFence() - { -#ifdef GL_ARB_sync - if (mSync) - { - glDeleteSync(mSync); - } - mSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); -#endif - } - - void 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 - } - - -}; - - -//which power of 2 is i? -//assumes i is a power of 2 > 0 -U32 wpo2(U32 i) -{ - llassert(i > 0); - llassert(nhpo2(i) == i); - - U32 r = 0; - - while (i >>= 1) ++r; - - return r; -} - -volatile U8* LLVBOPool::allocate(U32& name, U32 size) -{ - llassert(nhpo2(size) == size); - - U32 i = wpo2(size); - - if (mFreeList.size() <= i) - { - mFreeList.resize(i+1); - } - - volatile U8* ret = NULL; - - if (mFreeList[i].empty()) - { - //make a new buffer - glGenBuffersARB(1, &name); - glBindBufferARB(mType, name); - LLVertexBuffer::sAllocatedBytes += 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); - } - else - { - name = mFreeList[i].front().mGLName; - ret = mFreeList[i].front().mClientData; - - sBytesPooled -= size; - - mFreeList[i].pop_front(); - } - - return ret; -} - -void LLVBOPool::release(U32 name, volatile U8* buffer, U32 size) -{ - llassert(nhpo2(size) == size); - - U32 i = wpo2(size); - - llassert(mFreeList.size() > i); - - Record rec; - rec.mGLName = name; - rec.mClientData = buffer; - - sBytesPooled += size; - - if (!LLVertexBuffer::sDisableVBOMapping && mUsage == GL_DYNAMIC_DRAW_ARB) - { - glDeleteBuffersARB(1, &rec.mGLName); - } - else - { - mFreeList[i].push_back(rec); - } -} - -void LLVBOPool::cleanup() -{ - U32 size = 1; - - for (U32 i = 0; i < mFreeList.size(); ++i) - { - record_list_t& l = mFreeList[i]; - - while (!l.empty()) - { - Record& r = l.front(); - - glDeleteBuffersARB(1, &r.mGLName); - - if (r.mClientData) - { - ll_aligned_free_16((void*) r.mClientData); - } - - l.pop_front(); - - LLVertexBuffer::sAllocatedBytes -= size; - sBytesPooled -= size; - } - - size *= 2; - } -} - - -//NOTE: each component must be AT LEAST 4 bytes in size to avoid a performance penalty on AMD hardware -S32 LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_MAX] = -{ - sizeof(LLVector4), // TYPE_VERTEX, - sizeof(LLVector4), // TYPE_NORMAL, - sizeof(LLVector2), // TYPE_TEXCOORD0, - sizeof(LLVector2), // TYPE_TEXCOORD1, - sizeof(LLVector2), // TYPE_TEXCOORD2, - sizeof(LLVector2), // TYPE_TEXCOORD3, - sizeof(LLColor4U), // TYPE_COLOR, - sizeof(LLColor4U), // TYPE_EMISSIVE, only alpha is used currently - sizeof(LLVector4), // TYPE_BINORMAL, - sizeof(F32), // TYPE_WEIGHT, - sizeof(LLVector4), // TYPE_WEIGHT4, - sizeof(LLVector4), // TYPE_CLOTHWEIGHT, - sizeof(LLVector4), // TYPE_TEXTURE_INDEX (actually exists as position.w), no extra data, but stride is 16 bytes -}; - -U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] = -{ - GL_TRIANGLES, - GL_TRIANGLE_STRIP, - GL_TRIANGLE_FAN, - GL_POINTS, - GL_LINES, - GL_LINE_STRIP, - GL_QUADS, - GL_LINE_LOOP, -}; - - -//static -void LLVertexBuffer::setupClientArrays(U32 data_mask) -{ - if (sLastMask != data_mask) - { - BOOL error = FALSE; - - if (LLGLSLShader::sNoFixedFunction) - { - for (U32 i = 0; i < TYPE_MAX; ++i) - { - S32 loc = i; - - U32 mask = 1 << i; - - if (sLastMask & (1 << i)) - { //was enabled - if (!(data_mask & mask)) - { //needs to be disabled - glDisableVertexAttribArrayARB(loc); - } - } - else - { //was disabled - if (data_mask & mask) - { //needs to be enabled - glEnableVertexAttribArrayARB(loc); - } - } - } - } - else - { - - GLenum array[] = - { - GL_VERTEX_ARRAY, - GL_NORMAL_ARRAY, - GL_TEXTURE_COORD_ARRAY, - GL_COLOR_ARRAY, - }; - - GLenum mask[] = - { - MAP_VERTEX, - MAP_NORMAL, - MAP_TEXCOORD0, - MAP_COLOR - }; - - - - for (U32 i = 0; i < 4; ++i) - { - if (sLastMask & mask[i]) - { //was enabled - if (!(data_mask & mask[i])) - { //needs to be disabled - glDisableClientState(array[i]); - } - else if (gDebugGL) - { //needs to be enabled, make sure it was (DEBUG) - if (!glIsEnabled(array[i])) - { - if (gDebugSession) - { - error = TRUE; - gFailLog << "Bad client state! " << array[i] << " disabled." << std::endl; - } - else - { - llerrs << "Bad client state! " << array[i] << " disabled." << llendl; - } - } - } - } - else - { //was disabled - if (data_mask & mask[i]) - { //needs to be enabled - glEnableClientState(array[i]); - } - else if (gDebugGL && glIsEnabled(array[i])) - { //needs to be disabled, make sure it was (DEBUG TEMPORARY) - if (gDebugSession) - { - error = TRUE; - gFailLog << "Bad client state! " << array[i] << " enabled." << std::endl; - } - else - { - llerrs << "Bad client state! " << array[i] << " enabled." << llendl; - } - } - } - } - - U32 map_tc[] = - { - MAP_TEXCOORD1, - MAP_TEXCOORD2, - MAP_TEXCOORD3 - }; - - for (U32 i = 0; i < 3; i++) - { - if (sLastMask & map_tc[i]) - { - if (!(data_mask & map_tc[i])) - { //disable - glClientActiveTextureARB(GL_TEXTURE1_ARB+i); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glClientActiveTextureARB(GL_TEXTURE0_ARB); - } - } - else if (data_mask & map_tc[i]) - { - glClientActiveTextureARB(GL_TEXTURE1_ARB+i); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glClientActiveTextureARB(GL_TEXTURE0_ARB); - } - } - - if (sLastMask & MAP_BINORMAL) - { - if (!(data_mask & MAP_BINORMAL)) - { - glClientActiveTextureARB(GL_TEXTURE2_ARB); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glClientActiveTextureARB(GL_TEXTURE0_ARB); - } - } - else if (data_mask & MAP_BINORMAL) - { - glClientActiveTextureARB(GL_TEXTURE2_ARB); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glClientActiveTextureARB(GL_TEXTURE0_ARB); - } - } - - sLastMask = data_mask; - } -} - -//static -void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm) -{ - llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL); - gGL.syncMatrices(); - - U32 count = pos.size(); - llassert_always(norm.size() >= pos.size()); - llassert_always(count > 0) ; - - unbind(); - - setupClientArrays(MAP_VERTEX | MAP_NORMAL); - - LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; - - if (shader) - { - S32 loc = LLVertexBuffer::TYPE_VERTEX; - if (loc > -1) - { - glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 0, pos[0].mV); - } - loc = LLVertexBuffer::TYPE_NORMAL; - if (loc > -1) - { - glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 0, norm[0].mV); - } - } - else - { - glVertexPointer(3, GL_FLOAT, 0, pos[0].mV); - glNormalPointer(GL_FLOAT, 0, norm[0].mV); - } - - glDrawArrays(sGLMode[mode], 0, count); -} - -//static -void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp) -{ - llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL); - - gGL.syncMatrices(); - - U32 mask = LLVertexBuffer::MAP_VERTEX; - if (tc) - { - mask = mask | LLVertexBuffer::MAP_TEXCOORD0; - } - - unbind(); - - setupClientArrays(mask); - - if (LLGLSLShader::sNoFixedFunction) - { - S32 loc = LLVertexBuffer::TYPE_VERTEX; - glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 16, pos); - - if (tc) - { - loc = LLVertexBuffer::TYPE_TEXCOORD0; - glVertexAttribPointerARB(loc, 2, GL_FLOAT, GL_FALSE, 0, tc); - } - } - else - { - glTexCoordPointer(2, GL_FLOAT, 0, tc); - glVertexPointer(3, GL_FLOAT, 16, pos); - } - - glDrawElements(sGLMode[mode], num_indices, GL_UNSIGNED_SHORT, indicesp); -} - -void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_offset) const -{ - if (start >= (U32) mNumVerts || - end >= (U32) mNumVerts) - { - llerrs << "Bad vertex buffer draw range: [" << start << ", " << end << "] vs " << mNumVerts << llendl; - } - - llassert(mNumIndices >= 0); - - if (indices_offset >= (U32) mNumIndices || - indices_offset + count > (U32) mNumIndices) - { - llerrs << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << llendl; - } - - if (gDebugGL && !useVBOs()) - { - U16* idx = ((U16*) getIndicesPointer())+indices_offset; - for (U32 i = 0; i < count; ++i) - { - if (idx[i] < start || idx[i] > end) - { - llerrs << "Index out of range: " << idx[i] << " not in [" << start << ", " << end << "]" << llendl; - } - } - - LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; - - if (shader && shader->mFeatures.mIndexedTextureChannels > 1) - { - LLStrider<LLVector4a> v; - //hack to get non-const reference - LLVertexBuffer* vb = (LLVertexBuffer*) this; - vb->getVertexStrider(v); - - for (U32 i = start; i < end; i++) - { - S32 idx = (S32) (v[i][3]+0.25f); - if (idx < 0 || idx >= shader->mFeatures.mIndexedTextureChannels) - { - llerrs << "Bad texture index found in vertex data stream." << llendl; - } - } - } - } -} - -void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const -{ - validateRange(start, end, count, indices_offset); - mMappable = FALSE; - gGL.syncMatrices(); - - llassert(mNumVerts >= 0); - llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL); - - if (mGLArray) - { - if (mGLArray != sGLRenderArray) - { - llerrs << "Wrong vertex array bound." << llendl; - } - } - else - { - if (mGLIndices != sGLRenderIndices) - { - llerrs << "Wrong index buffer bound." << llendl; - } - - if (mGLBuffer != sGLRenderBuffer) - { - llerrs << "Wrong vertex buffer bound." << llendl; - } - } - - if (gDebugGL && !mGLArray && useVBOs()) - { - GLint elem = 0; - glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &elem); - - if (elem != mGLIndices) - { - llerrs << "Wrong index buffer bound!" << llendl; - } - } - - if (mode >= LLRender::NUM_MODES) - { - llerrs << "Invalid draw mode: " << mode << llendl; - return; - } - - U16* idx = ((U16*) getIndicesPointer())+indices_offset; - - stop_glerror(); - glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT, - idx); - stop_glerror(); - placeFence(); -} - -void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const -{ - llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL); - mMappable = FALSE; - gGL.syncMatrices(); - - llassert(mNumIndices >= 0); - if (indices_offset >= (U32) mNumIndices || - indices_offset + count > (U32) mNumIndices) - { - llerrs << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << llendl; - } - - if (mGLArray) - { - if (mGLArray != sGLRenderArray) - { - llerrs << "Wrong vertex array bound." << llendl; - } - } - else - { - if (mGLIndices != sGLRenderIndices) - { - llerrs << "Wrong index buffer bound." << llendl; - } - - if (mGLBuffer != sGLRenderBuffer) - { - llerrs << "Wrong vertex buffer bound." << llendl; - } - } - - if (mode >= LLRender::NUM_MODES) - { - llerrs << "Invalid draw mode: " << mode << llendl; - return; - } - - stop_glerror(); - glDrawElements(sGLMode[mode], count, GL_UNSIGNED_SHORT, - ((U16*) getIndicesPointer()) + indices_offset); - stop_glerror(); - placeFence(); -} - -void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const -{ - llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL); - mMappable = FALSE; - gGL.syncMatrices(); - - llassert(mNumVerts >= 0); - if (first >= (U32) mNumVerts || - first + count > (U32) mNumVerts) - { - llerrs << "Bad vertex buffer draw range: [" << first << ", " << first+count << "]" << llendl; - } - - if (mGLArray) - { - if (mGLArray != sGLRenderArray) - { - llerrs << "Wrong vertex array bound." << llendl; - } - } - else - { - if (mGLBuffer != sGLRenderBuffer || useVBOs() != sVBOActive) - { - llerrs << "Wrong vertex buffer bound." << llendl; - } - } - - if (mode >= LLRender::NUM_MODES) - { - llerrs << "Invalid draw mode: " << mode << llendl; - return; - } - - stop_glerror(); - glDrawArrays(sGLMode[mode], first, count); - stop_glerror(); - placeFence(); -} - -//static -void LLVertexBuffer::initClass(bool use_vbo, bool no_vbo_mapping) -{ - sEnableVBOs = use_vbo && gGLManager.mHasVertexBufferObject ; - sDisableVBOMapping = sEnableVBOs && no_vbo_mapping ; - - if(!sPrivatePoolp) - { - sPrivatePoolp = LLPrivateMemoryPoolManager::getInstance()->newPool(LLPrivateMemoryPool::STATIC) ; - } - - sStreamVBOPool.mType = GL_ARRAY_BUFFER_ARB; - sStreamVBOPool.mUsage= GL_STREAM_DRAW_ARB; - sStreamIBOPool.mType = GL_ELEMENT_ARRAY_BUFFER_ARB; - sStreamIBOPool.mUsage= GL_STREAM_DRAW_ARB; - - sDynamicVBOPool.mType = GL_ARRAY_BUFFER_ARB; - sDynamicVBOPool.mUsage= GL_DYNAMIC_DRAW_ARB; - sDynamicIBOPool.mType = GL_ELEMENT_ARRAY_BUFFER_ARB; - sDynamicIBOPool.mUsage= GL_DYNAMIC_DRAW_ARB; -} - -//static -void LLVertexBuffer::unbind() -{ - if (sGLRenderArray) - { -#if GL_ARB_vertex_array_object - glBindVertexArray(0); -#endif - sGLRenderArray = 0; - sGLRenderIndices = 0; - sIBOActive = FALSE; - } - - if (sVBOActive) - { - glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - sVBOActive = FALSE; - } - if (sIBOActive) - { - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); - sIBOActive = FALSE; - } - - sGLRenderBuffer = 0; - sGLRenderIndices = 0; - - setupClientArrays(0); -} - -//static -void LLVertexBuffer::cleanupClass() -{ - LLMemType mt2(LLMemType::MTYPE_VERTEX_CLEANUP_CLASS); - unbind(); - - sStreamIBOPool.cleanup(); - sDynamicIBOPool.cleanup(); - sStreamVBOPool.cleanup(); - sDynamicVBOPool.cleanup(); - - if(sPrivatePoolp) - { - LLPrivateMemoryPoolManager::getInstance()->deletePool(sPrivatePoolp) ; - sPrivatePoolp = NULL ; - } -} - -//---------------------------------------------------------------------------- - -LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) : - LLRefCount(), - - mNumVerts(0), - mNumIndices(0), - mUsage(usage), - mGLBuffer(0), - mGLArray(0), - mGLIndices(0), - mMappedData(NULL), - mMappedIndexData(NULL), - mVertexLocked(FALSE), - mIndexLocked(FALSE), - mFinal(FALSE), - mEmpty(TRUE), - mFence(NULL) -{ - LLMemType mt2(LLMemType::MTYPE_VERTEX_CONSTRUCTOR); - mFence = NULL; - if (!sEnableVBOs) - { - mUsage = 0 ; - } - - if (mUsage == GL_STREAM_DRAW_ARB && !sUseStreamDraw) - { - mUsage = 0; - } - - if (mUsage == GL_DYNAMIC_DRAW_ARB && sPreferStreamDraw) - { - mUsage = GL_STREAM_DRAW_ARB; - } - - if (mUsage == 0 && LLRender::sGLCoreProfile) - { //MUST use VBOs for all rendering - mUsage = GL_STREAM_DRAW_ARB; - } - - if (mUsage && mUsage != GL_STREAM_DRAW_ARB) - { //only stream_draw and dynamic_draw are supported when using VBOs, dynamic draw is the default - if (sDisableVBOMapping) - { //always use stream draw if VBO mapping is disabled - mUsage = GL_STREAM_DRAW_ARB; - } - else - { - mUsage = GL_DYNAMIC_DRAW_ARB; - } - } - - - if (mUsage == GL_DYNAMIC_DRAW_ARB && !sDisableVBOMapping) - { - mMappable = TRUE; - } - else - { - mMappable = FALSE; - } - - //zero out offsets - for (U32 i = 0; i < TYPE_MAX; i++) - { - mOffsets[i] = 0; - } - - mTypeMask = typemask; - mSize = 0; - mIndicesSize = 0; - mAlignedOffset = 0; - mAlignedIndexOffset = 0; - - sCount++; -} - -//static -S32 LLVertexBuffer::calcOffsets(const U32& typemask, S32* offsets, S32 num_vertices) -{ - S32 offset = 0; - for (S32 i=0; i<TYPE_TEXTURE_INDEX; i++) - { - U32 mask = 1<<i; - if (typemask & mask) - { - if (offsets && LLVertexBuffer::sTypeSize[i]) - { - offsets[i] = offset; - offset += LLVertexBuffer::sTypeSize[i]*num_vertices; - offset = (offset + 0xF) & ~0xF; - } - } - } - - offsets[TYPE_TEXTURE_INDEX] = offsets[TYPE_VERTEX] + 12; - - return offset+16; -} - -//static -S32 LLVertexBuffer::calcVertexSize(const U32& typemask) -{ - S32 size = 0; - for (S32 i = 0; i < TYPE_TEXTURE_INDEX; i++) - { - U32 mask = 1<<i; - if (typemask & mask) - { - size += LLVertexBuffer::sTypeSize[i]; - } - } - - return size; -} - -S32 LLVertexBuffer::getSize() const -{ - return mSize; -} - -// protected, use unref() -//virtual -LLVertexBuffer::~LLVertexBuffer() -{ - LLMemType mt2(LLMemType::MTYPE_VERTEX_DESTRUCTOR); - destroyGLBuffer(); - destroyGLIndices(); - - if (mGLArray) - { -#if GL_ARB_vertex_array_object - glDeleteVertexArrays(1, &mGLArray); -#endif - } - - sCount--; - - if (mFence) - { - delete mFence; - } - - mFence = NULL; - - llassert_always(!mMappedData && !mMappedIndexData) ; -}; - -void LLVertexBuffer::placeFence() const -{ - /*if (!mFence && useVBOs()) - { - if (gGLManager.mHasSync) - { - mFence = new LLGLSyncFence(); - } - } - - if (mFence) - { - mFence->placeFence(); - }*/ -} - -void LLVertexBuffer::waitFence() const -{ - /*if (mFence) - { - mFence->wait(); - }*/ -} - -//---------------------------------------------------------------------------- - -void LLVertexBuffer::genBuffer(U32 size) -{ - mSize = nhpo2(size); - - if (mUsage == GL_STREAM_DRAW_ARB) - { - mMappedData = sStreamVBOPool.allocate(mGLBuffer, mSize); - } - else - { - mMappedData = sDynamicVBOPool.allocate(mGLBuffer, mSize); - } - - sGLCount++; -} - -void LLVertexBuffer::genIndices(U32 size) -{ - mIndicesSize = nhpo2(size); - - if (mUsage == GL_STREAM_DRAW_ARB) - { - mMappedIndexData = sStreamIBOPool.allocate(mGLIndices, mIndicesSize); - } - else - { - mMappedIndexData = sDynamicIBOPool.allocate(mGLIndices, mIndicesSize); - } - - sGLCount++; -} - -void LLVertexBuffer::releaseBuffer() -{ - if (mUsage == GL_STREAM_DRAW_ARB) - { - sStreamVBOPool.release(mGLBuffer, mMappedData, mSize); - } - else - { - sDynamicVBOPool.release(mGLBuffer, mMappedData, mSize); - } - - mGLBuffer = 0; - mMappedData = NULL; - - sGLCount--; -} - -void LLVertexBuffer::releaseIndices() -{ - if (mUsage == GL_STREAM_DRAW_ARB) - { - sStreamIBOPool.release(mGLIndices, mMappedIndexData, mIndicesSize); - } - else - { - sDynamicIBOPool.release(mGLIndices, mMappedIndexData, mIndicesSize); - } - - mGLIndices = 0; - mMappedIndexData = NULL; - - sGLCount--; -} - -void LLVertexBuffer::createGLBuffer(U32 size) -{ - LLMemType mt2(LLMemType::MTYPE_VERTEX_CREATE_VERTICES); - - if (mGLBuffer) - { - destroyGLBuffer(); - } - - if (size == 0) - { - return; - } - - mEmpty = TRUE; - - if (useVBOs()) - { - genBuffer(size); - } - else - { - static int gl_buffer_idx = 0; - mGLBuffer = ++gl_buffer_idx; - mMappedData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size); - mSize = size; - } -} - -void LLVertexBuffer::createGLIndices(U32 size) -{ - LLMemType mt2(LLMemType::MTYPE_VERTEX_CREATE_INDICES); - - if (mGLIndices) - { - destroyGLIndices(); - } - - if (size == 0) - { - return; - } - - mEmpty = TRUE; - - //pad by 16 bytes for aligned copies - size += 16; - - if (useVBOs()) - { - //pad by another 16 bytes for VBO pointer adjustment - size += 16; - genIndices(size); - } - else - { - mMappedIndexData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size); - static int gl_buffer_idx = 0; - mGLIndices = ++gl_buffer_idx; - mIndicesSize = size; - } -} - -void LLVertexBuffer::destroyGLBuffer() -{ - LLMemType mt2(LLMemType::MTYPE_VERTEX_DESTROY_BUFFER); - if (mGLBuffer) - { - if (useVBOs()) - { - releaseBuffer(); - } - else - { - FREE_MEM(sPrivatePoolp, (void*) mMappedData) ; - mMappedData = NULL; - mEmpty = TRUE; - } - } - - mGLBuffer = 0; - //unbind(); -} - -void LLVertexBuffer::destroyGLIndices() -{ - LLMemType mt2(LLMemType::MTYPE_VERTEX_DESTROY_INDICES); - if (mGLIndices) - { - if (useVBOs()) - { - releaseIndices(); - } - else - { - FREE_MEM(sPrivatePoolp, (void*) mMappedIndexData) ; - mMappedIndexData = NULL; - mEmpty = TRUE; - } - } - - mGLIndices = 0; - //unbind(); -} - -void LLVertexBuffer::updateNumVerts(S32 nverts) -{ - LLMemType mt2(LLMemType::MTYPE_VERTEX_UPDATE_VERTS); - - llassert(nverts >= 0); - - if (nverts >= 65535) - { - llwarns << "Vertex buffer overflow!" << llendl; - nverts = 65535; - } - - U32 needed_size = calcOffsets(mTypeMask, mOffsets, nverts); - - if (needed_size > mSize || needed_size <= mSize/2) - { - createGLBuffer(needed_size); - } - - mNumVerts = nverts; -} - -void LLVertexBuffer::updateNumIndices(S32 nindices) -{ - LLMemType mt2(LLMemType::MTYPE_VERTEX_UPDATE_INDICES); - - llassert(nindices >= 0); - - U32 needed_size = sizeof(U16) * nindices; - - if (needed_size > mIndicesSize || needed_size <= mIndicesSize/2) - { - createGLIndices(needed_size); - } - - mNumIndices = nindices; -} - -void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create) -{ - LLMemType mt2(LLMemType::MTYPE_VERTEX_ALLOCATE_BUFFER); - - stop_glerror(); - - if (nverts < 0 || nindices < 0 || - nverts > 65536) - { - llerrs << "Bad vertex buffer allocation: " << nverts << " : " << nindices << llendl; - } - - updateNumVerts(nverts); - updateNumIndices(nindices); - - if (create && (nverts || nindices)) - { - //actually allocate space for the vertex buffer if using VBO mapping - flush(); - - if (gGLManager.mHasVertexArrayObject && useVBOs() && (LLRender::sGLCoreProfile || sUseVAO)) - { -#if GL_ARB_vertex_array_object - glGenVertexArrays(1, &mGLArray); -#endif - setupVertexArray(); - } - } -} - -static LLFastTimer::DeclareTimer FTM_SETUP_VERTEX_ARRAY("Setup VAO"); - -void LLVertexBuffer::setupVertexArray() -{ - if (!mGLArray) - { - return; - } - - LLFastTimer t(FTM_SETUP_VERTEX_ARRAY); -#if GL_ARB_vertex_array_object - glBindVertexArray(mGLArray); -#endif - sGLRenderArray = mGLArray; - - U32 attrib_size[] = - { - 3, //TYPE_VERTEX, - 3, //TYPE_NORMAL, - 2, //TYPE_TEXCOORD0, - 2, //TYPE_TEXCOORD1, - 2, //TYPE_TEXCOORD2, - 2, //TYPE_TEXCOORD3, - 4, //TYPE_COLOR, - 4, //TYPE_EMISSIVE, - 3, //TYPE_BINORMAL, - 1, //TYPE_WEIGHT, - 4, //TYPE_WEIGHT4, - 4, //TYPE_CLOTHWEIGHT, - 1, //TYPE_TEXTURE_INDEX - }; - - U32 attrib_type[] = - { - GL_FLOAT, //TYPE_VERTEX, - GL_FLOAT, //TYPE_NORMAL, - GL_FLOAT, //TYPE_TEXCOORD0, - GL_FLOAT, //TYPE_TEXCOORD1, - GL_FLOAT, //TYPE_TEXCOORD2, - GL_FLOAT, //TYPE_TEXCOORD3, - GL_UNSIGNED_BYTE, //TYPE_COLOR, - GL_UNSIGNED_BYTE, //TYPE_EMISSIVE, - GL_FLOAT, //TYPE_BINORMAL, - GL_FLOAT, //TYPE_WEIGHT, - GL_FLOAT, //TYPE_WEIGHT4, - GL_FLOAT, //TYPE_CLOTHWEIGHT, - GL_FLOAT, //TYPE_TEXTURE_INDEX - }; - - U32 attrib_normalized[] = - { - GL_FALSE, //TYPE_VERTEX, - GL_FALSE, //TYPE_NORMAL, - GL_FALSE, //TYPE_TEXCOORD0, - GL_FALSE, //TYPE_TEXCOORD1, - GL_FALSE, //TYPE_TEXCOORD2, - GL_FALSE, //TYPE_TEXCOORD3, - GL_TRUE, //TYPE_COLOR, - GL_TRUE, //TYPE_EMISSIVE, - GL_FALSE, //TYPE_BINORMAL, - GL_FALSE, //TYPE_WEIGHT, - GL_FALSE, //TYPE_WEIGHT4, - GL_FALSE, //TYPE_CLOTHWEIGHT, - GL_FALSE, //TYPE_TEXTURE_INDEX - }; - - bindGLBuffer(true); - bindGLIndices(true); - - for (U32 i = 0; i < TYPE_MAX; ++i) - { - if (mTypeMask & (1 << i)) - { - glEnableVertexAttribArrayARB(i); - glVertexAttribPointerARB(i, attrib_size[i], attrib_type[i], attrib_normalized[i], sTypeSize[i], (void*) mOffsets[i]); - } - else - { - glDisableVertexAttribArrayARB(i); - } - } - - //draw a dummy triangle to set index array pointer - //glDrawElements(GL_TRIANGLES, 0, GL_UNSIGNED_SHORT, NULL); - - unbind(); -} - -void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices) -{ - llassert(newnverts >= 0); - llassert(newnindices >= 0); - - LLMemType mt2(LLMemType::MTYPE_VERTEX_RESIZE_BUFFER); - - updateNumVerts(newnverts); - updateNumIndices(newnindices); - - if (useVBOs()) - { - flush(); - - if (mGLArray) - { //if size changed, offsets changed - setupVertexArray(); - } - } -} - -BOOL LLVertexBuffer::useVBOs() const -{ - //it's generally ineffective to use VBO for things that are streaming on apple - - if (!mUsage) - { - return FALSE; - } - - return TRUE; -} - -//---------------------------------------------------------------------------- - -bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count) -{ - S32 end = index+count; - S32 region_end = region.mIndex+region.mCount; - - if (end < region.mIndex || - index > region_end) - { //gap exists, do not merge - return false; - } - - S32 new_end = llmax(end, region_end); - S32 new_index = llmin(index, region.mIndex); - region.mIndex = new_index; - region.mCount = new_end-new_index; - return true; -} - -static LLFastTimer::DeclareTimer FTM_VBO_MAP_BUFFER_RANGE("VBO Map Range"); -static LLFastTimer::DeclareTimer FTM_VBO_MAP_BUFFER("VBO Map"); - -// Map for data access -volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range) -{ - bindGLBuffer(true); - LLMemType mt2(LLMemType::MTYPE_VERTEX_MAP_BUFFER); - if (mFinal) - { - llerrs << "LLVertexBuffer::mapVeretxBuffer() called on a finalized buffer." << llendl; - } - if (!useVBOs() && !mMappedData && !mMappedIndexData) - { - llerrs << "LLVertexBuffer::mapVertexBuffer() called on unallocated buffer." << llendl; - } - - if (useVBOs()) - { - if (!mMappable || gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange) - { - if (count == -1) - { - count = mNumVerts-index; - } - - bool mapped = false; - //see if range is already mapped - for (U32 i = 0; i < mMappedVertexRegions.size(); ++i) - { - MappedRegion& region = mMappedVertexRegions[i]; - if (region.mType == type) - { - if (expand_region(region, index, count)) - { - mapped = true; - break; - } - } - } - - if (!mapped) - { - //not already mapped, map new region - MappedRegion region(type, mMappable && map_range ? -1 : index, count); - mMappedVertexRegions.push_back(region); - } - } - - if (mVertexLocked && map_range) - { - llerrs << "Attempted to map a specific range of a buffer that was already mapped." << llendl; - } - - if (!mVertexLocked) - { - LLMemType mt_v(LLMemType::MTYPE_VERTEX_MAP_BUFFER_VERTICES); - mVertexLocked = TRUE; - sMappedCount++; - stop_glerror(); - - if(!mMappable) - { - map_range = false; - } - else - { - volatile U8* src = NULL; - waitFence(); - if (gGLManager.mHasMapBufferRange) - { - if (map_range) - { -#ifdef GL_ARB_map_buffer_range - LLFastTimer t(FTM_VBO_MAP_BUFFER_RANGE); - S32 offset = mOffsets[type] + sTypeSize[type]*index; - S32 length = (sTypeSize[type]*count+0xF) & ~0xF; - src = (U8*) glMapBufferRange(GL_ARRAY_BUFFER_ARB, offset, length, - GL_MAP_WRITE_BIT | - GL_MAP_FLUSH_EXPLICIT_BIT | - GL_MAP_INVALIDATE_RANGE_BIT); -#endif - } - else - { -#ifdef GL_ARB_map_buffer_range - - if (gDebugGL) - { - GLint size = 0; - glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SIZE_ARB, &size); - - if (size < mSize) - { - llerrs << "Invalid buffer size." << llendl; - } - } - - LLFastTimer t(FTM_VBO_MAP_BUFFER); - src = (U8*) glMapBufferRange(GL_ARRAY_BUFFER_ARB, 0, mSize, - GL_MAP_WRITE_BIT | - GL_MAP_FLUSH_EXPLICIT_BIT); -#endif - } - } - else if (gGLManager.mHasFlushBufferRange) - { - if (map_range) - { - glBufferParameteriAPPLE(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_FALSE); - glBufferParameteriAPPLE(GL_ARRAY_BUFFER_ARB, GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE); - src = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); - } - else - { - src = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); - } - } - else - { - map_range = false; - src = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); - } - - llassert(src != NULL); - - mMappedData = LL_NEXT_ALIGNED_ADDRESS<volatile U8>(src); - mAlignedOffset = mMappedData - src; - - stop_glerror(); - } - - if (!mMappedData) - { - log_glerror(); - - //check the availability of memory - LLMemory::logMemoryInfo(TRUE) ; - - if(mMappable) - { - //-------------------- - //print out more debug info before crash - llinfos << "vertex buffer size: (num verts : num indices) = " << getNumVerts() << " : " << getNumIndices() << llendl ; - GLint size ; - glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SIZE_ARB, &size) ; - llinfos << "GL_ARRAY_BUFFER_ARB size is " << size << llendl ; - //-------------------- - - GLint buff; - glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB, &buff); - if ((GLuint)buff != mGLBuffer) - { - llerrs << "Invalid GL vertex buffer bound: " << buff << llendl; - } - - - llerrs << "glMapBuffer returned NULL (no vertex data)" << llendl; - } - else - { - llerrs << "memory allocation for vertex data failed." << llendl ; - } - } - } - } - else - { - map_range = false; - } - - if (map_range && gGLManager.mHasMapBufferRange && mMappable) - { - return mMappedData; - } - else - { - return mMappedData+mOffsets[type]+sTypeSize[type]*index; - } -} - - -static LLFastTimer::DeclareTimer FTM_VBO_MAP_INDEX_RANGE("IBO Map Range"); -static LLFastTimer::DeclareTimer FTM_VBO_MAP_INDEX("IBO Map"); - -volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range) -{ - LLMemType mt2(LLMemType::MTYPE_VERTEX_MAP_BUFFER); - bindGLIndices(true); - if (mFinal) - { - llerrs << "LLVertexBuffer::mapIndexBuffer() called on a finalized buffer." << llendl; - } - if (!useVBOs() && !mMappedData && !mMappedIndexData) - { - llerrs << "LLVertexBuffer::mapIndexBuffer() called on unallocated buffer." << llendl; - } - - if (useVBOs()) - { - if (!mMappable || gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange) - { - if (count == -1) - { - count = mNumIndices-index; - } - - bool mapped = false; - //see if range is already mapped - for (U32 i = 0; i < mMappedIndexRegions.size(); ++i) - { - MappedRegion& region = mMappedIndexRegions[i]; - if (expand_region(region, index, count)) - { - mapped = true; - break; - } - } - - if (!mapped) - { - //not already mapped, map new region - MappedRegion region(TYPE_INDEX, mMappable && map_range ? -1 : index, count); - mMappedIndexRegions.push_back(region); - } - } - - if (mIndexLocked && map_range) - { - llerrs << "Attempted to map a specific range of a buffer that was already mapped." << llendl; - } - - if (!mIndexLocked) - { - LLMemType mt_v(LLMemType::MTYPE_VERTEX_MAP_BUFFER_INDICES); - - mIndexLocked = TRUE; - sMappedCount++; - stop_glerror(); - - if (gDebugGL && useVBOs()) - { - GLint elem = 0; - glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &elem); - - if (elem != mGLIndices) - { - llerrs << "Wrong index buffer bound!" << llendl; - } - } - - if(!mMappable) - { - map_range = false; - } - else - { - volatile U8* src = NULL; - waitFence(); - if (gGLManager.mHasMapBufferRange) - { - if (map_range) - { -#ifdef GL_ARB_map_buffer_range - LLFastTimer t(FTM_VBO_MAP_INDEX_RANGE); - S32 offset = sizeof(U16)*index; - S32 length = sizeof(U16)*count; - src = (U8*) glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length, - GL_MAP_WRITE_BIT | - GL_MAP_FLUSH_EXPLICIT_BIT | - GL_MAP_INVALIDATE_RANGE_BIT); -#endif - } - else - { -#ifdef GL_ARB_map_buffer_range - LLFastTimer t(FTM_VBO_MAP_INDEX); - src = (U8*) glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, sizeof(U16)*mNumIndices, - GL_MAP_WRITE_BIT | - GL_MAP_FLUSH_EXPLICIT_BIT); -#endif - } - } - else if (gGLManager.mHasFlushBufferRange) - { - if (map_range) - { - glBufferParameteriAPPLE(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_FALSE); - glBufferParameteriAPPLE(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE); - src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); - } - else - { - src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); - } - } - else - { - LLFastTimer t(FTM_VBO_MAP_INDEX); - map_range = false; - src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); - } - - llassert(src != NULL); - - - mMappedIndexData = src; //LL_NEXT_ALIGNED_ADDRESS<U8>(src); - mAlignedIndexOffset = mMappedIndexData - src; - stop_glerror(); - } - } - - if (!mMappedIndexData) - { - log_glerror(); - LLMemory::logMemoryInfo(TRUE) ; - - if(mMappable) - { - GLint buff; - glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff); - if ((GLuint)buff != mGLIndices) - { - llerrs << "Invalid GL index buffer bound: " << buff << llendl; - } - - llerrs << "glMapBuffer returned NULL (no index data)" << llendl; - } - else - { - llerrs << "memory allocation for Index data failed. " << llendl ; - } - } - } - else - { - map_range = false; - } - - if (map_range && gGLManager.mHasMapBufferRange && mMappable) - { - return mMappedIndexData; - } - else - { - return mMappedIndexData + sizeof(U16)*index; - } -} - -static LLFastTimer::DeclareTimer FTM_VBO_UNMAP("VBO Unmap"); -static LLFastTimer::DeclareTimer FTM_VBO_FLUSH_RANGE("Flush VBO Range"); - - -static LLFastTimer::DeclareTimer FTM_IBO_UNMAP("IBO Unmap"); -static LLFastTimer::DeclareTimer FTM_IBO_FLUSH_RANGE("Flush IBO Range"); - -void LLVertexBuffer::unmapBuffer() -{ - LLMemType mt2(LLMemType::MTYPE_VERTEX_UNMAP_BUFFER); - if (!useVBOs()) - { - return ; //nothing to unmap - } - - bool updated_all = false ; - - if (mMappedData && mVertexLocked) - { - LLFastTimer t(FTM_VBO_UNMAP); - bindGLBuffer(true); - updated_all = mIndexLocked; //both vertex and index buffers done updating - - if(!mMappable) - { - if (!mMappedVertexRegions.empty()) - { - stop_glerror(); - for (U32 i = 0; i < mMappedVertexRegions.size(); ++i) - { - const MappedRegion& region = mMappedVertexRegions[i]; - S32 offset = region.mIndex >= 0 ? mOffsets[region.mType]+sTypeSize[region.mType]*region.mIndex : 0; - S32 length = sTypeSize[region.mType]*region.mCount; - glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, offset, length, (U8*) mMappedData+offset); - stop_glerror(); - } - - mMappedVertexRegions.clear(); - } - else - { - stop_glerror(); - glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, getSize(), (U8*) mMappedData); - stop_glerror(); - } - } - else - { - if (gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange) - { - if (!mMappedVertexRegions.empty()) - { - stop_glerror(); - for (U32 i = 0; i < mMappedVertexRegions.size(); ++i) - { - const MappedRegion& region = mMappedVertexRegions[i]; - S32 offset = region.mIndex >= 0 ? mOffsets[region.mType]+sTypeSize[region.mType]*region.mIndex : 0; - S32 length = sTypeSize[region.mType]*region.mCount; - if (gGLManager.mHasMapBufferRange) - { - LLFastTimer t(FTM_VBO_FLUSH_RANGE); -#ifdef GL_ARB_map_buffer_range - glFlushMappedBufferRange(GL_ARRAY_BUFFER_ARB, offset, length); -#endif - } - else if (gGLManager.mHasFlushBufferRange) - { - glFlushMappedBufferRangeAPPLE(GL_ARRAY_BUFFER_ARB, offset, length); - } - stop_glerror(); - } - - mMappedVertexRegions.clear(); - } - } - stop_glerror(); - glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); - stop_glerror(); - - mMappedData = NULL; - } - - mVertexLocked = FALSE ; - sMappedCount--; - } - - if (mMappedIndexData && mIndexLocked) - { - LLFastTimer t(FTM_IBO_UNMAP); - bindGLIndices(); - if(!mMappable) - { - if (!mMappedIndexRegions.empty()) - { - for (U32 i = 0; i < mMappedIndexRegions.size(); ++i) - { - const MappedRegion& region = mMappedIndexRegions[i]; - S32 offset = region.mIndex >= 0 ? sizeof(U16)*region.mIndex : 0; - S32 length = sizeof(U16)*region.mCount; - glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length, (U8*) mMappedIndexData+offset); - stop_glerror(); - } - - mMappedIndexRegions.clear(); - } - else - { - stop_glerror(); - glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, getIndicesSize(), (U8*) mMappedIndexData); - stop_glerror(); - } - } - else - { - if (gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange) - { - if (!mMappedIndexRegions.empty()) - { - for (U32 i = 0; i < mMappedIndexRegions.size(); ++i) - { - const MappedRegion& region = mMappedIndexRegions[i]; - S32 offset = region.mIndex >= 0 ? sizeof(U16)*region.mIndex : 0; - S32 length = sizeof(U16)*region.mCount; - if (gGLManager.mHasMapBufferRange) - { - LLFastTimer t(FTM_IBO_FLUSH_RANGE); -#ifdef GL_ARB_map_buffer_range - glFlushMappedBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length); -#endif - } - else if (gGLManager.mHasFlushBufferRange) - { -#ifdef GL_APPLE_flush_buffer_range - glFlushMappedBufferRangeAPPLE(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length); -#endif - } - stop_glerror(); - } - - mMappedIndexRegions.clear(); - } - } - stop_glerror(); - glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB); - stop_glerror(); - - mMappedIndexData = NULL ; - } - - mIndexLocked = FALSE ; - sMappedCount--; - } - - if(updated_all) - { - mEmpty = FALSE; - } -} - -//---------------------------------------------------------------------------- - -template <class T,S32 type> struct VertexBufferStrider -{ - typedef LLStrider<T> strider_t; - static bool get(LLVertexBuffer& vbo, - strider_t& strider, - S32 index, S32 count, bool map_range) - { - if (type == LLVertexBuffer::TYPE_INDEX) - { - volatile U8* ptr = vbo.mapIndexBuffer(index, count, map_range); - - if (ptr == NULL) - { - llwarns << "mapIndexBuffer failed!" << llendl; - return FALSE; - } - - strider = (T*)ptr; - strider.setStride(0); - return TRUE; - } - else if (vbo.hasDataType(type)) - { - S32 stride = LLVertexBuffer::sTypeSize[type]; - - volatile U8* ptr = vbo.mapVertexBuffer(type, index, count, map_range); - - if (ptr == NULL) - { - llwarns << "mapVertexBuffer failed!" << llendl; - return FALSE; - } - - strider = (T*)ptr; - strider.setStride(stride); - return TRUE; - } - else - { - llerrs << "VertexBufferStrider could not find valid vertex data." << llendl; - } - return FALSE; - } -}; - -bool LLVertexBuffer::getVertexStrider(LLStrider<LLVector3>& strider, S32 index, S32 count, bool map_range) -{ - return VertexBufferStrider<LLVector3,TYPE_VERTEX>::get(*this, strider, index, count, map_range); -} -bool LLVertexBuffer::getVertexStrider(LLStrider<LLVector4a>& strider, S32 index, S32 count, bool map_range) -{ - return VertexBufferStrider<LLVector4a,TYPE_VERTEX>::get(*this, strider, index, count, map_range); -} -bool LLVertexBuffer::getIndexStrider(LLStrider<U16>& strider, S32 index, S32 count, bool map_range) -{ - return VertexBufferStrider<U16,TYPE_INDEX>::get(*this, strider, index, count, map_range); -} -bool LLVertexBuffer::getTexCoord0Strider(LLStrider<LLVector2>& strider, S32 index, S32 count, bool map_range) -{ - return VertexBufferStrider<LLVector2,TYPE_TEXCOORD0>::get(*this, strider, index, count, map_range); -} -bool LLVertexBuffer::getTexCoord1Strider(LLStrider<LLVector2>& strider, S32 index, S32 count, bool map_range) -{ - return VertexBufferStrider<LLVector2,TYPE_TEXCOORD1>::get(*this, strider, index, count, map_range); -} - -bool LLVertexBuffer::getNormalStrider(LLStrider<LLVector3>& strider, S32 index, S32 count, bool map_range) -{ - return VertexBufferStrider<LLVector3,TYPE_NORMAL>::get(*this, strider, index, count, map_range); -} -bool LLVertexBuffer::getBinormalStrider(LLStrider<LLVector3>& strider, S32 index, S32 count, bool map_range) -{ - return VertexBufferStrider<LLVector3,TYPE_BINORMAL>::get(*this, strider, index, count, map_range); -} -bool LLVertexBuffer::getColorStrider(LLStrider<LLColor4U>& strider, S32 index, S32 count, bool map_range) -{ - return VertexBufferStrider<LLColor4U,TYPE_COLOR>::get(*this, strider, index, count, map_range); -} -bool LLVertexBuffer::getEmissiveStrider(LLStrider<LLColor4U>& strider, S32 index, S32 count, bool map_range) -{ - return VertexBufferStrider<LLColor4U,TYPE_EMISSIVE>::get(*this, strider, index, count, map_range); -} -bool LLVertexBuffer::getWeightStrider(LLStrider<F32>& strider, S32 index, S32 count, bool map_range) -{ - return VertexBufferStrider<F32,TYPE_WEIGHT>::get(*this, strider, index, count, map_range); -} - -bool LLVertexBuffer::getWeight4Strider(LLStrider<LLVector4>& strider, S32 index, S32 count, bool map_range) -{ - return VertexBufferStrider<LLVector4,TYPE_WEIGHT4>::get(*this, strider, index, count, map_range); -} - -bool LLVertexBuffer::getClothWeightStrider(LLStrider<LLVector4>& strider, S32 index, S32 count, bool map_range) -{ - return VertexBufferStrider<LLVector4,TYPE_CLOTHWEIGHT>::get(*this, strider, index, count, map_range); -} - -//---------------------------------------------------------------------------- - -static LLFastTimer::DeclareTimer FTM_BIND_GL_ARRAY("Bind Array"); -bool LLVertexBuffer::bindGLArray() -{ - if (mGLArray && sGLRenderArray != mGLArray) - { - { - LLFastTimer t(FTM_BIND_GL_ARRAY); -#if GL_ARB_vertex_array_object - glBindVertexArray(mGLArray); -#endif - sGLRenderArray = mGLArray; - } - - //really shouldn't be necessary, but some drivers don't properly restore the - //state of GL_ELEMENT_ARRAY_BUFFER_BINDING - bindGLIndices(); - - return true; - } - - return false; -} - -static LLFastTimer::DeclareTimer FTM_BIND_GL_BUFFER("Bind Buffer"); - -bool LLVertexBuffer::bindGLBuffer(bool force_bind) -{ - bindGLArray(); - - bool ret = false; - - if (useVBOs() && (force_bind || (mGLBuffer && (mGLBuffer != sGLRenderBuffer || !sVBOActive)))) - { - LLFastTimer t(FTM_BIND_GL_BUFFER); - /*if (sMapped) - { - llerrs << "VBO bound while another VBO mapped!" << llendl; - }*/ - glBindBufferARB(GL_ARRAY_BUFFER_ARB, mGLBuffer); - sGLRenderBuffer = mGLBuffer; - sBindCount++; - sVBOActive = TRUE; - - if (mGLArray) - { - llassert(sGLRenderArray == mGLArray); - //mCachedRenderBuffer = mGLBuffer; - } - - ret = true; - } - - return ret; -} - -static LLFastTimer::DeclareTimer FTM_BIND_GL_INDICES("Bind Indices"); - -bool LLVertexBuffer::bindGLIndices(bool force_bind) -{ - bindGLArray(); - - bool ret = false; - if (useVBOs() && (force_bind || (mGLIndices && (mGLIndices != sGLRenderIndices || !sIBOActive)))) - { - LLFastTimer t(FTM_BIND_GL_INDICES); - /*if (sMapped) - { - llerrs << "VBO bound while another VBO mapped!" << llendl; - }*/ - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, mGLIndices); - sGLRenderIndices = mGLIndices; - stop_glerror(); - sBindCount++; - sIBOActive = TRUE; - ret = true; - } - - return ret; -} - -void LLVertexBuffer::flush() -{ - if (useVBOs()) - { - unmapBuffer(); - } -} - -// Set for rendering -void LLVertexBuffer::setBuffer(U32 data_mask) -{ - flush(); - - LLMemType mt2(LLMemType::MTYPE_VERTEX_SET_BUFFER); - //set up pointers if the data mask is different ... - BOOL setup = (sLastMask != data_mask); - - if (gDebugGL && data_mask != 0) - { //make sure data requirements are fulfilled - LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; - if (shader) - { - U32 required_mask = 0; - for (U32 i = 0; i < LLVertexBuffer::TYPE_TEXTURE_INDEX; ++i) - { - if (shader->getAttribLocation(i) > -1) - { - U32 required = 1 << i; - if ((data_mask & required) == 0) - { - llwarns << "Missing attribute: " << LLShaderMgr::instance()->mReservedAttribs[i] << llendl; - } - - required_mask |= required; - } - } - - if ((data_mask & required_mask) != required_mask) - { - llerrs << "Shader consumption mismatches data provision." << llendl; - } - } - } - - if (useVBOs()) - { - if (mGLArray) - { - bindGLArray(); - setup = FALSE; //do NOT perform pointer setup if using VAO - } - else - { - if (bindGLBuffer()) - { - setup = TRUE; - } - if (bindGLIndices()) - { - setup = TRUE; - } - } - - BOOL error = FALSE; - if (gDebugGL && !mGLArray) - { - GLint buff; - glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB, &buff); - if ((GLuint)buff != mGLBuffer) - { - if (gDebugSession) - { - error = TRUE; - gFailLog << "Invalid GL vertex buffer bound: " << buff << std::endl; - } - else - { - llerrs << "Invalid GL vertex buffer bound: " << buff << llendl; - } - } - - if (mGLIndices) - { - glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff); - if ((GLuint)buff != mGLIndices) - { - if (gDebugSession) - { - error = TRUE; - gFailLog << "Invalid GL index buffer bound: " << buff << std::endl; - } - else - { - llerrs << "Invalid GL index buffer bound: " << buff << llendl; - } - } - } - } - - - } - else - { - if (sGLRenderArray) - { -#if GL_ARB_vertex_array_object - glBindVertexArray(0); -#endif - sGLRenderArray = 0; - sGLRenderIndices = 0; - sIBOActive = FALSE; - } - - if (mGLBuffer) - { - if (sVBOActive) - { - glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - sBindCount++; - sVBOActive = FALSE; - setup = TRUE; // ... or a VBO is deactivated - } - if (sGLRenderBuffer != mGLBuffer) - { - sGLRenderBuffer = mGLBuffer; - setup = TRUE; // ... or a client memory pointer changed - } - } - if (mGLIndices) - { - if (sIBOActive) - { - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); - sBindCount++; - sIBOActive = FALSE; - } - - sGLRenderIndices = mGLIndices; - } - } - - if (!mGLArray) - { - setupClientArrays(data_mask); - } - - if (mGLBuffer) - { - if (data_mask && setup) - { - setupVertexBuffer(data_mask); // subclass specific setup (virtual function) - sSetCount++; - } - } -} - -// virtual (default) -void LLVertexBuffer::setupVertexBuffer(U32 data_mask) -{ - LLMemType mt2(LLMemType::MTYPE_VERTEX_SETUP_VERTEX_BUFFER); - stop_glerror(); - volatile U8* base = useVBOs() ? (U8*) mAlignedOffset : mMappedData; - - /*if ((data_mask & mTypeMask) != data_mask) - { - llerrs << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << llendl; - }*/ - - if (LLGLSLShader::sNoFixedFunction) - { - if (data_mask & MAP_NORMAL) - { - S32 loc = TYPE_NORMAL; - void* ptr = (void*)(base + mOffsets[TYPE_NORMAL]); - glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_NORMAL], ptr); - } - if (data_mask & MAP_TEXCOORD3) - { - S32 loc = TYPE_TEXCOORD3; - void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD3]); - glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], ptr); - } - if (data_mask & MAP_TEXCOORD2) - { - S32 loc = TYPE_TEXCOORD2; - void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD2]); - glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], ptr); - } - if (data_mask & MAP_TEXCOORD1) - { - S32 loc = TYPE_TEXCOORD1; - void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD1]); - glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], ptr); - } - if (data_mask & MAP_BINORMAL) - { - S32 loc = TYPE_BINORMAL; - void* ptr = (void*)(base + mOffsets[TYPE_BINORMAL]); - glVertexAttribPointerARB(loc, 3,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_BINORMAL], ptr); - } - if (data_mask & MAP_TEXCOORD0) - { - S32 loc = TYPE_TEXCOORD0; - void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD0]); - glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], ptr); - } - if (data_mask & MAP_COLOR) - { - S32 loc = TYPE_COLOR; - void* ptr = (void*)(base + mOffsets[TYPE_COLOR]); - glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_COLOR], ptr); - } - if (data_mask & MAP_EMISSIVE) - { - S32 loc = TYPE_EMISSIVE; - void* ptr = (void*)(base + mOffsets[TYPE_EMISSIVE]); - glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_EMISSIVE], ptr); - } - if (data_mask & MAP_WEIGHT) - { - S32 loc = TYPE_WEIGHT; - void* ptr = (void*)(base + mOffsets[TYPE_WEIGHT]); - glVertexAttribPointerARB(loc, 1, GL_FLOAT, FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT], ptr); - } - if (data_mask & MAP_WEIGHT4) - { - S32 loc = TYPE_WEIGHT4; - void* ptr = (void*)(base+mOffsets[TYPE_WEIGHT4]); - glVertexAttribPointerARB(loc, 4, GL_FLOAT, FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT4], ptr); - } - if (data_mask & MAP_CLOTHWEIGHT) - { - S32 loc = TYPE_CLOTHWEIGHT; - void* ptr = (void*)(base + mOffsets[TYPE_CLOTHWEIGHT]); - glVertexAttribPointerARB(loc, 4, GL_FLOAT, TRUE, LLVertexBuffer::sTypeSize[TYPE_CLOTHWEIGHT], ptr); - } - if (data_mask & MAP_TEXTURE_INDEX) - { - S32 loc = TYPE_TEXTURE_INDEX; - void *ptr = (void*) (base + mOffsets[TYPE_VERTEX] + 12); - glVertexAttribPointerARB(loc, 1, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr); - } - if (data_mask & MAP_VERTEX) - { - S32 loc = TYPE_VERTEX; - void* ptr = (void*)(base + mOffsets[TYPE_VERTEX]); - glVertexAttribPointerARB(loc, 3,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr); - } - } - else - { - if (data_mask & MAP_NORMAL) - { - glNormalPointer(GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_NORMAL], (void*)(base + mOffsets[TYPE_NORMAL])); - } - if (data_mask & MAP_TEXCOORD3) - { - glClientActiveTextureARB(GL_TEXTURE3_ARB); - glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], (void*)(base + mOffsets[TYPE_TEXCOORD3])); - glClientActiveTextureARB(GL_TEXTURE0_ARB); - } - if (data_mask & MAP_TEXCOORD2) - { - glClientActiveTextureARB(GL_TEXTURE2_ARB); - glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], (void*)(base + mOffsets[TYPE_TEXCOORD2])); - glClientActiveTextureARB(GL_TEXTURE0_ARB); - } - if (data_mask & MAP_TEXCOORD1) - { - glClientActiveTextureARB(GL_TEXTURE1_ARB); - glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], (void*)(base + mOffsets[TYPE_TEXCOORD1])); - glClientActiveTextureARB(GL_TEXTURE0_ARB); - } - if (data_mask & MAP_BINORMAL) - { - glClientActiveTextureARB(GL_TEXTURE2_ARB); - glTexCoordPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_BINORMAL], (void*)(base + mOffsets[TYPE_BINORMAL])); - glClientActiveTextureARB(GL_TEXTURE0_ARB); - } - if (data_mask & MAP_TEXCOORD0) - { - glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0])); - } - if (data_mask & MAP_COLOR) - { - glColorPointer(4, GL_UNSIGNED_BYTE, LLVertexBuffer::sTypeSize[TYPE_COLOR], (void*)(base + mOffsets[TYPE_COLOR])); - } - if (data_mask & MAP_VERTEX) - { - glVertexPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], (void*)(base + 0)); - } - } - - llglassertok(); -} - -LLVertexBuffer::MappedRegion::MappedRegion(S32 type, S32 index, S32 count) -: mType(type), mIndex(index), mCount(count) -{ - llassert(mType == LLVertexBuffer::TYPE_INDEX || - mType < LLVertexBuffer::TYPE_TEXTURE_INDEX); -} - - +/**
+ * @file llvertexbuffer.cpp
+ * @brief LLVertexBuffer implementation
+ *
+ * $LicenseInfo:firstyear=2003&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 <boost/static_assert.hpp>
+#include "llsys.h"
+#include "llvertexbuffer.h"
+// #include "llrender.h"
+#include "llglheaders.h"
+#include "llmemtype.h"
+#include "llrender.h"
+#include "llvector4a.h"
+#include "llshadermgr.h"
+#include "llglslshader.h"
+#include "llmemory.h"
+
+//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)
+{
+ U32 r = 1;
+ while (r < v) {
+ r *= 2;
+ }
+ return r;
+}
+
+
+//============================================================================
+
+//static
+LLVBOPool LLVertexBuffer::sStreamVBOPool;
+LLVBOPool LLVertexBuffer::sDynamicVBOPool;
+LLVBOPool LLVertexBuffer::sStreamIBOPool;
+LLVBOPool LLVertexBuffer::sDynamicIBOPool;
+U32 LLVBOPool::sBytesPooled = 0;
+
+LLPrivateMemoryPool* LLVertexBuffer::sPrivatePoolp = NULL ;
+U32 LLVertexBuffer::sBindCount = 0;
+U32 LLVertexBuffer::sSetCount = 0;
+S32 LLVertexBuffer::sCount = 0;
+S32 LLVertexBuffer::sGLCount = 0;
+S32 LLVertexBuffer::sMappedCount = 0;
+BOOL LLVertexBuffer::sDisableVBOMapping = FALSE ;
+BOOL LLVertexBuffer::sEnableVBOs = TRUE;
+U32 LLVertexBuffer::sGLRenderBuffer = 0;
+U32 LLVertexBuffer::sGLRenderArray = 0;
+U32 LLVertexBuffer::sGLRenderIndices = 0;
+U32 LLVertexBuffer::sLastMask = 0;
+BOOL LLVertexBuffer::sVBOActive = FALSE;
+BOOL LLVertexBuffer::sIBOActive = FALSE;
+U32 LLVertexBuffer::sAllocatedBytes = 0;
+BOOL LLVertexBuffer::sMapped = FALSE;
+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
+{
+public:
+#ifdef GL_ARB_sync
+ GLsync mSync;
+#endif
+
+ LLGLSyncFence()
+ {
+#ifdef GL_ARB_sync
+ mSync = 0;
+#endif
+ }
+
+ virtual ~LLGLSyncFence()
+ {
+#ifdef GL_ARB_sync
+ if (mSync)
+ {
+ glDeleteSync(mSync);
+ }
+#endif
+ }
+
+ void placeFence()
+ {
+#ifdef GL_ARB_sync
+ if (mSync)
+ {
+ glDeleteSync(mSync);
+ }
+ mSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+#endif
+ }
+
+ void 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
+ }
+
+
+};
+
+
+//which power of 2 is i?
+//assumes i is a power of 2 > 0
+U32 wpo2(U32 i)
+{
+ llassert(i > 0);
+ llassert(nhpo2(i) == i);
+
+ U32 r = 0;
+
+ while (i >>= 1) ++r;
+
+ return r;
+}
+
+volatile U8* LLVBOPool::allocate(U32& name, U32 size)
+{
+ llassert(nhpo2(size) == size);
+
+ U32 i = wpo2(size);
+
+ if (mFreeList.size() <= i)
+ {
+ mFreeList.resize(i+1);
+ }
+
+ volatile U8* ret = NULL;
+
+ if (mFreeList[i].empty())
+ {
+ //make a new buffer
+ glGenBuffersARB(1, &name);
+ glBindBufferARB(mType, name);
+ LLVertexBuffer::sAllocatedBytes += 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);
+ }
+ else
+ {
+ name = mFreeList[i].front().mGLName;
+ ret = mFreeList[i].front().mClientData;
+
+ sBytesPooled -= size;
+
+ mFreeList[i].pop_front();
+ }
+
+ return ret;
+}
+
+void LLVBOPool::release(U32 name, volatile U8* buffer, U32 size)
+{
+ llassert(nhpo2(size) == size);
+
+ U32 i = wpo2(size);
+
+ llassert(mFreeList.size() > i);
+
+ Record rec;
+ rec.mGLName = name;
+ rec.mClientData = buffer;
+
+ sBytesPooled += size;
+
+ if (!LLVertexBuffer::sDisableVBOMapping && mUsage == GL_DYNAMIC_DRAW_ARB)
+ {
+ glDeleteBuffersARB(1, &rec.mGLName);
+ }
+ else
+ {
+ mFreeList[i].push_back(rec);
+}
+}
+
+void LLVBOPool::cleanup()
+{
+ U32 size = 1;
+
+ for (U32 i = 0; i < mFreeList.size(); ++i)
+ {
+ record_list_t& l = mFreeList[i];
+
+ while (!l.empty())
+ {
+ Record& r = l.front();
+
+ glDeleteBuffersARB(1, &r.mGLName);
+
+ if (r.mClientData)
+ {
+ ll_aligned_free_16((void*) r.mClientData);
+ }
+
+ l.pop_front();
+
+ LLVertexBuffer::sAllocatedBytes -= size;
+ sBytesPooled -= size;
+ }
+
+ size *= 2;
+ }
+}
+
+
+//NOTE: each component must be AT LEAST 4 bytes in size to avoid a performance penalty on AMD hardware
+S32 LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_MAX] =
+{
+ sizeof(LLVector4), // TYPE_VERTEX,
+ sizeof(LLVector4), // TYPE_NORMAL,
+ sizeof(LLVector2), // TYPE_TEXCOORD0,
+ sizeof(LLVector2), // TYPE_TEXCOORD1,
+ sizeof(LLVector2), // TYPE_TEXCOORD2,
+ sizeof(LLVector2), // TYPE_TEXCOORD3,
+ sizeof(LLColor4U), // TYPE_COLOR,
+ sizeof(LLColor4U), // TYPE_EMISSIVE, only alpha is used currently
+ sizeof(LLVector4), // TYPE_BINORMAL,
+ sizeof(F32), // TYPE_WEIGHT,
+ sizeof(LLVector4), // TYPE_WEIGHT4,
+ sizeof(LLVector4), // TYPE_CLOTHWEIGHT,
+ sizeof(LLVector4), // TYPE_TEXTURE_INDEX (actually exists as position.w), no extra data, but stride is 16 bytes
+};
+
+U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] =
+{
+ GL_TRIANGLES,
+ GL_TRIANGLE_STRIP,
+ GL_TRIANGLE_FAN,
+ GL_POINTS,
+ GL_LINES,
+ GL_LINE_STRIP,
+ GL_QUADS,
+ GL_LINE_LOOP,
+};
+
+
+//static
+void LLVertexBuffer::setupClientArrays(U32 data_mask)
+{
+ if (sLastMask != data_mask)
+ {
+ BOOL error = FALSE;
+
+ if (LLGLSLShader::sNoFixedFunction)
+ {
+ for (U32 i = 0; i < TYPE_MAX; ++i)
+ {
+ S32 loc = i;
+
+ U32 mask = 1 << i;
+
+ if (sLastMask & (1 << i))
+ { //was enabled
+ if (!(data_mask & mask))
+ { //needs to be disabled
+ glDisableVertexAttribArrayARB(loc);
+ }
+ }
+ else
+ { //was disabled
+ if (data_mask & mask)
+ { //needs to be enabled
+ glEnableVertexAttribArrayARB(loc);
+ }
+ }
+ }
+ }
+ else
+ {
+
+ GLenum array[] =
+ {
+ GL_VERTEX_ARRAY,
+ GL_NORMAL_ARRAY,
+ GL_TEXTURE_COORD_ARRAY,
+ GL_COLOR_ARRAY,
+ };
+
+ GLenum mask[] =
+ {
+ MAP_VERTEX,
+ MAP_NORMAL,
+ MAP_TEXCOORD0,
+ MAP_COLOR
+ };
+
+
+
+ for (U32 i = 0; i < 4; ++i)
+ {
+ if (sLastMask & mask[i])
+ { //was enabled
+ if (!(data_mask & mask[i]))
+ { //needs to be disabled
+ glDisableClientState(array[i]);
+ }
+ else if (gDebugGL)
+ { //needs to be enabled, make sure it was (DEBUG)
+ if (!glIsEnabled(array[i]))
+ {
+ if (gDebugSession)
+ {
+ error = TRUE;
+ gFailLog << "Bad client state! " << array[i] << " disabled." << std::endl;
+ }
+ else
+ {
+ llerrs << "Bad client state! " << array[i] << " disabled." << llendl;
+ }
+ }
+ }
+ }
+ else
+ { //was disabled
+ if (data_mask & mask[i])
+ { //needs to be enabled
+ glEnableClientState(array[i]);
+ }
+ else if (gDebugGL && glIsEnabled(array[i]))
+ { //needs to be disabled, make sure it was (DEBUG TEMPORARY)
+ if (gDebugSession)
+ {
+ error = TRUE;
+ gFailLog << "Bad client state! " << array[i] << " enabled." << std::endl;
+ }
+ else
+ {
+ llerrs << "Bad client state! " << array[i] << " enabled." << llendl;
+ }
+ }
+ }
+ }
+
+ U32 map_tc[] =
+ {
+ MAP_TEXCOORD1,
+ MAP_TEXCOORD2,
+ MAP_TEXCOORD3
+ };
+
+ for (U32 i = 0; i < 3; i++)
+ {
+ if (sLastMask & map_tc[i])
+ {
+ if (!(data_mask & map_tc[i]))
+ { //disable
+ glClientActiveTextureARB(GL_TEXTURE1_ARB+i);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ }
+ }
+ else if (data_mask & map_tc[i])
+ {
+ glClientActiveTextureARB(GL_TEXTURE1_ARB+i);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ }
+ }
+
+ if (sLastMask & MAP_BINORMAL)
+ {
+ if (!(data_mask & MAP_BINORMAL))
+ {
+ glClientActiveTextureARB(GL_TEXTURE2_ARB);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ }
+ }
+ else if (data_mask & MAP_BINORMAL)
+ {
+ glClientActiveTextureARB(GL_TEXTURE2_ARB);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ }
+ }
+
+ sLastMask = data_mask;
+ }
+}
+
+//static
+void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm)
+{
+ llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
+ gGL.syncMatrices();
+
+ U32 count = pos.size();
+ llassert_always(norm.size() >= pos.size());
+ llassert_always(count > 0) ;
+
+ unbind();
+
+ setupClientArrays(MAP_VERTEX | MAP_NORMAL);
+
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+
+ if (shader)
+ {
+ S32 loc = LLVertexBuffer::TYPE_VERTEX;
+ if (loc > -1)
+ {
+ glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 0, pos[0].mV);
+ }
+ loc = LLVertexBuffer::TYPE_NORMAL;
+ if (loc > -1)
+ {
+ glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 0, norm[0].mV);
+ }
+ }
+ else
+ {
+ glVertexPointer(3, GL_FLOAT, 0, pos[0].mV);
+ glNormalPointer(GL_FLOAT, 0, norm[0].mV);
+ }
+
+ glDrawArrays(sGLMode[mode], 0, count);
+}
+
+//static
+void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp)
+{
+ llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
+
+ gGL.syncMatrices();
+
+ U32 mask = LLVertexBuffer::MAP_VERTEX;
+ if (tc)
+ {
+ mask = mask | LLVertexBuffer::MAP_TEXCOORD0;
+ }
+
+ unbind();
+
+ setupClientArrays(mask);
+
+ if (LLGLSLShader::sNoFixedFunction)
+ {
+ S32 loc = LLVertexBuffer::TYPE_VERTEX;
+ glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 16, pos);
+
+ if (tc)
+ {
+ loc = LLVertexBuffer::TYPE_TEXCOORD0;
+ glVertexAttribPointerARB(loc, 2, GL_FLOAT, GL_FALSE, 0, tc);
+ }
+ }
+ else
+ {
+ glTexCoordPointer(2, GL_FLOAT, 0, tc);
+ glVertexPointer(3, GL_FLOAT, 16, pos);
+ }
+
+ glDrawElements(sGLMode[mode], num_indices, GL_UNSIGNED_SHORT, indicesp);
+}
+
+void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_offset) const
+{
+ if (start >= (U32) mNumVerts ||
+ end >= (U32) mNumVerts)
+ {
+ llerrs << "Bad vertex buffer draw range: [" << start << ", " << end << "] vs " << mNumVerts << llendl;
+ }
+
+ llassert(mNumIndices >= 0);
+
+ if (indices_offset >= (U32) mNumIndices ||
+ indices_offset + count > (U32) mNumIndices)
+ {
+ llerrs << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << llendl;
+ }
+
+ if (gDebugGL && !useVBOs())
+ {
+ U16* idx = ((U16*) getIndicesPointer())+indices_offset;
+ for (U32 i = 0; i < count; ++i)
+ {
+ if (idx[i] < start || idx[i] > end)
+ {
+ llerrs << "Index out of range: " << idx[i] << " not in [" << start << ", " << end << "]" << llendl;
+ }
+ }
+
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+
+ if (shader && shader->mFeatures.mIndexedTextureChannels > 1)
+ {
+ LLStrider<LLVector4a> v;
+ //hack to get non-const reference
+ LLVertexBuffer* vb = (LLVertexBuffer*) this;
+ vb->getVertexStrider(v);
+
+ for (U32 i = start; i < end; i++)
+ {
+ S32 idx = (S32) (v[i][3]+0.25f);
+ if (idx < 0 || idx >= shader->mFeatures.mIndexedTextureChannels)
+ {
+ llerrs << "Bad texture index found in vertex data stream." << llendl;
+ }
+ }
+ }
+ }
+}
+
+void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const
+{
+ validateRange(start, end, count, indices_offset);
+ mMappable = FALSE;
+ gGL.syncMatrices();
+
+ llassert(mNumVerts >= 0);
+ llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
+
+ if (mGLArray)
+ {
+ if (mGLArray != sGLRenderArray)
+ {
+ llerrs << "Wrong vertex array bound." << llendl;
+ }
+ }
+ else
+ {
+ if (mGLIndices != sGLRenderIndices)
+ {
+ llerrs << "Wrong index buffer bound." << llendl;
+ }
+
+ if (mGLBuffer != sGLRenderBuffer)
+ {
+ llerrs << "Wrong vertex buffer bound." << llendl;
+ }
+ }
+
+ if (gDebugGL && !mGLArray && useVBOs())
+ {
+ GLint elem = 0;
+ glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &elem);
+
+ if (elem != mGLIndices)
+ {
+ llerrs << "Wrong index buffer bound!" << llendl;
+ }
+ }
+
+ if (mode >= LLRender::NUM_MODES)
+ {
+ llerrs << "Invalid draw mode: " << mode << llendl;
+ return;
+ }
+
+ U16* idx = ((U16*) getIndicesPointer())+indices_offset;
+
+ stop_glerror();
+ glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT,
+ idx);
+ stop_glerror();
+ placeFence();
+}
+
+void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
+{
+ llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
+ mMappable = FALSE;
+ gGL.syncMatrices();
+
+ llassert(mNumIndices >= 0);
+ if (indices_offset >= (U32) mNumIndices ||
+ indices_offset + count > (U32) mNumIndices)
+ {
+ llerrs << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << llendl;
+ }
+
+ if (mGLArray)
+ {
+ if (mGLArray != sGLRenderArray)
+ {
+ llerrs << "Wrong vertex array bound." << llendl;
+ }
+ }
+ else
+ {
+ if (mGLIndices != sGLRenderIndices)
+ {
+ llerrs << "Wrong index buffer bound." << llendl;
+ }
+
+ if (mGLBuffer != sGLRenderBuffer)
+ {
+ llerrs << "Wrong vertex buffer bound." << llendl;
+ }
+ }
+
+ if (mode >= LLRender::NUM_MODES)
+ {
+ llerrs << "Invalid draw mode: " << mode << llendl;
+ return;
+ }
+
+ stop_glerror();
+ glDrawElements(sGLMode[mode], count, GL_UNSIGNED_SHORT,
+ ((U16*) getIndicesPointer()) + indices_offset);
+ stop_glerror();
+ placeFence();
+}
+
+void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
+{
+ llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
+ mMappable = FALSE;
+ gGL.syncMatrices();
+
+ llassert(mNumVerts >= 0);
+ if (first >= (U32) mNumVerts ||
+ first + count > (U32) mNumVerts)
+ {
+ llerrs << "Bad vertex buffer draw range: [" << first << ", " << first+count << "]" << llendl;
+ }
+
+ if (mGLArray)
+ {
+ if (mGLArray != sGLRenderArray)
+ {
+ llerrs << "Wrong vertex array bound." << llendl;
+ }
+ }
+ else
+ {
+ BOOL uvb = useVBOs();
+ if (mGLBuffer != sGLRenderBuffer || uvb != sVBOActive)
+ {
+ llerrs << "Wrong vertex buffer bound." << llendl;
+ }
+ }
+
+ if (mode >= LLRender::NUM_MODES)
+ {
+ llerrs << "Invalid draw mode: " << mode << llendl;
+ return;
+ }
+
+ stop_glerror();
+ glDrawArrays(sGLMode[mode], first, count);
+ stop_glerror();
+ placeFence();
+}
+
+//static
+void LLVertexBuffer::initClass(bool use_vbo, bool no_vbo_mapping)
+{
+ sEnableVBOs = use_vbo && gGLManager.mHasVertexBufferObject ;
+ sDisableVBOMapping = sEnableVBOs && no_vbo_mapping ;
+
+ if(!sPrivatePoolp)
+ {
+ sPrivatePoolp = LLPrivateMemoryPoolManager::getInstance()->newPool(LLPrivateMemoryPool::STATIC) ;
+ }
+
+ sStreamVBOPool.mType = GL_ARRAY_BUFFER_ARB;
+ sStreamVBOPool.mUsage= GL_STREAM_DRAW_ARB;
+ sStreamIBOPool.mType = GL_ELEMENT_ARRAY_BUFFER_ARB;
+ sStreamIBOPool.mUsage= GL_STREAM_DRAW_ARB;
+
+ sDynamicVBOPool.mType = GL_ARRAY_BUFFER_ARB;
+ sDynamicVBOPool.mUsage= GL_DYNAMIC_DRAW_ARB;
+ sDynamicIBOPool.mType = GL_ELEMENT_ARRAY_BUFFER_ARB;
+ sDynamicIBOPool.mUsage= GL_DYNAMIC_DRAW_ARB;
+}
+
+//static
+void LLVertexBuffer::unbind()
+{
+ if (sGLRenderArray)
+ {
+#if GL_ARB_vertex_array_object
+ glBindVertexArray(0);
+#endif
+ sGLRenderArray = 0;
+ sGLRenderIndices = 0;
+ sIBOActive = FALSE;
+ }
+
+ if (sVBOActive)
+ {
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
+ sVBOActive = FALSE;
+ }
+ if (sIBOActive)
+ {
+ glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
+ sIBOActive = FALSE;
+ }
+
+ sGLRenderBuffer = 0;
+ sGLRenderIndices = 0;
+
+ setupClientArrays(0);
+}
+
+//static
+void LLVertexBuffer::cleanupClass()
+{
+ LLMemType mt2(LLMemType::MTYPE_VERTEX_CLEANUP_CLASS);
+ unbind();
+
+ sStreamIBOPool.cleanup();
+ sDynamicIBOPool.cleanup();
+ sStreamVBOPool.cleanup();
+ sDynamicVBOPool.cleanup();
+
+ if(sPrivatePoolp)
+ {
+ LLPrivateMemoryPoolManager::getInstance()->deletePool(sPrivatePoolp) ;
+ sPrivatePoolp = NULL ;
+ }
+}
+
+//----------------------------------------------------------------------------
+
+LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) :
+ LLRefCount(),
+
+ mNumVerts(0),
+ mNumIndices(0),
+ mUsage(usage),
+ mGLBuffer(0),
+ mGLArray(0),
+ mGLIndices(0),
+ mMappedData(NULL),
+ mMappedIndexData(NULL),
+ mVertexLocked(FALSE),
+ mIndexLocked(FALSE),
+ mFinal(FALSE),
+ mEmpty(TRUE),
+ mFence(NULL)
+{
+ LLMemType mt2(LLMemType::MTYPE_VERTEX_CONSTRUCTOR);
+ mFence = NULL;
+ if (!sEnableVBOs)
+ {
+ mUsage = 0 ;
+ }
+
+ if (mUsage == GL_STREAM_DRAW_ARB && !sUseStreamDraw)
+ {
+ mUsage = 0;
+ }
+
+ if (mUsage == GL_DYNAMIC_DRAW_ARB && sPreferStreamDraw)
+ {
+ mUsage = GL_STREAM_DRAW_ARB;
+ }
+
+ if (mUsage == 0 && LLRender::sGLCoreProfile)
+ { //MUST use VBOs for all rendering
+ mUsage = GL_STREAM_DRAW_ARB;
+ }
+
+ if (mUsage && mUsage != GL_STREAM_DRAW_ARB)
+ { //only stream_draw and dynamic_draw are supported when using VBOs, dynamic draw is the default
+ if (sDisableVBOMapping)
+ { //always use stream draw if VBO mapping is disabled
+ mUsage = GL_STREAM_DRAW_ARB;
+ }
+ else
+ {
+ mUsage = GL_DYNAMIC_DRAW_ARB;
+ }
+ }
+
+
+ if (mUsage == GL_DYNAMIC_DRAW_ARB && !sDisableVBOMapping)
+ {
+ mMappable = TRUE;
+ }
+ else
+ {
+ mMappable = FALSE;
+ }
+
+ //zero out offsets
+ for (U32 i = 0; i < TYPE_MAX; i++)
+ {
+ mOffsets[i] = 0;
+ }
+
+ mTypeMask = typemask;
+ mSize = 0;
+ mIndicesSize = 0;
+ mAlignedOffset = 0;
+ mAlignedIndexOffset = 0;
+
+ sCount++;
+}
+
+//static
+S32 LLVertexBuffer::calcOffsets(const U32& typemask, S32* offsets, S32 num_vertices)
+{
+ S32 offset = 0;
+ for (S32 i=0; i<TYPE_TEXTURE_INDEX; i++)
+ {
+ U32 mask = 1<<i;
+ if (typemask & mask)
+ {
+ if (offsets && LLVertexBuffer::sTypeSize[i])
+ {
+ offsets[i] = offset;
+ offset += LLVertexBuffer::sTypeSize[i]*num_vertices;
+ offset = (offset + 0xF) & ~0xF;
+ }
+ }
+ }
+
+ offsets[TYPE_TEXTURE_INDEX] = offsets[TYPE_VERTEX] + 12;
+
+ return offset+16;
+}
+
+//static
+S32 LLVertexBuffer::calcVertexSize(const U32& typemask)
+{
+ S32 size = 0;
+ for (S32 i = 0; i < TYPE_TEXTURE_INDEX; i++)
+ {
+ U32 mask = 1<<i;
+ if (typemask & mask)
+ {
+ size += LLVertexBuffer::sTypeSize[i];
+ }
+ }
+
+ return size;
+}
+
+S32 LLVertexBuffer::getSize() const
+{
+ return mSize;
+}
+
+// protected, use unref()
+//virtual
+LLVertexBuffer::~LLVertexBuffer()
+{
+ LLMemType mt2(LLMemType::MTYPE_VERTEX_DESTRUCTOR);
+ destroyGLBuffer();
+ destroyGLIndices();
+
+ if (mGLArray)
+ {
+#if GL_ARB_vertex_array_object
+ glDeleteVertexArrays(1, &mGLArray);
+#endif
+ }
+
+ sCount--;
+
+ if (mFence)
+ {
+ delete mFence;
+ }
+
+ mFence = NULL;
+
+ llassert_always(!mMappedData && !mMappedIndexData) ;
+};
+
+void LLVertexBuffer::placeFence() const
+{
+ /*if (!mFence && useVBOs())
+ {
+ if (gGLManager.mHasSync)
+ {
+ mFence = new LLGLSyncFence();
+ }
+ }
+
+ if (mFence)
+ {
+ mFence->placeFence();
+ }*/
+}
+
+void LLVertexBuffer::waitFence() const
+{
+ /*if (mFence)
+ {
+ mFence->wait();
+ }*/
+}
+
+//----------------------------------------------------------------------------
+
+void LLVertexBuffer::genBuffer(U32 size)
+{
+ mSize = nhpo2(size);
+
+ if (mUsage == GL_STREAM_DRAW_ARB)
+ {
+ mMappedData = sStreamVBOPool.allocate(mGLBuffer, mSize);
+ }
+ else
+ {
+ mMappedData = sDynamicVBOPool.allocate(mGLBuffer, mSize);
+ }
+
+ sGLCount++;
+}
+
+void LLVertexBuffer::genIndices(U32 size)
+{
+ mIndicesSize = nhpo2(size);
+
+ if (mUsage == GL_STREAM_DRAW_ARB)
+ {
+ mMappedIndexData = sStreamIBOPool.allocate(mGLIndices, mIndicesSize);
+ }
+ else
+ {
+ mMappedIndexData = sDynamicIBOPool.allocate(mGLIndices, mIndicesSize);
+ }
+
+ sGLCount++;
+}
+
+void LLVertexBuffer::releaseBuffer()
+{
+ if (mUsage == GL_STREAM_DRAW_ARB)
+ {
+ sStreamVBOPool.release(mGLBuffer, mMappedData, mSize);
+ }
+ else
+ {
+ sDynamicVBOPool.release(mGLBuffer, mMappedData, mSize);
+ }
+
+ mGLBuffer = 0;
+ mMappedData = NULL;
+
+ sGLCount--;
+}
+
+void LLVertexBuffer::releaseIndices()
+{
+ if (mUsage == GL_STREAM_DRAW_ARB)
+ {
+ sStreamIBOPool.release(mGLIndices, mMappedIndexData, mIndicesSize);
+ }
+ else
+ {
+ sDynamicIBOPool.release(mGLIndices, mMappedIndexData, mIndicesSize);
+ }
+
+ mGLIndices = 0;
+ mMappedIndexData = NULL;
+
+ sGLCount--;
+}
+
+void LLVertexBuffer::createGLBuffer(U32 size)
+{
+ LLMemType mt2(LLMemType::MTYPE_VERTEX_CREATE_VERTICES);
+
+ if (mGLBuffer)
+ {
+ destroyGLBuffer();
+ }
+
+ if (size == 0)
+ {
+ return;
+ }
+
+ mEmpty = TRUE;
+
+ if (useVBOs())
+ {
+ genBuffer(size);
+ }
+ else
+ {
+ static int gl_buffer_idx = 0;
+ mGLBuffer = ++gl_buffer_idx;
+ mMappedData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size);
+ mSize = size;
+ }
+}
+
+void LLVertexBuffer::createGLIndices(U32 size)
+{
+ LLMemType mt2(LLMemType::MTYPE_VERTEX_CREATE_INDICES);
+
+ if (mGLIndices)
+ {
+ destroyGLIndices();
+ }
+
+ if (size == 0)
+ {
+ return;
+ }
+
+ mEmpty = TRUE;
+
+ //pad by 16 bytes for aligned copies
+ size += 16;
+
+ if (useVBOs())
+ {
+ //pad by another 16 bytes for VBO pointer adjustment
+ size += 16;
+ genIndices(size);
+ }
+ else
+ {
+ mMappedIndexData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size);
+ static int gl_buffer_idx = 0;
+ mGLIndices = ++gl_buffer_idx;
+ mIndicesSize = size;
+ }
+}
+
+void LLVertexBuffer::destroyGLBuffer()
+{
+ LLMemType mt2(LLMemType::MTYPE_VERTEX_DESTROY_BUFFER);
+ if (mGLBuffer)
+ {
+ if (useVBOs())
+ {
+ releaseBuffer();
+ }
+ else
+ {
+ FREE_MEM(sPrivatePoolp, (void*) mMappedData) ;
+ mMappedData = NULL;
+ mEmpty = TRUE;
+ }
+ }
+
+ mGLBuffer = 0;
+ //unbind();
+}
+
+void LLVertexBuffer::destroyGLIndices()
+{
+ LLMemType mt2(LLMemType::MTYPE_VERTEX_DESTROY_INDICES);
+ if (mGLIndices)
+ {
+ if (useVBOs())
+ {
+ releaseIndices();
+ }
+ else
+ {
+ FREE_MEM(sPrivatePoolp, (void*) mMappedIndexData) ;
+ mMappedIndexData = NULL;
+ mEmpty = TRUE;
+ }
+ }
+
+ mGLIndices = 0;
+ //unbind();
+}
+
+void LLVertexBuffer::updateNumVerts(S32 nverts)
+{
+ LLMemType mt2(LLMemType::MTYPE_VERTEX_UPDATE_VERTS);
+
+ llassert(nverts >= 0);
+
+ if (nverts >= 65535)
+ {
+ llwarns << "Vertex buffer overflow!" << llendl;
+ nverts = 65535;
+ }
+
+ U32 needed_size = calcOffsets(mTypeMask, mOffsets, nverts);
+
+ if (needed_size > mSize || needed_size <= mSize/2)
+ {
+ createGLBuffer(needed_size);
+ }
+
+ mNumVerts = nverts;
+}
+
+void LLVertexBuffer::updateNumIndices(S32 nindices)
+{
+ LLMemType mt2(LLMemType::MTYPE_VERTEX_UPDATE_INDICES);
+
+ llassert(nindices >= 0);
+
+ U32 needed_size = sizeof(U16) * nindices;
+
+ if (needed_size > mIndicesSize || needed_size <= mIndicesSize/2)
+ {
+ createGLIndices(needed_size);
+ }
+
+ mNumIndices = nindices;
+}
+
+void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create)
+{
+ LLMemType mt2(LLMemType::MTYPE_VERTEX_ALLOCATE_BUFFER);
+
+ stop_glerror();
+
+ if (nverts < 0 || nindices < 0 ||
+ nverts > 65536)
+ {
+ llerrs << "Bad vertex buffer allocation: " << nverts << " : " << nindices << llendl;
+ }
+
+ updateNumVerts(nverts);
+ updateNumIndices(nindices);
+
+ if (create && (nverts || nindices))
+ {
+ //actually allocate space for the vertex buffer if using VBO mapping
+ flush();
+
+ if (gGLManager.mHasVertexArrayObject && useVBOs() && (LLRender::sGLCoreProfile || sUseVAO))
+ {
+#if GL_ARB_vertex_array_object
+ glGenVertexArrays(1, &mGLArray);
+#endif
+ setupVertexArray();
+ }
+ }
+}
+
+static LLFastTimer::DeclareTimer FTM_SETUP_VERTEX_ARRAY("Setup VAO");
+
+void LLVertexBuffer::setupVertexArray()
+{
+ if (!mGLArray)
+ {
+ return;
+ }
+
+ LLFastTimer t(FTM_SETUP_VERTEX_ARRAY);
+#if GL_ARB_vertex_array_object
+ glBindVertexArray(mGLArray);
+#endif
+ sGLRenderArray = mGLArray;
+
+ U32 attrib_size[] =
+ {
+ 3, //TYPE_VERTEX,
+ 3, //TYPE_NORMAL,
+ 2, //TYPE_TEXCOORD0,
+ 2, //TYPE_TEXCOORD1,
+ 2, //TYPE_TEXCOORD2,
+ 2, //TYPE_TEXCOORD3,
+ 4, //TYPE_COLOR,
+ 4, //TYPE_EMISSIVE,
+ 3, //TYPE_BINORMAL,
+ 1, //TYPE_WEIGHT,
+ 4, //TYPE_WEIGHT4,
+ 4, //TYPE_CLOTHWEIGHT,
+ 1, //TYPE_TEXTURE_INDEX
+ };
+
+ U32 attrib_type[] =
+ {
+ GL_FLOAT, //TYPE_VERTEX,
+ GL_FLOAT, //TYPE_NORMAL,
+ GL_FLOAT, //TYPE_TEXCOORD0,
+ GL_FLOAT, //TYPE_TEXCOORD1,
+ GL_FLOAT, //TYPE_TEXCOORD2,
+ GL_FLOAT, //TYPE_TEXCOORD3,
+ GL_UNSIGNED_BYTE, //TYPE_COLOR,
+ GL_UNSIGNED_BYTE, //TYPE_EMISSIVE,
+ GL_FLOAT, //TYPE_BINORMAL,
+ GL_FLOAT, //TYPE_WEIGHT,
+ GL_FLOAT, //TYPE_WEIGHT4,
+ GL_FLOAT, //TYPE_CLOTHWEIGHT,
+ GL_FLOAT, //TYPE_TEXTURE_INDEX
+ };
+
+ U32 attrib_normalized[] =
+ {
+ GL_FALSE, //TYPE_VERTEX,
+ GL_FALSE, //TYPE_NORMAL,
+ GL_FALSE, //TYPE_TEXCOORD0,
+ GL_FALSE, //TYPE_TEXCOORD1,
+ GL_FALSE, //TYPE_TEXCOORD2,
+ GL_FALSE, //TYPE_TEXCOORD3,
+ GL_TRUE, //TYPE_COLOR,
+ GL_TRUE, //TYPE_EMISSIVE,
+ GL_FALSE, //TYPE_BINORMAL,
+ GL_FALSE, //TYPE_WEIGHT,
+ GL_FALSE, //TYPE_WEIGHT4,
+ GL_FALSE, //TYPE_CLOTHWEIGHT,
+ GL_FALSE, //TYPE_TEXTURE_INDEX
+ };
+
+ bindGLBuffer(true);
+ bindGLIndices(true);
+
+ for (U32 i = 0; i < TYPE_MAX; ++i)
+ {
+ if (mTypeMask & (1 << i))
+ {
+ glEnableVertexAttribArrayARB(i);
+ glVertexAttribPointerARB(i, attrib_size[i], attrib_type[i], attrib_normalized[i], sTypeSize[i], (void*) mOffsets[i]);
+ }
+ else
+ {
+ glDisableVertexAttribArrayARB(i);
+ }
+ }
+
+ //draw a dummy triangle to set index array pointer
+ //glDrawElements(GL_TRIANGLES, 0, GL_UNSIGNED_SHORT, NULL);
+
+ unbind();
+}
+
+void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices)
+{
+ llassert(newnverts >= 0);
+ llassert(newnindices >= 0);
+
+ LLMemType mt2(LLMemType::MTYPE_VERTEX_RESIZE_BUFFER);
+
+ updateNumVerts(newnverts);
+ updateNumIndices(newnindices);
+
+ if (useVBOs())
+ {
+ flush();
+
+ if (mGLArray)
+ { //if size changed, offsets changed
+ setupVertexArray();
+ }
+ }
+}
+
+BOOL LLVertexBuffer::useVBOs() const
+{
+ //it's generally ineffective to use VBO for things that are streaming on apple
+
+ if (!mUsage)
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+//----------------------------------------------------------------------------
+
+bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count)
+{
+ S32 end = index+count;
+ S32 region_end = region.mIndex+region.mCount;
+
+ if (end < region.mIndex ||
+ index > region_end)
+ { //gap exists, do not merge
+ return false;
+ }
+
+ S32 new_end = llmax(end, region_end);
+ S32 new_index = llmin(index, region.mIndex);
+ region.mIndex = new_index;
+ region.mCount = new_end-new_index;
+ return true;
+}
+
+static LLFastTimer::DeclareTimer FTM_VBO_MAP_BUFFER_RANGE("VBO Map Range");
+static LLFastTimer::DeclareTimer FTM_VBO_MAP_BUFFER("VBO Map");
+
+// Map for data access
+volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range)
+{
+ bindGLBuffer(true);
+ LLMemType mt2(LLMemType::MTYPE_VERTEX_MAP_BUFFER);
+ if (mFinal)
+ {
+ llerrs << "LLVertexBuffer::mapVeretxBuffer() called on a finalized buffer." << llendl;
+ }
+ if (!useVBOs() && !mMappedData && !mMappedIndexData)
+ {
+ llerrs << "LLVertexBuffer::mapVertexBuffer() called on unallocated buffer." << llendl;
+ }
+
+ if (useVBOs())
+ {
+ if (!mMappable || gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange)
+ {
+ if (count == -1)
+ {
+ count = mNumVerts-index;
+ }
+
+ bool mapped = false;
+ //see if range is already mapped
+ for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
+ {
+ MappedRegion& region = mMappedVertexRegions[i];
+ if (region.mType == type)
+ {
+ if (expand_region(region, index, count))
+ {
+ mapped = true;
+ break;
+ }
+ }
+ }
+
+ if (!mapped)
+ {
+ //not already mapped, map new region
+ MappedRegion region(type, mMappable && map_range ? -1 : index, count);
+ mMappedVertexRegions.push_back(region);
+ }
+ }
+
+ if (mVertexLocked && map_range)
+ {
+ llerrs << "Attempted to map a specific range of a buffer that was already mapped." << llendl;
+ }
+
+ if (!mVertexLocked)
+ {
+ LLMemType mt_v(LLMemType::MTYPE_VERTEX_MAP_BUFFER_VERTICES);
+ mVertexLocked = TRUE;
+ sMappedCount++;
+ stop_glerror();
+
+ if(!mMappable)
+ {
+ map_range = false;
+ }
+ else
+ {
+ volatile U8* src = NULL;
+ waitFence();
+ if (gGLManager.mHasMapBufferRange)
+ {
+ if (map_range)
+ {
+#ifdef GL_ARB_map_buffer_range
+ LLFastTimer t(FTM_VBO_MAP_BUFFER_RANGE);
+ S32 offset = mOffsets[type] + sTypeSize[type]*index;
+ S32 length = (sTypeSize[type]*count+0xF) & ~0xF;
+ src = (U8*) glMapBufferRange(GL_ARRAY_BUFFER_ARB, offset, length,
+ GL_MAP_WRITE_BIT |
+ GL_MAP_FLUSH_EXPLICIT_BIT |
+ GL_MAP_INVALIDATE_RANGE_BIT);
+#endif
+ }
+ else
+ {
+#ifdef GL_ARB_map_buffer_range
+
+ if (gDebugGL)
+ {
+ GLint size = 0;
+ glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SIZE_ARB, &size);
+
+ if (size < mSize)
+ {
+ llerrs << "Invalid buffer size." << llendl;
+ }
+ }
+
+ LLFastTimer t(FTM_VBO_MAP_BUFFER);
+ src = (U8*) glMapBufferRange(GL_ARRAY_BUFFER_ARB, 0, mSize,
+ GL_MAP_WRITE_BIT |
+ GL_MAP_FLUSH_EXPLICIT_BIT);
+#endif
+ }
+ }
+ else if (gGLManager.mHasFlushBufferRange)
+ {
+ if (map_range)
+ {
+ glBufferParameteriAPPLE(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_FALSE);
+ glBufferParameteriAPPLE(GL_ARRAY_BUFFER_ARB, GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE);
+ src = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+ }
+ else
+ {
+ src = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+ }
+ }
+ else
+ {
+ map_range = false;
+ src = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+ }
+
+ llassert(src != NULL);
+
+ mMappedData = LL_NEXT_ALIGNED_ADDRESS<volatile U8>(src);
+ mAlignedOffset = mMappedData - src;
+
+ stop_glerror();
+ }
+
+ if (!mMappedData)
+ {
+ log_glerror();
+
+ //check the availability of memory
+ LLMemory::logMemoryInfo(TRUE) ;
+
+ if(mMappable)
+ {
+ //--------------------
+ //print out more debug info before crash
+ llinfos << "vertex buffer size: (num verts : num indices) = " << getNumVerts() << " : " << getNumIndices() << llendl ;
+ GLint size ;
+ glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SIZE_ARB, &size) ;
+ llinfos << "GL_ARRAY_BUFFER_ARB size is " << size << llendl ;
+ //--------------------
+
+ GLint buff;
+ glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB, &buff);
+ if ((GLuint)buff != mGLBuffer)
+ {
+ llerrs << "Invalid GL vertex buffer bound: " << buff << llendl;
+ }
+
+
+ llerrs << "glMapBuffer returned NULL (no vertex data)" << llendl;
+ }
+ else
+ {
+ llerrs << "memory allocation for vertex data failed." << llendl ;
+ }
+ }
+ }
+ }
+ else
+ {
+ map_range = false;
+ }
+
+ if (map_range && gGLManager.mHasMapBufferRange && mMappable)
+ {
+ return mMappedData;
+ }
+ else
+ {
+ return mMappedData+mOffsets[type]+sTypeSize[type]*index;
+ }
+}
+
+
+static LLFastTimer::DeclareTimer FTM_VBO_MAP_INDEX_RANGE("IBO Map Range");
+static LLFastTimer::DeclareTimer FTM_VBO_MAP_INDEX("IBO Map");
+
+volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range)
+{
+ LLMemType mt2(LLMemType::MTYPE_VERTEX_MAP_BUFFER);
+ bindGLIndices(true);
+ if (mFinal)
+ {
+ llerrs << "LLVertexBuffer::mapIndexBuffer() called on a finalized buffer." << llendl;
+ }
+ if (!useVBOs() && !mMappedData && !mMappedIndexData)
+ {
+ llerrs << "LLVertexBuffer::mapIndexBuffer() called on unallocated buffer." << llendl;
+ }
+
+ if (useVBOs())
+ {
+ if (!mMappable || gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange)
+ {
+ if (count == -1)
+ {
+ count = mNumIndices-index;
+ }
+
+ bool mapped = false;
+ //see if range is already mapped
+ for (U32 i = 0; i < mMappedIndexRegions.size(); ++i)
+ {
+ MappedRegion& region = mMappedIndexRegions[i];
+ if (expand_region(region, index, count))
+ {
+ mapped = true;
+ break;
+ }
+ }
+
+ if (!mapped)
+ {
+ //not already mapped, map new region
+ MappedRegion region(TYPE_INDEX, mMappable && map_range ? -1 : index, count);
+ mMappedIndexRegions.push_back(region);
+ }
+ }
+
+ if (mIndexLocked && map_range)
+ {
+ llerrs << "Attempted to map a specific range of a buffer that was already mapped." << llendl;
+ }
+
+ if (!mIndexLocked)
+ {
+ LLMemType mt_v(LLMemType::MTYPE_VERTEX_MAP_BUFFER_INDICES);
+
+ mIndexLocked = TRUE;
+ sMappedCount++;
+ stop_glerror();
+
+ if (gDebugGL && useVBOs())
+ {
+ GLint elem = 0;
+ glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &elem);
+
+ if (elem != mGLIndices)
+ {
+ llerrs << "Wrong index buffer bound!" << llendl;
+ }
+ }
+
+ if(!mMappable)
+ {
+ map_range = false;
+ }
+ else
+ {
+ volatile U8* src = NULL;
+ waitFence();
+ if (gGLManager.mHasMapBufferRange)
+ {
+ if (map_range)
+ {
+#ifdef GL_ARB_map_buffer_range
+ LLFastTimer t(FTM_VBO_MAP_INDEX_RANGE);
+ S32 offset = sizeof(U16)*index;
+ S32 length = sizeof(U16)*count;
+ src = (U8*) glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length,
+ GL_MAP_WRITE_BIT |
+ GL_MAP_FLUSH_EXPLICIT_BIT |
+ GL_MAP_INVALIDATE_RANGE_BIT);
+#endif
+ }
+ else
+ {
+#ifdef GL_ARB_map_buffer_range
+ LLFastTimer t(FTM_VBO_MAP_INDEX);
+ src = (U8*) glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, sizeof(U16)*mNumIndices,
+ GL_MAP_WRITE_BIT |
+ GL_MAP_FLUSH_EXPLICIT_BIT);
+#endif
+ }
+ }
+ else if (gGLManager.mHasFlushBufferRange)
+ {
+ if (map_range)
+ {
+ glBufferParameteriAPPLE(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_FALSE);
+ glBufferParameteriAPPLE(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE);
+ src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+ }
+ else
+ {
+ src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+ }
+ }
+ else
+ {
+ LLFastTimer t(FTM_VBO_MAP_INDEX);
+ map_range = false;
+ src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+ }
+
+ llassert(src != NULL);
+
+
+ mMappedIndexData = src; //LL_NEXT_ALIGNED_ADDRESS<U8>(src);
+ mAlignedIndexOffset = mMappedIndexData - src;
+ stop_glerror();
+ }
+ }
+
+ if (!mMappedIndexData)
+ {
+ log_glerror();
+ LLMemory::logMemoryInfo(TRUE) ;
+
+ if(mMappable)
+ {
+ GLint buff;
+ glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff);
+ if ((GLuint)buff != mGLIndices)
+ {
+ llerrs << "Invalid GL index buffer bound: " << buff << llendl;
+ }
+
+ llerrs << "glMapBuffer returned NULL (no index data)" << llendl;
+ }
+ else
+ {
+ llerrs << "memory allocation for Index data failed. " << llendl ;
+ }
+ }
+ }
+ else
+ {
+ map_range = false;
+ }
+
+ if (map_range && gGLManager.mHasMapBufferRange && mMappable)
+ {
+ return mMappedIndexData;
+ }
+ else
+ {
+ return mMappedIndexData + sizeof(U16)*index;
+ }
+}
+
+static LLFastTimer::DeclareTimer FTM_VBO_UNMAP("VBO Unmap");
+static LLFastTimer::DeclareTimer FTM_VBO_FLUSH_RANGE("Flush VBO Range");
+
+
+static LLFastTimer::DeclareTimer FTM_IBO_UNMAP("IBO Unmap");
+static LLFastTimer::DeclareTimer FTM_IBO_FLUSH_RANGE("Flush IBO Range");
+
+void LLVertexBuffer::unmapBuffer()
+{
+ LLMemType mt2(LLMemType::MTYPE_VERTEX_UNMAP_BUFFER);
+ if (!useVBOs())
+ {
+ return ; //nothing to unmap
+ }
+
+ bool updated_all = false ;
+
+ if (mMappedData && mVertexLocked)
+ {
+ LLFastTimer t(FTM_VBO_UNMAP);
+ bindGLBuffer(true);
+ updated_all = mIndexLocked; //both vertex and index buffers done updating
+
+ if(!mMappable)
+ {
+ if (!mMappedVertexRegions.empty())
+ {
+ stop_glerror();
+ for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
+ {
+ const MappedRegion& region = mMappedVertexRegions[i];
+ S32 offset = region.mIndex >= 0 ? mOffsets[region.mType]+sTypeSize[region.mType]*region.mIndex : 0;
+ S32 length = sTypeSize[region.mType]*region.mCount;
+ glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, offset, length, (U8*) mMappedData+offset);
+ stop_glerror();
+ }
+
+ mMappedVertexRegions.clear();
+ }
+ else
+ {
+ stop_glerror();
+ glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, getSize(), (U8*) mMappedData);
+ stop_glerror();
+ }
+ }
+ else
+ {
+ if (gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange)
+ {
+ if (!mMappedVertexRegions.empty())
+ {
+ stop_glerror();
+ for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
+ {
+ const MappedRegion& region = mMappedVertexRegions[i];
+ S32 offset = region.mIndex >= 0 ? mOffsets[region.mType]+sTypeSize[region.mType]*region.mIndex : 0;
+ S32 length = sTypeSize[region.mType]*region.mCount;
+ if (gGLManager.mHasMapBufferRange)
+ {
+ LLFastTimer t(FTM_VBO_FLUSH_RANGE);
+#ifdef GL_ARB_map_buffer_range
+ glFlushMappedBufferRange(GL_ARRAY_BUFFER_ARB, offset, length);
+#endif
+ }
+ else if (gGLManager.mHasFlushBufferRange)
+ {
+ glFlushMappedBufferRangeAPPLE(GL_ARRAY_BUFFER_ARB, offset, length);
+ }
+ stop_glerror();
+ }
+
+ mMappedVertexRegions.clear();
+ }
+ }
+ stop_glerror();
+ glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
+ stop_glerror();
+
+ mMappedData = NULL;
+ }
+
+ mVertexLocked = FALSE ;
+ sMappedCount--;
+ }
+
+ if (mMappedIndexData && mIndexLocked)
+ {
+ LLFastTimer t(FTM_IBO_UNMAP);
+ bindGLIndices();
+ if(!mMappable)
+ {
+ if (!mMappedIndexRegions.empty())
+ {
+ for (U32 i = 0; i < mMappedIndexRegions.size(); ++i)
+ {
+ const MappedRegion& region = mMappedIndexRegions[i];
+ S32 offset = region.mIndex >= 0 ? sizeof(U16)*region.mIndex : 0;
+ S32 length = sizeof(U16)*region.mCount;
+ glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length, (U8*) mMappedIndexData+offset);
+ stop_glerror();
+ }
+
+ mMappedIndexRegions.clear();
+ }
+ else
+ {
+ stop_glerror();
+ glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, getIndicesSize(), (U8*) mMappedIndexData);
+ stop_glerror();
+ }
+ }
+ else
+ {
+ if (gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange)
+ {
+ if (!mMappedIndexRegions.empty())
+ {
+ for (U32 i = 0; i < mMappedIndexRegions.size(); ++i)
+ {
+ const MappedRegion& region = mMappedIndexRegions[i];
+ S32 offset = region.mIndex >= 0 ? sizeof(U16)*region.mIndex : 0;
+ S32 length = sizeof(U16)*region.mCount;
+ if (gGLManager.mHasMapBufferRange)
+ {
+ LLFastTimer t(FTM_IBO_FLUSH_RANGE);
+#ifdef GL_ARB_map_buffer_range
+ glFlushMappedBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length);
+#endif
+ }
+ else if (gGLManager.mHasFlushBufferRange)
+ {
+#ifdef GL_APPLE_flush_buffer_range
+ glFlushMappedBufferRangeAPPLE(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length);
+#endif
+ }
+ stop_glerror();
+ }
+
+ mMappedIndexRegions.clear();
+ }
+ }
+ stop_glerror();
+ glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);
+ stop_glerror();
+
+ mMappedIndexData = NULL ;
+ }
+
+ mIndexLocked = FALSE ;
+ sMappedCount--;
+ }
+
+ if(updated_all)
+ {
+ mEmpty = FALSE;
+ }
+}
+
+//----------------------------------------------------------------------------
+
+template <class T,S32 type> struct VertexBufferStrider
+{
+ typedef LLStrider<T> strider_t;
+ static bool get(LLVertexBuffer& vbo,
+ strider_t& strider,
+ S32 index, S32 count, bool map_range)
+ {
+ if (type == LLVertexBuffer::TYPE_INDEX)
+ {
+ volatile U8* ptr = vbo.mapIndexBuffer(index, count, map_range);
+
+ if (ptr == NULL)
+ {
+ llwarns << "mapIndexBuffer failed!" << llendl;
+ return FALSE;
+ }
+
+ strider = (T*)ptr;
+ strider.setStride(0);
+ return TRUE;
+ }
+ else if (vbo.hasDataType(type))
+ {
+ S32 stride = LLVertexBuffer::sTypeSize[type];
+
+ volatile U8* ptr = vbo.mapVertexBuffer(type, index, count, map_range);
+
+ if (ptr == NULL)
+ {
+ llwarns << "mapVertexBuffer failed!" << llendl;
+ return FALSE;
+ }
+
+ strider = (T*)ptr;
+ strider.setStride(stride);
+ return TRUE;
+ }
+ else
+ {
+ llerrs << "VertexBufferStrider could not find valid vertex data." << llendl;
+ }
+ return FALSE;
+ }
+};
+
+bool LLVertexBuffer::getVertexStrider(LLStrider<LLVector3>& strider, S32 index, S32 count, bool map_range)
+{
+ return VertexBufferStrider<LLVector3,TYPE_VERTEX>::get(*this, strider, index, count, map_range);
+}
+bool LLVertexBuffer::getVertexStrider(LLStrider<LLVector4a>& strider, S32 index, S32 count, bool map_range)
+{
+ return VertexBufferStrider<LLVector4a,TYPE_VERTEX>::get(*this, strider, index, count, map_range);
+}
+bool LLVertexBuffer::getIndexStrider(LLStrider<U16>& strider, S32 index, S32 count, bool map_range)
+{
+ return VertexBufferStrider<U16,TYPE_INDEX>::get(*this, strider, index, count, map_range);
+}
+bool LLVertexBuffer::getTexCoord0Strider(LLStrider<LLVector2>& strider, S32 index, S32 count, bool map_range)
+{
+ return VertexBufferStrider<LLVector2,TYPE_TEXCOORD0>::get(*this, strider, index, count, map_range);
+}
+bool LLVertexBuffer::getTexCoord1Strider(LLStrider<LLVector2>& strider, S32 index, S32 count, bool map_range)
+{
+ return VertexBufferStrider<LLVector2,TYPE_TEXCOORD1>::get(*this, strider, index, count, map_range);
+}
+
+bool LLVertexBuffer::getNormalStrider(LLStrider<LLVector3>& strider, S32 index, S32 count, bool map_range)
+{
+ return VertexBufferStrider<LLVector3,TYPE_NORMAL>::get(*this, strider, index, count, map_range);
+}
+bool LLVertexBuffer::getBinormalStrider(LLStrider<LLVector3>& strider, S32 index, S32 count, bool map_range)
+{
+ return VertexBufferStrider<LLVector3,TYPE_BINORMAL>::get(*this, strider, index, count, map_range);
+}
+bool LLVertexBuffer::getColorStrider(LLStrider<LLColor4U>& strider, S32 index, S32 count, bool map_range)
+{
+ return VertexBufferStrider<LLColor4U,TYPE_COLOR>::get(*this, strider, index, count, map_range);
+}
+bool LLVertexBuffer::getEmissiveStrider(LLStrider<LLColor4U>& strider, S32 index, S32 count, bool map_range)
+{
+ return VertexBufferStrider<LLColor4U,TYPE_EMISSIVE>::get(*this, strider, index, count, map_range);
+}
+bool LLVertexBuffer::getWeightStrider(LLStrider<F32>& strider, S32 index, S32 count, bool map_range)
+{
+ return VertexBufferStrider<F32,TYPE_WEIGHT>::get(*this, strider, index, count, map_range);
+}
+
+bool LLVertexBuffer::getWeight4Strider(LLStrider<LLVector4>& strider, S32 index, S32 count, bool map_range)
+{
+ return VertexBufferStrider<LLVector4,TYPE_WEIGHT4>::get(*this, strider, index, count, map_range);
+}
+
+bool LLVertexBuffer::getClothWeightStrider(LLStrider<LLVector4>& strider, S32 index, S32 count, bool map_range)
+{
+ return VertexBufferStrider<LLVector4,TYPE_CLOTHWEIGHT>::get(*this, strider, index, count, map_range);
+}
+
+//----------------------------------------------------------------------------
+
+static LLFastTimer::DeclareTimer FTM_BIND_GL_ARRAY("Bind Array");
+bool LLVertexBuffer::bindGLArray()
+{
+ if (mGLArray && sGLRenderArray != mGLArray)
+ {
+ {
+ LLFastTimer t(FTM_BIND_GL_ARRAY);
+#if GL_ARB_vertex_array_object
+ glBindVertexArray(mGLArray);
+#endif
+ sGLRenderArray = mGLArray;
+ }
+
+ //really shouldn't be necessary, but some drivers don't properly restore the
+ //state of GL_ELEMENT_ARRAY_BUFFER_BINDING
+ bindGLIndices();
+
+ return true;
+ }
+
+ return false;
+}
+
+static LLFastTimer::DeclareTimer FTM_BIND_GL_BUFFER("Bind Buffer");
+
+bool LLVertexBuffer::bindGLBuffer(bool force_bind)
+{
+ bindGLArray();
+
+ bool ret = false;
+
+ if (useVBOs() && (force_bind || (mGLBuffer && (mGLBuffer != sGLRenderBuffer || !sVBOActive))))
+ {
+ LLFastTimer t(FTM_BIND_GL_BUFFER);
+ /*if (sMapped)
+ {
+ llerrs << "VBO bound while another VBO mapped!" << llendl;
+ }*/
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, mGLBuffer);
+ sGLRenderBuffer = mGLBuffer;
+ sBindCount++;
+ sVBOActive = TRUE;
+
+ if (mGLArray)
+ {
+ llassert(sGLRenderArray == mGLArray);
+ //mCachedRenderBuffer = mGLBuffer;
+ }
+
+ ret = true;
+ }
+
+ return ret;
+}
+
+static LLFastTimer::DeclareTimer FTM_BIND_GL_INDICES("Bind Indices");
+
+bool LLVertexBuffer::bindGLIndices(bool force_bind)
+{
+ bindGLArray();
+
+ bool ret = false;
+ if (useVBOs() && (force_bind || (mGLIndices && (mGLIndices != sGLRenderIndices || !sIBOActive))))
+ {
+ LLFastTimer t(FTM_BIND_GL_INDICES);
+ /*if (sMapped)
+ {
+ llerrs << "VBO bound while another VBO mapped!" << llendl;
+ }*/
+ glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, mGLIndices);
+ sGLRenderIndices = mGLIndices;
+ stop_glerror();
+ sBindCount++;
+ sIBOActive = TRUE;
+ ret = true;
+ }
+
+ return ret;
+}
+
+void LLVertexBuffer::flush()
+{
+ if (useVBOs())
+ {
+ unmapBuffer();
+ }
+}
+
+// Set for rendering
+void LLVertexBuffer::setBuffer(U32 data_mask)
+{
+ flush();
+
+ LLMemType mt2(LLMemType::MTYPE_VERTEX_SET_BUFFER);
+ //set up pointers if the data mask is different ...
+ BOOL setup = (sLastMask != data_mask);
+
+ if (gDebugGL && data_mask != 0)
+ { //make sure data requirements are fulfilled
+ LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+ if (shader)
+ {
+ U32 required_mask = 0;
+ for (U32 i = 0; i < LLVertexBuffer::TYPE_TEXTURE_INDEX; ++i)
+ {
+ if (shader->getAttribLocation(i) > -1)
+ {
+ U32 required = 1 << i;
+ if ((data_mask & required) == 0)
+ {
+ llwarns << "Missing attribute: " << LLShaderMgr::instance()->mReservedAttribs[i] << llendl;
+ }
+
+ required_mask |= required;
+ }
+ }
+
+ if ((data_mask & required_mask) != required_mask)
+ {
+ llerrs << "Shader consumption mismatches data provision." << llendl;
+ }
+ }
+ }
+
+ if (useVBOs())
+ {
+ if (mGLArray)
+ {
+ bindGLArray();
+ setup = FALSE; //do NOT perform pointer setup if using VAO
+ }
+ else
+ {
+ if (bindGLBuffer())
+ {
+ setup = TRUE;
+ }
+ if (bindGLIndices())
+ {
+ setup = TRUE;
+ }
+ }
+
+ BOOL error = FALSE;
+ if (gDebugGL && !mGLArray)
+ {
+ GLint buff;
+ glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB, &buff);
+ if ((GLuint)buff != mGLBuffer)
+ {
+ if (gDebugSession)
+ {
+ error = TRUE;
+ gFailLog << "Invalid GL vertex buffer bound: " << buff << std::endl;
+ }
+ else
+ {
+ llerrs << "Invalid GL vertex buffer bound: " << buff << llendl;
+ }
+ }
+
+ if (mGLIndices)
+ {
+ glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff);
+ if ((GLuint)buff != mGLIndices)
+ {
+ if (gDebugSession)
+ {
+ error = TRUE;
+ gFailLog << "Invalid GL index buffer bound: " << buff << std::endl;
+ }
+ else
+ {
+ llerrs << "Invalid GL index buffer bound: " << buff << llendl;
+ }
+ }
+ }
+ }
+
+
+ }
+ else
+ {
+ if (sGLRenderArray)
+ {
+#if GL_ARB_vertex_array_object
+ glBindVertexArray(0);
+#endif
+ sGLRenderArray = 0;
+ sGLRenderIndices = 0;
+ sIBOActive = FALSE;
+ }
+
+ if (mGLBuffer)
+ {
+ if (sVBOActive)
+ {
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
+ sBindCount++;
+ sVBOActive = FALSE;
+ setup = TRUE; // ... or a VBO is deactivated
+ }
+ if (sGLRenderBuffer != mGLBuffer)
+ {
+ sGLRenderBuffer = mGLBuffer;
+ setup = TRUE; // ... or a client memory pointer changed
+ }
+ }
+ if (mGLIndices)
+ {
+ if (sIBOActive)
+ {
+ glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
+ sBindCount++;
+ sIBOActive = FALSE;
+ }
+
+ sGLRenderIndices = mGLIndices;
+ }
+ }
+
+ if (!mGLArray)
+ {
+ setupClientArrays(data_mask);
+ }
+
+ if (mGLBuffer)
+ {
+ if (data_mask && setup)
+ {
+ setupVertexBuffer(data_mask); // subclass specific setup (virtual function)
+ sSetCount++;
+ }
+ }
+}
+
+// virtual (default)
+void LLVertexBuffer::setupVertexBuffer(U32 data_mask)
+{
+ LLMemType mt2(LLMemType::MTYPE_VERTEX_SETUP_VERTEX_BUFFER);
+ stop_glerror();
+ volatile U8* base = useVBOs() ? (U8*) mAlignedOffset : mMappedData;
+
+ /*if ((data_mask & mTypeMask) != data_mask)
+ {
+ llerrs << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << llendl;
+ }*/
+
+ if (LLGLSLShader::sNoFixedFunction)
+ {
+ if (data_mask & MAP_NORMAL)
+ {
+ S32 loc = TYPE_NORMAL;
+ void* ptr = (void*)(base + mOffsets[TYPE_NORMAL]);
+ glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_NORMAL], ptr);
+ }
+ if (data_mask & MAP_TEXCOORD3)
+ {
+ S32 loc = TYPE_TEXCOORD3;
+ void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD3]);
+ glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], ptr);
+ }
+ if (data_mask & MAP_TEXCOORD2)
+ {
+ S32 loc = TYPE_TEXCOORD2;
+ void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD2]);
+ glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], ptr);
+ }
+ if (data_mask & MAP_TEXCOORD1)
+ {
+ S32 loc = TYPE_TEXCOORD1;
+ void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD1]);
+ glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], ptr);
+ }
+ if (data_mask & MAP_BINORMAL)
+ {
+ S32 loc = TYPE_BINORMAL;
+ void* ptr = (void*)(base + mOffsets[TYPE_BINORMAL]);
+ glVertexAttribPointerARB(loc, 3,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_BINORMAL], ptr);
+ }
+ if (data_mask & MAP_TEXCOORD0)
+ {
+ S32 loc = TYPE_TEXCOORD0;
+ void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD0]);
+ glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], ptr);
+ }
+ if (data_mask & MAP_COLOR)
+ {
+ S32 loc = TYPE_COLOR;
+ void* ptr = (void*)(base + mOffsets[TYPE_COLOR]);
+ glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_COLOR], ptr);
+ }
+ if (data_mask & MAP_EMISSIVE)
+ {
+ S32 loc = TYPE_EMISSIVE;
+ void* ptr = (void*)(base + mOffsets[TYPE_EMISSIVE]);
+ glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_EMISSIVE], ptr);
+ }
+ if (data_mask & MAP_WEIGHT)
+ {
+ S32 loc = TYPE_WEIGHT;
+ void* ptr = (void*)(base + mOffsets[TYPE_WEIGHT]);
+ glVertexAttribPointerARB(loc, 1, GL_FLOAT, FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT], ptr);
+ }
+ if (data_mask & MAP_WEIGHT4)
+ {
+ S32 loc = TYPE_WEIGHT4;
+ void* ptr = (void*)(base+mOffsets[TYPE_WEIGHT4]);
+ glVertexAttribPointerARB(loc, 4, GL_FLOAT, FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT4], ptr);
+ }
+ if (data_mask & MAP_CLOTHWEIGHT)
+ {
+ S32 loc = TYPE_CLOTHWEIGHT;
+ void* ptr = (void*)(base + mOffsets[TYPE_CLOTHWEIGHT]);
+ glVertexAttribPointerARB(loc, 4, GL_FLOAT, TRUE, LLVertexBuffer::sTypeSize[TYPE_CLOTHWEIGHT], ptr);
+ }
+ if (data_mask & MAP_TEXTURE_INDEX)
+ {
+ S32 loc = TYPE_TEXTURE_INDEX;
+ void *ptr = (void*) (base + mOffsets[TYPE_VERTEX] + 12);
+ glVertexAttribPointerARB(loc, 1, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);
+ }
+ if (data_mask & MAP_VERTEX)
+ {
+ S32 loc = TYPE_VERTEX;
+ void* ptr = (void*)(base + mOffsets[TYPE_VERTEX]);
+ glVertexAttribPointerARB(loc, 3,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);
+ }
+ }
+ else
+ {
+ if (data_mask & MAP_NORMAL)
+ {
+ glNormalPointer(GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_NORMAL], (void*)(base + mOffsets[TYPE_NORMAL]));
+ }
+ if (data_mask & MAP_TEXCOORD3)
+ {
+ glClientActiveTextureARB(GL_TEXTURE3_ARB);
+ glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], (void*)(base + mOffsets[TYPE_TEXCOORD3]));
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ }
+ if (data_mask & MAP_TEXCOORD2)
+ {
+ glClientActiveTextureARB(GL_TEXTURE2_ARB);
+ glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], (void*)(base + mOffsets[TYPE_TEXCOORD2]));
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ }
+ if (data_mask & MAP_TEXCOORD1)
+ {
+ glClientActiveTextureARB(GL_TEXTURE1_ARB);
+ glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], (void*)(base + mOffsets[TYPE_TEXCOORD1]));
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ }
+ if (data_mask & MAP_BINORMAL)
+ {
+ glClientActiveTextureARB(GL_TEXTURE2_ARB);
+ glTexCoordPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_BINORMAL], (void*)(base + mOffsets[TYPE_BINORMAL]));
+ glClientActiveTextureARB(GL_TEXTURE0_ARB);
+ }
+ if (data_mask & MAP_TEXCOORD0)
+ {
+ glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0]));
+ }
+ if (data_mask & MAP_COLOR)
+ {
+ glColorPointer(4, GL_UNSIGNED_BYTE, LLVertexBuffer::sTypeSize[TYPE_COLOR], (void*)(base + mOffsets[TYPE_COLOR]));
+ }
+ if (data_mask & MAP_VERTEX)
+ {
+ glVertexPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], (void*)(base + 0));
+ }
+ }
+
+ llglassertok();
+}
+
+LLVertexBuffer::MappedRegion::MappedRegion(S32 type, S32 index, S32 count)
+: mType(type), mIndex(index), mCount(count)
+{
+ llassert(mType == LLVertexBuffer::TYPE_INDEX ||
+ mType < LLVertexBuffer::TYPE_TEXTURE_INDEX);
+}
+
+
diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index 466fac33ea..f7017064d7 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -389,6 +389,22 @@ std::vector<LLScrollListItem*> LLScrollListCtrl::getAllSelected() const return ret; } +S32 LLScrollListCtrl::getNumSelected() const +{ + S32 numSelected = 0; + + for(item_list::const_iterator iter = mItemList.begin(); iter != mItemList.end(); ++iter) + { + LLScrollListItem* item = *iter; + if (item->getSelected()) + { + ++numSelected; + } + } + + return numSelected; +} + S32 LLScrollListCtrl::getFirstSelectedIndex() const { S32 CurSelectedIndex = 0; diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h index ae8aea9245..44d9635838 100644 --- a/indra/llui/llscrolllistctrl.h +++ b/indra/llui/llscrolllistctrl.h @@ -257,6 +257,7 @@ public: LLScrollListItem* getFirstSelected() const; virtual S32 getFirstSelectedIndex() const; std::vector<LLScrollListItem*> getAllSelected() const; + S32 getNumSelected() const; LLScrollListItem* getLastSelectedItem() const { return mLastSelected; } // iterate over all items diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index f85b943c70..5223eead35 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -17,12 +17,12 @@ include(JsonCpp) include(LLAudio) include(LLCharacter) include(LLCommon) -include(LLConvexDecomposition) include(LLImage) include(LLImageJ2COJ) include(LLInventory) include(LLMath) include(LLMessage) +include(LLPhysicsExtensions) include(LLPlugin) include(LLPrimitive) include(LLRender) @@ -51,7 +51,7 @@ include_directories( ${LLAUDIO_INCLUDE_DIRS} ${LLCHARACTER_INCLUDE_DIRS} ${LLCOMMON_INCLUDE_DIRS} - ${LLCONVEXDECOMP_INCLUDE_DIRS} + ${LLPHYSICS_INCLUDE_DIRS} ${FMOD_INCLUDE_DIR} ${LLIMAGE_INCLUDE_DIRS} ${LLKDU_INCLUDE_DIRS} @@ -217,6 +217,10 @@ set(viewer_SOURCE_FILES llfloaterobjectweights.cpp llfloateropenobject.cpp llfloateroutbox.cpp + llfloaterpathfindingbasic.cpp + llfloaterpathfindingcharacters.cpp + llfloaterpathfindingconsole.cpp + llfloaterpathfindinglinksets.cpp llfloaterpay.cpp llfloaterperms.cpp llfloaterpostprocess.cpp @@ -329,6 +333,7 @@ set(viewer_SOURCE_FILES llnameeditor.cpp llnamelistctrl.cpp llnavigationbar.cpp + llnavmeshstation.cpp llnearbychat.cpp llnearbychatbar.cpp llnearbychathandler.cpp @@ -412,6 +417,10 @@ set(viewer_SOURCE_FILES llparcelselection.cpp llparticipantlist.cpp llpatchvertexarray.cpp + llpathfindingcharacter.cpp + llpathfindinglinkset.cpp + llpathfindinglinksetlist.cpp + llpathfindingmanager.cpp llphysicsmotion.cpp llphysicsshapebuilderutil.cpp llplacesinventorybridge.cpp @@ -773,6 +782,10 @@ set(viewer_HEADER_FILES llfloaterobjectweights.h llfloateropenobject.h llfloateroutbox.h + llfloaterpathfindingbasic.h + llfloaterpathfindingcharacters.h + llfloaterpathfindingconsole.h + llfloaterpathfindinglinksets.h llfloaterpay.h llfloaterperms.h llfloaterpostprocess.h @@ -885,6 +898,7 @@ set(viewer_HEADER_FILES llnameeditor.h llnamelistctrl.h llnavigationbar.h + llnavmeshstation.h llnearbychat.h llnearbychatbar.h llnearbychathandler.h @@ -957,6 +971,10 @@ set(viewer_HEADER_FILES llparcelselection.h llparticipantlist.h llpatchvertexarray.h + llpathfindingcharacter.h + llpathfindinglinkset.h + llpathfindinglinksetlist.h + llpathfindingmanager.h llphysicsmotion.h llphysicsshapebuilderutil.h llplacesinventorybridge.h @@ -1513,9 +1531,9 @@ if (WINDOWS) PROPERTIES # *TODO -reenable this once we get server usage sorted out #LINK_FLAGS "/debug /NODEFAULTLIB:LIBCMT /SUBSYSTEM:WINDOWS /INCLUDE:\"__tcmalloc\"" - LINK_FLAGS "/debug /NODEFAULTLIB:LIBCMT /SUBSYSTEM:WINDOWS /INCLUDE:__tcmalloc" + LINK_FLAGS "/debug /NODEFAULTLIB:LIBCMT /SUBSYSTEM:WINDOWS /INCLUDE:__tcmalloc " LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMT;LIBCMTD;MSVCRT\" /INCREMENTAL:NO" - LINK_FLAGS_RELEASE "" + LINK_FLAGS_RELEASE "/FORCE:MULTIPLE" ) if(USE_PRECOMPILED_HEADERS) set_target_properties( @@ -1729,6 +1747,7 @@ endif (WINDOWS) # To work around this, higher level modules should be listed before the modules # that they depend upon. -brad target_link_libraries(${VIEWER_BINARY_NAME} + ${LLPATHING_LIBRARIES} ${UPDATER_LIBRARIES} ${GOOGLE_PERFTOOLS_LIBRARIES} ${LLAUDIO_LIBRARIES} @@ -1767,7 +1786,7 @@ target_link_libraries(${VIEWER_BINARY_NAME} ${OPENSSL_LIBRARIES} ${CRYPTO_LIBRARIES} ${LLLOGIN_LIBRARIES} - ${LLCONVEXDECOMP_LIBRARY} + ${LLPHYSICS_LIBRARIES} ${TCMALLOC_LIBRARIES} ) diff --git a/indra/newview/app_settings/commands.xml b/indra/newview/app_settings/commands.xml index 1d1d39c786..d3253bc381 100644 --- a/indra/newview/app_settings/commands.xml +++ b/indra/newview/app_settings/commands.xml @@ -155,6 +155,46 @@ is_running_function="Floater.IsOpen" is_running_parameters="people" /> + <command name="pathfinding_basic" + available_in_toybox="false" + icon="Command_PF_Basic_Icon" + label_ref="Command_PF_Basic_Label" + tooltip_ref="Command_PF_Basic_Tooltip" + execute_function="Floater.ToggleOrBringToFront" + execute_parameters="pathfinding_basic" + is_running_function="Floater.IsOpen" + is_running_parameters="pathfinding_basic" + /> + <command name="pathfinding_console" + available_in_toybox="false" + icon="Command_Pathfinding_Icon" + label_ref="Command_Pathfinding_Label" + tooltip_ref="Command_Pathfinding_Tooltip" + execute_function="Floater.ToggleOrBringToFront" + execute_parameters="pathfinding_console" + is_running_function="Floater.IsOpen" + is_running_parameters="pathfinding_console" + /> + <command name="pathfinding_characters" + available_in_toybox="false" + icon="Command_PF_Characters_Icon" + label_ref="Command_PF_Characters_Label" + tooltip_ref="Command_PF_Characters_Tooltip" + execute_function="Floater.ToggleOrBringToFront" + execute_parameters="pathfinding_characters" + is_running_function="Floater.IsOpen" + is_running_parameters="pathfinding_characters" + /> + <command name="pathfinding_linksets" + available_in_toybox="false" + icon="Command_PF_Linksets_Icon" + label_ref="Command_PF_Linksets_Label" + tooltip_ref="Command_PF_Linksets_Tooltip" + execute_function="Floater.ToggleOrBringToFront" + execute_parameters="pathfinding_linksets" + is_running_function="Floater.IsOpen" + is_running_parameters="pathfinding_linksets" + /> <command name="picks" available_in_toybox="true" icon="Command_Picks_Icon" diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 0e26013152..77a76e6bf7 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -13483,5 +13483,28 @@ <key>Value</key> <integer>0</integer> </map> + <key>RetrieveNeighboringRegion</key> + <map> + <key>Comment</key> + <string>Download a neighboring region when visualize a navmesh (default val 99 is for the current region).</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <integer>99</integer> + </map> + <key>EnableVBOForNavMeshVisualization</key> + <map> + <key>Comment</key> + <string>Enable the use of VBOs for navmesh visualization.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> + </map> </llsd> diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index ab9b5ff436..657e464cbb 100755 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -88,6 +88,7 @@ #include "llworld.h" #include "llworldmap.h" #include "stringize.h" +#include "llfloaterpathfindingconsole.h" using namespace LLVOAvatarDefines; @@ -399,6 +400,12 @@ void LLAgent::ageChat() //----------------------------------------------------------------------------- void LLAgent::moveAt(S32 direction, bool reset) { + LLFloaterPathfindingConsole* pWindow = LLFloaterPathfindingConsole::getInstanceHandle().get();
+ if ( pWindow && pWindow->getHeartBeat() ) + { + return; + } + mMoveTimer.reset(); LLFirstUse::notMoving(false); @@ -427,6 +434,11 @@ void LLAgent::moveAt(S32 direction, bool reset) //----------------------------------------------------------------------------- void LLAgent::moveAtNudge(S32 direction) { + LLFloaterPathfindingConsole* pWindow = LLFloaterPathfindingConsole::getInstanceHandle().get();
+ if ( pWindow && pWindow->getHeartBeat() ) + { + return; + } mMoveTimer.reset(); LLFirstUse::notMoving(false); @@ -648,6 +660,12 @@ void LLAgent::setFlying(BOOL fly) // static void LLAgent::toggleFlying() { + LLFloaterPathfindingConsole* pWindow = LLFloaterPathfindingConsole::getInstanceHandle().get();
+ if ( pWindow && pWindow->getHeartBeat() ) + { + return; + } + if ( gAgent.mAutoPilot ) { LLToolPie::instance().stopClickToWalk(); @@ -2706,6 +2724,12 @@ void LLAgent::sendAnimationRequest(const LLUUID &anim_id, EAnimRequest request) void LLAgent::sendWalkRun(bool running) { + LLFloaterPathfindingConsole* pWindow = LLFloaterPathfindingConsole::getInstanceHandle().get();
+ if ( pWindow->getHeartBeat() ) + { + return; + } + LLMessageSystem* msgsys = gMessageSystem; if (msgsys) { diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 1174d108d2..c1217fc402 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -106,6 +106,7 @@ #include "llvfsthread.h" #include "llvolumemgr.h" #include "llxfermanager.h" +#include "LLPhysicsExtensions.h" #include "llnotificationmanager.h" #include "llnotifications.h" @@ -1548,6 +1549,9 @@ bool LLAppViewer::cleanup() // shut down mesh streamer gMeshRepo.shutdown(); + // shut down Havok + LLPhysicsExtensions::quitSystem(); + // Must clean up texture references before viewer window is destroyed. if(LLHUDManager::instanceExists()) { 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/llfloaterpathfindingbasic.cpp b/indra/newview/llfloaterpathfindingbasic.cpp new file mode 100644 index 0000000000..04d830632d --- /dev/null +++ b/indra/newview/llfloaterpathfindingbasic.cpp @@ -0,0 +1,167 @@ +/**
+* @file llfloaterpathfindingbasic.cpp
+* @author William Todd Stinson
+* @brief "Pathfinding basic" floater, allowing for basic freezing and unfreezing of the pathfinding avatar mode.
+*
+* $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 "llfloaterpathfindingbasic.h"
+#include "llsd.h"
+#include "lltextbase.h"
+#include "llbutton.h"
+#include "llpathfindingmanager.h"
+
+#include <boost/bind.hpp>
+
+//---------------------------------------------------------------------------
+// LLFloaterPathfindingBasic
+//---------------------------------------------------------------------------
+
+BOOL LLFloaterPathfindingBasic::postBuild()
+{
+ mStatusText = findChild<LLTextBase>("status_label");
+ llassert(mStatusText != NULL);
+
+ mUnfreezeLabel = findChild<LLTextBase>("unfreeze_label");
+ llassert(mUnfreezeLabel != NULL);
+
+ mUnfreezeButton = findChild<LLButton>("enter_unfrozen_mode");
+ llassert(mUnfreezeButton != NULL);
+ mUnfreezeButton->setCommitCallback(boost::bind(&LLFloaterPathfindingBasic::onUnfreezeClicked, this));
+
+ mFreezeLabel = findChild<LLTextBase>("freeze_label");
+ llassert(mFreezeLabel != NULL);
+
+ mFreezeButton = findChild<LLButton>("enter_frozen_mode");
+ llassert(mFreezeButton != NULL);
+ mFreezeButton->setCommitCallback(boost::bind(&LLFloaterPathfindingBasic::onFreezeClicked, this));
+
+ return LLFloater::postBuild();
+}
+
+void LLFloaterPathfindingBasic::onOpen(const LLSD& pKey)
+{
+ LLFloater::onOpen(pKey);
+
+ if (!mAgentStateSlot.connected())
+ {
+ mAgentStateSlot = LLPathfindingManager::getInstance()->registerAgentStateSignal(boost::bind(&LLFloaterPathfindingBasic::onAgentStateCB, this, _1));
+ }
+ setAgentState(LLPathfindingManager::getInstance()->getAgentState());
+}
+
+void LLFloaterPathfindingBasic::onClose(bool pIsAppQuitting)
+{
+ if (mAgentStateSlot.connected())
+ {
+ mAgentStateSlot.disconnect();
+ }
+
+ LLFloater::onClose(pIsAppQuitting);
+}
+
+LLFloaterPathfindingBasic::LLFloaterPathfindingBasic(const LLSD& pSeed)
+ : LLFloater(pSeed),
+ mStatusText(NULL),
+ mUnfreezeLabel(NULL),
+ mUnfreezeButton(NULL),
+ mFreezeLabel(NULL),
+ mFreezeButton(NULL),
+ mAgentStateSlot()
+{
+}
+
+LLFloaterPathfindingBasic::~LLFloaterPathfindingBasic()
+{
+}
+
+void LLFloaterPathfindingBasic::onUnfreezeClicked()
+{
+ mUnfreezeButton->setEnabled(FALSE);
+ LLPathfindingManager::getInstance()->requestSetAgentState(LLPathfindingManager::kAgentStateUnfrozen);
+}
+
+void LLFloaterPathfindingBasic::onFreezeClicked()
+{
+ mUnfreezeButton->setEnabled(FALSE);
+ LLPathfindingManager::getInstance()->requestSetAgentState(LLPathfindingManager::kAgentStateFrozen);
+}
+
+void LLFloaterPathfindingBasic::onAgentStateCB(LLPathfindingManager::EAgentState pAgentState)
+{
+ setAgentState(pAgentState);
+}
+
+void LLFloaterPathfindingBasic::setAgentState(LLPathfindingManager::EAgentState pAgentState)
+{
+ static const LLColor4 warningColor = LLUIColorTable::instance().getColor("DrYellow");
+ LLStyle::Params styleParams;
+
+ switch (pAgentState)
+ {
+ case LLPathfindingManager::kAgentStateUnknown :
+ mStatusText->setVisible(TRUE);
+ mStatusText->setText((LLStringExplicit)getString("status_querying_state"), styleParams);
+ break;
+ case LLPathfindingManager::kAgentStateNotEnabled :
+ mStatusText->setVisible(TRUE);
+ styleParams.color = warningColor;
+ mStatusText->setText((LLStringExplicit)getString("status_pathfinding_not_enabled"), styleParams);
+ break;
+ case LLPathfindingManager::kAgentStateError :
+ mStatusText->setVisible(TRUE);
+ styleParams.color = warningColor;
+ mStatusText->setText((LLStringExplicit)getString("status_unable_to_change_state"), styleParams);
+ break;
+ default :
+ mStatusText->setVisible(FALSE);
+ break;
+ }
+
+ switch (LLPathfindingManager::getInstance()->getLastKnownNonErrorAgentState())
+ {
+ case LLPathfindingManager::kAgentStateUnknown :
+ case LLPathfindingManager::kAgentStateNotEnabled :
+ mUnfreezeLabel->setEnabled(FALSE);
+ mUnfreezeButton->setEnabled(FALSE);
+ mFreezeLabel->setEnabled(FALSE);
+ mFreezeButton->setEnabled(FALSE);
+ break;
+ case LLPathfindingManager::kAgentStateFrozen :
+ mUnfreezeLabel->setEnabled(TRUE);
+ mUnfreezeButton->setEnabled(TRUE);
+ mFreezeLabel->setEnabled(FALSE);
+ mFreezeButton->setEnabled(FALSE);
+ break;
+ case LLPathfindingManager::kAgentStateUnfrozen :
+ mUnfreezeLabel->setEnabled(FALSE);
+ mUnfreezeButton->setEnabled(FALSE);
+ mFreezeLabel->setEnabled(TRUE);
+ mFreezeButton->setEnabled(TRUE);
+ break;
+ default :
+ llassert(0);
+ break;
+ }
+}
diff --git a/indra/newview/llfloaterpathfindingbasic.h b/indra/newview/llfloaterpathfindingbasic.h new file mode 100644 index 0000000000..286985c022 --- /dev/null +++ b/indra/newview/llfloaterpathfindingbasic.h @@ -0,0 +1,71 @@ +/** + * @file llfloaterpathfindingbasic.h + * @author William Todd Stinson + * @brief "Pathfinding basic" floater, allowing for basic freezing and unfreezing of the pathfinding avatar mode. + * + * $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$ + */ + +#ifndef LL_LLFLOATERPATHFINDINGBASIC_H +#define LL_LLFLOATERPATHFINDINGBASIC_H + +#include "llfloater.h" +#include "llpathfindingmanager.h" + +class LLSD; +class LLTextBase; +class LLButton; + +class LLFloaterPathfindingBasic +: public LLFloater +{ + friend class LLFloaterReg; + +public: + virtual BOOL postBuild(); + virtual void onOpen(const LLSD& pKey); + virtual void onClose(bool pIsAppQuitting); + +protected: + +private: + // Does its own instance management, so clients not allowed + // to allocate or destroy. + LLFloaterPathfindingBasic(const LLSD& pSeed); + virtual ~LLFloaterPathfindingBasic(); + + void onUnfreezeClicked(); + void onFreezeClicked(); + + void onAgentStateCB(LLPathfindingManager::EAgentState pAgentState); + + void setAgentState(LLPathfindingManager::EAgentState pAgentState); + + LLTextBase *mStatusText; + LLTextBase *mUnfreezeLabel; + LLButton *mUnfreezeButton; + LLTextBase *mFreezeLabel; + LLButton *mFreezeButton; + LLPathfindingManager::agent_state_slot_t mAgentStateSlot; +}; + +#endif // LL_LLFLOATERPATHFINDINGBASIC_H diff --git a/indra/newview/llfloaterpathfindingcharacters.cpp b/indra/newview/llfloaterpathfindingcharacters.cpp new file mode 100644 index 0000000000..e2e1921cc6 --- /dev/null +++ b/indra/newview/llfloaterpathfindingcharacters.cpp @@ -0,0 +1,611 @@ +/**
+ * @file llfloaterpathfindingcharacters.cpp
+ * @author William Todd Stinson
+ * @brief "Pathfinding linksets" floater, allowing manipulation of the Havok AI pathfinding settings.
+ *
+ * $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 "llfloater.h"
+#include "llfloaterpathfindingcharacters.h"
+#include "llpathfindingcharacter.h"
+#include "llsd.h"
+#include "llagent.h"
+#include "llhandle.h"
+#include "llfloaterreg.h"
+#include "lltextbase.h"
+#include "llscrolllistitem.h"
+#include "llscrolllistctrl.h"
+#include "llcheckboxctrl.h"
+#include "llradiogroup.h"
+#include "llbutton.h"
+#include "llresmgr.h"
+#include "llviewerregion.h"
+#include "llhttpclient.h"
+#include "lluuid.h"
+#include "llviewerobject.h"
+#include "llviewerobjectlist.h"
+#include "llviewermenu.h"
+#include "llselectmgr.h"
+
+//---------------------------------------------------------------------------
+// CharactersGetResponder
+//---------------------------------------------------------------------------
+
+class CharactersGetResponder : public LLHTTPClient::Responder
+{
+public:
+ CharactersGetResponder(const std::string& pCharactersDataGetURL,
+ const LLHandle<LLFloaterPathfindingCharacters> &pCharactersFloaterHandle);
+ virtual ~CharactersGetResponder();
+
+ virtual void result(const LLSD& pContent);
+ virtual void error(U32 pStatus, const std::string& pReason);
+
+private:
+ CharactersGetResponder(const CharactersGetResponder& pOther);
+
+ std::string mCharactersDataGetURL;
+ LLHandle<LLFloaterPathfindingCharacters> mCharactersFloaterHandle;
+};
+
+//---------------------------------------------------------------------------
+// LLFloaterPathfindingCharacters
+//---------------------------------------------------------------------------
+
+BOOL LLFloaterPathfindingCharacters::postBuild()
+{
+ childSetAction("refresh_characters_list", boost::bind(&LLFloaterPathfindingCharacters::onRefreshCharactersClicked, this));
+ childSetAction("select_all_characters", boost::bind(&LLFloaterPathfindingCharacters::onSelectAllCharactersClicked, this));
+ childSetAction("select_none_characters", boost::bind(&LLFloaterPathfindingCharacters::onSelectNoneCharactersClicked, this));
+
+ mCharactersScrollList = findChild<LLScrollListCtrl>("pathfinding_characters");
+ llassert(mCharactersScrollList != NULL);
+ mCharactersScrollList->setCommitCallback(boost::bind(&LLFloaterPathfindingCharacters::onCharactersSelectionChange, this));
+ mCharactersScrollList->sortByColumnIndex(0, true);
+
+ mCharactersStatus = findChild<LLTextBase>("characters_status");
+ llassert(mCharactersStatus != NULL);
+
+ mLabelActions = findChild<LLTextBase>("actions_label");
+ llassert(mLabelActions != NULL);
+
+ mShowBeaconCheckBox = findChild<LLCheckBoxCtrl>("show_beacon");
+ llassert(mShowBeaconCheckBox != NULL);
+
+ mTakeBtn = findChild<LLButton>("take_characters");
+ llassert(mTakeBtn != NULL)
+ mTakeBtn->setCommitCallback(boost::bind(&LLFloaterPathfindingCharacters::onTakeCharactersClicked, this));
+
+ mTakeCopyBtn = findChild<LLButton>("take_copy_characters");
+ llassert(mTakeCopyBtn != NULL)
+ mTakeCopyBtn->setCommitCallback(boost::bind(&LLFloaterPathfindingCharacters::onTakeCopyCharactersClicked, this));
+
+ mReturnBtn = findChild<LLButton>("return_characters");
+ llassert(mReturnBtn != NULL)
+ mReturnBtn->setCommitCallback(boost::bind(&LLFloaterPathfindingCharacters::onReturnCharactersClicked, this));
+
+ mDeleteBtn = findChild<LLButton>("delete_characters");
+ llassert(mDeleteBtn != NULL)
+ mDeleteBtn->setCommitCallback(boost::bind(&LLFloaterPathfindingCharacters::onDeleteCharactersClicked, this));
+
+ mTeleportBtn = findChild<LLButton>("teleport_to_character");
+ llassert(mTeleportBtn != NULL)
+ mTeleportBtn->setCommitCallback(boost::bind(&LLFloaterPathfindingCharacters::onTeleportCharacterToMeClicked, this));
+
+ setEnableActionFields(false);
+ setMessagingState(kMessagingInitial);
+
+ return LLFloater::postBuild();
+}
+
+void LLFloaterPathfindingCharacters::onOpen(const LLSD& pKey)
+{
+ sendCharactersDataGetRequest();
+ selectNoneCharacters();
+ mCharactersScrollList->setCommitOnSelectionChange(true);
+}
+
+void LLFloaterPathfindingCharacters::onClose(bool app_quitting)
+{
+ mCharactersScrollList->setCommitOnSelectionChange(false);
+ selectNoneCharacters();
+ if (mCharacterSelection.notNull())
+ {
+ std::vector<LLViewerObject *> selectedObjects;
+
+ LLObjectSelection *charactersSelected = mCharacterSelection.get();
+ for (LLObjectSelection::valid_iterator characterIter = charactersSelected->valid_begin();
+ characterIter != charactersSelected->valid_end(); ++characterIter)
+ {
+ LLSelectNode *characterNode = *characterIter;
+ selectedObjects.push_back(characterNode->getObject());
+ }
+
+ for (std::vector<LLViewerObject *>::const_iterator selectedObjectIter = selectedObjects.begin();
+ selectedObjectIter != selectedObjects.end(); ++selectedObjectIter)
+ {
+ LLViewerObject *selectedObject = *selectedObjectIter;
+ LLSelectMgr::getInstance()->deselectObjectAndFamily(selectedObject);
+ }
+
+ mCharacterSelection.clear();
+ }
+}
+
+void LLFloaterPathfindingCharacters::draw()
+{
+ if (mShowBeaconCheckBox->get())
+ {
+ std::vector<LLScrollListItem*> selectedItems = mCharactersScrollList->getAllSelected();
+ if (!selectedItems.empty())
+ {
+ int numSelectedItems = selectedItems.size();
+
+ std::vector<LLViewerObject *> viewerObjects;
+ viewerObjects.reserve(numSelectedItems);
+
+ for (std::vector<LLScrollListItem*>::const_iterator selectedItemIter = selectedItems.begin();
+ selectedItemIter != selectedItems.end(); ++selectedItemIter)
+ {
+ const LLScrollListItem *selectedItem = *selectedItemIter;
+
+ const std::string &objectName = selectedItem->getColumn(0)->getValue().asString();
+
+ LLViewerObject *viewerObject = gObjectList.findObject(selectedItem->getUUID());
+ if (viewerObject != NULL)
+ {
+ gObjectList.addDebugBeacon(viewerObject->getPositionAgent(), objectName, LLColor4(0.f, 0.f, 1.f, 0.8f), LLColor4(1.f, 1.f, 1.f, 1.f), 6);
+ }
+ }
+ }
+ }
+
+ LLFloater::draw();
+}
+
+void LLFloaterPathfindingCharacters::openCharactersViewer()
+{
+ LLFloaterReg::toggleInstanceOrBringToFront("pathfinding_characters");
+}
+
+LLFloaterPathfindingCharacters::EMessagingState LLFloaterPathfindingCharacters::getMessagingState() const
+{
+ return mMessagingState;
+}
+
+BOOL LLFloaterPathfindingCharacters::isMessagingInProgress() const
+{
+ BOOL retVal;
+ switch (getMessagingState())
+ {
+ case kMessagingFetchStarting :
+ case kMessagingFetchRequestSent :
+ case kMessagingFetchRequestSent_MultiRequested :
+ case kMessagingFetchReceived :
+ retVal = true;
+ break;
+ default :
+ retVal = false;
+ break;
+ }
+
+ return retVal;
+}
+
+LLFloaterPathfindingCharacters::LLFloaterPathfindingCharacters(const LLSD& pSeed)
+ : LLFloater(pSeed),
+ mSelfHandle(),
+ mPathfindingCharacters(),
+ mMessagingState(kMessagingInitial),
+ mCharactersScrollList(NULL),
+ mCharactersStatus(NULL),
+ mLabelActions(NULL),
+ mShowBeaconCheckBox(NULL),
+ mTakeBtn(NULL),
+ mTakeCopyBtn(NULL),
+ mReturnBtn(NULL),
+ mDeleteBtn(NULL),
+ mTeleportBtn(NULL),
+ mCharacterSelection()
+{
+ mSelfHandle.bind(this);
+}
+
+LLFloaterPathfindingCharacters::~LLFloaterPathfindingCharacters()
+{
+ mPathfindingCharacters.clear();
+ mCharacterSelection.clear();
+}
+
+void LLFloaterPathfindingCharacters::sendCharactersDataGetRequest()
+{
+ if (isMessagingInProgress())
+ {
+ if (getMessagingState() == kMessagingFetchRequestSent)
+ {
+ setMessagingState(kMessagingFetchRequestSent_MultiRequested);
+ }
+ }
+ else
+ {
+ setMessagingState(kMessagingFetchStarting);
+ mPathfindingCharacters.clear();
+ updateCharactersList();
+
+ std::string charactersDataURL = getCapabilityURL();
+ if (charactersDataURL.empty())
+ {
+ setMessagingState(kMessagingServiceNotAvailable);
+ llwarns << "cannot query pathfinding characters from current region '" << getRegionName() << "'" << llendl;
+ }
+ else
+ {
+ setMessagingState(kMessagingFetchRequestSent);
+ LLHTTPClient::get(charactersDataURL, new CharactersGetResponder(charactersDataURL, mSelfHandle));
+ }
+ }
+}
+
+void LLFloaterPathfindingCharacters::handleCharactersDataGetReply(const LLSD& pCharactersData)
+{
+ setMessagingState(kMessagingFetchReceived);
+ mPathfindingCharacters.clear();
+ parseCharactersData(pCharactersData);
+ updateCharactersList();
+ setMessagingState(kMessagingComplete);
+}
+
+void LLFloaterPathfindingCharacters::handleCharactersDataGetError(const std::string& pURL, const std::string& pErrorReason)
+{
+ setMessagingState(kMessagingFetchError);
+ mPathfindingCharacters.clear();
+ updateCharactersList();
+ llwarns << "Error fetching pathfinding characters from URL '" << pURL << "' because " << pErrorReason << llendl;
+}
+
+std::string LLFloaterPathfindingCharacters::getRegionName() const
+{
+ std::string regionName("");
+
+ LLViewerRegion* region = gAgent.getRegion();
+ if (region != NULL)
+ {
+ regionName = region->getName();
+ }
+
+ return regionName;
+}
+
+std::string LLFloaterPathfindingCharacters::getCapabilityURL() const
+{
+ std::string charactersDataURL("");
+
+ LLViewerRegion* region = gAgent.getRegion();
+ if (region != NULL)
+ {
+ charactersDataURL = region->getCapability("CharacterProperties");
+ }
+
+ return charactersDataURL;
+}
+
+void LLFloaterPathfindingCharacters::parseCharactersData(const LLSD &pCharactersData)
+{
+ for (LLSD::map_const_iterator characterItemIter = pCharactersData.beginMap();
+ characterItemIter != pCharactersData.endMap(); ++characterItemIter)
+ {
+ const std::string &uuid(characterItemIter->first);
+ const LLSD &characterData(characterItemIter->second);
+ LLPathfindingCharacter character(uuid, characterData);
+
+ mPathfindingCharacters.insert(std::pair<std::string, LLPathfindingCharacter>(uuid, character));
+ }
+}
+
+void LLFloaterPathfindingCharacters::setMessagingState(EMessagingState pMessagingState)
+{
+ mMessagingState = pMessagingState;
+ updateCharactersList();
+ updateActionFields();
+}
+
+void LLFloaterPathfindingCharacters::onCharactersSelectionChange()
+{
+ mCharacterSelection.clear();
+ LLSelectMgr::getInstance()->deselectAll();
+
+ std::vector<LLScrollListItem*> selectedItems = mCharactersScrollList->getAllSelected();
+ if (!selectedItems.empty())
+ {
+ int numSelectedItems = selectedItems.size();
+
+ std::vector<LLViewerObject *> viewerObjects;
+ viewerObjects.reserve(numSelectedItems);
+
+ for (std::vector<LLScrollListItem*>::const_iterator selectedItemIter = selectedItems.begin();
+ selectedItemIter != selectedItems.end(); ++selectedItemIter)
+ {
+ const LLScrollListItem *selectedItem = *selectedItemIter;
+
+ LLViewerObject *viewerObject = gObjectList.findObject(selectedItem->getUUID());
+ if (viewerObject != NULL)
+ {
+ viewerObjects.push_back(viewerObject);
+ }
+ }
+
+ if (!viewerObjects.empty())
+ {
+ mCharacterSelection = LLSelectMgr::getInstance()->selectObjectAndFamily(viewerObjects);
+ }
+ }
+
+ updateCharactersStatusMessage();
+ updateActionFields();
+}
+
+void LLFloaterPathfindingCharacters::onRefreshCharactersClicked()
+{
+ sendCharactersDataGetRequest();
+}
+
+void LLFloaterPathfindingCharacters::onSelectAllCharactersClicked()
+{
+ selectAllCharacters();
+}
+
+void LLFloaterPathfindingCharacters::onSelectNoneCharactersClicked()
+{
+ selectNoneCharacters();
+}
+
+void LLFloaterPathfindingCharacters::onTakeCharactersClicked()
+{
+ handle_take();
+}
+
+void LLFloaterPathfindingCharacters::onTakeCopyCharactersClicked()
+{
+ handle_take_copy();
+}
+
+void LLFloaterPathfindingCharacters::onReturnCharactersClicked()
+{
+ handle_object_return();
+}
+
+void LLFloaterPathfindingCharacters::onDeleteCharactersClicked()
+{
+ handle_object_delete();
+}
+
+void LLFloaterPathfindingCharacters::onTeleportCharacterToMeClicked()
+{
+ std::vector<LLScrollListItem*> selectedItems = mCharactersScrollList->getAllSelected();
+ llassert(selectedItems.size() == 1);
+ if (selectedItems.size() == 1)
+ {
+ std::vector<LLScrollListItem*>::const_reference selectedItemRef = selectedItems.front();
+ const LLScrollListItem *selectedItem = selectedItemRef;
+ PathfindingCharacterMap::const_iterator characterIter = mPathfindingCharacters.find(selectedItem->getUUID().asString());
+ const LLPathfindingCharacter &character = characterIter->second;
+ LLVector3 characterLocation = character.getLocation();
+
+ LLViewerRegion* region = gAgent.getRegion();
+ if (region != NULL)
+ {
+ gAgent.teleportRequest(region->getHandle(), characterLocation, true);
+ }
+ }
+}
+
+void LLFloaterPathfindingCharacters::updateCharactersList()
+{
+ std::vector<LLScrollListItem*> selectedItems = mCharactersScrollList->getAllSelected();
+ int numSelectedItems = selectedItems.size();
+ uuid_vec_t selectedUUIDs;
+ if (numSelectedItems > 0)
+ {
+ selectedUUIDs.reserve(selectedItems.size());
+ for (std::vector<LLScrollListItem*>::const_iterator itemIter = selectedItems.begin();
+ itemIter != selectedItems.end(); ++itemIter)
+ {
+ const LLScrollListItem *listItem = *itemIter;
+ selectedUUIDs.push_back(listItem->getUUID());
+ }
+ }
+
+ mCharactersScrollList->deleteAllItems();
+ updateCharactersStatusMessage();
+
+ LLLocale locale(LLStringUtil::getLocale());
+ for (PathfindingCharacterMap::const_iterator characterIter = mPathfindingCharacters.begin();
+ characterIter != mPathfindingCharacters.end(); ++characterIter)
+ {
+ const LLPathfindingCharacter& character(characterIter->second);
+
+ LLSD columns;
+
+ columns[0]["column"] = "name";
+ columns[0]["value"] = character.getName();
+ columns[0]["font"] = "SANSSERIF";
+
+ columns[1]["column"] = "description";
+ columns[1]["value"] = character.getDescription();
+ columns[1]["font"] = "SANSSERIF";
+
+ columns[2]["column"] = "owner";
+ columns[2]["value"] = character.getOwnerName();
+ columns[2]["font"] = "SANSSERIF";
+
+ S32 cpuTime = llround(character.getCPUTime());
+ std::string cpuTimeString;
+ LLResMgr::getInstance()->getIntegerString(cpuTimeString, cpuTime);
+
+ LLStringUtil::format_map_t string_args;
+ string_args["[CPU_TIME]"] = cpuTimeString;
+
+ columns[3]["column"] = "cpu_time";
+ columns[3]["value"] = getString("character_cpu_time", string_args);
+ columns[3]["font"] = "SANSSERIF";
+
+ columns[4]["column"] = "altitude";
+ columns[4]["value"] = llformat("%1.0f m", character.getLocation()[2]);
+ columns[4]["font"] = "SANSSERIF";
+
+ LLSD element;
+ element["id"] = character.getUUID().asString();
+ element["column"] = columns;
+
+ mCharactersScrollList->addElement(element);
+ }
+
+ mCharactersScrollList->selectMultiple(selectedUUIDs);
+ updateCharactersStatusMessage();
+ updateActionFields();
+}
+
+void LLFloaterPathfindingCharacters::selectAllCharacters()
+{
+ mCharactersScrollList->selectAll();
+}
+
+void LLFloaterPathfindingCharacters::selectNoneCharacters()
+{
+ mCharactersScrollList->deselectAllItems();
+}
+
+void LLFloaterPathfindingCharacters::updateCharactersStatusMessage()
+{
+ static const LLColor4 warningColor = LLUIColorTable::instance().getColor("DrYellow");
+
+ std::string statusText("");
+ LLStyle::Params styleParams;
+
+ switch (getMessagingState())
+ {
+ case kMessagingInitial:
+ statusText = getString("characters_messaging_initial");
+ break;
+ case kMessagingFetchStarting :
+ statusText = getString("characters_messaging_fetch_starting");
+ break;
+ case kMessagingFetchRequestSent :
+ statusText = getString("characters_messaging_fetch_inprogress");
+ break;
+ case kMessagingFetchRequestSent_MultiRequested :
+ statusText = getString("characters_messaging_fetch_inprogress_multi_request");
+ break;
+ case kMessagingFetchReceived :
+ statusText = getString("characters_messaging_fetch_received");
+ break;
+ case kMessagingFetchError :
+ statusText = getString("characters_messaging_fetch_error");
+ styleParams.color = warningColor;
+ break;
+ case kMessagingComplete :
+ if (mCharactersScrollList->isEmpty())
+ {
+ statusText = getString("characters_messaging_complete_none_found");
+ }
+ else
+ {
+ S32 numItems = mCharactersScrollList->getItemCount();
+ S32 numSelectedItems = mCharactersScrollList->getNumSelected();
+
+ LLLocale locale(LLStringUtil::getLocale());
+ std::string numItemsString;
+ LLResMgr::getInstance()->getIntegerString(numItemsString, numItems);
+
+ std::string numSelectedItemsString;
+ LLResMgr::getInstance()->getIntegerString(numSelectedItemsString, numSelectedItems);
+
+ LLStringUtil::format_map_t string_args;
+ string_args["[NUM_SELECTED]"] = numSelectedItemsString;
+ string_args["[NUM_TOTAL]"] = numItemsString;
+ statusText = getString("characters_messaging_complete_available", string_args);
+ }
+ break;
+ case kMessagingServiceNotAvailable:
+ statusText = getString("characters_messaging_service_not_available");
+ styleParams.color = warningColor;
+ break;
+ default:
+ statusText = getString("characters_messaging_initial");
+ llassert(0);
+ break;
+ }
+
+ mCharactersStatus->setText((LLStringExplicit)statusText, styleParams);
+}
+
+void LLFloaterPathfindingCharacters::updateActionFields()
+{
+ std::vector<LLScrollListItem*> selectedItems = mCharactersScrollList->getAllSelected();
+ setEnableActionFields(!selectedItems.empty());
+}
+
+void LLFloaterPathfindingCharacters::setEnableActionFields(BOOL pEnabled)
+{
+ mLabelActions->setEnabled(pEnabled);
+ mShowBeaconCheckBox->setEnabled(pEnabled);
+ mTakeBtn->setEnabled(pEnabled && tools_visible_take_object());
+ mTakeCopyBtn->setEnabled(pEnabled && enable_object_take_copy());
+ mReturnBtn->setEnabled(pEnabled && enable_object_return());
+ mDeleteBtn->setEnabled(pEnabled && enable_object_delete());
+ mTeleportBtn->setEnabled(pEnabled && (mCharactersScrollList->getNumSelected() == 1));
+}
+
+//---------------------------------------------------------------------------
+// CharactersGetResponder
+//---------------------------------------------------------------------------
+
+CharactersGetResponder::CharactersGetResponder(const std::string& pCharactersDataGetURL,
+ const LLHandle<LLFloaterPathfindingCharacters> &pCharactersFloaterHandle)
+ : mCharactersDataGetURL(pCharactersDataGetURL),
+ mCharactersFloaterHandle(pCharactersFloaterHandle)
+{
+}
+
+CharactersGetResponder::~CharactersGetResponder()
+{
+}
+
+void CharactersGetResponder::result(const LLSD& pContent)
+{
+ LLFloaterPathfindingCharacters *charactersFloater = mCharactersFloaterHandle.get();
+ if (charactersFloater != NULL)
+ {
+ charactersFloater->handleCharactersDataGetReply(pContent);
+ }
+}
+
+void CharactersGetResponder::error(U32 status, const std::string& reason)
+{
+ LLFloaterPathfindingCharacters *charactersFloater = mCharactersFloaterHandle.get();
+ if (charactersFloater != NULL)
+ {
+ charactersFloater->handleCharactersDataGetError(mCharactersDataGetURL, reason);
+ }
+}
diff --git a/indra/newview/llfloaterpathfindingcharacters.h b/indra/newview/llfloaterpathfindingcharacters.h new file mode 100644 index 0000000000..ecc605c300 --- /dev/null +++ b/indra/newview/llfloaterpathfindingcharacters.h @@ -0,0 +1,130 @@ +/**
+ * @file llfloaterpathfindingcharacters.h
+ * @author William Todd Stinson
+ * @brief "Pathfinding linksets" floater, allowing manipulation of the Havok AI pathfinding settings.
+ *
+ * $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$
+ */
+
+#ifndef LL_LLFLOATERPATHFINDINGCHARACTERS_H
+#define LL_LLFLOATERPATHFINDINGCHARACTERS_H
+
+#include <string>
+#include <map>
+
+#include "llhandle.h"
+#include "llfloater.h"
+#include "llpathfindingcharacter.h"
+#include "llselectmgr.h"
+
+class LLSD;
+class LLTextBase;
+class LLScrollListCtrl;
+class LLCheckBoxCtrl;
+class LLRadioGroup;
+class LLButton;
+
+class LLFloaterPathfindingCharacters
+: public LLFloater
+{
+ friend class LLFloaterReg;
+ friend class CharactersGetResponder;
+
+public:
+ typedef enum
+ {
+ kMessagingInitial,
+ kMessagingFetchStarting,
+ kMessagingFetchRequestSent,
+ kMessagingFetchRequestSent_MultiRequested,
+ kMessagingFetchReceived,
+ kMessagingFetchError,
+ kMessagingComplete,
+ kMessagingServiceNotAvailable
+ } EMessagingState;
+
+ virtual BOOL postBuild();
+ virtual void onOpen(const LLSD& pKey);
+ virtual void onClose(bool app_quitting);
+ virtual void draw();
+
+ static void openCharactersViewer();
+
+ EMessagingState getMessagingState() const;
+ BOOL isMessagingInProgress() const;
+
+protected:
+
+private:
+ typedef std::map<std::string, LLPathfindingCharacter> PathfindingCharacterMap;
+
+ LLRootHandle<LLFloaterPathfindingCharacters> mSelfHandle;
+ PathfindingCharacterMap mPathfindingCharacters;
+ EMessagingState mMessagingState;
+ LLScrollListCtrl *mCharactersScrollList;
+ LLTextBase *mCharactersStatus;
+ LLTextBase *mLabelActions;
+ LLCheckBoxCtrl *mShowBeaconCheckBox;
+ LLButton *mTakeBtn;
+ LLButton *mTakeCopyBtn;
+ LLButton *mReturnBtn;
+ LLButton *mDeleteBtn;
+ LLButton *mTeleportBtn;
+ LLObjectSelectionHandle mCharacterSelection;
+
+ // Does its own instance management, so clients not allowed
+ // to allocate or destroy.
+ LLFloaterPathfindingCharacters(const LLSD& pSeed);
+ virtual ~LLFloaterPathfindingCharacters();
+
+ void sendCharactersDataGetRequest();
+ void handleCharactersDataGetReply(const LLSD& pCharactersData);
+ void handleCharactersDataGetError(const std::string& pURL, const std::string& pErrorReason);
+
+ std::string getRegionName() const;
+ std::string getCapabilityURL() const;
+
+ void parseCharactersData(const LLSD &pCharactersData);
+
+ void setMessagingState(EMessagingState pMessagingState);
+
+ void onCharactersSelectionChange();
+ void onRefreshCharactersClicked();
+ void onSelectAllCharactersClicked();
+ void onSelectNoneCharactersClicked();
+ void onTakeCharactersClicked();
+ void onTakeCopyCharactersClicked();
+ void onReturnCharactersClicked();
+ void onDeleteCharactersClicked();
+ void onTeleportCharacterToMeClicked();
+
+ void updateCharactersList();
+ void selectAllCharacters();
+ void selectNoneCharacters();
+
+ void updateCharactersStatusMessage();
+
+ void updateActionFields();
+ void setEnableActionFields(BOOL pEnabled);
+};
+
+#endif // LL_LLFLOATERPATHFINDINGCHARACTERS_H
diff --git a/indra/newview/llfloaterpathfindingconsole.cpp b/indra/newview/llfloaterpathfindingconsole.cpp new file mode 100644 index 0000000000..2bf46175ee --- /dev/null +++ b/indra/newview/llfloaterpathfindingconsole.cpp @@ -0,0 +1,838 @@ +/**
+* @file llfloaterpathfindingconsole.cpp
+* @author William Todd Stinson
+* @brief "Pathfinding console" floater, allowing manipulation of the Havok AI pathfinding settings.
+*
+* $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 "llfloaterpathfindingconsole.h"
+#include "llfloaterpathfindinglinksets.h"
+#include "llfloaterpathfindingcharacters.h"
+
+#include "llsd.h"
+#include "llhandle.h"
+#include "llagent.h"
+#include "llbutton.h"
+#include "llradiogroup.h"
+#include "llsliderctrl.h"
+#include "lllineeditor.h"
+#include "lltextbase.h"
+#include "lltabcontainer.h"
+#include "llcombobox.h"
+#include "llnavmeshstation.h"
+#include "llfloaterreg.h"
+#include "llviewerregion.h"
+#include "llviewerwindow.h"
+#include "llviewercamera.h"
+#include "llviewercontrol.h"
+#include "llpathfindingmanager.h"
+
+#include "LLPathingLib.h"
+
+#define XUI_RENDER_HEATMAP_NONE 0
+#define XUI_RENDER_HEATMAP_A 1
+#define XUI_RENDER_HEATMAP_B 2
+#define XUI_RENDER_HEATMAP_C 3
+#define XUI_RENDER_HEATMAP_D 4
+
+#define XUI_CHARACTER_TYPE_A 1
+#define XUI_CHARACTER_TYPE_B 2
+#define XUI_CHARACTER_TYPE_C 3
+#define XUI_CHARACTER_TYPE_D 4
+
+#define XUI_TEST_TAB_INDEX 1
+
+const int CURRENT_REGION = 99;
+const int MAX_OBSERVERS = 10;
+
+LLHandle<LLFloaterPathfindingConsole> LLFloaterPathfindingConsole::sInstanceHandle;
+
+//---------------------------------------------------------------------------
+// LLFloaterPathfindingConsole
+//---------------------------------------------------------------------------
+
+BOOL LLFloaterPathfindingConsole::postBuild()
+{
+ mShowNavMeshCheckBox = findChild<LLCheckBoxCtrl>("show_navmesh");
+ llassert(mShowNavMeshCheckBox != NULL);
+
+ mShowNavMeshWalkabilityComboBox = findChild<LLComboBox>("show_heatmap_mode");
+ llassert(mShowNavMeshWalkabilityComboBox != NULL);
+ mShowNavMeshWalkabilityComboBox->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onShowWalkabilitySet, this));
+
+ mShowWalkablesCheckBox = findChild<LLCheckBoxCtrl>("show_walkables");
+ llassert(mShowWalkablesCheckBox != NULL);
+
+ mShowStaticObstaclesCheckBox = findChild<LLCheckBoxCtrl>("show_static_obstacles");
+ llassert(mShowStaticObstaclesCheckBox != NULL);
+
+ mShowMaterialVolumesCheckBox = findChild<LLCheckBoxCtrl>("show_material_volumes");
+ llassert(mShowMaterialVolumesCheckBox != NULL);
+
+ mShowExclusionVolumesCheckBox = findChild<LLCheckBoxCtrl>("show_exclusion_volumes");
+ llassert(mShowExclusionVolumesCheckBox != NULL);
+
+ mShowWorldCheckBox = findChild<LLCheckBoxCtrl>("show_world");
+ llassert(mShowWorldCheckBox != NULL);
+ mShowWorldCheckBox->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onShowWorldToggle, this));
+
+ mViewCharactersButton = findChild<LLButton>("view_characters_floater");
+ llassert(mViewCharactersButton != NULL);
+ mViewCharactersButton->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onViewCharactersClicked, this));
+
+ mEditTestTabContainer = findChild<LLTabContainer>("edit_test_tab_container");
+ llassert(mEditTestTabContainer != NULL);
+
+ mUnfreezeLabel = findChild<LLTextBase>("unfreeze_label");
+ llassert(mUnfreezeLabel != NULL);
+
+ mUnfreezeButton = findChild<LLButton>("enter_unfrozen_mode");
+ llassert(mUnfreezeButton != NULL);
+ mUnfreezeButton->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onUnfreezeClicked, this));
+
+ mLinksetsLabel = findChild<LLTextBase>("edit_linksets_label");
+ llassert(mLinksetsLabel != NULL);
+
+ mLinksetsButton = findChild<LLButton>("view_and_edit_linksets");
+ llassert(mLinksetsButton != NULL);
+ mLinksetsButton->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onViewEditLinksetClicked, this));
+
+ mFreezeLabel = findChild<LLTextBase>("freeze_label");
+ llassert(mFreezeLabel != NULL);
+
+ mFreezeButton = findChild<LLButton>("enter_frozen_mode");
+ llassert(mFreezeButton != NULL);
+ mFreezeButton->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onFreezeClicked, this));
+
+ mPathfindingStatus = findChild<LLTextBase>("pathfinding_status");
+ llassert(mPathfindingStatus != NULL);
+
+ mCharacterWidthSlider = findChild<LLSliderCtrl>("character_width");
+ llassert(mCharacterWidthSlider != NULL);
+ mCharacterWidthSlider->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onCharacterWidthSet, this));
+
+ mCharacterTypeRadioGroup = findChild<LLRadioGroup>("character_type");
+ llassert(mCharacterTypeRadioGroup != NULL);
+ mCharacterTypeRadioGroup->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onCharacterTypeSwitch, this));
+
+ mPathTestingStatus = findChild<LLTextBase>("path_test_status");
+ llassert(mPathTestingStatus != NULL);
+
+ mClearPathButton = findChild<LLButton>("clear_path");
+ llassert(mClearPathButton != NULL);
+ mClearPathButton->setCommitCallback(boost::bind(&LLFloaterPathfindingConsole::onClearPathClicked, this));
+
+ return LLFloater::postBuild();
+}
+
+void LLFloaterPathfindingConsole::onOpen(const LLSD& pKey)
+{
+ LLFloater::onOpen(pKey);
+ setHeartBeat( true );
+ //make sure we have a pathing system
+ if ( !LLPathingLib::getInstance() )
+ {
+ LLPathingLib::initSystem();
+ }
+ if ( LLPathingLib::getInstance() == NULL )
+ {
+ std::string str = getString("navmesh_library_not_implemented");
+ LLStyle::Params styleParams;
+ styleParams.color = LLUIColorTable::instance().getColor("DrYellow");
+ mPathfindingStatus->setText((LLStringExplicit)str, styleParams);
+ llwarns <<"Errror: cannout find pathing library implementation."<<llendl;
+ }
+ else
+ {
+ LLPathingLib::getInstance()->cleanupResidual();
+
+ mCurrentMDO = 0;
+ mNavMeshCnt = 0;
+
+ //make sure the region is essentially enabled for navmesh support
+ std::string capability = "RetrieveNavMeshSrc";
+
+ LLViewerRegion* pCurrentRegion = gAgent.getRegion();
+ std::vector<LLViewerRegion*> regions;
+ regions.push_back( pCurrentRegion );
+ std::vector<int> shiftDirections;
+ shiftDirections.push_back( CURRENT_REGION );
+
+ mNeighboringRegion = gSavedSettings.getU32("RetrieveNeighboringRegion");
+ if ( mNeighboringRegion != CURRENT_REGION )
+ {
+ //User wants to pull in a neighboring region
+ std::vector<S32> availableRegions;
+ pCurrentRegion->getNeighboringRegionsStatus( availableRegions );
+ //Is the desired region in the available list
+ std::vector<S32>::iterator foundElem = std::find(availableRegions.begin(),availableRegions.end(),mNeighboringRegion);
+ if ( foundElem != availableRegions.end() )
+ {
+ LLViewerRegion* pCurrentRegion = gAgent.getRegion();
+ std::vector<LLViewerRegion*> regionPtrs;
+ pCurrentRegion->getNeighboringRegions( regionPtrs );
+ regions.push_back( regionPtrs[mNeighboringRegion] );
+ shiftDirections.push_back( mNeighboringRegion );
+ }
+ }
+
+
+ //If the navmesh shift ops and the total region counts do not match - use the current region, only.
+ if ( shiftDirections.size() != regions.size() )
+ {
+ shiftDirections.clear();regions.clear();
+ regions.push_back( pCurrentRegion );
+ shiftDirections.push_back( CURRENT_REGION );
+ }
+
+ int regionCnt = regions.size();
+ mNavMeshCnt = regionCnt;
+
+ for ( int i=0; i<regionCnt; ++i )
+ {
+ std::string url = regions[i]->getCapability( capability );
+
+ if ( !url.empty() )
+ {
+ std::string str = getString("navmesh_fetch_inprogress");
+ mPathfindingStatus->setText((LLStringExplicit)str);
+ LLNavMeshStation::getInstance()->setNavMeshDownloadURL( url );
+ int dir = shiftDirections[i];
+ LLNavMeshStation::getInstance()->downloadNavMeshSrc( mNavMeshDownloadObserver[mCurrentMDO].getObserverHandle(), dir );
+ ++mCurrentMDO;
+ }
+ else
+ {
+ --mNavMeshCnt;
+ std::string str = getString("navmesh_region_not_enabled");
+ LLStyle::Params styleParams;
+ styleParams.color = LLUIColorTable::instance().getColor("DrYellow");
+ mPathfindingStatus->setText((LLStringExplicit)str, styleParams);
+ llinfos<<"Region has does not required caps of type ["<<capability<<"]"<<llendl;
+ }
+ }
+ }
+
+ if (!mAgentStateSlot.connected())
+ {
+ LLPathfindingManager::getInstance()->registerAgentStateSignal(boost::bind(&LLFloaterPathfindingConsole::onAgentStateCB, this, _1));
+ }
+ setAgentState(LLPathfindingManager::getInstance()->getAgentState());
+ updatePathTestStatus();
+}
+
+void LLFloaterPathfindingConsole::onClose(bool pIsAppQuitting)
+{
+ if (mAgentStateSlot.connected())
+ {
+ mAgentStateSlot.disconnect();
+ }
+ LLPathingLib::getInstance()->cleanupResidual();
+ LLFloater::onClose(pIsAppQuitting);
+ setHeartBeat( false );
+}
+
+BOOL LLFloaterPathfindingConsole::handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType clicktype, BOOL down)
+{
+ if (isGeneratePathMode(mask, clicktype, down))
+ {
+ LLVector3 dv = gViewerWindow->mouseDirectionGlobal(x, y);
+ LLVector3 mousePos = LLViewerCamera::getInstance()->getOrigin();
+ LLVector3 rayStart = mousePos;
+ LLVector3 rayEnd = mousePos + dv * 150;
+
+ if (mask & MASK_CONTROL)
+ {
+ mPathData.mStartPointA = rayStart;
+ mPathData.mEndPointA = rayEnd;
+ mHasStartPoint = true;
+ }
+ else if (mask & MASK_SHIFT)
+ {
+ mPathData.mStartPointB = rayStart;
+ mPathData.mEndPointB = rayEnd;
+ mHasEndPoint = true;
+ }
+ generatePath();
+ updatePathTestStatus();
+
+ return TRUE;
+ }
+ else
+ {
+ return LLFloater::handleAnyMouseClick(x, y, mask, clicktype, down);
+ }
+}
+
+BOOL LLFloaterPathfindingConsole::isGeneratePathMode(MASK mask, EClickType clicktype, BOOL down) const
+{
+ return (isShown() && (mEditTestTabContainer->getCurrentPanelIndex() == XUI_TEST_TAB_INDEX) &&
+ (clicktype == LLMouseHandler::CLICK_LEFT) && down &&
+ (((mask & MASK_CONTROL) && !(mask & (~MASK_CONTROL))) ||
+ ((mask & MASK_SHIFT) && !(mask & (~MASK_SHIFT)))));
+}
+
+LLHandle<LLFloaterPathfindingConsole> LLFloaterPathfindingConsole::getInstanceHandle()
+{
+ if (sInstanceHandle.isDead())
+ {
+ LLFloaterPathfindingConsole *floaterInstance = LLFloaterReg::getTypedInstance<LLFloaterPathfindingConsole>("pathfinding_console");
+ if (floaterInstance != NULL)
+ {
+ sInstanceHandle = floaterInstance->mSelfHandle;
+ }
+ }
+
+ return sInstanceHandle;
+}
+
+BOOL LLFloaterPathfindingConsole::isRenderPath() const
+{
+ return (mHasStartPoint && mHasEndPoint);
+}
+
+BOOL LLFloaterPathfindingConsole::isRenderNavMesh() const
+{
+ return mShowNavMeshCheckBox->get();
+}
+
+void LLFloaterPathfindingConsole::setRenderNavMesh(BOOL pIsRenderNavMesh)
+{
+ mShowNavMeshCheckBox->set(pIsRenderNavMesh);
+}
+
+BOOL LLFloaterPathfindingConsole::isRenderWalkables() const
+{
+ return mShowWalkablesCheckBox->get();
+}
+
+void LLFloaterPathfindingConsole::setRenderWalkables(BOOL pIsRenderWalkables)
+{
+ mShowWalkablesCheckBox->set(pIsRenderWalkables);
+}
+
+BOOL LLFloaterPathfindingConsole::isRenderStaticObstacles() const
+{
+ return mShowStaticObstaclesCheckBox->get();
+}
+
+void LLFloaterPathfindingConsole::setRenderStaticObstacles(BOOL pIsRenderStaticObstacles)
+{
+ mShowStaticObstaclesCheckBox->set(pIsRenderStaticObstacles);
+}
+
+BOOL LLFloaterPathfindingConsole::isRenderMaterialVolumes() const
+{
+ return mShowMaterialVolumesCheckBox->get();
+}
+
+void LLFloaterPathfindingConsole::setRenderMaterialVolumes(BOOL pIsRenderMaterialVolumes)
+{
+ mShowMaterialVolumesCheckBox->set(pIsRenderMaterialVolumes);
+}
+
+BOOL LLFloaterPathfindingConsole::isRenderExclusionVolumes() const
+{
+ return mShowExclusionVolumesCheckBox->get();
+}
+
+void LLFloaterPathfindingConsole::setRenderExclusionVolumes(BOOL pIsRenderExclusionVolumes)
+{
+ mShowExclusionVolumesCheckBox->set(pIsRenderExclusionVolumes);
+}
+
+BOOL LLFloaterPathfindingConsole::isRenderWorld() const
+{
+ return mShowWorldCheckBox->get();
+}
+
+void LLFloaterPathfindingConsole::setRenderWorld(BOOL pIsRenderWorld)
+{
+ mShowWorldCheckBox->set(pIsRenderWorld);
+}
+
+LLFloaterPathfindingConsole::ERenderHeatmapType LLFloaterPathfindingConsole::getRenderHeatmapType() const
+{
+ ERenderHeatmapType renderHeatmapType;
+
+ switch (mShowNavMeshWalkabilityComboBox->getValue().asInteger())
+ {
+ case XUI_RENDER_HEATMAP_NONE :
+ renderHeatmapType = kRenderHeatmapNone;
+ break;
+ case XUI_RENDER_HEATMAP_A :
+ renderHeatmapType = kRenderHeatmapA;
+ break;
+ case XUI_RENDER_HEATMAP_B :
+ renderHeatmapType = kRenderHeatmapB;
+ break;
+ case XUI_RENDER_HEATMAP_C :
+ renderHeatmapType = kRenderHeatmapC;
+ break;
+ case XUI_RENDER_HEATMAP_D :
+ renderHeatmapType = kRenderHeatmapD;
+ break;
+ default :
+ renderHeatmapType = kRenderHeatmapNone;
+ llassert(0);
+ break;
+ }
+
+ return renderHeatmapType;
+}
+
+void LLFloaterPathfindingConsole::setRenderHeatmapType(ERenderHeatmapType pRenderHeatmapType)
+{
+ LLSD comboBoxValue;
+
+ switch (pRenderHeatmapType)
+ {
+ case kRenderHeatmapNone :
+ comboBoxValue = XUI_RENDER_HEATMAP_NONE;
+ break;
+ case kRenderHeatmapA :
+ comboBoxValue = XUI_RENDER_HEATMAP_A;
+ break;
+ case kRenderHeatmapB :
+ comboBoxValue = XUI_RENDER_HEATMAP_B;
+ break;
+ case kRenderHeatmapC :
+ comboBoxValue = XUI_RENDER_HEATMAP_C;
+ break;
+ case kRenderHeatmapD :
+ comboBoxValue = XUI_RENDER_HEATMAP_D;
+ break;
+ default :
+ comboBoxValue = XUI_RENDER_HEATMAP_NONE;
+ llassert(0);
+ break;
+ }
+
+ return mShowNavMeshWalkabilityComboBox->setValue(comboBoxValue);
+}
+
+F32 LLFloaterPathfindingConsole::getCharacterWidth() const
+{
+ return mCharacterWidthSlider->getValueF32();
+}
+
+void LLFloaterPathfindingConsole::setCharacterWidth(F32 pCharacterWidth)
+{
+ mCharacterWidthSlider->setValue(LLSD(pCharacterWidth));
+}
+
+LLFloaterPathfindingConsole::ECharacterType LLFloaterPathfindingConsole::getCharacterType() const
+{
+ ECharacterType characterType;
+
+ switch (mCharacterTypeRadioGroup->getValue().asInteger())
+ {
+ case XUI_CHARACTER_TYPE_A :
+ characterType = kCharacterTypeA;
+ break;
+ case XUI_CHARACTER_TYPE_B :
+ characterType = kCharacterTypeB;
+ break;
+ case XUI_CHARACTER_TYPE_C :
+ characterType = kCharacterTypeC;
+ break;
+ case XUI_CHARACTER_TYPE_D :
+ characterType = kCharacterTypeD;
+ break;
+ default :
+ characterType = kCharacterTypeA;
+ llassert(0);
+ break;
+ }
+
+ return characterType;
+}
+
+void LLFloaterPathfindingConsole::setCharacterType(ECharacterType pCharacterType)
+{
+ LLSD radioGroupValue;
+
+ switch (pCharacterType)
+ {
+ case kCharacterTypeA :
+ radioGroupValue = XUI_CHARACTER_TYPE_A;
+ break;
+ case kCharacterTypeB :
+ radioGroupValue = XUI_CHARACTER_TYPE_B;
+ break;
+ case kCharacterTypeC :
+ radioGroupValue = XUI_CHARACTER_TYPE_C;
+ break;
+ case kCharacterTypeD :
+ radioGroupValue = XUI_CHARACTER_TYPE_D;
+ break;
+ default :
+ radioGroupValue = XUI_CHARACTER_TYPE_A;
+ llassert(0);
+ break;
+ }
+
+ mCharacterTypeRadioGroup->setValue(radioGroupValue);
+}
+
+void LLFloaterPathfindingConsole::setHasNavMeshReceived()
+{
+ std::string str = getString("navmesh_fetch_complete_available");
+ mPathfindingStatus->setText((LLStringExplicit)str);
+ //check to see if all regions are done loading and they are then stitch the navmeshes together
+ --mNavMeshCnt;
+ if ( mNavMeshCnt == 0 )
+ {
+ LLPathingLib::getInstance()->stitchNavMeshes( gSavedSettings.getBOOL("EnableVBOForNavMeshVisualization") );
+ }
+}
+
+void LLFloaterPathfindingConsole::setHasNoNavMesh()
+{
+ std::string str = getString("navmesh_fetch_complete_none");
+ mPathfindingStatus->setText((LLStringExplicit)str);
+}
+
+LLFloaterPathfindingConsole::LLFloaterPathfindingConsole(const LLSD& pSeed)
+ : LLFloater(pSeed),
+ mSelfHandle(),
+ mShowNavMeshCheckBox(NULL),
+ mShowNavMeshWalkabilityComboBox(NULL),
+ mShowWalkablesCheckBox(NULL),
+ mShowStaticObstaclesCheckBox(NULL),
+ mShowMaterialVolumesCheckBox(NULL),
+ mShowExclusionVolumesCheckBox(NULL),
+ mShowWorldCheckBox(NULL),
+ mPathfindingStatus(NULL),
+ mViewCharactersButton(NULL),
+ mEditTestTabContainer(NULL),
+ mUnfreezeLabel(NULL),
+ mUnfreezeButton(NULL),
+ mLinksetsLabel(NULL),
+ mLinksetsButton(NULL),
+ mFreezeLabel(NULL),
+ mFreezeButton(NULL),
+ mCharacterWidthSlider(NULL),
+ mCharacterTypeRadioGroup(NULL),
+ mPathTestingStatus(NULL),
+ mClearPathButton(NULL),
+ mAgentStateSlot(),
+ mNavMeshCnt(0),
+ mHasStartPoint(false),
+ mHasEndPoint(false),
+ mNeighboringRegion( CURRENT_REGION ),
+ mHeartBeat( false )
+{
+ mSelfHandle.bind(this);
+
+ for (int i=0;i<MAX_OBSERVERS;++i)
+ {
+ mNavMeshDownloadObserver[i].setPathfindingConsole(this);
+ }
+}
+
+LLFloaterPathfindingConsole::~LLFloaterPathfindingConsole()
+{
+}
+
+std::string LLFloaterPathfindingConsole::getCurrentRegionCapabilityURL() const
+{
+ std::string capURL("");
+
+ LLViewerRegion *region = gAgent.getRegion();
+ if (region != NULL)
+ {
+ capURL = region->getCapability("RetrieveNavMeshSrc");
+ }
+
+ return capURL;
+}
+
+void LLFloaterPathfindingConsole::onShowWalkabilitySet()
+{
+ switch (getRenderHeatmapType())
+ {
+ case kRenderHeatmapNone :
+ llwarns << "functionality has not yet been implemented to toggle '"
+ << mShowNavMeshWalkabilityComboBox->getName() << "' to RenderHeatmapNone"
+ << llendl;
+ break;
+ case kRenderHeatmapA :
+ llwarns << "functionality has not yet been implemented to toggle '"
+ << mShowNavMeshWalkabilityComboBox->getName() << "' to RenderHeatmapA"
+ << llendl;
+ break;
+ case kRenderHeatmapB :
+ llwarns << "functionality has not yet been implemented to toggle '"
+ << mShowNavMeshWalkabilityComboBox->getName() << "' to RenderHeatmapB"
+ << llendl;
+ break;
+ case kRenderHeatmapC :
+ llwarns << "functionality has not yet been implemented to toggle '"
+ << mShowNavMeshWalkabilityComboBox->getName() << "' to RenderHeatmapC"
+ << llendl;
+ break;
+ case kRenderHeatmapD :
+ llwarns << "functionality has not yet been implemented to toggle '"
+ << mShowNavMeshWalkabilityComboBox->getName() << "' to RenderHeatmapD"
+ << llendl;
+ break;
+ default :
+ llassert(0);
+ break;
+ }
+}
+
+void LLFloaterPathfindingConsole::onShowWorldToggle()
+{
+ BOOL checkBoxValue = mShowWorldCheckBox->get();
+
+ LLPathingLib *llPathingLibInstance = LLPathingLib::getInstance();
+ if (llPathingLibInstance != NULL)
+ {
+ llPathingLibInstance->setRenderWorld(checkBoxValue);
+ }
+ else
+ {
+ mShowWorldCheckBox->set(FALSE);
+ llwarns << "cannot find LLPathingLib instance" << llendl;
+ }
+}
+
+void LLFloaterPathfindingConsole::onCharacterWidthSet()
+{
+ generatePath();
+ updatePathTestStatus();
+}
+
+void LLFloaterPathfindingConsole::onCharacterTypeSwitch()
+{
+ switch (getCharacterType())
+ {
+ case kCharacterTypeA :
+ llwarns << "functionality has not yet been implemented to toggle '"
+ << mCharacterTypeRadioGroup->getName() << "' to CharacterTypeA"
+ << llendl;
+ break;
+ case kCharacterTypeB :
+ llwarns << "functionality has not yet been implemented to toggle '"
+ << mCharacterTypeRadioGroup->getName() << "' to CharacterTypeB"
+ << llendl;
+ break;
+ case kCharacterTypeC :
+ llwarns << "functionality has not yet been implemented to toggle '"
+ << mCharacterTypeRadioGroup->getName() << "' to CharacterTypeC"
+ << llendl;
+ break;
+ case kCharacterTypeD :
+ llwarns << "functionality has not yet been implemented to toggle '"
+ << mCharacterTypeRadioGroup->getName() << "' to CharacterTypeD"
+ << llendl;
+ break;
+ default :
+ llassert(0);
+ break;
+ }
+ updatePathTestStatus();
+}
+
+void LLFloaterPathfindingConsole::onViewCharactersClicked()
+{
+ LLFloaterPathfindingCharacters::openCharactersViewer();
+}
+
+void LLFloaterPathfindingConsole::onUnfreezeClicked()
+{
+ mUnfreezeButton->setEnabled(FALSE);
+ LLPathfindingManager::getInstance()->requestSetAgentState(LLPathfindingManager::kAgentStateUnfrozen);
+}
+
+void LLFloaterPathfindingConsole::onFreezeClicked()
+{
+ mFreezeButton->setEnabled(FALSE);
+ LLPathfindingManager::getInstance()->requestSetAgentState(LLPathfindingManager::kAgentStateFrozen);
+}
+
+void LLFloaterPathfindingConsole::onViewEditLinksetClicked()
+{
+ LLFloaterPathfindingLinksets::openLinksetsEditor();
+}
+
+void LLFloaterPathfindingConsole::onClearPathClicked()
+{
+ mHasStartPoint = false;
+ mHasEndPoint = false;
+ updatePathTestStatus();
+}
+
+void LLFloaterPathfindingConsole::onAgentStateCB(LLPathfindingManager::EAgentState pAgentState)
+{
+ setAgentState(pAgentState);
+}
+
+void LLFloaterPathfindingConsole::setAgentState(LLPathfindingManager::EAgentState pAgentState)
+{
+ switch (pAgentState)
+ {
+ case LLPathfindingManager::kAgentStateUnknown :
+ case LLPathfindingManager::kAgentStateNotEnabled :
+ mShowNavMeshCheckBox->setEnabled(FALSE);
+ mShowNavMeshWalkabilityComboBox->setEnabled(FALSE);
+ mShowWalkablesCheckBox->setEnabled(FALSE);
+ mShowStaticObstaclesCheckBox->setEnabled(FALSE);
+ mShowMaterialVolumesCheckBox->setEnabled(FALSE);
+ mShowExclusionVolumesCheckBox->setEnabled(FALSE);
+ mShowWorldCheckBox->setEnabled(FALSE);
+ mViewCharactersButton->setEnabled(FALSE);
+ mEditTestTabContainer->setEnabled(FALSE);
+ mCharacterWidthSlider->setEnabled(FALSE);
+ mCharacterTypeRadioGroup->setEnabled(FALSE);
+ mClearPathButton->setEnabled(FALSE);
+
+ mEditTestTabContainer->selectTab(0);
+ mHasStartPoint = false;
+ mHasEndPoint = false;
+ break;
+ default :
+ mShowNavMeshCheckBox->setEnabled(TRUE);
+ mShowNavMeshWalkabilityComboBox->setEnabled(TRUE);
+ mShowWalkablesCheckBox->setEnabled(TRUE);
+ mShowStaticObstaclesCheckBox->setEnabled(TRUE);
+ mShowMaterialVolumesCheckBox->setEnabled(TRUE);
+ mShowExclusionVolumesCheckBox->setEnabled(TRUE);
+ mShowWorldCheckBox->setEnabled(TRUE);
+ mViewCharactersButton->setEnabled(TRUE);
+ mEditTestTabContainer->setEnabled(TRUE);
+ mCharacterWidthSlider->setEnabled(TRUE);
+ mCharacterTypeRadioGroup->setEnabled(TRUE);
+ mClearPathButton->setEnabled(TRUE);
+ break;
+ }
+
+ switch (LLPathfindingManager::getInstance()->getLastKnownNonErrorAgentState())
+ {
+ case LLPathfindingManager::kAgentStateUnknown :
+ case LLPathfindingManager::kAgentStateNotEnabled :
+ mUnfreezeLabel->setEnabled(FALSE);
+ mUnfreezeButton->setEnabled(FALSE);
+ mLinksetsLabel->setEnabled(FALSE);
+ mLinksetsButton->setEnabled(FALSE);
+ mFreezeLabel->setEnabled(FALSE);
+ mFreezeButton->setEnabled(FALSE);
+ break;
+ case LLPathfindingManager::kAgentStateFrozen :
+ mUnfreezeLabel->setEnabled(TRUE);
+ mUnfreezeButton->setEnabled(TRUE);
+ mLinksetsLabel->setEnabled(FALSE);
+ mLinksetsButton->setEnabled(FALSE);
+ mFreezeLabel->setEnabled(FALSE);
+ mFreezeButton->setEnabled(FALSE);
+ break;
+ case LLPathfindingManager::kAgentStateUnfrozen :
+ mUnfreezeLabel->setEnabled(FALSE);
+ mUnfreezeButton->setEnabled(FALSE);
+ mLinksetsLabel->setEnabled(TRUE);
+ mLinksetsButton->setEnabled(TRUE);
+ mFreezeLabel->setEnabled(TRUE);
+ mFreezeButton->setEnabled(TRUE);
+ break;
+ default :
+ llassert(0);
+ break;
+ }
+}
+
+void LLFloaterPathfindingConsole::generatePath()
+{
+ if (mHasStartPoint && mHasEndPoint)
+ {
+ mPathData.mCharacterWidth = getCharacterWidth();
+ LLPathingLib::getInstance()->generatePath(mPathData);
+ }
+}
+
+void LLFloaterPathfindingConsole::updatePathTestStatus()
+{
+ static const LLColor4 warningColor = LLUIColorTable::instance().getColor("DrYellow");
+
+ std::string statusText("");
+ LLStyle::Params styleParams;
+
+ if (!mHasStartPoint && !mHasEndPoint)
+ {
+ statusText = getString("pathing_choose_start_and_end_points");
+ styleParams.color = warningColor;
+ }
+ else if (!mHasStartPoint && mHasEndPoint)
+ {
+ statusText = getString("pathing_choose_start_point");
+ styleParams.color = warningColor;
+ }
+ else if (mHasStartPoint && !mHasEndPoint)
+ {
+ statusText = getString("pathing_choose_end_point");
+ styleParams.color = warningColor;
+ }
+ else
+ {
+ statusText = getString("pathing_path_valid");
+ }
+
+ mPathTestingStatus->setText((LLStringExplicit)statusText, styleParams);
+}
+
+
+BOOL LLFloaterPathfindingConsole::isRenderAnyShapes() const +{ + if ( isRenderWalkables() || isRenderStaticObstacles() || + isRenderMaterialVolumes() || isRenderExclusionVolumes() ) + { + return true; + } + + return false; +} + +U32 LLFloaterPathfindingConsole::getRenderShapeFlags() +{ + resetShapeRenderFlags(); + + if ( isRenderWalkables() ) + { + setShapeRenderFlag( LLPathingLib::LLST_WalkableObjects ); + } + if ( isRenderStaticObstacles() ) + { + setShapeRenderFlag( LLPathingLib::LLST_ObstacleObjects ); + } + if ( isRenderMaterialVolumes() ) + { + setShapeRenderFlag( LLPathingLib::LLST_MaterialPhantoms ); + } + if ( isRenderExclusionVolumes() ) + { + setShapeRenderFlag( LLPathingLib::LLST_ExclusionPhantoms ); + } + return mShapeRenderFlags; +} diff --git a/indra/newview/llfloaterpathfindingconsole.h b/indra/newview/llfloaterpathfindingconsole.h new file mode 100644 index 0000000000..34a68ebed1 --- /dev/null +++ b/indra/newview/llfloaterpathfindingconsole.h @@ -0,0 +1,181 @@ +/** + * @file llfloaterpathfindingconsole.h + * @author William Todd Stinson + * @brief "Pathfinding console" floater, allowing manipulation of the Havok AI pathfinding settings. + * + * $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$ + */ + +#ifndef LL_LLFLOATERPATHFINDINGCONSOLE_H +#define LL_LLFLOATERPATHFINDINGCONSOLE_H + +#include "llfloater.h" +#include "llhandle.h" +#include "llnavmeshstation.h" +#include "LLPathingLib.h" +#include "llpathfindingmanager.h" + +class LLSD; +class LLRadioGroup; +class LLSliderCtrl; +class LLLineEditor; +class LLTextBase; +class LLCheckBoxCtrl; +class LLTabContainer; +class LLComboBox; +class LLButton; + +class LLFloaterPathfindingConsole +: public LLFloater +{ + friend class LLFloaterReg; + +public: + typedef enum + { + kRenderHeatmapNone, + kRenderHeatmapA, + kRenderHeatmapB, + kRenderHeatmapC, + kRenderHeatmapD + } ERenderHeatmapType; + + typedef enum + { + kCharacterTypeA = 0, + kCharacterTypeB = 1, + kCharacterTypeC = 2, + kCharacterTypeD = 3 + } ECharacterType; + + virtual BOOL postBuild(); + virtual void onOpen(const LLSD& pKey); + virtual void onClose(bool pIsAppQuitting); + virtual BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType clicktype, BOOL down); + + BOOL isGeneratePathMode(MASK mask, EClickType clicktype, BOOL down) const; + + static LLHandle<LLFloaterPathfindingConsole> getInstanceHandle(); + + BOOL isRenderPath() const; + + BOOL isRenderNavMesh() const; + void setRenderNavMesh(BOOL pIsRenderNavMesh); + + BOOL isRenderWalkables() const; + void setRenderWalkables(BOOL pIsRenderWalkables); + + BOOL isRenderStaticObstacles() const; + void setRenderStaticObstacles(BOOL pIsRenderStaticObstacles); + + BOOL isRenderMaterialVolumes() const; + void setRenderMaterialVolumes(BOOL pIsRenderMaterialVolumes); + + BOOL isRenderExclusionVolumes() const; + void setRenderExclusionVolumes(BOOL pIsRenderExclusionVolumes); + + BOOL isRenderWorld() const; + void setRenderWorld(BOOL pIsRenderWorld); + + BOOL isRenderAnyShapes() const; + U32 getRenderShapeFlags(); + + ERenderHeatmapType getRenderHeatmapType() const; + void setRenderHeatmapType(ERenderHeatmapType pRenderHeatmapType); + + F32 getCharacterWidth() const; + void setCharacterWidth(F32 pCharacterWidth); + + ECharacterType getCharacterType() const; + void setCharacterType(ECharacterType pCharacterType); + + void setHasNavMeshReceived(); + void setHasNoNavMesh(); + + bool getHeartBeat() const { return mHeartBeat;} + void setHeartBeat( bool state ) { mHeartBeat=state; } + +protected: + +private: + // Does its own instance management, so clients not allowed + // to allocate or destroy. + LLFloaterPathfindingConsole(const LLSD& pSeed); + virtual ~LLFloaterPathfindingConsole(); + + std::string getCurrentRegionCapabilityURL() const; + + void onShowWalkabilitySet(); + void onShowWorldToggle(); + void onCharacterWidthSet(); + void onCharacterTypeSwitch(); + void onViewCharactersClicked(); + void onUnfreezeClicked(); + void onFreezeClicked(); + void onViewEditLinksetClicked(); + void onClearPathClicked(); + void onAgentStateCB(LLPathfindingManager::EAgentState pAgentState); + + void setAgentState(LLPathfindingManager::EAgentState pAgentState); + + void generatePath(); + void updatePathTestStatus(); + void resetShapeRenderFlags() { mShapeRenderFlags = 0; } + void setShapeRenderFlag( LLPathingLib::LLShapeType type ) { mShapeRenderFlags |= (1<<type); } + + LLRootHandle<LLFloaterPathfindingConsole> mSelfHandle; + LLCheckBoxCtrl *mShowNavMeshCheckBox; + LLComboBox *mShowNavMeshWalkabilityComboBox; + LLCheckBoxCtrl *mShowWalkablesCheckBox; + LLCheckBoxCtrl *mShowStaticObstaclesCheckBox; + LLCheckBoxCtrl *mShowMaterialVolumesCheckBox; + LLCheckBoxCtrl *mShowExclusionVolumesCheckBox; + LLCheckBoxCtrl *mShowWorldCheckBox; + LLTextBase *mPathfindingStatus; + LLButton *mViewCharactersButton; + LLTabContainer *mEditTestTabContainer; + LLTextBase *mUnfreezeLabel; + LLButton *mUnfreezeButton; + LLTextBase *mLinksetsLabel; + LLButton *mLinksetsButton; + LLTextBase *mFreezeLabel; + LLButton *mFreezeButton; + LLSliderCtrl *mCharacterWidthSlider; + LLRadioGroup *mCharacterTypeRadioGroup; + LLTextBase *mPathTestingStatus; + LLButton *mClearPathButton; + LLPathfindingManager::agent_state_slot_t mAgentStateSlot; + + LLNavMeshDownloadObserver mNavMeshDownloadObserver[10]; + int mCurrentMDO; + int mNavMeshCnt; + U32 mNeighboringRegion; + //Container that is populated and subsequently submitted to the LLPathingSystem for processing + LLPathingLib::PathingPacket mPathData; + bool mHasStartPoint; + bool mHasEndPoint; + U32 mShapeRenderFlags; + bool mHeartBeat; + static LLHandle<LLFloaterPathfindingConsole> sInstanceHandle; +}; + +#endif // LL_LLFLOATERPATHFINDINGCONSOLE_H diff --git a/indra/newview/llfloaterpathfindinglinksets.cpp b/indra/newview/llfloaterpathfindinglinksets.cpp new file mode 100644 index 0000000000..9b86ecd66a --- /dev/null +++ b/indra/newview/llfloaterpathfindinglinksets.cpp @@ -0,0 +1,1211 @@ +/**
+ * @file llfloaterpathfindinglinksets.cpp
+ * @author William Todd Stinson
+ * @brief "Pathfinding linksets" floater, allowing manipulation of the Havok AI pathfinding settings.
+ *
+ * $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 "llfloater.h"
+#include "llfloaterreg.h"
+#include "llfloaterpathfindinglinksets.h"
+#include "llsd.h"
+#include "lluuid.h"
+#include "v3math.h"
+#include "lltextvalidate.h"
+#include "llagent.h"
+#include "lltextbase.h"
+#include "lllineeditor.h"
+#include "llscrolllistitem.h"
+#include "llscrolllistctrl.h"
+#include "llcombobox.h"
+#include "llcheckboxctrl.h"
+#include "llbutton.h"
+#include "llresmgr.h"
+#include "llviewerregion.h"
+#include "llselectmgr.h"
+#include "llviewermenu.h"
+#include "llviewerobject.h"
+#include "llviewerobjectlist.h"
+#include "llpathfindinglinkset.h"
+#include "llpathfindinglinksetlist.h"
+#include "llpathfindingmanager.h"
+#include "llnotificationsutil.h"
+
+#include <boost/bind.hpp>
+
+#define XUI_LINKSET_USE_NONE 0
+#define XUI_LINKSET_USE_WALKABLE 1
+#define XUI_LINKSET_USE_STATIC_OBSTACLE 2
+#define XUI_LINKSET_USE_DYNAMIC_OBSTACLE 3
+#define XUI_LINKSET_USE_MATERIAL_VOLUME 4
+#define XUI_LINKSET_USE_EXCLUSION_VOLUME 5
+#define XUI_LINKSET_USE_DYNAMIC_PHANTOM 6
+
+//---------------------------------------------------------------------------
+// LLFloaterPathfindingLinksets
+//---------------------------------------------------------------------------
+
+BOOL LLFloaterPathfindingLinksets::postBuild()
+{
+ childSetAction("apply_filters", boost::bind(&LLFloaterPathfindingLinksets::onApplyAllFilters, this));
+ childSetAction("clear_filters", boost::bind(&LLFloaterPathfindingLinksets::onClearFiltersClicked, this));
+
+ mFilterByName = findChild<LLLineEditor>("filter_by_name");
+ llassert(mFilterByName != NULL);
+ mFilterByName->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onApplyAllFilters, this));
+ mFilterByName->setSelectAllonFocusReceived(true);
+ mFilterByName->setCommitOnFocusLost(true);
+
+ mFilterByDescription = findChild<LLLineEditor>("filter_by_description");
+ llassert(mFilterByDescription != NULL);
+ mFilterByDescription->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onApplyAllFilters, this));
+ mFilterByDescription->setSelectAllonFocusReceived(true);
+ mFilterByDescription->setCommitOnFocusLost(true);
+
+ mFilterByLinksetUse = findChild<LLComboBox>("filter_by_linkset_use");
+ llassert(mFilterByLinksetUse != NULL);
+ mFilterByLinksetUse->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onApplyAllFilters, this));
+
+ mLinksetsScrollList = findChild<LLScrollListCtrl>("pathfinding_linksets");
+ llassert(mLinksetsScrollList != NULL);
+ mLinksetsScrollList->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onLinksetsSelectionChange, this));
+ mLinksetsScrollList->sortByColumnIndex(0, true);
+
+ mLinksetsStatus = findChild<LLTextBase>("linksets_status");
+ llassert(mLinksetsStatus != NULL);
+
+ mRefreshListButton = findChild<LLButton>("refresh_linksets_list");
+ llassert(mRefreshListButton != NULL);
+ mRefreshListButton->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onRefreshLinksetsClicked, this));
+
+ mSelectAllButton = findChild<LLButton>("select_all_linksets");
+ llassert(mSelectAllButton != NULL);
+ mSelectAllButton->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onSelectAllLinksetsClicked, this));
+
+ mSelectNoneButton = findChild<LLButton>("select_none_linksets");
+ llassert(mSelectNoneButton != NULL);
+ mSelectNoneButton->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onSelectNoneLinksetsClicked, this));
+
+ mShowBeaconCheckBox = findChild<LLCheckBoxCtrl>("show_beacon");
+ llassert(mShowBeaconCheckBox != NULL);
+
+ mTakeButton = findChild<LLButton>("take_linksets");
+ llassert(mTakeButton != NULL);
+ mTakeButton->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onTakeClicked, this));
+
+ mTakeCopyButton = findChild<LLButton>("take_copy_linksets");
+ llassert(mTakeCopyButton != NULL);
+ mTakeCopyButton->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onTakeCopyClicked, this));
+
+ mReturnButton = findChild<LLButton>("return_linksets");
+ llassert(mReturnButton != NULL);
+ mReturnButton->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onReturnClicked, this));
+
+ mDeleteButton = findChild<LLButton>("delete_linksets");
+ llassert(mDeleteButton != NULL);
+ mDeleteButton->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onDeleteClicked, this));
+
+ mTeleportButton = findChild<LLButton>("teleport_me_to_linkset");
+ llassert(mTeleportButton != NULL);
+ mTeleportButton->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onTeleportClicked, this));
+
+ mEditLinksetUse = findChild<LLComboBox>("edit_linkset_use");
+ llassert(mEditLinksetUse != NULL);
+
+ mEditLinksetUse->clearRows();
+
+ mEditLinksetUseUnset = mEditLinksetUse->addElement(buildLinksetUseScrollListElement(getString("linkset_choose_use"), XUI_LINKSET_USE_NONE));
+ llassert(mEditLinksetUseUnset != NULL);
+
+ mEditLinksetUseWalkable = mEditLinksetUse->addElement(buildLinksetUseScrollListElement(getLinksetUseString(LLPathfindingLinkset::kWalkable), XUI_LINKSET_USE_WALKABLE));
+ llassert(mEditLinksetUseWalkable != NULL);
+
+ mEditLinksetUseStaticObstacle = mEditLinksetUse->addElement(buildLinksetUseScrollListElement(getLinksetUseString(LLPathfindingLinkset::kStaticObstacle), XUI_LINKSET_USE_STATIC_OBSTACLE));
+ llassert(mEditLinksetUseStaticObstacle != NULL);
+
+ mEditLinksetUseDynamicObstacle = mEditLinksetUse->addElement(buildLinksetUseScrollListElement(getLinksetUseString(LLPathfindingLinkset::kDynamicObstacle), XUI_LINKSET_USE_DYNAMIC_OBSTACLE));
+ llassert(mEditLinksetUseDynamicObstacle != NULL);
+
+ mEditLinksetUseMaterialVolume = mEditLinksetUse->addElement(buildLinksetUseScrollListElement(getLinksetUseString(LLPathfindingLinkset::kMaterialVolume), XUI_LINKSET_USE_MATERIAL_VOLUME));
+ llassert(mEditLinksetUseMaterialVolume != NULL);
+
+ mEditLinksetUseExclusionVolume = mEditLinksetUse->addElement(buildLinksetUseScrollListElement(getLinksetUseString(LLPathfindingLinkset::kExclusionVolume), XUI_LINKSET_USE_EXCLUSION_VOLUME));
+ llassert(mEditLinksetUseExclusionVolume != NULL);
+
+ mEditLinksetUseDynamicPhantom = mEditLinksetUse->addElement(buildLinksetUseScrollListElement(getLinksetUseString(LLPathfindingLinkset::kDynamicPhantom), XUI_LINKSET_USE_DYNAMIC_PHANTOM));
+ llassert(mEditLinksetUseDynamicPhantom != NULL);
+
+ mEditLinksetUse->selectFirstItem();
+
+ mLabelWalkabilityCoefficients = findChild<LLTextBase>("walkability_coefficients_label");
+ llassert(mLabelWalkabilityCoefficients != NULL);
+
+ mLabelEditA = findChild<LLTextBase>("edit_a_label");
+ llassert(mLabelEditA != NULL);
+
+ mEditA = findChild<LLLineEditor>("edit_a_value");
+ llassert(mEditA != NULL);
+ mEditA->setPrevalidate(LLTextValidate::validateNonNegativeS32);
+ mEditA->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onWalkabilityCoefficientEntered, this, _1));
+
+ mLabelEditB = findChild<LLTextBase>("edit_b_label");
+ llassert(mLabelEditB != NULL);
+
+ mEditB = findChild<LLLineEditor>("edit_b_value");
+ llassert(mEditB != NULL);
+ mEditB->setPrevalidate(LLTextValidate::validateNonNegativeS32);
+ mEditB->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onWalkabilityCoefficientEntered, this, _1));
+
+ mLabelEditC = findChild<LLTextBase>("edit_c_label");
+ llassert(mLabelEditC != NULL);
+
+ mEditC = findChild<LLLineEditor>("edit_c_value");
+ llassert(mEditC != NULL);
+ mEditC->setPrevalidate(LLTextValidate::validateNonNegativeS32);
+ mEditC->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onWalkabilityCoefficientEntered, this, _1));
+
+ mLabelEditD = findChild<LLTextBase>("edit_d_label");
+ llassert(mLabelEditD != NULL);
+
+ mEditD = findChild<LLLineEditor>("edit_d_value");
+ llassert(mEditD != NULL);
+ mEditD->setPrevalidate(LLTextValidate::validateNonNegativeS32);
+ mEditD->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onWalkabilityCoefficientEntered, this, _1));
+
+ mApplyEditsButton = findChild<LLButton>("apply_edit_values");
+ llassert(mApplyEditsButton != NULL);
+ mApplyEditsButton->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onApplyChangesClicked, this));
+
+ return LLFloater::postBuild();
+}
+
+void LLFloaterPathfindingLinksets::onOpen(const LLSD& pKey)
+{
+ LLFloater::onOpen(pKey);
+
+ requestGetLinksets();
+ selectNoneLinksets();
+ mLinksetsScrollList->setCommitOnSelectionChange(true);
+
+ if (!mAgentStateSlot.connected())
+ {
+ LLPathfindingManager::getInstance()->registerAgentStateSignal(boost::bind(&LLFloaterPathfindingLinksets::onAgentStateCB, this, _1));
+ }
+}
+
+void LLFloaterPathfindingLinksets::onClose(bool pAppQuitting)
+{
+ if (mAgentStateSlot.connected())
+ {
+ mAgentStateSlot.disconnect();
+ }
+
+ mLinksetsScrollList->setCommitOnSelectionChange(false);
+ selectNoneLinksets();
+ if (mLinksetsSelection.notNull())
+ {
+ mLinksetsSelection.clear();
+ }
+
+ LLFloater::onClose(pAppQuitting);
+}
+
+void LLFloaterPathfindingLinksets::draw()
+{
+ if (mShowBeaconCheckBox->get())
+ {
+ std::vector<LLScrollListItem*> selectedItems = mLinksetsScrollList->getAllSelected();
+ if (!selectedItems.empty())
+ {
+ int numSelectedItems = selectedItems.size();
+
+ std::vector<LLViewerObject *> viewerObjects;
+ viewerObjects.reserve(numSelectedItems);
+
+ for (std::vector<LLScrollListItem*>::const_iterator selectedItemIter = selectedItems.begin();
+ selectedItemIter != selectedItems.end(); ++selectedItemIter)
+ {
+ const LLScrollListItem *selectedItem = *selectedItemIter;
+
+ const std::string &objectName = selectedItem->getColumn(0)->getValue().asString();
+
+ LLViewerObject *viewerObject = gObjectList.findObject(selectedItem->getUUID());
+ if (viewerObject != NULL)
+ {
+ gObjectList.addDebugBeacon(viewerObject->getPositionAgent(), objectName, LLColor4(0.f, 0.f, 1.f, 0.8f), LLColor4(1.f, 1.f, 1.f, 1.f), 6);
+ }
+ }
+ }
+ }
+
+ LLFloater::draw();
+}
+
+void LLFloaterPathfindingLinksets::openLinksetsEditor()
+{
+ LLFloaterReg::toggleInstanceOrBringToFront("pathfinding_linksets");
+}
+
+LLFloaterPathfindingLinksets::EMessagingState LLFloaterPathfindingLinksets::getMessagingState() const
+{
+ return mMessagingState;
+}
+
+bool LLFloaterPathfindingLinksets::isMessagingInProgress() const
+{
+ return ((mMessagingState == kMessagingGetRequestSent) || (mMessagingState == kMessagingSetRequestSent));
+}
+
+LLFloaterPathfindingLinksets::LLFloaterPathfindingLinksets(const LLSD& pSeed)
+ : LLFloater(pSeed),
+ mFilterByName(NULL),
+ mFilterByDescription(NULL),
+ mFilterByLinksetUse(NULL),
+ mLinksetsScrollList(NULL),
+ mLinksetsStatus(NULL),
+ mRefreshListButton(NULL),
+ mSelectAllButton(NULL),
+ mSelectNoneButton(NULL),
+ mShowBeaconCheckBox(NULL),
+ mTakeButton(NULL),
+ mTakeCopyButton(NULL),
+ mReturnButton(NULL),
+ mDeleteButton(NULL),
+ mTeleportButton(NULL),
+ mEditLinksetUse(NULL),
+ mLabelWalkabilityCoefficients(NULL),
+ mLabelEditA(NULL),
+ mEditA(NULL),
+ mLabelEditB(NULL),
+ mEditB(NULL),
+ mLabelEditC(NULL),
+ mEditC(NULL),
+ mLabelEditD(NULL),
+ mEditD(NULL),
+ mApplyEditsButton(NULL),
+ mMessagingState(kMessagingUnknown),
+ mLinksetsListPtr(),
+ mLinksetsSelection(),
+ mAgentStateSlot()
+{
+}
+
+LLFloaterPathfindingLinksets::~LLFloaterPathfindingLinksets()
+{
+}
+
+void LLFloaterPathfindingLinksets::setMessagingState(EMessagingState pMessagingState)
+{
+ mMessagingState = pMessagingState;
+ updateControls();
+}
+
+void LLFloaterPathfindingLinksets::requestGetLinksets()
+{
+ llassert(!isMessagingInProgress());
+ if (!isMessagingInProgress())
+ {
+ switch (LLPathfindingManager::getInstance()->requestGetLinksets(boost::bind(&LLFloaterPathfindingLinksets::handleNewLinksets, this, _1, _2)))
+ {
+ case LLPathfindingManager::kLinksetsRequestStarted :
+ setMessagingState(kMessagingGetRequestSent);
+ break;
+ case LLPathfindingManager::kLinksetsRequestCompleted :
+ clearLinksets();
+ setMessagingState(kMessagingComplete);
+ break;
+ case LLPathfindingManager::kLinksetsRequestNotEnabled :
+ clearLinksets();
+ setMessagingState(kMessagingNotEnabled);
+ break;
+ case LLPathfindingManager::kLinksetsRequestError :
+ setMessagingState(kMessagingGetError);
+ break;
+ default :
+ setMessagingState(kMessagingGetError);
+ llassert(0);
+ break;
+ }
+ }
+}
+
+void LLFloaterPathfindingLinksets::requestSetLinksets(LLPathfindingLinksetListPtr pLinksetList, LLPathfindingLinkset::ELinksetUse pLinksetUse, S32 pA, S32 pB, S32 pC, S32 pD)
+{
+ llassert(!isMessagingInProgress());
+ if (!isMessagingInProgress())
+ {
+ switch (LLPathfindingManager::getInstance()->requestSetLinksets(pLinksetList, pLinksetUse, pA, pB, pC, pD, boost::bind(&LLFloaterPathfindingLinksets::handleUpdateLinksets, this, _1, _2)))
+ {
+ case LLPathfindingManager::kLinksetsRequestStarted :
+ setMessagingState(kMessagingSetRequestSent);
+ break;
+ case LLPathfindingManager::kLinksetsRequestCompleted :
+ setMessagingState(kMessagingComplete);
+ break;
+ case LLPathfindingManager::kLinksetsRequestNotEnabled :
+ clearLinksets();
+ setMessagingState(kMessagingNotEnabled);
+ break;
+ case LLPathfindingManager::kLinksetsRequestError :
+ setMessagingState(kMessagingSetError);
+ break;
+ default :
+ setMessagingState(kMessagingSetError);
+ llassert(0);
+ break;
+ }
+ }
+}
+
+void LLFloaterPathfindingLinksets::handleNewLinksets(LLPathfindingManager::ELinksetsRequestStatus pLinksetsRequestStatus, LLPathfindingLinksetListPtr pLinksetsListPtr)
+{
+ mLinksetsListPtr = pLinksetsListPtr;
+ updateScrollList();
+
+ switch (pLinksetsRequestStatus)
+ {
+ case LLPathfindingManager::kLinksetsRequestCompleted :
+ setMessagingState(kMessagingComplete);
+ break;
+ case LLPathfindingManager::kLinksetsRequestError :
+ setMessagingState(kMessagingGetError);
+ break;
+ default :
+ setMessagingState(kMessagingGetError);
+ llassert(0);
+ break;
+ }
+}
+
+void LLFloaterPathfindingLinksets::handleUpdateLinksets(LLPathfindingManager::ELinksetsRequestStatus pLinksetsRequestStatus, LLPathfindingLinksetListPtr pLinksetsListPtr)
+{
+ if (mLinksetsListPtr == NULL)
+ {
+ mLinksetsListPtr = pLinksetsListPtr;
+ }
+ else
+ {
+ mLinksetsListPtr->update(*pLinksetsListPtr);
+ }
+ updateScrollList();
+
+ switch (pLinksetsRequestStatus)
+ {
+ case LLPathfindingManager::kLinksetsRequestCompleted :
+ setMessagingState(kMessagingComplete);
+ break;
+ case LLPathfindingManager::kLinksetsRequestError :
+ setMessagingState(kMessagingSetError);
+ break;
+ default :
+ setMessagingState(kMessagingSetError);
+ llassert(0);
+ break;
+ }
+}
+
+void LLFloaterPathfindingLinksets::onApplyAllFilters()
+{
+ applyFilters();
+}
+
+void LLFloaterPathfindingLinksets::onClearFiltersClicked()
+{
+ clearFilters();
+}
+
+void LLFloaterPathfindingLinksets::onLinksetsSelectionChange()
+{
+ mLinksetsSelection.clear();
+ LLSelectMgr::getInstance()->deselectAll();
+
+ std::vector<LLScrollListItem *> selectedItems = mLinksetsScrollList->getAllSelected();
+ if (!selectedItems.empty())
+ {
+ int numSelectedItems = selectedItems.size();
+
+ std::vector<LLViewerObject *>viewerObjects;
+ viewerObjects.reserve(numSelectedItems);
+
+ for (std::vector<LLScrollListItem *>::const_iterator selectedItemIter = selectedItems.begin();
+ selectedItemIter != selectedItems.end(); ++selectedItemIter)
+ {
+ const LLScrollListItem *selectedItem = *selectedItemIter;
+
+ LLViewerObject *viewerObject = gObjectList.findObject(selectedItem->getUUID());
+ if (viewerObject != NULL)
+ {
+ viewerObjects.push_back(viewerObject);
+ }
+ }
+
+ if (!viewerObjects.empty())
+ {
+ mLinksetsSelection = LLSelectMgr::getInstance()->selectObjectAndFamily(viewerObjects);
+ }
+ }
+
+ updateEditFieldValues();
+ updateControls();
+}
+
+void LLFloaterPathfindingLinksets::onRefreshLinksetsClicked()
+{
+ requestGetLinksets();
+}
+
+void LLFloaterPathfindingLinksets::onSelectAllLinksetsClicked()
+{
+ selectAllLinksets();
+}
+
+void LLFloaterPathfindingLinksets::onSelectNoneLinksetsClicked()
+{
+ selectNoneLinksets();
+}
+
+void LLFloaterPathfindingLinksets::onTakeClicked()
+{
+ handle_take();
+}
+
+void LLFloaterPathfindingLinksets::onTakeCopyClicked()
+{
+ handle_take_copy();
+}
+
+void LLFloaterPathfindingLinksets::onReturnClicked()
+{
+ handle_object_return();
+}
+
+void LLFloaterPathfindingLinksets::onDeleteClicked()
+{
+ handle_object_delete();
+}
+
+void LLFloaterPathfindingLinksets::onTeleportClicked()
+{
+ std::vector<LLScrollListItem*> selectedItems = mLinksetsScrollList->getAllSelected();
+ llassert(selectedItems.size() == 1);
+ if (selectedItems.size() == 1)
+ {
+ std::vector<LLScrollListItem*>::const_reference selectedItemRef = selectedItems.front();
+ const LLScrollListItem *selectedItem = selectedItemRef;
+ llassert(mLinksetsListPtr != NULL);
+ LLPathfindingLinksetList::const_iterator linksetIter = mLinksetsListPtr->find(selectedItem->getUUID().asString());
+ const LLPathfindingLinksetPtr linksetPtr = linksetIter->second;
+ const LLVector3 &linksetLocation = linksetPtr->getLocation();
+
+ LLViewerRegion* region = gAgent.getRegion();
+ if (region != NULL)
+ {
+ gAgent.teleportRequest(region->getHandle(), linksetLocation, true);
+ }
+ }
+}
+
+void LLFloaterPathfindingLinksets::onWalkabilityCoefficientEntered(LLUICtrl *pUICtrl)
+{
+ LLLineEditor *pLineEditor = static_cast<LLLineEditor *>(pUICtrl);
+ llassert(pLineEditor != NULL);
+
+ const std::string &valueString = pLineEditor->getText();
+ S32 value = static_cast<S32>(atoi(valueString.c_str()));
+
+ if ((value < LLPathfindingLinkset::MIN_WALKABILITY_VALUE) || (value > LLPathfindingLinkset::MAX_WALKABILITY_VALUE))
+ {
+ value = llclamp(value, LLPathfindingLinkset::MIN_WALKABILITY_VALUE, LLPathfindingLinkset::MAX_WALKABILITY_VALUE);
+ pLineEditor->setValue(LLSD(value));
+ }
+}
+
+void LLFloaterPathfindingLinksets::onApplyChangesClicked()
+{
+ applyEdit();
+}
+
+void LLFloaterPathfindingLinksets::onAgentStateCB(LLPathfindingManager::EAgentState pAgentState)
+{
+ updateControls();
+}
+
+void LLFloaterPathfindingLinksets::applyFilters()
+{
+ updateScrollList();
+}
+
+void LLFloaterPathfindingLinksets::clearFilters()
+{
+ mFilterByName->clear();
+ mFilterByDescription->clear();
+ setFilterLinksetUse(LLPathfindingLinkset::kUnknown);
+ updateScrollList();
+}
+
+void LLFloaterPathfindingLinksets::selectAllLinksets()
+{
+ mLinksetsScrollList->selectAll();
+}
+
+void LLFloaterPathfindingLinksets::selectNoneLinksets()
+{
+ mLinksetsScrollList->deselectAllItems();
+}
+
+void LLFloaterPathfindingLinksets::clearLinksets()
+{
+ if (mLinksetsListPtr != NULL)
+ {
+ mLinksetsListPtr->clear();
+ }
+ updateScrollList();
+}
+
+void LLFloaterPathfindingLinksets::updateControls()
+{
+ updateStatusMessage();
+ updateEnableStateOnListActions();
+ updateEnableStateOnEditFields();
+}
+
+void LLFloaterPathfindingLinksets::updateEditFieldValues()
+{
+ std::vector<LLScrollListItem*> selectedItems = mLinksetsScrollList->getAllSelected();
+ int numSelectedItems = selectedItems.size();
+ if (numSelectedItems <= 0)
+ {
+ mEditLinksetUse->selectFirstItem();
+ mEditA->clear();
+ mEditB->clear();
+ mEditC->clear();
+ mEditD->clear();
+ }
+ else
+ {
+ LLScrollListItem *firstItem = selectedItems.front();
+
+ llassert(mLinksetsListPtr != NULL);
+ LLPathfindingLinksetList::const_iterator linksetIter = mLinksetsListPtr->find(firstItem->getUUID().asString());
+ const LLPathfindingLinksetPtr linksetPtr(linksetIter->second);
+
+ setEditLinksetUse(linksetPtr->getLinksetUse());
+ mEditA->setValue(LLSD(linksetPtr->getWalkabilityCoefficientA()));
+ mEditB->setValue(LLSD(linksetPtr->getWalkabilityCoefficientB()));
+ mEditC->setValue(LLSD(linksetPtr->getWalkabilityCoefficientC()));
+ mEditD->setValue(LLSD(linksetPtr->getWalkabilityCoefficientD()));
+
+ switch (getAllowLinksetUse())
+ {
+ case kAllowLinksetUseAll :
+ mEditLinksetUseWalkable->setEnabled(TRUE);
+ mEditLinksetUseStaticObstacle->setEnabled(TRUE);
+ mEditLinksetUseDynamicObstacle->setEnabled(TRUE);
+ mEditLinksetUseMaterialVolume->setEnabled(TRUE);
+ mEditLinksetUseExclusionVolume->setEnabled(TRUE);
+ mEditLinksetUseDynamicPhantom->setEnabled(TRUE);
+ break;
+ case kAllowLinksetUseOnlyNonPhantom :
+ mEditLinksetUseWalkable->setEnabled(TRUE);
+ mEditLinksetUseStaticObstacle->setEnabled(TRUE);
+ mEditLinksetUseDynamicObstacle->setEnabled(TRUE);
+ mEditLinksetUseMaterialVolume->setEnabled(FALSE);
+ mEditLinksetUseExclusionVolume->setEnabled(FALSE);
+ mEditLinksetUseDynamicPhantom->setEnabled(FALSE);
+ break;
+ case kAllowLinksetUseOnlyPhantom :
+ mEditLinksetUseWalkable->setEnabled(FALSE);
+ mEditLinksetUseStaticObstacle->setEnabled(FALSE);
+ mEditLinksetUseDynamicObstacle->setEnabled(FALSE);
+ mEditLinksetUseMaterialVolume->setEnabled(TRUE);
+ mEditLinksetUseExclusionVolume->setEnabled(TRUE);
+ mEditLinksetUseDynamicPhantom->setEnabled(TRUE);
+ break;
+ case kAllowLinksetUseOnlyTerrain :
+ mEditLinksetUseWalkable->setEnabled(TRUE);
+ mEditLinksetUseStaticObstacle->setEnabled(FALSE);
+ mEditLinksetUseDynamicObstacle->setEnabled(FALSE);
+ mEditLinksetUseMaterialVolume->setEnabled(FALSE);
+ mEditLinksetUseExclusionVolume->setEnabled(FALSE);
+ mEditLinksetUseDynamicPhantom->setEnabled(FALSE);
+ break;
+ default :
+ llassert(0);
+ break;
+ }
+ }
+}
+
+void LLFloaterPathfindingLinksets::updateScrollList()
+{
+ std::vector<LLScrollListItem*> selectedItems = mLinksetsScrollList->getAllSelected();
+ int numSelectedItems = selectedItems.size();
+ uuid_vec_t selectedUUIDs;
+ if (numSelectedItems > 0)
+ {
+ selectedUUIDs.reserve(selectedItems.size());
+ for (std::vector<LLScrollListItem*>::const_iterator itemIter = selectedItems.begin();
+ itemIter != selectedItems.end(); ++itemIter)
+ {
+ const LLScrollListItem *listItem = *itemIter;
+ selectedUUIDs.push_back(listItem->getUUID());
+ }
+ }
+
+ mLinksetsScrollList->deleteAllItems();
+
+ if (mLinksetsListPtr != NULL)
+ {
+ std::string nameFilter = mFilterByName->getText();
+ std::string descriptionFilter = mFilterByDescription->getText();
+ LLPathfindingLinkset::ELinksetUse linksetUseFilter = getFilterLinksetUse();
+ bool isFilteringName = !nameFilter.empty();
+ bool isFilteringDescription = !descriptionFilter.empty();
+ bool isFilteringLinksetUse = (linksetUseFilter != LLPathfindingLinkset::kUnknown);
+
+ const LLVector3& avatarPosition = gAgent.getPositionAgent();
+
+ if (isFilteringName || isFilteringDescription || isFilteringLinksetUse)
+ {
+ LLStringUtil::toUpper(nameFilter);
+ LLStringUtil::toUpper(descriptionFilter);
+ for (LLPathfindingLinksetList::const_iterator linksetIter = mLinksetsListPtr->begin();
+ linksetIter != mLinksetsListPtr->end(); ++linksetIter)
+ {
+ const LLPathfindingLinksetPtr linksetPtr(linksetIter->second);
+ std::string linksetName = (linksetPtr->isTerrain() ? getString("linkset_terrain_name") : linksetPtr->getName());
+ std::string linksetDescription = linksetPtr->getDescription();
+ LLStringUtil::toUpper(linksetName);
+ LLStringUtil::toUpper(linksetDescription);
+ if ((!isFilteringName || (linksetName.find(nameFilter) != std::string::npos)) &&
+ (!isFilteringDescription || (linksetDescription.find(descriptionFilter) != std::string::npos)) &&
+ (!isFilteringLinksetUse || (linksetPtr->getLinksetUse() == linksetUseFilter)))
+ {
+ LLSD element = buildLinksetScrollListElement(linksetPtr, avatarPosition);
+ mLinksetsScrollList->addElement(element);
+ }
+ }
+ }
+ else
+ {
+ for (LLPathfindingLinksetList::const_iterator linksetIter = mLinksetsListPtr->begin();
+ linksetIter != mLinksetsListPtr->end(); ++linksetIter)
+ {
+ const LLPathfindingLinksetPtr linksetPtr(linksetIter->second);
+ LLSD element = buildLinksetScrollListElement(linksetPtr, avatarPosition);
+ mLinksetsScrollList->addElement(element);
+ }
+ }
+ }
+
+ mLinksetsScrollList->selectMultiple(selectedUUIDs);
+ updateEditFieldValues();
+ updateControls();
+}
+
+LLSD LLFloaterPathfindingLinksets::buildLinksetScrollListElement(const LLPathfindingLinksetPtr pLinksetPtr, const LLVector3 &pAvatarPosition) const
+{
+ LLSD columns;
+
+ if (pLinksetPtr->isTerrain())
+ {
+ columns[0]["column"] = "name";
+ columns[0]["value"] = getString("linkset_terrain_name");
+ columns[0]["font"] = "SANSSERIF";
+
+ columns[1]["column"] = "description";
+ columns[1]["value"] = getString("linkset_terrain_description");
+ columns[1]["font"] = "SANSSERIF";
+
+ columns[2]["column"] = "land_impact";
+ columns[2]["value"] = getString("linkset_terrain_land_impact");
+ columns[2]["font"] = "SANSSERIF";
+
+ columns[3]["column"] = "dist_from_you";
+ columns[3]["value"] = getString("linkset_terrain_dist_from_you");
+ columns[3]["font"] = "SANSSERIF";
+ }
+ else
+ {
+ columns[0]["column"] = "name";
+ columns[0]["value"] = pLinksetPtr->getName();
+ columns[0]["font"] = "SANSSERIF";
+
+ columns[1]["column"] = "description";
+ columns[1]["value"] = pLinksetPtr->getDescription();
+ columns[1]["font"] = "SANSSERIF";
+
+ columns[2]["column"] = "land_impact";
+ columns[2]["value"] = llformat("%1d", pLinksetPtr->getLandImpact());
+ columns[2]["font"] = "SANSSERIF";
+
+ columns[3]["column"] = "dist_from_you";
+ columns[3]["value"] = llformat("%1.0f m", dist_vec(pAvatarPosition, pLinksetPtr->getLocation()));
+ columns[3]["font"] = "SANSSERIF";
+ }
+
+ columns[4]["column"] = "linkset_use";
+ std::string linksetUse = getLinksetUseString(pLinksetPtr->getLinksetUse());
+ if (pLinksetPtr->isTerrain())
+ {
+ linksetUse += (" " + getString("linkset_is_terrain"));
+ }
+ else if (!pLinksetPtr->isModifiable())
+ {
+ linksetUse += (" " + getString("linkset_is_restricted_state"));
+ }
+ columns[4]["value"] = linksetUse;
+ columns[4]["font"] = "SANSSERIF";
+
+ columns[5]["column"] = "a_percent";
+ columns[5]["value"] = llformat("%3d", pLinksetPtr->getWalkabilityCoefficientA());
+ columns[5]["font"] = "SANSSERIF";
+
+ columns[6]["column"] = "b_percent";
+ columns[6]["value"] = llformat("%3d", pLinksetPtr->getWalkabilityCoefficientB());
+ columns[6]["font"] = "SANSSERIF";
+
+ columns[7]["column"] = "c_percent";
+ columns[7]["value"] = llformat("%3d", pLinksetPtr->getWalkabilityCoefficientC());
+ columns[7]["font"] = "SANSSERIF";
+
+ columns[8]["column"] = "d_percent";
+ columns[8]["value"] = llformat("%3d", pLinksetPtr->getWalkabilityCoefficientD());
+ columns[8]["font"] = "SANSSERIF";
+
+ LLSD element;
+ element["id"] = pLinksetPtr->getUUID().asString();
+ element["column"] = columns;
+
+ return element;
+}
+
+LLSD LLFloaterPathfindingLinksets::buildLinksetUseScrollListElement(const std::string &label, S32 value) const
+{
+ LLSD columns;
+
+ columns[0]["column"] = "name";
+ columns[0]["relwidth"] = static_cast<LLSD::Real>(100.0f);
+ columns[0]["value"] = label;
+ columns[0]["font"] = "SANSSERIF";
+
+ LLSD element;
+ element["value"] = value;
+ element["column"] = columns;
+
+ return element;
+}
+
+LLFloaterPathfindingLinksets::EAllowLinksetsUse LLFloaterPathfindingLinksets::getAllowLinksetUse() const
+{
+ EAllowLinksetsUse allowLinksetUse = kAllowLinksetUseAll;
+
+ std::vector<LLScrollListItem*> selectedItems = mLinksetsScrollList->getAllSelected();
+ if (!selectedItems.empty())
+ {
+ bool isAllLocked = true;
+ bool isAllPhantom = true;
+ bool isAllNonPhantom = true;
+ bool isAllTerrain = true;
+
+ for (std::vector<LLScrollListItem*>::const_iterator selectedItemIter = selectedItems.begin();
+ (isAllLocked || isAllPhantom || isAllNonPhantom) && (selectedItemIter != selectedItems.end()); ++selectedItemIter)
+ {
+ const LLScrollListItem *selectedItem = *selectedItemIter;
+ llassert(mLinksetsListPtr != NULL);
+ LLPathfindingLinksetList::const_iterator linksetIter = mLinksetsListPtr->find(selectedItem->getUUID().asString());
+ llassert(linksetIter != mLinksetsListPtr->end());
+ const LLPathfindingLinksetPtr linksetPtr = linksetIter->second;
+ if (!linksetPtr->isTerrain())
+ {
+ isAllTerrain = false;
+ }
+ if (!linksetPtr->isModifiable())
+ {
+ if (linksetPtr->isPhantom())
+ {
+ isAllNonPhantom = false;
+ }
+ else
+ {
+ isAllPhantom = false;
+ }
+ }
+ else
+ {
+ isAllLocked = false;
+ }
+ }
+
+ if (isAllTerrain)
+ {
+ allowLinksetUse = kAllowLinksetUseOnlyTerrain;
+ }
+ else if (isAllLocked)
+ {
+ if (isAllPhantom && !isAllNonPhantom)
+ {
+ allowLinksetUse = kAllowLinksetUseOnlyPhantom;
+ }
+ else if (isAllNonPhantom && !isAllPhantom)
+ {
+ allowLinksetUse = kAllowLinksetUseOnlyNonPhantom;
+ }
+ }
+ }
+
+ return allowLinksetUse;
+}
+
+bool LLFloaterPathfindingLinksets::doShowLinksetUseSetWarning(LLPathfindingLinkset::ELinksetUse linksetUse) const
+{
+ bool showWarning = false;
+
+ if (linksetUse != LLPathfindingLinkset::kUnknown)
+ {
+ std::vector<LLScrollListItem*> selectedItems = mLinksetsScrollList->getAllSelected();
+ if (!selectedItems.empty())
+ {
+ for (std::vector<LLScrollListItem*>::const_iterator selectedItemIter = selectedItems.begin();
+ !showWarning && (selectedItemIter != selectedItems.end()); ++selectedItemIter)
+ {
+ const LLScrollListItem *selectedItem = *selectedItemIter;
+ llassert(mLinksetsListPtr != NULL);
+ LLPathfindingLinksetList::const_iterator linksetIter = mLinksetsListPtr->find(selectedItem->getUUID().asString());
+ llassert(linksetIter != mLinksetsListPtr->end());
+ const LLPathfindingLinksetPtr linksetPtr = linksetIter->second;
+ showWarning = (!linksetPtr->isModifiable() && (linksetPtr->isPhantom() != LLPathfindingLinkset::isPhantom(linksetUse)));
+ }
+ }
+ }
+
+ return showWarning;
+}
+
+void LLFloaterPathfindingLinksets::updateStatusMessage()
+{
+ static const LLColor4 warningColor = LLUIColorTable::instance().getColor("DrYellow");
+
+ std::string statusText("");
+ LLStyle::Params styleParams;
+
+ switch (getMessagingState())
+ {
+ case kMessagingUnknown:
+ statusText = getString("linksets_messaging_initial");
+ break;
+ case kMessagingGetRequestSent :
+ statusText = getString("linksets_messaging_get_inprogress");
+ break;
+ case kMessagingGetError :
+ statusText = getString("linksets_messaging_get_error");
+ styleParams.color = warningColor;
+ break;
+ case kMessagingSetRequestSent :
+ statusText = getString("linksets_messaging_set_inprogress");
+ break;
+ case kMessagingSetError :
+ statusText = getString("linksets_messaging_set_error");
+ styleParams.color = warningColor;
+ break;
+ case kMessagingComplete :
+ if (mLinksetsScrollList->isEmpty())
+ {
+ statusText = getString("linksets_messaging_complete_none_found");
+ }
+ else
+ {
+ S32 numItems = mLinksetsScrollList->getItemCount();
+ S32 numSelectedItems = mLinksetsScrollList->getNumSelected();
+
+ LLLocale locale(LLStringUtil::getLocale());
+ std::string numItemsString;
+ LLResMgr::getInstance()->getIntegerString(numItemsString, numItems);
+
+ std::string numSelectedItemsString;
+ LLResMgr::getInstance()->getIntegerString(numSelectedItemsString, numSelectedItems);
+
+ LLStringUtil::format_map_t string_args;
+ string_args["[NUM_SELECTED]"] = numSelectedItemsString;
+ string_args["[NUM_TOTAL]"] = numItemsString;
+ statusText = getString("linksets_messaging_complete_available", string_args);
+ }
+ break;
+ case kMessagingNotEnabled :
+ statusText = getString("linksets_messaging_not_enabled");
+ styleParams.color = warningColor;
+ break;
+ default:
+ statusText = getString("linksets_messaging_initial");
+ llassert(0);
+ break;
+ }
+
+ mLinksetsStatus->setText((LLStringExplicit)statusText, styleParams);
+}
+
+void LLFloaterPathfindingLinksets::updateEnableStateOnListActions()
+{
+ switch (getMessagingState())
+ {
+ case kMessagingUnknown:
+ case kMessagingGetRequestSent :
+ case kMessagingSetRequestSent :
+ mRefreshListButton->setEnabled(FALSE);
+ mSelectAllButton->setEnabled(FALSE);
+ mSelectNoneButton->setEnabled(FALSE);
+ break;
+ case kMessagingGetError :
+ case kMessagingSetError :
+ case kMessagingNotEnabled :
+ mRefreshListButton->setEnabled(TRUE);
+ mSelectAllButton->setEnabled(FALSE);
+ mSelectNoneButton->setEnabled(FALSE);
+ break;
+ case kMessagingComplete :
+ {
+ int numItems = mLinksetsScrollList->getItemCount();
+ int numSelectedItems = mLinksetsScrollList->getNumSelected();
+ mRefreshListButton->setEnabled(TRUE);
+ mSelectAllButton->setEnabled(numSelectedItems < numItems);
+ mSelectNoneButton->setEnabled(numSelectedItems > 0);
+ }
+ break;
+ default:
+ llassert(0);
+ break;
+ }
+}
+
+void LLFloaterPathfindingLinksets::updateEnableStateOnEditFields()
+{
+ int numSelectedItems = mLinksetsScrollList->getNumSelected();
+ bool isEditEnabled = ((numSelectedItems > 0) && LLPathfindingManager::getInstance()->isAllowAlterPermanent());
+
+ mShowBeaconCheckBox->setEnabled(numSelectedItems > 0);
+ mTakeButton->setEnabled(isEditEnabled && tools_visible_take_object());
+ mTakeCopyButton->setEnabled(isEditEnabled && enable_object_take_copy());
+ mReturnButton->setEnabled(isEditEnabled && enable_object_return());
+ mDeleteButton->setEnabled(isEditEnabled && enable_object_delete());
+ mTeleportButton->setEnabled(numSelectedItems == 1);
+
+ mEditLinksetUse->setEnabled(isEditEnabled);
+
+ mLabelWalkabilityCoefficients->setEnabled(isEditEnabled);
+ mLabelEditA->setEnabled(isEditEnabled);
+ mLabelEditB->setEnabled(isEditEnabled);
+ mLabelEditC->setEnabled(isEditEnabled);
+ mLabelEditD->setEnabled(isEditEnabled);
+ mEditA->setEnabled(isEditEnabled);
+ mEditB->setEnabled(isEditEnabled);
+ mEditC->setEnabled(isEditEnabled);
+ mEditD->setEnabled(isEditEnabled);
+
+ mApplyEditsButton->setEnabled(isEditEnabled && (getMessagingState() == kMessagingComplete));
+}
+
+void LLFloaterPathfindingLinksets::applyEdit()
+{
+ LLPathfindingLinkset::ELinksetUse linksetUse = getEditLinksetUse();
+
+ if (doShowLinksetUseSetWarning(linksetUse))
+ {
+ LLPathfindingLinkset::ELinksetUse restrictedLinksetUse = LLPathfindingLinkset::getLinksetUseWithToggledPhantom(linksetUse);
+ LLSD substitutions;
+ substitutions["REQUESTED_TYPE"] = getLinksetUseString(linksetUse);
+ substitutions["RESTRICTED_TYPE"] = getLinksetUseString(restrictedLinksetUse);
+ LLNotificationsUtil::add("PathfindingLinksets_SetLinksetUseMismatchOnRestricted", substitutions, LLSD(), boost::bind(&LLFloaterPathfindingLinksets::handleApplyEdit, this, _1, _2));
+ }
+ else
+ {
+ doApplyEdit();
+ }
+}
+
+void LLFloaterPathfindingLinksets::handleApplyEdit(const LLSD &pNotification, const LLSD &pResponse)
+{
+ if (LLNotificationsUtil::getSelectedOption(pNotification, pResponse) == 0)
+ {
+ doApplyEdit();
+ }
+}
+
+void LLFloaterPathfindingLinksets::doApplyEdit()
+{
+ std::vector<LLScrollListItem*> selectedItems = mLinksetsScrollList->getAllSelected();
+ if (!selectedItems.empty())
+ {
+ LLPathfindingLinkset::ELinksetUse linksetUse = getEditLinksetUse();
+ const std::string &aString = mEditA->getText();
+ const std::string &bString = mEditB->getText();
+ const std::string &cString = mEditC->getText();
+ const std::string &dString = mEditD->getText();
+ S32 aValue = static_cast<S32>(atoi(aString.c_str()));
+ S32 bValue = static_cast<S32>(atoi(bString.c_str()));
+ S32 cValue = static_cast<S32>(atoi(cString.c_str()));
+ S32 dValue = static_cast<S32>(atoi(dString.c_str()));
+
+ LLPathfindingLinksetListPtr editListPtr(new LLPathfindingLinksetList());
+ for (std::vector<LLScrollListItem*>::const_iterator itemIter = selectedItems.begin();
+ itemIter != selectedItems.end(); ++itemIter)
+ {
+ const LLScrollListItem *listItem = *itemIter;
+ LLUUID uuid = listItem->getUUID();
+ const std::string &uuidString = uuid.asString();
+ llassert(mLinksetsListPtr != NULL);
+ LLPathfindingLinksetList::iterator linksetIter = mLinksetsListPtr->find(uuidString);
+ llassert(linksetIter != mLinksetsListPtr->end());
+ LLPathfindingLinksetPtr linksetPtr = linksetIter->second;
+ editListPtr->insert(std::pair<std::string, LLPathfindingLinksetPtr>(uuidString, linksetPtr));
+ }
+
+ requestSetLinksets(editListPtr, linksetUse, aValue, bValue, cValue, dValue);
+ }
+}
+
+std::string LLFloaterPathfindingLinksets::getLinksetUseString(LLPathfindingLinkset::ELinksetUse pLinksetUse) const
+{
+ std::string linksetUse;
+
+ switch (pLinksetUse)
+ {
+ case LLPathfindingLinkset::kWalkable :
+ linksetUse = getString("linkset_use_walkable");
+ break;
+ case LLPathfindingLinkset::kStaticObstacle :
+ linksetUse = getString("linkset_use_static_obstacle");
+ break;
+ case LLPathfindingLinkset::kDynamicObstacle :
+ linksetUse = getString("linkset_use_dynamic_obstacle");
+ break;
+ case LLPathfindingLinkset::kMaterialVolume :
+ linksetUse = getString("linkset_use_material_volume");
+ break;
+ case LLPathfindingLinkset::kExclusionVolume :
+ linksetUse = getString("linkset_use_exclusion_volume");
+ break;
+ case LLPathfindingLinkset::kDynamicPhantom :
+ linksetUse = getString("linkset_use_dynamic_phantom");
+ break;
+ case LLPathfindingLinkset::kUnknown :
+ default :
+ linksetUse = getString("linkset_use_dynamic_obstacle");
+ llassert(0);
+ break;
+ }
+
+ return linksetUse;
+}
+
+LLPathfindingLinkset::ELinksetUse LLFloaterPathfindingLinksets::getFilterLinksetUse() const
+{
+ return convertToLinksetUse(mFilterByLinksetUse->getValue());
+}
+
+void LLFloaterPathfindingLinksets::setFilterLinksetUse(LLPathfindingLinkset::ELinksetUse pLinksetUse)
+{
+ mFilterByLinksetUse->setValue(convertToXuiValue(pLinksetUse));
+}
+
+LLPathfindingLinkset::ELinksetUse LLFloaterPathfindingLinksets::getEditLinksetUse() const
+{
+ return convertToLinksetUse(mEditLinksetUse->getValue());
+}
+
+void LLFloaterPathfindingLinksets::setEditLinksetUse(LLPathfindingLinkset::ELinksetUse pLinksetUse)
+{
+ mEditLinksetUse->setValue(convertToXuiValue(pLinksetUse));
+}
+
+LLPathfindingLinkset::ELinksetUse LLFloaterPathfindingLinksets::convertToLinksetUse(LLSD pXuiValue) const
+{
+ LLPathfindingLinkset::ELinksetUse linkUse;
+
+ switch (pXuiValue.asInteger())
+ {
+ case XUI_LINKSET_USE_NONE :
+ linkUse = LLPathfindingLinkset::kUnknown;
+ break;
+ case XUI_LINKSET_USE_WALKABLE :
+ linkUse = LLPathfindingLinkset::kWalkable;
+ break;
+ case XUI_LINKSET_USE_STATIC_OBSTACLE :
+ linkUse = LLPathfindingLinkset::kStaticObstacle;
+ break;
+ case XUI_LINKSET_USE_DYNAMIC_OBSTACLE :
+ linkUse = LLPathfindingLinkset::kDynamicObstacle;
+ break;
+ case XUI_LINKSET_USE_MATERIAL_VOLUME :
+ linkUse = LLPathfindingLinkset::kMaterialVolume;
+ break;
+ case XUI_LINKSET_USE_EXCLUSION_VOLUME :
+ linkUse = LLPathfindingLinkset::kExclusionVolume;
+ break;
+ case XUI_LINKSET_USE_DYNAMIC_PHANTOM :
+ linkUse = LLPathfindingLinkset::kDynamicPhantom;
+ break;
+ default :
+ linkUse = LLPathfindingLinkset::kUnknown;
+ llassert(0);
+ break;
+ }
+
+ return linkUse;
+}
+
+LLSD LLFloaterPathfindingLinksets::convertToXuiValue(LLPathfindingLinkset::ELinksetUse pLinksetUse) const
+{
+ LLSD xuiValue;
+
+ switch (pLinksetUse)
+ {
+ case LLPathfindingLinkset::kUnknown :
+ xuiValue = XUI_LINKSET_USE_NONE;
+ break;
+ case LLPathfindingLinkset::kWalkable :
+ xuiValue = XUI_LINKSET_USE_WALKABLE;
+ break;
+ case LLPathfindingLinkset::kStaticObstacle :
+ xuiValue = XUI_LINKSET_USE_STATIC_OBSTACLE;
+ break;
+ case LLPathfindingLinkset::kDynamicObstacle :
+ xuiValue = XUI_LINKSET_USE_DYNAMIC_OBSTACLE;
+ break;
+ case LLPathfindingLinkset::kMaterialVolume :
+ xuiValue = XUI_LINKSET_USE_MATERIAL_VOLUME;
+ break;
+ case LLPathfindingLinkset::kExclusionVolume :
+ xuiValue = XUI_LINKSET_USE_EXCLUSION_VOLUME;
+ break;
+ case LLPathfindingLinkset::kDynamicPhantom :
+ xuiValue = XUI_LINKSET_USE_DYNAMIC_PHANTOM;
+ break;
+ default :
+ xuiValue = XUI_LINKSET_USE_NONE;
+ llassert(0);
+ break;
+ }
+
+ return xuiValue;
+}
diff --git a/indra/newview/llfloaterpathfindinglinksets.h b/indra/newview/llfloaterpathfindinglinksets.h new file mode 100644 index 0000000000..6432652568 --- /dev/null +++ b/indra/newview/llfloaterpathfindinglinksets.h @@ -0,0 +1,186 @@ +/**
+ * @file llfloaterpathfindinglinksets.h
+ * @author William Todd Stinson
+ * @brief "Pathfinding linksets" floater, allowing manipulation of the Havok AI pathfinding settings.
+ *
+ * $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$
+ */
+
+#ifndef LL_LLFLOATERPATHFINDINGLINKSETS_H
+#define LL_LLFLOATERPATHFINDINGLINKSETS_H
+
+#include "llfloater.h"
+#include "lluuid.h"
+#include "llselectmgr.h"
+#include "llpathfindinglinkset.h"
+#include "llpathfindinglinksetlist.h"
+#include "llpathfindingmanager.h"
+
+class LLSD;
+class LLUICtrl;
+class LLTextBase;
+class LLScrollListCtrl;
+class LLScrollListItem;
+class LLLineEditor;
+class LLComboBox;
+class LLCheckBoxCtrl;
+class LLButton;
+
+class LLFloaterPathfindingLinksets
+: public LLFloater
+{
+ friend class LLFloaterReg;
+
+public:
+ typedef enum
+ {
+ kMessagingUnknown,
+ kMessagingGetRequestSent,
+ kMessagingGetError,
+ kMessagingSetRequestSent,
+ kMessagingSetError,
+ kMessagingComplete,
+ kMessagingNotEnabled
+ } EMessagingState;
+
+ virtual BOOL postBuild();
+ virtual void onOpen(const LLSD& pKey);
+ virtual void onClose(bool pAppQuitting);
+ virtual void draw();
+
+ static void openLinksetsEditor();
+
+ EMessagingState getMessagingState() const;
+ bool isMessagingInProgress() const;
+
+protected:
+
+private:
+ typedef enum
+ {
+ kAllowLinksetUseAll,
+ kAllowLinksetUseOnlyNonPhantom,
+ kAllowLinksetUseOnlyPhantom,
+ kAllowLinksetUseOnlyTerrain
+ } EAllowLinksetsUse;
+
+ LLLineEditor *mFilterByName;
+ LLLineEditor *mFilterByDescription;
+ LLComboBox *mFilterByLinksetUse;
+ LLScrollListCtrl *mLinksetsScrollList;
+ LLTextBase *mLinksetsStatus;
+ LLButton *mRefreshListButton;
+ LLButton *mSelectAllButton;
+ LLButton *mSelectNoneButton;
+ LLCheckBoxCtrl *mShowBeaconCheckBox;
+ LLButton *mTakeButton;
+ LLButton *mTakeCopyButton;
+ LLButton *mReturnButton;
+ LLButton *mDeleteButton;
+ LLButton *mTeleportButton;
+ LLComboBox *mEditLinksetUse;
+ LLScrollListItem *mEditLinksetUseUnset;
+ LLScrollListItem *mEditLinksetUseWalkable;
+ LLScrollListItem *mEditLinksetUseStaticObstacle;
+ LLScrollListItem *mEditLinksetUseDynamicObstacle;
+ LLScrollListItem *mEditLinksetUseMaterialVolume;
+ LLScrollListItem *mEditLinksetUseExclusionVolume;
+ LLScrollListItem *mEditLinksetUseDynamicPhantom;
+ LLTextBase *mLabelWalkabilityCoefficients;
+ LLTextBase *mLabelEditA;
+ LLLineEditor *mEditA;
+ LLTextBase *mLabelEditB;
+ LLLineEditor *mEditB;
+ LLTextBase *mLabelEditC;
+ LLLineEditor *mEditC;
+ LLTextBase *mLabelEditD;
+ LLLineEditor *mEditD;
+ LLButton *mApplyEditsButton;
+
+ EMessagingState mMessagingState;
+ LLPathfindingLinksetListPtr mLinksetsListPtr;
+ LLObjectSelectionHandle mLinksetsSelection;
+ LLPathfindingManager::agent_state_slot_t mAgentStateSlot;
+
+ // Does its own instance management, so clients not allowed
+ // to allocate or destroy.
+ LLFloaterPathfindingLinksets(const LLSD& pSeed);
+ virtual ~LLFloaterPathfindingLinksets();
+
+ void setMessagingState(EMessagingState pMessagingState);
+ void requestGetLinksets();
+ void requestSetLinksets(LLPathfindingLinksetListPtr pLinksetList, LLPathfindingLinkset::ELinksetUse pLinksetUse, S32 pA, S32 pB, S32 pC, S32 pD);
+ void handleNewLinksets(LLPathfindingManager::ELinksetsRequestStatus pLinksetsRequestStatus, LLPathfindingLinksetListPtr pLinksetsListPtr);
+ void handleUpdateLinksets(LLPathfindingManager::ELinksetsRequestStatus pLinksetsRequestStatus, LLPathfindingLinksetListPtr pLinksetsListPtr);
+
+ void onApplyAllFilters();
+ void onClearFiltersClicked();
+ void onLinksetsSelectionChange();
+ void onRefreshLinksetsClicked();
+ void onSelectAllLinksetsClicked();
+ void onSelectNoneLinksetsClicked();
+ void onTakeClicked();
+ void onTakeCopyClicked();
+ void onReturnClicked();
+ void onDeleteClicked();
+ void onTeleportClicked();
+ void onWalkabilityCoefficientEntered(LLUICtrl *pUICtrl);
+ void onApplyChangesClicked();
+ void onAgentStateCB(LLPathfindingManager::EAgentState pAgentState);
+
+ void applyFilters();
+ void clearFilters();
+
+ void selectAllLinksets();
+ void selectNoneLinksets();
+ void clearLinksets();
+
+ void updateControls();
+ void updateEditFieldValues();
+ void updateScrollList();
+ LLSD buildLinksetScrollListElement(const LLPathfindingLinksetPtr pLinksetPtr, const LLVector3 &pAvatarPosition) const;
+ LLSD buildLinksetUseScrollListElement(const std::string &label, S32 value) const;
+
+ EAllowLinksetsUse getAllowLinksetUse() const;
+ bool doShowLinksetUseSetWarning(LLPathfindingLinkset::ELinksetUse linksetUse) const;
+
+ void updateStatusMessage();
+ void updateEnableStateOnListActions();
+ void updateEnableStateOnEditFields();
+
+ void applyEdit();
+ void handleApplyEdit(const LLSD &pNotification, const LLSD &pResponse);
+ void doApplyEdit();
+
+ std::string getLinksetUseString(LLPathfindingLinkset::ELinksetUse pLinksetUse) const;
+
+ LLPathfindingLinkset::ELinksetUse getFilterLinksetUse() const;
+ void setFilterLinksetUse(LLPathfindingLinkset::ELinksetUse pLinksetUse);
+
+ LLPathfindingLinkset::ELinksetUse getEditLinksetUse() const;
+ void setEditLinksetUse(LLPathfindingLinkset::ELinksetUse pLinksetUse);
+
+ LLPathfindingLinkset::ELinksetUse convertToLinksetUse(LLSD pXuiValue) const;
+ LLSD convertToXuiValue(LLPathfindingLinkset::ELinksetUse pLinksetUse) const;
+};
+
+#endif // LL_LLFLOATERPATHFINDINGLINKSETS_H
diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index da81bb057b..4139b9725b 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -35,7 +35,7 @@ #define LLCONVEXDECOMPINTER_STATIC 1 -#include "llconvexdecomposition.h" +#include "LLConvexDecomposition.h" #include "lluploadfloaterobservers.h" class LLVOVolume; diff --git a/indra/newview/llnavmeshstation.cpp b/indra/newview/llnavmeshstation.cpp new file mode 100644 index 0000000000..54a945e562 --- /dev/null +++ b/indra/newview/llnavmeshstation.cpp @@ -0,0 +1,134 @@ +/** + * @file llnavmeshstation.cpp + * @brief + * + * $LicenseInfo:firstyear=2005&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 "llnavmeshstation.h" +#include "llcurl.h" +#include "LLPathingLib.h" +#include "llagent.h" +#include "llviewerregion.h" +#include "llsdutil.h" +#include "llfloaterpathfindingconsole.h" +#include "llsdserialize.h" +//=============================================================================== +LLNavMeshStation::LLNavMeshStation() +{ +} +//=============================================================================== +class LLNavMeshDownloadResponder : public LLCurl::Responder +{ +public: + LLNavMeshDownloadResponder( const LLHandle<LLNavMeshDownloadObserver>& observer_handle, int dir ) + : mObserverHandle( observer_handle ) + , mDir( dir ) + { + } + + void error( U32 statusNum, const std::string& reason ) + { + llwarns << "Transport error "<<reason<<llendl; + } + + void result( const LLSD& content ) + { + llinfos<<"Content received"<<llendl; + if ( content.has("error") ) + { + llwarns << "Error on fetched data"<< llendl; + //llinfos<<"LLsd buffer on error"<<ll_pretty_print_sd(content)<<llendl; + } + else + { + LLNavMeshDownloadObserver* pObserver = mObserverHandle.get(); + if ( pObserver ) + { + if ( content.has("navmesh_data") ) + { + const std::vector<U8>& value = content["navmesh_data"].asBinary();
+ unsigned int binSize = value.size();
+ U8* pBinBuffer = new U8[binSize];
+ memcpy( &pBinBuffer[0], &value[0], binSize );
+ std::string newStr((char*) pBinBuffer, binSize );
+ std::istringstream streamdecomp( newStr );
+ unsigned int decompBinSize = 0;
+ bool valid = false;
+ if ( pBinBuffer )
+ {
+ delete [] pBinBuffer ;
+ }
+ U8* pUncompressedNavMeshContainer = unzip_llsdNavMesh( valid, decompBinSize, streamdecomp, binSize ) ;
+ if ( !valid )
+ {
+ if ( pUncompressedNavMeshContainer )
+ {
+ free( pUncompressedNavMeshContainer );
+ }
+ llwarns << "Unable to decompress the navmesh llsd." << llendl;
+ pObserver->getPathfindingConsole()->setHasNoNavMesh();
+ return;
+ }
+ else
+ {
+ if ( pUncompressedNavMeshContainer )
+ {
+ std::vector<U8> lsd;
+ lsd.resize( decompBinSize );
+ memcpy( &lsd[0], &pUncompressedNavMeshContainer[0], decompBinSize );
+ LLPathingLib::getInstance()->extractNavMeshSrcFromLLSD( lsd, mDir );
+ pObserver->getPathfindingConsole()->setHasNavMeshReceived();
+ free( pUncompressedNavMeshContainer );
+ }
+ } + } + else + { + llwarns<<"No mesh data received"<<llendl; + pObserver->getPathfindingConsole()->setHasNoNavMesh(); + } + } + } +} +private: + //Observer handle + LLHandle<LLNavMeshDownloadObserver> mObserverHandle; + int mDir; +}; +//=============================================================================== +void LLNavMeshStation::downloadNavMeshSrc( const LLHandle<LLNavMeshDownloadObserver>& observerHandle, int dir ) +{ + if ( mNavMeshDownloadURL.empty() ) + { + llinfos << "Unable to upload navmesh because of missing URL" << llendl; + } + else + { + LLSD data; + data["agent_id"] = gAgent.getID(); + data["region_id"] = gAgent.getRegion()->getRegionID(); + LLHTTPClient::post(mNavMeshDownloadURL, data, new LLNavMeshDownloadResponder( observerHandle, dir ) ); + } +} +//=============================================================================== diff --git a/indra/newview/llnavmeshstation.h b/indra/newview/llnavmeshstation.h new file mode 100644 index 0000000000..72bf725688 --- /dev/null +++ b/indra/newview/llnavmeshstation.h @@ -0,0 +1,101 @@ +/** + * @file llnavmeshstation.h + * @brief Client-side navmesh support + * + * $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 LL_NAV_MESH_STATION_H +#define LL_NAV_MESH_STATION_H + +//=============================================================================== +#include "llhandle.h" +//=============================================================================== +class LLCurlRequest; +class LLFloaterPathfindingConsole; +//=============================================================================== +class LLNavMeshObserver +{ +public: + //Ctor + LLNavMeshObserver() + : mPathfindingConsole(NULL) + { mObserverHandle.bind(this); } + //Dtor + virtual ~LLNavMeshObserver() {} + //Accessor for the observers handle + const LLHandle<LLNavMeshObserver>& getObserverHandle() const { return mObserverHandle; } + LLFloaterPathfindingConsole *getPathfindingConsole() {return mPathfindingConsole;} + void setPathfindingConsole(LLFloaterPathfindingConsole *pPathfindingConsole) {mPathfindingConsole = pPathfindingConsole;} + +protected: + LLRootHandle<LLNavMeshObserver> mObserverHandle; + LLFloaterPathfindingConsole *mPathfindingConsole; +}; +//=============================================================================== +class LLNavMeshDownloadObserver +{ +public: + //Ctor + LLNavMeshDownloadObserver() { mObserverHandle.bind(this); } + //Dtor + virtual ~LLNavMeshDownloadObserver() {} + //Accessor for the observers handle + const LLHandle<LLNavMeshDownloadObserver>& getObserverHandle() const { return mObserverHandle; } + LLFloaterPathfindingConsole *getPathfindingConsole() {return mPathfindingConsole;} + void setPathfindingConsole(LLFloaterPathfindingConsole *pPathfindingConsole) {mPathfindingConsole = pPathfindingConsole;} + +protected: + LLRootHandle<LLNavMeshDownloadObserver> mObserverHandle; + LLFloaterPathfindingConsole *mPathfindingConsole; +}; +//=============================================================================== +class LLNavMeshStation : public LLSingleton<LLNavMeshStation> +{ +public: + //Ctor + LLNavMeshStation(); + //Facilitates the posting of a prepopulated llsd block to an existing url + bool postNavMeshToServer( LLSD& data, const LLHandle<LLNavMeshObserver>& observerHandle ); + //Setter for the navmesh upload url + void setNavMeshUploadURL( std::string& url ) { mNavMeshUploadURL = url; } + //Setter for the navmesh download url + void setNavMeshDownloadURL( std::string& url ) { mNavMeshDownloadURL = url; } + //Callback to handle the requested src data for this regions navmesh src + static void processNavMeshSrc( LLMessageSystem* msg, void** ); + //Initiate download of the navmesh source from the server + void downloadNavMeshSrc( const LLHandle<LLNavMeshDownloadObserver>& observerHandle, int dir ); + +protected: + //Curl object to facilitate posts to server + LLCurlRequest* mCurlRequest; + //Maximum time in seconds to execute an uploading request. + S32 mMeshUploadTimeOut ; + //URL used for uploading viewer generated navmesh + std::string mNavMeshUploadURL; + //URL used for download the src data for a navmesh + std::string mNavMeshDownloadURL; + +}; +//=============================================================================== +#endif //LL_NAV_MESH_STATION_H + diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index 1f77e7a602..ee62a39f75 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -283,7 +283,6 @@ LLPanelObject::LLPanelObject() mIsPhysical(FALSE), mIsTemporary(FALSE), mIsPhantom(FALSE), - mCastShadows(TRUE), mSelectedType(MI_BOX), mSculptTextureRevert(LLUUID::null), mSculptTypeRevert(0) @@ -497,7 +496,7 @@ void LLPanelObject::getState( ) BOOL is_flexible = volobjp && volobjp->isFlexible(); // Physics checkbox - mIsPhysical = root_objectp->usePhysics(); + mIsPhysical = root_objectp->flagUsePhysics(); mCheckPhysics->set( mIsPhysical ); mCheckPhysics->setEnabled( roots_selected>0 && (editable || gAgent.isGodlike()) @@ -512,12 +511,6 @@ void LLPanelObject::getState( ) mCheckPhantom->setEnabled( roots_selected>0 && editable && !is_flexible ); -#if 0 // 1.9.2 - mCastShadows = root_objectp->flagCastShadows(); - mCheckCastShadows->set( mCastShadows ); - mCheckCastShadows->setEnabled( roots_selected==1 && editable ); -#endif - //---------------------------------------------------------------------------- S32 selected_item = MI_BOX; @@ -1214,22 +1207,6 @@ void LLPanelObject::sendIsPhantom() } } -void LLPanelObject::sendCastShadows() -{ - BOOL value = mCheckCastShadows->get(); - if( mCastShadows != value ) - { - LLSelectMgr::getInstance()->selectionUpdateCastShadows(value); - mCastShadows = value; - - llinfos << "update cast shadows sent" << llendl; - } - else - { - llinfos << "update cast shadows not changed" << llendl; - } -} - // static void LLPanelObject::onCommitParametric( LLUICtrl* ctrl, void* userdata ) { @@ -1886,10 +1863,6 @@ void LLPanelObject::clearCtrls() mCheckPhantom ->set(FALSE); mCheckPhantom ->setEnabled( FALSE ); -#if 0 // 1.9.2 - mCheckCastShadows->set(FALSE); - mCheckCastShadows->setEnabled( FALSE ); -#endif // Disable text labels mLabelPosition ->setEnabled( FALSE ); mLabelSize ->setEnabled( FALSE ); @@ -1977,14 +1950,6 @@ void LLPanelObject::onCommitPhantom( LLUICtrl* ctrl, void* userdata ) self->sendIsPhantom(); } -// static -void LLPanelObject::onCommitCastShadows( LLUICtrl* ctrl, void* userdata ) -{ - LLPanelObject* self = (LLPanelObject*) userdata; - self->sendCastShadows(); -} - - void LLPanelObject::onSelectSculpt(const LLSD& data) { LLTextureCtrl* mTextureCtrl = getChild<LLTextureCtrl>("sculpt texture control"); diff --git a/indra/newview/llpanelobject.h b/indra/newview/llpanelobject.h index 475dfdaedb..86b59d4ff9 100644 --- a/indra/newview/llpanelobject.h +++ b/indra/newview/llpanelobject.h @@ -64,7 +64,6 @@ public: static void onCommitRotation( LLUICtrl* ctrl, void* userdata); static void onCommitTemporary( LLUICtrl* ctrl, void* userdata); static void onCommitPhantom( LLUICtrl* ctrl, void* userdata); - static void onCommitCastShadows( LLUICtrl* ctrl, void* userdata); static void onCommitPhysics( LLUICtrl* ctrl, void* userdata); static void onCommitParametric(LLUICtrl* ctrl, void* userdata); @@ -87,7 +86,6 @@ protected: void sendIsTemporary(); void sendIsPhantom(); - void sendCastShadows(); void sendSculpt(); void getVolumeParams(LLVolumeParams& volume_params); @@ -153,7 +151,6 @@ protected: LLCheckBoxCtrl *mCheckPhysics; LLCheckBoxCtrl *mCheckTemporary; LLCheckBoxCtrl *mCheckPhantom; - LLCheckBoxCtrl *mCheckCastShadows; LLTextureCtrl *mCtrlSculptTexture; LLTextBox *mLabelSculptType; @@ -165,7 +162,6 @@ protected: BOOL mIsPhysical; // to avoid sending "physical" when not changed BOOL mIsTemporary; // to avoid sending "temporary" when not changed BOOL mIsPhantom; // to avoid sending "phantom" when not changed - BOOL mCastShadows; // to avoid sending "cast shadows" when not changed S32 mSelectedType; // So we know what selected type we last were LLUUID mSculptTextureRevert; // so we can revert the sculpt texture on cancel diff --git a/indra/newview/llpathfindingcharacter.cpp b/indra/newview/llpathfindingcharacter.cpp new file mode 100644 index 0000000000..afa07457bc --- /dev/null +++ b/indra/newview/llpathfindingcharacter.cpp @@ -0,0 +1,103 @@ +/**
+ * @file llpathfindingcharacter.cpp
+ * @author William Todd Stinson
+ * @brief Definition of a pathfinding character that contains various properties required for havok pathfinding.
+ *
+ * $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 "llpathfindingcharacter.h"
+#include "llsd.h"
+#include "v3math.h"
+#include "lluuid.h"
+#include "llavatarname.h"
+#include "llavatarnamecache.h"
+
+#define CHARACTER_NAME_FIELD "name"
+#define CHARACTER_DESCRIPTION_FIELD "description"
+#define CHARACTER_OWNER_FIELD "owner"
+#define CHARACTER_CPU_TIME_FIELD "cpu_time"
+#define CHARACTER_POSITION_FIELD "position"
+
+//---------------------------------------------------------------------------
+// LLPathfindingCharacter
+//---------------------------------------------------------------------------
+
+LLPathfindingCharacter::LLPathfindingCharacter(const std::string &pUUID, const LLSD& pCharacterItem)
+ : mUUID(pUUID),
+ mName(),
+ mDescription(),
+ mOwnerUUID(),
+ mOwnerName(),
+ mCPUTime(0U),
+ mLocation()
+{
+ llassert(pCharacterItem.has(CHARACTER_NAME_FIELD));
+ llassert(pCharacterItem.get(CHARACTER_NAME_FIELD).isString());
+ mName = pCharacterItem.get(CHARACTER_NAME_FIELD).asString();
+
+ llassert(pCharacterItem.has(CHARACTER_DESCRIPTION_FIELD));
+ llassert(pCharacterItem.get(CHARACTER_DESCRIPTION_FIELD).isString());
+ mDescription = pCharacterItem.get(CHARACTER_DESCRIPTION_FIELD).asString();
+
+ llassert(pCharacterItem.has(CHARACTER_OWNER_FIELD));
+ llassert(pCharacterItem.get(CHARACTER_OWNER_FIELD).isUUID());
+ mOwnerUUID = pCharacterItem.get(CHARACTER_OWNER_FIELD).asUUID();
+ LLAvatarNameCache::get(mOwnerUUID, &mOwnerName);
+
+ llassert(pCharacterItem.has(CHARACTER_CPU_TIME_FIELD));
+ llassert(pCharacterItem.get(CHARACTER_CPU_TIME_FIELD).isReal());
+ mCPUTime = pCharacterItem.get(CHARACTER_CPU_TIME_FIELD).asReal();
+
+ llassert(pCharacterItem.has(CHARACTER_POSITION_FIELD));
+ llassert(pCharacterItem.get(CHARACTER_POSITION_FIELD).isArray());
+ mLocation.setValue(pCharacterItem.get(CHARACTER_POSITION_FIELD));
+}
+
+LLPathfindingCharacter::LLPathfindingCharacter(const LLPathfindingCharacter& pOther)
+ : mUUID(pOther.mUUID),
+ mName(pOther.mName),
+ mDescription(pOther.mDescription),
+ mOwnerUUID(pOther.mOwnerUUID),
+ mOwnerName(pOther.mOwnerName),
+ mCPUTime(pOther.mCPUTime),
+ mLocation(pOther.mLocation)
+{
+}
+
+LLPathfindingCharacter::~LLPathfindingCharacter()
+{
+}
+
+LLPathfindingCharacter& LLPathfindingCharacter::operator =(const LLPathfindingCharacter& pOther)
+{
+ mUUID = pOther.mUUID;
+ mName = pOther.mName;
+ mDescription = pOther.mDescription;
+ mOwnerUUID = pOther.mOwnerUUID;
+ mOwnerName = pOther.mOwnerName;
+ mCPUTime = pOther.mCPUTime;
+ mLocation = pOther.mLocation;
+
+ return *this;
+}
diff --git a/indra/newview/llpathfindingcharacter.h b/indra/newview/llpathfindingcharacter.h new file mode 100644 index 0000000000..9b0a7bae30 --- /dev/null +++ b/indra/newview/llpathfindingcharacter.h @@ -0,0 +1,66 @@ +/**
+ * @file llpathfindingcharacter.h
+ * @author William Todd Stinson
+ * @brief Definition of a pathfinding character that contains various properties required for havok pathfinding.
+ *
+ * $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$
+ */
+
+#ifndef LL_LLPATHFINDINGCHARACTER_H
+#define LL_LLPATHFINDINGCHARACTER_H
+
+#include "v3math.h"
+#include "lluuid.h"
+#include "llavatarname.h"
+
+class LLSD;
+class LLAvatarName;
+
+class LLPathfindingCharacter
+{
+public:
+ LLPathfindingCharacter(const std::string &pUUID, const LLSD &pCharacterItem);
+ LLPathfindingCharacter(const LLPathfindingCharacter& pOther);
+ virtual ~LLPathfindingCharacter();
+
+ LLPathfindingCharacter& operator = (const LLPathfindingCharacter& pOther);
+
+ inline const LLUUID& getUUID() const {return mUUID;};
+ inline const std::string& getName() const {return mName;};
+ inline const std::string& getDescription() const {return mDescription;};
+ inline const std::string getOwnerName() const {return mOwnerName.getCompleteName();};
+ inline F32 getCPUTime() const {return mCPUTime;};
+ inline const LLVector3& getLocation() const {return mLocation;};
+
+protected:
+
+private:
+ LLUUID mUUID;
+ std::string mName;
+ std::string mDescription;
+ LLUUID mOwnerUUID;
+ LLAvatarName mOwnerName;
+ F32 mCPUTime;
+ LLVector3 mLocation;
+};
+
+#endif // LL_LLPATHFINDINGCHARACTER_H
diff --git a/indra/newview/llpathfindinglinkset.cpp b/indra/newview/llpathfindinglinkset.cpp new file mode 100644 index 0000000000..1578494241 --- /dev/null +++ b/indra/newview/llpathfindinglinkset.cpp @@ -0,0 +1,326 @@ +/**
+ * @file llpathfindinglinksets.cpp
+ * @author William Todd Stinson
+ * @brief Definition of a pathfinding linkset that contains various properties required for havok pathfinding.
+ *
+ * $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 "llpathfindinglinkset.h"
+#include "llsd.h"
+#include "v3math.h"
+#include "lluuid.h"
+
+#define LINKSET_NAME_FIELD "name"
+#define LINKSET_DESCRIPTION_FIELD "description"
+#define LINKSET_LAND_IMPACT_FIELD "landimpact"
+#define LINKSET_MODIFIABLE_FIELD "modifiable"
+#define LINKSET_PERMANENT_FIELD "permanent"
+#define LINKSET_WALKABLE_FIELD "walkable"
+#define LINKSET_PHANTOM_FIELD "phantom"
+#define LINKSET_WALKABILITY_A_FIELD "A"
+#define LINKSET_WALKABILITY_B_FIELD "B"
+#define LINKSET_WALKABILITY_C_FIELD "C"
+#define LINKSET_WALKABILITY_D_FIELD "D"
+#define LINKSET_POSITION_FIELD "position"
+
+//---------------------------------------------------------------------------
+// LLPathfindingLinkset
+//---------------------------------------------------------------------------
+
+const S32 LLPathfindingLinkset::MIN_WALKABILITY_VALUE(0);
+const S32 LLPathfindingLinkset::MAX_WALKABILITY_VALUE(100);
+
+LLPathfindingLinkset::LLPathfindingLinkset(const LLSD& pTerrainLinksetItem)
+ : mUUID(),
+ mIsTerrain(true),
+ mName(),
+ mDescription(),
+ mLandImpact(0U),
+ mLocation(LLVector3::zero),
+ mIsModifiable(TRUE),
+ mLinksetUse(kUnknown),
+ mWalkabilityCoefficientA(MIN_WALKABILITY_VALUE),
+ mWalkabilityCoefficientB(MIN_WALKABILITY_VALUE),
+ mWalkabilityCoefficientC(MIN_WALKABILITY_VALUE),
+ mWalkabilityCoefficientD(MIN_WALKABILITY_VALUE)
+{
+ parsePathfindingData(pTerrainLinksetItem);
+}
+
+LLPathfindingLinkset::LLPathfindingLinkset(const std::string &pUUID, const LLSD& pLinksetItem)
+ : mUUID(pUUID),
+ mIsTerrain(false),
+ mName(),
+ mDescription(),
+ mLandImpact(0U),
+ mLocation(LLVector3::zero),
+ mIsModifiable(TRUE),
+ mLinksetUse(kUnknown),
+ mWalkabilityCoefficientA(MIN_WALKABILITY_VALUE),
+ mWalkabilityCoefficientB(MIN_WALKABILITY_VALUE),
+ mWalkabilityCoefficientC(MIN_WALKABILITY_VALUE),
+ mWalkabilityCoefficientD(MIN_WALKABILITY_VALUE)
+{
+ parseObjectData(pLinksetItem);
+ parsePathfindingData(pLinksetItem);
+}
+
+LLPathfindingLinkset::LLPathfindingLinkset(const LLPathfindingLinkset& pOther)
+ : mUUID(pOther.mUUID),
+ mName(pOther.mName),
+ mDescription(pOther.mDescription),
+ mLandImpact(pOther.mLandImpact),
+ mLocation(pOther.mLocation),
+ mIsModifiable(pOther.mIsModifiable),
+ mLinksetUse(pOther.mLinksetUse),
+ mWalkabilityCoefficientA(pOther.mWalkabilityCoefficientA),
+ mWalkabilityCoefficientB(pOther.mWalkabilityCoefficientB),
+ mWalkabilityCoefficientC(pOther.mWalkabilityCoefficientC),
+ mWalkabilityCoefficientD(pOther.mWalkabilityCoefficientD)
+{
+}
+
+LLPathfindingLinkset::~LLPathfindingLinkset()
+{
+}
+
+LLPathfindingLinkset& LLPathfindingLinkset::operator =(const LLPathfindingLinkset& pOther)
+{
+ mUUID = pOther.mUUID;
+ mName = pOther.mName;
+ mDescription = pOther.mDescription;
+ mLandImpact = pOther.mLandImpact;
+ mLocation = pOther.mLocation;
+ mIsModifiable = pOther.mIsModifiable;
+ mLinksetUse = pOther.mLinksetUse;
+ mWalkabilityCoefficientA = pOther.mWalkabilityCoefficientA;
+ mWalkabilityCoefficientB = pOther.mWalkabilityCoefficientB;
+ mWalkabilityCoefficientC = pOther.mWalkabilityCoefficientC;
+ mWalkabilityCoefficientD = pOther.mWalkabilityCoefficientD;
+
+ return *this;
+}
+
+BOOL LLPathfindingLinkset::isPhantom() const
+{
+ return isPhantom(getLinksetUse());
+}
+
+BOOL LLPathfindingLinkset::isPhantom(ELinksetUse pLinksetUse)
+{
+ BOOL retVal;
+
+ switch (pLinksetUse)
+ {
+ case kWalkable :
+ case kStaticObstacle :
+ case kDynamicObstacle :
+ retVal = false;
+ break;
+ case kMaterialVolume :
+ case kExclusionVolume :
+ case kDynamicPhantom :
+ retVal = true;
+ break;
+ case kUnknown :
+ default :
+ retVal = false;
+ llassert(0);
+ break;
+ }
+
+ return retVal;
+}
+
+LLPathfindingLinkset::ELinksetUse LLPathfindingLinkset::getLinksetUseWithToggledPhantom(ELinksetUse pLinksetUse)
+{
+ BOOL isPhantom = LLPathfindingLinkset::isPhantom(pLinksetUse);
+ BOOL isPermanent = LLPathfindingLinkset::isPermanent(pLinksetUse);
+ BOOL isWalkable = LLPathfindingLinkset::isWalkable(pLinksetUse);
+
+ return getLinksetUse(!isPhantom, isPermanent, isWalkable);
+}
+
+LLSD LLPathfindingLinkset::encodeAlteredFields(ELinksetUse pLinksetUse, S32 pA, S32 pB, S32 pC, S32 pD) const
+{
+ LLSD itemData;
+
+ if (!isTerrain() && (pLinksetUse != kUnknown) && (mLinksetUse != pLinksetUse))
+ {
+ if (mIsModifiable)
+ {
+ itemData[LINKSET_PHANTOM_FIELD] = static_cast<bool>(LLPathfindingLinkset::isPhantom(pLinksetUse));
+ }
+ itemData[LINKSET_PERMANENT_FIELD] = static_cast<bool>(LLPathfindingLinkset::isPermanent(pLinksetUse));
+ itemData[LINKSET_WALKABLE_FIELD] = static_cast<bool>(LLPathfindingLinkset::isWalkable(pLinksetUse));
+ }
+
+ if (mWalkabilityCoefficientA != pA)
+ {
+ itemData[LINKSET_WALKABILITY_A_FIELD] = llclamp(pA, MIN_WALKABILITY_VALUE, MAX_WALKABILITY_VALUE);
+ }
+
+ if (mWalkabilityCoefficientB != pB)
+ {
+ itemData[LINKSET_WALKABILITY_B_FIELD] = llclamp(pB, MIN_WALKABILITY_VALUE, MAX_WALKABILITY_VALUE);
+ }
+
+ if (mWalkabilityCoefficientC != pC)
+ {
+ itemData[LINKSET_WALKABILITY_C_FIELD] = llclamp(pC, MIN_WALKABILITY_VALUE, MAX_WALKABILITY_VALUE);
+ }
+
+ if (mWalkabilityCoefficientD != pD)
+ {
+ itemData[LINKSET_WALKABILITY_D_FIELD] = llclamp(pD, MIN_WALKABILITY_VALUE, MAX_WALKABILITY_VALUE);
+ }
+
+ return itemData;
+}
+
+void LLPathfindingLinkset::parseObjectData(const LLSD &pLinksetItem)
+{
+ llassert(pLinksetItem.has(LINKSET_NAME_FIELD));
+ llassert(pLinksetItem.get(LINKSET_NAME_FIELD).isString());
+ mName = pLinksetItem.get(LINKSET_NAME_FIELD).asString();
+
+ llassert(pLinksetItem.has(LINKSET_DESCRIPTION_FIELD));
+ llassert(pLinksetItem.get(LINKSET_DESCRIPTION_FIELD).isString());
+ mDescription = pLinksetItem.get(LINKSET_DESCRIPTION_FIELD).asString();
+
+ llassert(pLinksetItem.has(LINKSET_LAND_IMPACT_FIELD));
+ llassert(pLinksetItem.get(LINKSET_LAND_IMPACT_FIELD).isInteger());
+ llassert(pLinksetItem.get(LINKSET_LAND_IMPACT_FIELD).asInteger() >= 0);
+ mLandImpact = pLinksetItem.get(LINKSET_LAND_IMPACT_FIELD).asInteger();
+
+ llassert(pLinksetItem.has(LINKSET_MODIFIABLE_FIELD));
+ llassert(pLinksetItem.get(LINKSET_MODIFIABLE_FIELD).isBoolean());
+ mIsModifiable = pLinksetItem.get(LINKSET_MODIFIABLE_FIELD).asBoolean();
+
+ llassert(pLinksetItem.has(LINKSET_POSITION_FIELD));
+ llassert(pLinksetItem.get(LINKSET_POSITION_FIELD).isArray());
+ mLocation.setValue(pLinksetItem.get(LINKSET_POSITION_FIELD));
+}
+
+void LLPathfindingLinkset::parsePathfindingData(const LLSD &pLinksetItem)
+{
+ bool isPhantom = false;
+ if (pLinksetItem.has(LINKSET_PHANTOM_FIELD))
+ {
+ llassert(pLinksetItem.get(LINKSET_PHANTOM_FIELD).isBoolean());
+ isPhantom = pLinksetItem.get(LINKSET_PHANTOM_FIELD).asBoolean();
+ }
+
+ llassert(pLinksetItem.has(LINKSET_PERMANENT_FIELD));
+ llassert(pLinksetItem.get(LINKSET_PERMANENT_FIELD).isBoolean());
+ bool isPermanent = pLinksetItem.get(LINKSET_PERMANENT_FIELD).asBoolean();
+
+ llassert(pLinksetItem.has(LINKSET_WALKABLE_FIELD));
+ llassert(pLinksetItem.get(LINKSET_WALKABLE_FIELD).isBoolean());
+ bool isWalkable = pLinksetItem.get(LINKSET_WALKABLE_FIELD).asBoolean();
+
+ mLinksetUse = getLinksetUse(isPhantom, isPermanent, isWalkable);
+
+ llassert(pLinksetItem.has(LINKSET_WALKABILITY_A_FIELD));
+ llassert(pLinksetItem.get(LINKSET_WALKABILITY_A_FIELD).isInteger());
+ mWalkabilityCoefficientA = pLinksetItem.get(LINKSET_WALKABILITY_A_FIELD).asInteger();
+ llassert(mWalkabilityCoefficientA >= MIN_WALKABILITY_VALUE);
+ llassert(mWalkabilityCoefficientA <= MAX_WALKABILITY_VALUE);
+
+ llassert(pLinksetItem.has(LINKSET_WALKABILITY_B_FIELD));
+ llassert(pLinksetItem.get(LINKSET_WALKABILITY_B_FIELD).isInteger());
+ mWalkabilityCoefficientB = pLinksetItem.get(LINKSET_WALKABILITY_B_FIELD).asInteger();
+ llassert(mWalkabilityCoefficientB >= MIN_WALKABILITY_VALUE);
+ llassert(mWalkabilityCoefficientB <= MAX_WALKABILITY_VALUE);
+
+ llassert(pLinksetItem.has(LINKSET_WALKABILITY_C_FIELD));
+ llassert(pLinksetItem.get(LINKSET_WALKABILITY_C_FIELD).isInteger());
+ mWalkabilityCoefficientC = pLinksetItem.get(LINKSET_WALKABILITY_C_FIELD).asInteger();
+ llassert(mWalkabilityCoefficientC >= MIN_WALKABILITY_VALUE);
+ llassert(mWalkabilityCoefficientC <= MAX_WALKABILITY_VALUE);
+
+ llassert(pLinksetItem.has(LINKSET_WALKABILITY_D_FIELD));
+ llassert(pLinksetItem.get(LINKSET_WALKABILITY_D_FIELD).isInteger());
+ mWalkabilityCoefficientD = pLinksetItem.get(LINKSET_WALKABILITY_D_FIELD).asInteger();
+ llassert(mWalkabilityCoefficientD >= MIN_WALKABILITY_VALUE);
+ llassert(mWalkabilityCoefficientD <= MAX_WALKABILITY_VALUE);
+}
+
+LLPathfindingLinkset::ELinksetUse LLPathfindingLinkset::getLinksetUse(bool pIsPhantom, bool pIsPermanent, bool pIsWalkable)
+{
+ return (pIsPhantom ? (pIsPermanent ? (pIsWalkable ? kMaterialVolume : kExclusionVolume) : kDynamicPhantom) :
+ (pIsPermanent ? (pIsWalkable ? kWalkable : kStaticObstacle) : kDynamicObstacle));
+}
+
+BOOL LLPathfindingLinkset::isPermanent(ELinksetUse pLinksetUse)
+{
+ BOOL retVal;
+
+ switch (pLinksetUse)
+ {
+ case kWalkable :
+ case kStaticObstacle :
+ case kMaterialVolume :
+ case kExclusionVolume :
+ retVal = true;
+ break;
+ case kDynamicObstacle :
+ case kDynamicPhantom :
+ retVal = false;
+ break;
+ case kUnknown :
+ default :
+ retVal = false;
+ llassert(0);
+ break;
+ }
+
+ return retVal;
+}
+
+BOOL LLPathfindingLinkset::isWalkable(ELinksetUse pLinksetUse)
+{
+ BOOL retVal;
+
+ switch (pLinksetUse)
+ {
+ case kWalkable :
+ case kMaterialVolume :
+ retVal = true;
+ break;
+ case kStaticObstacle :
+ case kDynamicObstacle :
+ case kExclusionVolume :
+ case kDynamicPhantom :
+ retVal = false;
+ break;
+ case kUnknown :
+ default :
+ retVal = false;
+ llassert(0);
+ break;
+ }
+
+ return retVal;
+}
diff --git a/indra/newview/llpathfindinglinkset.h b/indra/newview/llpathfindinglinkset.h new file mode 100644 index 0000000000..81acad7d4d --- /dev/null +++ b/indra/newview/llpathfindinglinkset.h @@ -0,0 +1,108 @@ +/**
+ * @file llpathfindinglinkset.h
+ * @author William Todd Stinson
+ * @brief Definition of a pathfinding linkset that contains various properties required for havok pathfinding.
+ *
+ * $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$
+ */
+
+#ifndef LL_LLPATHFINDINGLINKSET_H
+#define LL_LLPATHFINDINGLINKSET_H
+
+#include "v3math.h"
+#include "lluuid.h"
+
+#include <boost/shared_ptr.hpp>
+
+class LLSD;
+class LLPathfindingLinkset;
+
+typedef boost::shared_ptr<LLPathfindingLinkset> LLPathfindingLinksetPtr;
+
+class LLPathfindingLinkset
+{
+public:
+ typedef enum
+ {
+ kUnknown,
+ kWalkable,
+ kStaticObstacle,
+ kDynamicObstacle,
+ kMaterialVolume,
+ kExclusionVolume,
+ kDynamicPhantom
+ } ELinksetUse;
+
+ LLPathfindingLinkset(const LLSD &pTerrainLinksetItem);
+ LLPathfindingLinkset(const std::string &pUUID, const LLSD &pLinksetItem);
+ LLPathfindingLinkset(const LLPathfindingLinkset& pOther);
+ virtual ~LLPathfindingLinkset();
+
+ LLPathfindingLinkset& operator = (const LLPathfindingLinkset& pOther);
+
+ inline bool isTerrain() const {return mIsTerrain;};
+ inline const LLUUID& getUUID() const {return mUUID;};
+ inline const std::string& getName() const {return mName;};
+ inline const std::string& getDescription() const {return mDescription;};
+ inline U32 getLandImpact() const {return mLandImpact;};
+ inline const LLVector3& getLocation() const {return mLocation;};
+ BOOL isModifiable() const {return mIsModifiable;};
+ BOOL isPhantom() const;
+ static BOOL isPhantom(ELinksetUse pLinksetUse);
+ static ELinksetUse getLinksetUseWithToggledPhantom(ELinksetUse pLinksetUse);
+
+ inline ELinksetUse getLinksetUse() const {return mLinksetUse;};
+
+ inline S32 getWalkabilityCoefficientA() const {return mWalkabilityCoefficientA;};
+ inline S32 getWalkabilityCoefficientB() const {return mWalkabilityCoefficientB;};
+ inline S32 getWalkabilityCoefficientC() const {return mWalkabilityCoefficientC;};
+ inline S32 getWalkabilityCoefficientD() const {return mWalkabilityCoefficientD;};
+
+ LLSD encodeAlteredFields(ELinksetUse pLinksetUse, S32 pA, S32 pB, S32 pC, S32 pD) const;
+
+ static const S32 MIN_WALKABILITY_VALUE;
+ static const S32 MAX_WALKABILITY_VALUE;
+
+protected:
+
+private:
+ void parseObjectData(const LLSD &pLinksetItem);
+ void parsePathfindingData(const LLSD &pLinksetItem);
+ static ELinksetUse getLinksetUse(bool pIsPhantom, bool pIsPermanent, bool pIsWalkable);
+ static BOOL isPermanent(ELinksetUse pLinksetUse);
+ static BOOL isWalkable(ELinksetUse pLinksetUse);
+
+ LLUUID mUUID;
+ bool mIsTerrain;
+ std::string mName;
+ std::string mDescription;
+ U32 mLandImpact;
+ LLVector3 mLocation;
+ BOOL mIsModifiable;
+ ELinksetUse mLinksetUse;
+ S32 mWalkabilityCoefficientA;
+ S32 mWalkabilityCoefficientB;
+ S32 mWalkabilityCoefficientC;
+ S32 mWalkabilityCoefficientD;
+};
+
+#endif // LL_LLPATHFINDINGLINKSET_H
diff --git a/indra/newview/llpathfindinglinksetlist.cpp b/indra/newview/llpathfindinglinksetlist.cpp new file mode 100644 index 0000000000..57febbf0f2 --- /dev/null +++ b/indra/newview/llpathfindinglinksetlist.cpp @@ -0,0 +1,122 @@ +/**
+ * @file llpathfindinglinksetlist.cpp
+ * @author William Todd Stinson
+ * @brief Class to implement the list of a set of pathfinding linksets
+ *
+ * $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 <string>
+#include <map>
+
+#include "llsd.h"
+#include "lluuid.h"
+#include "llpathfindinglinkset.h"
+#include "llpathfindinglinksetlist.h"
+
+//---------------------------------------------------------------------------
+// LLPathfindingLinksetList
+//---------------------------------------------------------------------------
+
+LLPathfindingLinksetList::LLPathfindingLinksetList()
+ : LLPathfindingLinksetMap()
+{
+}
+
+LLPathfindingLinksetList::LLPathfindingLinksetList(const LLSD& pLinksetItems)
+ : LLPathfindingLinksetMap()
+{
+ for (LLSD::map_const_iterator linksetItemIter = pLinksetItems.beginMap();
+ linksetItemIter != pLinksetItems.endMap(); ++linksetItemIter)
+ {
+ const std::string& uuid(linksetItemIter->first);
+ const LLSD& linksetData = linksetItemIter->second;
+ LLPathfindingLinksetPtr linkset(new LLPathfindingLinkset(uuid, linksetData));
+ insert(std::pair<std::string, LLPathfindingLinksetPtr>(uuid, linkset));
+ }
+}
+
+LLPathfindingLinksetList::~LLPathfindingLinksetList()
+{
+ clear();
+}
+
+void LLPathfindingLinksetList::update(const LLPathfindingLinksetList &pUpdateLinksetList)
+{
+ for (LLPathfindingLinksetList::const_iterator updateLinksetIter = pUpdateLinksetList.begin();
+ updateLinksetIter != pUpdateLinksetList.end(); ++updateLinksetIter)
+ {
+ const std::string &uuid = updateLinksetIter->first;
+ const LLPathfindingLinksetPtr updateLinksetPtr = updateLinksetIter->second;
+
+ LLPathfindingLinksetList::iterator linksetIter = find(uuid);
+ if (linksetIter == end())
+ {
+ insert(std::pair<std::string, LLPathfindingLinksetPtr>(uuid, updateLinksetPtr));
+ }
+ else
+ {
+ LLPathfindingLinksetPtr linksetPtr = linksetIter->second;
+ *linksetPtr = *updateLinksetPtr;
+ }
+ }
+}
+
+LLSD LLPathfindingLinksetList::encodeObjectFields(LLPathfindingLinkset::ELinksetUse pLinksetUse, S32 pA, S32 pB, S32 pC, S32 pD) const
+{
+ LLSD listData;
+
+ for (LLPathfindingLinksetMap::const_iterator linksetIter = begin(); linksetIter != end(); ++linksetIter)
+ {
+ const LLPathfindingLinksetPtr linksetPtr = linksetIter->second;
+ if (!linksetPtr->isTerrain())
+ {
+ LLSD linksetData = linksetPtr->encodeAlteredFields(pLinksetUse, pA, pB, pC, pD);
+ if (!linksetData.isUndefined())
+ {
+ const std::string& uuid(linksetIter->first);
+ listData[uuid] = linksetData;
+ }
+ }
+ }
+
+ return listData;
+}
+
+LLSD LLPathfindingLinksetList::encodeTerrainFields(LLPathfindingLinkset::ELinksetUse pLinksetUse, S32 pA, S32 pB, S32 pC, S32 pD) const
+{
+ LLSD terrainData;
+
+ for (LLPathfindingLinksetMap::const_iterator linksetIter = begin(); linksetIter != end(); ++linksetIter)
+ {
+ const LLPathfindingLinksetPtr linksetPtr = linksetIter->second;
+ if (linksetPtr->isTerrain())
+ {
+ terrainData = linksetPtr->encodeAlteredFields(pLinksetUse, pA, pB, pC, pD);
+ break;
+ }
+ }
+
+ return terrainData;
+}
diff --git a/indra/newview/llpathfindinglinksetlist.h b/indra/newview/llpathfindinglinksetlist.h new file mode 100644 index 0000000000..813c4ec46c --- /dev/null +++ b/indra/newview/llpathfindinglinksetlist.h @@ -0,0 +1,61 @@ +/**
+ * @file llpathfindinglinksetlist.h
+ * @author William Todd Stinson
+ * @brief Class to implement the list of a set of pathfinding linksets
+ *
+ * $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$
+ */
+
+#ifndef LL_LLPATHFINDINGLINKSETLIST_H
+#define LL_LLPATHFINDINGLINKSETLIST_H
+
+#include <string>
+#include <map>
+#include "llpathfindinglinkset.h"
+
+#include <boost/shared_ptr.hpp>
+
+class LLSD;
+class LLPathfindingLinksetList;
+
+typedef boost::shared_ptr<LLPathfindingLinksetList> LLPathfindingLinksetListPtr;
+typedef std::map<std::string, LLPathfindingLinksetPtr> LLPathfindingLinksetMap;
+
+class LLPathfindingLinksetList : public LLPathfindingLinksetMap
+{
+public:
+ LLPathfindingLinksetList();
+ LLPathfindingLinksetList(const LLSD& pLinksetItems);
+ virtual ~LLPathfindingLinksetList();
+
+ void update(const LLPathfindingLinksetList &pUpdateLinksetList);
+
+ LLSD encodeObjectFields(LLPathfindingLinkset::ELinksetUse pLinksetUse, S32 pA, S32 pB, S32 pC, S32 pD) const;
+ LLSD encodeTerrainFields(LLPathfindingLinkset::ELinksetUse pLinksetUse, S32 pA, S32 pB, S32 pC, S32 pD) const;
+
+protected:
+
+private:
+
+};
+
+#endif // LL_LLPATHFINDINGLINKSETLIST_H
diff --git a/indra/newview/llpathfindingmanager.cpp b/indra/newview/llpathfindingmanager.cpp new file mode 100644 index 0000000000..5c9293a28a --- /dev/null +++ b/indra/newview/llpathfindingmanager.cpp @@ -0,0 +1,552 @@ +/**
+ * @file llpathfindingmanager.cpp
+ * @author William Todd Stinson
+ * @brief A state manager for the various pathfinding states.
+ *
+ * $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 <string>
+
+#include "llviewerprecompiledheaders.h"
+#include "llpathfindingmanager.h"
+#include "llsingleton.h"
+#include "llhttpclient.h"
+#include "llagent.h"
+#include "llviewerregion.h"
+#include "llpathfindinglinkset.h"
+#include "llpathfindinglinksetlist.h"
+
+#include <boost/function.hpp>
+#include <boost/signals2.hpp>
+
+#define CAP_SERVICE_RETRIEVE_NAVMESH "RetrieveNavMeshSrc"
+
+#define CAP_SERVICE_AGENT_STATE "AgentPreferences"
+#define ALTER_PERMANENT_OBJECTS_FIELD "alter_permanent_objects"
+
+#define CAP_SERVICE_OBJECT_LINKSETS "ObjectNavMeshProperties"
+#define CAP_SERVICE_TERRAIN_LINKSETS "TerrainNavMeshProperties"
+
+//---------------------------------------------------------------------------
+// AgentStateResponder
+//---------------------------------------------------------------------------
+
+class AgentStateResponder : public LLHTTPClient::Responder
+{
+public:
+ AgentStateResponder(const std::string &pCapabilityURL, LLPathfindingManager::EAgentState pRequestedAgentState = LLPathfindingManager::kAgentStateUnknown);
+ virtual ~AgentStateResponder();
+
+ virtual void result(const LLSD &pContent);
+ virtual void error(U32 pStatus, const std::string& pReason);
+
+protected:
+
+private:
+ std::string mCapabilityURL;
+ LLPathfindingManager::EAgentState mRequestedAgentState;
+};
+
+//---------------------------------------------------------------------------
+// LinksetsResponder
+//---------------------------------------------------------------------------
+
+class LinksetsResponder
+{
+public:
+ LinksetsResponder(LLPathfindingManager::linksets_callback_t pLinksetsCallback, bool pIsObjectRequested, bool pIsTerrainRequested);
+ virtual ~LinksetsResponder();
+
+ void handleObjectLinksetsResult(const LLSD &pContent);
+ void handleObjectLinksetsError(U32 pStatus, const std::string &pReason, const std::string &pURL);
+ void handleTerrainLinksetsResult(const LLSD &pContent);
+ void handleTerrainLinksetsError(U32 pStatus, const std::string &pReason, const std::string &pURL);
+
+protected:
+
+private:
+ void sendCallback();
+
+ typedef enum
+ {
+ kNotRequested,
+ kWaiting,
+ kReceivedGood,
+ kReceivedError
+ } EMessagingState;
+
+ LLPathfindingManager::linksets_callback_t mLinksetsCallback;
+
+ EMessagingState mObjectMessagingState;
+ EMessagingState mTerrainMessagingState;
+
+ LLPathfindingLinksetListPtr mObjectLinksetListPtr;
+ LLPathfindingLinksetPtr mTerrainLinksetPtr;
+};
+
+typedef boost::shared_ptr<LinksetsResponder> LinksetsResponderPtr;
+
+//---------------------------------------------------------------------------
+// ObjectLinksetsResponder
+//---------------------------------------------------------------------------
+
+class ObjectLinksetsResponder : public LLHTTPClient::Responder
+{
+public:
+ ObjectLinksetsResponder(const std::string &pCapabilityURL, LinksetsResponderPtr pLinksetsResponsderPtr);
+ virtual ~ObjectLinksetsResponder();
+
+ virtual void result(const LLSD &pContent);
+ virtual void error(U32 pStatus, const std::string &pReason);
+
+protected:
+
+private:
+ std::string mCapabilityURL;
+ LinksetsResponderPtr mLinksetsResponsderPtr;
+};
+
+//---------------------------------------------------------------------------
+// TerrainLinksetsResponder
+//---------------------------------------------------------------------------
+
+class TerrainLinksetsResponder : public LLHTTPClient::Responder
+{
+public:
+ TerrainLinksetsResponder(const std::string &pCapabilityURL, LinksetsResponderPtr pLinksetsResponsderPtr);
+ virtual ~TerrainLinksetsResponder();
+
+ virtual void result(const LLSD &pContent);
+ virtual void error(U32 pStatus, const std::string &pReason);
+
+protected:
+
+private:
+ std::string mCapabilityURL;
+ LinksetsResponderPtr mLinksetsResponsderPtr;
+};
+
+//---------------------------------------------------------------------------
+// LLPathfindingManager
+//---------------------------------------------------------------------------
+
+LLPathfindingManager::LLPathfindingManager()
+ : LLSingleton<LLPathfindingManager>(),
+ mAgentStateSignal(),
+ mAgentState(kAgentStateUnknown),
+ mLastKnownNonErrorAgentState(kAgentStateUnknown)
+{
+}
+
+LLPathfindingManager::~LLPathfindingManager()
+{
+}
+
+bool LLPathfindingManager::isPathfindingEnabledForCurrentRegion() const
+{
+ std::string retrieveNavMeshURL = getRetrieveNavMeshURLForCurrentRegion();
+ return !retrieveNavMeshURL.empty();
+}
+
+bool LLPathfindingManager::isAllowAlterPermanent()
+{
+ return (!isPathfindingEnabledForCurrentRegion() || (getAgentState() == kAgentStateUnfrozen));
+}
+
+bool LLPathfindingManager::isAllowViewTerrainProperties() const
+{
+ LLViewerRegion* region = getCurrentRegion();
+ return (gAgent.isGodlike() || ((region != NULL) && region->canManageEstate()));
+}
+
+LLPathfindingManager::agent_state_slot_t LLPathfindingManager::registerAgentStateSignal(agent_state_callback_t pAgentStateCallback)
+{
+ return mAgentStateSignal.connect(pAgentStateCallback);
+}
+
+LLPathfindingManager::EAgentState LLPathfindingManager::getAgentState()
+{
+ if (!isPathfindingEnabledForCurrentRegion())
+ {
+ setAgentState(kAgentStateNotEnabled);
+ }
+ else
+ {
+ if (!isValidAgentState(mAgentState))
+ {
+ requestGetAgentState();
+ }
+ }
+
+ return mAgentState;
+}
+
+LLPathfindingManager::EAgentState LLPathfindingManager::getLastKnownNonErrorAgentState() const
+{
+ return mLastKnownNonErrorAgentState;
+}
+
+void LLPathfindingManager::requestSetAgentState(EAgentState pRequestedAgentState)
+{
+ llassert(isValidAgentState(pRequestedAgentState));
+ std::string agentStateURL = getAgentStateURLForCurrentRegion();
+
+ if (agentStateURL.empty())
+ {
+ setAgentState(kAgentStateNotEnabled);
+ }
+ else
+ {
+ LLSD request;
+ request[ALTER_PERMANENT_OBJECTS_FIELD] = static_cast<LLSD::Boolean>(pRequestedAgentState == kAgentStateUnfrozen);
+
+ LLHTTPClient::ResponderPtr responder = new AgentStateResponder(agentStateURL, pRequestedAgentState);
+ LLHTTPClient::post(agentStateURL, request, responder);
+ }
+}
+
+LLPathfindingManager::ELinksetsRequestStatus LLPathfindingManager::requestGetLinksets(linksets_callback_t pLinksetsCallback) const
+{
+ ELinksetsRequestStatus status;
+
+ std::string objectLinksetsURL = getObjectLinksetsURLForCurrentRegion();
+ std::string terrainLinksetsURL = getTerrainLinksetsURLForCurrentRegion();
+ if (objectLinksetsURL.empty() || terrainLinksetsURL.empty())
+ {
+ status = kLinksetsRequestNotEnabled;
+ }
+ else
+ {
+ bool doRequestTerrain = isAllowViewTerrainProperties();
+ LinksetsResponderPtr linksetsResponderPtr(new LinksetsResponder(pLinksetsCallback, true, doRequestTerrain));
+
+ LLHTTPClient::ResponderPtr objectLinksetsResponder = new ObjectLinksetsResponder(objectLinksetsURL, linksetsResponderPtr);
+ LLHTTPClient::get(objectLinksetsURL, objectLinksetsResponder);
+
+ if (doRequestTerrain)
+ {
+ LLHTTPClient::ResponderPtr terrainLinksetsResponder = new TerrainLinksetsResponder(terrainLinksetsURL, linksetsResponderPtr);
+ LLHTTPClient::get(terrainLinksetsURL, terrainLinksetsResponder);
+ }
+
+ status = kLinksetsRequestStarted;
+ }
+
+ return status;
+}
+
+LLPathfindingManager::ELinksetsRequestStatus LLPathfindingManager::requestSetLinksets(LLPathfindingLinksetListPtr pLinksetList, LLPathfindingLinkset::ELinksetUse pLinksetUse, S32 pA, S32 pB, S32 pC, S32 pD, linksets_callback_t pLinksetsCallback) const
+{
+ ELinksetsRequestStatus status = kLinksetsRequestNotEnabled;
+
+ std::string objectLinksetsURL = getObjectLinksetsURLForCurrentRegion();
+ std::string terrainLinksetsURL = getTerrainLinksetsURLForCurrentRegion();
+ if (objectLinksetsURL.empty() || terrainLinksetsURL.empty())
+ {
+ status = kLinksetsRequestNotEnabled;
+ }
+ else
+ {
+ LLSD objectPostData = pLinksetList->encodeObjectFields(pLinksetUse, pA, pB, pC, pD);
+ LLSD terrainPostData;
+ if (isAllowViewTerrainProperties())
+ {
+ terrainPostData = pLinksetList->encodeTerrainFields(pLinksetUse, pA, pB, pC, pD);
+ }
+
+ if (objectPostData.isUndefined() && terrainPostData.isUndefined())
+ {
+ status = kLinksetsRequestCompleted;
+ }
+ else
+ {
+ LinksetsResponderPtr linksetsResponderPtr(new LinksetsResponder(pLinksetsCallback, !objectPostData.isUndefined(), !terrainPostData.isUndefined()));
+
+ if (!objectPostData.isUndefined())
+ {
+ LLHTTPClient::ResponderPtr objectLinksetsResponder = new ObjectLinksetsResponder(objectLinksetsURL, linksetsResponderPtr);
+ LLHTTPClient::put(objectLinksetsURL, objectPostData, objectLinksetsResponder);
+ }
+
+ if (!terrainPostData.isUndefined())
+ {
+ LLHTTPClient::ResponderPtr terrainLinksetsResponder = new TerrainLinksetsResponder(terrainLinksetsURL, linksetsResponderPtr);
+ LLHTTPClient::put(terrainLinksetsURL, terrainPostData, terrainLinksetsResponder);
+ }
+
+ status = kLinksetsRequestStarted;
+ }
+ }
+
+ return status;
+}
+
+bool LLPathfindingManager::isValidAgentState(EAgentState pAgentState)
+{
+ return ((pAgentState == kAgentStateFrozen) || (pAgentState == kAgentStateUnfrozen));
+}
+
+void LLPathfindingManager::requestGetAgentState()
+{
+ std::string agentStateURL = getAgentStateURLForCurrentRegion();
+
+ if (agentStateURL.empty())
+ {
+ setAgentState(kAgentStateNotEnabled);
+ }
+ else
+ {
+ LLHTTPClient::ResponderPtr responder = new AgentStateResponder(agentStateURL);
+ LLHTTPClient::get(agentStateURL, responder);
+ }
+}
+
+void LLPathfindingManager::setAgentState(EAgentState pAgentState)
+{
+ mAgentState = pAgentState;
+
+ if (mAgentState != kAgentStateError)
+ {
+ mLastKnownNonErrorAgentState = mAgentState;
+ }
+
+ mAgentStateSignal(mAgentState);
+}
+
+void LLPathfindingManager::handleAgentStateResult(const LLSD &pContent, EAgentState pRequestedAgentState)
+{
+ llassert(pContent.has(ALTER_PERMANENT_OBJECTS_FIELD));
+ llassert(pContent.get(ALTER_PERMANENT_OBJECTS_FIELD).isBoolean());
+ EAgentState agentState = (pContent.get(ALTER_PERMANENT_OBJECTS_FIELD).asBoolean() ? kAgentStateUnfrozen : kAgentStateFrozen);
+
+ if (isValidAgentState(pRequestedAgentState) && (agentState != pRequestedAgentState))
+ {
+ agentState = kAgentStateError;
+ llassert(0);
+ }
+
+ setAgentState(agentState);
+}
+
+void LLPathfindingManager::handleAgentStateError(U32 pStatus, const std::string &pReason, const std::string &pURL)
+{
+ llwarns << "error with request to URL '" << pURL << "' because " << pReason << " (statusCode:" << pStatus << ")" << llendl;
+ setAgentState(kAgentStateError);
+}
+
+std::string LLPathfindingManager::getRetrieveNavMeshURLForCurrentRegion() const
+{
+ return getCapabilityURLForCurrentRegion(CAP_SERVICE_RETRIEVE_NAVMESH);
+}
+
+std::string LLPathfindingManager::getAgentStateURLForCurrentRegion() const
+{
+ return getCapabilityURLForCurrentRegion(CAP_SERVICE_AGENT_STATE);
+}
+
+std::string LLPathfindingManager::getObjectLinksetsURLForCurrentRegion() const
+{
+ return getCapabilityURLForCurrentRegion(CAP_SERVICE_OBJECT_LINKSETS);
+}
+
+std::string LLPathfindingManager::getTerrainLinksetsURLForCurrentRegion() const
+{
+ return getCapabilityURLForCurrentRegion(CAP_SERVICE_TERRAIN_LINKSETS);
+}
+
+std::string LLPathfindingManager::getCapabilityURLForCurrentRegion(const std::string &pCapabilityName) const
+{
+ std::string capabilityURL("");
+
+ LLViewerRegion* region = getCurrentRegion();
+ if (region != NULL)
+ {
+ capabilityURL = region->getCapability(pCapabilityName);
+ }
+
+ if (capabilityURL.empty())
+ {
+ llwarns << "cannot find capability '" << pCapabilityName << "' for current region '"
+ << ((region != NULL) ? region->getName() : "<null>") << "'" << llendl;
+ }
+
+ return capabilityURL;
+}
+
+LLViewerRegion *LLPathfindingManager::getCurrentRegion() const
+{
+ return gAgent.getRegion();
+}
+
+//---------------------------------------------------------------------------
+// AgentStateResponder
+//---------------------------------------------------------------------------
+
+AgentStateResponder::AgentStateResponder(const std::string &pCapabilityURL, LLPathfindingManager::EAgentState pRequestedAgentState)
+ : LLHTTPClient::Responder(),
+ mCapabilityURL(pCapabilityURL),
+ mRequestedAgentState(pRequestedAgentState)
+{
+}
+
+AgentStateResponder::~AgentStateResponder()
+{
+}
+
+void AgentStateResponder::result(const LLSD &pContent)
+{
+ LLPathfindingManager::getInstance()->handleAgentStateResult(pContent, mRequestedAgentState);
+}
+
+void AgentStateResponder::error(U32 pStatus, const std::string &pReason)
+{
+ LLPathfindingManager::getInstance()->handleAgentStateError(pStatus, pReason, mCapabilityURL);
+}
+
+//---------------------------------------------------------------------------
+// LinksetsResponder
+//---------------------------------------------------------------------------
+
+LinksetsResponder::LinksetsResponder(LLPathfindingManager::linksets_callback_t pLinksetsCallback, bool pIsObjectRequested, bool pIsTerrainRequested)
+ : mLinksetsCallback(pLinksetsCallback),
+ mObjectMessagingState(pIsObjectRequested ? kWaiting : kNotRequested),
+ mTerrainMessagingState(pIsTerrainRequested ? kWaiting : kNotRequested),
+ mObjectLinksetListPtr(),
+ mTerrainLinksetPtr()
+{
+}
+
+LinksetsResponder::~LinksetsResponder()
+{
+}
+
+void LinksetsResponder::handleObjectLinksetsResult(const LLSD &pContent)
+{
+ mObjectLinksetListPtr = LLPathfindingLinksetListPtr(new LLPathfindingLinksetList(pContent));
+
+ mObjectMessagingState = kReceivedGood;
+ if (mTerrainMessagingState != kWaiting)
+ {
+ sendCallback();
+ }
+}
+
+void LinksetsResponder::handleObjectLinksetsError(U32 pStatus, const std::string &pReason, const std::string &pURL)
+{
+ llwarns << "error with request to URL '" << pURL << "' because " << pReason << " (statusCode:" << pStatus << ")" << llendl;
+ mObjectMessagingState = kReceivedError;
+ if (mTerrainMessagingState != kWaiting)
+ {
+ sendCallback();
+ }
+}
+
+void LinksetsResponder::handleTerrainLinksetsResult(const LLSD &pContent)
+{
+ mTerrainLinksetPtr = LLPathfindingLinksetPtr(new LLPathfindingLinkset(pContent));
+
+ mTerrainMessagingState = kReceivedGood;
+ if (mObjectMessagingState != kWaiting)
+ {
+ sendCallback();
+ }
+}
+
+void LinksetsResponder::handleTerrainLinksetsError(U32 pStatus, const std::string &pReason, const std::string &pURL)
+{
+ mTerrainMessagingState = kReceivedError;
+ if (mObjectMessagingState != kWaiting)
+ {
+ sendCallback();
+ }
+}
+
+void LinksetsResponder::sendCallback()
+{
+ llassert(mObjectMessagingState != kWaiting);
+ llassert(mTerrainMessagingState != kWaiting);
+ LLPathfindingManager::ELinksetsRequestStatus requestStatus =
+ ((((mObjectMessagingState == kReceivedGood) || (mObjectMessagingState == kNotRequested)) &&
+ ((mTerrainMessagingState == kReceivedGood) || (mTerrainMessagingState == kNotRequested))) ?
+ LLPathfindingManager::kLinksetsRequestCompleted : LLPathfindingManager::kLinksetsRequestError);
+
+ if (mObjectMessagingState != kReceivedGood)
+ {
+ mObjectLinksetListPtr = LLPathfindingLinksetListPtr(new LLPathfindingLinksetList());
+ }
+
+ if (mTerrainMessagingState == kReceivedGood)
+ {
+ mObjectLinksetListPtr->insert(std::pair<std::string, LLPathfindingLinksetPtr>(mTerrainLinksetPtr->getUUID().asString(), mTerrainLinksetPtr));
+ }
+
+ mLinksetsCallback(requestStatus, mObjectLinksetListPtr);
+}
+
+//---------------------------------------------------------------------------
+// ObjectLinksetsResponder
+//---------------------------------------------------------------------------
+
+ObjectLinksetsResponder::ObjectLinksetsResponder(const std::string &pCapabilityURL, LinksetsResponderPtr pLinksetsResponsderPtr)
+ : mCapabilityURL(pCapabilityURL),
+ mLinksetsResponsderPtr(pLinksetsResponsderPtr)
+{
+}
+
+ObjectLinksetsResponder::~ObjectLinksetsResponder()
+{
+}
+
+void ObjectLinksetsResponder::result(const LLSD &pContent)
+{
+ mLinksetsResponsderPtr->handleObjectLinksetsResult(pContent);
+}
+
+void ObjectLinksetsResponder::error(U32 pStatus, const std::string &pReason)
+{
+ mLinksetsResponsderPtr->handleObjectLinksetsError(pStatus, pReason, mCapabilityURL);
+}
+
+//---------------------------------------------------------------------------
+// TerrainLinksetsResponder
+//---------------------------------------------------------------------------
+
+TerrainLinksetsResponder::TerrainLinksetsResponder(const std::string &pCapabilityURL, LinksetsResponderPtr pLinksetsResponsderPtr)
+: mCapabilityURL(pCapabilityURL),
+mLinksetsResponsderPtr(pLinksetsResponsderPtr)
+{
+}
+
+TerrainLinksetsResponder::~TerrainLinksetsResponder()
+{
+}
+
+void TerrainLinksetsResponder::result(const LLSD &pContent)
+{
+ mLinksetsResponsderPtr->handleTerrainLinksetsResult(pContent);
+}
+
+void TerrainLinksetsResponder::error(U32 pStatus, const std::string &pReason)
+{
+ mLinksetsResponsderPtr->handleTerrainLinksetsError(pStatus, pReason, mCapabilityURL);
+}
diff --git a/indra/newview/llpathfindingmanager.h b/indra/newview/llpathfindingmanager.h new file mode 100644 index 0000000000..9a6bbb81b9 --- /dev/null +++ b/indra/newview/llpathfindingmanager.h @@ -0,0 +1,107 @@ +/**
+ * @file llpathfindingmanager.h
+ * @author William Todd Stinson
+ * @brief A state manager for the various pathfinding states.
+ *
+ * $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$
+ */
+
+#ifndef LL_LLPATHFINDINGMANAGER_H
+#define LL_LLPATHFINDINGMANAGER_H
+
+#include <string>
+
+#include <boost/function.hpp>
+#include <boost/signals2.hpp>
+
+#include "llsingleton.h"
+#include "llpathfindinglinkset.h"
+#include "llpathfindinglinksetlist.h"
+
+class LLFloater;
+class LLViewerRegion;
+
+class LLPathfindingManager : public LLSingleton<LLPathfindingManager>
+{
+ friend class AgentStateResponder;
+public:
+ typedef enum {
+ kAgentStateUnknown,
+ kAgentStateFrozen,
+ kAgentStateUnfrozen,
+ kAgentStateNotEnabled,
+ kAgentStateError
+ } EAgentState;
+
+ typedef boost::function<void (EAgentState)> agent_state_callback_t;
+ typedef boost::signals2::signal<void (EAgentState)> agent_state_signal_t;
+ typedef boost::signals2::connection agent_state_slot_t;
+
+ typedef enum {
+ kLinksetsRequestStarted,
+ kLinksetsRequestCompleted,
+ kLinksetsRequestNotEnabled,
+ kLinksetsRequestError
+ } ELinksetsRequestStatus;
+
+ typedef boost::function<void (ELinksetsRequestStatus, LLPathfindingLinksetListPtr)> linksets_callback_t;
+
+ LLPathfindingManager();
+ virtual ~LLPathfindingManager();
+
+ bool isPathfindingEnabledForCurrentRegion() const;
+
+ bool isAllowAlterPermanent();
+ bool isAllowViewTerrainProperties() const;
+
+ agent_state_slot_t registerAgentStateSignal(agent_state_callback_t pAgentStateCallback);
+ EAgentState getAgentState();
+ EAgentState getLastKnownNonErrorAgentState() const;
+ void requestSetAgentState(EAgentState pAgentState);
+
+ ELinksetsRequestStatus requestGetLinksets(linksets_callback_t pLinksetsCallback) const;
+ ELinksetsRequestStatus requestSetLinksets(LLPathfindingLinksetListPtr pLinksetList, LLPathfindingLinkset::ELinksetUse pLinksetUse, S32 pA, S32 pB, S32 pC, S32 pD, linksets_callback_t pLinksetsCallback) const;
+
+protected:
+
+private:
+ static bool isValidAgentState(EAgentState pAgentState);
+
+ void requestGetAgentState();
+ void setAgentState(EAgentState pAgentState);
+ void handleAgentStateResult(const LLSD &pContent, EAgentState pRequestedAgentState);
+ void handleAgentStateError(U32 pStatus, const std::string &pReason, const std::string &pURL);
+
+ std::string getRetrieveNavMeshURLForCurrentRegion() const;
+ std::string getAgentStateURLForCurrentRegion() const;
+ std::string getObjectLinksetsURLForCurrentRegion() const;
+ std::string getTerrainLinksetsURLForCurrentRegion() const;
+
+ std::string getCapabilityURLForCurrentRegion(const std::string &pCapabilityName) const;
+ LLViewerRegion *getCurrentRegion() const;
+
+ agent_state_signal_t mAgentStateSignal;
+ EAgentState mAgentState;
+ EAgentState mLastKnownNonErrorAgentState;
+};
+
+#endif // LL_LLPATHFINDINGMANAGER_H
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 6111255a66..9cfcf3de79 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -4144,12 +4144,6 @@ void LLSelectMgr::selectionUpdatePhantom(BOOL is_phantom) getSelection()->applyToObjects(&func); } -void LLSelectMgr::selectionUpdateCastShadows(BOOL cast_shadows) -{ - LLSelectMgrApplyFlags func( FLAGS_CAST_SHADOWS, cast_shadows); - getSelection()->applyToObjects(&func); -} - //---------------------------------------------------------------------- // Helpful packing functions for sendObjectMessage() //---------------------------------------------------------------------- diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index 87ada5ac6b..c2816fe78a 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -501,7 +501,6 @@ public: void selectionUpdatePhysics(BOOL use_physics); void selectionUpdateTemporary(BOOL is_temporary); void selectionUpdatePhantom(BOOL is_ghost); - void selectionUpdateCastShadows(BOOL cast_shadows); void selectionDump(); BOOL selectionAllPCode(LLPCode code); // all objects have this PCode diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 5d196a465f..746320f887 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -1,4795 +1,4797 @@ -/** - * @file llspatialpartition.cpp - * @brief LLSpatialGroup class implementation and supporting functions - * - * $LicenseInfo:firstyear=2003&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 "llspatialpartition.h" - -#include "llappviewer.h" -#include "lltexturecache.h" -#include "lltexturefetch.h" -#include "llimageworker.h" -#include "llviewerwindow.h" -#include "llviewerobjectlist.h" -#include "llvovolume.h" -#include "llvolume.h" -#include "llvolumeoctree.h" -#include "llviewercamera.h" -#include "llface.h" -#include "llfloatertools.h" -#include "llviewercontrol.h" -#include "llviewerregion.h" -#include "llcamera.h" -#include "pipeline.h" -#include "llmeshrepository.h" -#include "llrender.h" -#include "lloctree.h" -#include "llphysicsshapebuilderutil.h" -#include "llvoavatar.h" -#include "llvolumemgr.h" -#include "lltextureatlas.h" -#include "llglslshader.h" -#include "llviewershadermgr.h" - -static LLFastTimer::DeclareTimer FTM_FRUSTUM_CULL("Frustum Culling"); -static LLFastTimer::DeclareTimer FTM_CULL_REBOUND("Cull Rebound"); - -const F32 SG_OCCLUSION_FUDGE = 0.25f; -#define SG_DISCARD_TOLERANCE 0.01f - -#if LL_OCTREE_PARANOIA_CHECK -#define assert_octree_valid(x) x->validate() -#define assert_states_valid(x) ((LLSpatialGroup*) x->mSpatialPartition->mOctree->getListener(0))->checkStates() -#else -#define assert_octree_valid(x) -#define assert_states_valid(x) -#endif - - -static U32 sZombieGroups = 0; -U32 LLSpatialGroup::sNodeCount = 0; - -#define LL_TRACK_PENDING_OCCLUSION_QUERIES 0 - -std::set<GLuint> LLSpatialGroup::sPendingQueries; - -U32 gOctreeMaxCapacity; - -BOOL LLSpatialGroup::sNoDelete = FALSE; - -static F32 sLastMaxTexPriority = 1.f; -static F32 sCurMaxTexPriority = 1.f; - -class LLOcclusionQueryPool : public LLGLNamePool -{ -protected: - virtual GLuint allocateName() - { - GLuint name; - glGenQueriesARB(1, &name); - return name; - } - - virtual void releaseName(GLuint name) - { -#if LL_TRACK_PENDING_OCCLUSION_QUERIES - LLSpatialGroup::sPendingQueries.erase(name); -#endif - glDeleteQueriesARB(1, &name); - } -}; - -static LLOcclusionQueryPool sQueryPool; - -//static counter for frame to switch LOD on - -void sg_assert(BOOL expr) -{ -#if LL_OCTREE_PARANOIA_CHECK - if (!expr) - { - llerrs << "Octree invalid!" << llendl; - } -#endif -} - -S32 AABBSphereIntersect(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &rad) -{ - return AABBSphereIntersectR2(min, max, origin, rad*rad); -} - -S32 AABBSphereIntersectR2(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &r) -{ - F32 d = 0.f; - F32 t; - - if ((min-origin).magVecSquared() < r && - (max-origin).magVecSquared() < r) - { - return 2; - } - - for (U32 i = 0; i < 3; i++) - { - if (origin.mV[i] < min.mV[i]) - { - t = min.mV[i] - origin.mV[i]; - d += t*t; - } - else if (origin.mV[i] > max.mV[i]) - { - t = origin.mV[i] - max.mV[i]; - d += t*t; - } - - if (d > r) - { - return 0; - } - } - - return 1; -} - - -S32 AABBSphereIntersect(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &rad) -{ - return AABBSphereIntersectR2(min, max, origin, rad*rad); -} - -S32 AABBSphereIntersectR2(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &r) -{ - F32 d = 0.f; - F32 t; - - LLVector4a origina; - origina.load3(origin.mV); - - LLVector4a v; - v.setSub(min, origina); - - if (v.dot3(v) < r) - { - v.setSub(max, origina); - if (v.dot3(v) < r) - { - return 2; - } - } - - - for (U32 i = 0; i < 3; i++) - { - if (origin.mV[i] < min[i]) - { - t = min[i] - origin.mV[i]; - d += t*t; - } - else if (origin.mV[i] > max[i]) - { - t = origin.mV[i] - max[i]; - d += t*t; - } - - if (d > r) - { - return 0; - } - } - - return 1; -} - - -typedef enum -{ - b000 = 0x00, - b001 = 0x01, - b010 = 0x02, - b011 = 0x03, - b100 = 0x04, - b101 = 0x05, - b110 = 0x06, - b111 = 0x07, -} eLoveTheBits; - -//contact Runitai Linden for a copy of the SL object used to write this table -//basically, you give the table a bitmask of the look-at vector to a node and it -//gives you a triangle fan index array -static U16 sOcclusionIndices[] = -{ - //000 - b111, b110, b010, b011, b001, b101, b100, b110, - //001 - b011, b010, b000, b001, b101, b111, b110, b010, - //010 - b101, b100, b110, b111, b011, b001, b000, b100, - //011 - b001, b000, b100, b101, b111, b011, b010, b000, - //100 - b110, b000, b010, b011, b111, b101, b100, b000, - //101 - b010, b100, b000, b001, b011, b111, b110, b100, - //110 - b100, b010, b110, b111, b101, b001, b000, b010, - //111 - b000, b110, b100, b101, b001, b011, b010, b110, -}; - -U32 get_box_fan_indices(LLCamera* camera, const LLVector4a& center) -{ - LLVector4a origin; - origin.load3(camera->getOrigin().mV); - - S32 cypher = center.greaterThan(origin).getGatheredBits() & 0x7; - - return cypher*8; -} - -U8* get_box_fan_indices_ptr(LLCamera* camera, const LLVector4a& center) -{ - LLVector4a origin; - origin.load3(camera->getOrigin().mV); - - S32 cypher = center.greaterThan(origin).getGatheredBits() & 0x7; - - return (U8*) (sOcclusionIndices+cypher*8); -} - - -static LLFastTimer::DeclareTimer FTM_BUILD_OCCLUSION("Build Occlusion"); - -void LLSpatialGroup::buildOcclusion() -{ - //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]; - } - } - - LLVector4a fudge; - fudge.splat(SG_OCCLUSION_FUDGE); - - LLVector4a r; - r.setAdd(mBounds[1], fudge); - - LLStrider<LLVector3> pos; - - { - LLFastTimer t(FTM_BUILD_OCCLUSION); - mOcclusionVerts->getVertexStrider(pos); - } - - { - LLVector4a* v = (LLVector4a*) pos.get(); - - 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; - } - } - - { - mOcclusionVerts->flush(); - LLVertexBuffer::unbind(); - } - - clearState(LLSpatialGroup::OCCLUSION_DIRTY); -} - - -BOOL earlyFail(LLCamera* camera, LLSpatialGroup* group); - -//returns: -// 0 if sphere and AABB are not intersecting -// 1 if they are -// 2 if AABB is entirely inside sphere - -S32 LLSphereAABB(const LLVector3& center, const LLVector3& size, const LLVector3& pos, const F32 &rad) -{ - S32 ret = 2; - - LLVector3 min = center - size; - LLVector3 max = center + size; - for (U32 i = 0; i < 3; i++) - { - if (min.mV[i] > pos.mV[i] + rad || - max.mV[i] < pos.mV[i] - rad) - { //totally outside - return 0; - } - - if (min.mV[i] < pos.mV[i] - rad || - max.mV[i] > pos.mV[i] + rad) - { //intersecting - ret = 1; - } - } - - return ret; -} - -LLSpatialGroup::~LLSpatialGroup() -{ - /*if (sNoDelete) - { - llerrs << "Illegal deletion of LLSpatialGroup!" << llendl; - }*/ - - if (gDebugGL) - { - gPipeline.checkReferences(this); - } - - if (isState(DEAD)) - { - sZombieGroups--; - } - - sNodeCount--; - - if (gGLManager.mHasOcclusionQuery) - { - for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; ++i) - { - if (mOcclusionQuery[i]) - { - sQueryPool.release(mOcclusionQuery[i]); - } - } - } - - mOcclusionVerts = NULL; - - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - clearDrawMap(); - clearAtlasList() ; -} - -BOOL LLSpatialGroup::hasAtlas(LLTextureAtlas* atlasp) -{ - S8 type = atlasp->getComponents() - 1 ; - for(std::list<LLTextureAtlas*>::iterator iter = mAtlasList[type].begin(); iter != mAtlasList[type].end() ; ++iter) - { - if(atlasp == *iter) - { - return TRUE ; - } - } - return FALSE ; -} - -void LLSpatialGroup::addAtlas(LLTextureAtlas* atlasp, S8 recursive_level) -{ - if(!hasAtlas(atlasp)) - { - mAtlasList[atlasp->getComponents() - 1].push_back(atlasp) ; - atlasp->addSpatialGroup(this) ; - } - - --recursive_level; - if(recursive_level)//levels propagating up. - { - LLSpatialGroup* parent = getParent() ; - if(parent) - { - parent->addAtlas(atlasp, recursive_level) ; - } - } -} - -void LLSpatialGroup::removeAtlas(LLTextureAtlas* atlasp, BOOL remove_group, S8 recursive_level) -{ - mAtlasList[atlasp->getComponents() - 1].remove(atlasp) ; - if(remove_group) - { - atlasp->removeSpatialGroup(this) ; - } - - --recursive_level; - if(recursive_level)//levels propagating up. - { - LLSpatialGroup* parent = getParent() ; - if(parent) - { - parent->removeAtlas(atlasp, recursive_level) ; - } - } -} - -void LLSpatialGroup::clearAtlasList() -{ - std::list<LLTextureAtlas*>::iterator iter ; - for(S8 i = 0 ; i < 4 ; i++) - { - if(mAtlasList[i].size() > 0) - { - for(iter = mAtlasList[i].begin(); iter != mAtlasList[i].end() ; ++iter) - { - ((LLTextureAtlas*)*iter)->removeSpatialGroup(this) ; - } - mAtlasList[i].clear() ; - } - } -} - -LLTextureAtlas* LLSpatialGroup::getAtlas(S8 ncomponents, S8 to_be_reserved, S8 recursive_level) -{ - S8 type = ncomponents - 1 ; - if(mAtlasList[type].size() > 0) - { - for(std::list<LLTextureAtlas*>::iterator iter = mAtlasList[type].begin(); iter != mAtlasList[type].end() ; ++iter) - { - if(!((LLTextureAtlas*)*iter)->isFull(to_be_reserved)) - { - return *iter ; - } - } - } - - --recursive_level; - if(recursive_level) - { - LLSpatialGroup* parent = getParent() ; - if(parent) - { - return parent->getAtlas(ncomponents, to_be_reserved, recursive_level) ; - } - } - return NULL ; -} - -void LLSpatialGroup::setCurUpdatingSlot(LLTextureAtlasSlot* slotp) -{ - mCurUpdatingSlotp = slotp; - - //if(!hasAtlas(mCurUpdatingSlotp->getAtlas())) - //{ - // addAtlas(mCurUpdatingSlotp->getAtlas()) ; - //} -} - -LLTextureAtlasSlot* LLSpatialGroup::getCurUpdatingSlot(LLViewerTexture* imagep, S8 recursive_level) -{ - if(gFrameCount && mCurUpdatingTime == gFrameCount && mCurUpdatingTexture == imagep) - { - return mCurUpdatingSlotp ; - } - - //--recursive_level ; - //if(recursive_level) - //{ - // LLSpatialGroup* parent = getParent() ; - // if(parent) - // { - // return parent->getCurUpdatingSlot(imagep, recursive_level) ; - // } - //} - return NULL ; -} - -void LLSpatialGroup::clearDrawMap() -{ - mDrawMap.clear(); -} - -BOOL LLSpatialGroup::isHUDGroup() -{ - return mSpatialPartition && mSpatialPartition->isHUDPartition() ; -} - -BOOL LLSpatialGroup::isRecentlyVisible() const -{ - return (LLDrawable::getCurrentFrame() - mVisible[LLViewerCamera::sCurCameraID]) < LLDrawable::getMinVisFrameRange() ; -} - -BOOL LLSpatialGroup::isVisible() const -{ - return mVisible[LLViewerCamera::sCurCameraID] >= LLDrawable::getCurrentFrame() ? TRUE : FALSE; -} - -void LLSpatialGroup::setVisible() -{ - mVisible[LLViewerCamera::sCurCameraID] = LLDrawable::getCurrentFrame(); -} - -void LLSpatialGroup::validate() -{ -#if LL_OCTREE_PARANOIA_CHECK - - sg_assert(!isState(DIRTY)); - sg_assert(!isDead()); - - LLVector4a myMin; - myMin.setSub(mBounds[0], mBounds[1]); - LLVector4a myMax; - myMax.setAdd(mBounds[0], mBounds[1]); - - validateDrawMap(); - - for (element_iter i = getData().begin(); i != getData().end(); ++i) - { - LLDrawable* drawable = *i; - sg_assert(drawable->getSpatialGroup() == this); - if (drawable->getSpatialBridge()) - { - sg_assert(drawable->getSpatialBridge() == mSpatialPartition->asBridge()); - } - - /*if (drawable->isSpatialBridge()) - { - LLSpatialPartition* part = drawable->asPartition(); - if (!part) - { - llerrs << "Drawable reports it is a spatial bridge but not a partition." << llendl; - } - LLSpatialGroup* group = (LLSpatialGroup*) part->mOctree->getListener(0); - group->validate(); - }*/ - } - - for (U32 i = 0; i < mOctreeNode->getChildCount(); ++i) - { - LLSpatialGroup* group = (LLSpatialGroup*) mOctreeNode->getChild(i)->getListener(0); - - group->validate(); - - //ensure all children are enclosed in this node - LLVector4a center = group->mBounds[0]; - LLVector4a size = group->mBounds[1]; - - LLVector4a min; - min.setSub(center, size); - LLVector4a max; - max.setAdd(center, size); - - for (U32 j = 0; j < 3; j++) - { - sg_assert(min[j] >= myMin[j]-0.02f); - sg_assert(max[j] <= myMax[j]+0.02f); - } - } - -#endif -} - -void LLSpatialGroup::checkStates() -{ -#if LL_OCTREE_PARANOIA_CHECK - //LLOctreeStateCheck checker; - //checker.traverse(mOctreeNode); -#endif -} - -void LLSpatialGroup::validateDrawMap() -{ -#if LL_OCTREE_PARANOIA_CHECK - for (draw_map_t::iterator i = mDrawMap.begin(); i != mDrawMap.end(); ++i) - { - LLSpatialGroup::drawmap_elem_t& draw_vec = i->second; - for (drawmap_elem_t::iterator j = draw_vec.begin(); j != draw_vec.end(); ++j) - { - LLDrawInfo& params = **j; - - params.validate(); - } - } -#endif -} - -BOOL LLSpatialGroup::updateInGroup(LLDrawable *drawablep, BOOL immediate) -{ - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - - drawablep->updateSpatialExtents(); - - OctreeNode* parent = mOctreeNode->getOctParent(); - - if (mOctreeNode->isInside(drawablep->getPositionGroup()) && - (mOctreeNode->contains(drawablep) || - (drawablep->getBinRadius() > mOctreeNode->getSize()[0] && - parent && parent->getElementCount() >= gOctreeMaxCapacity))) - { - unbound(); - setState(OBJECT_DIRTY); - //setState(GEOM_DIRTY); - return TRUE; - } - - return FALSE; -} - - -BOOL LLSpatialGroup::addObject(LLDrawable *drawablep, BOOL add_all, BOOL from_octree) -{ - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - if (!from_octree) - { - mOctreeNode->insert(drawablep); - } - else - { - drawablep->setSpatialGroup(this); - setState(OBJECT_DIRTY | GEOM_DIRTY); - setOcclusionState(LLSpatialGroup::DISCARD_QUERY, LLSpatialGroup::STATE_MODE_ALL_CAMERAS); - gPipeline.markRebuild(this, TRUE); - if (drawablep->isSpatialBridge()) - { - mBridgeList.push_back((LLSpatialBridge*) drawablep); - } - if (drawablep->getRadius() > 1.f) - { - setState(IMAGE_DIRTY); - } - } - - return TRUE; -} - -void LLSpatialGroup::rebuildGeom() -{ - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - if (!isDead()) - { - mSpatialPartition->rebuildGeom(this); - } -} - -void LLSpatialGroup::rebuildMesh() -{ - if (!isDead()) - { - mSpatialPartition->rebuildMesh(this); - } -} - -static LLFastTimer::DeclareTimer FTM_REBUILD_VBO("VBO Rebuilt"); - -void LLSpatialPartition::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_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) - { //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(); - } - else - { - group->mVertexBuffer->resizeBuffer(vertex_count, index_count); - stop_glerror(); - } - - getGeometry(group); - } - else - { - group->mVertexBuffer = NULL; - group->mBufferMap.clear(); - } - - group->mLastUpdateTime = gFrameTimeSeconds; - group->clearState(LLSpatialGroup::GEOM_DIRTY); -} - - -void LLSpatialPartition::rebuildMesh(LLSpatialGroup* group) -{ - -} - -BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector4a& minOut, LLVector4a& maxOut) -{ - const OctreeNode* node = mOctreeNode; - - if (node->getData().empty()) - { //don't do anything if there are no objects - if (empty && mOctreeNode->getParent()) - { //only root is allowed to be empty - OCT_ERRS << "Empty leaf found in octree." << llendl; - } - return FALSE; - } - - LLVector4a& newMin = mObjectExtents[0]; - LLVector4a& newMax = mObjectExtents[1]; - - if (isState(OBJECT_DIRTY)) - { //calculate new bounding box - clearState(OBJECT_DIRTY); - - //initialize bounding box to first element - OctreeNode::const_element_iter i = node->getData().begin(); - LLDrawable* drawablep = *i; - const LLVector4a* minMax = drawablep->getSpatialExtents(); - - newMin = minMax[0]; - newMax = minMax[1]; - - for (++i; i != node->getData().end(); ++i) - { - drawablep = *i; - minMax = drawablep->getSpatialExtents(); - - update_min_max(newMin, newMax, minMax[0]); - update_min_max(newMin, newMax, minMax[1]); - - //bin up the object - /*for (U32 i = 0; i < 3; i++) - { - if (minMax[0].mV[i] < newMin.mV[i]) - { - newMin.mV[i] = minMax[0].mV[i]; - } - if (minMax[1].mV[i] > newMax.mV[i]) - { - newMax.mV[i] = minMax[1].mV[i]; - } - }*/ - } - - mObjectBounds[0].setAdd(newMin, newMax); - mObjectBounds[0].mul(0.5f); - mObjectBounds[1].setSub(newMax, newMin); - mObjectBounds[1].mul(0.5f); - } - - if (empty) - { - minOut = newMin; - maxOut = newMax; - } - else - { - minOut.setMin(minOut, newMin); - maxOut.setMax(maxOut, newMax); - } - - return TRUE; -} - -void LLSpatialGroup::unbound() -{ - if (isState(DIRTY)) - { - return; - } - - setState(DIRTY); - - //all the parent nodes need to rebound this child - if (mOctreeNode) - { - OctreeNode* parent = (OctreeNode*) mOctreeNode->getParent(); - while (parent != NULL) - { - LLSpatialGroup* group = (LLSpatialGroup*) parent->getListener(0); - if (group->isState(DIRTY)) - { - return; - } - - group->setState(DIRTY); - parent = (OctreeNode*) parent->getParent(); - } - } -} - -LLSpatialGroup* LLSpatialGroup::getParent() -{ - if (isDead()) - { - return NULL; - } - - if(!mOctreeNode) - { - return NULL; - } - OctreeNode* parent = mOctreeNode->getOctParent(); - - if (parent) - { - return (LLSpatialGroup*) parent->getListener(0); - } - - return NULL; -} - -BOOL LLSpatialGroup::removeObject(LLDrawable *drawablep, BOOL from_octree) -{ - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - unbound(); - if (mOctreeNode && !from_octree) - { - if (!mOctreeNode->remove(drawablep)) - { - OCT_ERRS << "Could not remove drawable from spatial group" << llendl; - } - } - else - { - drawablep->setSpatialGroup(NULL); - setState(GEOM_DIRTY); - gPipeline.markRebuild(this, TRUE); - - if (drawablep->isSpatialBridge()) - { - for (bridge_list_t::iterator i = mBridgeList.begin(); i != mBridgeList.end(); ++i) - { - if (*i == drawablep) - { - mBridgeList.erase(i); - break; - } - } - } - - if (getElementCount() == 0) - { //delete draw map on last element removal since a rebuild might never happen - clearDrawMap(); - } - } - return TRUE; -} - -void LLSpatialGroup::shift(const LLVector4a &offset) -{ - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - LLVector4a t = mOctreeNode->getCenter(); - t.add(offset); - mOctreeNode->setCenter(t); - mOctreeNode->updateMinMax(); - mBounds[0].add(offset); - mExtents[0].add(offset); - mExtents[1].add(offset); - mObjectBounds[0].add(offset); - mObjectExtents[0].add(offset); - mObjectExtents[1].add(offset); - - //if (!mSpatialPartition->mRenderByGroup) - { - setState(GEOM_DIRTY); - gPipeline.markRebuild(this, TRUE); - } - - if (mOcclusionVerts.notNull()) - { - setState(OCCLUSION_DIRTY); - } -} - -class LLSpatialSetState : public LLSpatialGroup::OctreeTraveler -{ -public: - U32 mState; - LLSpatialSetState(U32 state) : mState(state) { } - virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->setState(mState); } -}; - -class LLSpatialSetStateDiff : public LLSpatialSetState -{ -public: - LLSpatialSetStateDiff(U32 state) : LLSpatialSetState(state) { } - - virtual void traverse(const LLSpatialGroup::OctreeNode* n) - { - LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0); - - if (!group->isState(mState)) - { - LLSpatialGroup::OctreeTraveler::traverse(n); - } - } -}; - -void LLSpatialGroup::setState(U32 state) -{ - mState |= state; - - llassert(state <= LLSpatialGroup::STATE_MASK); -} - -void LLSpatialGroup::setState(U32 state, S32 mode) -{ - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - - llassert(state <= LLSpatialGroup::STATE_MASK); - - if (mode > STATE_MODE_SINGLE) - { - if (mode == STATE_MODE_DIFF) - { - LLSpatialSetStateDiff setter(state); - setter.traverse(mOctreeNode); - } - else - { - LLSpatialSetState setter(state); - setter.traverse(mOctreeNode); - } - } - else - { - mState |= state; - } -} - -class LLSpatialClearState : public LLSpatialGroup::OctreeTraveler -{ -public: - U32 mState; - LLSpatialClearState(U32 state) : mState(state) { } - virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->clearState(mState); } -}; - -class LLSpatialClearStateDiff : public LLSpatialClearState -{ -public: - LLSpatialClearStateDiff(U32 state) : LLSpatialClearState(state) { } - - virtual void traverse(const LLSpatialGroup::OctreeNode* n) - { - LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0); - - if (group->isState(mState)) - { - LLSpatialGroup::OctreeTraveler::traverse(n); - } - } -}; - -void LLSpatialGroup::clearState(U32 state) -{ - llassert(state <= LLSpatialGroup::STATE_MASK); - - mState &= ~state; -} - -void LLSpatialGroup::clearState(U32 state, S32 mode) -{ - llassert(state <= LLSpatialGroup::STATE_MASK); - - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - - if (mode > STATE_MODE_SINGLE) - { - if (mode == STATE_MODE_DIFF) - { - LLSpatialClearStateDiff clearer(state); - clearer.traverse(mOctreeNode); - } - else - { - LLSpatialClearState clearer(state); - clearer.traverse(mOctreeNode); - } - } - else - { - mState &= ~state; - } -} - -BOOL LLSpatialGroup::isState(U32 state) const -{ - llassert(state <= LLSpatialGroup::STATE_MASK); - - return mState & state ? TRUE : FALSE; -} - -//===================================== -// Occlusion State Set/Clear -//===================================== -class LLSpatialSetOcclusionState : public LLSpatialGroup::OctreeTraveler -{ -public: - U32 mState; - LLSpatialSetOcclusionState(U32 state) : mState(state) { } - virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->setOcclusionState(mState); } -}; - -class LLSpatialSetOcclusionStateDiff : public LLSpatialSetOcclusionState -{ -public: - LLSpatialSetOcclusionStateDiff(U32 state) : LLSpatialSetOcclusionState(state) { } - - virtual void traverse(const LLSpatialGroup::OctreeNode* n) - { - LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0); - - if (!group->isOcclusionState(mState)) - { - LLSpatialGroup::OctreeTraveler::traverse(n); - } - } -}; - - -void LLSpatialGroup::setOcclusionState(U32 state, S32 mode) -{ - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - - if (mode > STATE_MODE_SINGLE) - { - if (mode == STATE_MODE_DIFF) - { - LLSpatialSetOcclusionStateDiff setter(state); - setter.traverse(mOctreeNode); - } - else if (mode == STATE_MODE_BRANCH) - { - LLSpatialSetOcclusionState setter(state); - setter.traverse(mOctreeNode); - } - else - { - for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) - { - mOcclusionState[i] |= state; - - if ((state & DISCARD_QUERY) && mOcclusionQuery[i]) - { - sQueryPool.release(mOcclusionQuery[i]); - mOcclusionQuery[i] = 0; - } - } - } - } - else - { - mOcclusionState[LLViewerCamera::sCurCameraID] |= state; - if ((state & DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID]) - { - sQueryPool.release(mOcclusionQuery[LLViewerCamera::sCurCameraID]); - mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0; - } - } -} - -class LLSpatialClearOcclusionState : public LLSpatialGroup::OctreeTraveler -{ -public: - U32 mState; - - LLSpatialClearOcclusionState(U32 state) : mState(state) { } - virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->clearOcclusionState(mState); } -}; - -class LLSpatialClearOcclusionStateDiff : public LLSpatialClearOcclusionState -{ -public: - LLSpatialClearOcclusionStateDiff(U32 state) : LLSpatialClearOcclusionState(state) { } - - virtual void traverse(const LLSpatialGroup::OctreeNode* n) - { - LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0); - - if (group->isOcclusionState(mState)) - { - LLSpatialGroup::OctreeTraveler::traverse(n); - } - } -}; - -void LLSpatialGroup::clearOcclusionState(U32 state, S32 mode) -{ - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - - if (mode > STATE_MODE_SINGLE) - { - if (mode == STATE_MODE_DIFF) - { - LLSpatialClearOcclusionStateDiff clearer(state); - clearer.traverse(mOctreeNode); - } - else if (mode == STATE_MODE_BRANCH) - { - LLSpatialClearOcclusionState clearer(state); - clearer.traverse(mOctreeNode); - } - else - { - for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) - { - mOcclusionState[i] &= ~state; - } - } - } - else - { - mOcclusionState[LLViewerCamera::sCurCameraID] &= ~state; - } -} -//====================================== -// Octree Listener Implementation -//====================================== - -LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) : - mState(0), - mGeometryBytes(0), - mSurfaceArea(0.f), - mBuilt(0.f), - mOctreeNode(node), - mSpatialPartition(part), - mVertexBuffer(NULL), - mBufferUsage(part->mBufferUsage), - mDistance(0.f), - mDepth(0.f), - mLastUpdateDistance(-1.f), - mLastUpdateTime(gFrameTimeSeconds), - mAtlasList(4), - mCurUpdatingTime(0), - mCurUpdatingSlotp(NULL), - mCurUpdatingTexture (NULL) -{ - sNodeCount++; - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - - mViewAngle.splat(0.f); - mLastUpdateViewAngle.splat(-1.f); - mExtents[0] = mExtents[1] = mObjectBounds[0] = mObjectBounds[0] = mObjectBounds[1] = - mObjectExtents[0] = mObjectExtents[1] = mViewAngle; - - sg_assert(mOctreeNode->getListenerCount() == 0); - mOctreeNode->addListener(this); - setState(SG_INITIAL_STATE_MASK); - gPipeline.markRebuild(this, TRUE); - - mBounds[0] = node->getCenter(); - mBounds[1] = node->getSize(); - - part->mLODSeed = (part->mLODSeed+1)%part->mLODPeriod; - mLODHash = part->mLODSeed; - - OctreeNode* oct_parent = node->getOctParent(); - - LLSpatialGroup* parent = oct_parent ? (LLSpatialGroup*) oct_parent->getListener(0) : NULL; - - for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) - { - mOcclusionQuery[i] = 0; - mOcclusionIssued[i] = 0; - mOcclusionState[i] = parent ? SG_STATE_INHERIT_MASK & parent->mOcclusionState[i] : 0; - mVisible[i] = 0; - } - - mOcclusionVerts = NULL; - - mRadius = 1; - mPixelArea = 1024.f; -} - -void LLSpatialGroup::updateDistance(LLCamera &camera) -{ - if (LLViewerCamera::sCurCameraID != LLViewerCamera::CAMERA_WORLD) - { - llwarns << "Attempted to update distance for camera other than world camera!" << llendl; - return; - } - -#if !LL_RELEASE_FOR_DOWNLOAD - if (isState(LLSpatialGroup::OBJECT_DIRTY)) - { - llerrs << "Spatial group dirty on distance update." << llendl; - } -#endif - if (!getData().empty()) - { - mRadius = mSpatialPartition->mRenderByGroup ? mObjectBounds[1].getLength3().getF32() : - (F32) mOctreeNode->getSize().getLength3().getF32(); - mDistance = mSpatialPartition->calcDistance(this, camera); - mPixelArea = mSpatialPartition->calcPixelArea(this, camera); - } -} - -F32 LLSpatialPartition::calcDistance(LLSpatialGroup* group, LLCamera& camera) -{ - LLVector4a eye; - LLVector4a origin; - origin.load3(camera.getOrigin().mV); - - eye.setSub(group->mObjectBounds[0], origin); - - F32 dist = 0.f; - - if (group->mDrawMap.find(LLRenderPass::PASS_ALPHA) != group->mDrawMap.end()) - { - LLVector4a v = eye; - - dist = eye.getLength3().getF32(); - eye.normalize3fast(); - - if (!group->isState(LLSpatialGroup::ALPHA_DIRTY)) - { - if (!group->mSpatialPartition->isBridge()) - { - LLVector4a view_angle = eye; - - LLVector4a diff; - diff.setSub(view_angle, group->mLastUpdateViewAngle); - - if (diff.getLength3().getF32() > 0.64f) - { - group->mViewAngle = view_angle; - group->mLastUpdateViewAngle = view_angle; - //for occasional alpha sorting within the group - //NOTE: If there is a trivial way to detect that alpha sorting here would not change the render order, - //not setting this node to dirty would be a very good thing - group->setState(LLSpatialGroup::ALPHA_DIRTY); - gPipeline.markRebuild(group, FALSE); - } - } - } - - //calculate depth of node for alpha sorting - - LLVector3 at = camera.getAtAxis(); - - LLVector4a ata; - ata.load3(at.mV); - - LLVector4a t = ata; - //front of bounding box - t.mul(0.25f); - t.mul(group->mObjectBounds[1]); - v.sub(t); - - group->mDepth = v.dot3(ata).getF32(); - } - else - { - dist = eye.getLength3().getF32(); - } - - if (dist < 16.f) - { - dist /= 16.f; - dist *= dist; - dist *= 16.f; - } - - return dist; -} - -F32 LLSpatialPartition::calcPixelArea(LLSpatialGroup* group, LLCamera& camera) -{ - return LLPipeline::calcPixelArea(group->mObjectBounds[0], group->mObjectBounds[1], camera); -} - -F32 LLSpatialGroup::getUpdateUrgency() const -{ - if (!isVisible()) - { - return 0.f; - } - else - { - F32 time = gFrameTimeSeconds-mLastUpdateTime+4.f; - return time + (mObjectBounds[1].dot3(mObjectBounds[1]).getF32()+1.f)/mDistance; - } -} - -BOOL LLSpatialGroup::needsUpdate() -{ - return (LLDrawable::getCurrentFrame()%mSpatialPartition->mLODPeriod == mLODHash) ? TRUE : FALSE; -} - -BOOL LLSpatialGroup::changeLOD() -{ - if (isState(ALPHA_DIRTY | OBJECT_DIRTY)) - { ///a rebuild is going to happen, update distance and LoD - return TRUE; - } - - if (mSpatialPartition->mSlopRatio > 0.f) - { - F32 ratio = (mDistance - mLastUpdateDistance)/(llmax(mLastUpdateDistance, mRadius)); - - if (fabsf(ratio) >= mSpatialPartition->mSlopRatio) - { - return TRUE; - } - - if (mDistance > mRadius*2.f) - { - return FALSE; - } - } - - if (needsUpdate()) - { - return TRUE; - } - - return FALSE; -} - -void LLSpatialGroup::handleInsertion(const TreeNode* node, LLDrawable* drawablep) -{ - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - addObject(drawablep, FALSE, TRUE); - unbound(); - setState(OBJECT_DIRTY); -} - -void LLSpatialGroup::handleRemoval(const TreeNode* node, LLDrawable* drawable) -{ - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - removeObject(drawable, TRUE); - setState(OBJECT_DIRTY); -} - -void LLSpatialGroup::handleDestruction(const TreeNode* node) -{ - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - setState(DEAD); - - for (element_iter i = getData().begin(); i != getData().end(); ++i) - { - LLDrawable* drawable = *i; - if (drawable->getSpatialGroup() == this) - { - drawable->setSpatialGroup(NULL); - } - } - - //clean up avatar attachment stats - LLSpatialBridge* bridge = mSpatialPartition->asBridge(); - if (bridge) - { - if (bridge->mAvatar.notNull()) - { - bridge->mAvatar->mAttachmentGeometryBytes -= mGeometryBytes; - bridge->mAvatar->mAttachmentSurfaceArea -= mSurfaceArea; - } - } - - clearDrawMap(); - mVertexBuffer = NULL; - mBufferMap.clear(); - sZombieGroups++; - mOctreeNode = NULL; -} - -void LLSpatialGroup::handleStateChange(const TreeNode* node) -{ - //drop bounding box upon state change - if (mOctreeNode != node) - { - mOctreeNode = (OctreeNode*) node; - } - unbound(); -} - -void LLSpatialGroup::handleChildAddition(const OctreeNode* parent, OctreeNode* child) -{ - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - if (child->getListenerCount() == 0) - { - new LLSpatialGroup(child, mSpatialPartition); - } - else - { - OCT_ERRS << "LLSpatialGroup redundancy detected." << llendl; - } - - unbound(); - - assert_states_valid(this); -} - -void LLSpatialGroup::handleChildRemoval(const OctreeNode* parent, const OctreeNode* child) -{ - unbound(); -} - -void LLSpatialGroup::destroyGL() -{ - setState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::IMAGE_DIRTY); - gPipeline.markRebuild(this, TRUE); - - mLastUpdateTime = gFrameTimeSeconds; - mVertexBuffer = NULL; - mBufferMap.clear(); - - clearDrawMap(); - - for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) - { - if (mOcclusionQuery[i]) - { - sQueryPool.release(mOcclusionQuery[i]); - mOcclusionQuery[i] = 0; - } - } - - mOcclusionVerts = NULL; - - for (LLSpatialGroup::element_iter i = getData().begin(); i != getData().end(); ++i) - { - LLDrawable* drawable = *i; - for (S32 j = 0; j < drawable->getNumFaces(); j++) - { - LLFace* facep = drawable->getFace(j); - facep->clearVertexBuffer(); - } - } -} - -BOOL LLSpatialGroup::rebound() -{ - if (!isState(DIRTY)) - { //return TRUE if we're not empty - return TRUE; - } - - if (mOctreeNode->getChildCount() == 1 && mOctreeNode->getElementCount() == 0) - { - LLSpatialGroup* group = (LLSpatialGroup*) mOctreeNode->getChild(0)->getListener(0); - group->rebound(); - - //copy single child's bounding box - mBounds[0] = group->mBounds[0]; - mBounds[1] = group->mBounds[1]; - mExtents[0] = group->mExtents[0]; - mExtents[1] = group->mExtents[1]; - - group->setState(SKIP_FRUSTUM_CHECK); - } - else if (mOctreeNode->isLeaf()) - { //copy object bounding box if this is a leaf - boundObjects(TRUE, mExtents[0], mExtents[1]); - mBounds[0] = mObjectBounds[0]; - mBounds[1] = mObjectBounds[1]; - } - else - { - LLVector4a& newMin = mExtents[0]; - LLVector4a& newMax = mExtents[1]; - LLSpatialGroup* group = (LLSpatialGroup*) mOctreeNode->getChild(0)->getListener(0); - group->clearState(SKIP_FRUSTUM_CHECK); - group->rebound(); - //initialize to first child - newMin = group->mExtents[0]; - newMax = group->mExtents[1]; - - //first, rebound children - for (U32 i = 1; i < mOctreeNode->getChildCount(); i++) - { - group = (LLSpatialGroup*) mOctreeNode->getChild(i)->getListener(0); - group->clearState(SKIP_FRUSTUM_CHECK); - group->rebound(); - const LLVector4a& max = group->mExtents[1]; - const LLVector4a& min = group->mExtents[0]; - - newMax.setMax(newMax, max); - newMin.setMin(newMin, min); - } - - boundObjects(FALSE, newMin, newMax); - - mBounds[0].setAdd(newMin, newMax); - mBounds[0].mul(0.5f); - mBounds[1].setSub(newMax, newMin); - 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"); - -void LLSpatialGroup::checkOcclusion() -{ - if (LLPipeline::sUseOcclusion > 1) - { - LLFastTimer t(FTM_OCCLUSION_READBACK); - LLSpatialGroup* parent = getParent(); - if (parent && parent->isOcclusionState(LLSpatialGroup::OCCLUDED)) - { //if the parent has been marked as occluded, the child is implicitly occluded - clearOcclusionState(QUERY_PENDING | DISCARD_QUERY); - } - else if (isOcclusionState(QUERY_PENDING)) - { //otherwise, if a query is pending, read it back - - GLuint available = 0; - if (mOcclusionQuery[LLViewerCamera::sCurCameraID]) - { - glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available); - - if (mOcclusionIssued[LLViewerCamera::sCurCameraID] < gFrameCount) - { //query was issued last frame, wait until it's available - S32 max_loop = 1024; - LLFastTimer t(FTM_OCCLUSION_WAIT); - while (!available && max_loop-- > 0) - { - F32 max_time = llmin(gFrameIntervalSeconds*10.f, 1.f); - //do some usefu 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 - - glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available); - } - } - } - else - { - available = 1; - } - - if (available) - { //result is available, read it back, otherwise wait until next frame - GLuint res = 1; - if (!isOcclusionState(DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID]) - { - glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_ARB, &res); -#if LL_TRACK_PENDING_OCCLUSION_QUERIES - sPendingQueries.erase(mOcclusionQuery[LLViewerCamera::sCurCameraID]); -#endif - } - else if (mOcclusionQuery[LLViewerCamera::sCurCameraID]) - { //delete the query to avoid holding onto hundreds of pending queries - sQueryPool.release(mOcclusionQuery[LLViewerCamera::sCurCameraID]); - mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0; - } - - if (isOcclusionState(DISCARD_QUERY)) - { - res = 2; - } - - if (res > 0) - { - assert_states_valid(this); - clearOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF); - assert_states_valid(this); - } - else - { - assert_states_valid(this); - setOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF); - assert_states_valid(this); - } - - clearOcclusionState(QUERY_PENDING | DISCARD_QUERY); - } - } - else if (mSpatialPartition->isOcclusionEnabled() && isOcclusionState(LLSpatialGroup::OCCLUDED)) - { //check occlusion has been issued for occluded node that has not had a query issued - assert_states_valid(this); - clearOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF); - assert_states_valid(this); - } - } -} - -static LLFastTimer::DeclareTimer FTM_PUSH_OCCLUSION_VERTS("Push Occlusion"); -static LLFastTimer::DeclareTimer FTM_SET_OCCLUSION_STATE("Occlusion State"); -static LLFastTimer::DeclareTimer FTM_OCCLUSION_EARLY_FAIL("Occlusion Early Fail"); -static LLFastTimer::DeclareTimer FTM_OCCLUSION_ALLOCATE("Allocate"); -static LLFastTimer::DeclareTimer FTM_OCCLUSION_BUILD("Build"); -static LLFastTimer::DeclareTimer FTM_OCCLUSION_BEGIN_QUERY("Begin Query"); -static LLFastTimer::DeclareTimer FTM_OCCLUSION_END_QUERY("End Query"); -static LLFastTimer::DeclareTimer FTM_OCCLUSION_SET_BUFFER("Set Buffer"); -static LLFastTimer::DeclareTimer FTM_OCCLUSION_DRAW_WATER("Draw Water"); -static LLFastTimer::DeclareTimer FTM_OCCLUSION_DRAW("Draw"); - - - -void LLSpatialGroup::doOcclusion(LLCamera* camera) -{ - if (mSpatialPartition->isOcclusionEnabled() && LLPipeline::sUseOcclusion > 1) - { - // Don't cull hole/edge water, unless we have the GL_ARB_depth_clamp extension - if (earlyFail(camera, this)) - { - LLFastTimer t(FTM_OCCLUSION_EARLY_FAIL); - setOcclusionState(LLSpatialGroup::DISCARD_QUERY); - assert_states_valid(this); - clearOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF); - assert_states_valid(this); - } - else - { - if (!isOcclusionState(QUERY_PENDING) || isOcclusionState(DISCARD_QUERY)) - { - { //no query pending, or previous query to be discarded - LLFastTimer t(FTM_RENDER_OCCLUSION); - - if (!mOcclusionQuery[LLViewerCamera::sCurCameraID]) - { - LLFastTimer t(FTM_OCCLUSION_ALLOCATE); - 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. - bool const use_depth_clamp = gGLManager.mHasDepthClamp && - (mSpatialPartition->mDrawableType == LLDrawPool::POOL_WATER || - mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER); - - LLGLEnable clamp(use_depth_clamp ? GL_DEPTH_CLAMP : 0); - -#if !LL_DARWIN - U32 mode = gGLManager.mHasOcclusionQuery2 ? GL_ANY_SAMPLES_PASSED : GL_SAMPLES_PASSED_ARB; -#else - U32 mode = GL_SAMPLES_PASSED_ARB; -#endif - -#if LL_TRACK_PENDING_OCCLUSION_QUERIES - sPendingQueries.insert(mOcclusionQuery[LLViewerCamera::sCurCameraID]); -#endif - - { - LLFastTimer t(FTM_PUSH_OCCLUSION_VERTS); - - //store which frame this query was issued on - mOcclusionIssued[LLViewerCamera::sCurCameraID] = gFrameCount; - - { - LLFastTimer t(FTM_OCCLUSION_BEGIN_QUERY); - glBeginQueryARB(mode, mOcclusionQuery[LLViewerCamera::sCurCameraID]); - } - - { - LLFastTimer t(FTM_OCCLUSION_SET_BUFFER); - mOcclusionVerts->setBuffer(LLVertexBuffer::MAP_VERTEX); - } - - if (!use_depth_clamp && mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER) - { - LLFastTimer t(FTM_OCCLUSION_DRAW_WATER); - - 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); - } - else - { - mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0])); - } - } - else - { - 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); - } - else - { - mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0])); - } - } - - - { - LLFastTimer t(FTM_OCCLUSION_END_QUERY); - glEndQueryARB(mode); - } - } - } - - { - LLFastTimer t(FTM_SET_OCCLUSION_STATE); - setOcclusionState(LLSpatialGroup::QUERY_PENDING); - clearOcclusionState(LLSpatialGroup::DISCARD_QUERY); - } - } - } - } -} - -//============================================== - -LLSpatialPartition::LLSpatialPartition(U32 data_mask, BOOL render_by_group, U32 buffer_usage) -: mRenderByGroup(render_by_group), mBridge(NULL) -{ - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - mOcclusionEnabled = TRUE; - mDrawableType = 0; - mPartitionType = LLViewerRegion::PARTITION_NONE; - mLODSeed = 0; - mLODPeriod = 1; - mVertexDataMask = data_mask; - mBufferUsage = buffer_usage; - mDepthMask = FALSE; - mSlopRatio = 0.25f; - mInfiniteFarClip = FALSE; - - LLVector4a center, size; - center.splat(0.f); - size.splat(1.f); - - mOctree = new LLSpatialGroup::OctreeRoot(center,size, - NULL); - new LLSpatialGroup(mOctree, this); -} - - -LLSpatialPartition::~LLSpatialPartition() -{ - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - - delete mOctree; - mOctree = NULL; -} - - -LLSpatialGroup *LLSpatialPartition::put(LLDrawable *drawablep, BOOL was_visible) -{ - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - - drawablep->updateSpatialExtents(); - - //keep drawable from being garbage collected - LLPointer<LLDrawable> ptr = drawablep; - - assert_octree_valid(mOctree); - mOctree->insert(drawablep); - assert_octree_valid(mOctree); - - LLSpatialGroup* group = drawablep->getSpatialGroup(); - - if (group && was_visible && group->isOcclusionState(LLSpatialGroup::QUERY_PENDING)) - { - group->setOcclusionState(LLSpatialGroup::DISCARD_QUERY, LLSpatialGroup::STATE_MODE_ALL_CAMERAS); - } - - return group; -} - -BOOL LLSpatialPartition::remove(LLDrawable *drawablep, LLSpatialGroup *curp) -{ - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - - drawablep->setSpatialGroup(NULL); - - if (!curp->removeObject(drawablep)) - { - OCT_ERRS << "Failed to remove drawable from octree!" << llendl; - } - - assert_octree_valid(mOctree); - - return TRUE; -} - -void LLSpatialPartition::move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL immediate) -{ - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - - // sanity check submitted by open source user bushing Spatula - // who was seeing crashing here. (See VWR-424 reported by Bunny Mayne) - if (!drawablep) - { - OCT_ERRS << "LLSpatialPartition::move was passed a bad drawable." << llendl; - return; - } - - BOOL was_visible = curp ? curp->isVisible() : FALSE; - - if (curp && curp->mSpatialPartition != this) - { - //keep drawable from being garbage collected - LLPointer<LLDrawable> ptr = drawablep; - if (curp->mSpatialPartition->remove(drawablep, curp)) - { - put(drawablep, was_visible); - return; - } - else - { - OCT_ERRS << "Drawable lost between spatial partitions on outbound transition." << llendl; - } - } - - if (curp && curp->updateInGroup(drawablep, immediate)) - { - // Already updated, don't need to do anything - assert_octree_valid(mOctree); - return; - } - - //keep drawable from being garbage collected - LLPointer<LLDrawable> ptr = drawablep; - if (curp && !remove(drawablep, curp)) - { - OCT_ERRS << "Move couldn't find existing spatial group!" << llendl; - } - - put(drawablep, was_visible); -} - -class LLSpatialShift : public LLSpatialGroup::OctreeTraveler -{ -public: - const LLVector4a& mOffset; - - LLSpatialShift(const LLVector4a& offset) : mOffset(offset) { } - virtual void visit(const LLSpatialGroup::OctreeNode* branch) - { - ((LLSpatialGroup*) branch->getListener(0))->shift(mOffset); - } -}; - -void LLSpatialPartition::shift(const LLVector4a &offset) -{ //shift octree node bounding boxes by offset - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - LLSpatialShift shifter(offset); - shifter.traverse(mOctree); -} - -class LLOctreeCull : public LLSpatialGroup::OctreeTraveler -{ -public: - LLOctreeCull(LLCamera* camera) - : mCamera(camera), mRes(0) { } - - virtual bool earlyFail(LLSpatialGroup* group) - { - group->checkOcclusion(); - - if (group->mOctreeNode->getParent() && //never occlusion cull the root node - LLPipeline::sUseOcclusion && //ignore occlusion if disabled - group->isOcclusionState(LLSpatialGroup::OCCLUDED)) - { - gPipeline.markOccluder(group); - return true; - } - - return false; - } - - virtual void traverse(const LLSpatialGroup::OctreeNode* n) - { - LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0); - - if (earlyFail(group)) - { - return; - } - - if (mRes == 2 || - (mRes && group->isState(LLSpatialGroup::SKIP_FRUSTUM_CHECK))) - { //fully in, just add everything - LLSpatialGroup::OctreeTraveler::traverse(n); - } - else - { - mRes = frustumCheck(group); - - if (mRes) - { //at least partially in, run on down - LLSpatialGroup::OctreeTraveler::traverse(n); - } - - mRes = 0; - } - } - - virtual S32 frustumCheck(const LLSpatialGroup* group) - { - S32 res = mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]); - if (res != 0) - { - res = llmin(res, AABBSphereIntersect(group->mExtents[0], group->mExtents[1], mCamera->getOrigin(), mCamera->mFrustumCornerDist)); - } - return res; - } - - virtual S32 frustumCheckObjects(const LLSpatialGroup* group) - { - S32 res = mCamera->AABBInFrustumNoFarClip(group->mObjectBounds[0], group->mObjectBounds[1]); - if (res != 0) - { - res = llmin(res, AABBSphereIntersect(group->mObjectExtents[0], group->mObjectExtents[1], mCamera->getOrigin(), mCamera->mFrustumCornerDist)); - } - return res; - } - - virtual bool checkObjects(const LLSpatialGroup::OctreeNode* branch, const LLSpatialGroup* group) - { - if (branch->getElementCount() == 0) //no elements - { - return false; - } - else if (branch->getChildCount() == 0) //leaf state, already checked tightest bounding box - { - return true; - } - else if (mRes == 1 && !frustumCheckObjects(group)) //no objects in frustum - { - return false; - } - - return true; - } - - virtual void preprocess(LLSpatialGroup* group) - { - - } - - virtual void processGroup(LLSpatialGroup* group) - { - if (group->needsUpdate() || - group->mVisible[LLViewerCamera::sCurCameraID] < LLDrawable::getCurrentFrame() - 1) - { - group->doOcclusion(mCamera); - } - gPipeline.markNotCulled(group, *mCamera); - } - - virtual void visit(const LLSpatialGroup::OctreeNode* branch) - { - LLSpatialGroup* group = (LLSpatialGroup*) branch->getListener(0); - - preprocess(group); - - if (checkObjects(branch, group)) - { - processGroup(group); - } - } - - LLCamera *mCamera; - S32 mRes; -}; - -class LLOctreeCullNoFarClip : public LLOctreeCull -{ -public: - LLOctreeCullNoFarClip(LLCamera* camera) - : LLOctreeCull(camera) { } - - virtual S32 frustumCheck(const LLSpatialGroup* group) - { - return mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]); - } - - virtual S32 frustumCheckObjects(const LLSpatialGroup* group) - { - S32 res = mCamera->AABBInFrustumNoFarClip(group->mObjectBounds[0], group->mObjectBounds[1]); - return res; - } -}; - -class LLOctreeCullShadow : public LLOctreeCull -{ -public: - LLOctreeCullShadow(LLCamera* camera) - : LLOctreeCull(camera) { } - - virtual S32 frustumCheck(const LLSpatialGroup* group) - { - return mCamera->AABBInFrustum(group->mBounds[0], group->mBounds[1]); - } - - virtual S32 frustumCheckObjects(const LLSpatialGroup* group) - { - return mCamera->AABBInFrustum(group->mObjectBounds[0], group->mObjectBounds[1]); - } -}; - -class LLOctreeCullVisExtents: public LLOctreeCullShadow -{ -public: - LLOctreeCullVisExtents(LLCamera* camera, LLVector4a& min, LLVector4a& max) - : LLOctreeCullShadow(camera), mMin(min), mMax(max), mEmpty(TRUE) { } - - virtual bool earlyFail(LLSpatialGroup* group) - { - if (group->mOctreeNode->getParent() && //never occlusion cull the root node - LLPipeline::sUseOcclusion && //ignore occlusion if disabled - group->isOcclusionState(LLSpatialGroup::OCCLUDED)) - { - return true; - } - - return false; - } - - virtual void traverse(const LLSpatialGroup::OctreeNode* n) - { - LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0); - - if (earlyFail(group)) - { - return; - } - - if ((mRes && group->isState(LLSpatialGroup::SKIP_FRUSTUM_CHECK)) || - mRes == 2) - { //don't need to do frustum check - LLSpatialGroup::OctreeTraveler::traverse(n); - } - else - { - mRes = frustumCheck(group); - - if (mRes) - { //at least partially in, run on down - LLSpatialGroup::OctreeTraveler::traverse(n); - } - - mRes = 0; - } - } - - virtual void processGroup(LLSpatialGroup* group) - { - llassert(!group->isState(LLSpatialGroup::DIRTY) && !group->getData().empty()) - - if (mRes < 2) - { - if (mCamera->AABBInFrustum(group->mObjectBounds[0], group->mObjectBounds[1]) > 0) - { - mEmpty = FALSE; - update_min_max(mMin, mMax, group->mObjectExtents[0]); - update_min_max(mMin, mMax, group->mObjectExtents[1]); - } - } - else - { - mEmpty = FALSE; - update_min_max(mMin, mMax, group->mExtents[0]); - update_min_max(mMin, mMax, group->mExtents[1]); - } - } - - BOOL mEmpty; - LLVector4a& mMin; - LLVector4a& mMax; -}; - -class LLOctreeCullDetectVisible: public LLOctreeCullShadow -{ -public: - LLOctreeCullDetectVisible(LLCamera* camera) - : LLOctreeCullShadow(camera), mResult(FALSE) { } - - virtual bool earlyFail(LLSpatialGroup* group) - { - if (mResult || //already found a node, don't check any more - (group->mOctreeNode->getParent() && //never occlusion cull the root node - LLPipeline::sUseOcclusion && //ignore occlusion if disabled - group->isOcclusionState(LLSpatialGroup::OCCLUDED))) - { - return true; - } - - return false; - } - - virtual void processGroup(LLSpatialGroup* group) - { - if (group->isVisible()) - { - mResult = TRUE; - } - } - - BOOL mResult; -}; - -class LLOctreeSelect : public LLOctreeCull -{ -public: - LLOctreeSelect(LLCamera* camera, std::vector<LLDrawable*>* results) - : LLOctreeCull(camera), mResults(results) { } - - virtual bool earlyFail(LLSpatialGroup* group) { return false; } - virtual void preprocess(LLSpatialGroup* group) { } - - virtual void processGroup(LLSpatialGroup* group) - { - LLSpatialGroup::OctreeNode* branch = group->mOctreeNode; - - for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i) - { - LLDrawable* drawable = *i; - - if (!drawable->isDead()) - { - if (drawable->isSpatialBridge()) - { - drawable->setVisible(*mCamera, mResults, TRUE); - } - else - { - mResults->push_back(drawable); - } - } - } - } - - std::vector<LLDrawable*>* mResults; -}; - -void drawBox(const LLVector3& c, const LLVector3& r) -{ - LLVertexBuffer::unbind(); - - gGL.begin(LLRender::TRIANGLE_STRIP); - //left front - gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,-1))).mV); - gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,1))).mV); - //right front - gGL.vertex3fv((c+r.scaledVec(LLVector3(1,1,-1))).mV); - gGL.vertex3fv((c+r.scaledVec(LLVector3(1,1,1))).mV); - //right back - gGL.vertex3fv((c+r.scaledVec(LLVector3(1,-1,-1))).mV); - gGL.vertex3fv((c+r.scaledVec(LLVector3(1,-1,1))).mV); - //left back - gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,-1,-1))).mV); - gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,-1,1))).mV); - //left front - gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,-1))).mV); - gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,1))).mV); - gGL.end(); - - //bottom - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.vertex3fv((c+r.scaledVec(LLVector3(1,1,-1))).mV); - gGL.vertex3fv((c+r.scaledVec(LLVector3(1,-1,-1))).mV); - gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,-1))).mV); - gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,-1,-1))).mV); - gGL.end(); - - //top - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.vertex3fv((c+r.scaledVec(LLVector3(1,1,1))).mV); - gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,1))).mV); - gGL.vertex3fv((c+r.scaledVec(LLVector3(1,-1,1))).mV); - gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,-1,1))).mV); - gGL.end(); -} - -void drawBox(const LLVector4a& c, const LLVector4a& r) -{ - drawBox(reinterpret_cast<const LLVector3&>(c), reinterpret_cast<const LLVector3&>(r)); -} - -void drawBoxOutline(const LLVector3& pos, const LLVector3& size) -{ - LLVector3 v1 = size.scaledVec(LLVector3( 1, 1,1)); - LLVector3 v2 = size.scaledVec(LLVector3(-1, 1,1)); - LLVector3 v3 = size.scaledVec(LLVector3(-1,-1,1)); - LLVector3 v4 = size.scaledVec(LLVector3( 1,-1,1)); - - gGL.begin(LLRender::LINES); - - //top - gGL.vertex3fv((pos+v1).mV); - gGL.vertex3fv((pos+v2).mV); - gGL.vertex3fv((pos+v2).mV); - gGL.vertex3fv((pos+v3).mV); - gGL.vertex3fv((pos+v3).mV); - gGL.vertex3fv((pos+v4).mV); - gGL.vertex3fv((pos+v4).mV); - gGL.vertex3fv((pos+v1).mV); - - //bottom - gGL.vertex3fv((pos-v1).mV); - gGL.vertex3fv((pos-v2).mV); - gGL.vertex3fv((pos-v2).mV); - gGL.vertex3fv((pos-v3).mV); - gGL.vertex3fv((pos-v3).mV); - gGL.vertex3fv((pos-v4).mV); - gGL.vertex3fv((pos-v4).mV); - gGL.vertex3fv((pos-v1).mV); - - //right - gGL.vertex3fv((pos+v1).mV); - gGL.vertex3fv((pos-v3).mV); - - gGL.vertex3fv((pos+v4).mV); - gGL.vertex3fv((pos-v2).mV); - - //left - gGL.vertex3fv((pos+v2).mV); - gGL.vertex3fv((pos-v4).mV); - - gGL.vertex3fv((pos+v3).mV); - gGL.vertex3fv((pos-v1).mV); - - gGL.end(); -} - -void drawBoxOutline(const LLVector4a& pos, const LLVector4a& size) -{ - drawBoxOutline(reinterpret_cast<const LLVector3&>(pos), reinterpret_cast<const LLVector3&>(size)); -} - -class LLOctreeDirty : public LLOctreeTraveler<LLDrawable> -{ -public: - virtual void visit(const LLOctreeNode<LLDrawable>* state) - { - LLSpatialGroup* group = (LLSpatialGroup*) state->getListener(0); - group->destroyGL(); - - for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) - { - LLDrawable* drawable = *i; - if (drawable->getVObj().notNull() && !group->mSpatialPartition->mRenderByGroup) - { - gPipeline.markRebuild(drawable, LLDrawable::REBUILD_ALL, TRUE); - } - } - - for (LLSpatialGroup::bridge_list_t::iterator i = group->mBridgeList.begin(); i != group->mBridgeList.end(); ++i) - { - LLSpatialBridge* bridge = *i; - traverse(bridge->mOctree); - } - } -}; - -void LLSpatialPartition::restoreGL() -{ - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); -} - -void LLSpatialPartition::resetVertexBuffers() -{ - LLOctreeDirty dirty; - dirty.traverse(mOctree); -} - -BOOL LLSpatialPartition::isOcclusionEnabled() -{ - return mOcclusionEnabled || LLPipeline::sUseOcclusion > 2; -} - -BOOL LLSpatialPartition::getVisibleExtents(LLCamera& camera, LLVector3& visMin, LLVector3& visMax) -{ - LLVector4a visMina, visMaxa; - visMina.load3(visMin.mV); - visMaxa.load3(visMax.mV); - - { - LLFastTimer ftm(FTM_CULL_REBOUND); - LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0); - group->rebound(); - } - - LLOctreeCullVisExtents vis(&camera, visMina, visMaxa); - vis.traverse(mOctree); - - visMin.set(visMina.getF32ptr()); - visMax.set(visMaxa.getF32ptr()); - return vis.mEmpty; -} - -BOOL LLSpatialPartition::visibleObjectsInFrustum(LLCamera& camera) -{ - LLOctreeCullDetectVisible vis(&camera); - vis.traverse(mOctree); - return vis.mResult; -} - -S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* results, BOOL for_select) -{ - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); -#if LL_OCTREE_PARANOIA_CHECK - ((LLSpatialGroup*)mOctree->getListener(0))->checkStates(); -#endif - { - LLFastTimer ftm(FTM_CULL_REBOUND); - LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0); - group->rebound(); - } - -#if LL_OCTREE_PARANOIA_CHECK - ((LLSpatialGroup*)mOctree->getListener(0))->validate(); -#endif - - - if (for_select) - { - LLOctreeSelect selecter(&camera, results); - selecter.traverse(mOctree); - } - else if (LLPipeline::sShadowRender) - { - LLFastTimer ftm(FTM_FRUSTUM_CULL); - LLOctreeCullShadow culler(&camera); - culler.traverse(mOctree); - } - else if (mInfiniteFarClip || !LLPipeline::sUseFarClip) - { - LLFastTimer ftm(FTM_FRUSTUM_CULL); - LLOctreeCullNoFarClip culler(&camera); - culler.traverse(mOctree); - } - else - { - LLFastTimer ftm(FTM_FRUSTUM_CULL); - LLOctreeCull culler(&camera); - culler.traverse(mOctree); - } - - return 0; -} - -BOOL earlyFail(LLCamera* camera, LLSpatialGroup* group) -{ - if (camera->getOrigin().isExactlyZero()) - { - return FALSE; - } - - const F32 vel = SG_OCCLUSION_FUDGE*2.f; - LLVector4a fudge; - fudge.splat(vel); - - const LLVector4a& c = group->mBounds[0]; - LLVector4a r; - r.setAdd(group->mBounds[1], fudge); - - /*if (r.magVecSquared() > 1024.0*1024.0) - { - return TRUE; - }*/ - - LLVector4a e; - e.load3(camera->getOrigin().mV); - - LLVector4a min; - min.setSub(c,r); - LLVector4a max; - max.setAdd(c,r); - - S32 lt = e.lessThan(min).getGatheredBits() & 0x7; - if (lt) - { - return FALSE; - } - - S32 gt = e.greaterThan(max).getGatheredBits() & 0x7; - if (gt) - { - return FALSE; - } - - return TRUE; -} - - -void pushVerts(LLDrawInfo* params, U32 mask) -{ - LLRenderPass::applyModelMatrix(*params); - params->mVertexBuffer->setBuffer(mask); - params->mVertexBuffer->drawRange(params->mParticle ? LLRender::POINTS : LLRender::TRIANGLES, - params->mStart, params->mEnd, params->mCount, params->mOffset); -} - -void pushVerts(LLSpatialGroup* group, U32 mask) -{ - LLDrawInfo* params = NULL; - - for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i) - { - for (LLSpatialGroup::drawmap_elem_t::iterator j = i->second.begin(); j != i->second.end(); ++j) - { - params = *j; - pushVerts(params, mask); - } - } -} - -void pushVerts(LLFace* face, U32 mask) -{ - llassert(face->verify()); - - 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); - } -} - -void pushVerts(LLDrawable* drawable, U32 mask) -{ - for (S32 i = 0; i < drawable->getNumFaces(); ++i) - { - pushVerts(drawable->getFace(i), mask); - } -} - -void pushVerts(LLVolume* volume) -{ - LLVertexBuffer::unbind(); - for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i) - { - const LLVolumeFace& face = volume->getVolumeFace(i); - LLVertexBuffer::drawElements(LLRender::TRIANGLES, face.mPositions, NULL, face.mNumIndices, face.mIndices); - } -} - -void pushBufferVerts(LLVertexBuffer* buffer, U32 mask) -{ - if (buffer) - { - buffer->setBuffer(mask); - buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); - } -} - -void pushBufferVerts(LLSpatialGroup* group, U32 mask) -{ - if (group->mSpatialPartition->mRenderByGroup) - { - if (!group->mDrawMap.empty()) - { - LLDrawInfo* params = *(group->mDrawMap.begin()->second.begin()); - LLRenderPass::applyModelMatrix(*params); - - pushBufferVerts(group->mVertexBuffer, mask); - - for (LLSpatialGroup::buffer_map_t::iterator i = group->mBufferMap.begin(); i != group->mBufferMap.end(); ++i) - { - for (LLSpatialGroup::buffer_texture_map_t::iterator j = i->second.begin(); j != i->second.end(); ++j) - { - for (LLSpatialGroup::buffer_list_t::iterator k = j->second.begin(); k != j->second.end(); ++k) - { - pushBufferVerts(*k, mask); - } - } - } - } - } - else - { - drawBox(group->mBounds[0], group->mBounds[1]); - } -} - -void pushVertsColorCoded(LLSpatialGroup* group, U32 mask) -{ - LLDrawInfo* params = NULL; - - LLColor4 colors[] = { - LLColor4::green, - LLColor4::green1, - LLColor4::green2, - LLColor4::green3, - LLColor4::green4, - LLColor4::green5, - LLColor4::green6 - }; - - static const U32 col_count = LL_ARRAY_SIZE(colors); - - U32 col = 0; - - for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i) - { - for (LLSpatialGroup::drawmap_elem_t::iterator j = i->second.begin(); j != i->second.end(); ++j) - { - params = *j; - LLRenderPass::applyModelMatrix(*params); - gGL.diffuseColor4f(colors[col].mV[0], colors[col].mV[1], colors[col].mV[2], 0.5f); - params->mVertexBuffer->setBuffer(mask); - params->mVertexBuffer->drawRange(params->mParticle ? LLRender::POINTS : LLRender::TRIANGLES, - params->mStart, params->mEnd, params->mCount, params->mOffset); - col = (col+1)%col_count; - } - } -} - -void renderOctree(LLSpatialGroup* group) -{ - //render solid object bounding box, color - //coded by buffer usage and activity - gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA); - LLVector4 col; - if (group->mBuilt > 0.f) - { - group->mBuilt -= 2.f * gFrameIntervalSeconds; - if (group->mBufferUsage == GL_STATIC_DRAW_ARB) - { - col.setVec(1.0f, 0, 0, group->mBuilt*0.5f); - } - else - { - col.setVec(0.1f,0.1f,1,0.1f); - //col.setVec(1.0f, 1.0f, 0, sinf(group->mBuilt*3.14159f)*0.5f); - } - - if (group->mBufferUsage != GL_STATIC_DRAW_ARB) - { - LLGLDepthTest gl_depth(FALSE, FALSE); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - - gGL.diffuseColor4f(1,0,0,group->mBuilt); - gGL.flush(); - glLineWidth(5.f); - drawBoxOutline(group->mObjectBounds[0], group->mObjectBounds[1]); - gGL.flush(); - glLineWidth(1.f); - gGL.flush(); - for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) - { - LLDrawable* drawable = *i; - if (!group->mSpatialPartition->isBridge()) - { - gGL.pushMatrix(); - LLVector3 trans = drawable->getRegion()->getOriginAgent(); - gGL.translatef(trans.mV[0], trans.mV[1], trans.mV[2]); - } - - for (S32 j = 0; j < drawable->getNumFaces(); j++) - { - LLFace* face = drawable->getFace(j); - if (face->getVertexBuffer()) - { - if (gFrameTimeSeconds - face->mLastUpdateTime < 0.5f) - { - gGL.diffuseColor4f(0, 1, 0, group->mBuilt); - } - else if (gFrameTimeSeconds - face->mLastMoveTime < 0.5f) - { - gGL.diffuseColor4f(1, 0, 0, group->mBuilt); - } - else - { - continue; - } - - face->getVertexBuffer()->setBuffer(LLVertexBuffer::MAP_VERTEX); - //drawBox((face->mExtents[0] + face->mExtents[1])*0.5f, - // (face->mExtents[1]-face->mExtents[0])*0.5f); - face->getVertexBuffer()->draw(LLRender::TRIANGLES, face->getIndicesCount(), face->getIndicesStart()); - } - } - - if (!group->mSpatialPartition->isBridge()) - { - gGL.popMatrix(); - } - } - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - gGL.diffuseColor4f(1,1,1,1); - } - } - else - { - if (group->mBufferUsage == GL_STATIC_DRAW_ARB && !group->getData().empty() - && group->mSpatialPartition->mRenderByGroup) - { - col.setVec(0.8f, 0.4f, 0.1f, 0.1f); - } - else - { - col.setVec(0.1f, 0.1f, 1.f, 0.1f); - } - } - - gGL.diffuseColor4fv(col.mV); - LLVector4a fudge; - fudge.splat(0.001f); - LLVector4a size = group->mObjectBounds[1]; - size.mul(1.01f); - size.add(fudge); - - //{ - // LLGLDepthTest depth(GL_TRUE, GL_FALSE); - // drawBox(group->mObjectBounds[0], fudge); - //} - - gGL.setSceneBlendType(LLRender::BT_ALPHA); - - //if (group->mBuilt <= 0.f) - { - //draw opaque outline - //gGL.diffuseColor4f(col.mV[0], col.mV[1], col.mV[2], 1.f); - //drawBoxOutline(group->mObjectBounds[0], group->mObjectBounds[1]); - - gGL.diffuseColor4f(0,1,1,1); - drawBoxOutline(group->mBounds[0],group->mBounds[1]); - - //draw bounding box for draw info - /*if (group->mSpatialPartition->mRenderByGroup) - { - gGL.diffuseColor4f(1.0f, 0.75f, 0.25f, 0.6f); - for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i) - { - for (LLSpatialGroup::drawmap_elem_t::iterator j = i->second.begin(); j != i->second.end(); ++j) - { - LLDrawInfo* draw_info = *j; - LLVector4a center; - center.setAdd(draw_info->mExtents[1], draw_info->mExtents[0]); - center.mul(0.5f); - LLVector4a size; - size.setSub(draw_info->mExtents[1], draw_info->mExtents[0]); - size.mul(0.5f); - drawBoxOutline(center, size); - } - } - }*/ - } - -// LLSpatialGroup::OctreeNode* node = group->mOctreeNode; -// gGL.diffuseColor4f(0,1,0,1); -// drawBoxOutline(LLVector3(node->getCenter()), LLVector3(node->getSize())); -} - -void renderVisibility(LLSpatialGroup* group, LLCamera* camera) -{ - LLGLEnable blend(GL_BLEND); - gGL.setSceneBlendType(LLRender::BT_ALPHA); - LLGLEnable cull(GL_CULL_FACE); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - - BOOL render_objects = (!LLPipeline::sUseOcclusion || !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) && group->isVisible() && - !group->getData().empty(); - - if (render_objects) - { - LLGLDepthTest depth_under(GL_TRUE, GL_FALSE, GL_GREATER); - gGL.diffuseColor4f(0, 0.5f, 0, 0.5f); - gGL.diffuseColor4f(0, 0.5f, 0, 0.5f); - pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX); - } - - { - LLGLDepthTest depth_over(GL_TRUE, GL_FALSE, GL_LEQUAL); - - if (render_objects) - { - gGL.diffuseColor4f(0.f, 0.5f, 0.f,1.f); - gGL.diffuseColor4f(0.f, 0.5f, 0.f, 1.f); - pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX); - } - - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - - if (render_objects) - { - gGL.diffuseColor4f(0.f, 0.75f, 0.f,0.5f); - 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); - }*/ - } -} - -void renderCrossHairs(LLVector3 position, F32 size, LLColor4 color) -{ - gGL.diffuseColor4fv(color.mV); - gGL.begin(LLRender::LINES); - { - gGL.vertex3fv((position - LLVector3(size, 0.f, 0.f)).mV); - gGL.vertex3fv((position + LLVector3(size, 0.f, 0.f)).mV); - gGL.vertex3fv((position - LLVector3(0.f, size, 0.f)).mV); - gGL.vertex3fv((position + LLVector3(0.f, size, 0.f)).mV); - gGL.vertex3fv((position - LLVector3(0.f, 0.f, size)).mV); - gGL.vertex3fv((position + LLVector3(0.f, 0.f, size)).mV); - } - gGL.end(); -} - -void renderUpdateType(LLDrawable* drawablep) -{ - LLViewerObject* vobj = drawablep->getVObj(); - if (!vobj || OUT_UNKNOWN == vobj->getLastUpdateType()) - { - return; - } - LLGLEnable blend(GL_BLEND); - switch (vobj->getLastUpdateType()) - { - case OUT_FULL: - gGL.diffuseColor4f(0,1,0,0.5f); - break; - case OUT_TERSE_IMPROVED: - gGL.diffuseColor4f(0,1,1,0.5f); - break; - case OUT_FULL_COMPRESSED: - if (vobj->getLastUpdateCached()) - { - gGL.diffuseColor4f(1,0,0,0.5f); - } - else - { - gGL.diffuseColor4f(1,1,0,0.5f); - } - break; - case OUT_FULL_CACHED: - gGL.diffuseColor4f(0,0,1,0.5f); - break; - default: - llwarns << "Unknown update_type " << vobj->getLastUpdateType() << llendl; - break; - }; - S32 num_faces = drawablep->getNumFaces(); - if (num_faces) - { - for (S32 i = 0; i < num_faces; ++i) - { - pushVerts(drawablep->getFace(i), LLVertexBuffer::MAP_VERTEX); - } - } -} - -void renderComplexityDisplay(LLDrawable* drawablep) -{ - LLViewerObject* vobj = drawablep->getVObj(); - if (!vobj) - { - return; - } - - LLVOVolume *voVol = dynamic_cast<LLVOVolume*>(vobj); - - if (!voVol) - { - return; - } - - if (!voVol->isRoot()) - { - return; - } - - LLVOVolume::texture_cost_t textures; - F32 cost = (F32) voVol->getRenderCost(textures); - - // add any child volumes - LLViewerObject::const_child_list_t children = voVol->getChildren(); - for (LLViewerObject::const_child_list_t::const_iterator iter = children.begin(); iter != children.end(); ++iter) - { - const LLViewerObject *child = *iter; - const LLVOVolume *child_volume = dynamic_cast<const LLVOVolume*>(child); - if (child_volume) - { - cost += child_volume->getRenderCost(textures); - } - } - - // add texture cost - for (LLVOVolume::texture_cost_t::iterator iter = textures.begin(); iter != textures.end(); ++iter) - { - // add the cost of each individual texture in the linkset - cost += iter->second; - } - - F32 cost_max = (F32) LLVOVolume::getRenderComplexityMax(); - - - - // allow user to set a static color scale - if (gSavedSettings.getS32("RenderComplexityStaticMax") > 0) - { - cost_max = gSavedSettings.getS32("RenderComplexityStaticMax"); - } - - F32 cost_ratio = cost / cost_max; - - // cap cost ratio at 1.0f in case cost_max is at a low threshold - cost_ratio = cost_ratio > 1.0f ? 1.0f : cost_ratio; - - LLGLEnable blend(GL_BLEND); - - LLColor4 color; - const LLColor4 color_min = gSavedSettings.getColor4("RenderComplexityColorMin"); - const LLColor4 color_mid = gSavedSettings.getColor4("RenderComplexityColorMid"); - const LLColor4 color_max = gSavedSettings.getColor4("RenderComplexityColorMax"); - - if (cost_ratio < 0.5f) - { - color = color_min * (1 - cost_ratio * 2) + color_mid * (cost_ratio * 2); - } - else - { - color = color_mid * (1 - (cost_ratio - 0.5) * 2) + color_max * ((cost_ratio - 0.5) * 2); - } - - LLSD color_val = color.getValue(); - - // don't highlight objects below the threshold - if (cost > gSavedSettings.getS32("RenderComplexityThreshold")) - { - glColor4f(color[0],color[1],color[2],0.5f); - - - S32 num_faces = drawablep->getNumFaces(); - if (num_faces) - { - for (S32 i = 0; i < num_faces; ++i) - { - pushVerts(drawablep->getFace(i), LLVertexBuffer::MAP_VERTEX); - } - } - LLViewerObject::const_child_list_t children = voVol->getChildren(); - for (LLViewerObject::const_child_list_t::const_iterator iter = children.begin(); iter != children.end(); ++iter) - { - const LLViewerObject *child = *iter; - if (child) - { - num_faces = child->getNumFaces(); - if (num_faces) - { - for (S32 i = 0; i < num_faces; ++i) - { - pushVerts(child->mDrawable->getFace(i), LLVertexBuffer::MAP_VERTEX); - } - } - } - } - } - - voVol->setDebugText(llformat("%4.0f", cost)); -} - -void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE) -{ - if (set_color) - { - if (drawable->isSpatialBridge()) - { - gGL.diffuseColor4f(1,0.5f,0,1); - } - else if (drawable->getVOVolume()) - { - if (drawable->isRoot()) - { - gGL.diffuseColor4f(1,1,0,1); - } - else - { - gGL.diffuseColor4f(0,1,0,1); - } - } - else if (drawable->getVObj()) - { - switch (drawable->getVObj()->getPCode()) - { - case LLViewerObject::LL_VO_SURFACE_PATCH: - gGL.diffuseColor4f(0,1,1,1); - break; - case LLViewerObject::LL_VO_CLOUDS: - // no longer used - break; - case LLViewerObject::LL_VO_PART_GROUP: - case LLViewerObject::LL_VO_HUD_PART_GROUP: - gGL.diffuseColor4f(0,0,1,1); - break; - case LLViewerObject::LL_VO_VOID_WATER: - case LLViewerObject::LL_VO_WATER: - gGL.diffuseColor4f(0,0.5f,1,1); - break; - case LL_PCODE_LEGACY_TREE: - gGL.diffuseColor4f(0,0.5f,0,1); - break; - default: - gGL.diffuseColor4f(1,0,1,1); - break; - } - } - else - { - gGL.diffuseColor4f(1,0,0,1); - } - } - - const LLVector4a* ext; - LLVector4a pos, size; - - //render face bounding boxes - for (S32 i = 0; i < drawable->getNumFaces(); i++) - { - LLFace* facep = drawable->getFace(i); - - ext = facep->mExtents; - - pos.setAdd(ext[0], ext[1]); - pos.mul(0.5f); - size.setSub(ext[1], ext[0]); - size.mul(0.5f); - - drawBoxOutline(pos,size); - } - - //render drawable bounding box - ext = drawable->getSpatialExtents(); - - pos.setAdd(ext[0], ext[1]); - pos.mul(0.5f); - size.setSub(ext[1], ext[0]); - size.mul(0.5f); - - LLViewerObject* vobj = drawable->getVObj(); - if (vobj && vobj->onActiveList()) - { - gGL.flush(); - glLineWidth(llmax(4.f*sinf(gFrameTimeSeconds*2.f)+1.f, 1.f)); - //glLineWidth(4.f*(sinf(gFrameTimeSeconds*2.f)*0.25f+0.75f)); - stop_glerror(); - drawBoxOutline(pos,size); - gGL.flush(); - glLineWidth(1.f); - } - else - { - drawBoxOutline(pos,size); - } -} - -void renderNormals(LLDrawable* drawablep) -{ - LLVertexBuffer::unbind(); - - LLVOVolume* vol = drawablep->getVOVolume(); - if (vol) - { - LLVolume* volume = vol->getVolume(); - gGL.pushMatrix(); - gGL.multMatrix((F32*) vol->getRelativeXform().mMatrix); - - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - - LLVector4a scale(gSavedSettings.getF32("RenderDebugNormalScale")); - - for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i) - { - const LLVolumeFace& face = volume->getVolumeFace(i); - - for (S32 j = 0; j < face.mNumVertices; ++j) - { - gGL.begin(LLRender::LINES); - LLVector4a n,p; - - n.setMul(face.mNormals[j], scale); - p.setAdd(face.mPositions[j], n); - - gGL.diffuseColor4f(1,1,1,1); - gGL.vertex3fv(face.mPositions[j].getF32ptr()); - gGL.vertex3fv(p.getF32ptr()); - - if (face.mBinormals) - { - n.setMul(face.mBinormals[j], scale); - p.setAdd(face.mPositions[j], n); - - gGL.diffuseColor4f(0,1,1,1); - gGL.vertex3fv(face.mPositions[j].getF32ptr()); - gGL.vertex3fv(p.getF32ptr()); - } - gGL.end(); - } - } - - gGL.popMatrix(); - } -} - -S32 get_physics_detail(const LLVolumeParams& volume_params, const LLVector3& scale) -{ - const S32 DEFAULT_DETAIL = 1; - const F32 LARGE_THRESHOLD = 5.f; - const F32 MEGA_THRESHOLD = 25.f; - - S32 detail = DEFAULT_DETAIL; - F32 avg_scale = (scale[0]+scale[1]+scale[2])/3.f; - - if (avg_scale > LARGE_THRESHOLD) - { - detail += 1; - if (avg_scale > MEGA_THRESHOLD) - { - detail += 1; - } - } - - return detail; -} - -void renderMeshBaseHull(LLVOVolume* volume, U32 data_mask, LLColor4& color, LLColor4& line_color) -{ - LLUUID mesh_id = volume->getVolume()->getParams().getSculptID(); - LLModel::Decomposition* decomp = gMeshRepo.getDecomposition(mesh_id); - - const LLVector3 center(0,0,0); - const LLVector3 size(0.25f,0.25f,0.25f); - - if (decomp) - { - if (!decomp->mBaseHullMesh.empty()) - { - gGL.diffuseColor4fv(color.mV); - LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mBaseHullMesh.mPositions, decomp->mBaseHullMesh.mNormals); - } - else - { - gMeshRepo.buildPhysicsMesh(*decomp); - gGL.diffuseColor4f(0,1,1,1); - drawBoxOutline(center, size); - } - - } - else - { - gGL.diffuseColor3f(1,0,1); - drawBoxOutline(center, size); - } -} - -void render_hull(LLModel::PhysicsMesh& mesh, const LLColor4& color, const LLColor4& line_color) -{ - gGL.diffuseColor4fv(color.mV); - LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions, mesh.mNormals); - LLGLEnable offset(GL_POLYGON_OFFSET_LINE); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - glPolygonOffset(3.f, 3.f); - glLineWidth(3.f); - gGL.diffuseColor4fv(line_color.mV); - LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions, mesh.mNormals); - glLineWidth(1.f); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); -} - -void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume) -{ - U8 physics_type = volume->getPhysicsShapeType(); - - if (physics_type == LLViewerObject::PHYSICS_SHAPE_NONE || volume->isFlexible()) - { - return; - } - - //not allowed to return at this point without rendering *something* - - F32 threshold = gSavedSettings.getF32("ObjectCostHighThreshold"); - F32 cost = volume->getObjectCost(); - - LLColor4 low = gSavedSettings.getColor4("ObjectCostLowColor"); - LLColor4 mid = gSavedSettings.getColor4("ObjectCostMidColor"); - LLColor4 high = gSavedSettings.getColor4("ObjectCostHighColor"); - - F32 normalizedCost = 1.f - exp( -(cost / threshold) ); - - LLColor4 color; - if ( normalizedCost <= 0.5f ) - { - color = lerp( low, mid, 2.f * normalizedCost ); - } - else - { - color = lerp( mid, high, 2.f * ( normalizedCost - 0.5f ) ); - } - - LLColor4 line_color = color*0.5f; - - U32 data_mask = LLVertexBuffer::MAP_VERTEX; - - LLVolumeParams volume_params = volume->getVolume()->getParams(); - - LLPhysicsVolumeParams physics_params(volume_params, - physics_type == LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL); - - LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification physics_spec; - LLPhysicsShapeBuilderUtil::determinePhysicsShape(physics_params, volume->getScale(), physics_spec); - - U32 type = physics_spec.getType(); - - LLVector3 center(0,0,0); - LLVector3 size(0.25f,0.25f,0.25f); - - gGL.pushMatrix(); - gGL.multMatrix((F32*) volume->getRelativeXform().mMatrix); - - if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::USER_MESH) - { - LLUUID mesh_id = volume->getVolume()->getParams().getSculptID(); - LLModel::Decomposition* decomp = gMeshRepo.getDecomposition(mesh_id); - - if (decomp) - { //render a physics based mesh - - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - - if (!decomp->mHull.empty()) - { //decomposition exists, use that - - if (decomp->mMesh.empty()) - { - gMeshRepo.buildPhysicsMesh(*decomp); - } - - for (U32 i = 0; i < decomp->mMesh.size(); ++i) - { - render_hull(decomp->mMesh[i], color, line_color); - } - } - else if (!decomp->mPhysicsShapeMesh.empty()) - { - //decomp has physics mesh, render that mesh - gGL.diffuseColor4fv(color.mV); - LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions, decomp->mPhysicsShapeMesh.mNormals); - - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - gGL.diffuseColor4fv(line_color.mV); - LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions, decomp->mPhysicsShapeMesh.mNormals); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - } - else - { //no mesh or decomposition, render base hull - renderMeshBaseHull(volume, data_mask, color, line_color); - - if (decomp->mPhysicsShapeMesh.empty()) - { - //attempt to fetch physics shape mesh if available - gMeshRepo.fetchPhysicsShape(mesh_id); - } - } - } - else - { - gGL.diffuseColor3f(1,1,0); - drawBoxOutline(center, size); - } - } - else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::USER_CONVEX || - type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::PRIM_CONVEX) - { - if (volume->isMesh()) - { - renderMeshBaseHull(volume, data_mask, color, line_color); - } - else - { - LLVolumeParams volume_params = volume->getVolume()->getParams(); - S32 detail = get_physics_detail(volume_params, volume->getScale()); - LLVolume* phys_volume = LLPrimitive::sVolumeManager->refVolume(volume_params, detail); - - if (!phys_volume->mHullPoints) - { //build convex hull - std::vector<LLVector3> pos; - std::vector<U16> index; - - S32 index_offset = 0; - - for (S32 i = 0; i < phys_volume->getNumVolumeFaces(); ++i) - { - const LLVolumeFace& face = phys_volume->getVolumeFace(i); - if (index_offset + face.mNumVertices > 65535) - { - continue; - } - - for (S32 j = 0; j < face.mNumVertices; ++j) - { - pos.push_back(LLVector3(face.mPositions[j].getF32ptr())); - } - - for (S32 j = 0; j < face.mNumIndices; ++j) - { - index.push_back(face.mIndices[j]+index_offset); - } - - index_offset += face.mNumVertices; - } - - if (!pos.empty() && !index.empty()) - { - LLCDMeshData mesh; - mesh.mIndexBase = &index[0]; - mesh.mVertexBase = pos[0].mV; - mesh.mNumVertices = pos.size(); - mesh.mVertexStrideBytes = 12; - mesh.mIndexStrideBytes = 6; - mesh.mIndexType = LLCDMeshData::INT_16; - - mesh.mNumTriangles = index.size()/3; - - LLCDMeshData res; - - LLConvexDecomposition::getInstance()->generateSingleHullMeshFromMesh( &mesh, &res ); - - //copy res into phys_volume - phys_volume->mHullPoints = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*res.mNumVertices); - phys_volume->mNumHullPoints = res.mNumVertices; - - S32 idx_size = (res.mNumTriangles*3*2+0xF) & ~0xF; - phys_volume->mHullIndices = (U16*) ll_aligned_malloc_16(idx_size); - phys_volume->mNumHullIndices = res.mNumTriangles*3; - - const F32* v = res.mVertexBase; - - for (S32 i = 0; i < res.mNumVertices; ++i) - { - F32* p = (F32*) ((U8*)v+i*res.mVertexStrideBytes); - phys_volume->mHullPoints[i].load3(p); - } - - if (res.mIndexType == LLCDMeshData::INT_16) - { - for (S32 i = 0; i < res.mNumTriangles; ++i) - { - U16* idx = (U16*) (((U8*)res.mIndexBase)+i*res.mIndexStrideBytes); - - phys_volume->mHullIndices[i*3+0] = idx[0]; - phys_volume->mHullIndices[i*3+1] = idx[1]; - phys_volume->mHullIndices[i*3+2] = idx[2]; - } - } - else - { - for (S32 i = 0; i < res.mNumTriangles; ++i) - { - U32* idx = (U32*) (((U8*)res.mIndexBase)+i*res.mIndexStrideBytes); - - phys_volume->mHullIndices[i*3+0] = (U16) idx[0]; - phys_volume->mHullIndices[i*3+1] = (U16) idx[1]; - phys_volume->mHullIndices[i*3+2] = (U16) idx[2]; - } - } - } - } - - if (phys_volume->mHullPoints) - { - //render hull - - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - - gGL.diffuseColor4fv(line_color.mV); - LLVertexBuffer::unbind(); - - llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShader != 0); - - LLVertexBuffer::drawElements(LLRender::TRIANGLES, phys_volume->mHullPoints, NULL, phys_volume->mNumHullIndices, phys_volume->mHullIndices); - - gGL.diffuseColor4fv(color.mV); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - LLVertexBuffer::drawElements(LLRender::TRIANGLES, phys_volume->mHullPoints, NULL, phys_volume->mNumHullIndices, phys_volume->mHullIndices); - - } - else - { - gGL.diffuseColor4f(1,0,1,1); - drawBoxOutline(center, size); - } - - LLPrimitive::sVolumeManager->unrefVolume(phys_volume); - } - } - else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::BOX) - { - LLVector3 center = physics_spec.getCenter(); - LLVector3 scale = physics_spec.getScale(); - LLVector3 vscale = volume->getScale()*2.f; - scale.set(scale[0]/vscale[0], scale[1]/vscale[1], scale[2]/vscale[2]); - - gGL.diffuseColor4fv(color.mV); - drawBox(center, scale); - } - else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::SPHERE) - { - /*LLVolumeParams volume_params; - volume_params.setType( LL_PCODE_PROFILE_CIRCLE_HALF, LL_PCODE_PATH_CIRCLE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 1, 1 ); - volume_params.setShear ( 0, 0 ); - LLVolume* sphere = LLPrimitive::sVolumeManager->refVolume(volume_params, 3); - - gGL.diffuseColor4fv(color.mV); - pushVerts(sphere); - LLPrimitive::sVolumeManager->unrefVolume(sphere);*/ - } - else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::CYLINDER) - { - LLVolumeParams volume_params; - volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE ); - volume_params.setBeginAndEndS( 0.f, 1.f ); - volume_params.setBeginAndEndT( 0.f, 1.f ); - volume_params.setRatio ( 1, 1 ); - volume_params.setShear ( 0, 0 ); - LLVolume* cylinder = LLPrimitive::sVolumeManager->refVolume(volume_params, 3); - - gGL.diffuseColor4fv(color.mV); - pushVerts(cylinder); - LLPrimitive::sVolumeManager->unrefVolume(cylinder); - } - else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::PRIM_MESH) - { - LLVolumeParams volume_params = volume->getVolume()->getParams(); - S32 detail = get_physics_detail(volume_params, volume->getScale()); - - LLVolume* phys_volume = LLPrimitive::sVolumeManager->refVolume(volume_params, detail); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - - gGL.diffuseColor4fv(line_color.mV); - pushVerts(phys_volume); - - gGL.diffuseColor4fv(color.mV); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - pushVerts(phys_volume); - LLPrimitive::sVolumeManager->unrefVolume(phys_volume); - } - else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::PRIM_CONVEX) - { - LLVolumeParams volume_params = volume->getVolume()->getParams(); - S32 detail = get_physics_detail(volume_params, volume->getScale()); - - LLVolume* phys_volume = LLPrimitive::sVolumeManager->refVolume(volume_params, detail); - - if (phys_volume->mHullPoints && phys_volume->mHullIndices) - { - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShader != 0); - LLVertexBuffer::unbind(); - glVertexPointer(3, GL_FLOAT, 16, phys_volume->mHullPoints); - gGL.diffuseColor4fv(line_color.mV); - gGL.syncMatrices(); - glDrawElements(GL_TRIANGLES, phys_volume->mNumHullIndices, GL_UNSIGNED_SHORT, phys_volume->mHullIndices); - - gGL.diffuseColor4fv(color.mV); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glDrawElements(GL_TRIANGLES, phys_volume->mNumHullIndices, GL_UNSIGNED_SHORT, phys_volume->mHullIndices); - } - else - { - gGL.diffuseColor3f(1,0,1); - drawBoxOutline(center, size); - gMeshRepo.buildHull(volume_params, detail); - } - LLPrimitive::sVolumeManager->unrefVolume(phys_volume); - } - else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::SCULPT) - { - //TODO: implement sculpted prim physics display - } - else - { - llerrs << "Unhandled type" << llendl; - } - - gGL.popMatrix(); -} - -void renderPhysicsShapes(LLSpatialGroup* group) -{ - for (LLSpatialGroup::OctreeNode::const_element_iter i = group->getData().begin(); i != group->getData().end(); ++i) - { - LLDrawable* drawable = *i; - LLVOVolume* volume = drawable->getVOVolume(); - if (volume && !volume->isAttachment() && volume->getPhysicsShapeType() != LLViewerObject::PHYSICS_SHAPE_NONE ) - { - if (!group->mSpatialPartition->isBridge()) - { - gGL.pushMatrix(); - LLVector3 trans = drawable->getRegion()->getOriginAgent(); - gGL.translatef(trans.mV[0], trans.mV[1], trans.mV[2]); - renderPhysicsShape(drawable, volume); - gGL.popMatrix(); - } - else - { - renderPhysicsShape(drawable, volume); - } - } - else - { - LLViewerObject* object = drawable->getVObj(); - if (object && object->getPCode() == LLViewerObject::LL_VO_SURFACE_PATCH) - { - //push face vertices for terrain - for (S32 i = 0; i < drawable->getNumFaces(); ++i) - { - LLFace* face = drawable->getFace(i); - 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); - - gGL.diffuseColor3f(0.2f, 1.f, 0.3f); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - buff->draw(LLRender::TRIANGLES, buff->getNumIndices(), 0); - } - } - } - } - } -} - -void renderTexturePriority(LLDrawable* drawable) -{ - for (int face=0; face<drawable->getNumFaces(); ++face) - { - LLFace *facep = drawable->getFace(face); - - LLVector4 cold(0,0,0.25f); - LLVector4 hot(1,0.25f,0.25f); - - LLVector4 boost_cold(0,0,0,0); - LLVector4 boost_hot(0,1,0,1); - - LLGLDisable blend(GL_BLEND); - - //LLViewerTexture* imagep = facep->getTexture(); - //if (imagep) - { - - //F32 vsize = imagep->mMaxVirtualSize; - F32 vsize = facep->getPixelArea(); - - if (vsize > sCurMaxTexPriority) - { - sCurMaxTexPriority = vsize; - } - - F32 t = vsize/sLastMaxTexPriority; - - LLVector4 col = lerp(cold, hot, t); - gGL.diffuseColor4fv(col.mV); - } - //else - //{ - // gGL.diffuseColor4f(1,0,1,1); - //} - - LLVector4a center; - center.setAdd(facep->mExtents[1],facep->mExtents[0]); - center.mul(0.5f); - LLVector4a size; - size.setSub(facep->mExtents[1],facep->mExtents[0]); - size.mul(0.5f); - size.add(LLVector4a(0.01f)); - drawBox(center, size); - - /*S32 boost = imagep->getBoostLevel(); - if (boost>LLViewerTexture::BOOST_NONE) - { - F32 t = (F32) boost / (F32) (LLViewerTexture::BOOST_MAX_LEVEL-1); - LLVector4 col = lerp(boost_cold, boost_hot, t); - LLGLEnable blend_on(GL_BLEND); - gGL.blendFunc(GL_SRC_ALPHA, GL_ONE); - gGL.diffuseColor4fv(col.mV); - drawBox(center, size); - gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - }*/ - } -} - -void renderPoints(LLDrawable* drawablep) -{ - LLGLDepthTest depth(GL_FALSE, GL_FALSE); - if (drawablep->getNumFaces()) - { - gGL.begin(LLRender::POINTS); - gGL.diffuseColor3f(1,1,1); - for (S32 i = 0; i < drawablep->getNumFaces(); i++) - { - gGL.vertex3fv(drawablep->getFace(i)->mCenterLocal.mV); - } - gGL.end(); - } -} - -void renderTextureAnim(LLDrawInfo* params) -{ - if (!params->mTextureMatrix) - { - return; - } - - LLGLEnable blend(GL_BLEND); - gGL.diffuseColor4f(1,1,0,0.5f); - pushVerts(params, LLVertexBuffer::MAP_VERTEX); -} - -void renderBatchSize(LLDrawInfo* params) -{ - LLGLEnable offset(GL_POLYGON_OFFSET_FILL); - glPolygonOffset(-1.f, 1.f); - gGL.diffuseColor4ubv((GLubyte*) &(params->mDebugColor)); - pushVerts(params, LLVertexBuffer::MAP_VERTEX); -} - -void renderShadowFrusta(LLDrawInfo* params) -{ - LLGLEnable blend(GL_BLEND); - gGL.setSceneBlendType(LLRender::BT_ADD); - - LLVector4a center; - center.setAdd(params->mExtents[1], params->mExtents[0]); - center.mul(0.5f); - LLVector4a size; - size.setSub(params->mExtents[1],params->mExtents[0]); - size.mul(0.5f); - - if (gPipeline.mShadowCamera[4].AABBInFrustum(center, size)) - { - gGL.diffuseColor3f(1,0,0); - pushVerts(params, LLVertexBuffer::MAP_VERTEX); - } - if (gPipeline.mShadowCamera[5].AABBInFrustum(center, size)) - { - gGL.diffuseColor3f(0,1,0); - pushVerts(params, LLVertexBuffer::MAP_VERTEX); - } - if (gPipeline.mShadowCamera[6].AABBInFrustum(center, size)) - { - gGL.diffuseColor3f(0,0,1); - pushVerts(params, LLVertexBuffer::MAP_VERTEX); - } - if (gPipeline.mShadowCamera[7].AABBInFrustum(center, size)) - { - gGL.diffuseColor3f(1,0,1); - pushVerts(params, LLVertexBuffer::MAP_VERTEX); - } - - gGL.setSceneBlendType(LLRender::BT_ALPHA); -} - - -void renderLights(LLDrawable* drawablep) -{ - if (!drawablep->isLight()) - { - return; - } - - if (drawablep->getNumFaces()) - { - LLGLEnable blend(GL_BLEND); - gGL.diffuseColor4f(0,1,1,0.5f); - - for (S32 i = 0; i < drawablep->getNumFaces(); i++) - { - pushVerts(drawablep->getFace(i), LLVertexBuffer::MAP_VERTEX); - } - - const LLVector4a* ext = drawablep->getSpatialExtents(); - - LLVector4a pos; - pos.setAdd(ext[0], ext[1]); - pos.mul(0.5f); - LLVector4a size; - size.setSub(ext[1], ext[0]); - size.mul(0.5f); - - { - LLGLDepthTest depth(GL_FALSE, GL_TRUE); - gGL.diffuseColor4f(1,1,1,1); - drawBoxOutline(pos, size); - } - - gGL.diffuseColor4f(1,1,0,1); - F32 rad = drawablep->getVOVolume()->getLightRadius(); - drawBoxOutline(pos, LLVector4a(rad)); - } -} - -class LLRenderOctreeRaycast : public LLOctreeTriangleRayIntersect -{ -public: - - - LLRenderOctreeRaycast(const LLVector4a& start, const LLVector4a& dir, F32* closest_t) - : LLOctreeTriangleRayIntersect(start, dir, NULL, closest_t, NULL, NULL, NULL, NULL) - { - - } - - void visit(const LLOctreeNode<LLVolumeTriangle>* branch) - { - LLVolumeOctreeListener* vl = (LLVolumeOctreeListener*) branch->getListener(0); - - LLVector3 center, size; - - if (branch->getData().empty()) - { - gGL.diffuseColor3f(1.f,0.2f,0.f); - center.set(branch->getCenter().getF32ptr()); - size.set(branch->getSize().getF32ptr()); - } - else - { - gGL.diffuseColor3f(0.75f, 1.f, 0.f); - center.set(vl->mBounds[0].getF32ptr()); - size.set(vl->mBounds[1].getF32ptr()); - } - - drawBoxOutline(center, size); - - for (U32 i = 0; i < 2; i++) - { - LLGLDepthTest depth(GL_TRUE, GL_FALSE, i == 1 ? GL_LEQUAL : GL_GREATER); - - if (i == 1) - { - gGL.diffuseColor4f(0,1,1,0.5f); - } - else - { - gGL.diffuseColor4f(0,0.5f,0.5f, 0.25f); - drawBoxOutline(center, size); - } - - if (i == 1) - { - gGL.flush(); - glLineWidth(3.f); - } - - gGL.begin(LLRender::TRIANGLES); - for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter = branch->getData().begin(); - iter != branch->getData().end(); - ++iter) - { - const LLVolumeTriangle* tri = *iter; - - gGL.vertex3fv(tri->mV[0]->getF32ptr()); - gGL.vertex3fv(tri->mV[1]->getF32ptr()); - gGL.vertex3fv(tri->mV[2]->getF32ptr()); - } - gGL.end(); - - if (i == 1) - { - gGL.flush(); - glLineWidth(1.f); - } - } - } -}; - -void renderRaycast(LLDrawable* drawablep) -{ - if (drawablep->getNumFaces()) - { - LLGLEnable blend(GL_BLEND); - gGL.diffuseColor4f(0,1,1,0.5f); - - if (drawablep->getVOVolume()) - { - //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - //pushVerts(drawablep->getFace(gDebugRaycastFaceHit), LLVertexBuffer::MAP_VERTEX); - //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - - LLVOVolume* vobj = drawablep->getVOVolume(); - LLVolume* volume = vobj->getVolume(); - - bool transform = true; - if (drawablep->isState(LLDrawable::RIGGED)) - { - volume = vobj->getRiggedVolume(); - transform = false; - } - - if (volume) - { - LLVector3 trans = drawablep->getRegion()->getOriginAgent(); - - for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i) - { - const LLVolumeFace& face = volume->getVolumeFace(i); - - gGL.pushMatrix(); - gGL.translatef(trans.mV[0], trans.mV[1], trans.mV[2]); - gGL.multMatrix((F32*) vobj->getRelativeXform().mMatrix); - - LLVector3 start, end; - if (transform) - { - start = vobj->agentPositionToVolume(gDebugRaycastStart); - end = vobj->agentPositionToVolume(gDebugRaycastEnd); - } - else - { - start = gDebugRaycastStart; - end = gDebugRaycastEnd; - } - - LLVector4a starta, enda; - starta.load3(start.mV); - enda.load3(end.mV); - LLVector4a dir; - dir.setSub(enda, starta); - - gGL.flush(); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - - { - //render face positions - LLVertexBuffer::unbind(); - gGL.diffuseColor4f(0,1,1,0.5f); - glVertexPointer(3, GL_FLOAT, sizeof(LLVector4a), face.mPositions); - gGL.syncMatrices(); - glDrawElements(GL_TRIANGLES, face.mNumIndices, GL_UNSIGNED_SHORT, face.mIndices); - } - - if (!volume->isUnique()) - { - F32 t = 1.f; - - if (!face.mOctree) - { - ((LLVolumeFace*) &face)->createOctree(); - } - - LLRenderOctreeRaycast render(starta, dir, &t); - - render.traverse(face.mOctree); - } - - gGL.popMatrix(); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - } - } - } - else if (drawablep->isAvatar()) - { - if (drawablep->getVObj() == gDebugRaycastObject) - { - LLGLDepthTest depth(GL_FALSE); - LLVOAvatar* av = (LLVOAvatar*) drawablep->getVObj().get(); - av->renderCollisionVolumes(); - } - } - - if (drawablep->getVObj() == gDebugRaycastObject) - { - // draw intersection point - gGL.pushMatrix(); - gGL.loadMatrix(gGLModelView); - LLVector3 translate = gDebugRaycastIntersection; - gGL.translatef(translate.mV[0], translate.mV[1], translate.mV[2]); - LLCoordFrame orient; - orient.lookDir(gDebugRaycastNormal, gDebugRaycastBinormal); - LLMatrix4 rotation; - orient.getRotMatrixToParent(rotation); - gGL.multMatrix((float*)rotation.mMatrix); - - gGL.diffuseColor4f(1,0,0,0.5f); - drawBox(LLVector3(0, 0, 0), LLVector3(0.1f, 0.022f, 0.022f)); - gGL.diffuseColor4f(0,1,0,0.5f); - drawBox(LLVector3(0, 0, 0), LLVector3(0.021f, 0.1f, 0.021f)); - gGL.diffuseColor4f(0,0,1,0.5f); - drawBox(LLVector3(0, 0, 0), LLVector3(0.02f, 0.02f, 0.1f)); - gGL.popMatrix(); - - // draw bounding box of prim - const LLVector4a* ext = drawablep->getSpatialExtents(); - - LLVector4a pos; - pos.setAdd(ext[0], ext[1]); - pos.mul(0.5f); - LLVector4a size; - size.setSub(ext[1], ext[0]); - size.mul(0.5f); - - LLGLDepthTest depth(GL_FALSE, GL_TRUE); - gGL.diffuseColor4f(0,0.5f,0.5f,1); - drawBoxOutline(pos, size); - } - } -} - - -void renderAvatarCollisionVolumes(LLVOAvatar* avatar) -{ - avatar->renderCollisionVolumes(); -} - -void renderAgentTarget(LLVOAvatar* avatar) -{ - // render these for self only (why, i don't know) - if (avatar->isSelf()) - { - renderCrossHairs(avatar->getPositionAgent(), 0.2f, LLColor4(1, 0, 0, 0.8f)); - renderCrossHairs(avatar->mDrawable->getPositionAgent(), 0.2f, LLColor4(1, 0, 0, 0.8f)); - renderCrossHairs(avatar->mRoot.getWorldPosition(), 0.2f, LLColor4(1, 1, 1, 0.8f)); - renderCrossHairs(avatar->mPelvisp->getWorldPosition(), 0.2f, LLColor4(0, 0, 1, 0.8f)); - } -} - -class LLOctreeRenderNonOccluded : public LLOctreeTraveler<LLDrawable> -{ -public: - LLCamera* mCamera; - LLOctreeRenderNonOccluded(LLCamera* camera): mCamera(camera) {} - - virtual void traverse(const LLSpatialGroup::OctreeNode* node) - { - LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0); - - if (!mCamera || mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1])) - { - node->accept(this); - stop_glerror(); - - for (U32 i = 0; i < node->getChildCount(); i++) - { - traverse(node->getChild(i)); - stop_glerror(); - } - - //draw tight fit bounding boxes for spatial group - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCTREE)) - { - group->rebuildGeom(); - group->rebuildMesh(); - - renderOctree(group); - stop_glerror(); - } - - //render visibility wireframe - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION)) - { - group->rebuildGeom(); - group->rebuildMesh(); - - gGL.flush(); - gGL.pushMatrix(); - gGLLastMatrix = NULL; - gGL.loadMatrix(gGLModelView); - renderVisibility(group, mCamera); - stop_glerror(); - gGLLastMatrix = NULL; - gGL.popMatrix(); - gGL.diffuseColor4f(1,1,1,1); - } - } - } - - virtual void visit(const LLSpatialGroup::OctreeNode* branch) - { - LLSpatialGroup* group = (LLSpatialGroup*) branch->getListener(0); - - if (group->isState(LLSpatialGroup::GEOM_DIRTY) || (mCamera && !mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]))) - { - return; - } - - LLVector4a nodeCenter = group->mBounds[0]; - LLVector4a octCenter = group->mOctreeNode->getCenter(); - - group->rebuildGeom(); - group->rebuildMesh(); - - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BBOXES)) - { - if (!group->getData().empty()) - { - gGL.diffuseColor3f(0,0,1); - drawBoxOutline(group->mObjectBounds[0], - group->mObjectBounds[1]); - } - } - - for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i) - { - LLDrawable* drawable = *i; - - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BBOXES)) - { - renderBoundingBox(drawable); - } - - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_NORMALS)) - { - renderNormals(drawable); - } - - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BUILD_QUEUE)) - { - if (drawable->isState(LLDrawable::IN_REBUILD_Q2)) - { - gGL.diffuseColor4f(0.6f, 0.6f, 0.1f, 1.f); - const LLVector4a* ext = drawable->getSpatialExtents(); - LLVector4a center; - center.setAdd(ext[0], ext[1]); - center.mul(0.5f); - LLVector4a size; - size.setSub(ext[1], ext[0]); - size.mul(0.5f); - drawBoxOutline(center, size); - } - } - - if (drawable->getVOVolume() && gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY)) - { - renderTexturePriority(drawable); - } - - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_POINTS)) - { - renderPoints(drawable); - } - - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_LIGHTS)) - { - renderLights(drawable); - } - - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST)) - { - renderRaycast(drawable); - } - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_UPDATE_TYPE)) - { - renderUpdateType(drawable); - } - if(gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RENDER_COMPLEXITY)) - { - renderComplexityDisplay(drawable); - } - - LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(drawable->getVObj().get()); - - if (avatar && gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_AVATAR_VOLUME)) - { - renderAvatarCollisionVolumes(avatar); - } - - if (avatar && gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_AGENT_TARGET)) - { - renderAgentTarget(avatar); - } - - if (gDebugGL) - { - for (U32 i = 0; i < drawable->getNumFaces(); ++i) - { - LLFace* facep = drawable->getFace(i); - U8 index = facep->getTextureIndex(); - if (facep->mDrawInfo) - { - if (index < 255) - { - 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; - } - } - } - } - } - } - - for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i) - { - LLSpatialGroup::drawmap_elem_t& draw_vec = i->second; - for (LLSpatialGroup::drawmap_elem_t::iterator j = draw_vec.begin(); j != draw_vec.end(); ++j) - { - LLDrawInfo* draw_info = *j; - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_ANIM)) - { - renderTextureAnim(draw_info); - } - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BATCH_SIZE)) - { - renderBatchSize(draw_info); - } - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) - { - renderShadowFrusta(draw_info); - } - } - } - } -}; - - -class LLOctreeRenderPhysicsShapes : public LLOctreeTraveler<LLDrawable> -{ -public: - LLCamera* mCamera; - LLOctreeRenderPhysicsShapes(LLCamera* camera): mCamera(camera) {} - - virtual void traverse(const LLSpatialGroup::OctreeNode* node) - { - LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0); - - if (!mCamera || mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1])) - { - node->accept(this); - stop_glerror(); - - for (U32 i = 0; i < node->getChildCount(); i++) - { - traverse(node->getChild(i)); - stop_glerror(); - } - - group->rebuildGeom(); - group->rebuildMesh(); - - renderPhysicsShapes(group); - } - } - - virtual void visit(const LLSpatialGroup::OctreeNode* branch) - { - - } -}; - -class LLOctreePushBBoxVerts : public LLOctreeTraveler<LLDrawable> -{ -public: - LLCamera* mCamera; - LLOctreePushBBoxVerts(LLCamera* camera): mCamera(camera) {} - - virtual void traverse(const LLSpatialGroup::OctreeNode* node) - { - LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0); - - if (!mCamera || mCamera->AABBInFrustum(group->mBounds[0], group->mBounds[1])) - { - node->accept(this); - - for (U32 i = 0; i < node->getChildCount(); i++) - { - traverse(node->getChild(i)); - } - } - } - - virtual void visit(const LLSpatialGroup::OctreeNode* branch) - { - LLSpatialGroup* group = (LLSpatialGroup*) branch->getListener(0); - - if (group->isState(LLSpatialGroup::GEOM_DIRTY) || (mCamera && !mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]))) - { - return; - } - - for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i) - { - LLDrawable* drawable = *i; - - renderBoundingBox(drawable, FALSE); - } - } -}; - -void LLSpatialPartition::renderIntersectingBBoxes(LLCamera* camera) -{ - LLOctreePushBBoxVerts pusher(camera); - pusher.traverse(mOctree); -} - -class LLOctreeStateCheck : public LLOctreeTraveler<LLDrawable> -{ -public: - U32 mInheritedMask[LLViewerCamera::NUM_CAMERAS]; - - LLOctreeStateCheck() - { - for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) - { - mInheritedMask[i] = 0; - } - } - - virtual void traverse(const LLSpatialGroup::OctreeNode* node) - { - LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0); - - node->accept(this); - - - U32 temp[LLViewerCamera::NUM_CAMERAS]; - - for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) - { - temp[i] = mInheritedMask[i]; - mInheritedMask[i] |= group->mOcclusionState[i] & LLSpatialGroup::OCCLUDED; - } - - for (U32 i = 0; i < node->getChildCount(); i++) - { - traverse(node->getChild(i)); - } - - for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) - { - mInheritedMask[i] = temp[i]; - } - } - - - virtual void visit(const LLOctreeNode<LLDrawable>* state) - { - LLSpatialGroup* group = (LLSpatialGroup*) state->getListener(0); - - for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) - { - if (mInheritedMask[i] && !(group->mOcclusionState[i] & mInheritedMask[i])) - { - llerrs << "Spatial group failed inherited mask test." << llendl; - } - } - - if (group->isState(LLSpatialGroup::DIRTY)) - { - assert_parent_state(group, LLSpatialGroup::DIRTY); - } - } - - void assert_parent_state(LLSpatialGroup* group, U32 state) - { - LLSpatialGroup* parent = group->getParent(); - while (parent) - { - if (!parent->isState(state)) - { - llerrs << "Spatial group failed parent state check." << llendl; - } - parent = parent->getParent(); - } - } -}; - - -void LLSpatialPartition::renderPhysicsShapes() -{ - LLSpatialBridge* bridge = asBridge(); - LLCamera* camera = LLViewerCamera::getInstance(); - - if (bridge) - { - camera = NULL; - } - - gGL.flush(); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - glLineWidth(3.f); - LLOctreeRenderPhysicsShapes render_physics(camera); - render_physics.traverse(mOctree); - gGL.flush(); - glLineWidth(1.f); -} - -void LLSpatialPartition::renderDebug() -{ - if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCTREE | - LLPipeline::RENDER_DEBUG_OCCLUSION | - LLPipeline::RENDER_DEBUG_LIGHTS | - LLPipeline::RENDER_DEBUG_BATCH_SIZE | - LLPipeline::RENDER_DEBUG_UPDATE_TYPE | - LLPipeline::RENDER_DEBUG_BBOXES | - LLPipeline::RENDER_DEBUG_NORMALS | - LLPipeline::RENDER_DEBUG_POINTS | - LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY | - LLPipeline::RENDER_DEBUG_TEXTURE_ANIM | - LLPipeline::RENDER_DEBUG_RAYCAST | - LLPipeline::RENDER_DEBUG_AVATAR_VOLUME | - LLPipeline::RENDER_DEBUG_AGENT_TARGET | - //LLPipeline::RENDER_DEBUG_BUILD_QUEUE | - LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA | - LLPipeline::RENDER_DEBUG_RENDER_COMPLEXITY)) - { - return; - } - - if (LLGLSLShader::sNoFixedFunction) - { - gDebugProgram.bind(); - } - - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY)) - { - //sLastMaxTexPriority = lerp(sLastMaxTexPriority, sCurMaxTexPriority, gFrameIntervalSeconds); - sLastMaxTexPriority = (F32) LLViewerCamera::getInstance()->getScreenPixelArea(); - sCurMaxTexPriority = 0.f; - } - - LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - - LLGLDisable cullface(GL_CULL_FACE); - LLGLEnable blend(GL_BLEND); - gGL.setSceneBlendType(LLRender::BT_ALPHA); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gPipeline.disableLights(); - - LLSpatialBridge* bridge = asBridge(); - LLCamera* camera = LLViewerCamera::getInstance(); - - if (bridge) - { - camera = NULL; - } - - LLOctreeStateCheck checker; - checker.traverse(mOctree); - - LLOctreeRenderNonOccluded render_debug(camera); - render_debug.traverse(mOctree); - - if (LLGLSLShader::sNoFixedFunction) - { - gDebugProgram.unbind(); - } -} - -void LLSpatialGroup::drawObjectBox(LLColor4 col) -{ - gGL.diffuseColor4fv(col.mV); - LLVector4a size; - size = mObjectBounds[1]; - size.mul(1.01f); - size.add(LLVector4a(0.001f)); - drawBox(mObjectBounds[0], size); -} - -bool LLSpatialPartition::isHUDPartition() -{ - return mPartitionType == LLViewerRegion::PARTITION_HUD ; -} - -BOOL LLSpatialPartition::isVisible(const LLVector3& v) -{ - if (!LLViewerCamera::getInstance()->sphereInFrustum(v, 4.0f)) - { - return FALSE; - } - - return TRUE; -} - -class LLOctreeIntersect : public LLSpatialGroup::OctreeTraveler -{ -public: - LLVector3 mStart; - LLVector3 mEnd; - S32 *mFaceHit; - LLVector3 *mIntersection; - LLVector2 *mTexCoord; - LLVector3 *mNormal; - LLVector3 *mBinormal; - LLDrawable* mHit; - BOOL mPickTransparent; - - LLOctreeIntersect(LLVector3 start, LLVector3 end, BOOL pick_transparent, - S32* face_hit, LLVector3* intersection, LLVector2* tex_coord, LLVector3* normal, LLVector3* binormal) - : mStart(start), - mEnd(end), - mFaceHit(face_hit), - mIntersection(intersection), - mTexCoord(tex_coord), - mNormal(normal), - mBinormal(binormal), - mHit(NULL), - mPickTransparent(pick_transparent) - { - } - - virtual void visit(const LLSpatialGroup::OctreeNode* branch) - { - for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i) - { - check(*i); - } - } - - virtual LLDrawable* check(const LLSpatialGroup::OctreeNode* node) - { - node->accept(this); - - for (U32 i = 0; i < node->getChildCount(); i++) - { - const LLSpatialGroup::OctreeNode* child = node->getChild(i); - LLVector3 res; - - LLSpatialGroup* group = (LLSpatialGroup*) child->getListener(0); - - LLVector4a size; - LLVector4a center; - - size = group->mBounds[1]; - center = group->mBounds[0]; - - LLVector3 local_start = mStart; - LLVector3 local_end = mEnd; - - if (group->mSpatialPartition->isBridge()) - { - LLMatrix4 local_matrix = group->mSpatialPartition->asBridge()->mDrawable->getRenderMatrix(); - local_matrix.invert(); - - local_start = mStart * local_matrix; - local_end = mEnd * local_matrix; - } - - LLVector4a start, end; - start.load3(local_start.mV); - end.load3(local_end.mV); - - if (LLLineSegmentBoxIntersect(start, end, center, size)) - { - check(child); - } - } - - return mHit; - } - - virtual bool check(LLDrawable* drawable) - { - LLVector3 local_start = mStart; - LLVector3 local_end = mEnd; - - if (!drawable || !gPipeline.hasRenderType(drawable->getRenderType()) || !drawable->isVisible()) - { - return false; - } - - if (drawable->isSpatialBridge()) - { - LLSpatialPartition *part = drawable->asPartition(); - LLSpatialBridge* bridge = part->asBridge(); - if (bridge && gPipeline.hasRenderType(bridge->mDrawableType)) - { - check(part->mOctree); - } - } - else - { - LLViewerObject* vobj = drawable->getVObj(); - - if (vobj) - { - LLVector3 intersection; - bool skip_check = false; - if (vobj->isAvatar()) - { - LLVOAvatar* avatar = (LLVOAvatar*) vobj; - if (avatar->isSelf() && LLFloater::isVisible(gFloaterTools)) - { - LLViewerObject* hit = avatar->lineSegmentIntersectRiggedAttachments(mStart, mEnd, -1, mPickTransparent, mFaceHit, &intersection, mTexCoord, mNormal, mBinormal); - if (hit) - { - mEnd = intersection; - if (mIntersection) - { - *mIntersection = intersection; - } - - mHit = hit->mDrawable; - skip_check = true; - } - - } - } - - if (!skip_check && vobj->lineSegmentIntersect(mStart, mEnd, -1, mPickTransparent, mFaceHit, &intersection, mTexCoord, mNormal, mBinormal)) - { - mEnd = intersection; // shorten ray so we only find CLOSER hits - if (mIntersection) - { - *mIntersection = intersection; - } - - mHit = vobj->mDrawable; - } - } - } - - return false; - } -}; - -LLDrawable* LLSpatialPartition::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, - BOOL pick_transparent, - S32* face_hit, // return the face hit - LLVector3* intersection, // return the intersection point - LLVector2* tex_coord, // return the texture coordinates of the intersection point - LLVector3* normal, // return the surface normal at the intersection point - LLVector3* bi_normal // return the surface bi-normal at the intersection point - ) - -{ - LLOctreeIntersect intersect(start, end, pick_transparent, face_hit, intersection, tex_coord, normal, bi_normal); - LLDrawable* drawable = intersect.check(mOctree); - - return drawable; -} - -LLDrawInfo::LLDrawInfo(U16 start, U16 end, U32 count, U32 offset, - LLViewerTexture* texture, LLVertexBuffer* buffer, - BOOL fullbright, U8 bump, BOOL particle, F32 part_size) -: - mVertexBuffer(buffer), - mTexture(texture), - mTextureMatrix(NULL), - mModelMatrix(NULL), - mStart(start), - mEnd(end), - mCount(count), - mOffset(offset), - mFullbright(fullbright), - mBump(bump), - mParticle(particle), - mPartSize(part_size), - mVSize(0.f), - mGroup(NULL), - mFace(NULL), - mDistance(0.f), - mDrawMode(LLRender::TRIANGLES) -{ - mVertexBuffer->validateRange(mStart, mEnd, mCount, mOffset); - - mDebugColor = (rand() << 16) + rand(); -} - -LLDrawInfo::~LLDrawInfo() -{ - /*if (LLSpatialGroup::sNoDelete) - { - llerrs << "LLDrawInfo deleted illegally!" << llendl; - }*/ - - if (mFace) - { - mFace->setDrawInfo(NULL); - } - - if (gDebugGL) - { - gPipeline.checkReferences(this); - } -} - -void LLDrawInfo::validate() -{ - mVertexBuffer->validateRange(mStart, mEnd, mCount, mOffset); -} - -LLVertexBuffer* LLGeometryManager::createVertexBuffer(U32 type_mask, U32 usage) -{ - return new LLVertexBuffer(type_mask, usage); -} - -LLCullResult::LLCullResult() -{ - clear(); -} - -void LLCullResult::clear() -{ - mVisibleGroupsSize = 0; - mVisibleGroupsEnd = mVisibleGroups.begin(); - - mAlphaGroupsSize = 0; - mAlphaGroupsEnd = mAlphaGroups.begin(); - - mOcclusionGroupsSize = 0; - mOcclusionGroupsEnd = mOcclusionGroups.begin(); - - mDrawableGroupsSize = 0; - mDrawableGroupsEnd = mDrawableGroups.begin(); - - mVisibleListSize = 0; - mVisibleListEnd = mVisibleList.begin(); - - mVisibleBridgeSize = 0; - mVisibleBridgeEnd = mVisibleBridge.begin(); - - - for (U32 i = 0; i < LLRenderPass::NUM_RENDER_TYPES; i++) - { - for (U32 j = 0; j < mRenderMapSize[i]; j++) - { - mRenderMap[i][j] = 0; - } - mRenderMapSize[i] = 0; - mRenderMapEnd[i] = mRenderMap[i].begin(); - } -} - -LLCullResult::sg_list_t::iterator LLCullResult::beginVisibleGroups() -{ - return mVisibleGroups.begin(); -} - -LLCullResult::sg_list_t::iterator LLCullResult::endVisibleGroups() -{ - return mVisibleGroupsEnd; -} - -LLCullResult::sg_list_t::iterator LLCullResult::beginAlphaGroups() -{ - return mAlphaGroups.begin(); -} - -LLCullResult::sg_list_t::iterator LLCullResult::endAlphaGroups() -{ - return mAlphaGroupsEnd; -} - -LLCullResult::sg_list_t::iterator LLCullResult::beginOcclusionGroups() -{ - return mOcclusionGroups.begin(); -} - -LLCullResult::sg_list_t::iterator LLCullResult::endOcclusionGroups() -{ - return mOcclusionGroupsEnd; -} - -LLCullResult::sg_list_t::iterator LLCullResult::beginDrawableGroups() -{ - return mDrawableGroups.begin(); -} - -LLCullResult::sg_list_t::iterator LLCullResult::endDrawableGroups() -{ - return mDrawableGroupsEnd; -} - -LLCullResult::drawable_list_t::iterator LLCullResult::beginVisibleList() -{ - return mVisibleList.begin(); -} - -LLCullResult::drawable_list_t::iterator LLCullResult::endVisibleList() -{ - return mVisibleListEnd; -} - -LLCullResult::bridge_list_t::iterator LLCullResult::beginVisibleBridge() -{ - return mVisibleBridge.begin(); -} - -LLCullResult::bridge_list_t::iterator LLCullResult::endVisibleBridge() -{ - return mVisibleBridgeEnd; -} - -LLCullResult::drawinfo_list_t::iterator LLCullResult::beginRenderMap(U32 type) -{ - return mRenderMap[type].begin(); -} - -LLCullResult::drawinfo_list_t::iterator LLCullResult::endRenderMap(U32 type) -{ - return mRenderMapEnd[type]; -} - -void LLCullResult::pushVisibleGroup(LLSpatialGroup* group) -{ - if (mVisibleGroupsSize < mVisibleGroups.size()) - { - mVisibleGroups[mVisibleGroupsSize] = group; - } - else - { - mVisibleGroups.push_back(group); - } - ++mVisibleGroupsSize; - mVisibleGroupsEnd = mVisibleGroups.begin()+mVisibleGroupsSize; -} - -void LLCullResult::pushAlphaGroup(LLSpatialGroup* group) -{ - if (mAlphaGroupsSize < mAlphaGroups.size()) - { - mAlphaGroups[mAlphaGroupsSize] = group; - } - else - { - mAlphaGroups.push_back(group); - } - ++mAlphaGroupsSize; - mAlphaGroupsEnd = mAlphaGroups.begin()+mAlphaGroupsSize; -} - -void LLCullResult::pushOcclusionGroup(LLSpatialGroup* group) -{ - if (mOcclusionGroupsSize < mOcclusionGroups.size()) - { - mOcclusionGroups[mOcclusionGroupsSize] = group; - } - else - { - mOcclusionGroups.push_back(group); - } - ++mOcclusionGroupsSize; - mOcclusionGroupsEnd = mOcclusionGroups.begin()+mOcclusionGroupsSize; -} - -void LLCullResult::pushDrawableGroup(LLSpatialGroup* group) -{ - if (mDrawableGroupsSize < mDrawableGroups.size()) - { - mDrawableGroups[mDrawableGroupsSize] = group; - } - else - { - mDrawableGroups.push_back(group); - } - ++mDrawableGroupsSize; - mDrawableGroupsEnd = mDrawableGroups.begin()+mDrawableGroupsSize; -} - -void LLCullResult::pushDrawable(LLDrawable* drawable) -{ - if (mVisibleListSize < mVisibleList.size()) - { - mVisibleList[mVisibleListSize] = drawable; - } - else - { - mVisibleList.push_back(drawable); - } - ++mVisibleListSize; - mVisibleListEnd = mVisibleList.begin()+mVisibleListSize; -} - -void LLCullResult::pushBridge(LLSpatialBridge* bridge) -{ - if (mVisibleBridgeSize < mVisibleBridge.size()) - { - mVisibleBridge[mVisibleBridgeSize] = bridge; - } - else - { - mVisibleBridge.push_back(bridge); - } - ++mVisibleBridgeSize; - mVisibleBridgeEnd = mVisibleBridge.begin()+mVisibleBridgeSize; -} - -void LLCullResult::pushDrawInfo(U32 type, LLDrawInfo* draw_info) -{ - if (mRenderMapSize[type] < mRenderMap[type].size()) - { - mRenderMap[type][mRenderMapSize[type]] = draw_info; - } - else - { - mRenderMap[type].push_back(draw_info); - } - ++mRenderMapSize[type]; - mRenderMapEnd[type] = mRenderMap[type].begin() + mRenderMapSize[type]; -} - - -void LLCullResult::assertDrawMapsEmpty() -{ - for (U32 i = 0; i < LLRenderPass::NUM_RENDER_TYPES; i++) - { - if (mRenderMapSize[i] != 0) - { - llerrs << "Stale LLDrawInfo's in LLCullResult!" << llendl; - } - } -} - - - +/**
+ * @file llspatialpartition.cpp
+ * @brief LLSpatialGroup class implementation and supporting functions
+ *
+ * $LicenseInfo:firstyear=2003&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 "llspatialpartition.h"
+
+#include "llappviewer.h"
+#include "lltexturecache.h"
+#include "lltexturefetch.h"
+#include "llimageworker.h"
+#include "llviewerwindow.h"
+#include "llviewerobjectlist.h"
+#include "llvovolume.h"
+#include "llvolume.h"
+#include "llvolumeoctree.h"
+#include "llviewercamera.h"
+#include "llface.h"
+#include "llfloatertools.h"
+#include "llviewercontrol.h"
+#include "llviewerregion.h"
+#include "llcamera.h"
+#include "pipeline.h"
+#include "llmeshrepository.h"
+#include "llrender.h"
+#include "lloctree.h"
+#include "llphysicsshapebuilderutil.h"
+#include "llvoavatar.h"
+#include "llvolumemgr.h"
+#include "lltextureatlas.h"
+#include "llglslshader.h"
+#include "llagent.h"
+#include "llviewershadermgr.h"
+
+static LLFastTimer::DeclareTimer FTM_FRUSTUM_CULL("Frustum Culling");
+static LLFastTimer::DeclareTimer FTM_CULL_REBOUND("Cull Rebound");
+
+const F32 SG_OCCLUSION_FUDGE = 0.25f;
+#define SG_DISCARD_TOLERANCE 0.01f
+
+#if LL_OCTREE_PARANOIA_CHECK
+#define assert_octree_valid(x) x->validate()
+#define assert_states_valid(x) ((LLSpatialGroup*) x->mSpatialPartition->mOctree->getListener(0))->checkStates()
+#else
+#define assert_octree_valid(x)
+#define assert_states_valid(x)
+#endif
+
+
+static U32 sZombieGroups = 0;
+U32 LLSpatialGroup::sNodeCount = 0;
+
+#define LL_TRACK_PENDING_OCCLUSION_QUERIES 0
+
+std::set<GLuint> LLSpatialGroup::sPendingQueries;
+
+U32 gOctreeMaxCapacity;
+
+BOOL LLSpatialGroup::sNoDelete = FALSE;
+
+static F32 sLastMaxTexPriority = 1.f;
+static F32 sCurMaxTexPriority = 1.f;
+
+class LLOcclusionQueryPool : public LLGLNamePool
+{
+protected:
+ virtual GLuint allocateName()
+ {
+ GLuint name;
+ glGenQueriesARB(1, &name);
+ return name;
+ }
+
+ virtual void releaseName(GLuint name)
+ {
+#if LL_TRACK_PENDING_OCCLUSION_QUERIES
+ LLSpatialGroup::sPendingQueries.erase(name);
+#endif
+ glDeleteQueriesARB(1, &name);
+ }
+};
+
+static LLOcclusionQueryPool sQueryPool;
+
+//static counter for frame to switch LOD on
+
+void sg_assert(BOOL expr)
+{
+#if LL_OCTREE_PARANOIA_CHECK
+ if (!expr)
+ {
+ llerrs << "Octree invalid!" << llendl;
+ }
+#endif
+}
+
+S32 AABBSphereIntersect(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &rad)
+{
+ return AABBSphereIntersectR2(min, max, origin, rad*rad);
+}
+
+S32 AABBSphereIntersectR2(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &r)
+{
+ F32 d = 0.f;
+ F32 t;
+
+ if ((min-origin).magVecSquared() < r &&
+ (max-origin).magVecSquared() < r)
+ {
+ return 2;
+ }
+
+ for (U32 i = 0; i < 3; i++)
+ {
+ if (origin.mV[i] < min.mV[i])
+ {
+ t = min.mV[i] - origin.mV[i];
+ d += t*t;
+ }
+ else if (origin.mV[i] > max.mV[i])
+ {
+ t = origin.mV[i] - max.mV[i];
+ d += t*t;
+ }
+
+ if (d > r)
+ {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+
+S32 AABBSphereIntersect(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &rad)
+{
+ return AABBSphereIntersectR2(min, max, origin, rad*rad);
+}
+
+S32 AABBSphereIntersectR2(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &r)
+{
+ F32 d = 0.f;
+ F32 t;
+
+ LLVector4a origina;
+ origina.load3(origin.mV);
+
+ LLVector4a v;
+ v.setSub(min, origina);
+
+ if (v.dot3(v) < r)
+ {
+ v.setSub(max, origina);
+ if (v.dot3(v) < r)
+ {
+ return 2;
+ }
+ }
+
+
+ for (U32 i = 0; i < 3; i++)
+ {
+ if (origin.mV[i] < min[i])
+ {
+ t = min[i] - origin.mV[i];
+ d += t*t;
+ }
+ else if (origin.mV[i] > max[i])
+ {
+ t = origin.mV[i] - max[i];
+ d += t*t;
+ }
+
+ if (d > r)
+ {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+
+typedef enum
+{
+ b000 = 0x00,
+ b001 = 0x01,
+ b010 = 0x02,
+ b011 = 0x03,
+ b100 = 0x04,
+ b101 = 0x05,
+ b110 = 0x06,
+ b111 = 0x07,
+} eLoveTheBits;
+
+//contact Runitai Linden for a copy of the SL object used to write this table
+//basically, you give the table a bitmask of the look-at vector to a node and it
+//gives you a triangle fan index array
+static U16 sOcclusionIndices[] =
+{
+ //000
+ b111, b110, b010, b011, b001, b101, b100, b110,
+ //001
+ b011, b010, b000, b001, b101, b111, b110, b010,
+ //010
+ b101, b100, b110, b111, b011, b001, b000, b100,
+ //011
+ b001, b000, b100, b101, b111, b011, b010, b000,
+ //100
+ b110, b000, b010, b011, b111, b101, b100, b000,
+ //101
+ b010, b100, b000, b001, b011, b111, b110, b100,
+ //110
+ b100, b010, b110, b111, b101, b001, b000, b010,
+ //111
+ b000, b110, b100, b101, b001, b011, b010, b110,
+};
+
+U32 get_box_fan_indices(LLCamera* camera, const LLVector4a& center)
+{
+ LLVector4a origin;
+ origin.load3(camera->getOrigin().mV);
+
+ S32 cypher = center.greaterThan(origin).getGatheredBits() & 0x7;
+
+ return cypher*8;
+}
+
+U8* get_box_fan_indices_ptr(LLCamera* camera, const LLVector4a& center)
+{
+ LLVector4a origin;
+ origin.load3(camera->getOrigin().mV);
+
+ S32 cypher = center.greaterThan(origin).getGatheredBits() & 0x7;
+
+ return (U8*) (sOcclusionIndices+cypher*8);
+}
+
+
+static LLFastTimer::DeclareTimer FTM_BUILD_OCCLUSION("Build Occlusion");
+
+void LLSpatialGroup::buildOcclusion()
+{
+ //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];
+ }
+ }
+
+ LLVector4a fudge;
+ fudge.splat(SG_OCCLUSION_FUDGE);
+
+ LLVector4a r;
+ r.setAdd(mBounds[1], fudge);
+
+ LLStrider<LLVector3> pos;
+
+ {
+ LLFastTimer t(FTM_BUILD_OCCLUSION);
+ mOcclusionVerts->getVertexStrider(pos);
+ }
+
+ {
+ LLVector4a* v = (LLVector4a*) pos.get();
+
+ 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;
+ }
+ }
+
+ {
+ mOcclusionVerts->flush();
+ LLVertexBuffer::unbind();
+ }
+
+ clearState(LLSpatialGroup::OCCLUSION_DIRTY);
+}
+
+
+BOOL earlyFail(LLCamera* camera, LLSpatialGroup* group);
+
+//returns:
+// 0 if sphere and AABB are not intersecting
+// 1 if they are
+// 2 if AABB is entirely inside sphere
+
+S32 LLSphereAABB(const LLVector3& center, const LLVector3& size, const LLVector3& pos, const F32 &rad)
+{
+ S32 ret = 2;
+
+ LLVector3 min = center - size;
+ LLVector3 max = center + size;
+ for (U32 i = 0; i < 3; i++)
+ {
+ if (min.mV[i] > pos.mV[i] + rad ||
+ max.mV[i] < pos.mV[i] - rad)
+ { //totally outside
+ return 0;
+ }
+
+ if (min.mV[i] < pos.mV[i] - rad ||
+ max.mV[i] > pos.mV[i] + rad)
+ { //intersecting
+ ret = 1;
+ }
+ }
+
+ return ret;
+}
+
+LLSpatialGroup::~LLSpatialGroup()
+{
+ /*if (sNoDelete)
+ {
+ llerrs << "Illegal deletion of LLSpatialGroup!" << llendl;
+ }*/
+
+ if (gDebugGL)
+ {
+ gPipeline.checkReferences(this);
+ }
+
+ if (isState(DEAD))
+ {
+ sZombieGroups--;
+ }
+
+ sNodeCount--;
+
+ if (gGLManager.mHasOcclusionQuery)
+ {
+ for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; ++i)
+ {
+ if (mOcclusionQuery[i])
+ {
+ sQueryPool.release(mOcclusionQuery[i]);
+ }
+ }
+ }
+
+ mOcclusionVerts = NULL;
+
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+ clearDrawMap();
+ clearAtlasList() ;
+}
+
+BOOL LLSpatialGroup::hasAtlas(LLTextureAtlas* atlasp)
+{
+ S8 type = atlasp->getComponents() - 1 ;
+ for(std::list<LLTextureAtlas*>::iterator iter = mAtlasList[type].begin(); iter != mAtlasList[type].end() ; ++iter)
+ {
+ if(atlasp == *iter)
+ {
+ return TRUE ;
+ }
+ }
+ return FALSE ;
+}
+
+void LLSpatialGroup::addAtlas(LLTextureAtlas* atlasp, S8 recursive_level)
+{
+ if(!hasAtlas(atlasp))
+ {
+ mAtlasList[atlasp->getComponents() - 1].push_back(atlasp) ;
+ atlasp->addSpatialGroup(this) ;
+ }
+
+ --recursive_level;
+ if(recursive_level)//levels propagating up.
+ {
+ LLSpatialGroup* parent = getParent() ;
+ if(parent)
+ {
+ parent->addAtlas(atlasp, recursive_level) ;
+ }
+ }
+}
+
+void LLSpatialGroup::removeAtlas(LLTextureAtlas* atlasp, BOOL remove_group, S8 recursive_level)
+{
+ mAtlasList[atlasp->getComponents() - 1].remove(atlasp) ;
+ if(remove_group)
+ {
+ atlasp->removeSpatialGroup(this) ;
+ }
+
+ --recursive_level;
+ if(recursive_level)//levels propagating up.
+ {
+ LLSpatialGroup* parent = getParent() ;
+ if(parent)
+ {
+ parent->removeAtlas(atlasp, recursive_level) ;
+ }
+ }
+}
+
+void LLSpatialGroup::clearAtlasList()
+{
+ std::list<LLTextureAtlas*>::iterator iter ;
+ for(S8 i = 0 ; i < 4 ; i++)
+ {
+ if(mAtlasList[i].size() > 0)
+ {
+ for(iter = mAtlasList[i].begin(); iter != mAtlasList[i].end() ; ++iter)
+ {
+ ((LLTextureAtlas*)*iter)->removeSpatialGroup(this) ;
+ }
+ mAtlasList[i].clear() ;
+ }
+ }
+}
+
+LLTextureAtlas* LLSpatialGroup::getAtlas(S8 ncomponents, S8 to_be_reserved, S8 recursive_level)
+{
+ S8 type = ncomponents - 1 ;
+ if(mAtlasList[type].size() > 0)
+ {
+ for(std::list<LLTextureAtlas*>::iterator iter = mAtlasList[type].begin(); iter != mAtlasList[type].end() ; ++iter)
+ {
+ if(!((LLTextureAtlas*)*iter)->isFull(to_be_reserved))
+ {
+ return *iter ;
+ }
+ }
+ }
+
+ --recursive_level;
+ if(recursive_level)
+ {
+ LLSpatialGroup* parent = getParent() ;
+ if(parent)
+ {
+ return parent->getAtlas(ncomponents, to_be_reserved, recursive_level) ;
+ }
+ }
+ return NULL ;
+}
+
+void LLSpatialGroup::setCurUpdatingSlot(LLTextureAtlasSlot* slotp)
+{
+ mCurUpdatingSlotp = slotp;
+
+ //if(!hasAtlas(mCurUpdatingSlotp->getAtlas()))
+ //{
+ // addAtlas(mCurUpdatingSlotp->getAtlas()) ;
+ //}
+}
+
+LLTextureAtlasSlot* LLSpatialGroup::getCurUpdatingSlot(LLViewerTexture* imagep, S8 recursive_level)
+{
+ if(gFrameCount && mCurUpdatingTime == gFrameCount && mCurUpdatingTexture == imagep)
+ {
+ return mCurUpdatingSlotp ;
+ }
+
+ //--recursive_level ;
+ //if(recursive_level)
+ //{
+ // LLSpatialGroup* parent = getParent() ;
+ // if(parent)
+ // {
+ // return parent->getCurUpdatingSlot(imagep, recursive_level) ;
+ // }
+ //}
+ return NULL ;
+}
+
+void LLSpatialGroup::clearDrawMap()
+{
+ mDrawMap.clear();
+}
+
+BOOL LLSpatialGroup::isHUDGroup()
+{
+ return mSpatialPartition && mSpatialPartition->isHUDPartition() ;
+}
+
+BOOL LLSpatialGroup::isRecentlyVisible() const
+{
+ return (LLDrawable::getCurrentFrame() - mVisible[LLViewerCamera::sCurCameraID]) < LLDrawable::getMinVisFrameRange() ;
+}
+
+BOOL LLSpatialGroup::isVisible() const
+{
+ return mVisible[LLViewerCamera::sCurCameraID] >= LLDrawable::getCurrentFrame() ? TRUE : FALSE;
+}
+
+void LLSpatialGroup::setVisible()
+{
+ mVisible[LLViewerCamera::sCurCameraID] = LLDrawable::getCurrentFrame();
+}
+
+void LLSpatialGroup::validate()
+{
+#if LL_OCTREE_PARANOIA_CHECK
+
+ sg_assert(!isState(DIRTY));
+ sg_assert(!isDead());
+
+ LLVector4a myMin;
+ myMin.setSub(mBounds[0], mBounds[1]);
+ LLVector4a myMax;
+ myMax.setAdd(mBounds[0], mBounds[1]);
+
+ validateDrawMap();
+
+ for (element_iter i = getData().begin(); i != getData().end(); ++i)
+ {
+ LLDrawable* drawable = *i;
+ sg_assert(drawable->getSpatialGroup() == this);
+ if (drawable->getSpatialBridge())
+ {
+ sg_assert(drawable->getSpatialBridge() == mSpatialPartition->asBridge());
+ }
+
+ /*if (drawable->isSpatialBridge())
+ {
+ LLSpatialPartition* part = drawable->asPartition();
+ if (!part)
+ {
+ llerrs << "Drawable reports it is a spatial bridge but not a partition." << llendl;
+ }
+ LLSpatialGroup* group = (LLSpatialGroup*) part->mOctree->getListener(0);
+ group->validate();
+ }*/
+ }
+
+ for (U32 i = 0; i < mOctreeNode->getChildCount(); ++i)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) mOctreeNode->getChild(i)->getListener(0);
+
+ group->validate();
+
+ //ensure all children are enclosed in this node
+ LLVector4a center = group->mBounds[0];
+ LLVector4a size = group->mBounds[1];
+
+ LLVector4a min;
+ min.setSub(center, size);
+ LLVector4a max;
+ max.setAdd(center, size);
+
+ for (U32 j = 0; j < 3; j++)
+ {
+ sg_assert(min[j] >= myMin[j]-0.02f);
+ sg_assert(max[j] <= myMax[j]+0.02f);
+ }
+ }
+
+#endif
+}
+
+void LLSpatialGroup::checkStates()
+{
+#if LL_OCTREE_PARANOIA_CHECK
+ //LLOctreeStateCheck checker;
+ //checker.traverse(mOctreeNode);
+#endif
+}
+
+void LLSpatialGroup::validateDrawMap()
+{
+#if LL_OCTREE_PARANOIA_CHECK
+ for (draw_map_t::iterator i = mDrawMap.begin(); i != mDrawMap.end(); ++i)
+ {
+ LLSpatialGroup::drawmap_elem_t& draw_vec = i->second;
+ for (drawmap_elem_t::iterator j = draw_vec.begin(); j != draw_vec.end(); ++j)
+ {
+ LLDrawInfo& params = **j;
+
+ params.validate();
+ }
+ }
+#endif
+}
+
+BOOL LLSpatialGroup::updateInGroup(LLDrawable *drawablep, BOOL immediate)
+{
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+
+ drawablep->updateSpatialExtents();
+
+ OctreeNode* parent = mOctreeNode->getOctParent();
+
+ if (mOctreeNode->isInside(drawablep->getPositionGroup()) &&
+ (mOctreeNode->contains(drawablep) ||
+ (drawablep->getBinRadius() > mOctreeNode->getSize()[0] &&
+ parent && parent->getElementCount() >= gOctreeMaxCapacity)))
+ {
+ unbound();
+ setState(OBJECT_DIRTY);
+ //setState(GEOM_DIRTY);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+BOOL LLSpatialGroup::addObject(LLDrawable *drawablep, BOOL add_all, BOOL from_octree)
+{
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+ if (!from_octree)
+ {
+ mOctreeNode->insert(drawablep);
+ }
+ else
+ {
+ drawablep->setSpatialGroup(this);
+ setState(OBJECT_DIRTY | GEOM_DIRTY);
+ setOcclusionState(LLSpatialGroup::DISCARD_QUERY, LLSpatialGroup::STATE_MODE_ALL_CAMERAS);
+ gPipeline.markRebuild(this, TRUE);
+ if (drawablep->isSpatialBridge())
+ {
+ mBridgeList.push_back((LLSpatialBridge*) drawablep);
+ }
+ if (drawablep->getRadius() > 1.f)
+ {
+ setState(IMAGE_DIRTY);
+ }
+ }
+
+ return TRUE;
+}
+
+void LLSpatialGroup::rebuildGeom()
+{
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+ if (!isDead())
+ {
+ mSpatialPartition->rebuildGeom(this);
+ }
+}
+
+void LLSpatialGroup::rebuildMesh()
+{
+ if (!isDead())
+ {
+ mSpatialPartition->rebuildMesh(this);
+ }
+}
+
+static LLFastTimer::DeclareTimer FTM_REBUILD_VBO("VBO Rebuilt");
+
+void LLSpatialPartition::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_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)
+ { //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();
+ }
+ else
+ {
+ group->mVertexBuffer->resizeBuffer(vertex_count, index_count);
+ stop_glerror();
+ }
+
+ getGeometry(group);
+ }
+ else
+ {
+ group->mVertexBuffer = NULL;
+ group->mBufferMap.clear();
+ }
+
+ group->mLastUpdateTime = gFrameTimeSeconds;
+ group->clearState(LLSpatialGroup::GEOM_DIRTY);
+}
+
+
+void LLSpatialPartition::rebuildMesh(LLSpatialGroup* group)
+{
+
+}
+
+BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector4a& minOut, LLVector4a& maxOut)
+{
+ const OctreeNode* node = mOctreeNode;
+
+ if (node->getData().empty())
+ { //don't do anything if there are no objects
+ if (empty && mOctreeNode->getParent())
+ { //only root is allowed to be empty
+ OCT_ERRS << "Empty leaf found in octree." << llendl;
+ }
+ return FALSE;
+ }
+
+ LLVector4a& newMin = mObjectExtents[0];
+ LLVector4a& newMax = mObjectExtents[1];
+
+ if (isState(OBJECT_DIRTY))
+ { //calculate new bounding box
+ clearState(OBJECT_DIRTY);
+
+ //initialize bounding box to first element
+ OctreeNode::const_element_iter i = node->getData().begin();
+ LLDrawable* drawablep = *i;
+ const LLVector4a* minMax = drawablep->getSpatialExtents();
+
+ newMin = minMax[0];
+ newMax = minMax[1];
+
+ for (++i; i != node->getData().end(); ++i)
+ {
+ drawablep = *i;
+ minMax = drawablep->getSpatialExtents();
+
+ update_min_max(newMin, newMax, minMax[0]);
+ update_min_max(newMin, newMax, minMax[1]);
+
+ //bin up the object
+ /*for (U32 i = 0; i < 3; i++)
+ {
+ if (minMax[0].mV[i] < newMin.mV[i])
+ {
+ newMin.mV[i] = minMax[0].mV[i];
+ }
+ if (minMax[1].mV[i] > newMax.mV[i])
+ {
+ newMax.mV[i] = minMax[1].mV[i];
+ }
+ }*/
+ }
+
+ mObjectBounds[0].setAdd(newMin, newMax);
+ mObjectBounds[0].mul(0.5f);
+ mObjectBounds[1].setSub(newMax, newMin);
+ mObjectBounds[1].mul(0.5f);
+ }
+
+ if (empty)
+ {
+ minOut = newMin;
+ maxOut = newMax;
+ }
+ else
+ {
+ minOut.setMin(minOut, newMin);
+ maxOut.setMax(maxOut, newMax);
+ }
+
+ return TRUE;
+}
+
+void LLSpatialGroup::unbound()
+{
+ if (isState(DIRTY))
+ {
+ return;
+ }
+
+ setState(DIRTY);
+
+ //all the parent nodes need to rebound this child
+ if (mOctreeNode)
+ {
+ OctreeNode* parent = (OctreeNode*) mOctreeNode->getParent();
+ while (parent != NULL)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) parent->getListener(0);
+ if (group->isState(DIRTY))
+ {
+ return;
+ }
+
+ group->setState(DIRTY);
+ parent = (OctreeNode*) parent->getParent();
+ }
+ }
+}
+
+LLSpatialGroup* LLSpatialGroup::getParent()
+{
+ if (isDead())
+ {
+ return NULL;
+ }
+
+ if(!mOctreeNode)
+ {
+ return NULL;
+ }
+ OctreeNode* parent = mOctreeNode->getOctParent();
+
+ if (parent)
+ {
+ return (LLSpatialGroup*) parent->getListener(0);
+ }
+
+ return NULL;
+}
+
+BOOL LLSpatialGroup::removeObject(LLDrawable *drawablep, BOOL from_octree)
+{
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+ unbound();
+ if (mOctreeNode && !from_octree)
+ {
+ if (!mOctreeNode->remove(drawablep))
+ {
+ OCT_ERRS << "Could not remove drawable from spatial group" << llendl;
+ }
+ }
+ else
+ {
+ drawablep->setSpatialGroup(NULL);
+ setState(GEOM_DIRTY);
+ gPipeline.markRebuild(this, TRUE);
+
+ if (drawablep->isSpatialBridge())
+ {
+ for (bridge_list_t::iterator i = mBridgeList.begin(); i != mBridgeList.end(); ++i)
+ {
+ if (*i == drawablep)
+ {
+ mBridgeList.erase(i);
+ break;
+ }
+ }
+ }
+
+ if (getElementCount() == 0)
+ { //delete draw map on last element removal since a rebuild might never happen
+ clearDrawMap();
+ }
+ }
+ return TRUE;
+}
+
+void LLSpatialGroup::shift(const LLVector4a &offset)
+{
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+ LLVector4a t = mOctreeNode->getCenter();
+ t.add(offset);
+ mOctreeNode->setCenter(t);
+ mOctreeNode->updateMinMax();
+ mBounds[0].add(offset);
+ mExtents[0].add(offset);
+ mExtents[1].add(offset);
+ mObjectBounds[0].add(offset);
+ mObjectExtents[0].add(offset);
+ mObjectExtents[1].add(offset);
+
+ //if (!mSpatialPartition->mRenderByGroup)
+ {
+ setState(GEOM_DIRTY);
+ gPipeline.markRebuild(this, TRUE);
+ }
+
+ if (mOcclusionVerts.notNull())
+ {
+ setState(OCCLUSION_DIRTY);
+ }
+}
+
+class LLSpatialSetState : public LLSpatialGroup::OctreeTraveler
+{
+public:
+ U32 mState;
+ LLSpatialSetState(U32 state) : mState(state) { }
+ virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->setState(mState); }
+};
+
+class LLSpatialSetStateDiff : public LLSpatialSetState
+{
+public:
+ LLSpatialSetStateDiff(U32 state) : LLSpatialSetState(state) { }
+
+ virtual void traverse(const LLSpatialGroup::OctreeNode* n)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
+
+ if (!group->isState(mState))
+ {
+ LLSpatialGroup::OctreeTraveler::traverse(n);
+ }
+ }
+};
+
+void LLSpatialGroup::setState(U32 state)
+{
+ mState |= state;
+
+ llassert(state <= LLSpatialGroup::STATE_MASK);
+}
+
+void LLSpatialGroup::setState(U32 state, S32 mode)
+{
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+
+ llassert(state <= LLSpatialGroup::STATE_MASK);
+
+ if (mode > STATE_MODE_SINGLE)
+ {
+ if (mode == STATE_MODE_DIFF)
+ {
+ LLSpatialSetStateDiff setter(state);
+ setter.traverse(mOctreeNode);
+ }
+ else
+ {
+ LLSpatialSetState setter(state);
+ setter.traverse(mOctreeNode);
+ }
+ }
+ else
+ {
+ mState |= state;
+ }
+}
+
+class LLSpatialClearState : public LLSpatialGroup::OctreeTraveler
+{
+public:
+ U32 mState;
+ LLSpatialClearState(U32 state) : mState(state) { }
+ virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->clearState(mState); }
+};
+
+class LLSpatialClearStateDiff : public LLSpatialClearState
+{
+public:
+ LLSpatialClearStateDiff(U32 state) : LLSpatialClearState(state) { }
+
+ virtual void traverse(const LLSpatialGroup::OctreeNode* n)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
+
+ if (group->isState(mState))
+ {
+ LLSpatialGroup::OctreeTraveler::traverse(n);
+ }
+ }
+};
+
+void LLSpatialGroup::clearState(U32 state)
+{
+ llassert(state <= LLSpatialGroup::STATE_MASK);
+
+ mState &= ~state;
+}
+
+void LLSpatialGroup::clearState(U32 state, S32 mode)
+{
+ llassert(state <= LLSpatialGroup::STATE_MASK);
+
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+
+ if (mode > STATE_MODE_SINGLE)
+ {
+ if (mode == STATE_MODE_DIFF)
+ {
+ LLSpatialClearStateDiff clearer(state);
+ clearer.traverse(mOctreeNode);
+ }
+ else
+ {
+ LLSpatialClearState clearer(state);
+ clearer.traverse(mOctreeNode);
+ }
+ }
+ else
+ {
+ mState &= ~state;
+ }
+}
+
+BOOL LLSpatialGroup::isState(U32 state) const
+{
+ llassert(state <= LLSpatialGroup::STATE_MASK);
+
+ return mState & state ? TRUE : FALSE;
+}
+
+//=====================================
+// Occlusion State Set/Clear
+//=====================================
+class LLSpatialSetOcclusionState : public LLSpatialGroup::OctreeTraveler
+{
+public:
+ U32 mState;
+ LLSpatialSetOcclusionState(U32 state) : mState(state) { }
+ virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->setOcclusionState(mState); }
+};
+
+class LLSpatialSetOcclusionStateDiff : public LLSpatialSetOcclusionState
+{
+public:
+ LLSpatialSetOcclusionStateDiff(U32 state) : LLSpatialSetOcclusionState(state) { }
+
+ virtual void traverse(const LLSpatialGroup::OctreeNode* n)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
+
+ if (!group->isOcclusionState(mState))
+ {
+ LLSpatialGroup::OctreeTraveler::traverse(n);
+ }
+ }
+};
+
+
+void LLSpatialGroup::setOcclusionState(U32 state, S32 mode)
+{
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+
+ if (mode > STATE_MODE_SINGLE)
+ {
+ if (mode == STATE_MODE_DIFF)
+ {
+ LLSpatialSetOcclusionStateDiff setter(state);
+ setter.traverse(mOctreeNode);
+ }
+ else if (mode == STATE_MODE_BRANCH)
+ {
+ LLSpatialSetOcclusionState setter(state);
+ setter.traverse(mOctreeNode);
+ }
+ else
+ {
+ for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
+ {
+ mOcclusionState[i] |= state;
+
+ if ((state & DISCARD_QUERY) && mOcclusionQuery[i])
+ {
+ sQueryPool.release(mOcclusionQuery[i]);
+ mOcclusionQuery[i] = 0;
+ }
+ }
+ }
+ }
+ else
+ {
+ mOcclusionState[LLViewerCamera::sCurCameraID] |= state;
+ if ((state & DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID])
+ {
+ sQueryPool.release(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+ mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0;
+ }
+ }
+}
+
+class LLSpatialClearOcclusionState : public LLSpatialGroup::OctreeTraveler
+{
+public:
+ U32 mState;
+
+ LLSpatialClearOcclusionState(U32 state) : mState(state) { }
+ virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->clearOcclusionState(mState); }
+};
+
+class LLSpatialClearOcclusionStateDiff : public LLSpatialClearOcclusionState
+{
+public:
+ LLSpatialClearOcclusionStateDiff(U32 state) : LLSpatialClearOcclusionState(state) { }
+
+ virtual void traverse(const LLSpatialGroup::OctreeNode* n)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
+
+ if (group->isOcclusionState(mState))
+ {
+ LLSpatialGroup::OctreeTraveler::traverse(n);
+ }
+ }
+};
+
+void LLSpatialGroup::clearOcclusionState(U32 state, S32 mode)
+{
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+
+ if (mode > STATE_MODE_SINGLE)
+ {
+ if (mode == STATE_MODE_DIFF)
+ {
+ LLSpatialClearOcclusionStateDiff clearer(state);
+ clearer.traverse(mOctreeNode);
+ }
+ else if (mode == STATE_MODE_BRANCH)
+ {
+ LLSpatialClearOcclusionState clearer(state);
+ clearer.traverse(mOctreeNode);
+ }
+ else
+ {
+ for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
+ {
+ mOcclusionState[i] &= ~state;
+ }
+ }
+ }
+ else
+ {
+ mOcclusionState[LLViewerCamera::sCurCameraID] &= ~state;
+ }
+}
+//======================================
+// Octree Listener Implementation
+//======================================
+
+LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) :
+ mState(0),
+ mGeometryBytes(0),
+ mSurfaceArea(0.f),
+ mBuilt(0.f),
+ mOctreeNode(node),
+ mSpatialPartition(part),
+ mVertexBuffer(NULL),
+ mBufferUsage(part->mBufferUsage),
+ mDistance(0.f),
+ mDepth(0.f),
+ mLastUpdateDistance(-1.f),
+ mLastUpdateTime(gFrameTimeSeconds),
+ mAtlasList(4),
+ mCurUpdatingTime(0),
+ mCurUpdatingSlotp(NULL),
+ mCurUpdatingTexture (NULL)
+{
+ sNodeCount++;
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+
+ mViewAngle.splat(0.f);
+ mLastUpdateViewAngle.splat(-1.f);
+ mExtents[0] = mExtents[1] = mObjectBounds[0] = mObjectBounds[0] = mObjectBounds[1] =
+ mObjectExtents[0] = mObjectExtents[1] = mViewAngle;
+
+ sg_assert(mOctreeNode->getListenerCount() == 0);
+ mOctreeNode->addListener(this);
+ setState(SG_INITIAL_STATE_MASK);
+ gPipeline.markRebuild(this, TRUE);
+
+ mBounds[0] = node->getCenter();
+ mBounds[1] = node->getSize();
+
+ part->mLODSeed = (part->mLODSeed+1)%part->mLODPeriod;
+ mLODHash = part->mLODSeed;
+
+ OctreeNode* oct_parent = node->getOctParent();
+
+ LLSpatialGroup* parent = oct_parent ? (LLSpatialGroup*) oct_parent->getListener(0) : NULL;
+
+ for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
+ {
+ mOcclusionQuery[i] = 0;
+ mOcclusionIssued[i] = 0;
+ mOcclusionState[i] = parent ? SG_STATE_INHERIT_MASK & parent->mOcclusionState[i] : 0;
+ mVisible[i] = 0;
+ }
+
+ mOcclusionVerts = NULL;
+
+ mRadius = 1;
+ mPixelArea = 1024.f;
+}
+
+void LLSpatialGroup::updateDistance(LLCamera &camera)
+{
+ if (LLViewerCamera::sCurCameraID != LLViewerCamera::CAMERA_WORLD)
+ {
+ llwarns << "Attempted to update distance for camera other than world camera!" << llendl;
+ return;
+ }
+
+#if !LL_RELEASE_FOR_DOWNLOAD
+ if (isState(LLSpatialGroup::OBJECT_DIRTY))
+ {
+ llerrs << "Spatial group dirty on distance update." << llendl;
+ }
+#endif
+ if (!getData().empty())
+ {
+ mRadius = mSpatialPartition->mRenderByGroup ? mObjectBounds[1].getLength3().getF32() :
+ (F32) mOctreeNode->getSize().getLength3().getF32();
+ mDistance = mSpatialPartition->calcDistance(this, camera);
+ mPixelArea = mSpatialPartition->calcPixelArea(this, camera);
+ }
+}
+
+F32 LLSpatialPartition::calcDistance(LLSpatialGroup* group, LLCamera& camera)
+{
+ LLVector4a eye;
+ LLVector4a origin;
+ origin.load3(camera.getOrigin().mV);
+
+ eye.setSub(group->mObjectBounds[0], origin);
+
+ F32 dist = 0.f;
+
+ if (group->mDrawMap.find(LLRenderPass::PASS_ALPHA) != group->mDrawMap.end())
+ {
+ LLVector4a v = eye;
+
+ dist = eye.getLength3().getF32();
+ eye.normalize3fast();
+
+ if (!group->isState(LLSpatialGroup::ALPHA_DIRTY))
+ {
+ if (!group->mSpatialPartition->isBridge())
+ {
+ LLVector4a view_angle = eye;
+
+ LLVector4a diff;
+ diff.setSub(view_angle, group->mLastUpdateViewAngle);
+
+ if (diff.getLength3().getF32() > 0.64f)
+ {
+ group->mViewAngle = view_angle;
+ group->mLastUpdateViewAngle = view_angle;
+ //for occasional alpha sorting within the group
+ //NOTE: If there is a trivial way to detect that alpha sorting here would not change the render order,
+ //not setting this node to dirty would be a very good thing
+ group->setState(LLSpatialGroup::ALPHA_DIRTY);
+ gPipeline.markRebuild(group, FALSE);
+ }
+ }
+ }
+
+ //calculate depth of node for alpha sorting
+
+ LLVector3 at = camera.getAtAxis();
+
+ LLVector4a ata;
+ ata.load3(at.mV);
+
+ LLVector4a t = ata;
+ //front of bounding box
+ t.mul(0.25f);
+ t.mul(group->mObjectBounds[1]);
+ v.sub(t);
+
+ group->mDepth = v.dot3(ata).getF32();
+ }
+ else
+ {
+ dist = eye.getLength3().getF32();
+ }
+
+ if (dist < 16.f)
+ {
+ dist /= 16.f;
+ dist *= dist;
+ dist *= 16.f;
+ }
+
+ return dist;
+}
+
+F32 LLSpatialPartition::calcPixelArea(LLSpatialGroup* group, LLCamera& camera)
+{
+ return LLPipeline::calcPixelArea(group->mObjectBounds[0], group->mObjectBounds[1], camera);
+}
+
+F32 LLSpatialGroup::getUpdateUrgency() const
+{
+ if (!isVisible())
+ {
+ return 0.f;
+ }
+ else
+ {
+ F32 time = gFrameTimeSeconds-mLastUpdateTime+4.f;
+ return time + (mObjectBounds[1].dot3(mObjectBounds[1]).getF32()+1.f)/mDistance;
+ }
+}
+
+BOOL LLSpatialGroup::needsUpdate()
+{
+ return (LLDrawable::getCurrentFrame()%mSpatialPartition->mLODPeriod == mLODHash) ? TRUE : FALSE;
+}
+
+BOOL LLSpatialGroup::changeLOD()
+{
+ if (isState(ALPHA_DIRTY | OBJECT_DIRTY))
+ { ///a rebuild is going to happen, update distance and LoD
+ return TRUE;
+ }
+
+ if (mSpatialPartition->mSlopRatio > 0.f)
+ {
+ F32 ratio = (mDistance - mLastUpdateDistance)/(llmax(mLastUpdateDistance, mRadius));
+
+ if (fabsf(ratio) >= mSpatialPartition->mSlopRatio)
+ {
+ return TRUE;
+ }
+
+ if (mDistance > mRadius*2.f)
+ {
+ return FALSE;
+ }
+ }
+
+ if (needsUpdate())
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void LLSpatialGroup::handleInsertion(const TreeNode* node, LLDrawable* drawablep)
+{
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+ addObject(drawablep, FALSE, TRUE);
+ unbound();
+ setState(OBJECT_DIRTY);
+}
+
+void LLSpatialGroup::handleRemoval(const TreeNode* node, LLDrawable* drawable)
+{
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+ removeObject(drawable, TRUE);
+ setState(OBJECT_DIRTY);
+}
+
+void LLSpatialGroup::handleDestruction(const TreeNode* node)
+{
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+ setState(DEAD);
+
+ for (element_iter i = getData().begin(); i != getData().end(); ++i)
+ {
+ LLDrawable* drawable = *i;
+ if (drawable->getSpatialGroup() == this)
+ {
+ drawable->setSpatialGroup(NULL);
+ }
+ }
+
+ //clean up avatar attachment stats
+ LLSpatialBridge* bridge = mSpatialPartition->asBridge();
+ if (bridge)
+ {
+ if (bridge->mAvatar.notNull())
+ {
+ bridge->mAvatar->mAttachmentGeometryBytes -= mGeometryBytes;
+ bridge->mAvatar->mAttachmentSurfaceArea -= mSurfaceArea;
+ }
+ }
+
+ clearDrawMap();
+ mVertexBuffer = NULL;
+ mBufferMap.clear();
+ sZombieGroups++;
+ mOctreeNode = NULL;
+}
+
+void LLSpatialGroup::handleStateChange(const TreeNode* node)
+{
+ //drop bounding box upon state change
+ if (mOctreeNode != node)
+ {
+ mOctreeNode = (OctreeNode*) node;
+ }
+ unbound();
+}
+
+void LLSpatialGroup::handleChildAddition(const OctreeNode* parent, OctreeNode* child)
+{
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+ if (child->getListenerCount() == 0)
+ {
+ new LLSpatialGroup(child, mSpatialPartition);
+ }
+ else
+ {
+ OCT_ERRS << "LLSpatialGroup redundancy detected." << llendl;
+ }
+
+ unbound();
+
+ assert_states_valid(this);
+}
+
+void LLSpatialGroup::handleChildRemoval(const OctreeNode* parent, const OctreeNode* child)
+{
+ unbound();
+}
+
+void LLSpatialGroup::destroyGL()
+{
+ setState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::IMAGE_DIRTY);
+ gPipeline.markRebuild(this, TRUE);
+
+ mLastUpdateTime = gFrameTimeSeconds;
+ mVertexBuffer = NULL;
+ mBufferMap.clear();
+
+ clearDrawMap();
+
+ for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
+ {
+ if (mOcclusionQuery[i])
+ {
+ sQueryPool.release(mOcclusionQuery[i]);
+ mOcclusionQuery[i] = 0;
+ }
+ }
+
+ mOcclusionVerts = NULL;
+
+ for (LLSpatialGroup::element_iter i = getData().begin(); i != getData().end(); ++i)
+ {
+ LLDrawable* drawable = *i;
+ for (S32 j = 0; j < drawable->getNumFaces(); j++)
+ {
+ LLFace* facep = drawable->getFace(j);
+ facep->clearVertexBuffer();
+ }
+ }
+}
+
+BOOL LLSpatialGroup::rebound()
+{
+ if (!isState(DIRTY))
+ { //return TRUE if we're not empty
+ return TRUE;
+ }
+
+ if (mOctreeNode->getChildCount() == 1 && mOctreeNode->getElementCount() == 0)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) mOctreeNode->getChild(0)->getListener(0);
+ group->rebound();
+
+ //copy single child's bounding box
+ mBounds[0] = group->mBounds[0];
+ mBounds[1] = group->mBounds[1];
+ mExtents[0] = group->mExtents[0];
+ mExtents[1] = group->mExtents[1];
+
+ group->setState(SKIP_FRUSTUM_CHECK);
+ }
+ else if (mOctreeNode->isLeaf())
+ { //copy object bounding box if this is a leaf
+ boundObjects(TRUE, mExtents[0], mExtents[1]);
+ mBounds[0] = mObjectBounds[0];
+ mBounds[1] = mObjectBounds[1];
+ }
+ else
+ {
+ LLVector4a& newMin = mExtents[0];
+ LLVector4a& newMax = mExtents[1];
+ LLSpatialGroup* group = (LLSpatialGroup*) mOctreeNode->getChild(0)->getListener(0);
+ group->clearState(SKIP_FRUSTUM_CHECK);
+ group->rebound();
+ //initialize to first child
+ newMin = group->mExtents[0];
+ newMax = group->mExtents[1];
+
+ //first, rebound children
+ for (U32 i = 1; i < mOctreeNode->getChildCount(); i++)
+ {
+ group = (LLSpatialGroup*) mOctreeNode->getChild(i)->getListener(0);
+ group->clearState(SKIP_FRUSTUM_CHECK);
+ group->rebound();
+ const LLVector4a& max = group->mExtents[1];
+ const LLVector4a& min = group->mExtents[0];
+
+ newMax.setMax(newMax, max);
+ newMin.setMin(newMin, min);
+ }
+
+ boundObjects(FALSE, newMin, newMax);
+
+ mBounds[0].setAdd(newMin, newMax);
+ mBounds[0].mul(0.5f);
+ mBounds[1].setSub(newMax, newMin);
+ 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");
+
+void LLSpatialGroup::checkOcclusion()
+{
+ if (LLPipeline::sUseOcclusion > 1)
+ {
+ LLFastTimer t(FTM_OCCLUSION_READBACK);
+ LLSpatialGroup* parent = getParent();
+ if (parent && parent->isOcclusionState(LLSpatialGroup::OCCLUDED))
+ { //if the parent has been marked as occluded, the child is implicitly occluded
+ clearOcclusionState(QUERY_PENDING | DISCARD_QUERY);
+ }
+ else if (isOcclusionState(QUERY_PENDING))
+ { //otherwise, if a query is pending, read it back
+
+ GLuint available = 0;
+ if (mOcclusionQuery[LLViewerCamera::sCurCameraID])
+ {
+ glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available);
+
+ if (mOcclusionIssued[LLViewerCamera::sCurCameraID] < gFrameCount)
+ { //query was issued last frame, wait until it's available
+ S32 max_loop = 1024;
+ LLFastTimer t(FTM_OCCLUSION_WAIT);
+ while (!available && max_loop-- > 0)
+ {
+ F32 max_time = llmin(gFrameIntervalSeconds*10.f, 1.f);
+ //do some usefu 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
+
+ glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available);
+ }
+ }
+ }
+ else
+ {
+ available = 1;
+ }
+
+ if (available)
+ { //result is available, read it back, otherwise wait until next frame
+ GLuint res = 1;
+ if (!isOcclusionState(DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID])
+ {
+ glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_ARB, &res);
+#if LL_TRACK_PENDING_OCCLUSION_QUERIES
+ sPendingQueries.erase(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+#endif
+ }
+ else if (mOcclusionQuery[LLViewerCamera::sCurCameraID])
+ { //delete the query to avoid holding onto hundreds of pending queries
+ sQueryPool.release(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+ mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0;
+ }
+
+ if (isOcclusionState(DISCARD_QUERY))
+ {
+ res = 2;
+ }
+
+ if (res > 0)
+ {
+ assert_states_valid(this);
+ clearOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
+ assert_states_valid(this);
+ }
+ else
+ {
+ assert_states_valid(this);
+ setOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
+ assert_states_valid(this);
+ }
+
+ clearOcclusionState(QUERY_PENDING | DISCARD_QUERY);
+ }
+ }
+ else if (mSpatialPartition->isOcclusionEnabled() && isOcclusionState(LLSpatialGroup::OCCLUDED))
+ { //check occlusion has been issued for occluded node that has not had a query issued
+ assert_states_valid(this);
+ clearOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
+ assert_states_valid(this);
+ }
+ }
+}
+
+static LLFastTimer::DeclareTimer FTM_PUSH_OCCLUSION_VERTS("Push Occlusion");
+static LLFastTimer::DeclareTimer FTM_SET_OCCLUSION_STATE("Occlusion State");
+static LLFastTimer::DeclareTimer FTM_OCCLUSION_EARLY_FAIL("Occlusion Early Fail");
+static LLFastTimer::DeclareTimer FTM_OCCLUSION_ALLOCATE("Allocate");
+static LLFastTimer::DeclareTimer FTM_OCCLUSION_BUILD("Build");
+static LLFastTimer::DeclareTimer FTM_OCCLUSION_BEGIN_QUERY("Begin Query");
+static LLFastTimer::DeclareTimer FTM_OCCLUSION_END_QUERY("End Query");
+static LLFastTimer::DeclareTimer FTM_OCCLUSION_SET_BUFFER("Set Buffer");
+static LLFastTimer::DeclareTimer FTM_OCCLUSION_DRAW_WATER("Draw Water");
+static LLFastTimer::DeclareTimer FTM_OCCLUSION_DRAW("Draw");
+
+
+
+void LLSpatialGroup::doOcclusion(LLCamera* camera)
+{
+ if (mSpatialPartition->isOcclusionEnabled() && LLPipeline::sUseOcclusion > 1)
+ {
+ // Don't cull hole/edge water, unless we have the GL_ARB_depth_clamp extension
+ if (earlyFail(camera, this))
+ {
+ LLFastTimer t(FTM_OCCLUSION_EARLY_FAIL);
+ setOcclusionState(LLSpatialGroup::DISCARD_QUERY);
+ assert_states_valid(this);
+ clearOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
+ assert_states_valid(this);
+ }
+ else
+ {
+ if (!isOcclusionState(QUERY_PENDING) || isOcclusionState(DISCARD_QUERY))
+ {
+ { //no query pending, or previous query to be discarded
+ LLFastTimer t(FTM_RENDER_OCCLUSION);
+
+ if (!mOcclusionQuery[LLViewerCamera::sCurCameraID])
+ {
+ LLFastTimer t(FTM_OCCLUSION_ALLOCATE);
+ 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.
+ bool const use_depth_clamp = gGLManager.mHasDepthClamp &&
+ (mSpatialPartition->mDrawableType == LLDrawPool::POOL_WATER ||
+ mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER);
+
+ LLGLEnable clamp(use_depth_clamp ? GL_DEPTH_CLAMP : 0);
+
+#if !LL_DARWIN
+ U32 mode = gGLManager.mHasOcclusionQuery2 ? GL_ANY_SAMPLES_PASSED : GL_SAMPLES_PASSED_ARB;
+#else
+ U32 mode = GL_SAMPLES_PASSED_ARB;
+#endif
+
+#if LL_TRACK_PENDING_OCCLUSION_QUERIES
+ sPendingQueries.insert(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+#endif
+
+ {
+ LLFastTimer t(FTM_PUSH_OCCLUSION_VERTS);
+
+ //store which frame this query was issued on
+ mOcclusionIssued[LLViewerCamera::sCurCameraID] = gFrameCount;
+
+ {
+ LLFastTimer t(FTM_OCCLUSION_BEGIN_QUERY);
+ glBeginQueryARB(mode, mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+ }
+
+ {
+ LLFastTimer t(FTM_OCCLUSION_SET_BUFFER);
+ mOcclusionVerts->setBuffer(LLVertexBuffer::MAP_VERTEX);
+ }
+
+ if (!use_depth_clamp && mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER)
+ {
+ LLFastTimer t(FTM_OCCLUSION_DRAW_WATER);
+
+ 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);
+ }
+ else
+ {
+ mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0]));
+ }
+ }
+ else
+ {
+ 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);
+ }
+ else
+ {
+ mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0]));
+ }
+ }
+
+
+ {
+ LLFastTimer t(FTM_OCCLUSION_END_QUERY);
+ glEndQueryARB(mode);
+ }
+ }
+ }
+
+ {
+ LLFastTimer t(FTM_SET_OCCLUSION_STATE);
+ setOcclusionState(LLSpatialGroup::QUERY_PENDING);
+ clearOcclusionState(LLSpatialGroup::DISCARD_QUERY);
+ }
+ }
+ }
+ }
+}
+
+//==============================================
+
+LLSpatialPartition::LLSpatialPartition(U32 data_mask, BOOL render_by_group, U32 buffer_usage)
+: mRenderByGroup(render_by_group), mBridge(NULL)
+{
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+ mOcclusionEnabled = TRUE;
+ mDrawableType = 0;
+ mPartitionType = LLViewerRegion::PARTITION_NONE;
+ mLODSeed = 0;
+ mLODPeriod = 1;
+ mVertexDataMask = data_mask;
+ mBufferUsage = buffer_usage;
+ mDepthMask = FALSE;
+ mSlopRatio = 0.25f;
+ mInfiniteFarClip = FALSE;
+
+ LLVector4a center, size;
+ center.splat(0.f);
+ size.splat(1.f);
+
+ mOctree = new LLSpatialGroup::OctreeRoot(center,size,
+ NULL);
+ new LLSpatialGroup(mOctree, this);
+}
+
+
+LLSpatialPartition::~LLSpatialPartition()
+{
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+
+ delete mOctree;
+ mOctree = NULL;
+}
+
+
+LLSpatialGroup *LLSpatialPartition::put(LLDrawable *drawablep, BOOL was_visible)
+{
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+
+ drawablep->updateSpatialExtents();
+
+ //keep drawable from being garbage collected
+ LLPointer<LLDrawable> ptr = drawablep;
+
+ assert_octree_valid(mOctree);
+ mOctree->insert(drawablep);
+ assert_octree_valid(mOctree);
+
+ LLSpatialGroup* group = drawablep->getSpatialGroup();
+
+ if (group && was_visible && group->isOcclusionState(LLSpatialGroup::QUERY_PENDING))
+ {
+ group->setOcclusionState(LLSpatialGroup::DISCARD_QUERY, LLSpatialGroup::STATE_MODE_ALL_CAMERAS);
+ }
+
+ return group;
+}
+
+BOOL LLSpatialPartition::remove(LLDrawable *drawablep, LLSpatialGroup *curp)
+{
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+
+ drawablep->setSpatialGroup(NULL);
+
+ if (!curp->removeObject(drawablep))
+ {
+ OCT_ERRS << "Failed to remove drawable from octree!" << llendl;
+ }
+
+ assert_octree_valid(mOctree);
+
+ return TRUE;
+}
+
+void LLSpatialPartition::move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL immediate)
+{
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+
+ // sanity check submitted by open source user bushing Spatula
+ // who was seeing crashing here. (See VWR-424 reported by Bunny Mayne)
+ if (!drawablep)
+ {
+ OCT_ERRS << "LLSpatialPartition::move was passed a bad drawable." << llendl;
+ return;
+ }
+
+ BOOL was_visible = curp ? curp->isVisible() : FALSE;
+
+ if (curp && curp->mSpatialPartition != this)
+ {
+ //keep drawable from being garbage collected
+ LLPointer<LLDrawable> ptr = drawablep;
+ if (curp->mSpatialPartition->remove(drawablep, curp))
+ {
+ put(drawablep, was_visible);
+ return;
+ }
+ else
+ {
+ OCT_ERRS << "Drawable lost between spatial partitions on outbound transition." << llendl;
+ }
+ }
+
+ if (curp && curp->updateInGroup(drawablep, immediate))
+ {
+ // Already updated, don't need to do anything
+ assert_octree_valid(mOctree);
+ return;
+ }
+
+ //keep drawable from being garbage collected
+ LLPointer<LLDrawable> ptr = drawablep;
+ if (curp && !remove(drawablep, curp))
+ {
+ OCT_ERRS << "Move couldn't find existing spatial group!" << llendl;
+ }
+
+ put(drawablep, was_visible);
+}
+
+class LLSpatialShift : public LLSpatialGroup::OctreeTraveler
+{
+public:
+ const LLVector4a& mOffset;
+
+ LLSpatialShift(const LLVector4a& offset) : mOffset(offset) { }
+ virtual void visit(const LLSpatialGroup::OctreeNode* branch)
+ {
+ ((LLSpatialGroup*) branch->getListener(0))->shift(mOffset);
+ }
+};
+
+void LLSpatialPartition::shift(const LLVector4a &offset)
+{ //shift octree node bounding boxes by offset
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+ LLSpatialShift shifter(offset);
+ shifter.traverse(mOctree);
+}
+
+class LLOctreeCull : public LLSpatialGroup::OctreeTraveler
+{
+public:
+ LLOctreeCull(LLCamera* camera)
+ : mCamera(camera), mRes(0) { }
+
+ virtual bool earlyFail(LLSpatialGroup* group)
+ {
+ group->checkOcclusion();
+
+ if (group->mOctreeNode->getParent() && //never occlusion cull the root node
+ LLPipeline::sUseOcclusion && //ignore occlusion if disabled
+ group->isOcclusionState(LLSpatialGroup::OCCLUDED))
+ {
+ gPipeline.markOccluder(group);
+ return true;
+ }
+
+ return false;
+ }
+
+ virtual void traverse(const LLSpatialGroup::OctreeNode* n)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
+
+ if (earlyFail(group))
+ {
+ return;
+ }
+
+ if (mRes == 2 ||
+ (mRes && group->isState(LLSpatialGroup::SKIP_FRUSTUM_CHECK)))
+ { //fully in, just add everything
+ LLSpatialGroup::OctreeTraveler::traverse(n);
+ }
+ else
+ {
+ mRes = frustumCheck(group);
+
+ if (mRes)
+ { //at least partially in, run on down
+ LLSpatialGroup::OctreeTraveler::traverse(n);
+ }
+
+ mRes = 0;
+ }
+ }
+
+ virtual S32 frustumCheck(const LLSpatialGroup* group)
+ {
+ S32 res = mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]);
+ if (res != 0)
+ {
+ res = llmin(res, AABBSphereIntersect(group->mExtents[0], group->mExtents[1], mCamera->getOrigin(), mCamera->mFrustumCornerDist));
+ }
+ return res;
+ }
+
+ virtual S32 frustumCheckObjects(const LLSpatialGroup* group)
+ {
+ S32 res = mCamera->AABBInFrustumNoFarClip(group->mObjectBounds[0], group->mObjectBounds[1]);
+ if (res != 0)
+ {
+ res = llmin(res, AABBSphereIntersect(group->mObjectExtents[0], group->mObjectExtents[1], mCamera->getOrigin(), mCamera->mFrustumCornerDist));
+ }
+ return res;
+ }
+
+ virtual bool checkObjects(const LLSpatialGroup::OctreeNode* branch, const LLSpatialGroup* group)
+ {
+ if (branch->getElementCount() == 0) //no elements
+ {
+ return false;
+ }
+ else if (branch->getChildCount() == 0) //leaf state, already checked tightest bounding box
+ {
+ return true;
+ }
+ else if (mRes == 1 && !frustumCheckObjects(group)) //no objects in frustum
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ virtual void preprocess(LLSpatialGroup* group)
+ {
+
+ }
+
+ virtual void processGroup(LLSpatialGroup* group)
+ {
+ if (group->needsUpdate() ||
+ group->mVisible[LLViewerCamera::sCurCameraID] < LLDrawable::getCurrentFrame() - 1)
+ {
+ group->doOcclusion(mCamera);
+ }
+ gPipeline.markNotCulled(group, *mCamera);
+ }
+
+ virtual void visit(const LLSpatialGroup::OctreeNode* branch)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) branch->getListener(0);
+
+ preprocess(group);
+
+ if (checkObjects(branch, group))
+ {
+ processGroup(group);
+ }
+ }
+
+ LLCamera *mCamera;
+ S32 mRes;
+};
+
+class LLOctreeCullNoFarClip : public LLOctreeCull
+{
+public:
+ LLOctreeCullNoFarClip(LLCamera* camera)
+ : LLOctreeCull(camera) { }
+
+ virtual S32 frustumCheck(const LLSpatialGroup* group)
+ {
+ return mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]);
+ }
+
+ virtual S32 frustumCheckObjects(const LLSpatialGroup* group)
+ {
+ S32 res = mCamera->AABBInFrustumNoFarClip(group->mObjectBounds[0], group->mObjectBounds[1]);
+ return res;
+ }
+};
+
+class LLOctreeCullShadow : public LLOctreeCull
+{
+public:
+ LLOctreeCullShadow(LLCamera* camera)
+ : LLOctreeCull(camera) { }
+
+ virtual S32 frustumCheck(const LLSpatialGroup* group)
+ {
+ return mCamera->AABBInFrustum(group->mBounds[0], group->mBounds[1]);
+ }
+
+ virtual S32 frustumCheckObjects(const LLSpatialGroup* group)
+ {
+ return mCamera->AABBInFrustum(group->mObjectBounds[0], group->mObjectBounds[1]);
+ }
+};
+
+class LLOctreeCullVisExtents: public LLOctreeCullShadow
+{
+public:
+ LLOctreeCullVisExtents(LLCamera* camera, LLVector4a& min, LLVector4a& max)
+ : LLOctreeCullShadow(camera), mMin(min), mMax(max), mEmpty(TRUE) { }
+
+ virtual bool earlyFail(LLSpatialGroup* group)
+ {
+ if (group->mOctreeNode->getParent() && //never occlusion cull the root node
+ LLPipeline::sUseOcclusion && //ignore occlusion if disabled
+ group->isOcclusionState(LLSpatialGroup::OCCLUDED))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ virtual void traverse(const LLSpatialGroup::OctreeNode* n)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
+
+ if (earlyFail(group))
+ {
+ return;
+ }
+
+ if ((mRes && group->isState(LLSpatialGroup::SKIP_FRUSTUM_CHECK)) ||
+ mRes == 2)
+ { //don't need to do frustum check
+ LLSpatialGroup::OctreeTraveler::traverse(n);
+ }
+ else
+ {
+ mRes = frustumCheck(group);
+
+ if (mRes)
+ { //at least partially in, run on down
+ LLSpatialGroup::OctreeTraveler::traverse(n);
+ }
+
+ mRes = 0;
+ }
+ }
+
+ virtual void processGroup(LLSpatialGroup* group)
+ {
+ llassert(!group->isState(LLSpatialGroup::DIRTY) && !group->getData().empty())
+
+ if (mRes < 2)
+ {
+ if (mCamera->AABBInFrustum(group->mObjectBounds[0], group->mObjectBounds[1]) > 0)
+ {
+ mEmpty = FALSE;
+ update_min_max(mMin, mMax, group->mObjectExtents[0]);
+ update_min_max(mMin, mMax, group->mObjectExtents[1]);
+ }
+ }
+ else
+ {
+ mEmpty = FALSE;
+ update_min_max(mMin, mMax, group->mExtents[0]);
+ update_min_max(mMin, mMax, group->mExtents[1]);
+ }
+ }
+
+ BOOL mEmpty;
+ LLVector4a& mMin;
+ LLVector4a& mMax;
+};
+
+class LLOctreeCullDetectVisible: public LLOctreeCullShadow
+{
+public:
+ LLOctreeCullDetectVisible(LLCamera* camera)
+ : LLOctreeCullShadow(camera), mResult(FALSE) { }
+
+ virtual bool earlyFail(LLSpatialGroup* group)
+ {
+ if (mResult || //already found a node, don't check any more
+ (group->mOctreeNode->getParent() && //never occlusion cull the root node
+ LLPipeline::sUseOcclusion && //ignore occlusion if disabled
+ group->isOcclusionState(LLSpatialGroup::OCCLUDED)))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ virtual void processGroup(LLSpatialGroup* group)
+ {
+ if (group->isVisible())
+ {
+ mResult = TRUE;
+ }
+ }
+
+ BOOL mResult;
+};
+
+class LLOctreeSelect : public LLOctreeCull
+{
+public:
+ LLOctreeSelect(LLCamera* camera, std::vector<LLDrawable*>* results)
+ : LLOctreeCull(camera), mResults(results) { }
+
+ virtual bool earlyFail(LLSpatialGroup* group) { return false; }
+ virtual void preprocess(LLSpatialGroup* group) { }
+
+ virtual void processGroup(LLSpatialGroup* group)
+ {
+ LLSpatialGroup::OctreeNode* branch = group->mOctreeNode;
+
+ for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i)
+ {
+ LLDrawable* drawable = *i;
+
+ if (!drawable->isDead())
+ {
+ if (drawable->isSpatialBridge())
+ {
+ drawable->setVisible(*mCamera, mResults, TRUE);
+ }
+ else
+ {
+ mResults->push_back(drawable);
+ }
+ }
+ }
+ }
+
+ std::vector<LLDrawable*>* mResults;
+};
+
+void drawBox(const LLVector3& c, const LLVector3& r)
+{
+ LLVertexBuffer::unbind();
+
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ //left front
+ gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,-1))).mV);
+ gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,1))).mV);
+ //right front
+ gGL.vertex3fv((c+r.scaledVec(LLVector3(1,1,-1))).mV);
+ gGL.vertex3fv((c+r.scaledVec(LLVector3(1,1,1))).mV);
+ //right back
+ gGL.vertex3fv((c+r.scaledVec(LLVector3(1,-1,-1))).mV);
+ gGL.vertex3fv((c+r.scaledVec(LLVector3(1,-1,1))).mV);
+ //left back
+ gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,-1,-1))).mV);
+ gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,-1,1))).mV);
+ //left front
+ gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,-1))).mV);
+ gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,1))).mV);
+ gGL.end();
+
+ //bottom
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.vertex3fv((c+r.scaledVec(LLVector3(1,1,-1))).mV);
+ gGL.vertex3fv((c+r.scaledVec(LLVector3(1,-1,-1))).mV);
+ gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,-1))).mV);
+ gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,-1,-1))).mV);
+ gGL.end();
+
+ //top
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.vertex3fv((c+r.scaledVec(LLVector3(1,1,1))).mV);
+ gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,1))).mV);
+ gGL.vertex3fv((c+r.scaledVec(LLVector3(1,-1,1))).mV);
+ gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,-1,1))).mV);
+ gGL.end();
+}
+
+void drawBox(const LLVector4a& c, const LLVector4a& r)
+{
+ drawBox(reinterpret_cast<const LLVector3&>(c), reinterpret_cast<const LLVector3&>(r));
+}
+
+void drawBoxOutline(const LLVector3& pos, const LLVector3& size)
+{
+ LLVector3 v1 = size.scaledVec(LLVector3( 1, 1,1));
+ LLVector3 v2 = size.scaledVec(LLVector3(-1, 1,1));
+ LLVector3 v3 = size.scaledVec(LLVector3(-1,-1,1));
+ LLVector3 v4 = size.scaledVec(LLVector3( 1,-1,1));
+
+ gGL.begin(LLRender::LINES);
+
+ //top
+ gGL.vertex3fv((pos+v1).mV);
+ gGL.vertex3fv((pos+v2).mV);
+ gGL.vertex3fv((pos+v2).mV);
+ gGL.vertex3fv((pos+v3).mV);
+ gGL.vertex3fv((pos+v3).mV);
+ gGL.vertex3fv((pos+v4).mV);
+ gGL.vertex3fv((pos+v4).mV);
+ gGL.vertex3fv((pos+v1).mV);
+
+ //bottom
+ gGL.vertex3fv((pos-v1).mV);
+ gGL.vertex3fv((pos-v2).mV);
+ gGL.vertex3fv((pos-v2).mV);
+ gGL.vertex3fv((pos-v3).mV);
+ gGL.vertex3fv((pos-v3).mV);
+ gGL.vertex3fv((pos-v4).mV);
+ gGL.vertex3fv((pos-v4).mV);
+ gGL.vertex3fv((pos-v1).mV);
+
+ //right
+ gGL.vertex3fv((pos+v1).mV);
+ gGL.vertex3fv((pos-v3).mV);
+
+ gGL.vertex3fv((pos+v4).mV);
+ gGL.vertex3fv((pos-v2).mV);
+
+ //left
+ gGL.vertex3fv((pos+v2).mV);
+ gGL.vertex3fv((pos-v4).mV);
+
+ gGL.vertex3fv((pos+v3).mV);
+ gGL.vertex3fv((pos-v1).mV);
+
+ gGL.end();
+}
+
+void drawBoxOutline(const LLVector4a& pos, const LLVector4a& size)
+{
+ drawBoxOutline(reinterpret_cast<const LLVector3&>(pos), reinterpret_cast<const LLVector3&>(size));
+}
+
+class LLOctreeDirty : public LLOctreeTraveler<LLDrawable>
+{
+public:
+ virtual void visit(const LLOctreeNode<LLDrawable>* state)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) state->getListener(0);
+ group->destroyGL();
+
+ for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
+ {
+ LLDrawable* drawable = *i;
+ if (drawable->getVObj().notNull() && !group->mSpatialPartition->mRenderByGroup)
+ {
+ gPipeline.markRebuild(drawable, LLDrawable::REBUILD_ALL, TRUE);
+ }
+ }
+
+ for (LLSpatialGroup::bridge_list_t::iterator i = group->mBridgeList.begin(); i != group->mBridgeList.end(); ++i)
+ {
+ LLSpatialBridge* bridge = *i;
+ traverse(bridge->mOctree);
+ }
+ }
+};
+
+void LLSpatialPartition::restoreGL()
+{
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+}
+
+void LLSpatialPartition::resetVertexBuffers()
+{
+ LLOctreeDirty dirty;
+ dirty.traverse(mOctree);
+}
+
+BOOL LLSpatialPartition::isOcclusionEnabled()
+{
+ return mOcclusionEnabled || LLPipeline::sUseOcclusion > 2;
+}
+
+BOOL LLSpatialPartition::getVisibleExtents(LLCamera& camera, LLVector3& visMin, LLVector3& visMax)
+{
+ LLVector4a visMina, visMaxa;
+ visMina.load3(visMin.mV);
+ visMaxa.load3(visMax.mV);
+
+ {
+ LLFastTimer ftm(FTM_CULL_REBOUND);
+ LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0);
+ group->rebound();
+ }
+
+ LLOctreeCullVisExtents vis(&camera, visMina, visMaxa);
+ vis.traverse(mOctree);
+
+ visMin.set(visMina.getF32ptr());
+ visMax.set(visMaxa.getF32ptr());
+ return vis.mEmpty;
+}
+
+BOOL LLSpatialPartition::visibleObjectsInFrustum(LLCamera& camera)
+{
+ LLOctreeCullDetectVisible vis(&camera);
+ vis.traverse(mOctree);
+ return vis.mResult;
+}
+
+S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* results, BOOL for_select)
+{
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+#if LL_OCTREE_PARANOIA_CHECK
+ ((LLSpatialGroup*)mOctree->getListener(0))->checkStates();
+#endif
+ {
+ LLFastTimer ftm(FTM_CULL_REBOUND);
+ LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0);
+ group->rebound();
+ }
+
+#if LL_OCTREE_PARANOIA_CHECK
+ ((LLSpatialGroup*)mOctree->getListener(0))->validate();
+#endif
+
+
+ if (for_select)
+ {
+ LLOctreeSelect selecter(&camera, results);
+ selecter.traverse(mOctree);
+ }
+ else if (LLPipeline::sShadowRender)
+ {
+ LLFastTimer ftm(FTM_FRUSTUM_CULL);
+ LLOctreeCullShadow culler(&camera);
+ culler.traverse(mOctree);
+ }
+ else if (mInfiniteFarClip || !LLPipeline::sUseFarClip)
+ {
+ LLFastTimer ftm(FTM_FRUSTUM_CULL);
+ LLOctreeCullNoFarClip culler(&camera);
+ culler.traverse(mOctree);
+ }
+ else
+ {
+ LLFastTimer ftm(FTM_FRUSTUM_CULL);
+ LLOctreeCull culler(&camera);
+ culler.traverse(mOctree);
+ }
+
+ return 0;
+}
+
+BOOL earlyFail(LLCamera* camera, LLSpatialGroup* group)
+{
+ if (camera->getOrigin().isExactlyZero())
+ {
+ return FALSE;
+ }
+
+ const F32 vel = SG_OCCLUSION_FUDGE*2.f;
+ LLVector4a fudge;
+ fudge.splat(vel);
+
+ const LLVector4a& c = group->mBounds[0];
+ LLVector4a r;
+ r.setAdd(group->mBounds[1], fudge);
+
+ /*if (r.magVecSquared() > 1024.0*1024.0)
+ {
+ return TRUE;
+ }*/
+
+ LLVector4a e;
+ e.load3(camera->getOrigin().mV);
+
+ LLVector4a min;
+ min.setSub(c,r);
+ LLVector4a max;
+ max.setAdd(c,r);
+
+ S32 lt = e.lessThan(min).getGatheredBits() & 0x7;
+ if (lt)
+ {
+ return FALSE;
+ }
+
+ S32 gt = e.greaterThan(max).getGatheredBits() & 0x7;
+ if (gt)
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+void pushVerts(LLDrawInfo* params, U32 mask)
+{
+ LLRenderPass::applyModelMatrix(*params);
+ params->mVertexBuffer->setBuffer(mask);
+ params->mVertexBuffer->drawRange(params->mParticle ? LLRender::POINTS : LLRender::TRIANGLES,
+ params->mStart, params->mEnd, params->mCount, params->mOffset);
+}
+
+void pushVerts(LLSpatialGroup* group, U32 mask)
+{
+ LLDrawInfo* params = NULL;
+
+ for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i)
+ {
+ for (LLSpatialGroup::drawmap_elem_t::iterator j = i->second.begin(); j != i->second.end(); ++j)
+ {
+ params = *j;
+ pushVerts(params, mask);
+ }
+ }
+}
+
+void pushVerts(LLFace* face, U32 mask)
+{
+ llassert(face->verify());
+
+ 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);
+ }
+}
+
+void pushVerts(LLDrawable* drawable, U32 mask)
+{
+ for (S32 i = 0; i < drawable->getNumFaces(); ++i)
+ {
+ pushVerts(drawable->getFace(i), mask);
+ }
+}
+
+void pushVerts(LLVolume* volume)
+{
+ LLVertexBuffer::unbind();
+ for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
+ {
+ const LLVolumeFace& face = volume->getVolumeFace(i);
+ LLVertexBuffer::drawElements(LLRender::TRIANGLES, face.mPositions, NULL, face.mNumIndices, face.mIndices);
+ }
+}
+
+void pushBufferVerts(LLVertexBuffer* buffer, U32 mask)
+{
+ if (buffer)
+ {
+ buffer->setBuffer(mask);
+ buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
+ }
+}
+
+void pushBufferVerts(LLSpatialGroup* group, U32 mask)
+{
+ if (group->mSpatialPartition->mRenderByGroup)
+ {
+ if (!group->mDrawMap.empty())
+ {
+ LLDrawInfo* params = *(group->mDrawMap.begin()->second.begin());
+ LLRenderPass::applyModelMatrix(*params);
+
+ pushBufferVerts(group->mVertexBuffer, mask);
+
+ for (LLSpatialGroup::buffer_map_t::iterator i = group->mBufferMap.begin(); i != group->mBufferMap.end(); ++i)
+ {
+ for (LLSpatialGroup::buffer_texture_map_t::iterator j = i->second.begin(); j != i->second.end(); ++j)
+ {
+ for (LLSpatialGroup::buffer_list_t::iterator k = j->second.begin(); k != j->second.end(); ++k)
+ {
+ pushBufferVerts(*k, mask);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ drawBox(group->mBounds[0], group->mBounds[1]);
+ }
+}
+
+void pushVertsColorCoded(LLSpatialGroup* group, U32 mask)
+{
+ LLDrawInfo* params = NULL;
+
+ LLColor4 colors[] = {
+ LLColor4::green,
+ LLColor4::green1,
+ LLColor4::green2,
+ LLColor4::green3,
+ LLColor4::green4,
+ LLColor4::green5,
+ LLColor4::green6
+ };
+
+ static const U32 col_count = LL_ARRAY_SIZE(colors);
+
+ U32 col = 0;
+
+ for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i)
+ {
+ for (LLSpatialGroup::drawmap_elem_t::iterator j = i->second.begin(); j != i->second.end(); ++j)
+ {
+ params = *j;
+ LLRenderPass::applyModelMatrix(*params);
+ gGL.diffuseColor4f(colors[col].mV[0], colors[col].mV[1], colors[col].mV[2], 0.5f);
+ params->mVertexBuffer->setBuffer(mask);
+ params->mVertexBuffer->drawRange(params->mParticle ? LLRender::POINTS : LLRender::TRIANGLES,
+ params->mStart, params->mEnd, params->mCount, params->mOffset);
+ col = (col+1)%col_count;
+ }
+ }
+}
+
+void renderOctree(LLSpatialGroup* group)
+{
+ //render solid object bounding box, color
+ //coded by buffer usage and activity
+ gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA);
+ LLVector4 col;
+ if (group->mBuilt > 0.f)
+ {
+ group->mBuilt -= 2.f * gFrameIntervalSeconds;
+ if (group->mBufferUsage == GL_STATIC_DRAW_ARB)
+ {
+ col.setVec(1.0f, 0, 0, group->mBuilt*0.5f);
+ }
+ else
+ {
+ col.setVec(0.1f,0.1f,1,0.1f);
+ //col.setVec(1.0f, 1.0f, 0, sinf(group->mBuilt*3.14159f)*0.5f);
+ }
+
+ if (group->mBufferUsage != GL_STATIC_DRAW_ARB)
+ {
+ LLGLDepthTest gl_depth(FALSE, FALSE);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+
+ gGL.diffuseColor4f(1,0,0,group->mBuilt);
+ gGL.flush();
+ glLineWidth(5.f);
+ drawBoxOutline(group->mObjectBounds[0], group->mObjectBounds[1]);
+ gGL.flush();
+ glLineWidth(1.f);
+ gGL.flush();
+ for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
+ {
+ LLDrawable* drawable = *i;
+ if (!group->mSpatialPartition->isBridge())
+ {
+ gGL.pushMatrix();
+ LLVector3 trans = drawable->getRegion()->getOriginAgent();
+ gGL.translatef(trans.mV[0], trans.mV[1], trans.mV[2]);
+ }
+
+ for (S32 j = 0; j < drawable->getNumFaces(); j++)
+ {
+ LLFace* face = drawable->getFace(j);
+ if (face->getVertexBuffer())
+ {
+ if (gFrameTimeSeconds - face->mLastUpdateTime < 0.5f)
+ {
+ gGL.diffuseColor4f(0, 1, 0, group->mBuilt);
+ }
+ else if (gFrameTimeSeconds - face->mLastMoveTime < 0.5f)
+ {
+ gGL.diffuseColor4f(1, 0, 0, group->mBuilt);
+ }
+ else
+ {
+ continue;
+ }
+
+ face->getVertexBuffer()->setBuffer(LLVertexBuffer::MAP_VERTEX);
+ //drawBox((face->mExtents[0] + face->mExtents[1])*0.5f,
+ // (face->mExtents[1]-face->mExtents[0])*0.5f);
+ face->getVertexBuffer()->draw(LLRender::TRIANGLES, face->getIndicesCount(), face->getIndicesStart());
+ }
+ }
+
+ if (!group->mSpatialPartition->isBridge())
+ {
+ gGL.popMatrix();
+ }
+ }
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ gGL.diffuseColor4f(1,1,1,1);
+ }
+ }
+ else
+ {
+ if (group->mBufferUsage == GL_STATIC_DRAW_ARB && !group->getData().empty()
+ && group->mSpatialPartition->mRenderByGroup)
+ {
+ col.setVec(0.8f, 0.4f, 0.1f, 0.1f);
+ }
+ else
+ {
+ col.setVec(0.1f, 0.1f, 1.f, 0.1f);
+ }
+ }
+
+ gGL.diffuseColor4fv(col.mV);
+ LLVector4a fudge;
+ fudge.splat(0.001f);
+ LLVector4a size = group->mObjectBounds[1];
+ size.mul(1.01f);
+ size.add(fudge);
+
+ //{
+ // LLGLDepthTest depth(GL_TRUE, GL_FALSE);
+ // drawBox(group->mObjectBounds[0], fudge);
+ //}
+
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+
+ //if (group->mBuilt <= 0.f)
+ {
+ //draw opaque outline
+ //gGL.diffuseColor4f(col.mV[0], col.mV[1], col.mV[2], 1.f);
+ //drawBoxOutline(group->mObjectBounds[0], group->mObjectBounds[1]);
+
+ gGL.diffuseColor4f(0,1,1,1);
+ drawBoxOutline(group->mBounds[0],group->mBounds[1]);
+
+ //draw bounding box for draw info
+ /*if (group->mSpatialPartition->mRenderByGroup)
+ {
+ gGL.diffuseColor4f(1.0f, 0.75f, 0.25f, 0.6f);
+ for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i)
+ {
+ for (LLSpatialGroup::drawmap_elem_t::iterator j = i->second.begin(); j != i->second.end(); ++j)
+ {
+ LLDrawInfo* draw_info = *j;
+ LLVector4a center;
+ center.setAdd(draw_info->mExtents[1], draw_info->mExtents[0]);
+ center.mul(0.5f);
+ LLVector4a size;
+ size.setSub(draw_info->mExtents[1], draw_info->mExtents[0]);
+ size.mul(0.5f);
+ drawBoxOutline(center, size);
+ }
+ }
+ }*/
+ }
+
+// LLSpatialGroup::OctreeNode* node = group->mOctreeNode;
+// gGL.diffuseColor4f(0,1,0,1);
+// drawBoxOutline(LLVector3(node->getCenter()), LLVector3(node->getSize()));
+}
+
+void renderVisibility(LLSpatialGroup* group, LLCamera* camera)
+{
+ LLGLEnable blend(GL_BLEND);
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+ LLGLEnable cull(GL_CULL_FACE);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+
+ BOOL render_objects = (!LLPipeline::sUseOcclusion || !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) && group->isVisible() &&
+ !group->getData().empty();
+
+ if (render_objects)
+ {
+ LLGLDepthTest depth_under(GL_TRUE, GL_FALSE, GL_GREATER);
+ gGL.diffuseColor4f(0, 0.5f, 0, 0.5f);
+ gGL.diffuseColor4f(0, 0.5f, 0, 0.5f);
+ pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX);
+ }
+
+ {
+ LLGLDepthTest depth_over(GL_TRUE, GL_FALSE, GL_LEQUAL);
+
+ if (render_objects)
+ {
+ gGL.diffuseColor4f(0.f, 0.5f, 0.f,1.f);
+ gGL.diffuseColor4f(0.f, 0.5f, 0.f, 1.f);
+ pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX);
+ }
+
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+
+ if (render_objects)
+ {
+ gGL.diffuseColor4f(0.f, 0.75f, 0.f,0.5f);
+ 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);
+ }*/
+ }
+}
+
+void renderCrossHairs(LLVector3 position, F32 size, LLColor4 color)
+{
+ gGL.diffuseColor4fv(color.mV);
+ gGL.begin(LLRender::LINES);
+ {
+ gGL.vertex3fv((position - LLVector3(size, 0.f, 0.f)).mV);
+ gGL.vertex3fv((position + LLVector3(size, 0.f, 0.f)).mV);
+ gGL.vertex3fv((position - LLVector3(0.f, size, 0.f)).mV);
+ gGL.vertex3fv((position + LLVector3(0.f, size, 0.f)).mV);
+ gGL.vertex3fv((position - LLVector3(0.f, 0.f, size)).mV);
+ gGL.vertex3fv((position + LLVector3(0.f, 0.f, size)).mV);
+ }
+ gGL.end();
+}
+
+void renderUpdateType(LLDrawable* drawablep)
+{
+ LLViewerObject* vobj = drawablep->getVObj();
+ if (!vobj || OUT_UNKNOWN == vobj->getLastUpdateType())
+ {
+ return;
+ }
+ LLGLEnable blend(GL_BLEND);
+ switch (vobj->getLastUpdateType())
+ {
+ case OUT_FULL:
+ gGL.diffuseColor4f(0,1,0,0.5f);
+ break;
+ case OUT_TERSE_IMPROVED:
+ gGL.diffuseColor4f(0,1,1,0.5f);
+ break;
+ case OUT_FULL_COMPRESSED:
+ if (vobj->getLastUpdateCached())
+ {
+ gGL.diffuseColor4f(1,0,0,0.5f);
+ }
+ else
+ {
+ gGL.diffuseColor4f(1,1,0,0.5f);
+ }
+ break;
+ case OUT_FULL_CACHED:
+ gGL.diffuseColor4f(0,0,1,0.5f);
+ break;
+ default:
+ llwarns << "Unknown update_type " << vobj->getLastUpdateType() << llendl;
+ break;
+ };
+ S32 num_faces = drawablep->getNumFaces();
+ if (num_faces)
+ {
+ for (S32 i = 0; i < num_faces; ++i)
+ {
+ pushVerts(drawablep->getFace(i), LLVertexBuffer::MAP_VERTEX);
+ }
+ }
+}
+
+void renderComplexityDisplay(LLDrawable* drawablep)
+{
+ LLViewerObject* vobj = drawablep->getVObj();
+ if (!vobj)
+ {
+ return;
+ }
+
+ LLVOVolume *voVol = dynamic_cast<LLVOVolume*>(vobj);
+
+ if (!voVol)
+ {
+ return;
+ }
+
+ if (!voVol->isRoot())
+ {
+ return;
+ }
+
+ LLVOVolume::texture_cost_t textures;
+ F32 cost = (F32) voVol->getRenderCost(textures);
+
+ // add any child volumes
+ LLViewerObject::const_child_list_t children = voVol->getChildren();
+ for (LLViewerObject::const_child_list_t::const_iterator iter = children.begin(); iter != children.end(); ++iter)
+ {
+ const LLViewerObject *child = *iter;
+ const LLVOVolume *child_volume = dynamic_cast<const LLVOVolume*>(child);
+ if (child_volume)
+ {
+ cost += child_volume->getRenderCost(textures);
+ }
+ }
+
+ // add texture cost
+ for (LLVOVolume::texture_cost_t::iterator iter = textures.begin(); iter != textures.end(); ++iter)
+ {
+ // add the cost of each individual texture in the linkset
+ cost += iter->second;
+ }
+
+ F32 cost_max = (F32) LLVOVolume::getRenderComplexityMax();
+
+
+
+ // allow user to set a static color scale
+ if (gSavedSettings.getS32("RenderComplexityStaticMax") > 0)
+ {
+ cost_max = gSavedSettings.getS32("RenderComplexityStaticMax");
+ }
+
+ F32 cost_ratio = cost / cost_max;
+
+ // cap cost ratio at 1.0f in case cost_max is at a low threshold
+ cost_ratio = cost_ratio > 1.0f ? 1.0f : cost_ratio;
+
+ LLGLEnable blend(GL_BLEND);
+
+ LLColor4 color;
+ const LLColor4 color_min = gSavedSettings.getColor4("RenderComplexityColorMin");
+ const LLColor4 color_mid = gSavedSettings.getColor4("RenderComplexityColorMid");
+ const LLColor4 color_max = gSavedSettings.getColor4("RenderComplexityColorMax");
+
+ if (cost_ratio < 0.5f)
+ {
+ color = color_min * (1 - cost_ratio * 2) + color_mid * (cost_ratio * 2);
+ }
+ else
+ {
+ color = color_mid * (1 - (cost_ratio - 0.5) * 2) + color_max * ((cost_ratio - 0.5) * 2);
+ }
+
+ LLSD color_val = color.getValue();
+
+ // don't highlight objects below the threshold
+ if (cost > gSavedSettings.getS32("RenderComplexityThreshold"))
+ {
+ glColor4f(color[0],color[1],color[2],0.5f);
+
+
+ S32 num_faces = drawablep->getNumFaces();
+ if (num_faces)
+ {
+ for (S32 i = 0; i < num_faces; ++i)
+ {
+ pushVerts(drawablep->getFace(i), LLVertexBuffer::MAP_VERTEX);
+ }
+ }
+ LLViewerObject::const_child_list_t children = voVol->getChildren();
+ for (LLViewerObject::const_child_list_t::const_iterator iter = children.begin(); iter != children.end(); ++iter)
+ {
+ const LLViewerObject *child = *iter;
+ if (child)
+ {
+ num_faces = child->getNumFaces();
+ if (num_faces)
+ {
+ for (S32 i = 0; i < num_faces; ++i)
+ {
+ pushVerts(child->mDrawable->getFace(i), LLVertexBuffer::MAP_VERTEX);
+ }
+ }
+ }
+ }
+ }
+
+ voVol->setDebugText(llformat("%4.0f", cost));
+}
+
+void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE)
+{
+ if (set_color)
+ {
+ if (drawable->isSpatialBridge())
+ {
+ gGL.diffuseColor4f(1,0.5f,0,1);
+ }
+ else if (drawable->getVOVolume())
+ {
+ if (drawable->isRoot())
+ {
+ gGL.diffuseColor4f(1,1,0,1);
+ }
+ else
+ {
+ gGL.diffuseColor4f(0,1,0,1);
+ }
+ }
+ else if (drawable->getVObj())
+ {
+ switch (drawable->getVObj()->getPCode())
+ {
+ case LLViewerObject::LL_VO_SURFACE_PATCH:
+ gGL.diffuseColor4f(0,1,1,1);
+ break;
+ case LLViewerObject::LL_VO_CLOUDS:
+ // no longer used
+ break;
+ case LLViewerObject::LL_VO_PART_GROUP:
+ case LLViewerObject::LL_VO_HUD_PART_GROUP:
+ gGL.diffuseColor4f(0,0,1,1);
+ break;
+ case LLViewerObject::LL_VO_VOID_WATER:
+ case LLViewerObject::LL_VO_WATER:
+ gGL.diffuseColor4f(0,0.5f,1,1);
+ break;
+ case LL_PCODE_LEGACY_TREE:
+ gGL.diffuseColor4f(0,0.5f,0,1);
+ break;
+ default:
+ gGL.diffuseColor4f(1,0,1,1);
+ break;
+ }
+ }
+ else
+ {
+ gGL.diffuseColor4f(1,0,0,1);
+ }
+ }
+
+ const LLVector4a* ext;
+ LLVector4a pos, size;
+
+ //render face bounding boxes
+ for (S32 i = 0; i < drawable->getNumFaces(); i++)
+ {
+ LLFace* facep = drawable->getFace(i);
+
+ ext = facep->mExtents;
+
+ pos.setAdd(ext[0], ext[1]);
+ pos.mul(0.5f);
+ size.setSub(ext[1], ext[0]);
+ size.mul(0.5f);
+
+ drawBoxOutline(pos,size);
+ }
+
+ //render drawable bounding box
+ ext = drawable->getSpatialExtents();
+
+ pos.setAdd(ext[0], ext[1]);
+ pos.mul(0.5f);
+ size.setSub(ext[1], ext[0]);
+ size.mul(0.5f);
+
+ LLViewerObject* vobj = drawable->getVObj();
+ if (vobj && vobj->onActiveList())
+ {
+ gGL.flush();
+ glLineWidth(llmax(4.f*sinf(gFrameTimeSeconds*2.f)+1.f, 1.f));
+ //glLineWidth(4.f*(sinf(gFrameTimeSeconds*2.f)*0.25f+0.75f));
+ stop_glerror();
+ drawBoxOutline(pos,size);
+ gGL.flush();
+ glLineWidth(1.f);
+ }
+ else
+ {
+ drawBoxOutline(pos,size);
+ }
+}
+
+void renderNormals(LLDrawable* drawablep)
+{
+ LLVertexBuffer::unbind();
+
+ LLVOVolume* vol = drawablep->getVOVolume();
+ if (vol)
+ {
+ LLVolume* volume = vol->getVolume();
+ gGL.pushMatrix();
+ gGL.multMatrix((F32*) vol->getRelativeXform().mMatrix);
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ LLVector4a scale(gSavedSettings.getF32("RenderDebugNormalScale"));
+
+ for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
+ {
+ const LLVolumeFace& face = volume->getVolumeFace(i);
+
+ for (S32 j = 0; j < face.mNumVertices; ++j)
+ {
+ gGL.begin(LLRender::LINES);
+ LLVector4a n,p;
+
+ n.setMul(face.mNormals[j], scale);
+ p.setAdd(face.mPositions[j], n);
+
+ gGL.diffuseColor4f(1,1,1,1);
+ gGL.vertex3fv(face.mPositions[j].getF32ptr());
+ gGL.vertex3fv(p.getF32ptr());
+
+ if (face.mBinormals)
+ {
+ n.setMul(face.mBinormals[j], scale);
+ p.setAdd(face.mPositions[j], n);
+
+ gGL.diffuseColor4f(0,1,1,1);
+ gGL.vertex3fv(face.mPositions[j].getF32ptr());
+ gGL.vertex3fv(p.getF32ptr());
+ }
+ gGL.end();
+ }
+ }
+
+ gGL.popMatrix();
+ }
+}
+
+S32 get_physics_detail(const LLVolumeParams& volume_params, const LLVector3& scale)
+{
+ const S32 DEFAULT_DETAIL = 1;
+ const F32 LARGE_THRESHOLD = 5.f;
+ const F32 MEGA_THRESHOLD = 25.f;
+
+ S32 detail = DEFAULT_DETAIL;
+ F32 avg_scale = (scale[0]+scale[1]+scale[2])/3.f;
+
+ if (avg_scale > LARGE_THRESHOLD)
+ {
+ detail += 1;
+ if (avg_scale > MEGA_THRESHOLD)
+ {
+ detail += 1;
+ }
+ }
+
+ return detail;
+}
+
+void renderMeshBaseHull(LLVOVolume* volume, U32 data_mask, LLColor4& color, LLColor4& line_color)
+{
+ LLUUID mesh_id = volume->getVolume()->getParams().getSculptID();
+ LLModel::Decomposition* decomp = gMeshRepo.getDecomposition(mesh_id);
+
+ const LLVector3 center(0,0,0);
+ const LLVector3 size(0.25f,0.25f,0.25f);
+
+ if (decomp)
+ {
+ if (!decomp->mBaseHullMesh.empty())
+ {
+ gGL.diffuseColor4fv(color.mV);
+ LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mBaseHullMesh.mPositions, decomp->mBaseHullMesh.mNormals);
+ }
+ else
+ {
+ gMeshRepo.buildPhysicsMesh(*decomp);
+ gGL.diffuseColor4f(0,1,1,1);
+ drawBoxOutline(center, size);
+ }
+
+ }
+ else
+ {
+ gGL.diffuseColor3f(1,0,1);
+ drawBoxOutline(center, size);
+ }
+}
+
+void render_hull(LLModel::PhysicsMesh& mesh, const LLColor4& color, const LLColor4& line_color)
+{
+ gGL.diffuseColor4fv(color.mV);
+ LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions, mesh.mNormals);
+ LLGLEnable offset(GL_POLYGON_OFFSET_LINE);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ glPolygonOffset(3.f, 3.f);
+ glLineWidth(3.f);
+ gGL.diffuseColor4fv(line_color.mV);
+ LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions, mesh.mNormals);
+ glLineWidth(1.f);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+}
+
+void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume)
+{
+ U8 physics_type = volume->getPhysicsShapeType();
+
+ if (physics_type == LLViewerObject::PHYSICS_SHAPE_NONE || volume->isFlexible())
+ {
+ return;
+ }
+
+ //not allowed to return at this point without rendering *something*
+
+ F32 threshold = gSavedSettings.getF32("ObjectCostHighThreshold");
+ F32 cost = volume->getObjectCost();
+
+ LLColor4 low = gSavedSettings.getColor4("ObjectCostLowColor");
+ LLColor4 mid = gSavedSettings.getColor4("ObjectCostMidColor");
+ LLColor4 high = gSavedSettings.getColor4("ObjectCostHighColor");
+
+ F32 normalizedCost = 1.f - exp( -(cost / threshold) );
+
+ LLColor4 color;
+ if ( normalizedCost <= 0.5f )
+ {
+ color = lerp( low, mid, 2.f * normalizedCost );
+ }
+ else
+ {
+ color = lerp( mid, high, 2.f * ( normalizedCost - 0.5f ) );
+ }
+
+ LLColor4 line_color = color*0.5f;
+
+ U32 data_mask = LLVertexBuffer::MAP_VERTEX;
+
+ LLVolumeParams volume_params = volume->getVolume()->getParams();
+
+ LLPhysicsVolumeParams physics_params(volume_params,
+ physics_type == LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL);
+
+ LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification physics_spec;
+ LLPhysicsShapeBuilderUtil::determinePhysicsShape(physics_params, volume->getScale(), physics_spec);
+
+ U32 type = physics_spec.getType();
+
+ LLVector3 center(0,0,0);
+ LLVector3 size(0.25f,0.25f,0.25f);
+
+ gGL.pushMatrix();
+ gGL.multMatrix((F32*) volume->getRelativeXform().mMatrix);
+
+ if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::USER_MESH)
+ {
+ LLUUID mesh_id = volume->getVolume()->getParams().getSculptID();
+ LLModel::Decomposition* decomp = gMeshRepo.getDecomposition(mesh_id);
+
+ if (decomp)
+ { //render a physics based mesh
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ if (!decomp->mHull.empty())
+ { //decomposition exists, use that
+
+ if (decomp->mMesh.empty())
+ {
+ gMeshRepo.buildPhysicsMesh(*decomp);
+ }
+
+ for (U32 i = 0; i < decomp->mMesh.size(); ++i)
+ {
+ render_hull(decomp->mMesh[i], color, line_color);
+ }
+ }
+ else if (!decomp->mPhysicsShapeMesh.empty())
+ {
+ //decomp has physics mesh, render that mesh
+ gGL.diffuseColor4fv(color.mV);
+ LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions, decomp->mPhysicsShapeMesh.mNormals);
+
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ gGL.diffuseColor4fv(line_color.mV);
+ LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions, decomp->mPhysicsShapeMesh.mNormals);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ }
+ else
+ { //no mesh or decomposition, render base hull
+ renderMeshBaseHull(volume, data_mask, color, line_color);
+
+ if (decomp->mPhysicsShapeMesh.empty())
+ {
+ //attempt to fetch physics shape mesh if available
+ gMeshRepo.fetchPhysicsShape(mesh_id);
+ }
+ }
+ }
+ else
+ {
+ gGL.diffuseColor3f(1,1,0);
+ drawBoxOutline(center, size);
+ }
+ }
+ else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::USER_CONVEX ||
+ type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::PRIM_CONVEX)
+ {
+ if (volume->isMesh())
+ {
+ renderMeshBaseHull(volume, data_mask, color, line_color);
+ }
+ else
+ {
+ LLVolumeParams volume_params = volume->getVolume()->getParams();
+ S32 detail = get_physics_detail(volume_params, volume->getScale());
+ LLVolume* phys_volume = LLPrimitive::sVolumeManager->refVolume(volume_params, detail);
+
+ if (!phys_volume->mHullPoints)
+ { //build convex hull
+ std::vector<LLVector3> pos;
+ std::vector<U16> index;
+
+ S32 index_offset = 0;
+
+ for (S32 i = 0; i < phys_volume->getNumVolumeFaces(); ++i)
+ {
+ const LLVolumeFace& face = phys_volume->getVolumeFace(i);
+ if (index_offset + face.mNumVertices > 65535)
+ {
+ continue;
+ }
+
+ for (S32 j = 0; j < face.mNumVertices; ++j)
+ {
+ pos.push_back(LLVector3(face.mPositions[j].getF32ptr()));
+ }
+
+ for (S32 j = 0; j < face.mNumIndices; ++j)
+ {
+ index.push_back(face.mIndices[j]+index_offset);
+ }
+
+ index_offset += face.mNumVertices;
+ }
+
+ if (!pos.empty() && !index.empty())
+ {
+ LLCDMeshData mesh;
+ mesh.mIndexBase = &index[0];
+ mesh.mVertexBase = pos[0].mV;
+ mesh.mNumVertices = pos.size();
+ mesh.mVertexStrideBytes = 12;
+ mesh.mIndexStrideBytes = 6;
+ mesh.mIndexType = LLCDMeshData::INT_16;
+
+ mesh.mNumTriangles = index.size()/3;
+
+ LLCDMeshData res;
+
+ LLConvexDecomposition::getInstance()->generateSingleHullMeshFromMesh( &mesh, &res );
+
+ //copy res into phys_volume
+ phys_volume->mHullPoints = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*res.mNumVertices);
+ phys_volume->mNumHullPoints = res.mNumVertices;
+
+ S32 idx_size = (res.mNumTriangles*3*2+0xF) & ~0xF;
+ phys_volume->mHullIndices = (U16*) ll_aligned_malloc_16(idx_size);
+ phys_volume->mNumHullIndices = res.mNumTriangles*3;
+
+ const F32* v = res.mVertexBase;
+
+ for (S32 i = 0; i < res.mNumVertices; ++i)
+ {
+ F32* p = (F32*) ((U8*)v+i*res.mVertexStrideBytes);
+ phys_volume->mHullPoints[i].load3(p);
+ }
+
+ if (res.mIndexType == LLCDMeshData::INT_16)
+ {
+ for (S32 i = 0; i < res.mNumTriangles; ++i)
+ {
+ U16* idx = (U16*) (((U8*)res.mIndexBase)+i*res.mIndexStrideBytes);
+
+ phys_volume->mHullIndices[i*3+0] = idx[0];
+ phys_volume->mHullIndices[i*3+1] = idx[1];
+ phys_volume->mHullIndices[i*3+2] = idx[2];
+ }
+ }
+ else
+ {
+ for (S32 i = 0; i < res.mNumTriangles; ++i)
+ {
+ U32* idx = (U32*) (((U8*)res.mIndexBase)+i*res.mIndexStrideBytes);
+
+ phys_volume->mHullIndices[i*3+0] = (U16) idx[0];
+ phys_volume->mHullIndices[i*3+1] = (U16) idx[1];
+ phys_volume->mHullIndices[i*3+2] = (U16) idx[2];
+ }
+ }
+ }
+ }
+
+ if (phys_volume->mHullPoints)
+ {
+ //render hull
+
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+
+ gGL.diffuseColor4fv(line_color.mV);
+ LLVertexBuffer::unbind();
+
+ llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShader != 0);
+
+ LLVertexBuffer::drawElements(LLRender::TRIANGLES, phys_volume->mHullPoints, NULL, phys_volume->mNumHullIndices, phys_volume->mHullIndices);
+
+ gGL.diffuseColor4fv(color.mV);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ LLVertexBuffer::drawElements(LLRender::TRIANGLES, phys_volume->mHullPoints, NULL, phys_volume->mNumHullIndices, phys_volume->mHullIndices);
+
+ }
+ else
+ {
+ gGL.diffuseColor4f(1,0,1,1);
+ drawBoxOutline(center, size);
+ }
+
+ LLPrimitive::sVolumeManager->unrefVolume(phys_volume);
+ }
+ }
+ else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::BOX)
+ {
+ LLVector3 center = physics_spec.getCenter();
+ LLVector3 scale = physics_spec.getScale();
+ LLVector3 vscale = volume->getScale()*2.f;
+ scale.set(scale[0]/vscale[0], scale[1]/vscale[1], scale[2]/vscale[2]);
+
+ gGL.diffuseColor4fv(color.mV);
+ drawBox(center, scale);
+ }
+ else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::SPHERE)
+ {
+ /*LLVolumeParams volume_params;
+ volume_params.setType( LL_PCODE_PROFILE_CIRCLE_HALF, LL_PCODE_PATH_CIRCLE );
+ volume_params.setBeginAndEndS( 0.f, 1.f );
+ volume_params.setBeginAndEndT( 0.f, 1.f );
+ volume_params.setRatio ( 1, 1 );
+ volume_params.setShear ( 0, 0 );
+ LLVolume* sphere = LLPrimitive::sVolumeManager->refVolume(volume_params, 3);
+
+ gGL.diffuseColor4fv(color.mV);
+ pushVerts(sphere);
+ LLPrimitive::sVolumeManager->unrefVolume(sphere);*/
+ }
+ else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::CYLINDER)
+ {
+ LLVolumeParams volume_params;
+ volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE );
+ volume_params.setBeginAndEndS( 0.f, 1.f );
+ volume_params.setBeginAndEndT( 0.f, 1.f );
+ volume_params.setRatio ( 1, 1 );
+ volume_params.setShear ( 0, 0 );
+ LLVolume* cylinder = LLPrimitive::sVolumeManager->refVolume(volume_params, 3);
+
+ gGL.diffuseColor4fv(color.mV);
+ pushVerts(cylinder);
+ LLPrimitive::sVolumeManager->unrefVolume(cylinder);
+ }
+ else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::PRIM_MESH)
+ {
+ LLVolumeParams volume_params = volume->getVolume()->getParams();
+ S32 detail = get_physics_detail(volume_params, volume->getScale());
+
+ LLVolume* phys_volume = LLPrimitive::sVolumeManager->refVolume(volume_params, detail);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+
+ gGL.diffuseColor4fv(line_color.mV);
+ pushVerts(phys_volume);
+
+ gGL.diffuseColor4fv(color.mV);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ pushVerts(phys_volume);
+ LLPrimitive::sVolumeManager->unrefVolume(phys_volume);
+ }
+ else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::PRIM_CONVEX)
+ {
+ LLVolumeParams volume_params = volume->getVolume()->getParams();
+ S32 detail = get_physics_detail(volume_params, volume->getScale());
+
+ LLVolume* phys_volume = LLPrimitive::sVolumeManager->refVolume(volume_params, detail);
+
+ if (phys_volume->mHullPoints && phys_volume->mHullIndices)
+ {
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShader != 0);
+ LLVertexBuffer::unbind();
+ glVertexPointer(3, GL_FLOAT, 16, phys_volume->mHullPoints);
+ gGL.diffuseColor4fv(line_color.mV);
+ gGL.syncMatrices();
+ glDrawElements(GL_TRIANGLES, phys_volume->mNumHullIndices, GL_UNSIGNED_SHORT, phys_volume->mHullIndices);
+
+ gGL.diffuseColor4fv(color.mV);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ glDrawElements(GL_TRIANGLES, phys_volume->mNumHullIndices, GL_UNSIGNED_SHORT, phys_volume->mHullIndices);
+ }
+ else
+ {
+ gGL.diffuseColor3f(1,0,1);
+ drawBoxOutline(center, size);
+ gMeshRepo.buildHull(volume_params, detail);
+ }
+ LLPrimitive::sVolumeManager->unrefVolume(phys_volume);
+ }
+ else if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::SCULPT)
+ {
+ //TODO: implement sculpted prim physics display
+ }
+ else
+ {
+ llerrs << "Unhandled type" << llendl;
+ }
+
+ gGL.popMatrix();
+}
+
+void renderPhysicsShapes(LLSpatialGroup* group)
+{
+ for (LLSpatialGroup::OctreeNode::const_element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
+ {
+ LLDrawable* drawable = *i;
+ LLVOVolume* volume = drawable->getVOVolume();
+ if (volume && !volume->isAttachment() && volume->getPhysicsShapeType() != LLViewerObject::PHYSICS_SHAPE_NONE )
+ {
+ if (!group->mSpatialPartition->isBridge())
+ {
+ gGL.pushMatrix();
+ LLVector3 trans = drawable->getRegion()->getOriginAgent();
+ gGL.translatef(trans.mV[0], trans.mV[1], trans.mV[2]);
+ renderPhysicsShape(drawable, volume);
+ gGL.popMatrix();
+ }
+ else
+ {
+ renderPhysicsShape(drawable, volume);
+ }
+ }
+ else
+ {
+ LLViewerObject* object = drawable->getVObj();
+ if (object && object->getPCode() == LLViewerObject::LL_VO_SURFACE_PATCH)
+ {
+ //push face vertices for terrain
+ for (S32 i = 0; i < drawable->getNumFaces(); ++i)
+ {
+ LLFace* face = drawable->getFace(i);
+ 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);
+
+ gGL.diffuseColor3f(0.2f, 1.f, 0.3f);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ buff->draw(LLRender::TRIANGLES, buff->getNumIndices(), 0);
+ }
+ }
+ }
+ }
+ }
+}
+
+void renderTexturePriority(LLDrawable* drawable)
+{
+ for (int face=0; face<drawable->getNumFaces(); ++face)
+ {
+ LLFace *facep = drawable->getFace(face);
+
+ LLVector4 cold(0,0,0.25f);
+ LLVector4 hot(1,0.25f,0.25f);
+
+ LLVector4 boost_cold(0,0,0,0);
+ LLVector4 boost_hot(0,1,0,1);
+
+ LLGLDisable blend(GL_BLEND);
+
+ //LLViewerTexture* imagep = facep->getTexture();
+ //if (imagep)
+ {
+
+ //F32 vsize = imagep->mMaxVirtualSize;
+ F32 vsize = facep->getPixelArea();
+
+ if (vsize > sCurMaxTexPriority)
+ {
+ sCurMaxTexPriority = vsize;
+ }
+
+ F32 t = vsize/sLastMaxTexPriority;
+
+ LLVector4 col = lerp(cold, hot, t);
+ gGL.diffuseColor4fv(col.mV);
+ }
+ //else
+ //{
+ // gGL.diffuseColor4f(1,0,1,1);
+ //}
+
+ LLVector4a center;
+ center.setAdd(facep->mExtents[1],facep->mExtents[0]);
+ center.mul(0.5f);
+ LLVector4a size;
+ size.setSub(facep->mExtents[1],facep->mExtents[0]);
+ size.mul(0.5f);
+ size.add(LLVector4a(0.01f));
+ drawBox(center, size);
+
+ /*S32 boost = imagep->getBoostLevel();
+ if (boost>LLViewerTexture::BOOST_NONE)
+ {
+ F32 t = (F32) boost / (F32) (LLViewerTexture::BOOST_MAX_LEVEL-1);
+ LLVector4 col = lerp(boost_cold, boost_hot, t);
+ LLGLEnable blend_on(GL_BLEND);
+ gGL.blendFunc(GL_SRC_ALPHA, GL_ONE);
+ gGL.diffuseColor4fv(col.mV);
+ drawBox(center, size);
+ gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }*/
+ }
+}
+
+void renderPoints(LLDrawable* drawablep)
+{
+ LLGLDepthTest depth(GL_FALSE, GL_FALSE);
+ if (drawablep->getNumFaces())
+ {
+ gGL.begin(LLRender::POINTS);
+ gGL.diffuseColor3f(1,1,1);
+ for (S32 i = 0; i < drawablep->getNumFaces(); i++)
+ {
+ gGL.vertex3fv(drawablep->getFace(i)->mCenterLocal.mV);
+ }
+ gGL.end();
+ }
+}
+
+void renderTextureAnim(LLDrawInfo* params)
+{
+ if (!params->mTextureMatrix)
+ {
+ return;
+ }
+
+ LLGLEnable blend(GL_BLEND);
+ gGL.diffuseColor4f(1,1,0,0.5f);
+ pushVerts(params, LLVertexBuffer::MAP_VERTEX);
+}
+
+void renderBatchSize(LLDrawInfo* params)
+{
+ LLGLEnable offset(GL_POLYGON_OFFSET_FILL);
+ glPolygonOffset(-1.f, 1.f);
+ gGL.diffuseColor4ubv((GLubyte*) &(params->mDebugColor));
+ pushVerts(params, LLVertexBuffer::MAP_VERTEX);
+}
+
+void renderShadowFrusta(LLDrawInfo* params)
+{
+ LLGLEnable blend(GL_BLEND);
+ gGL.setSceneBlendType(LLRender::BT_ADD);
+
+ LLVector4a center;
+ center.setAdd(params->mExtents[1], params->mExtents[0]);
+ center.mul(0.5f);
+ LLVector4a size;
+ size.setSub(params->mExtents[1],params->mExtents[0]);
+ size.mul(0.5f);
+
+ if (gPipeline.mShadowCamera[4].AABBInFrustum(center, size))
+ {
+ gGL.diffuseColor3f(1,0,0);
+ pushVerts(params, LLVertexBuffer::MAP_VERTEX);
+ }
+ if (gPipeline.mShadowCamera[5].AABBInFrustum(center, size))
+ {
+ gGL.diffuseColor3f(0,1,0);
+ pushVerts(params, LLVertexBuffer::MAP_VERTEX);
+ }
+ if (gPipeline.mShadowCamera[6].AABBInFrustum(center, size))
+ {
+ gGL.diffuseColor3f(0,0,1);
+ pushVerts(params, LLVertexBuffer::MAP_VERTEX);
+ }
+ if (gPipeline.mShadowCamera[7].AABBInFrustum(center, size))
+ {
+ gGL.diffuseColor3f(1,0,1);
+ pushVerts(params, LLVertexBuffer::MAP_VERTEX);
+ }
+
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+}
+
+
+void renderLights(LLDrawable* drawablep)
+{
+ if (!drawablep->isLight())
+ {
+ return;
+ }
+
+ if (drawablep->getNumFaces())
+ {
+ LLGLEnable blend(GL_BLEND);
+ gGL.diffuseColor4f(0,1,1,0.5f);
+
+ for (S32 i = 0; i < drawablep->getNumFaces(); i++)
+ {
+ pushVerts(drawablep->getFace(i), LLVertexBuffer::MAP_VERTEX);
+ }
+
+ const LLVector4a* ext = drawablep->getSpatialExtents();
+
+ LLVector4a pos;
+ pos.setAdd(ext[0], ext[1]);
+ pos.mul(0.5f);
+ LLVector4a size;
+ size.setSub(ext[1], ext[0]);
+ size.mul(0.5f);
+
+ {
+ LLGLDepthTest depth(GL_FALSE, GL_TRUE);
+ gGL.diffuseColor4f(1,1,1,1);
+ drawBoxOutline(pos, size);
+ }
+
+ gGL.diffuseColor4f(1,1,0,1);
+ F32 rad = drawablep->getVOVolume()->getLightRadius();
+ drawBoxOutline(pos, LLVector4a(rad));
+ }
+}
+
+class LLRenderOctreeRaycast : public LLOctreeTriangleRayIntersect
+{
+public:
+
+
+ LLRenderOctreeRaycast(const LLVector4a& start, const LLVector4a& dir, F32* closest_t)
+ : LLOctreeTriangleRayIntersect(start, dir, NULL, closest_t, NULL, NULL, NULL, NULL)
+ {
+
+ }
+
+ void visit(const LLOctreeNode<LLVolumeTriangle>* branch)
+ {
+ LLVolumeOctreeListener* vl = (LLVolumeOctreeListener*) branch->getListener(0);
+
+ LLVector3 center, size;
+
+ if (branch->getData().empty())
+ {
+ gGL.diffuseColor3f(1.f,0.2f,0.f);
+ center.set(branch->getCenter().getF32ptr());
+ size.set(branch->getSize().getF32ptr());
+ }
+ else
+ {
+ gGL.diffuseColor3f(0.75f, 1.f, 0.f);
+ center.set(vl->mBounds[0].getF32ptr());
+ size.set(vl->mBounds[1].getF32ptr());
+ }
+
+ drawBoxOutline(center, size);
+
+ for (U32 i = 0; i < 2; i++)
+ {
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE, i == 1 ? GL_LEQUAL : GL_GREATER);
+
+ if (i == 1)
+ {
+ gGL.diffuseColor4f(0,1,1,0.5f);
+ }
+ else
+ {
+ gGL.diffuseColor4f(0,0.5f,0.5f, 0.25f);
+ drawBoxOutline(center, size);
+ }
+
+ if (i == 1)
+ {
+ gGL.flush();
+ glLineWidth(3.f);
+ }
+
+ gGL.begin(LLRender::TRIANGLES);
+ for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter = branch->getData().begin();
+ iter != branch->getData().end();
+ ++iter)
+ {
+ const LLVolumeTriangle* tri = *iter;
+
+ gGL.vertex3fv(tri->mV[0]->getF32ptr());
+ gGL.vertex3fv(tri->mV[1]->getF32ptr());
+ gGL.vertex3fv(tri->mV[2]->getF32ptr());
+ }
+ gGL.end();
+
+ if (i == 1)
+ {
+ gGL.flush();
+ glLineWidth(1.f);
+ }
+ }
+ }
+};
+
+void renderRaycast(LLDrawable* drawablep)
+{
+ if (drawablep->getNumFaces())
+ {
+ LLGLEnable blend(GL_BLEND);
+ gGL.diffuseColor4f(0,1,1,0.5f);
+
+ if (drawablep->getVOVolume())
+ {
+ //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ //pushVerts(drawablep->getFace(gDebugRaycastFaceHit), LLVertexBuffer::MAP_VERTEX);
+ //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+
+ LLVOVolume* vobj = drawablep->getVOVolume();
+ LLVolume* volume = vobj->getVolume();
+
+ bool transform = true;
+ if (drawablep->isState(LLDrawable::RIGGED))
+ {
+ volume = vobj->getRiggedVolume();
+ transform = false;
+ }
+
+ if (volume)
+ {
+ LLVector3 trans = drawablep->getRegion()->getOriginAgent();
+
+ for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
+ {
+ const LLVolumeFace& face = volume->getVolumeFace(i);
+
+ gGL.pushMatrix();
+ gGL.translatef(trans.mV[0], trans.mV[1], trans.mV[2]);
+ gGL.multMatrix((F32*) vobj->getRelativeXform().mMatrix);
+
+ LLVector3 start, end;
+ if (transform)
+ {
+ start = vobj->agentPositionToVolume(gDebugRaycastStart);
+ end = vobj->agentPositionToVolume(gDebugRaycastEnd);
+ }
+ else
+ {
+ start = gDebugRaycastStart;
+ end = gDebugRaycastEnd;
+ }
+
+ LLVector4a starta, enda;
+ starta.load3(start.mV);
+ enda.load3(end.mV);
+ LLVector4a dir;
+ dir.setSub(enda, starta);
+
+ gGL.flush();
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+
+ {
+ //render face positions
+ LLVertexBuffer::unbind();
+ gGL.diffuseColor4f(0,1,1,0.5f);
+ glVertexPointer(3, GL_FLOAT, sizeof(LLVector4a), face.mPositions);
+ gGL.syncMatrices();
+ glDrawElements(GL_TRIANGLES, face.mNumIndices, GL_UNSIGNED_SHORT, face.mIndices);
+ }
+
+ if (!volume->isUnique())
+ {
+ F32 t = 1.f;
+
+ if (!face.mOctree)
+ {
+ ((LLVolumeFace*) &face)->createOctree();
+ }
+
+ LLRenderOctreeRaycast render(starta, dir, &t);
+
+ render.traverse(face.mOctree);
+ }
+
+ gGL.popMatrix();
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ }
+ }
+ }
+ else if (drawablep->isAvatar())
+ {
+ if (drawablep->getVObj() == gDebugRaycastObject)
+ {
+ LLGLDepthTest depth(GL_FALSE);
+ LLVOAvatar* av = (LLVOAvatar*) drawablep->getVObj().get();
+ av->renderCollisionVolumes();
+ }
+ }
+
+ if (drawablep->getVObj() == gDebugRaycastObject)
+ {
+ // draw intersection point
+ gGL.pushMatrix();
+ gGL.loadMatrix(gGLModelView);
+ LLVector3 translate = gDebugRaycastIntersection;
+ gGL.translatef(translate.mV[0], translate.mV[1], translate.mV[2]);
+ LLCoordFrame orient;
+ orient.lookDir(gDebugRaycastNormal, gDebugRaycastBinormal);
+ LLMatrix4 rotation;
+ orient.getRotMatrixToParent(rotation);
+ gGL.multMatrix((float*)rotation.mMatrix);
+
+ gGL.diffuseColor4f(1,0,0,0.5f);
+ drawBox(LLVector3(0, 0, 0), LLVector3(0.1f, 0.022f, 0.022f));
+ gGL.diffuseColor4f(0,1,0,0.5f);
+ drawBox(LLVector3(0, 0, 0), LLVector3(0.021f, 0.1f, 0.021f));
+ gGL.diffuseColor4f(0,0,1,0.5f);
+ drawBox(LLVector3(0, 0, 0), LLVector3(0.02f, 0.02f, 0.1f));
+ gGL.popMatrix();
+
+ // draw bounding box of prim
+ const LLVector4a* ext = drawablep->getSpatialExtents();
+
+ LLVector4a pos;
+ pos.setAdd(ext[0], ext[1]);
+ pos.mul(0.5f);
+ LLVector4a size;
+ size.setSub(ext[1], ext[0]);
+ size.mul(0.5f);
+
+ LLGLDepthTest depth(GL_FALSE, GL_TRUE);
+ gGL.diffuseColor4f(0,0.5f,0.5f,1);
+ drawBoxOutline(pos, size);
+ }
+ }
+}
+
+
+void renderAvatarCollisionVolumes(LLVOAvatar* avatar)
+{
+ avatar->renderCollisionVolumes();
+}
+
+void renderAgentTarget(LLVOAvatar* avatar)
+{
+ // render these for self only (why, i don't know)
+ if (avatar->isSelf())
+ {
+ renderCrossHairs(avatar->getPositionAgent(), 0.2f, LLColor4(1, 0, 0, 0.8f));
+ renderCrossHairs(avatar->mDrawable->getPositionAgent(), 0.2f, LLColor4(1, 0, 0, 0.8f));
+ renderCrossHairs(avatar->mRoot.getWorldPosition(), 0.2f, LLColor4(1, 1, 1, 0.8f));
+ renderCrossHairs(avatar->mPelvisp->getWorldPosition(), 0.2f, LLColor4(0, 0, 1, 0.8f));
+ }
+}
+
+class LLOctreeRenderNonOccluded : public LLOctreeTraveler<LLDrawable>
+{
+public:
+ LLCamera* mCamera;
+ LLOctreeRenderNonOccluded(LLCamera* camera): mCamera(camera) {}
+
+ virtual void traverse(const LLSpatialGroup::OctreeNode* node)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
+
+ if (!mCamera || mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]))
+ {
+ node->accept(this);
+ stop_glerror();
+
+ for (U32 i = 0; i < node->getChildCount(); i++)
+ {
+ traverse(node->getChild(i));
+ stop_glerror();
+ }
+
+ //draw tight fit bounding boxes for spatial group
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCTREE))
+ {
+ group->rebuildGeom();
+ group->rebuildMesh();
+
+ renderOctree(group);
+ stop_glerror();
+ }
+
+ //render visibility wireframe
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION))
+ {
+ group->rebuildGeom();
+ group->rebuildMesh();
+
+ gGL.flush();
+ gGL.pushMatrix();
+ gGLLastMatrix = NULL;
+ gGL.loadMatrix(gGLModelView);
+ renderVisibility(group, mCamera);
+ stop_glerror();
+ gGLLastMatrix = NULL;
+ gGL.popMatrix();
+ gGL.diffuseColor4f(1,1,1,1);
+ }
+ }
+ }
+
+ virtual void visit(const LLSpatialGroup::OctreeNode* branch)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) branch->getListener(0);
+
+ if (group->isState(LLSpatialGroup::GEOM_DIRTY) || (mCamera && !mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1])))
+ {
+ return;
+ }
+
+ LLVector4a nodeCenter = group->mBounds[0];
+ LLVector4a octCenter = group->mOctreeNode->getCenter();
+
+ group->rebuildGeom();
+ group->rebuildMesh();
+
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BBOXES))
+ {
+ if (!group->getData().empty())
+ {
+ gGL.diffuseColor3f(0,0,1);
+ drawBoxOutline(group->mObjectBounds[0],
+ group->mObjectBounds[1]);
+ }
+ }
+
+ for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i)
+ {
+ LLDrawable* drawable = *i;
+
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BBOXES))
+ {
+ renderBoundingBox(drawable);
+ }
+
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_NORMALS))
+ {
+ renderNormals(drawable);
+ }
+
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BUILD_QUEUE))
+ {
+ if (drawable->isState(LLDrawable::IN_REBUILD_Q2))
+ {
+ gGL.diffuseColor4f(0.6f, 0.6f, 0.1f, 1.f);
+ const LLVector4a* ext = drawable->getSpatialExtents();
+ LLVector4a center;
+ center.setAdd(ext[0], ext[1]);
+ center.mul(0.5f);
+ LLVector4a size;
+ size.setSub(ext[1], ext[0]);
+ size.mul(0.5f);
+ drawBoxOutline(center, size);
+ }
+ }
+
+ if (drawable->getVOVolume() && gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY))
+ {
+ renderTexturePriority(drawable);
+ }
+
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_POINTS))
+ {
+ renderPoints(drawable);
+ }
+
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_LIGHTS))
+ {
+ renderLights(drawable);
+ }
+
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST))
+ {
+ renderRaycast(drawable);
+ }
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_UPDATE_TYPE))
+ {
+ renderUpdateType(drawable);
+ }
+ if(gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RENDER_COMPLEXITY))
+ {
+ renderComplexityDisplay(drawable);
+ }
+
+ LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(drawable->getVObj().get());
+
+ if (avatar && gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_AVATAR_VOLUME))
+ {
+ renderAvatarCollisionVolumes(avatar);
+ }
+
+ if (avatar && gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_AGENT_TARGET))
+ {
+ renderAgentTarget(avatar);
+ }
+
+
+ if (gDebugGL)
+ {
+ for (U32 i = 0; i < drawable->getNumFaces(); ++i)
+ {
+ LLFace* facep = drawable->getFace(i);
+ U8 index = facep->getTextureIndex();
+ if (facep->mDrawInfo)
+ {
+ if (index < 255)
+ {
+ 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;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i)
+ {
+ LLSpatialGroup::drawmap_elem_t& draw_vec = i->second;
+ for (LLSpatialGroup::drawmap_elem_t::iterator j = draw_vec.begin(); j != draw_vec.end(); ++j)
+ {
+ LLDrawInfo* draw_info = *j;
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_ANIM))
+ {
+ renderTextureAnim(draw_info);
+ }
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BATCH_SIZE))
+ {
+ renderBatchSize(draw_info);
+ }
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
+ {
+ renderShadowFrusta(draw_info);
+ }
+ }
+ }
+ }
+};
+
+
+class LLOctreeRenderPhysicsShapes : public LLOctreeTraveler<LLDrawable>
+{
+public:
+ LLCamera* mCamera;
+ LLOctreeRenderPhysicsShapes(LLCamera* camera): mCamera(camera) {}
+
+ virtual void traverse(const LLSpatialGroup::OctreeNode* node)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
+
+ if (!mCamera || mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]))
+ {
+ node->accept(this);
+ stop_glerror();
+
+ for (U32 i = 0; i < node->getChildCount(); i++)
+ {
+ traverse(node->getChild(i));
+ stop_glerror();
+ }
+
+ group->rebuildGeom();
+ group->rebuildMesh();
+
+ renderPhysicsShapes(group);
+ }
+ }
+
+ virtual void visit(const LLSpatialGroup::OctreeNode* branch)
+ {
+
+ }
+};
+
+class LLOctreePushBBoxVerts : public LLOctreeTraveler<LLDrawable>
+{
+public:
+ LLCamera* mCamera;
+ LLOctreePushBBoxVerts(LLCamera* camera): mCamera(camera) {}
+
+ virtual void traverse(const LLSpatialGroup::OctreeNode* node)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
+
+ if (!mCamera || mCamera->AABBInFrustum(group->mBounds[0], group->mBounds[1]))
+ {
+ node->accept(this);
+
+ for (U32 i = 0; i < node->getChildCount(); i++)
+ {
+ traverse(node->getChild(i));
+ }
+ }
+ }
+
+ virtual void visit(const LLSpatialGroup::OctreeNode* branch)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) branch->getListener(0);
+
+ if (group->isState(LLSpatialGroup::GEOM_DIRTY) || (mCamera && !mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1])))
+ {
+ return;
+ }
+
+ for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i)
+ {
+ LLDrawable* drawable = *i;
+
+ renderBoundingBox(drawable, FALSE);
+ }
+ }
+};
+
+void LLSpatialPartition::renderIntersectingBBoxes(LLCamera* camera)
+{
+ LLOctreePushBBoxVerts pusher(camera);
+ pusher.traverse(mOctree);
+}
+
+class LLOctreeStateCheck : public LLOctreeTraveler<LLDrawable>
+{
+public:
+ U32 mInheritedMask[LLViewerCamera::NUM_CAMERAS];
+
+ LLOctreeStateCheck()
+ {
+ for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
+ {
+ mInheritedMask[i] = 0;
+ }
+ }
+
+ virtual void traverse(const LLSpatialGroup::OctreeNode* node)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
+
+ node->accept(this);
+
+
+ U32 temp[LLViewerCamera::NUM_CAMERAS];
+
+ for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
+ {
+ temp[i] = mInheritedMask[i];
+ mInheritedMask[i] |= group->mOcclusionState[i] & LLSpatialGroup::OCCLUDED;
+ }
+
+ for (U32 i = 0; i < node->getChildCount(); i++)
+ {
+ traverse(node->getChild(i));
+ }
+
+ for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
+ {
+ mInheritedMask[i] = temp[i];
+ }
+ }
+
+
+ virtual void visit(const LLOctreeNode<LLDrawable>* state)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) state->getListener(0);
+
+ for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
+ {
+ if (mInheritedMask[i] && !(group->mOcclusionState[i] & mInheritedMask[i]))
+ {
+ llerrs << "Spatial group failed inherited mask test." << llendl;
+ }
+ }
+
+ if (group->isState(LLSpatialGroup::DIRTY))
+ {
+ assert_parent_state(group, LLSpatialGroup::DIRTY);
+ }
+ }
+
+ void assert_parent_state(LLSpatialGroup* group, U32 state)
+ {
+ LLSpatialGroup* parent = group->getParent();
+ while (parent)
+ {
+ if (!parent->isState(state))
+ {
+ llerrs << "Spatial group failed parent state check." << llendl;
+ }
+ parent = parent->getParent();
+ }
+ }
+};
+
+
+void LLSpatialPartition::renderPhysicsShapes()
+{
+ LLSpatialBridge* bridge = asBridge();
+ LLCamera* camera = LLViewerCamera::getInstance();
+
+ if (bridge)
+ {
+ camera = NULL;
+ }
+
+ gGL.flush();
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ glLineWidth(3.f);
+ LLOctreeRenderPhysicsShapes render_physics(camera);
+ render_physics.traverse(mOctree);
+ gGL.flush();
+ glLineWidth(1.f);
+}
+
+void LLSpatialPartition::renderDebug()
+{
+ if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCTREE |
+ LLPipeline::RENDER_DEBUG_OCCLUSION |
+ LLPipeline::RENDER_DEBUG_LIGHTS |
+ LLPipeline::RENDER_DEBUG_BATCH_SIZE |
+ LLPipeline::RENDER_DEBUG_UPDATE_TYPE |
+ LLPipeline::RENDER_DEBUG_BBOXES |
+ LLPipeline::RENDER_DEBUG_NORMALS |
+ LLPipeline::RENDER_DEBUG_POINTS |
+ LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY |
+ LLPipeline::RENDER_DEBUG_TEXTURE_ANIM |
+ LLPipeline::RENDER_DEBUG_RAYCAST |
+ LLPipeline::RENDER_DEBUG_AVATAR_VOLUME |
+ LLPipeline::RENDER_DEBUG_AGENT_TARGET |
+ //LLPipeline::RENDER_DEBUG_BUILD_QUEUE |
+ LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA |
+ LLPipeline::RENDER_DEBUG_RENDER_COMPLEXITY))
+ {
+ return;
+ }
+
+ if (LLGLSLShader::sNoFixedFunction)
+ {
+ gDebugProgram.bind();
+ }
+
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY))
+ {
+ //sLastMaxTexPriority = lerp(sLastMaxTexPriority, sCurMaxTexPriority, gFrameIntervalSeconds);
+ sLastMaxTexPriority = (F32) LLViewerCamera::getInstance()->getScreenPixelArea();
+ sCurMaxTexPriority = 0.f;
+ }
+
+ LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+
+ LLGLDisable cullface(GL_CULL_FACE);
+ LLGLEnable blend(GL_BLEND);
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ gPipeline.disableLights();
+
+ LLSpatialBridge* bridge = asBridge();
+ LLCamera* camera = LLViewerCamera::getInstance();
+
+ if (bridge)
+ {
+ camera = NULL;
+ }
+
+ LLOctreeStateCheck checker;
+ checker.traverse(mOctree);
+
+ LLOctreeRenderNonOccluded render_debug(camera);
+ render_debug.traverse(mOctree);
+
+ if (LLGLSLShader::sNoFixedFunction)
+ {
+ gDebugProgram.unbind();
+ }
+}
+
+void LLSpatialGroup::drawObjectBox(LLColor4 col)
+{
+ gGL.diffuseColor4fv(col.mV);
+ LLVector4a size;
+ size = mObjectBounds[1];
+ size.mul(1.01f);
+ size.add(LLVector4a(0.001f));
+ drawBox(mObjectBounds[0], size);
+}
+
+bool LLSpatialPartition::isHUDPartition()
+{
+ return mPartitionType == LLViewerRegion::PARTITION_HUD ;
+}
+
+BOOL LLSpatialPartition::isVisible(const LLVector3& v)
+{
+ if (!LLViewerCamera::getInstance()->sphereInFrustum(v, 4.0f))
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+class LLOctreeIntersect : public LLSpatialGroup::OctreeTraveler
+{
+public:
+ LLVector3 mStart;
+ LLVector3 mEnd;
+ S32 *mFaceHit;
+ LLVector3 *mIntersection;
+ LLVector2 *mTexCoord;
+ LLVector3 *mNormal;
+ LLVector3 *mBinormal;
+ LLDrawable* mHit;
+ BOOL mPickTransparent;
+
+ LLOctreeIntersect(LLVector3 start, LLVector3 end, BOOL pick_transparent,
+ S32* face_hit, LLVector3* intersection, LLVector2* tex_coord, LLVector3* normal, LLVector3* binormal)
+ : mStart(start),
+ mEnd(end),
+ mFaceHit(face_hit),
+ mIntersection(intersection),
+ mTexCoord(tex_coord),
+ mNormal(normal),
+ mBinormal(binormal),
+ mHit(NULL),
+ mPickTransparent(pick_transparent)
+ {
+ }
+
+ virtual void visit(const LLSpatialGroup::OctreeNode* branch)
+ {
+ for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i)
+ {
+ check(*i);
+ }
+ }
+
+ virtual LLDrawable* check(const LLSpatialGroup::OctreeNode* node)
+ {
+ node->accept(this);
+
+ for (U32 i = 0; i < node->getChildCount(); i++)
+ {
+ const LLSpatialGroup::OctreeNode* child = node->getChild(i);
+ LLVector3 res;
+
+ LLSpatialGroup* group = (LLSpatialGroup*) child->getListener(0);
+
+ LLVector4a size;
+ LLVector4a center;
+
+ size = group->mBounds[1];
+ center = group->mBounds[0];
+
+ LLVector3 local_start = mStart;
+ LLVector3 local_end = mEnd;
+
+ if (group->mSpatialPartition->isBridge())
+ {
+ LLMatrix4 local_matrix = group->mSpatialPartition->asBridge()->mDrawable->getRenderMatrix();
+ local_matrix.invert();
+
+ local_start = mStart * local_matrix;
+ local_end = mEnd * local_matrix;
+ }
+
+ LLVector4a start, end;
+ start.load3(local_start.mV);
+ end.load3(local_end.mV);
+
+ if (LLLineSegmentBoxIntersect(start, end, center, size))
+ {
+ check(child);
+ }
+ }
+
+ return mHit;
+ }
+
+ virtual bool check(LLDrawable* drawable)
+ {
+ LLVector3 local_start = mStart;
+ LLVector3 local_end = mEnd;
+
+ if (!drawable || !gPipeline.hasRenderType(drawable->getRenderType()) || !drawable->isVisible())
+ {
+ return false;
+ }
+
+ if (drawable->isSpatialBridge())
+ {
+ LLSpatialPartition *part = drawable->asPartition();
+ LLSpatialBridge* bridge = part->asBridge();
+ if (bridge && gPipeline.hasRenderType(bridge->mDrawableType))
+ {
+ check(part->mOctree);
+ }
+ }
+ else
+ {
+ LLViewerObject* vobj = drawable->getVObj();
+
+ if (vobj)
+ {
+ LLVector3 intersection;
+ bool skip_check = false;
+ if (vobj->isAvatar())
+ {
+ LLVOAvatar* avatar = (LLVOAvatar*) vobj;
+ if (avatar->isSelf() && LLFloater::isVisible(gFloaterTools))
+ {
+ LLViewerObject* hit = avatar->lineSegmentIntersectRiggedAttachments(mStart, mEnd, -1, mPickTransparent, mFaceHit, &intersection, mTexCoord, mNormal, mBinormal);
+ if (hit)
+ {
+ mEnd = intersection;
+ if (mIntersection)
+ {
+ *mIntersection = intersection;
+ }
+
+ mHit = hit->mDrawable;
+ skip_check = true;
+ }
+
+ }
+ }
+
+ if (!skip_check && vobj->lineSegmentIntersect(mStart, mEnd, -1, mPickTransparent, mFaceHit, &intersection, mTexCoord, mNormal, mBinormal))
+ {
+ mEnd = intersection; // shorten ray so we only find CLOSER hits
+ if (mIntersection)
+ {
+ *mIntersection = intersection;
+ }
+
+ mHit = vobj->mDrawable;
+ }
+ }
+ }
+
+ return false;
+ }
+};
+
+LLDrawable* LLSpatialPartition::lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
+ BOOL pick_transparent,
+ S32* face_hit, // return the face hit
+ LLVector3* intersection, // return the intersection point
+ LLVector2* tex_coord, // return the texture coordinates of the intersection point
+ LLVector3* normal, // return the surface normal at the intersection point
+ LLVector3* bi_normal // return the surface bi-normal at the intersection point
+ )
+
+{
+ LLOctreeIntersect intersect(start, end, pick_transparent, face_hit, intersection, tex_coord, normal, bi_normal);
+ LLDrawable* drawable = intersect.check(mOctree);
+
+ return drawable;
+}
+
+LLDrawInfo::LLDrawInfo(U16 start, U16 end, U32 count, U32 offset,
+ LLViewerTexture* texture, LLVertexBuffer* buffer,
+ BOOL fullbright, U8 bump, BOOL particle, F32 part_size)
+:
+ mVertexBuffer(buffer),
+ mTexture(texture),
+ mTextureMatrix(NULL),
+ mModelMatrix(NULL),
+ mStart(start),
+ mEnd(end),
+ mCount(count),
+ mOffset(offset),
+ mFullbright(fullbright),
+ mBump(bump),
+ mParticle(particle),
+ mPartSize(part_size),
+ mVSize(0.f),
+ mGroup(NULL),
+ mFace(NULL),
+ mDistance(0.f),
+ mDrawMode(LLRender::TRIANGLES)
+{
+ mVertexBuffer->validateRange(mStart, mEnd, mCount, mOffset);
+
+ mDebugColor = (rand() << 16) + rand();
+}
+
+LLDrawInfo::~LLDrawInfo()
+{
+ /*if (LLSpatialGroup::sNoDelete)
+ {
+ llerrs << "LLDrawInfo deleted illegally!" << llendl;
+ }*/
+
+ if (mFace)
+ {
+ mFace->setDrawInfo(NULL);
+ }
+
+ if (gDebugGL)
+ {
+ gPipeline.checkReferences(this);
+ }
+}
+
+void LLDrawInfo::validate()
+{
+ mVertexBuffer->validateRange(mStart, mEnd, mCount, mOffset);
+}
+
+LLVertexBuffer* LLGeometryManager::createVertexBuffer(U32 type_mask, U32 usage)
+{
+ return new LLVertexBuffer(type_mask, usage);
+}
+
+LLCullResult::LLCullResult()
+{
+ clear();
+}
+
+void LLCullResult::clear()
+{
+ mVisibleGroupsSize = 0;
+ mVisibleGroupsEnd = mVisibleGroups.begin();
+
+ mAlphaGroupsSize = 0;
+ mAlphaGroupsEnd = mAlphaGroups.begin();
+
+ mOcclusionGroupsSize = 0;
+ mOcclusionGroupsEnd = mOcclusionGroups.begin();
+
+ mDrawableGroupsSize = 0;
+ mDrawableGroupsEnd = mDrawableGroups.begin();
+
+ mVisibleListSize = 0;
+ mVisibleListEnd = mVisibleList.begin();
+
+ mVisibleBridgeSize = 0;
+ mVisibleBridgeEnd = mVisibleBridge.begin();
+
+
+ for (U32 i = 0; i < LLRenderPass::NUM_RENDER_TYPES; i++)
+ {
+ for (U32 j = 0; j < mRenderMapSize[i]; j++)
+ {
+ mRenderMap[i][j] = 0;
+ }
+ mRenderMapSize[i] = 0;
+ mRenderMapEnd[i] = mRenderMap[i].begin();
+ }
+}
+
+LLCullResult::sg_list_t::iterator LLCullResult::beginVisibleGroups()
+{
+ return mVisibleGroups.begin();
+}
+
+LLCullResult::sg_list_t::iterator LLCullResult::endVisibleGroups()
+{
+ return mVisibleGroupsEnd;
+}
+
+LLCullResult::sg_list_t::iterator LLCullResult::beginAlphaGroups()
+{
+ return mAlphaGroups.begin();
+}
+
+LLCullResult::sg_list_t::iterator LLCullResult::endAlphaGroups()
+{
+ return mAlphaGroupsEnd;
+}
+
+LLCullResult::sg_list_t::iterator LLCullResult::beginOcclusionGroups()
+{
+ return mOcclusionGroups.begin();
+}
+
+LLCullResult::sg_list_t::iterator LLCullResult::endOcclusionGroups()
+{
+ return mOcclusionGroupsEnd;
+}
+
+LLCullResult::sg_list_t::iterator LLCullResult::beginDrawableGroups()
+{
+ return mDrawableGroups.begin();
+}
+
+LLCullResult::sg_list_t::iterator LLCullResult::endDrawableGroups()
+{
+ return mDrawableGroupsEnd;
+}
+
+LLCullResult::drawable_list_t::iterator LLCullResult::beginVisibleList()
+{
+ return mVisibleList.begin();
+}
+
+LLCullResult::drawable_list_t::iterator LLCullResult::endVisibleList()
+{
+ return mVisibleListEnd;
+}
+
+LLCullResult::bridge_list_t::iterator LLCullResult::beginVisibleBridge()
+{
+ return mVisibleBridge.begin();
+}
+
+LLCullResult::bridge_list_t::iterator LLCullResult::endVisibleBridge()
+{
+ return mVisibleBridgeEnd;
+}
+
+LLCullResult::drawinfo_list_t::iterator LLCullResult::beginRenderMap(U32 type)
+{
+ return mRenderMap[type].begin();
+}
+
+LLCullResult::drawinfo_list_t::iterator LLCullResult::endRenderMap(U32 type)
+{
+ return mRenderMapEnd[type];
+}
+
+void LLCullResult::pushVisibleGroup(LLSpatialGroup* group)
+{
+ if (mVisibleGroupsSize < mVisibleGroups.size())
+ {
+ mVisibleGroups[mVisibleGroupsSize] = group;
+ }
+ else
+ {
+ mVisibleGroups.push_back(group);
+ }
+ ++mVisibleGroupsSize;
+ mVisibleGroupsEnd = mVisibleGroups.begin()+mVisibleGroupsSize;
+}
+
+void LLCullResult::pushAlphaGroup(LLSpatialGroup* group)
+{
+ if (mAlphaGroupsSize < mAlphaGroups.size())
+ {
+ mAlphaGroups[mAlphaGroupsSize] = group;
+ }
+ else
+ {
+ mAlphaGroups.push_back(group);
+ }
+ ++mAlphaGroupsSize;
+ mAlphaGroupsEnd = mAlphaGroups.begin()+mAlphaGroupsSize;
+}
+
+void LLCullResult::pushOcclusionGroup(LLSpatialGroup* group)
+{
+ if (mOcclusionGroupsSize < mOcclusionGroups.size())
+ {
+ mOcclusionGroups[mOcclusionGroupsSize] = group;
+ }
+ else
+ {
+ mOcclusionGroups.push_back(group);
+ }
+ ++mOcclusionGroupsSize;
+ mOcclusionGroupsEnd = mOcclusionGroups.begin()+mOcclusionGroupsSize;
+}
+
+void LLCullResult::pushDrawableGroup(LLSpatialGroup* group)
+{
+ if (mDrawableGroupsSize < mDrawableGroups.size())
+ {
+ mDrawableGroups[mDrawableGroupsSize] = group;
+ }
+ else
+ {
+ mDrawableGroups.push_back(group);
+ }
+ ++mDrawableGroupsSize;
+ mDrawableGroupsEnd = mDrawableGroups.begin()+mDrawableGroupsSize;
+}
+
+void LLCullResult::pushDrawable(LLDrawable* drawable)
+{
+ if (mVisibleListSize < mVisibleList.size())
+ {
+ mVisibleList[mVisibleListSize] = drawable;
+ }
+ else
+ {
+ mVisibleList.push_back(drawable);
+ }
+ ++mVisibleListSize;
+ mVisibleListEnd = mVisibleList.begin()+mVisibleListSize;
+}
+
+void LLCullResult::pushBridge(LLSpatialBridge* bridge)
+{
+ if (mVisibleBridgeSize < mVisibleBridge.size())
+ {
+ mVisibleBridge[mVisibleBridgeSize] = bridge;
+ }
+ else
+ {
+ mVisibleBridge.push_back(bridge);
+ }
+ ++mVisibleBridgeSize;
+ mVisibleBridgeEnd = mVisibleBridge.begin()+mVisibleBridgeSize;
+}
+
+void LLCullResult::pushDrawInfo(U32 type, LLDrawInfo* draw_info)
+{
+ if (mRenderMapSize[type] < mRenderMap[type].size())
+ {
+ mRenderMap[type][mRenderMapSize[type]] = draw_info;
+ }
+ else
+ {
+ mRenderMap[type].push_back(draw_info);
+ }
+ ++mRenderMapSize[type];
+ mRenderMapEnd[type] = mRenderMap[type].begin() + mRenderMapSize[type];
+}
+
+
+void LLCullResult::assertDrawMapsEmpty()
+{
+ for (U32 i = 0; i < LLRenderPass::NUM_RENDER_TYPES; i++)
+ {
+ if (mRenderMapSize[i] != 0)
+ {
+ llerrs << "Stale LLDrawInfo's in LLCullResult!" << llendl;
+ }
+ }
+}
+
+
+
diff --git a/indra/newview/llsurface.cpp b/indra/newview/llsurface.cpp index 66df7dae3e..65393cc168 100644 --- a/indra/newview/llsurface.cpp +++ b/indra/newview/llsurface.cpp @@ -346,6 +346,19 @@ void LLSurface::getNeighboringRegions( std::vector<LLViewerRegion*>& uniqueRegio } } + +void LLSurface::getNeighboringRegionsStatus( std::vector<S32>& regions ) +{ + S32 i; + for (i = 0; i < 8; i++) + { + if ( mNeighbors[i] != NULL ) + { + regions.push_back( i ); + } + } +} + void LLSurface::connectNeighbor(LLSurface *neighborp, U32 direction) { S32 i; diff --git a/indra/newview/llsurface.h b/indra/newview/llsurface.h index a4ef4fe2de..8052fb0d18 100644 --- a/indra/newview/llsurface.h +++ b/indra/newview/llsurface.h @@ -142,6 +142,7 @@ public: friend std::ostream& operator<<(std::ostream &s, const LLSurface &S); void getNeighboringRegions( std::vector<LLViewerRegion*>& uniqueRegions ); + void getNeighboringRegionsStatus( std::vector<S32>& regions ); public: // Number of grid points on one side of a region, including +1 buffer for diff --git a/indra/newview/lltoolgrab.cpp b/indra/newview/lltoolgrab.cpp index 319e2508e0..61ff59c53a 100644 --- a/indra/newview/lltoolgrab.cpp +++ b/indra/newview/lltoolgrab.cpp @@ -205,9 +205,9 @@ BOOL LLToolGrab::handleObjectHit(const LLPickInfo& info) // Clicks on scripted or physical objects are temporary grabs, so // not "Build mode" - mHideBuildHighlight = script_touch || objectp->usePhysics(); + mHideBuildHighlight = script_touch || objectp->flagUsePhysics(); - if (!objectp->usePhysics()) + if (!objectp->flagUsePhysics()) { if (script_touch) { diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index b0d9bd5d70..3cd761b73b 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -312,7 +312,7 @@ BOOL LLToolPie::handleLeftClickPick() // Switch to grab tool if physical or triggerable if (object && !object->isAvatar() && - ((object->usePhysics() || (parent && !parent->isAvatar() && parent->usePhysics())) || touchable) + ((object->flagUsePhysics() || (parent && !parent->isAvatar() && parent->flagUsePhysics())) || touchable) ) { gGrabTransientTool = this; @@ -596,8 +596,8 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask) lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl; } - else if ((object && !object->isAvatar() && object->usePhysics()) - || (parent && !parent->isAvatar() && parent->usePhysics())) + else if ((object && !object->isAvatar() && object->flagUsePhysics()) + || (parent && !parent->isAvatar() && parent->flagUsePhysics())) { show_highlight = true; gViewerWindow->setCursor(UI_CURSOR_TOOLGRAB); diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index cb40af7061..001c23278d 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -77,6 +77,9 @@ #include "llwlparammanager.h" #include "llwaterparammanager.h" #include "llpostprocess.h" +#include "LLPathingLib.h" +#include "llfloaterpathfindingconsole.h" +#include "llfloaterreg.h" extern LLPointer<LLViewerTexture> gStartTexture; @@ -110,6 +113,7 @@ void render_hud_attachments(); void render_ui_3d(); void render_ui_2d(); void render_disconnected_background(); +void render_navmesh( bool& allowRenderables, bool& exclusiveNavDraw ); void display_startup() { @@ -668,8 +672,9 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) if (!for_snapshot) { if (gFrameCount > 1) - { //for some reason, ATI 4800 series will error out if you - //try to generate a shadow before the first frame is through + { + //for some reason, ATI 4800 series will error out if you + //try to generate a shadow before the first frame is through gPipeline.generateSunShadow(*LLViewerCamera::getInstance()); } @@ -880,7 +885,8 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) } LLAppViewer::instance()->pingMainloopTimeout("Display:RenderGeom"); - + bool exclusiveNavDraw = false; + bool allowRenderables = false; if (!(LLAppViewer::instance()->logoutRequestSent() && LLAppViewer::instance()->hasSavedFinalSnapshot()) && !gRestoreGL) { @@ -889,13 +895,16 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) gGL.setColorMask(true, false); if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender) { - gPipeline.renderGeomDeferred(*LLViewerCamera::getInstance()); + gPipeline.renderGeomDeferred(*LLViewerCamera::getInstance()); } - else + + render_navmesh( allowRenderables, exclusiveNavDraw ); + + if ( !exclusiveNavDraw || allowRenderables ) { gPipeline.renderGeom(*LLViewerCamera::getInstance(), TRUE); } - + gGL.setColorMask(true, true); //store this frame's modelview matrix for use @@ -947,7 +956,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) } } - if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender) + if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender ) { gPipeline.renderDeferredLighting(); } @@ -983,6 +992,42 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) LLAppViewer::instance()->pingMainloopTimeout("Display:Done"); } +void render_navmesh( bool& allowRenderables, bool& exclusiveNavDraw ) +{ + //Render any navmesh geometry + LLPathingLib *llPathingLibInstance = LLPathingLib::getInstance(); + if ( llPathingLibInstance != NULL ) + { + LLHandle<LLFloaterPathfindingConsole> pathfindingConsoleHandle = LLFloaterPathfindingConsole::getInstanceHandle(); + if (!pathfindingConsoleHandle.isDead()) + { + LLFloaterPathfindingConsole *pathfindingConsole = pathfindingConsoleHandle.get(); + //Determine if we can should overlay the navmesh ontop of the scenes typical renderables + allowRenderables = pathfindingConsole->isRenderWorld(); + + //NavMesh + if ( pathfindingConsole->isRenderNavMesh() ) + { + glClearColor(0,0,0,0); + glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + LLGLDisable lighting(GL_LIGHTING); + llPathingLibInstance->renderNavMesh(); + exclusiveNavDraw = true; + } + //physics/exclusion shapes + if ( pathfindingConsole->isRenderAnyShapes() ) + { + llPathingLibInstance->renderNavMeshShapesVBO( pathfindingConsole->getRenderShapeFlags() ); + exclusiveNavDraw = true; + } + //User designated path + if ( pathfindingConsole->isRenderPath() ) + { + llPathingLibInstance->renderPath(); + } + } + } +} void render_hud_attachments() { LLMemType mt_ra(LLMemType::MTYPE_DISPLAY_RENDER_ATTACHMENTS); diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index bb870f7651..d396219bf8 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -84,6 +84,10 @@ #include "llfloaterobjectweights.h" #include "llfloateropenobject.h" #include "llfloateroutbox.h" +#include "llfloaterpathfindingbasic.h" +#include "llfloaterpathfindingcharacters.h" +#include "llfloaterpathfindinglinksets.h" +#include "llfloaterpathfindingconsole.h" #include "llfloaterpay.h" #include "llfloaterperms.h" #include "llfloaterpostprocess.h" @@ -243,6 +247,10 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("outgoing_call", "floater_outgoing_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLOutgoingCallDialog>); LLFloaterPayUtil::registerFloater(); + LLFloaterReg::add("pathfinding_basic", "floater_pathfinding_basic.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPathfindingBasic>); + LLFloaterReg::add("pathfinding_characters", "floater_pathfinding_characters.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPathfindingCharacters>); + LLFloaterReg::add("pathfinding_linksets", "floater_pathfinding_linksets.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPathfindingLinksets>); + LLFloaterReg::add("pathfinding_console", "floater_pathfinding_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPathfindingConsole>); LLFloaterReg::add("people", "floater_people.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSidePanelContainer>); LLFloaterReg::add("places", "floater_places.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSidePanelContainer>); LLFloaterReg::add("preferences", "floater_preferences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreference>); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 99540ccce9..92a01c22b3 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -197,7 +197,6 @@ void near_sit_object(); BOOL is_selection_buy_not_take(); S32 selection_price(); BOOL enable_take(); -void handle_take(); void handle_object_show_inspector(); void handle_avatar_show_inspector(); bool confirm_take(const LLSD& notification, const LLSD& response); @@ -5011,6 +5010,12 @@ class LLEditDelete : public view_listener_t } }; +bool enable_object_return() +{ + return (!LLSelectMgr::getInstance()->getSelection()->isEmpty() && + (gAgent.isGodlike() || can_derez(DRD_RETURN_TO_OWNER))); +} + bool enable_object_delete() { bool new_value = @@ -5026,6 +5031,49 @@ bool enable_object_delete() return new_value; } +class LLObjectsReturnPackage +{ +public: + LLObjectsReturnPackage() : mObjectSelection(), mReturnableObjects(), mError(), mFirstRegion(NULL) {}; + ~LLObjectsReturnPackage() + { + mObjectSelection.clear(); + mReturnableObjects.clear(); + mError.clear(); + mFirstRegion = NULL; + }; + + LLObjectSelectionHandle mObjectSelection; + LLDynamicArray<LLViewerObjectPtr> mReturnableObjects; + std::string mError; + LLViewerRegion *mFirstRegion; +}; + +static void return_objects(LLObjectsReturnPackage *objectsReturnPackage, const LLSD& notification, const LLSD& response) +{ + if (LLNotificationsUtil::getSelectedOption(notification, response) == 0) + { + // Ignore category ID for this derez destination. + derez_objects(DRD_RETURN_TO_OWNER, LLUUID::null, objectsReturnPackage->mFirstRegion, objectsReturnPackage->mError, &objectsReturnPackage->mReturnableObjects); + } + + delete objectsReturnPackage; +} + +void handle_object_return() +{ + if (!LLSelectMgr::getInstance()->getSelection()->isEmpty()) + { + LLObjectsReturnPackage *objectsReturnPackage = new LLObjectsReturnPackage(); + objectsReturnPackage->mObjectSelection = LLSelectMgr::getInstance()->getEditSelection(); + + // Save selected objects, so that we still know what to return after the confirmation dialog resets selection. + get_derezzable_objects(DRD_RETURN_TO_OWNER, objectsReturnPackage->mError, objectsReturnPackage->mFirstRegion, &objectsReturnPackage->mReturnableObjects); + + LLNotificationsUtil::add("ReturnToOwner", LLSD(), LLSD(), boost::bind(&return_objects, objectsReturnPackage, _1, _2)); + } +} + void handle_object_delete() { diff --git a/indra/newview/llviewermenu.h b/indra/newview/llviewermenu.h index 87cb4efbc4..f10891737f 100644 --- a/indra/newview/llviewermenu.h +++ b/indra/newview/llviewermenu.h @@ -93,11 +93,20 @@ void handle_object_touch(); bool enable_object_open(); void handle_object_open(); +bool visible_take_object(); +bool tools_visible_take_object(); +bool enable_object_take_copy(); +bool enable_object_return(); +bool enable_object_delete(); + // Buy either contents or object itself void handle_buy(); +void handle_take(); void handle_take_copy(); void handle_look_at_selection(const LLSD& param); void handle_zoom_to_object(LLUUID object_id); +void handle_object_return(); +void handle_object_delete(); void handle_buy_land(); diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index 7e830e14bf..99d08087d4 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -1,1272 +1,1272 @@ -/** - * @file llviewermenufile.cpp - * @brief "File" menu in the main menu bar. - * - * $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 "llviewermenufile.h" - -// project includes -#include "llagent.h" -#include "llagentcamera.h" -#include "llfilepicker.h" -#include "llfloaterreg.h" -#include "llbuycurrencyhtml.h" -#include "llfloatermodelpreview.h" -#include "llfloatersnapshot.h" -#include "llimage.h" -#include "llimagebmp.h" -#include "llimagepng.h" -#include "llimagej2c.h" -#include "llimagejpeg.h" -#include "llimagetga.h" -#include "llinventorymodel.h" // gInventory -#include "llresourcedata.h" -#include "llfloaterperms.h" -#include "llstatusbar.h" -#include "llviewercontrol.h" // gSavedSettings -#include "llviewertexturelist.h" -#include "lluictrlfactory.h" -#include "llvfile.h" -#include "llvfs.h" -#include "llviewerinventory.h" -#include "llviewermenu.h" // gMenuHolder -#include "llviewerparcelmgr.h" -#include "llviewerregion.h" -#include "llviewerstats.h" -#include "llviewerwindow.h" -#include "llappviewer.h" -#include "lluploaddialog.h" -#include "lltrans.h" -#include "llfloaterbuycurrency.h" - -// linden libraries -#include "llassetuploadresponders.h" -#include "lleconomy.h" -#include "llhttpclient.h" -#include "llnotificationsutil.h" -#include "llsdserialize.h" -#include "llsdutil.h" -#include "llstring.h" -#include "lltransactiontypes.h" -#include "lluuid.h" -#include "llvorbisencode.h" -#include "message.h" - -// system libraries -#include <boost/tokenizer.hpp> - -class LLFileEnableUpload : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = gStatusBar && LLGlobalEconomy::Singleton::getInstance() && (gStatusBar->getBalance() >= LLGlobalEconomy::Singleton::getInstance()->getPriceUpload()); - return new_value; - } -}; - -class LLFileEnableUploadModel : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - return true; - } -}; - -class LLMeshEnabled : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - return gSavedSettings.getBOOL("MeshEnabled"); - } -}; - -class LLMeshUploadVisible : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - return gMeshRepo.meshUploadEnabled(); - } -}; - -LLMutex* LLFilePickerThread::sMutex = NULL; -std::queue<LLFilePickerThread*> LLFilePickerThread::sDeadQ; - -void LLFilePickerThread::getFile() -{ -#if LL_WINDOWS - start(); -#else - run(); -#endif -} - -//virtual -void LLFilePickerThread::run() -{ - LLFilePicker picker; -#if LL_WINDOWS - if (picker.getOpenFile(mFilter, false)) - { - mFile = picker.getFirstFile(); - } -#else - if (picker.getOpenFile(mFilter, true)) - { - mFile = picker.getFirstFile(); - } -#endif - - { - LLMutexLock lock(sMutex); - sDeadQ.push(this); - } - -} - -//static -void LLFilePickerThread::initClass() -{ - sMutex = new LLMutex(NULL); -} - -//static -void LLFilePickerThread::cleanupClass() -{ - clearDead(); - - delete sMutex; - sMutex = NULL; -} - -//static -void LLFilePickerThread::clearDead() -{ - if (!sDeadQ.empty()) - { - LLMutexLock lock(sMutex); - while (!sDeadQ.empty()) - { - LLFilePickerThread* thread = sDeadQ.front(); - thread->notify(thread->mFile); - delete thread; - sDeadQ.pop(); - } - } -} - - -//============================================================================ - -#if LL_WINDOWS -static std::string SOUND_EXTENSIONS = "wav"; -static std::string IMAGE_EXTENSIONS = "tga bmp jpg jpeg png"; -static std::string ANIM_EXTENSIONS = "bvh"; -#ifdef _CORY_TESTING -static std::string GEOMETRY_EXTENSIONS = "slg"; -#endif -static std::string XML_EXTENSIONS = "xml"; -static std::string SLOBJECT_EXTENSIONS = "slobject"; -#endif -static std::string ALL_FILE_EXTENSIONS = "*.*"; -static std::string MODEL_EXTENSIONS = "dae"; - -std::string build_extensions_string(LLFilePicker::ELoadFilter filter) -{ - switch(filter) - { -#if LL_WINDOWS - case LLFilePicker::FFLOAD_IMAGE: - return IMAGE_EXTENSIONS; - case LLFilePicker::FFLOAD_WAV: - return SOUND_EXTENSIONS; - case LLFilePicker::FFLOAD_ANIM: - return ANIM_EXTENSIONS; - case LLFilePicker::FFLOAD_SLOBJECT: - return SLOBJECT_EXTENSIONS; - case LLFilePicker::FFLOAD_MODEL: - return MODEL_EXTENSIONS; -#ifdef _CORY_TESTING - case LLFilePicker::FFLOAD_GEOMETRY: - return GEOMETRY_EXTENSIONS; -#endif - case LLFilePicker::FFLOAD_XML: - return XML_EXTENSIONS; - case LLFilePicker::FFLOAD_ALL: - return ALL_FILE_EXTENSIONS; -#endif - default: - return ALL_FILE_EXTENSIONS; - } -} - -/** - char* upload_pick(void* data) - - If applicable, brings up a file chooser in which the user selects a file - to upload for a particular task. If the file is valid for the given action, - returns the string to the full path filename, else returns NULL. - Data is the load filter for the type of file as defined in LLFilePicker. -**/ -const std::string upload_pick(void* data) -{ - if( gAgentCamera.cameraMouselook() ) - { - gAgentCamera.changeCameraToDefault(); - // This doesn't seem necessary. JC - // display(); - } - - LLFilePicker::ELoadFilter type; - if(data) - { - type = (LLFilePicker::ELoadFilter)((intptr_t)data); - } - else - { - type = LLFilePicker::FFLOAD_ALL; - } - - LLFilePicker& picker = LLFilePicker::instance(); - if (!picker.getOpenFile(type)) - { - llinfos << "Couldn't import objects from file" << llendl; - return std::string(); - } - - - const std::string& filename = picker.getFirstFile(); - std::string ext = gDirUtilp->getExtension(filename); - - //strincmp doesn't like NULL pointers - if (ext.empty()) - { - std::string short_name = gDirUtilp->getBaseFileName(filename); - - // No extension - LLSD args; - args["FILE"] = short_name; - LLNotificationsUtil::add("NoFileExtension", args); - return std::string(); - } - else - { - //so there is an extension - //loop over the valid extensions and compare to see - //if the extension is valid - - //now grab the set of valid file extensions - std::string valid_extensions = build_extensions_string(type); - - BOOL ext_valid = FALSE; - - typedef boost::tokenizer<boost::char_separator<char> > tokenizer; - boost::char_separator<char> sep(" "); - tokenizer tokens(valid_extensions, sep); - tokenizer::iterator token_iter; - - //now loop over all valid file extensions - //and compare them to the extension of the file - //to be uploaded - for( token_iter = tokens.begin(); - token_iter != tokens.end() && ext_valid != TRUE; - ++token_iter) - { - const std::string& cur_token = *token_iter; - - if (cur_token == ext || cur_token == "*.*") - { - //valid extension - //or the acceptable extension is any - ext_valid = TRUE; - } - }//end for (loop over all tokens) - - if (ext_valid == FALSE) - { - //should only get here if the extension exists - //but is invalid - LLSD args; - args["EXTENSION"] = ext; - args["VALIDS"] = valid_extensions; - LLNotificationsUtil::add("InvalidFileExtension", args); - return std::string(); - } - }//end else (non-null extension) - - //valid file extension - - //now we check to see - //if the file is actually a valid image/sound/etc. - if (type == LLFilePicker::FFLOAD_WAV) - { - // pre-qualify wavs to make sure the format is acceptable - std::string error_msg; - if (check_for_invalid_wav_formats(filename,error_msg)) - { - llinfos << error_msg << ": " << filename << llendl; - LLSD args; - args["FILE"] = filename; - LLNotificationsUtil::add( error_msg, args ); - return std::string(); - } - }//end if a wave/sound file - - - return filename; -} - -class LLFileUploadImage : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - std::string filename = upload_pick((void *)LLFilePicker::FFLOAD_IMAGE); - if (!filename.empty()) - { - LLFloaterReg::showInstance("upload_image", LLSD(filename)); - } - return TRUE; - } -}; - -class LLFileUploadModel : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) LLFloaterReg::getInstance("upload_model"); - if (fmp) - { - fmp->loadModel(3); - } - - return TRUE; - } -}; - -class LLFileUploadSound : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - std::string filename = upload_pick((void*)LLFilePicker::FFLOAD_WAV); - if (!filename.empty()) - { - LLFloaterReg::showInstance("upload_sound", LLSD(filename)); - } - return true; - } -}; - -class LLFileUploadAnim : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - const std::string filename = upload_pick((void*)LLFilePicker::FFLOAD_ANIM); - if (!filename.empty()) - { - LLFloaterReg::showInstance("upload_anim", LLSD(filename)); - } - return true; - } -}; - -class LLFileUploadBulk : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - if( gAgentCamera.cameraMouselook() ) - { - gAgentCamera.changeCameraToDefault(); - } - - // TODO: - // Iterate over all files - // Check extensions for uploadability, cost - // Check user balance for entire cost - // Charge user entire cost - // Loop, uploading - // If an upload fails, refund the user for that one - // - // Also fix single upload to charge first, then refund - - LLFilePicker& picker = LLFilePicker::instance(); - if (picker.getMultipleOpenFiles()) - { - const std::string& filename = picker.getFirstFile(); - std::string name = gDirUtilp->getBaseFileName(filename, true); - - std::string asset_name = name; - LLStringUtil::replaceNonstandardASCII( asset_name, '?' ); - LLStringUtil::replaceChar(asset_name, '|', '?'); - LLStringUtil::stripNonprintable(asset_name); - LLStringUtil::trim(asset_name); - - std::string display_name = LLStringUtil::null; - LLAssetStorage::LLStoreAssetCallback callback = NULL; - S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); - void *userdata = NULL; - - upload_new_resource( - filename, - asset_name, - asset_name, - 0, - LLFolderType::FT_NONE, - LLInventoryType::IT_NONE, - LLFloaterPerms::getNextOwnerPerms(), - LLFloaterPerms::getGroupPerms(), - LLFloaterPerms::getEveryonePerms(), - display_name, - callback, - expected_upload_cost, - userdata); - - // *NOTE: Ew, we don't iterate over the file list here, - // we handle the next files in upload_done_callback() - } - else - { - llinfos << "Couldn't import objects from file" << llendl; - } - return true; - } -}; - -void upload_error(const std::string& error_message, const std::string& label, const std::string& filename, const LLSD& args) -{ - llwarns << error_message << llendl; - LLNotificationsUtil::add(label, args); - if(LLFile::remove(filename) == -1) - { - lldebugs << "unable to remove temp file" << llendl; - } - LLFilePicker::instance().reset(); -} - -class LLFileEnableCloseWindow : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = NULL != LLFloater::getClosableFloaterFromFocus(); - return new_value; - } -}; - -class LLFileCloseWindow : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLFloater::closeFocusedFloater(); - - return true; - } -}; - -class LLFileEnableCloseAllWindows : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool open_children = gFloaterView->allChildrenClosed(); - return !open_children; - } -}; - -class LLFileCloseAllWindows : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool app_quitting = false; - gFloaterView->closeAllChildren(app_quitting); - - return true; - } -}; - -class LLFileTakeSnapshotToDisk : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLPointer<LLImageRaw> raw = new LLImageRaw; - - S32 width = gViewerWindow->getWindowWidthRaw(); - S32 height = gViewerWindow->getWindowHeightRaw(); - - if (gSavedSettings.getBOOL("HighResSnapshot")) - { - width *= 2; - height *= 2; - } - - if (gViewerWindow->rawSnapshot(raw, - width, - height, - TRUE, - FALSE, - gSavedSettings.getBOOL("RenderUIInSnapshot"), - FALSE)) - { - gViewerWindow->playSnapshotAnimAndSound(); - - LLPointer<LLImageFormatted> formatted = new LLImagePNG; - formatted->enableOverSize() ; - formatted->encode(raw, 0); - formatted->disableOverSize() ; - gViewerWindow->saveImageNumbered(formatted); - } - return true; - } -}; - -class LLFileQuit : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLAppViewer::instance()->userQuit(); - return true; - } -}; - - -void handle_compress_image(void*) -{ - LLFilePicker& picker = LLFilePicker::instance(); - if (picker.getMultipleOpenFiles(LLFilePicker::FFLOAD_IMAGE)) - { - std::string infile = picker.getFirstFile(); - while (!infile.empty()) - { - std::string outfile = infile + ".j2c"; - - llinfos << "Input: " << infile << llendl; - llinfos << "Output: " << outfile << llendl; - - BOOL success; - - success = LLViewerTextureList::createUploadFile(infile, outfile, IMG_CODEC_TGA); - - if (success) - { - llinfos << "Compression complete" << llendl; - } - else - { - llinfos << "Compression failed: " << LLImage::getLastError() << llendl; - } - - infile = picker.getNextFile(); - } - } -} - -LLUUID upload_new_resource( - const std::string& src_filename, - std::string name, - std::string desc, - S32 compression_info, - LLFolderType::EType destination_folder_type, - LLInventoryType::EType inv_type, - U32 next_owner_perms, - U32 group_perms, - U32 everyone_perms, - const std::string& display_name, - LLAssetStorage::LLStoreAssetCallback callback, - S32 expected_upload_cost, - void *userdata) -{ - // Generate the temporary UUID. - std::string filename = gDirUtilp->getTempFilename(); - LLTransactionID tid; - LLAssetID uuid; - - LLSD args; - - std::string exten = gDirUtilp->getExtension(src_filename); - U32 codec = LLImageBase::getCodecFromExtension(exten); - LLAssetType::EType asset_type = LLAssetType::AT_NONE; - std::string error_message; - - BOOL error = FALSE; - - if (exten.empty()) - { - std::string short_name = gDirUtilp->getBaseFileName(filename); - - // No extension - error_message = llformat( - "No file extension for the file: '%s'\nPlease make sure the file has a correct file extension", - short_name.c_str()); - args["FILE"] = short_name; - upload_error(error_message, "NoFileExtension", filename, args); - return LLUUID(); - } - else if (codec != IMG_CODEC_INVALID) - { - // It's an image file, the upload procedure is the same for all - asset_type = LLAssetType::AT_TEXTURE; - if (!LLViewerTextureList::createUploadFile(src_filename, filename, codec )) - { - error_message = llformat( "Problem with file %s:\n\n%s\n", - src_filename.c_str(), LLImage::getLastError().c_str()); - args["FILE"] = src_filename; - args["ERROR"] = LLImage::getLastError(); - upload_error(error_message, "ProblemWithFile", filename, args); - return LLUUID(); - } - } - else if(exten == "wav") - { - asset_type = LLAssetType::AT_SOUND; // tag it as audio - S32 encode_result = 0; - - llinfos << "Attempting to encode wav as an ogg file" << llendl; - - encode_result = encode_vorbis_file(src_filename, filename); - - if (LLVORBISENC_NOERR != encode_result) - { - switch(encode_result) - { - case LLVORBISENC_DEST_OPEN_ERR: - error_message = llformat( "Couldn't open temporary compressed sound file for writing: %s\n", filename.c_str()); - args["FILE"] = filename; - upload_error(error_message, "CannotOpenTemporarySoundFile", filename, args); - break; - - default: - error_message = llformat("Unknown vorbis encode failure on: %s\n", src_filename.c_str()); - args["FILE"] = src_filename; - upload_error(error_message, "UnknownVorbisEncodeFailure", filename, args); - break; - } - return LLUUID(); - } - } - else if(exten == "tmp") - { - // This is a generic .lin resource file - asset_type = LLAssetType::AT_OBJECT; - LLFILE* in = LLFile::fopen(src_filename, "rb"); /* Flawfinder: ignore */ - if (in) - { - // read in the file header - char buf[16384]; /* Flawfinder: ignore */ - size_t readbytes; - S32 version; - if (fscanf(in, "LindenResource\nversion %d\n", &version)) - { - if (2 == version) - { - // *NOTE: This buffer size is hard coded into scanf() below. - char label[MAX_STRING]; /* Flawfinder: ignore */ - char value[MAX_STRING]; /* Flawfinder: ignore */ - S32 tokens_read; - while (fgets(buf, 1024, in)) - { - label[0] = '\0'; - value[0] = '\0'; - tokens_read = sscanf( /* Flawfinder: ignore */ - buf, - "%254s %254s\n", - label, value); - - llinfos << "got: " << label << " = " << value - << llendl; - - if (EOF == tokens_read) - { - fclose(in); - error_message = llformat("corrupt resource file: %s", src_filename.c_str()); - args["FILE"] = src_filename; - upload_error(error_message, "CorruptResourceFile", filename, args); - return LLUUID(); - } - - if (2 == tokens_read) - { - if (! strcmp("type", label)) - { - asset_type = (LLAssetType::EType)(atoi(value)); - } - } - else - { - if (! strcmp("_DATA_", label)) - { - // below is the data section - break; - } - } - // other values are currently discarded - } - - } - else - { - fclose(in); - error_message = llformat("unknown linden resource file version in file: %s", src_filename.c_str()); - args["FILE"] = src_filename; - upload_error(error_message, "UnknownResourceFileVersion", filename, args); - return LLUUID(); - } - } - else - { - // this is an original binary formatted .lin file - // start over at the beginning of the file - fseek(in, 0, SEEK_SET); - - const S32 MAX_ASSET_DESCRIPTION_LENGTH = 256; - const S32 MAX_ASSET_NAME_LENGTH = 64; - S32 header_size = 34 + MAX_ASSET_DESCRIPTION_LENGTH + MAX_ASSET_NAME_LENGTH; - S16 type_num; - - // read in and throw out most of the header except for the type - if (fread(buf, header_size, 1, in) != 1) - { - llwarns << "Short read" << llendl; - } - memcpy(&type_num, buf + 16, sizeof(S16)); /* Flawfinder: ignore */ - asset_type = (LLAssetType::EType)type_num; - } - - // copy the file's data segment into another file for uploading - LLFILE* out = LLFile::fopen(filename, "wb"); /* Flawfinder: ignore */ - if (out) - { - while((readbytes = fread(buf, 1, 16384, in))) /* Flawfinder: ignore */ - { - if (fwrite(buf, 1, readbytes, out) != readbytes) - { - llwarns << "Short write" << llendl; - } - } - fclose(out); - } - else - { - fclose(in); - error_message = llformat( "Unable to create output file: %s", filename.c_str()); - args["FILE"] = filename; - upload_error(error_message, "UnableToCreateOutputFile", filename, args); - return LLUUID(); - } - - fclose(in); - } - else - { - llinfos << "Couldn't open .lin file " << src_filename << llendl; - } - } - else if (exten == "bvh") - { - error_message = llformat("We do not currently support bulk upload of animation files\n"); - upload_error(error_message, "DoNotSupportBulkAnimationUpload", filename, args); - return LLUUID(); - } - else - { - // Unknown extension - error_message = llformat(LLTrans::getString("UnknownFileExtension").c_str(), exten.c_str()); - error = TRUE;; - } - - // gen a new transaction ID for this asset - tid.generate(); - - if (!error) - { - uuid = tid.makeAssetID(gAgent.getSecureSessionID()); - // copy this file into the vfs for upload - S32 file_size; - LLAPRFile infile ; - infile.open(filename, LL_APR_RB, NULL, &file_size); - if (infile.getFileHandle()) - { - LLVFile file(gVFS, uuid, asset_type, LLVFile::WRITE); - - file.setMaxSize(file_size); - - const S32 buf_size = 65536; - U8 copy_buf[buf_size]; - while ((file_size = infile.read(copy_buf, buf_size))) - { - file.write(copy_buf, file_size); - } - } - else - { - error_message = llformat( "Unable to access output file: %s", filename.c_str()); - error = TRUE; - } - } - - if (!error) - { - std::string t_disp_name = display_name; - if (t_disp_name.empty()) - { - t_disp_name = src_filename; - } - upload_new_resource( - tid, - asset_type, - name, - desc, - compression_info, // tid - destination_folder_type, - inv_type, - next_owner_perms, - group_perms, - everyone_perms, - display_name, - callback, - expected_upload_cost, - userdata); - } - else - { - llwarns << error_message << llendl; - LLSD args; - args["ERROR_MESSAGE"] = error_message; - LLNotificationsUtil::add("ErrorMessage", args); - if(LLFile::remove(filename) == -1) - { - lldebugs << "unable to remove temp file" << llendl; - } - LLFilePicker::instance().reset(); - } - - return uuid; -} - -void upload_done_callback( - const LLUUID& uuid, - void* user_data, - S32 result, - LLExtStat ext_status) // StoreAssetData callback (fixed) -{ - LLResourceData* data = (LLResourceData*)user_data; - S32 expected_upload_cost = data ? data->mExpectedUploadCost : 0; - //LLAssetType::EType pref_loc = data->mPreferredLocation; - BOOL is_balance_sufficient = TRUE; - - if(data) - { - if (result >= 0) - { - LLFolderType::EType dest_loc = (data->mPreferredLocation == LLFolderType::FT_NONE) ? LLFolderType::assetTypeToFolderType(data->mAssetInfo.mType) : data->mPreferredLocation; - - if (LLAssetType::AT_SOUND == data->mAssetInfo.mType || - LLAssetType::AT_TEXTURE == data->mAssetInfo.mType || - LLAssetType::AT_ANIMATION == data->mAssetInfo.mType) - { - // Charge the user for the upload. - LLViewerRegion* region = gAgent.getRegion(); - - if(!(can_afford_transaction(expected_upload_cost))) - { - LLStringUtil::format_map_t args; - args["NAME"] = data->mAssetInfo.getName(); - args["AMOUNT"] = llformat("%d", expected_upload_cost); - LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("UploadingCosts", args), expected_upload_cost ); - is_balance_sufficient = FALSE; - } - else if(region) - { - // Charge user for upload - gStatusBar->debitBalance(expected_upload_cost); - - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_MoneyTransferRequest); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_MoneyData); - msg->addUUIDFast(_PREHASH_SourceID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_DestID, LLUUID::null); - msg->addU8("Flags", 0); - // we tell the sim how much we were expecting to pay so it - // can respond to any discrepancy - msg->addS32Fast(_PREHASH_Amount, expected_upload_cost); - msg->addU8Fast(_PREHASH_AggregatePermNextOwner, (U8)LLAggregatePermissions::AP_EMPTY); - msg->addU8Fast(_PREHASH_AggregatePermInventory, (U8)LLAggregatePermissions::AP_EMPTY); - msg->addS32Fast(_PREHASH_TransactionType, TRANS_UPLOAD_CHARGE); - msg->addStringFast(_PREHASH_Description, NULL); - msg->sendReliable(region->getHost()); - } - } - - if(is_balance_sufficient) - { - // Actually add the upload to inventory - llinfos << "Adding " << uuid << " to inventory." << llendl; - const LLUUID folder_id = gInventory.findCategoryUUIDForType(dest_loc); - if(folder_id.notNull()) - { - U32 next_owner_perms = data->mNextOwnerPerm; - if(PERM_NONE == next_owner_perms) - { - next_owner_perms = PERM_MOVE | PERM_TRANSFER; - } - create_inventory_item(gAgent.getID(), gAgent.getSessionID(), - folder_id, data->mAssetInfo.mTransactionID, data->mAssetInfo.getName(), - data->mAssetInfo.getDescription(), data->mAssetInfo.mType, - data->mInventoryType, NOT_WEARABLE, next_owner_perms, - LLPointer<LLInventoryCallback>(NULL)); - } - else - { - llwarns << "Can't find a folder to put it in" << llendl; - } - } - } - else // if(result >= 0) - { - LLSD args; - args["FILE"] = LLInventoryType::lookupHumanReadable(data->mInventoryType); - args["REASON"] = std::string(LLAssetStorage::getErrorString(result)); - LLNotificationsUtil::add("CannotUploadReason", args); - } - } - - LLUploadDialog::modalUploadFinished(); - delete data; - data = NULL; - - // *NOTE: This is a pretty big hack. What this does is check the - // file picker if there are any more pending uploads. If so, - // upload that file. - const std::string& next_file = LLFilePicker::instance().getNextFile(); - if(is_balance_sufficient && !next_file.empty()) - { - std::string asset_name = gDirUtilp->getBaseFileName(next_file, true); - LLStringUtil::replaceNonstandardASCII( asset_name, '?' ); - LLStringUtil::replaceChar(asset_name, '|', '?'); - LLStringUtil::stripNonprintable(asset_name); - LLStringUtil::trim(asset_name); - - std::string display_name = LLStringUtil::null; - LLAssetStorage::LLStoreAssetCallback callback = NULL; - void *userdata = NULL; - upload_new_resource( - next_file, - asset_name, - asset_name, // file - 0, - LLFolderType::FT_NONE, - LLInventoryType::IT_NONE, - PERM_NONE, - PERM_NONE, - PERM_NONE, - display_name, - callback, - expected_upload_cost, // assuming next in a group of uploads is of roughly the same type, i.e. same upload cost - userdata); - } -} - -static LLAssetID upload_new_resource_prep( - const LLTransactionID& tid, - LLAssetType::EType asset_type, - LLInventoryType::EType& inventory_type, - std::string& name, - const std::string& display_name, - std::string& description) -{ - LLAssetID uuid = generate_asset_id_for_new_upload(tid); - - increase_new_upload_stats(asset_type); - - assign_defaults_and_show_upload_message( - asset_type, - inventory_type, - name, - display_name, - description); - - return uuid; -} - -LLSD generate_new_resource_upload_capability_body( - LLAssetType::EType asset_type, - const std::string& name, - const std::string& desc, - LLFolderType::EType destination_folder_type, - LLInventoryType::EType inv_type, - U32 next_owner_perms, - U32 group_perms, - U32 everyone_perms) -{ - LLSD body; - - body["folder_id"] = gInventory.findCategoryUUIDForType( - (destination_folder_type == LLFolderType::FT_NONE) ? - (LLFolderType::EType) asset_type : - destination_folder_type); - - body["asset_type"] = LLAssetType::lookup(asset_type); - body["inventory_type"] = LLInventoryType::lookup(inv_type); - body["name"] = name; - body["description"] = desc; - body["next_owner_mask"] = LLSD::Integer(next_owner_perms); - body["group_mask"] = LLSD::Integer(group_perms); - body["everyone_mask"] = LLSD::Integer(everyone_perms); - - return body; -} - -void upload_new_resource( - const LLTransactionID &tid, - LLAssetType::EType asset_type, - std::string name, - std::string desc, - S32 compression_info, - LLFolderType::EType destination_folder_type, - LLInventoryType::EType inv_type, - U32 next_owner_perms, - U32 group_perms, - U32 everyone_perms, - const std::string& display_name, - LLAssetStorage::LLStoreAssetCallback callback, - S32 expected_upload_cost, - void *userdata) -{ - if(gDisconnected) - { - return ; - } - - LLAssetID uuid = - upload_new_resource_prep( - tid, - asset_type, - inv_type, - name, - display_name, - desc); - - if( LLAssetType::AT_SOUND == asset_type ) - { - LLViewerStats::getInstance()->incStat(LLViewerStats::ST_UPLOAD_SOUND_COUNT ); - } - else - if( LLAssetType::AT_TEXTURE == asset_type ) - { - LLViewerStats::getInstance()->incStat(LLViewerStats::ST_UPLOAD_TEXTURE_COUNT ); - } - else - if( LLAssetType::AT_ANIMATION == asset_type) - { - LLViewerStats::getInstance()->incStat(LLViewerStats::ST_UPLOAD_ANIM_COUNT ); - } - - if(LLInventoryType::IT_NONE == inv_type) - { - inv_type = LLInventoryType::defaultForAssetType(asset_type); - } - LLStringUtil::stripNonprintable(name); - LLStringUtil::stripNonprintable(desc); - if(name.empty()) - { - name = "(No Name)"; - } - if(desc.empty()) - { - desc = "(No Description)"; - } - - // At this point, we're ready for the upload. - std::string upload_message = "Uploading...\n\n"; - upload_message.append(display_name); - LLUploadDialog::modalUploadDialog(upload_message); - - llinfos << "*** Uploading: " << llendl; - llinfos << "Type: " << LLAssetType::lookup(asset_type) << llendl; - llinfos << "UUID: " << uuid << llendl; - llinfos << "Name: " << name << llendl; - llinfos << "Desc: " << desc << llendl; - llinfos << "Expected Upload Cost: " << expected_upload_cost << llendl; - lldebugs << "Folder: " << gInventory.findCategoryUUIDForType((destination_folder_type == LLFolderType::FT_NONE) ? LLFolderType::assetTypeToFolderType(asset_type) : destination_folder_type) << llendl; - lldebugs << "Asset Type: " << LLAssetType::lookup(asset_type) << llendl; - - std::string url = gAgent.getRegion()->getCapability( - "NewFileAgentInventory"); - - if ( !url.empty() ) - { - llinfos << "New Agent Inventory via capability" << llendl; - - LLSD body; - body = generate_new_resource_upload_capability_body( - asset_type, - name, - desc, - destination_folder_type, - inv_type, - next_owner_perms, - group_perms, - everyone_perms); - - LLHTTPClient::post( - url, - body, - new LLNewAgentInventoryResponder( - body, - uuid, - asset_type)); - } - else - { - llinfos << "NewAgentInventory capability not found, new agent inventory via asset system." << llendl; - // check for adequate funds - // TODO: do this check on the sim - if (LLAssetType::AT_SOUND == asset_type || - LLAssetType::AT_TEXTURE == asset_type || - LLAssetType::AT_ANIMATION == asset_type) - { - S32 balance = gStatusBar->getBalance(); - if (balance < expected_upload_cost) - { - // insufficient funds, bail on this upload - LLStringUtil::format_map_t args; - args["NAME"] = name; - args["AMOUNT"] = llformat("%d", expected_upload_cost); - LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("UploadingCosts", args), expected_upload_cost ); - return; - } - } - - LLResourceData* data = new LLResourceData; - data->mAssetInfo.mTransactionID = tid; - data->mAssetInfo.mUuid = uuid; - data->mAssetInfo.mType = asset_type; - data->mAssetInfo.mCreatorID = gAgentID; - data->mInventoryType = inv_type; - data->mNextOwnerPerm = next_owner_perms; - data->mExpectedUploadCost = expected_upload_cost; - data->mUserData = userdata; - data->mAssetInfo.setName(name); - data->mAssetInfo.setDescription(desc); - data->mPreferredLocation = destination_folder_type; - - LLAssetStorage::LLStoreAssetCallback asset_callback = &upload_done_callback; - if (callback) - { - asset_callback = callback; - } - gAssetStorage->storeAssetData( - data->mAssetInfo.mTransactionID, - data->mAssetInfo.mType, - asset_callback, - (void*)data, - FALSE); - } -} - -LLAssetID generate_asset_id_for_new_upload(const LLTransactionID& tid) -{ - if ( gDisconnected ) - { - LLAssetID rv; - - rv.setNull(); - return rv; - } - - LLAssetID uuid = tid.makeAssetID(gAgent.getSecureSessionID()); - - return uuid; -} - -void increase_new_upload_stats(LLAssetType::EType asset_type) -{ - if ( LLAssetType::AT_SOUND == asset_type ) - { - LLViewerStats::getInstance()->incStat( - LLViewerStats::ST_UPLOAD_SOUND_COUNT ); - } - else if ( LLAssetType::AT_TEXTURE == asset_type ) - { - LLViewerStats::getInstance()->incStat( - LLViewerStats::ST_UPLOAD_TEXTURE_COUNT ); - } - else if ( LLAssetType::AT_ANIMATION == asset_type ) - { - LLViewerStats::getInstance()->incStat( - LLViewerStats::ST_UPLOAD_ANIM_COUNT ); - } -} - -void assign_defaults_and_show_upload_message( - LLAssetType::EType asset_type, - LLInventoryType::EType& inventory_type, - std::string& name, - const std::string& display_name, - std::string& description) -{ - if ( LLInventoryType::IT_NONE == inventory_type ) - { - inventory_type = LLInventoryType::defaultForAssetType(asset_type); - } - LLStringUtil::stripNonprintable(name); - LLStringUtil::stripNonprintable(description); - - if ( name.empty() ) - { - name = "(No Name)"; - } - if ( description.empty() ) - { - description = "(No Description)"; - } - - // At this point, we're ready for the upload. - std::string upload_message = "Uploading...\n\n"; - upload_message.append(display_name); - LLUploadDialog::modalUploadDialog(upload_message); -} - - -void init_menu_file() -{ - view_listener_t::addCommit(new LLFileUploadImage(), "File.UploadImage"); - view_listener_t::addCommit(new LLFileUploadSound(), "File.UploadSound"); - view_listener_t::addCommit(new LLFileUploadAnim(), "File.UploadAnim"); - view_listener_t::addCommit(new LLFileUploadModel(), "File.UploadModel"); - view_listener_t::addCommit(new LLFileUploadBulk(), "File.UploadBulk"); - view_listener_t::addCommit(new LLFileCloseWindow(), "File.CloseWindow"); - view_listener_t::addCommit(new LLFileCloseAllWindows(), "File.CloseAllWindows"); - view_listener_t::addEnable(new LLFileEnableCloseWindow(), "File.EnableCloseWindow"); - view_listener_t::addEnable(new LLFileEnableCloseAllWindows(), "File.EnableCloseAllWindows"); - view_listener_t::addCommit(new LLFileTakeSnapshotToDisk(), "File.TakeSnapshotToDisk"); - view_listener_t::addCommit(new LLFileQuit(), "File.Quit"); - - view_listener_t::addEnable(new LLFileEnableUpload(), "File.EnableUpload"); - view_listener_t::addEnable(new LLFileEnableUploadModel(), "File.EnableUploadModel"); - view_listener_t::addMenu(new LLMeshEnabled(), "File.MeshEnabled"); - view_listener_t::addMenu(new LLMeshUploadVisible(), "File.VisibleUploadModel"); - - // "File.SaveTexture" moved to llpanelmaininventory so that it can be properly handled. -} +/**
+ * @file llviewermenufile.cpp
+ * @brief "File" menu in the main menu bar.
+ *
+ * $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 "llviewermenufile.h"
+
+// project includes
+#include "llagent.h"
+#include "llagentcamera.h"
+#include "llfilepicker.h"
+#include "llfloaterreg.h"
+#include "llbuycurrencyhtml.h"
+#include "llfloatermodelpreview.h"
+#include "llfloatersnapshot.h"
+#include "llimage.h"
+#include "llimagebmp.h"
+#include "llimagepng.h"
+#include "llimagej2c.h"
+#include "llimagejpeg.h"
+#include "llimagetga.h"
+#include "llinventorymodel.h" // gInventory
+#include "llresourcedata.h"
+#include "llfloaterperms.h"
+#include "llstatusbar.h"
+#include "llviewercontrol.h" // gSavedSettings
+#include "llviewertexturelist.h"
+#include "lluictrlfactory.h"
+#include "llvfile.h"
+#include "llvfs.h"
+#include "llviewerinventory.h"
+#include "llviewermenu.h" // gMenuHolder
+#include "llviewerparcelmgr.h"
+#include "llviewerregion.h"
+#include "llviewerstats.h"
+#include "llviewerwindow.h"
+#include "llappviewer.h"
+#include "lluploaddialog.h"
+#include "lltrans.h"
+#include "llfloaterbuycurrency.h"
+
+// linden libraries
+#include "llassetuploadresponders.h"
+#include "lleconomy.h"
+#include "llhttpclient.h"
+#include "llnotificationsutil.h"
+#include "llsdserialize.h"
+#include "llsdutil.h"
+#include "llstring.h"
+#include "lltransactiontypes.h"
+#include "lluuid.h"
+#include "llvorbisencode.h"
+#include "message.h"
+
+// system libraries
+#include <boost/tokenizer.hpp>
+
+class LLFileEnableUpload : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = gStatusBar && LLGlobalEconomy::Singleton::getInstance() && (gStatusBar->getBalance() >= LLGlobalEconomy::Singleton::getInstance()->getPriceUpload());
+ return new_value;
+ }
+};
+
+class LLFileEnableUploadModel : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ return true;
+ }
+};
+
+class LLMeshEnabled : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ return gSavedSettings.getBOOL("MeshEnabled");
+ }
+};
+
+class LLMeshUploadVisible : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ return gMeshRepo.meshUploadEnabled();
+ }
+};
+
+LLMutex* LLFilePickerThread::sMutex = NULL;
+std::queue<LLFilePickerThread*> LLFilePickerThread::sDeadQ;
+
+void LLFilePickerThread::getFile()
+{
+#if LL_WINDOWS
+ start();
+#else
+ run();
+#endif
+}
+
+//virtual
+void LLFilePickerThread::run()
+{
+ LLFilePicker picker;
+#if LL_WINDOWS
+ if (picker.getOpenFile(mFilter, false))
+ {
+ mFile = picker.getFirstFile();
+ }
+#else
+ if (picker.getOpenFile(mFilter, true))
+ {
+ mFile = picker.getFirstFile();
+ }
+#endif
+
+ {
+ LLMutexLock lock(sMutex);
+ sDeadQ.push(this);
+ }
+
+}
+
+//static
+void LLFilePickerThread::initClass()
+{
+ sMutex = new LLMutex(NULL);
+}
+
+//static
+void LLFilePickerThread::cleanupClass()
+{
+ clearDead();
+
+ delete sMutex;
+ sMutex = NULL;
+}
+
+//static
+void LLFilePickerThread::clearDead()
+{
+ if (!sDeadQ.empty())
+ {
+ LLMutexLock lock(sMutex);
+ while (!sDeadQ.empty())
+ {
+ LLFilePickerThread* thread = sDeadQ.front();
+ thread->notify(thread->mFile);
+ delete thread;
+ sDeadQ.pop();
+ }
+ }
+}
+
+
+//============================================================================
+
+#if LL_WINDOWS
+static std::string SOUND_EXTENSIONS = "wav";
+static std::string IMAGE_EXTENSIONS = "tga bmp jpg jpeg png";
+static std::string ANIM_EXTENSIONS = "bvh";
+#ifdef _CORY_TESTING
+static std::string GEOMETRY_EXTENSIONS = "slg";
+#endif
+static std::string XML_EXTENSIONS = "xml";
+static std::string SLOBJECT_EXTENSIONS = "slobject";
+#endif
+static std::string ALL_FILE_EXTENSIONS = "*.*";
+static std::string MODEL_EXTENSIONS = "dae";
+
+std::string build_extensions_string(LLFilePicker::ELoadFilter filter)
+{
+ switch(filter)
+ {
+#if LL_WINDOWS
+ case LLFilePicker::FFLOAD_IMAGE:
+ return IMAGE_EXTENSIONS;
+ case LLFilePicker::FFLOAD_WAV:
+ return SOUND_EXTENSIONS;
+ case LLFilePicker::FFLOAD_ANIM:
+ return ANIM_EXTENSIONS;
+ case LLFilePicker::FFLOAD_SLOBJECT:
+ return SLOBJECT_EXTENSIONS;
+ case LLFilePicker::FFLOAD_MODEL:
+ return MODEL_EXTENSIONS;
+#ifdef _CORY_TESTING
+ case LLFilePicker::FFLOAD_GEOMETRY:
+ return GEOMETRY_EXTENSIONS;
+#endif
+ case LLFilePicker::FFLOAD_XML:
+ return XML_EXTENSIONS;
+ case LLFilePicker::FFLOAD_ALL:
+ return ALL_FILE_EXTENSIONS;
+#endif
+ default:
+ return ALL_FILE_EXTENSIONS;
+ }
+}
+
+/**
+ char* upload_pick(void* data)
+
+ If applicable, brings up a file chooser in which the user selects a file
+ to upload for a particular task. If the file is valid for the given action,
+ returns the string to the full path filename, else returns NULL.
+ Data is the load filter for the type of file as defined in LLFilePicker.
+**/
+const std::string upload_pick(void* data)
+{
+ if( gAgentCamera.cameraMouselook() )
+ {
+ gAgentCamera.changeCameraToDefault();
+ // This doesn't seem necessary. JC
+ // display();
+ }
+
+ LLFilePicker::ELoadFilter type;
+ if(data)
+ {
+ type = (LLFilePicker::ELoadFilter)((intptr_t)data);
+ }
+ else
+ {
+ type = LLFilePicker::FFLOAD_ALL;
+ }
+
+ LLFilePicker& picker = LLFilePicker::instance();
+ if (!picker.getOpenFile(type))
+ {
+ llinfos << "Couldn't import objects from file" << llendl;
+ return std::string();
+ }
+
+
+ const std::string& filename = picker.getFirstFile();
+ std::string ext = gDirUtilp->getExtension(filename);
+
+ //strincmp doesn't like NULL pointers
+ if (ext.empty())
+ {
+ std::string short_name = gDirUtilp->getBaseFileName(filename);
+
+ // No extension
+ LLSD args;
+ args["FILE"] = short_name;
+ LLNotificationsUtil::add("NoFileExtension", args);
+ return std::string();
+ }
+ else
+ {
+ //so there is an extension
+ //loop over the valid extensions and compare to see
+ //if the extension is valid
+
+ //now grab the set of valid file extensions
+ std::string valid_extensions = build_extensions_string(type);
+
+ BOOL ext_valid = FALSE;
+
+ typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
+ boost::char_separator<char> sep(" ");
+ tokenizer tokens(valid_extensions, sep);
+ tokenizer::iterator token_iter;
+
+ //now loop over all valid file extensions
+ //and compare them to the extension of the file
+ //to be uploaded
+ for( token_iter = tokens.begin();
+ token_iter != tokens.end() && ext_valid != TRUE;
+ ++token_iter)
+ {
+ const std::string& cur_token = *token_iter;
+
+ if (cur_token == ext || cur_token == "*.*")
+ {
+ //valid extension
+ //or the acceptable extension is any
+ ext_valid = TRUE;
+ }
+ }//end for (loop over all tokens)
+
+ if (ext_valid == FALSE)
+ {
+ //should only get here if the extension exists
+ //but is invalid
+ LLSD args;
+ args["EXTENSION"] = ext;
+ args["VALIDS"] = valid_extensions;
+ LLNotificationsUtil::add("InvalidFileExtension", args);
+ return std::string();
+ }
+ }//end else (non-null extension)
+
+ //valid file extension
+
+ //now we check to see
+ //if the file is actually a valid image/sound/etc.
+ if (type == LLFilePicker::FFLOAD_WAV)
+ {
+ // pre-qualify wavs to make sure the format is acceptable
+ std::string error_msg;
+ if (check_for_invalid_wav_formats(filename,error_msg))
+ {
+ llinfos << error_msg << ": " << filename << llendl;
+ LLSD args;
+ args["FILE"] = filename;
+ LLNotificationsUtil::add( error_msg, args );
+ return std::string();
+ }
+ }//end if a wave/sound file
+
+
+ return filename;
+}
+
+class LLFileUploadImage : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string filename = upload_pick((void *)LLFilePicker::FFLOAD_IMAGE);
+ if (!filename.empty())
+ {
+ LLFloaterReg::showInstance("upload_image", LLSD(filename));
+ }
+ return TRUE;
+ }
+};
+
+class LLFileUploadModel : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) LLFloaterReg::getInstance("upload_model");
+ if (fmp)
+ {
+ fmp->loadModel(3);
+ }
+
+ return TRUE;
+ }
+};
+
+class LLFileUploadSound : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string filename = upload_pick((void*)LLFilePicker::FFLOAD_WAV);
+ if (!filename.empty())
+ {
+ LLFloaterReg::showInstance("upload_sound", LLSD(filename));
+ }
+ return true;
+ }
+};
+
+class LLFileUploadAnim : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ const std::string filename = upload_pick((void*)LLFilePicker::FFLOAD_ANIM);
+ if (!filename.empty())
+ {
+ LLFloaterReg::showInstance("upload_anim", LLSD(filename));
+ }
+ return true;
+ }
+};
+
+class LLFileUploadBulk : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if( gAgentCamera.cameraMouselook() )
+ {
+ gAgentCamera.changeCameraToDefault();
+ }
+
+ // TODO:
+ // Iterate over all files
+ // Check extensions for uploadability, cost
+ // Check user balance for entire cost
+ // Charge user entire cost
+ // Loop, uploading
+ // If an upload fails, refund the user for that one
+ //
+ // Also fix single upload to charge first, then refund
+
+ LLFilePicker& picker = LLFilePicker::instance();
+ if (picker.getMultipleOpenFiles())
+ {
+ const std::string& filename = picker.getFirstFile();
+ std::string name = gDirUtilp->getBaseFileName(filename, true);
+
+ std::string asset_name = name;
+ LLStringUtil::replaceNonstandardASCII( asset_name, '?' );
+ LLStringUtil::replaceChar(asset_name, '|', '?');
+ LLStringUtil::stripNonprintable(asset_name);
+ LLStringUtil::trim(asset_name);
+
+ std::string display_name = LLStringUtil::null;
+ LLAssetStorage::LLStoreAssetCallback callback = NULL;
+ S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
+ void *userdata = NULL;
+
+ upload_new_resource(
+ filename,
+ asset_name,
+ asset_name,
+ 0,
+ LLFolderType::FT_NONE,
+ LLInventoryType::IT_NONE,
+ LLFloaterPerms::getNextOwnerPerms(),
+ LLFloaterPerms::getGroupPerms(),
+ LLFloaterPerms::getEveryonePerms(),
+ display_name,
+ callback,
+ expected_upload_cost,
+ userdata);
+
+ // *NOTE: Ew, we don't iterate over the file list here,
+ // we handle the next files in upload_done_callback()
+ }
+ else
+ {
+ llinfos << "Couldn't import objects from file" << llendl;
+ }
+ return true;
+ }
+};
+
+void upload_error(const std::string& error_message, const std::string& label, const std::string& filename, const LLSD& args)
+{
+ llwarns << error_message << llendl;
+ LLNotificationsUtil::add(label, args);
+ if(LLFile::remove(filename) == -1)
+ {
+ lldebugs << "unable to remove temp file" << llendl;
+ }
+ LLFilePicker::instance().reset();
+}
+
+class LLFileEnableCloseWindow : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = NULL != LLFloater::getClosableFloaterFromFocus();
+ return new_value;
+ }
+};
+
+class LLFileCloseWindow : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLFloater::closeFocusedFloater();
+
+ return true;
+ }
+};
+
+class LLFileEnableCloseAllWindows : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool open_children = gFloaterView->allChildrenClosed();
+ return !open_children;
+ }
+};
+
+class LLFileCloseAllWindows : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool app_quitting = false;
+ gFloaterView->closeAllChildren(app_quitting);
+
+ return true;
+ }
+};
+
+class LLFileTakeSnapshotToDisk : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLPointer<LLImageRaw> raw = new LLImageRaw;
+
+ S32 width = gViewerWindow->getWindowWidthRaw();
+ S32 height = gViewerWindow->getWindowHeightRaw();
+
+ if (gSavedSettings.getBOOL("HighResSnapshot"))
+ {
+ width *= 2;
+ height *= 2;
+ }
+
+ if (gViewerWindow->rawSnapshot(raw,
+ width,
+ height,
+ TRUE,
+ FALSE,
+ gSavedSettings.getBOOL("RenderUIInSnapshot"),
+ FALSE))
+ {
+ gViewerWindow->playSnapshotAnimAndSound();
+
+ LLPointer<LLImageFormatted> formatted = new LLImagePNG;
+ formatted->enableOverSize() ;
+ formatted->encode(raw, 0);
+ formatted->disableOverSize() ;
+ gViewerWindow->saveImageNumbered(formatted);
+ }
+ return true;
+ }
+};
+
+class LLFileQuit : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLAppViewer::instance()->userQuit();
+ return true;
+ }
+};
+
+
+void handle_compress_image(void*)
+{
+ LLFilePicker& picker = LLFilePicker::instance();
+ if (picker.getMultipleOpenFiles(LLFilePicker::FFLOAD_IMAGE))
+ {
+ std::string infile = picker.getFirstFile();
+ while (!infile.empty())
+ {
+ std::string outfile = infile + ".j2c";
+
+ llinfos << "Input: " << infile << llendl;
+ llinfos << "Output: " << outfile << llendl;
+
+ BOOL success;
+
+ success = LLViewerTextureList::createUploadFile(infile, outfile, IMG_CODEC_TGA);
+
+ if (success)
+ {
+ llinfos << "Compression complete" << llendl;
+ }
+ else
+ {
+ llinfos << "Compression failed: " << LLImage::getLastError() << llendl;
+ }
+
+ infile = picker.getNextFile();
+ }
+ }
+}
+
+LLUUID upload_new_resource(
+ const std::string& src_filename,
+ std::string name,
+ std::string desc,
+ S32 compression_info,
+ LLFolderType::EType destination_folder_type,
+ LLInventoryType::EType inv_type,
+ U32 next_owner_perms,
+ U32 group_perms,
+ U32 everyone_perms,
+ const std::string& display_name,
+ LLAssetStorage::LLStoreAssetCallback callback,
+ S32 expected_upload_cost,
+ void *userdata)
+{
+ // Generate the temporary UUID.
+ std::string filename = gDirUtilp->getTempFilename();
+ LLTransactionID tid;
+ LLAssetID uuid;
+
+ LLSD args;
+
+ std::string exten = gDirUtilp->getExtension(src_filename);
+ U32 codec = LLImageBase::getCodecFromExtension(exten);
+ LLAssetType::EType asset_type = LLAssetType::AT_NONE;
+ std::string error_message;
+
+ BOOL error = FALSE;
+
+ if (exten.empty())
+ {
+ std::string short_name = gDirUtilp->getBaseFileName(filename);
+
+ // No extension
+ error_message = llformat(
+ "No file extension for the file: '%s'\nPlease make sure the file has a correct file extension",
+ short_name.c_str());
+ args["FILE"] = short_name;
+ upload_error(error_message, "NoFileExtension", filename, args);
+ return LLUUID();
+ }
+ else if (codec != IMG_CODEC_INVALID)
+ {
+ // It's an image file, the upload procedure is the same for all
+ asset_type = LLAssetType::AT_TEXTURE;
+ if (!LLViewerTextureList::createUploadFile(src_filename, filename, codec ))
+ {
+ error_message = llformat( "Problem with file %s:\n\n%s\n",
+ src_filename.c_str(), LLImage::getLastError().c_str());
+ args["FILE"] = src_filename;
+ args["ERROR"] = LLImage::getLastError();
+ upload_error(error_message, "ProblemWithFile", filename, args);
+ return LLUUID();
+ }
+ }
+ else if(exten == "wav")
+ {
+ asset_type = LLAssetType::AT_SOUND; // tag it as audio
+ S32 encode_result = 0;
+
+ llinfos << "Attempting to encode wav as an ogg file" << llendl;
+
+ encode_result = encode_vorbis_file(src_filename, filename);
+
+ if (LLVORBISENC_NOERR != encode_result)
+ {
+ switch(encode_result)
+ {
+ case LLVORBISENC_DEST_OPEN_ERR:
+ error_message = llformat( "Couldn't open temporary compressed sound file for writing: %s\n", filename.c_str());
+ args["FILE"] = filename;
+ upload_error(error_message, "CannotOpenTemporarySoundFile", filename, args);
+ break;
+
+ default:
+ error_message = llformat("Unknown vorbis encode failure on: %s\n", src_filename.c_str());
+ args["FILE"] = src_filename;
+ upload_error(error_message, "UnknownVorbisEncodeFailure", filename, args);
+ break;
+ }
+ return LLUUID();
+ }
+ }
+ else if(exten == "tmp")
+ {
+ // This is a generic .lin resource file
+ asset_type = LLAssetType::AT_OBJECT;
+ LLFILE* in = LLFile::fopen(src_filename, "rb"); /* Flawfinder: ignore */
+ if (in)
+ {
+ // read in the file header
+ char buf[16384]; /* Flawfinder: ignore */
+ size_t readbytes;
+ S32 version;
+ if (fscanf(in, "LindenResource\nversion %d\n", &version))
+ {
+ if (2 == version)
+ {
+ // *NOTE: This buffer size is hard coded into scanf() below.
+ char label[MAX_STRING]; /* Flawfinder: ignore */
+ char value[MAX_STRING]; /* Flawfinder: ignore */
+ S32 tokens_read;
+ while (fgets(buf, 1024, in))
+ {
+ label[0] = '\0';
+ value[0] = '\0';
+ tokens_read = sscanf( /* Flawfinder: ignore */
+ buf,
+ "%254s %254s\n",
+ label, value);
+
+ llinfos << "got: " << label << " = " << value
+ << llendl;
+
+ if (EOF == tokens_read)
+ {
+ fclose(in);
+ error_message = llformat("corrupt resource file: %s", src_filename.c_str());
+ args["FILE"] = src_filename;
+ upload_error(error_message, "CorruptResourceFile", filename, args);
+ return LLUUID();
+ }
+
+ if (2 == tokens_read)
+ {
+ if (! strcmp("type", label))
+ {
+ asset_type = (LLAssetType::EType)(atoi(value));
+ }
+ }
+ else
+ {
+ if (! strcmp("_DATA_", label))
+ {
+ // below is the data section
+ break;
+ }
+ }
+ // other values are currently discarded
+ }
+
+ }
+ else
+ {
+ fclose(in);
+ error_message = llformat("unknown linden resource file version in file: %s", src_filename.c_str());
+ args["FILE"] = src_filename;
+ upload_error(error_message, "UnknownResourceFileVersion", filename, args);
+ return LLUUID();
+ }
+ }
+ else
+ {
+ // this is an original binary formatted .lin file
+ // start over at the beginning of the file
+ fseek(in, 0, SEEK_SET);
+
+ const S32 MAX_ASSET_DESCRIPTION_LENGTH = 256;
+ const S32 MAX_ASSET_NAME_LENGTH = 64;
+ S32 header_size = 34 + MAX_ASSET_DESCRIPTION_LENGTH + MAX_ASSET_NAME_LENGTH;
+ S16 type_num;
+
+ // read in and throw out most of the header except for the type
+ if (fread(buf, header_size, 1, in) != 1)
+ {
+ llwarns << "Short read" << llendl;
+ }
+ memcpy(&type_num, buf + 16, sizeof(S16)); /* Flawfinder: ignore */
+ asset_type = (LLAssetType::EType)type_num;
+ }
+
+ // copy the file's data segment into another file for uploading
+ LLFILE* out = LLFile::fopen(filename, "wb"); /* Flawfinder: ignore */
+ if (out)
+ {
+ while((readbytes = fread(buf, 1, 16384, in))) /* Flawfinder: ignore */
+ {
+ if (fwrite(buf, 1, readbytes, out) != readbytes)
+ {
+ llwarns << "Short write" << llendl;
+ }
+ }
+ fclose(out);
+ }
+ else
+ {
+ fclose(in);
+ error_message = llformat( "Unable to create output file: %s", filename.c_str());
+ args["FILE"] = filename;
+ upload_error(error_message, "UnableToCreateOutputFile", filename, args);
+ return LLUUID();
+ }
+
+ fclose(in);
+ }
+ else
+ {
+ llinfos << "Couldn't open .lin file " << src_filename << llendl;
+ }
+ }
+ else if (exten == "bvh")
+ {
+ error_message = llformat("We do not currently support bulk upload of animation files\n");
+ upload_error(error_message, "DoNotSupportBulkAnimationUpload", filename, args);
+ return LLUUID();
+ }
+ else
+ {
+ // Unknown extension
+ error_message = llformat(LLTrans::getString("UnknownFileExtension").c_str(), exten.c_str());
+ error = TRUE;;
+ }
+
+ // gen a new transaction ID for this asset
+ tid.generate();
+
+ if (!error)
+ {
+ uuid = tid.makeAssetID(gAgent.getSecureSessionID());
+ // copy this file into the vfs for upload
+ S32 file_size;
+ LLAPRFile infile ;
+ infile.open(filename, LL_APR_RB, NULL, &file_size);
+ if (infile.getFileHandle())
+ {
+ LLVFile file(gVFS, uuid, asset_type, LLVFile::WRITE);
+
+ file.setMaxSize(file_size);
+
+ const S32 buf_size = 65536;
+ U8 copy_buf[buf_size];
+ while ((file_size = infile.read(copy_buf, buf_size)))
+ {
+ file.write(copy_buf, file_size);
+ }
+ }
+ else
+ {
+ error_message = llformat( "Unable to access output file: %s", filename.c_str());
+ error = TRUE;
+ }
+ }
+
+ if (!error)
+ {
+ std::string t_disp_name = display_name;
+ if (t_disp_name.empty())
+ {
+ t_disp_name = src_filename;
+ }
+ upload_new_resource(
+ tid,
+ asset_type,
+ name,
+ desc,
+ compression_info, // tid
+ destination_folder_type,
+ inv_type,
+ next_owner_perms,
+ group_perms,
+ everyone_perms,
+ display_name,
+ callback,
+ expected_upload_cost,
+ userdata);
+ }
+ else
+ {
+ llwarns << error_message << llendl;
+ LLSD args;
+ args["ERROR_MESSAGE"] = error_message;
+ LLNotificationsUtil::add("ErrorMessage", args);
+ if(LLFile::remove(filename) == -1)
+ {
+ lldebugs << "unable to remove temp file" << llendl;
+ }
+ LLFilePicker::instance().reset();
+ }
+
+ return uuid;
+}
+
+void upload_done_callback(
+ const LLUUID& uuid,
+ void* user_data,
+ S32 result,
+ LLExtStat ext_status) // StoreAssetData callback (fixed)
+{
+ LLResourceData* data = (LLResourceData*)user_data;
+ S32 expected_upload_cost = data ? data->mExpectedUploadCost : 0;
+ //LLAssetType::EType pref_loc = data->mPreferredLocation;
+ BOOL is_balance_sufficient = TRUE;
+
+ if(data)
+ {
+ if (result >= 0)
+ {
+ LLFolderType::EType dest_loc = (data->mPreferredLocation == LLFolderType::FT_NONE) ? LLFolderType::assetTypeToFolderType(data->mAssetInfo.mType) : data->mPreferredLocation;
+
+ if (LLAssetType::AT_SOUND == data->mAssetInfo.mType ||
+ LLAssetType::AT_TEXTURE == data->mAssetInfo.mType ||
+ LLAssetType::AT_ANIMATION == data->mAssetInfo.mType)
+ {
+ // Charge the user for the upload.
+ LLViewerRegion* region = gAgent.getRegion();
+
+ if(!(can_afford_transaction(expected_upload_cost)))
+ {
+ LLStringUtil::format_map_t args;
+ args["NAME"] = data->mAssetInfo.getName();
+ args["AMOUNT"] = llformat("%d", expected_upload_cost);
+ LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("UploadingCosts", args), expected_upload_cost );
+ is_balance_sufficient = FALSE;
+ }
+ else if(region)
+ {
+ // Charge user for upload
+ gStatusBar->debitBalance(expected_upload_cost);
+
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_MoneyTransferRequest);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_MoneyData);
+ msg->addUUIDFast(_PREHASH_SourceID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_DestID, LLUUID::null);
+ msg->addU8("Flags", 0);
+ // we tell the sim how much we were expecting to pay so it
+ // can respond to any discrepancy
+ msg->addS32Fast(_PREHASH_Amount, expected_upload_cost);
+ msg->addU8Fast(_PREHASH_AggregatePermNextOwner, (U8)LLAggregatePermissions::AP_EMPTY);
+ msg->addU8Fast(_PREHASH_AggregatePermInventory, (U8)LLAggregatePermissions::AP_EMPTY);
+ msg->addS32Fast(_PREHASH_TransactionType, TRANS_UPLOAD_CHARGE);
+ msg->addStringFast(_PREHASH_Description, NULL);
+ msg->sendReliable(region->getHost());
+ }
+ }
+
+ if(is_balance_sufficient)
+ {
+ // Actually add the upload to inventory
+ llinfos << "Adding " << uuid << " to inventory." << llendl;
+ const LLUUID folder_id = gInventory.findCategoryUUIDForType(dest_loc);
+ if(folder_id.notNull())
+ {
+ U32 next_owner_perms = data->mNextOwnerPerm;
+ if(PERM_NONE == next_owner_perms)
+ {
+ next_owner_perms = PERM_MOVE | PERM_TRANSFER;
+ }
+ create_inventory_item(gAgent.getID(), gAgent.getSessionID(),
+ folder_id, data->mAssetInfo.mTransactionID, data->mAssetInfo.getName(),
+ data->mAssetInfo.getDescription(), data->mAssetInfo.mType,
+ data->mInventoryType, NOT_WEARABLE, next_owner_perms,
+ LLPointer<LLInventoryCallback>(NULL));
+ }
+ else
+ {
+ llwarns << "Can't find a folder to put it in" << llendl;
+ }
+ }
+ }
+ else // if(result >= 0)
+ {
+ LLSD args;
+ args["FILE"] = LLInventoryType::lookupHumanReadable(data->mInventoryType);
+ args["REASON"] = std::string(LLAssetStorage::getErrorString(result));
+ LLNotificationsUtil::add("CannotUploadReason", args);
+ }
+ }
+
+ LLUploadDialog::modalUploadFinished();
+ delete data;
+ data = NULL;
+
+ // *NOTE: This is a pretty big hack. What this does is check the
+ // file picker if there are any more pending uploads. If so,
+ // upload that file.
+ const std::string& next_file = LLFilePicker::instance().getNextFile();
+ if(is_balance_sufficient && !next_file.empty())
+ {
+ std::string asset_name = gDirUtilp->getBaseFileName(next_file, true);
+ LLStringUtil::replaceNonstandardASCII( asset_name, '?' );
+ LLStringUtil::replaceChar(asset_name, '|', '?');
+ LLStringUtil::stripNonprintable(asset_name);
+ LLStringUtil::trim(asset_name);
+
+ std::string display_name = LLStringUtil::null;
+ LLAssetStorage::LLStoreAssetCallback callback = NULL;
+ void *userdata = NULL;
+ upload_new_resource(
+ next_file,
+ asset_name,
+ asset_name, // file
+ 0,
+ LLFolderType::FT_NONE,
+ LLInventoryType::IT_NONE,
+ PERM_NONE,
+ PERM_NONE,
+ PERM_NONE,
+ display_name,
+ callback,
+ expected_upload_cost, // assuming next in a group of uploads is of roughly the same type, i.e. same upload cost
+ userdata);
+ }
+}
+
+static LLAssetID upload_new_resource_prep(
+ const LLTransactionID& tid,
+ LLAssetType::EType asset_type,
+ LLInventoryType::EType& inventory_type,
+ std::string& name,
+ const std::string& display_name,
+ std::string& description)
+{
+ LLAssetID uuid = generate_asset_id_for_new_upload(tid);
+
+ increase_new_upload_stats(asset_type);
+
+ assign_defaults_and_show_upload_message(
+ asset_type,
+ inventory_type,
+ name,
+ display_name,
+ description);
+
+ return uuid;
+}
+
+LLSD generate_new_resource_upload_capability_body(
+ LLAssetType::EType asset_type,
+ const std::string& name,
+ const std::string& desc,
+ LLFolderType::EType destination_folder_type,
+ LLInventoryType::EType inv_type,
+ U32 next_owner_perms,
+ U32 group_perms,
+ U32 everyone_perms)
+{
+ LLSD body;
+
+ body["folder_id"] = gInventory.findCategoryUUIDForType(
+ (destination_folder_type == LLFolderType::FT_NONE) ?
+ (LLFolderType::EType) asset_type :
+ destination_folder_type);
+
+ body["asset_type"] = LLAssetType::lookup(asset_type);
+ body["inventory_type"] = LLInventoryType::lookup(inv_type);
+ body["name"] = name;
+ body["description"] = desc;
+ body["next_owner_mask"] = LLSD::Integer(next_owner_perms);
+ body["group_mask"] = LLSD::Integer(group_perms);
+ body["everyone_mask"] = LLSD::Integer(everyone_perms);
+
+ return body;
+}
+
+void upload_new_resource(
+ const LLTransactionID &tid,
+ LLAssetType::EType asset_type,
+ std::string name,
+ std::string desc,
+ S32 compression_info,
+ LLFolderType::EType destination_folder_type,
+ LLInventoryType::EType inv_type,
+ U32 next_owner_perms,
+ U32 group_perms,
+ U32 everyone_perms,
+ const std::string& display_name,
+ LLAssetStorage::LLStoreAssetCallback callback,
+ S32 expected_upload_cost,
+ void *userdata)
+{
+ if(gDisconnected)
+ {
+ return ;
+ }
+
+ LLAssetID uuid =
+ upload_new_resource_prep(
+ tid,
+ asset_type,
+ inv_type,
+ name,
+ display_name,
+ desc);
+
+ if( LLAssetType::AT_SOUND == asset_type )
+ {
+ LLViewerStats::getInstance()->incStat(LLViewerStats::ST_UPLOAD_SOUND_COUNT );
+ }
+ else
+ if( LLAssetType::AT_TEXTURE == asset_type )
+ {
+ LLViewerStats::getInstance()->incStat(LLViewerStats::ST_UPLOAD_TEXTURE_COUNT );
+ }
+ else
+ if( LLAssetType::AT_ANIMATION == asset_type)
+ {
+ LLViewerStats::getInstance()->incStat(LLViewerStats::ST_UPLOAD_ANIM_COUNT );
+ }
+
+ if(LLInventoryType::IT_NONE == inv_type)
+ {
+ inv_type = LLInventoryType::defaultForAssetType(asset_type);
+ }
+ LLStringUtil::stripNonprintable(name);
+ LLStringUtil::stripNonprintable(desc);
+ if(name.empty())
+ {
+ name = "(No Name)";
+ }
+ if(desc.empty())
+ {
+ desc = "(No Description)";
+ }
+
+ // At this point, we're ready for the upload.
+ std::string upload_message = "Uploading...\n\n";
+ upload_message.append(display_name);
+ LLUploadDialog::modalUploadDialog(upload_message);
+
+ llinfos << "*** Uploading: " << llendl;
+ llinfos << "Type: " << LLAssetType::lookup(asset_type) << llendl;
+ llinfos << "UUID: " << uuid << llendl;
+ llinfos << "Name: " << name << llendl;
+ llinfos << "Desc: " << desc << llendl;
+ llinfos << "Expected Upload Cost: " << expected_upload_cost << llendl;
+ lldebugs << "Folder: " << gInventory.findCategoryUUIDForType((destination_folder_type == LLFolderType::FT_NONE) ? LLFolderType::assetTypeToFolderType(asset_type) : destination_folder_type) << llendl;
+ lldebugs << "Asset Type: " << LLAssetType::lookup(asset_type) << llendl;
+
+ std::string url = gAgent.getRegion()->getCapability(
+ "NewFileAgentInventory");
+
+ if ( !url.empty() )
+ {
+ llinfos << "New Agent Inventory via capability" << llendl;
+
+ LLSD body;
+ body = generate_new_resource_upload_capability_body(
+ asset_type,
+ name,
+ desc,
+ destination_folder_type,
+ inv_type,
+ next_owner_perms,
+ group_perms,
+ everyone_perms);
+
+ LLHTTPClient::post(
+ url,
+ body,
+ new LLNewAgentInventoryResponder(
+ body,
+ uuid,
+ asset_type));
+ }
+ else
+ {
+ llinfos << "NewAgentInventory capability not found, new agent inventory via asset system." << llendl;
+ // check for adequate funds
+ // TODO: do this check on the sim
+ if (LLAssetType::AT_SOUND == asset_type ||
+ LLAssetType::AT_TEXTURE == asset_type ||
+ LLAssetType::AT_ANIMATION == asset_type)
+ {
+ S32 balance = gStatusBar->getBalance();
+ if (balance < expected_upload_cost)
+ {
+ // insufficient funds, bail on this upload
+ LLStringUtil::format_map_t args;
+ args["NAME"] = name;
+ args["AMOUNT"] = llformat("%d", expected_upload_cost);
+ LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("UploadingCosts", args), expected_upload_cost );
+ return;
+ }
+ }
+
+ LLResourceData* data = new LLResourceData;
+ data->mAssetInfo.mTransactionID = tid;
+ data->mAssetInfo.mUuid = uuid;
+ data->mAssetInfo.mType = asset_type;
+ data->mAssetInfo.mCreatorID = gAgentID;
+ data->mInventoryType = inv_type;
+ data->mNextOwnerPerm = next_owner_perms;
+ data->mExpectedUploadCost = expected_upload_cost;
+ data->mUserData = userdata;
+ data->mAssetInfo.setName(name);
+ data->mAssetInfo.setDescription(desc);
+ data->mPreferredLocation = destination_folder_type;
+
+ LLAssetStorage::LLStoreAssetCallback asset_callback = &upload_done_callback;
+ if (callback)
+ {
+ asset_callback = callback;
+ }
+ gAssetStorage->storeAssetData(
+ data->mAssetInfo.mTransactionID,
+ data->mAssetInfo.mType,
+ asset_callback,
+ (void*)data,
+ FALSE);
+ }
+}
+
+LLAssetID generate_asset_id_for_new_upload(const LLTransactionID& tid)
+{
+ if ( gDisconnected )
+ {
+ LLAssetID rv;
+
+ rv.setNull();
+ return rv;
+ }
+
+ LLAssetID uuid = tid.makeAssetID(gAgent.getSecureSessionID());
+
+ return uuid;
+}
+
+void increase_new_upload_stats(LLAssetType::EType asset_type)
+{
+ if ( LLAssetType::AT_SOUND == asset_type )
+ {
+ LLViewerStats::getInstance()->incStat(
+ LLViewerStats::ST_UPLOAD_SOUND_COUNT );
+ }
+ else if ( LLAssetType::AT_TEXTURE == asset_type )
+ {
+ LLViewerStats::getInstance()->incStat(
+ LLViewerStats::ST_UPLOAD_TEXTURE_COUNT );
+ }
+ else if ( LLAssetType::AT_ANIMATION == asset_type )
+ {
+ LLViewerStats::getInstance()->incStat(
+ LLViewerStats::ST_UPLOAD_ANIM_COUNT );
+ }
+}
+
+void assign_defaults_and_show_upload_message(
+ LLAssetType::EType asset_type,
+ LLInventoryType::EType& inventory_type,
+ std::string& name,
+ const std::string& display_name,
+ std::string& description)
+{
+ if ( LLInventoryType::IT_NONE == inventory_type )
+ {
+ inventory_type = LLInventoryType::defaultForAssetType(asset_type);
+ }
+ LLStringUtil::stripNonprintable(name);
+ LLStringUtil::stripNonprintable(description);
+
+ if ( name.empty() )
+ {
+ name = "(No Name)";
+ }
+ if ( description.empty() )
+ {
+ description = "(No Description)";
+ }
+
+ // At this point, we're ready for the upload.
+ std::string upload_message = "Uploading...\n\n";
+ upload_message.append(display_name);
+ LLUploadDialog::modalUploadDialog(upload_message);
+}
+
+
+void init_menu_file()
+{
+ view_listener_t::addCommit(new LLFileUploadImage(), "File.UploadImage");
+ view_listener_t::addCommit(new LLFileUploadSound(), "File.UploadSound");
+ view_listener_t::addCommit(new LLFileUploadAnim(), "File.UploadAnim");
+ view_listener_t::addCommit(new LLFileUploadModel(), "File.UploadModel");
+ view_listener_t::addCommit(new LLFileUploadBulk(), "File.UploadBulk");
+ view_listener_t::addCommit(new LLFileCloseWindow(), "File.CloseWindow");
+ view_listener_t::addCommit(new LLFileCloseAllWindows(), "File.CloseAllWindows");
+ view_listener_t::addEnable(new LLFileEnableCloseWindow(), "File.EnableCloseWindow");
+ view_listener_t::addEnable(new LLFileEnableCloseAllWindows(), "File.EnableCloseAllWindows");
+ view_listener_t::addCommit(new LLFileTakeSnapshotToDisk(), "File.TakeSnapshotToDisk");
+ view_listener_t::addCommit(new LLFileQuit(), "File.Quit");
+
+ view_listener_t::addEnable(new LLFileEnableUpload(), "File.EnableUpload");
+ view_listener_t::addEnable(new LLFileEnableUploadModel(), "File.EnableUploadModel");
+ view_listener_t::addMenu(new LLMeshEnabled(), "File.MeshEnabled");
+ view_listener_t::addMenu(new LLMeshUploadVisible(), "File.VisibleUploadModel");
+
+ // "File.SaveTexture" moved to llpanelmaininventory so that it can be properly handled.
+}
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 3c6770df43..8905efed75 100755 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -4715,7 +4715,7 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data) LLViewerObject* object = gObjectList.findObject(object_id); if (object) { - object->mFlags |= FLAGS_ANIM_SOURCE; + object->setFlags(FLAGS_ANIM_SOURCE, TRUE); BOOL anim_found = FALSE; LLVOAvatar::AnimSourceIterator anim_it = avatarp->mAnimationSources.find(object_id); @@ -4862,7 +4862,7 @@ void process_set_follow_cam_properties(LLMessageSystem *mesgsys, void **user_dat LLViewerObject* objectp = gObjectList.findObject(source_id); if (objectp) { - objectp->mFlags |= FLAGS_CAMERA_SOURCE; + objectp->setFlags(FLAGS_CAMERA_SOURCE, TRUE); } S32 num_objects = mesgsys->getNumberOfBlocks("CameraProperty"); diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 37fb77a10a..330cf51b3e 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -443,7 +443,7 @@ void LLViewerObject::dump() const /* llinfos << "Velocity: " << getVelocity() << llendl; llinfos << "AnyOwner: " << permAnyOwner() << " YouOwner: " << permYouOwner() << " Edit: " << mPermEdit << llendl; - llinfos << "UsePhysics: " << usePhysics() << " CanSelect " << mbCanSelect << " UserSelected " << mUserSelected << llendl; + llinfos << "UsePhysics: " << flagUsePhysics() << " CanSelect " << mbCanSelect << " UserSelected " << mUserSelected << llendl; llinfos << "AppAngle: " << mAppAngle << llendl; llinfos << "PixelArea: " << mPixelArea << llendl; @@ -5123,7 +5123,7 @@ BOOL LLViewerObject::permAnyOwner() const { if (isRootEdit()) { - return ((mFlags & FLAGS_OBJECT_ANY_OWNER) != 0); + return flagObjectAnyOwner(); } else { @@ -5145,7 +5145,7 @@ BOOL LLViewerObject::permYouOwner() const return TRUE; } # endif - return ((mFlags & FLAGS_OBJECT_YOU_OWNER) != 0); + return flagObjectYouOwner(); #endif } else @@ -5159,7 +5159,7 @@ BOOL LLViewerObject::permGroupOwner() const { if (isRootEdit()) { - return ((mFlags & FLAGS_OBJECT_GROUP_OWNED) != 0); + return flagObjectGroupOwned(); } else { @@ -5182,7 +5182,7 @@ BOOL LLViewerObject::permOwnerModify() const return TRUE; } # endif - return ((mFlags & FLAGS_OBJECT_OWNER_MODIFY) != 0); + return flagObjectOwnerModify(); #endif } else @@ -5206,7 +5206,7 @@ BOOL LLViewerObject::permModify() const return TRUE; } # endif - return ((mFlags & FLAGS_OBJECT_MODIFY) != 0); + return flagObjectModify(); #endif } else @@ -5230,7 +5230,7 @@ BOOL LLViewerObject::permCopy() const return TRUE; } # endif - return ((mFlags & FLAGS_OBJECT_COPY) != 0); + return flagObjectCopy(); #endif } else @@ -5254,7 +5254,7 @@ BOOL LLViewerObject::permMove() const return TRUE; } # endif - return ((mFlags & FLAGS_OBJECT_MOVE) != 0); + return flagObjectMove(); #endif } else @@ -5278,7 +5278,7 @@ BOOL LLViewerObject::permTransfer() const return TRUE; } # endif - return ((mFlags & FLAGS_OBJECT_TRANSFER) != 0); + return flagObjectTransfer(); #endif } else @@ -5323,19 +5323,12 @@ void LLViewerObject::markForUpdate(BOOL priority) bool LLViewerObject::getIncludeInSearch() const { - return ((mFlags & FLAGS_INCLUDE_IN_SEARCH) != 0); + return flagIncludeInSearch(); } void LLViewerObject::setIncludeInSearch(bool include_in_search) { - if (include_in_search) - { - mFlags |= FLAGS_INCLUDE_IN_SEARCH; - } - else - { - mFlags &= ~FLAGS_INCLUDE_IN_SEARCH; - } + setFlags(FLAGS_INCLUDE_IN_SEARCH, include_in_search); } void LLViewerObject::setRegion(LLViewerRegion *regionp) @@ -5374,8 +5367,8 @@ void LLViewerObject::updateRegion(LLViewerRegion *regionp) bool LLViewerObject::specialHoverCursor() const { - return (mFlags & FLAGS_USE_PHYSICS) - || (mFlags & FLAGS_HANDLE_TOUCH) + return flagUsePhysics() + || flagHandleTouch() || (mClickAction != 0); } @@ -5388,10 +5381,15 @@ void LLViewerObject::updateFlags(BOOL physics_changed) gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, getLocalID() ); - gMessageSystem->addBOOLFast(_PREHASH_UsePhysics, usePhysics() ); + gMessageSystem->addBOOLFast(_PREHASH_UsePhysics, flagUsePhysics() ); gMessageSystem->addBOOL("IsTemporary", flagTemporaryOnRez() ); gMessageSystem->addBOOL("IsPhantom", flagPhantom() ); - gMessageSystem->addBOOL("CastsShadows", flagCastShadows() ); + + // stinson 02/28/2012 : This CastsShadows BOOL is no longer used in either the viewer or the simulator + // The simulator code does not even unpack this value when the message is received. + // This could be potentially hijacked in the future for another use should the urgent need arise. + gMessageSystem->addBOOL("CastsShadows", FALSE ); + if (physics_changed) { gMessageSystem->nextBlock("ExtraPhysics"); diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index c8152e1539..63215942ac 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -468,20 +468,28 @@ public: BOOL permCopy() const; BOOL permMove() const; BOOL permTransfer() const; - inline BOOL usePhysics() const { return ((mFlags & FLAGS_USE_PHYSICS) != 0); } + inline BOOL flagUsePhysics() const { return ((mFlags & FLAGS_USE_PHYSICS) != 0); } + inline BOOL flagObjectAnyOwner() const { return ((mFlags & FLAGS_OBJECT_ANY_OWNER) != 0); } + inline BOOL flagObjectYouOwner() const { return ((mFlags & FLAGS_OBJECT_YOU_OWNER) != 0); } + inline BOOL flagObjectGroupOwned() const { return ((mFlags & FLAGS_OBJECT_GROUP_OWNED) != 0); } + inline BOOL flagObjectOwnerModify() const { return ((mFlags & FLAGS_OBJECT_OWNER_MODIFY) != 0); } + inline BOOL flagObjectModify() const { return ((mFlags & FLAGS_OBJECT_MODIFY) != 0); } + inline BOOL flagObjectCopy() const { return ((mFlags & FLAGS_OBJECT_COPY) != 0); } + inline BOOL flagObjectMove() const { return ((mFlags & FLAGS_OBJECT_MOVE) != 0); } + inline BOOL flagObjectTransfer() const { return ((mFlags & FLAGS_OBJECT_TRANSFER) != 0); } + inline BOOL flagObjectPermanent() const { return ((mFlags & FLAGS_OBJECT_PERMANENT) != 0); } + inline BOOL flagCharacter() const { return ((mFlags & FLAGS_CHARACTER) != 0); } + inline BOOL flagIncludeInSearch() const { return ((mFlags & FLAGS_INCLUDE_IN_SEARCH) != 0); } inline BOOL flagScripted() const { return ((mFlags & FLAGS_SCRIPTED) != 0); } inline BOOL flagHandleTouch() const { return ((mFlags & FLAGS_HANDLE_TOUCH) != 0); } inline BOOL flagTakesMoney() const { return ((mFlags & FLAGS_TAKES_MONEY) != 0); } inline BOOL flagPhantom() const { return ((mFlags & FLAGS_PHANTOM) != 0); } inline BOOL flagInventoryEmpty() const { return ((mFlags & FLAGS_INVENTORY_EMPTY) != 0); } - inline BOOL flagCastShadows() const { return ((mFlags & FLAGS_CAST_SHADOWS) != 0); } inline BOOL flagAllowInventoryAdd() const { return ((mFlags & FLAGS_ALLOW_INVENTORY_DROP) != 0); } - inline BOOL flagTemporary() const { return ((mFlags & FLAGS_TEMPORARY) != 0); } inline BOOL flagTemporaryOnRez() const { return ((mFlags & FLAGS_TEMPORARY_ON_REZ) != 0); } inline BOOL flagAnimSource() const { return ((mFlags & FLAGS_ANIM_SOURCE) != 0); } inline BOOL flagCameraSource() const { return ((mFlags & FLAGS_CAMERA_SOURCE) != 0); } inline BOOL flagCameraDecoupled() const { return ((mFlags & FLAGS_CAMERA_DECOUPLED) != 0); } - inline BOOL flagObjectMove() const { return ((mFlags & FLAGS_OBJECT_MOVE) != 0); } U8 getPhysicsShapeType() const; inline F32 getPhysicsGravity() const { return mPhysicsGravity; } @@ -595,9 +603,11 @@ public: U32 mGLName; // GL "name" used by selection code BOOL mbCanSelect; // true if user can select this object by clicking +private: // Grabbed from UPDATE_FLAGS U32 mFlags; +public: // Sent to sim in UPDATE_FLAGS, received in ObjectPhysicsProperties U8 mPhysicsShapeType; F32 mPhysicsGravity; diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 6912faa9ec..6dedf0a2fe 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -385,9 +385,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, } else if (compressed) { - U8 compbuffer[2048]; S32 uncompressed_length = 2048; - S32 compressed_length; compressed_dp.reset(); U32 flags = 0; @@ -396,24 +394,9 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, i); } - // I don't think we ever use this flag from the server. DK 2010/12/09 - if (flags & FLAGS_ZLIB_COMPRESSED) - { - //llinfos << "TEST: flags & FLAGS_ZLIB_COMPRESSED" << llendl; - compressed_length = mesgsys->getSizeFast(_PREHASH_ObjectData, i, _PREHASH_Data); - mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_Data, compbuffer, 0, i); - uncompressed_length = 2048; - uncompress(compressed_dpbuffer, (unsigned long *)&uncompressed_length, - compbuffer, compressed_length); - compressed_dp.assignBuffer(compressed_dpbuffer, uncompressed_length); - } - else - { - uncompressed_length = mesgsys->getSizeFast(_PREHASH_ObjectData, i, _PREHASH_Data); - mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_Data, compressed_dpbuffer, 0, i); - compressed_dp.assignBuffer(compressed_dpbuffer, uncompressed_length); - } - + uncompressed_length = mesgsys->getSizeFast(_PREHASH_ObjectData, i, _PREHASH_Data); + mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_Data, compressed_dpbuffer, 0, i); + compressed_dp.assignBuffer(compressed_dpbuffer, uncompressed_length); if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only? { diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index e3cb985ddb..6e422a5821 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -1489,8 +1489,10 @@ void LLViewerRegion::unpackRegionHandshake() void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) { + capabilityNames.append("AgentPreferences"); capabilityNames.append("AttachmentResources"); capabilityNames.append("AvatarPickerSearch"); + capabilityNames.append("CharacterProperties"); capabilityNames.append("ChatSessionRequest"); capabilityNames.append("CopyInventoryFromNotecard"); capabilityNames.append("CreateInventoryCategory"); @@ -1519,8 +1521,10 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) capabilityNames.append("LandResources"); capabilityNames.append("MapLayer"); capabilityNames.append("MapLayerGod"); - capabilityNames.append("MeshUploadFlag"); + capabilityNames.append("MeshUploadFlag"); + capabilityNames.append("NavMeshUpload"); capabilityNames.append("NewFileAgentInventory"); + capabilityNames.append("ObjectNavMeshProperties"); capabilityNames.append("ParcelPropertiesUpdate"); capabilityNames.append("ParcelMediaURLFilterList"); capabilityNames.append("ParcelNavigateMedia"); @@ -1530,6 +1534,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) capabilityNames.append("RemoteParcelRequest"); capabilityNames.append("RequestTextureDownload"); capabilityNames.append("ResourceCostSelected"); + capabilityNames.append("RetrieveNavMeshSrc"); capabilityNames.append("SearchStatRequest"); capabilityNames.append("SearchStatTracking"); capabilityNames.append("SendPostcard"); @@ -1541,6 +1546,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) capabilityNames.append("SetDisplayName"); capabilityNames.append("SimConsoleAsync"); capabilityNames.append("StartGroupProposal"); + capabilityNames.append("TerrainNavMeshProperties"); capabilityNames.append("TextureStats"); capabilityNames.append("UntrustedSimulatorMessage"); capabilityNames.append("UpdateAgentInformation"); @@ -1555,7 +1561,6 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) capabilityNames.append("ViewerMetrics"); capabilityNames.append("ViewerStartAuction"); capabilityNames.append("ViewerStats"); - // Please add new capabilities alphabetically to reduce // merge conflicts. } @@ -1794,7 +1799,10 @@ void LLViewerRegion::getNeighboringRegions( std::vector<LLViewerRegion*>& unique { mImpl->mLandp->getNeighboringRegions( uniqueRegions ); } - +void LLViewerRegion::getNeighboringRegionsStatus( std::vector<S32>& regions ) +{ + mImpl->mLandp->getNeighboringRegionsStatus( regions ); +} void LLViewerRegion::showReleaseNotes() { std::string url = this->getCapability("ServerReleaseNotes"); diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index c483c6ef52..6004165b0e 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -325,6 +325,7 @@ public: bool objectsCrossParcel(const std::vector<LLBBox>& boxes) const; void getNeighboringRegions( std::vector<LLViewerRegion*>& uniqueRegions ); + void getNeighboringRegionsStatus( std::vector<S32>& regions ); public: struct CompareDistance diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index e0653fec30..2d837b3df8 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -203,6 +203,8 @@ #include "llwindowlistener.h" #include "llviewerwindowlistener.h" #include "llpaneltopinfobar.h" +#include "LLPathingLib.h" +#include "llfloaterpathfindingconsole.h" #if LL_WINDOWS #include <tchar.h> // For Unicode conversion methods @@ -836,6 +838,7 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK x = llround((F32)x / mDisplayScale.mV[VX]); y = llround((F32)y / mDisplayScale.mV[VY]); + // only send mouse clicks to UI if UI is visible if(gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) { @@ -949,13 +952,26 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK } } + //Determine if we have a pathing system and subsequently provide any mouse input + if (LLPathingLib::getInstance() != NULL) + { + LLHandle<LLFloaterPathfindingConsole> pathfindingConsoleHandle = LLFloaterPathfindingConsole::getInstanceHandle(); + if (!pathfindingConsoleHandle.isDead()) + { + LLFloaterPathfindingConsole *pathfindingConsoleFloater = pathfindingConsoleHandle.get(); + if (pathfindingConsoleFloater->isGeneratePathMode(mask, clicktype, down)) + { + return pathfindingConsoleFloater->handleAnyMouseClick(x, y, mask, clicktype, down); + } + } + } + // Do not allow tool manager to handle mouseclicks if we have disconnected if(!gDisconnected && LLToolMgr::getInstance()->getCurrentTool()->handleAnyMouseClick( x, y, mask, clicktype, down ) ) { return TRUE; } - // If we got this far on a down-click, it wasn't handled. // Up-clicks, though, are always handled as far as the OS is concerned. BOOL default_rtn = !down; diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index e525d6bad0..15786b5dd0 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -758,7 +758,7 @@ void LLVOAvatarSelf::stopMotionFromSource(const LLUUID& source_id) LLViewerObject* object = gObjectList.findObject(source_id); if (object) { - object->mFlags &= ~FLAGS_ANIM_SOURCE; + object->setFlags(FLAGS_ANIM_SOURCE, FALSE); } } diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index c523a78b22..70cf09caca 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -104,7 +104,7 @@ #include "lltoolpie.h" #include "llcurl.h" #include "llnotifications.h" - +#include "LLPathingLib.h" #ifdef _DEBUG // Debug indices is disabled for now for debug performance - djs 4/24/02 @@ -3203,7 +3203,7 @@ void renderPhysicalBeacons(LLDrawable* drawablep) if (vobj && !vobj->isAvatar() //&& !vobj->getParent() - && vobj->usePhysics()) + && vobj->flagUsePhysics()) { if (gPipeline.sRenderBeacons) { @@ -3792,6 +3792,7 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate) gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sDefaultImagep); LLViewerFetchedTexture::sDefaultImagep->setAddressMode(LLTexUnit::TAM_WRAP); + ////////////////////////////////////////////// // // Actually render all of the geometry @@ -6217,6 +6218,10 @@ void LLPipeline::resetVertexBuffers() gSky.resetVertexBuffers(); + if ( LLPathingLib::getInstance() ) + { + LLPathingLib::getInstance()->cleanupVBOManger(); + } LLVertexBuffer::cleanupClass(); //delete all name pool caches @@ -6805,7 +6810,7 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield) mFXAABuffer.bindTexture(0, channel); gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); } - + gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft; gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom; gGLViewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth(); @@ -7457,7 +7462,7 @@ void LLPipeline::renderDeferredLighting() F32 s = volume->getLightRadius()*1.5f; LLColor3 col = volume->getLightColor(); - + if (col.magVecSquared() < 0.001f) { continue; @@ -7570,7 +7575,7 @@ void LLPipeline::renderDeferredLighting() 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 @@ -7679,7 +7684,7 @@ void LLPipeline::renderDeferredLighting() setupSpotLight(gDeferredMultiSpotLightProgram, drawablep); LLColor3 col = volume->getLightColor(); - + gDeferredMultiSpotLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, tc.v); gDeferredMultiSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s*s); gDeferredMultiSpotLightProgram.uniform3fv(LLShaderMgr::DIFFUSE_COLOR, 1, col.mV); @@ -8155,6 +8160,7 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in) gGL.setColorMask(true, false); renderGeom(camera); + } LLPipeline::sUnderWaterRender = FALSE; diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index e4a8622a4b..ee8b7ba082 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -138,7 +138,11 @@ with the same filename but different name <texture name="Command_MiniMap_Icon" file_name="toolbar_icons/mini_map.png" preload="true" /> <texture name="Command_Move_Icon" file_name="toolbar_icons/move.png" preload="true" /> <texture name="Command_Outbox_Icon" file_name="toolbar_icons/outbox.png" preload="true" /> + <texture name="Command_Pathfinding_Icon" file_name="toolbar_icons/land.png" preload="true" /> <texture name="Command_People_Icon" file_name="toolbar_icons/people.png" preload="true" /> + <texture name="Command_PF_Basic_Icon" file_name="toolbar_icons/land.png" preload="true" /> + <texture name="Command_PF_Characters_Icon" file_name="toolbar_icons/land.png" preload="true" /> + <texture name="Command_PF_Linksets_Icon" file_name="toolbar_icons/land.png" preload="true" /> <texture name="Command_Picks_Icon" file_name="toolbar_icons/picks.png" preload="true" /> <texture name="Command_Places_Icon" file_name="toolbar_icons/places.png" preload="true" /> <texture name="Command_Preferences_Icon" file_name="toolbar_icons/preferences.png" preload="true" /> diff --git a/indra/newview/skins/default/xui/en/floater_pathfinding_basic.xml b/indra/newview/skins/default/xui/en/floater_pathfinding_basic.xml new file mode 100644 index 0000000000..7af40bbff6 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_pathfinding_basic.xml @@ -0,0 +1,79 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + open_positioning="cascading" + can_tear_off="false" + height="213" + layout="topleft" + name="floater_pathfinding_basic" + help_topic="floater_pathfinding_basic" + reuse_instance="false" + save_rect="false" + single_instance="true" + title="Basic pathfinding setup" + width="312"> + <floater.string name="status_pathfinding_not_enabled">This region is not enabled for pathfinding.</floater.string> + <floater.string name="status_unable_to_change_state">Unable to change modes successfully.</floater.string> + <floater.string name="status_querying_state">Checking status ...</floater.string> + <text + height="13" + word_wrap="false" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + length="1" + follows="left|top" + layout="topleft" + left="15" + name="status_label" + top="8" + width="289"> + </text> + <text + height="13" + word_wrap="true" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + text_readonly_color="LabelDisabledColor" + length="1" + follows="left|top" + layout="topleft" + left="15" + name="unfreeze_label" + top_pad="4" + width="289"> + Allow object / terrain changes: + </text> + <button + follows="left|top" + height="22" + label="Unfreeze" + layout="topleft" + name="enter_unfrozen_mode" + width="116"/> + <text + height="82" + word_wrap="true" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + text_readonly_color="LabelDisabledColor" + length="1" + follows="left|top" + layout="topleft" + line_spacing.multiple="1.5" + left="15" + name="freeze_label" + top_pad="23" + width="289"> + In unfrozen mode, you can move and make changes to objects and terrain. When you are finished, click the Freeze button. It may require a few minutes to process your changes. + </text> + <button + follows="left|top" + height="22" + label="Freeze" + layout="topleft" + name="enter_frozen_mode" + top_pad="0" + width="116"/> +</floater> diff --git a/indra/newview/skins/default/xui/en/floater_pathfinding_characters.xml b/indra/newview/skins/default/xui/en/floater_pathfinding_characters.xml new file mode 100644 index 0000000000..e9d58c7a33 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_pathfinding_characters.xml @@ -0,0 +1,179 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + open_positioning="cascading" + can_resize="true" + can_tear_off="false" + height="273" + width="635" + min_height="273" + min_width="635" + layout="topleft" + name="floater_pathfinding_characters" + help_topic="floater_pathfinding_characters" + reuse_instance="true" + save_rect="false" + single_instance="true" + title="Pathfinding characters"> + <floater.string name="characters_messaging_initial"></floater.string> + <floater.string name="characters_messaging_fetch_starting">Building query for pathfinding characters ...</floater.string> + <floater.string name="characters_messaging_fetch_inprogress">Querying for pathfinding characters ...</floater.string> + <floater.string name="characters_messaging_fetch_inprogress_multi_request">Querying for pathfinding characters (already in progress) ...</floater.string> + <floater.string name="characters_messaging_fetch_received">Loading pathfinding characters data from response ...</floater.string> + <floater.string name="characters_messaging_fetch_error">Error detected while querying for pathfinding characters</floater.string> + <floater.string name="characters_messaging_complete_none_found">No pathfinding characters</floater.string> + <floater.string name="characters_messaging_complete_available">[NUM_SELECTED] characters selected out of [NUM_TOTAL]</floater.string> + <floater.string name="characters_messaging_service_not_available">Required capability is not available in current region</floater.string> + <floater.string name="character_cpu_time">[CPU_TIME] µs</floater.string> + <scroll_list + column_padding="0" + draw_heading="true" + follows="all" + height="135" + layout="topleft" + left="18" + top="10" + multi_select="true" + name="pathfinding_characters" + width="600"> + <scroll_list.columns + label="Name" + name="name" + dynamic_width="true" /> + <scroll_list.columns + label="Description" + name="description" + width="172" /> + <scroll_list.columns + label="Owner" + name="owner" + width="141" /> + <scroll_list.columns + label="CPU" + name="cpu_time" + width="60" /> + <scroll_list.columns + label="Altitude" + name="altitude" + width="64" /> + </scroll_list> + <text + height="26" + word_wrap="true" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + length="1" + follows="left|bottom" + layout="topleft" + name="characters_status" + top="161" + width="240"> + Characters: + </text> + <button + follows="right|bottom" + height="21" + label="Refresh list" + layout="topleft" + name="refresh_characters_list" + top="161" + left="257" + width="115"/> + <button + follows="right|bottom" + height="21" + label="Select all" + layout="topleft" + name="select_all_characters" + top="161" + left="378" + width="115"/> + <button + follows="right|bottom" + height="21" + label="Select none" + layout="topleft" + name="select_none_characters" + top="161" + left="502" + width="115"/> + <view_border + bevel_style="none" + follows="left|right|bottom" + height="0" + layout="topleft" + name="horiz_separator" + top="196" + left="20" + width="600"/> + <text + height="13" + word_wrap="false" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + text_readonly_color="LabelDisabledColor" + length="1" + follows="left|bottom" + layout="topleft" + name="actions_label" + top_pad="12" + width="242"> + Actions on selected characters: + </text> + <check_box + height="19" + follows="left|bottom" + label="Show beacon" + layout="topleft" + name="show_beacon" + top="208" + left="259" + width="90" /> + <button + follows="left|bottom" + height="22" + label="Take" + layout="topleft" + name="take_characters" + top="232" + left="17" + width="94"/> + <button + follows="left|bottom" + height="22" + label="Take copy" + layout="topleft" + name="take_copy_characters" + top="232" + left="119" + width="94"/> + <button + follows="left|bottom" + height="22" + label="Return" + layout="topleft" + name="return_characters" + top="233" + left="220" + width="94"/> + <button + follows="left|bottom" + height="22" + label="Delete" + layout="topleft" + name="delete_characters" + top="233" + left="322" + width="94"/> + <button + follows="left|bottom" + height="22" + label="Teleport me to it" + layout="topleft" + name="teleport_to_character" + tool_tip="Enabled only when one character is selected." + top="233" + left="420" + width="159"/> +</floater> diff --git a/indra/newview/skins/default/xui/en/floater_pathfinding_console.xml b/indra/newview/skins/default/xui/en/floater_pathfinding_console.xml new file mode 100644 index 0000000000..b608e513d5 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_pathfinding_console.xml @@ -0,0 +1,464 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + open_positioning="cascading" + can_tear_off="false" + height="352" + layout="topleft" + name="floater_pathfinding_console" + help_topic="floater_pathfinding_console" + reuse_instance="true" + save_rect="true" + single_instance="true" + title="Pathfinding edit / test" + width="456"> + <floater.string name="navmesh_fetch_initial"></floater.string> + <floater.string name="navmesh_fetch_inprogress">Downloading the navmesh ...</floater.string> + <floater.string name="navmesh_fetch_complete_available">Navmesh received.</floater.string> + <floater.string name="navmesh_fetch_complete_none">No navmesh for region.</floater.string> + <floater.string name="navmesh_region_not_enabled">This region is not enabled for pathfinding.</floater.string> + <floater.string name="navmesh_library_not_implemented">Cannot find pathing library implementation.</floater.string> + <floater.string name="pathing_choose_start_and_end_points">Please choose start and end points.</floater.string> + <floater.string name="pathing_choose_start_point">Please choose start point.</floater.string> + <floater.string name="pathing_choose_end_point">Please choose end point.</floater.string> + <floater.string name="pathing_path_valid">Path is shown in blue.</floater.string> + <text + height="13" + word_wrap="true" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + length="1" + follows="left|top" + layout="topleft" + left="15" + top="9" + width="208"> + Show: + </text> + <check_box + height="19" + label="Navmesh" + layout="topleft" + left="14" + name="show_navmesh" + top_pad="7" + width="90" /> + <text + height="13" + word_wrap="true" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + length="1" + follows="left|top" + layout="topleft" + left="35" + width="208"> + Show walkability map: + </text> + <combo_box + height="19" + layout="topleft" + left="34" + name="show_heatmap_mode" + top_pad="8" + width="156"> + <combo_box.item + label="None" + name="show_heatmap_mode_none" + value="0" /> + <combo_box.item + label="Character type A" + name="show_heatmap_mode_a" + value="1" /> + <combo_box.item + label="Character type B" + name="show_heatmap_mode_b" + value="2" /> + <combo_box.item + label="Character type C" + name="show_heatmap_mode_c" + value="3" /> + <combo_box.item + label="Character type D" + name="show_heatmap_mode_d" + value="4" /> + </combo_box> + <check_box + height="19" + label="Walkables" + layout="topleft" + left="14" + name="show_walkables" + top_pad="10" + tool_tip="Functionality is not implemented currently." + width="90" /> + <check_box + height="19" + label="Material volumes" + layout="topleft" + left="14" + name="show_material_volumes" + top_pad="4" + tool_tip="Functionality is not implemented currently." + width="90" /> + <check_box + height="19" + label="Static obstacles" + layout="topleft" + left="14" + name="show_static_obstacles" + top_pad="4" + tool_tip="Functionality is not implemented currently." + width="90" /> + <check_box + height="19" + label="Exclusion volumes" + layout="topleft" + left="14" + name="show_exclusion_volumes" + top_pad="4" + width="90" /> + <check_box + height="19" + label="World" + layout="topleft" + left="14" + name="show_world" + top_pad="4" + width="90" /> + <view_border + bevel_style="none" + follows="top|left" + layout="topleft" + left="14" + height="0" + width="200" + top_pad="12" + visible="true" /> + <panel + border="false" + bevel_style="none" + follows="left|top" + layout="topleft" + height="73" + width="200"> + <text + height="13" + word_wrap="true" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + length="1" + layout="topleft" + left="0" + top_pad="5" + width="200"> + Status + </text> + <text + height="40" + word_wrap="true" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + length="1" + follows="left|top" + layout="topleft" + left="0" + name="pathfinding_status" + top_pad="8" + width="200"> + </text> + </panel> + <view_border + bevel_style="none" + follows="top|left" + layout="topleft" + left="14" + height="0" + width="200" + top_pad="0" + visible="true" /> + <text + height="13" + word_wrap="true" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + length="1" + layout="topleft" + left="14" + top_pad="18" + width="105"> + Lost characters? + </text> + <button + follows="left|top" + height="21" + label="Characters..." + layout="topleft" + name="view_characters_floater" + left_pad="0" + width="96"/> + <view_border + bevel_style="none" + follows="top|left" + layout="topleft" + left="230" + top="35" + height="305" + width="214" + visible="true" /> + <tab_container + follows="left|top" + layout="topleft" + tab_position="top" + name="edit_test_tab_container" + left="227" + top="14" + height="327" + width="218"> + <panel + border="false" + bevel_style="none" + follows="left|top" + layout="topleft" + name="edit_panel" + left="1" + label="Edit"> + <text + word_wrap="true" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + text_readonly_color="LabelDisabledColor" + length="1" + follows="left|top" + layout="topleft" + name="unfreeze_label" + left="16" + top_pad="16" + height="13" + width="190"> + Allow object / terrain changes: + </text> + <button + follows="left|top" + height="22" + left="16" + enabled="false" + label="Unfreeze" + layout="topleft" + name="enter_unfrozen_mode" + top_pad="5" + width="116"/> + <text + word_wrap="true" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + text_readonly_color="LabelDisabledColor" + length="1" + follows="left|top" + layout="topleft" + left="16" + name="edit_linksets_label" + top_pad="23" + height="13" + width="190"> + Edit linkset attributes: + </text> + <button + follows="left|top" + height="22" + left="16" + label="Linksets..." + layout="topleft" + name="view_and_edit_linksets" + top_pad="5" + width="116"/> + <text + word_wrap="true" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + text_readonly_color="LabelDisabledColor" + length="1" + follows="left|top" + layout="topleft" + left="16" + line_spacing.multiple="1.5" + name="freeze_label" + top_pad="23" + height="26" + width="190"> + Prevent object / terrain changes and update the navmesh: + </text> + <button + follows="left|top" + height="22" + left="16" + enabled="false" + label="Freeze" + layout="topleft" + name="enter_frozen_mode" + top_pad="9" + width="116"/> + </panel> + <panel + border="false" + bevel_style="none" + follows="left|top" + layout="topleft" + left="1" + name="test_panel" + label="Test"> + <text + height="14" + word_wrap="true" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + length="1" + follows="left|top" + layout="topleft" + left="16" + top_pad="14" + width="190"> + Character width + </text> + <slider + decimal_digits="1" + height="14" + increment="0.1" + layout="topleft" + follows="left|top" + max_val="2" + min_val="0.2" + name="character_width" + top_pad="5" + value="1" + width="145" /> + <text + height="14" + word_wrap="false" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + length="1" + follows="left|top" + layout="topleft" + top_pad="-14" + left_pad="0" + width="20"> + m + </text> + <text + height="14" + word_wrap="true" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + length="1" + follows="left|top" + layout="topleft" + left_pad="-165" + top_pad="9" + width="190"> + Character type + </text> + <radio_group + follows="top|left" + height="20" + layout="topleft" + left_delta="0" + name="character_type" + top_delta="18" + value="1" + width="190"> + <radio_item + label="A" + height="14" + width="30" + value="1" + name="character_type_a"/> + <radio_item + label="B" + height="14" + width="30" + layout="topleft" + top="4" + left="50" + value="2" + name="character_type_b"/> + <radio_item + label="C" + height="14" + width="30" + layout="topleft" + top="4" + left="100" + value="3" + name="character_type_c"/> + <radio_item + label="D" + height="14" + width="30" + layout="topleft" + top="4" + left="150" + value="4" + name="character_type_d"/> + </radio_group> + <text + height="14" + word_wrap="true" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + length="1" + follows="left|top" + layout="topleft" + left_pad="-190" + top_pad="12" + width="190"> + Ctrl-click to select start point. + </text> + <text + height="14" + word_wrap="true" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + length="1" + follows="left|top" + layout="topleft" + top_pad="5" + width="190"> + Shift-click to select end point. + </text> + <text + height="14" + word_wrap="true" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + length="1" + follows="left|top" + layout="topleft" + name="path_test_status" + top_pad="11" + width="190"> + </text> + <button + follows="left|top" + height="22" + label="Clear path" + layout="topleft" + name="clear_path" + top_pad="27" + width="96"/> + </panel> + </tab_container> +</floater> diff --git a/indra/newview/skins/default/xui/en/floater_pathfinding_linksets.xml b/indra/newview/skins/default/xui/en/floater_pathfinding_linksets.xml new file mode 100644 index 0000000000..d00b85f5d7 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_pathfinding_linksets.xml @@ -0,0 +1,512 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + open_positioning="cascading" + can_resize="true" + can_tear_off="false" + height="382" + width="950" + min_height="382" + min_width="950" + layout="topleft" + name="floater_pathfinding_linksets" + help_topic="floater_pathfinding_linksets" + reuse_instance="true" + save_rect="false" + single_instance="true" + title="Pathfinding linksets"> + <floater.string name="linksets_messaging_initial"></floater.string> + <floater.string name="linksets_messaging_get_inprogress">Querying for pathfinding linksets ...</floater.string> + <floater.string name="linksets_messaging_get_error">Error detected while querying for pathfinding linksets</floater.string> + <floater.string name="linksets_messaging_set_inprogress">Modifying selected pathfinding linksets ...</floater.string> + <floater.string name="linksets_messaging_set_error">Error detected while modifying selected pathfinding linksets</floater.string> + <floater.string name="linksets_messaging_complete_none_found">No pathfinding linksets</floater.string> + <floater.string name="linksets_messaging_complete_available">[NUM_SELECTED] linksets selected out of [NUM_TOTAL]</floater.string> + <floater.string name="linksets_messaging_not_enabled">This region is not enabled for pathfinding.</floater.string> + <floater.string name="linkset_terrain_name">[Terrain]</floater.string> + <floater.string name="linkset_terrain_description">--</floater.string> + <floater.string name="linkset_terrain_land_impact">--</floater.string> + <floater.string name="linkset_terrain_dist_from_you">--</floater.string> + <floater.string name="linkset_use_walkable">Walkable</floater.string> + <floater.string name="linkset_use_static_obstacle">Static obstacle</floater.string> + <floater.string name="linkset_use_dynamic_obstacle">Movable obstacle</floater.string> + <floater.string name="linkset_use_material_volume">Material volume</floater.string> + <floater.string name="linkset_use_exclusion_volume">Exclusion volume</floater.string> + <floater.string name="linkset_use_dynamic_phantom">Movable phantom</floater.string> + <floater.string name="linkset_is_terrain">[unmodifiable]</floater.string> + <floater.string name="linkset_is_restricted_state">[restricted]</floater.string> + <floater.string name="linkset_choose_use">Choose linkset use...</floater.string> + <panel + border="false" + bevel_style="none" + follows="left|top|right|bottom" + layout="topleft" + height="226" + width="950"> + <text + height="13" + word_wrap="false" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + length="1" + follows="left|top" + layout="topleft" + left="20" + top_pad="14" + width="67"> + Filter by: + </text> + <text + height="13" + word_wrap="false" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + length="1" + follows="left|top" + layout="topleft" + left_pad="0" + width="62"> + Name + </text> + <line_editor + border_style="line" + border_thickness="1" + follows="left|top" + height="20" + layout="topleft" + left_pad="0" + top_pad="-18" + max_length_bytes="10" + name="filter_by_name" + width="105" /> + <text + height="13" + word_wrap="false" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + length="1" + follows="left|top" + layout="topleft" + left_pad="22" + top_pad="-15" + width="88"> + Description + </text> + <line_editor + border_style="line" + border_thickness="1" + follows="left|top" + height="20" + layout="topleft" + left_pad="0" + top_pad="-17" + max_length_bytes="10" + name="filter_by_description" + width="145" /> + <combo_box + height="20" + layout="topleft" + follows="left|top" + name="filter_by_linkset_use" + left_pad="32" + top_pad="-20" + width="199"> + <combo_box.item + label="Filter by linkset use..." + name="filter_by_linkset_use_none" + value="0" /> + <combo_box.item + label="Walkable" + name="filter_by_linkset_use_walkable" + value="1" /> + <combo_box.item + label="Static obstacle" + name="filter_by_linkset_use_static_obstacle" + value="2" /> + <combo_box.item + label="Movable obstacle" + name="filter_by_linkset_use_dynamic_obstacle" + value="3" /> + <combo_box.item + label="Material volume" + name="filter_by_linkset_use_material_volume" + value="4" /> + <combo_box.item + label="Exclusion volume" + name="filter_by_linkset_use_exclusion_volume" + value="5" /> + <combo_box.item + label="Movable phantom" + name="filter_by_linkset_use_dynamic_phantom" + value="6" /> + </combo_box> + <button + follows="right|top" + height="21" + label="Apply" + layout="topleft" + name="apply_filters" + top_pad="-21" + left_pad="31" + width="73"/> + <button + follows="right|top" + height="21" + label="Clear" + layout="topleft" + name="clear_filters" + top_pad="-21" + left_pad="8" + width="73"/> + <scroll_list + column_padding="0" + draw_heading="true" + follows="all" + height="135" + layout="topleft" + left="18" + top_pad="15" + multi_select="true" + name="pathfinding_linksets" + width="910"> + <scroll_list.columns + label="Name (root prim)" + name="name" + dynamic_width="true" /> + <scroll_list.columns + label="Description (root prim)" + name="description" + width="192" /> + <scroll_list.columns + label="Land impact" + name="land_impact" + width="88" /> + <scroll_list.columns + label="Dist from you" + name="dist_from_you" + width="97" /> + <scroll_list.columns + label="Linkset use" + name="linkset_use" + width="210" /> + <scroll_list.columns + label="A %" + name="a_percent" + width="41" /> + <scroll_list.columns + label="B %" + name="b_percent" + width="41" /> + <scroll_list.columns + label="C %" + name="c_percent" + width="41" /> + <scroll_list.columns + label="D %" + name="d_percent" + width="41" /> + </scroll_list> + <text + height="13" + word_wrap="false" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + length="1" + follows="left|bottom" + layout="topleft" + name="linksets_status" + top_pad="17" + width="549"> + Linksets: + </text> + <button + follows="right|bottom" + height="21" + label="Refresh list" + layout="topleft" + name="refresh_linksets_list" + top_pad="-16" + left_pad="0" + width="115"/> + <button + follows="right|bottom" + height="21" + label="Select all" + layout="topleft" + name="select_all_linksets" + top_pad="-21" + left_pad="8" + width="115"/> + <button + follows="right|bottom" + height="21" + label="Select none" + layout="topleft" + name="select_none_linksets" + top_pad="-21" + left_pad="8" + width="115"/> + </panel> + <view_border + bevel_style="none" + follows="left|bottom|right" + height="0" + layout="topleft" + name="horiz_separator" + top_pad="0" + left="18" + width="912"/> + <panel + border="false" + bevel_style="none" + follows="left|right|bottom" + layout="topleft" + left="0" + height="67" + width="950"> + <text + height="13" + word_wrap="false" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + length="1" + left="18" + follows="left|bottom|right" + layout="topleft" + top_pad="8" + width="580"> + Actions on selected linksets (If a linkset is removed from the world, its attributes will be lost): + </text> + <check_box + height="19" + follows="left|bottom" + label="Show beacon" + layout="topleft" + name="show_beacon" + left_pad="0" + top_pad="-16" + width="90" /> + <button + follows="left|bottom" + height="21" + label="Take" + layout="topleft" + name="take_linksets" + top_pad="9" + left="18" + width="95"/> + <button + follows="left|bottom" + height="21" + label="Take copy" + layout="topleft" + name="take_copy_linksets" + top_pad="-21" + left_pad="6" + width="95"/> + <button + follows="left|bottom" + height="21" + label="Return" + layout="topleft" + name="return_linksets" + top_pad="-21" + left_pad="6" + width="95"/> + <button + follows="left|bottom" + height="21" + label="Delete" + layout="topleft" + name="delete_linksets" + top_pad="-21" + left_pad="6" + width="95"/> + <button + follows="left|bottom" + height="21" + label="Teleport me to it" + layout="topleft" + name="teleport_me_to_linkset" + top_pad="-21" + left_pad="6" + width="160"/> + </panel> + <view_border + bevel_style="none" + follows="left|bottom|right" + height="0" + layout="topleft" + name="horiz_separator" + top_pad="0" + left="18" + width="912"/> + <panel + border="false" + bevel_style="none" + follows="left|right|bottom" + layout="topleft" + left="0" + height="75" + width="950"> + <text + height="13" + word_wrap="false" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + length="1" + follows="left|bottom" + layout="topleft" + left="18" + top_pad="8" + width="912"> + Edit attributes of selected linksets and press the button to apply changes + </text> + <combo_box + height="20" + layout="topleft" + follows="left|top" + name="edit_linkset_use" + left="18" + top_pad="17" + width="199"> + </combo_box> + <text + height="13" + word_wrap="false" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + text_readonly_color="LabelDisabledColor" + name="walkability_coefficients_label" + length="1" + follows="left|bottom" + layout="topleft" + left_pad="36" + top_pad="-17" + width="110"> + Walkability: + </text> + <text + height="13" + word_wrap="false" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + text_readonly_color="LabelDisabledColor" + name="edit_a_label" + length="1" + follows="left|bottom" + layout="topleft" + left_pad="0" + width="18"> + A + </text> + <line_editor + border_style="line" + border_thickness="1" + follows="left|bottom" + height="21" + layout="topleft" + left_pad="0" + top_pad="-19" + max_length_chars="3" + name="edit_a_value" + width="45" /> + <text + height="13" + word_wrap="false" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + text_readonly_color="LabelDisabledColor" + name="edit_b_label" + length="1" + follows="left|bottom" + layout="topleft" + left_pad="44" + top_pad="-15" + width="18"> + B + </text> + <line_editor + border_style="line" + border_thickness="1" + follows="left|bottom" + height="21" + layout="topleft" + left_pad="0" + top_pad="-19" + max_length_chars="3" + name="edit_b_value" + width="45" /> + <text + height="13" + word_wrap="false" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + text_readonly_color="LabelDisabledColor" + name="edit_c_label" + length="1" + follows="left|bottom" + layout="topleft" + left_pad="44" + top_pad="-15" + width="18"> + C + </text> + <line_editor + border_style="line" + border_thickness="1" + follows="left|bottom" + height="21" + layout="topleft" + left_pad="0" + top_pad="-19" + max_length_chars="3" + name="edit_c_value" + width="45" /> + <text + height="13" + word_wrap="false" + use_ellipses="false" + type="string" + text_color="LabelTextColor" + text_readonly_color="LabelDisabledColor" + name="edit_d_label" + length="1" + follows="left|bottom" + layout="topleft" + left_pad="44" + top_pad="-15" + width="18"> + D + </text> + <line_editor + border_style="line" + border_thickness="1" + follows="left|bottom" + height="21" + layout="topleft" + left_pad="0" + top_pad="-19" + max_length_chars="3" + name="edit_d_value" + width="45" /> + <button + follows="right|bottom" + height="21" + label="Apply changes" + layout="topleft" + name="apply_edit_values" + top_pad="-21" + left_pad="40" + width="140"/> + </panel> +</floater> diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 1d11abcf73..bea3037616 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -681,6 +681,7 @@ <menu_item_check.on_enable function="Build.Enabled" /> </menu_item_check> + <menu create_jump_keys="true" label="Select Build Tool" @@ -937,7 +938,36 @@ </menu_item_call> </menu> - <menu_item_separator/> + <menu + create_jump_keys="true" + label="Pathfinding" + name="Pathfinding" + tear_off="false"> + <menu_item_call + label="Basic setup..." + name="pathfinding_basic_menu_item"> + <menu_item_call.on_click + function="Floater.ToggleOrBringToFront" + parameter="pathfinding_basic" /> + </menu_item_call> + <menu_item_call + label="Edit / test..." + name="pathfinding_console_menu_item"> + <menu_item_call.on_click + function="Floater.ToggleOrBringToFront" + parameter="pathfinding_console" /> + </menu_item_call> + <menu_item_call + label="Characters..." + name="pathfinding_characters_menu_item"> + <menu_item_call.on_click + function="Floater.ToggleOrBringToFront" + parameter="pathfinding_characters" /> + </menu_item_call> + </menu> + + + <menu_item_separator/> <menu create_jump_keys="true" @@ -1123,6 +1153,14 @@ <menu_item_call.on_visible function="File.VisibleUploadModel"/> </menu_item_call> + <menu_item_call + label="BuildNavMeshTest" + layout="topleft" + name="BuildNavMesh"> + <menu_item_call.on_click + function="File.UploadNavMesh" + parameter="" /> + </menu_item_call> <menu_item_call label="Bulk (L$[COST] per file)..." layout="topleft" diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index af75d49353..f70d4db0f2 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -7663,7 +7663,20 @@ The site at '<nolink>[HOST_NAME]</nolink>' in realm ' notext="Cancel" ignoretext="Confirm before hiding UI"/> </notification> - + + <notification + icon="alertmodal.tga" + name="PathfindingLinksets_SetLinksetUseMismatchOnRestricted" + type="alertmodal"> + Some selected linksets cannot be set to be '[REQUESTED_TYPE]' because of permission restrictions on the linkset. These linksets will be set to be '[RESTRICTED_TYPE]' instead. + <tag>confirm</tag> + <usetemplate + ignoretext="Do you wish to proceed?" + name="okcancelignore" + notext="Cancel" + yestext="OK"/> + </notification> + <global name="UnsupportedGLRequirements"> You do not appear to have the proper hardware requirements for [APP_NAME]. [APP_NAME] requires an OpenGL graphics card that has multitexture support. If this is the case, you may want to make sure that you have the latest drivers for your graphics card, and service packs and patches for your operating system. diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 4bc72be49b..d6b5f3559f 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -3694,7 +3694,11 @@ Try enclosing path to the editor with double quotes. <string name="Command_MiniMap_Label">Mini-map</string> <string name="Command_Move_Label">Walk / run / fly</string> <string name="Command_Outbox_Label">Merchant outbox</string> + <string name="Command_Pathfinding_Label">Pathfinding</string> <string name="Command_People_Label">People</string> + <string name="Command_PF_Basic_Label">Pathfinding Basic</string> + <string name="Command_PF_Characters_Label">Pathfinding Characters</string> + <string name="Command_PF_Linksets_Label">Pathfinding Linksets</string> <string name="Command_Picks_Label">Picks</string> <string name="Command_Places_Label">Places</string> <string name="Command_Preferences_Label">Preferences</string> @@ -3720,7 +3724,11 @@ Try enclosing path to the editor with double quotes. <string name="Command_MiniMap_Tooltip">Show nearby people</string> <string name="Command_Move_Tooltip">Moving your avatar</string> <string name="Command_Outbox_Tooltip">Transfer items to your marketplace for sale</string> + <string name="Command_Pathfinding_Tooltip">Information about pathfinding</string> <string name="Command_People_Tooltip">Friends, groups, and nearby people</string> + <string name="Command_PF_Basic_Tooltip">Manipulation of pathfinding frozen/unfrozen state</string> + <string name="Command_PF_Characters_Tooltip">Manipulation of pathfinding characters</string> + <string name="Command_PF_Linksets_Tooltip">Manipulation of pathfinding linksets</string> <string name="Command_Picks_Tooltip">Places to show as favorites in your profile</string> <string name="Command_Places_Tooltip">Places you've saved</string> <string name="Command_Preferences_Tooltip">Preferences</string> diff --git a/package_physicsextensions.sh b/package_physicsextensions.sh new file mode 100755 index 0000000000..5b4c23ecc9 --- /dev/null +++ b/package_physicsextensions.sh @@ -0,0 +1,52 @@ +#!/bin/bash + +cd "$(dirname "$0")" + +# turn on verbose debugging output for parabuild logs. +set -x +# make errors fatal +set -e + +if [ -z "$AUTOBUILD" ] ; then + fail +fi + +if [ "$OSTYPE" = "cygwin" ] ; then + export AUTOBUILD="$(cygpath -u $AUTOBUILD)" +fi + +# load autbuild provided shell functions and variables +eval "$("$AUTOBUILD" source_environment)" + +projectDir="$(pwd)" + +#directories we need the headers from +projects="llcommon llimage llmath llrender" + +source="$projectDir/indra" + +stage="$projectDir/stage/include" +mkdir -p $stage + +for project in $projects +do + dstIncludeDir="$stage/$project" + mkdir -p $dstIncludeDir + headers="$source/$project/*.h" + cp $headers "$dstIncludeDir" + headers="$source/$project/*.inl" + # not all projects have .inl files + files=$(ls $headers 2> /dev/null | wc -l) + if [ "$files" != "0" ] ; then + cp $headers "$dstIncludeDir" + fi +done + +# Copy the license files into place for packaging +srcLicenseDir="$projectDir/doc" +dstLicenseDir="$projectDir/stage/LICENSES" + +mkdir -p "$dstLicenseDir" +cp "$srcLicenseDir/LGPL-licence.txt" "$dstLicenseDir/LGPL-licence.txt" + +pass diff --git a/package_physicsextensions.xml b/package_physicsextensions.xml new file mode 100644 index 0000000000..0bde6ad770 --- /dev/null +++ b/package_physicsextensions.xml @@ -0,0 +1,292 @@ +<?xml version="1.0" ?> +<llsd> +<map> + <key>package_description</key> + <map> + <key>description</key> + <string>include files referenced in the llphysicsextensions</string> + <key>license</key> + <string>LGPL</string> + <key>license_file</key> + <string>LICENSES/LGPL-licence.txt</string> + <key>name</key> + <string>pathfinding_includes</string> + <key>platforms</key> + <map> + <key>common</key> + <map> + <key>build_directory</key> + <string>stage</string> + <key>configurations</key> + <map> + <key>Debug</key> + <map> + <key>build</key> + <map> + <key>command</key> + <string>bash</string> + <key>options</key> + <array> + <string>-c ../package_physicsextensions.sh</string> + </array> + </map> + <key>default</key> + <string>True</string> + <key>name</key> + <string>Debug</string> + </map> + <key>Release</key> + <map> + <key>build</key> + <map> + <key>command</key> + <string>bash</string> + <key>options</key> + <array> + <string>-c ../package_physicsextensions.sh</string> + </array> + </map> + <key>default</key> + <string>True</string> + <key>name</key> + <string>Release</string> + </map> + <key>RelWithDebInfo</key> + <map> + <key>build</key> + <map> + <key>command</key> + <string>bash</string> + <key>options</key> + <array> + <string>-c ../package_physicsextensions.sh</string> + </array> + </map> + <key>default</key> + <string>True</string> + <key>name</key> + <string>RelWithDebInfo</string> + </map> + </map> + <key>name</key> + <string>common</string> + </map> + <key>darwin</key> + <map> + <key>build_directory</key> + <string>stage</string> + <key>configurations</key> + <map> + <key>Debug</key> + <map> + <key>build</key> + <map> + <key>command</key> + <string>bash</string> + <key>options</key> + <array> + <string>-c ../package_physicsextensions.sh</string> + </array> + </map> + <key>default</key> + <string>true</string> + <key>manifest</key> + <array> + <string>include/</string> + <string>LICENSES</string> + </array> + <key>name</key> + <string>Debug</string> + </map> + <key>Release</key> + <map> + <key>build</key> + <map> + <key>command</key> + <string>bash</string> + <key>options</key> + <array> + <string>-c ../package_physicsextensions.sh</string> + </array> + </map> + <key>default</key> + <string>true</string> + <key>manifest</key> + <array> + <string>include/</string> + <string>LICENSES</string> + </array> + <key>name</key> + <string>Release</string> + </map> + <key>RelWithDebInfo</key> + <map> + <key>build</key> + <map> + <key>command</key> + <string>bash</string> + <key>options</key> + <array> + <string>-c ../package_physicsextensions.sh</string> + </array> + </map> + <key>default</key> + <string>true</string> + <key>manifest</key> + <array> + <string>include/</string> + <string>LICENSES</string> + </array> + <key>name</key> + <string>RelWithDebInfo</string> + </map> + </map> + <key>name</key> + <string>darwin</string> + </map> + <key>linux</key> + <map> + <key>build_directory</key> + <string>stage</string> + <key>configurations</key> + <map> + <key>Debug</key> + <map> + <key>build</key> + <map> + <key>command</key> + <string>bash</string> + <key>options</key> + <array> + <string>-c ../package_physicsextensions.sh</string> + </array> + </map> + <key>default</key> + <string>true</string> + <key>name</key> + <string>Debug</string> + </map> + <key>Release</key> + <map> + <key>build</key> + <map> + <key>command</key> + <string>bash</string> + <key>options</key> + <array> + <string>-c ../package_physicsextensions.sh</string> + </array> + </map> + <key>default</key> + <string>true</string> + <key>name</key> + <string>Release</string> + </map> + <key>RelWithDebInfo</key> + <map> + <key>build</key> + <map> + <key>command</key> + <string>bash</string> + <key>options</key> + <array> + <string>-c ../package_physicsextensions.sh</string> + </array> + </map> + <key>default</key> + <string>true</string> + <key>name</key> + <string>RelWithDebInfo</string> + </map> + </map> + <key>manifest</key> + <array> + <string>include</string> + <string>LICENSES</string> + </array> + <key>name</key> + <string>linux</string> + </map> + <key>windows</key> + <map> + <key>build_directory</key> + <string>stage</string> + <key>configurations</key> + <map> + <key>Debug</key> + <map> + <key>build</key> + <map> + <key>command</key> + <string>bash</string> + <key>options</key> + <array> + <string>-c ../package_physicsextensions.sh</string> + </array> + </map> + <key>default</key> + <string>true</string> + <key>manifest</key> + <array> + <string>include/</string> + <string>LICENSES</string> + </array> + <key>name</key> + <string>Debug</string> + </map> + <key>Release</key> + <map> + <key>build</key> + <map> + <key>command</key> + <string>bash</string> + <key>options</key> + <array> + <string>-c ../package_physicsextensions.sh</string> + </array> + </map> + <key>default</key> + <string>true</string> + <key>manifest</key> + <array> + <string>include/</string> + <string>LICENSES</string> + </array> + <key>name</key> + <string>Release</string> + </map> + <key>RelWithDebInfo</key> + <map> + <key>build</key> + <map> + <key>command</key> + <string>bash</string> + <key>options</key> + <array> + <string>-c ../package_physicsextensions.sh</string> + </array> + </map> + <key>default</key> + <string>true</string> + <key>manifest</key> + <array> + <string>include/</string> + <string>LICENSES</string> + </array> + <key>name</key> + <string>RelWithDebInfo</string> + </map> + </map> + <key>name</key> + <string>windows</string> + </map> + </map> + <key>version</key> + <string>1.0</string> + </map> + <key>type</key> + <string>autobuild</string> + <key>version</key> + <string>1.2</string> + </map> +</llsd> |