summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--autobuild.xml68
-rw-r--r--indra/CMakeLists.txt3
-rw-r--r--indra/cmake/CMakeLists.txt1
-rw-r--r--indra/cmake/LLPhysicsExtensions.cmake8
-rw-r--r--indra/cmake/VHACD.cmake9
-rw-r--r--indra/llconvexdecomposition/CMakeLists.txt39
-rw-r--r--indra/llconvexdecomposition/llconvexdecomposition.cpp83
-rw-r--r--indra/llconvexdecomposition/llconvexdecomposition.h231
-rw-r--r--indra/llconvexdecomposition/llconvexdecompositionvhacd.cpp492
-rw-r--r--indra/llconvexdecomposition/llconvexdecompositionvhacd.h339
-rw-r--r--indra/llprimitive/CMakeLists.txt6
-rw-r--r--indra/llprimitive/llmodel.cpp4
-rw-r--r--indra/llprimitive/llmodel.h3
-rw-r--r--indra/newview/CMakeLists.txt8
-rw-r--r--indra/newview/llfloatermarketplace.cpp22
-rw-r--r--indra/newview/llfloatermarketplace.h8
-rw-r--r--indra/newview/llfloatermodelpreview.cpp12
-rw-r--r--indra/newview/llfloatersearch.cpp14
-rw-r--r--indra/newview/llfloatersearch.h4
-rw-r--r--indra/newview/llmeshrepository.cpp45
-rw-r--r--indra/newview/llmeshrepository.h5
-rw-r--r--indra/newview/llmodelpreview.cpp14
-rw-r--r--indra/newview/llstatusbar.cpp7
-rw-r--r--indra/newview/llviewermenufile.cpp18
-rw-r--r--indra/newview/llviewerobjectlist.cpp4
-rw-r--r--indra/newview/skins/default/xui/en/floater_marketplace.xml221
-rw-r--r--indra/newview/skins/default/xui/en/floater_model_preview.xml149
-rw-r--r--indra/newview/skins/default/xui/en/floater_search.xml222
-rw-r--r--indra/newview/skins/default/xui/en/notifications.xml19
29 files changed, 1937 insertions, 121 deletions
diff --git a/autobuild.xml b/autobuild.xml
index c9355c73c0..8a022cd304 100644
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -1496,41 +1496,19 @@
<map>
<key>platforms</key>
<map>
- <key>darwin64</key>
- <map>
- <key>archive</key>
- <map>
- <key>hash</key>
- <string>f290b000b31f9e36f2489946cbc99f5e</string>
- <key>url</key>
- <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/59995/563653/llphysicsextensions_stub-1.0.542456-darwin64-542456.tar.bz2</string>
- </map>
- <key>name</key>
- <string>darwin64</string>
- </map>
- <key>linux64</key>
- <map>
- <key>archive</key>
- <map>
- <key>hash</key>
- <string>711f4ec769e4b5f59ba25ee43c11bcbc</string>
- <key>url</key>
- <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/4724/14846/llphysicsextensions_stub-1.0.504712-linux64-504712.tar.bz2</string>
- </map>
- <key>name</key>
- <string>linux64</string>
- </map>
- <key>windows64</key>
+ <key>common</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
- <string>2e5f1f7046a49d8b0bc295aa878116bc</string>
+ <string>bc41438b10ac6474cf5560465a3662a64f9e65a81342e4c33f18f6694581c7ee28c9ee6f091c36e80a0b1e10c68205be71eb5f8e40fef115d2c744fc2bbfcb43</string>
+ <key>hash_algorithm</key>
+ <string>blake2b</string>
<key>url</key>
- <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/60043/564063/llphysicsextensions_stub-1.0.542456-windows-542456.tar.bz2</string>
+ <string>https://github.com/AlchemyViewer/llphysicsextensions_stub/releases/download/v1.0-cb4900e/llphysicsextensions_stub-1.0-common-17836965684.tar.zst</string>
</map>
<key>name</key>
- <string>windows64</string>
+ <string>common</string>
</map>
</map>
<key>license</key>
@@ -1540,7 +1518,7 @@
<key>copyright</key>
<string>Copyright (c) 2010, Linden Research, Inc.</string>
<key>version</key>
- <string>1.0.542456</string>
+ <string>1.0</string>
<key>name</key>
<string>llphysicsextensions_stub</string>
</map>
@@ -2966,6 +2944,38 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>description</key>
<string>Discord Social SDK</string>
</map>
+ <key>vhacd</key>
+ <map>
+ <key>platforms</key>
+ <map>
+ <key>common</key>
+ <map>
+ <key>archive</key>
+ <map>
+ <key>hash</key>
+ <string>140d8fc952a10edb5f2d72ab405336019ef32cadfa64f0cfce76c9de4bc6268cbc87cc8cd89d3417fb78b531d441701afc8d016bafe4bd275df2707f7daf1387</string>
+ <key>hash_algorithm</key>
+ <string>blake2b</string>
+ <key>url</key>
+ <string>https://github.com/AlchemyViewer/3p-vhacd/releases/download/v4.1.0-r2/vhacd-4.1.0-r2-common-18166921729.tar.zst</string>
+ </map>
+ <key>name</key>
+ <string>common</string>
+ </map>
+ </map>
+ <key>license</key>
+ <string>BSD</string>
+ <key>license_file</key>
+ <string>LICENSES/vhacd.txt</string>
+ <key>copyright</key>
+ <string>Copyright (c) 2011, Khaled Mamou</string>
+ <key>version</key>
+ <string>4.1.0-r2</string>
+ <key>name</key>
+ <string>vhacd</string>
+ <key>description</key>
+ <string>Voxelized Hierarchical Approximate Convex Decomposition</string>
+ </map>
</map>
<key>package_description</key>
<map>
diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt
index 6504002dd9..246bd7bfa0 100644
--- a/indra/CMakeLists.txt
+++ b/indra/CMakeLists.txt
@@ -61,6 +61,9 @@ add_subdirectory(cmake)
add_subdirectory(${LIBS_OPEN_PREFIX}llaudio)
add_subdirectory(${LIBS_OPEN_PREFIX}llappearance)
add_subdirectory(${LIBS_OPEN_PREFIX}llcharacter)
+if (NOT HAVOK AND NOT HAVOK_TPV)
+ add_subdirectory(${LIBS_OPEN_PREFIX}llconvexdecomposition)
+endif ()
add_subdirectory(${LIBS_OPEN_PREFIX}llcommon)
add_subdirectory(${LIBS_OPEN_PREFIX}llcorehttp)
add_subdirectory(${LIBS_OPEN_PREFIX}llimage)
diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt
index 4608f68f50..2ba282bdb7 100644
--- a/indra/cmake/CMakeLists.txt
+++ b/indra/cmake/CMakeLists.txt
@@ -62,6 +62,7 @@ set(cmake_SOURCE_FILES
UI.cmake
UnixInstall.cmake
Variables.cmake
+ VHACD.cmake
ViewerMiscLibs.cmake
VisualLeakDetector.cmake
LibVLCPlugin.cmake
diff --git a/indra/cmake/LLPhysicsExtensions.cmake b/indra/cmake/LLPhysicsExtensions.cmake
index 80d243d9f8..bb6cb703d2 100644
--- a/indra/cmake/LLPhysicsExtensions.cmake
+++ b/indra/cmake/LLPhysicsExtensions.cmake
@@ -23,9 +23,15 @@ if (HAVOK)
use_prebuilt_binary(llphysicsextensions_source)
set(LLPHYSICSEXTENSIONS_SRC_DIR ${LIBS_PREBUILT_DIR}/llphysicsextensions/src)
target_link_libraries( llphysicsextensions_impl INTERFACE llphysicsextensions)
+ target_compile_definitions( llphysicsextensions_impl INTERFACE LL_HAVOK=1 )
elseif (HAVOK_TPV)
use_prebuilt_binary(llphysicsextensions_tpv)
- target_link_libraries( llphysicsextensions_impl INTERFACE llphysicsextensions_tpv)
+ if(WINDOWS)
+ target_link_libraries( llphysicsextensions_impl INTERFACE ${ARCH_PREBUILT_DIRS}/llphysicsextensions_tpv.lib)
+ else()
+ target_link_libraries( llphysicsextensions_impl INTERFACE ${ARCH_PREBUILT_DIRS}/libllphysicsextensions_tpv.a)
+ endif()
+ target_compile_definitions( llphysicsextensions_impl INTERFACE LL_HAVOK=1 )
else (HAVOK)
use_prebuilt_binary(llphysicsextensions_stub)
set(LLPHYSICSEXTENSIONS_SRC_DIR ${LIBS_PREBUILT_DIR}/llphysicsextensions/stub)
diff --git a/indra/cmake/VHACD.cmake b/indra/cmake/VHACD.cmake
new file mode 100644
index 0000000000..9f37f32b2d
--- /dev/null
+++ b/indra/cmake/VHACD.cmake
@@ -0,0 +1,9 @@
+# -*- cmake -*-
+include(Prebuilt)
+
+add_library(ll::vhacd INTERFACE IMPORTED)
+
+use_system_binary(vhacd)
+use_prebuilt_binary(vhacd)
+
+target_include_directories(ll::vhacd SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/vhacd/)
diff --git a/indra/llconvexdecomposition/CMakeLists.txt b/indra/llconvexdecomposition/CMakeLists.txt
new file mode 100644
index 0000000000..7dae884db8
--- /dev/null
+++ b/indra/llconvexdecomposition/CMakeLists.txt
@@ -0,0 +1,39 @@
+# -*- cmake -*-
+
+project(llconvexdecomposition)
+
+include(00-Common)
+include(LLCommon)
+include(LLMath)
+include(VHACD)
+
+set(llconvexdecomposition_SOURCE_FILES
+ llconvexdecomposition.cpp
+ llconvexdecompositionvhacd.cpp
+ )
+
+set(llconvexdecomposition_HEADER_FILES
+ CMakeLists.txt
+ llconvexdecomposition.h
+ llconvexdecompositionvhacd.h
+ )
+
+set_source_files_properties(${llconvexdecomposition_HEADER_FILES}
+ PROPERTIES HEADER_FILE_ONLY TRUE)
+
+list(APPEND llconvexdecomposition_SOURCE_FILES ${llconvexdecomposition_HEADER_FILES})
+
+add_library (llconvexdecomposition ${llconvexdecomposition_SOURCE_FILES})
+target_include_directories(llconvexdecomposition INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
+
+target_link_libraries(llconvexdecomposition
+ llcommon
+ llmath
+ ll::vhacd)
+
+if(WINDOWS)
+ target_compile_options(llconvexdecomposition PRIVATE /bigobj)
+endif()
+
+# Add tests
+
diff --git a/indra/llconvexdecomposition/llconvexdecomposition.cpp b/indra/llconvexdecomposition/llconvexdecomposition.cpp
new file mode 100644
index 0000000000..7b9d775c53
--- /dev/null
+++ b/indra/llconvexdecomposition/llconvexdecomposition.cpp
@@ -0,0 +1,83 @@
+/**
+* @file llconvexdecomposition.cpp
+* @author falcon@lindenlab.com
+* @brief Inner implementation of LLConvexDecomposition interface
+*
+* $LicenseInfo:firstyear=2011&license=lgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2011, Linden Research, Inc.
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation;
+* version 2.1 of the License only.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*
+* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+* $/LicenseInfo$
+*/
+
+#include "linden_common.h"
+
+#include "llconvexdecompositionvhacd.h"
+#include "llconvexdecomposition.h"
+
+bool LLConvexDecomposition::s_isInitialized = false;
+
+// static
+bool LLConvexDecomposition::isFunctional()
+{
+ return LLConvexDecompositionVHACD::isFunctional();
+}
+
+// static
+LLConvexDecomposition* LLConvexDecomposition::getInstance()
+{
+ if ( !s_isInitialized )
+ {
+ return nullptr;
+ }
+ else
+ {
+ return LLConvexDecompositionVHACD::getInstance();
+ }
+}
+
+// static
+LLCDResult LLConvexDecomposition::initSystem()
+{
+ LLCDResult result = LLConvexDecompositionVHACD::initSystem();
+ if ( result == LLCD_OK )
+ {
+ s_isInitialized = true;
+ }
+ return result;
+}
+
+// static
+LLCDResult LLConvexDecomposition::initThread()
+{
+ return LLConvexDecompositionVHACD::initThread();
+}
+
+// static
+LLCDResult LLConvexDecomposition::quitThread()
+{
+ return LLConvexDecompositionVHACD::quitThread();
+}
+
+// static
+LLCDResult LLConvexDecomposition::quitSystem()
+{
+ return LLConvexDecompositionVHACD::quitSystem();
+}
+
+
diff --git a/indra/llconvexdecomposition/llconvexdecomposition.h b/indra/llconvexdecomposition/llconvexdecomposition.h
new file mode 100644
index 0000000000..8008bc6e12
--- /dev/null
+++ b/indra/llconvexdecomposition/llconvexdecomposition.h
@@ -0,0 +1,231 @@
+/**
+ * @file llconvexdecomposition.cpp
+ * @brief LLConvexDecomposition interface definition
+ *
+ * $LicenseInfo:firstyear=2011&license=lgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_CONVEX_DECOMPOSITION
+#define LL_CONVEX_DECOMPOSITION
+
+typedef int bool32;
+
+#if defined(_WIN32) || defined(_WIN64)
+#define LLCD_CALL __cdecl
+#else
+#define LLCD_CALL
+#endif
+
+struct LLCDParam
+{
+ enum LLCDParamType
+ {
+ LLCD_INVALID = 0,
+ LLCD_INTEGER,
+ LLCD_FLOAT,
+ LLCD_BOOLEAN,
+ LLCD_ENUM
+ };
+
+ struct LLCDEnumItem
+ {
+ const char* mName;
+ int mValue;
+ };
+
+ union LLCDValue
+ {
+ float mFloat;
+ int mIntOrEnumValue;
+ bool32 mBool;
+ };
+
+ union LLCDParamDetails
+ {
+ struct {
+ LLCDValue mLow;
+ LLCDValue mHigh;
+ LLCDValue mDelta;
+ } mRange;
+
+ struct {
+ int mNumEnums;
+ LLCDEnumItem* mEnumsArray;
+ } mEnumValues;
+ };
+
+ const char* mName;
+ const char* mDescription;
+ LLCDParamType mType;
+ LLCDParamDetails mDetails;
+ LLCDValue mDefault;
+ int mStage;
+
+ // WARNING: Only the LLConvexDecomposition implementation
+ // should change this value
+ int mReserved;
+};
+
+struct LLCDStageData
+{
+ const char* mName;
+ const char* mDescription;
+ bool32 mSupportsCallback;
+};
+
+struct LLCDMeshData
+{
+ enum IndexType
+ {
+ INT_16,
+ INT_32
+ };
+
+ const float* mVertexBase;
+ int mVertexStrideBytes;
+ int mNumVertices;
+ const void* mIndexBase;
+ IndexType mIndexType;
+ int mIndexStrideBytes;
+ int mNumTriangles;
+};
+
+struct LLCDHull
+{
+ const float* mVertexBase;
+ int mVertexStrideBytes;
+ int mNumVertices;
+};
+
+enum LLCDResult
+{
+ LLCD_OK = 0,
+ LLCD_UNKOWN_ERROR,
+ LLCD_NULL_PTR,
+ LLCD_INVALID_STAGE,
+ LLCD_UNKNOWN_PARAM,
+ LLCD_BAD_VALUE,
+ LLCD_REQUEST_OUT_OF_RANGE,
+ LLCD_INVALID_MESH_DATA,
+ LLCD_INVALID_HULL_DATA,
+ LLCD_STAGE_NOT_READY,
+ LLCD_INVALID_THREAD,
+ LLCD_NOT_IMPLEMENTED
+};
+
+// This callback will receive a string describing the current subtask being performed
+// as well as a pair of numbers indicating progress. (The values should not be interpreted
+// as a completion percentage as 'current' may be greater than 'final'.)
+// If the callback returns zero, the decomposition will be terminated
+typedef int (LLCD_CALL *llcdCallbackFunc)(const char* description, int current_progress, int final_progress);
+
+class LLConvexDecomposition
+{
+public:
+ // Obtain a pointer to the actual implementation
+ static LLConvexDecomposition* getInstance();
+
+ /// @returns false if this is the stub
+ static bool isFunctional();
+
+ static LLCDResult initSystem();
+ static LLCDResult initThread();
+ static LLCDResult quitThread();
+ static LLCDResult quitSystem();
+
+ // Generate a decomposition object handle
+ virtual void genDecomposition(int& decomp) = 0;
+ // Delete decomposition object handle
+ virtual void deleteDecomposition(int decomp) = 0;
+ // Bind given decomposition handle
+ // Commands operate on currently bound decomposition
+ virtual void bindDecomposition(int decomp) = 0;
+
+ // Sets *paramsOut to the address of the LLCDParam array and returns
+ // the number of parameters
+ virtual int getParameters(const LLCDParam** paramsOut) = 0;
+
+
+ // Sets *stagesOut to the address of the LLCDStageData array and returns
+ // the number of stages
+ virtual int getStages(const LLCDStageData** stagesOut) = 0;
+
+
+ // Set a parameter by name. Pass enum values as integers.
+ virtual LLCDResult setParam(const char* name, float val) = 0;
+ virtual LLCDResult setParam(const char* name, int val) = 0;
+ virtual LLCDResult setParam(const char* name, bool val) = 0;
+
+
+ // Set incoming mesh data. Data is copied to local buffers and will
+ // persist until the next setMeshData call
+ virtual LLCDResult setMeshData( const LLCDMeshData* data, bool vertex_based ) = 0;
+
+
+ // Register a callback to be called periodically during the specified stage
+ // See the typedef above for more information
+ virtual LLCDResult registerCallback( int stage, llcdCallbackFunc callback ) = 0;
+
+
+ // Execute the specified decomposition stage
+ virtual LLCDResult executeStage(int stage) = 0;
+ virtual LLCDResult buildSingleHull() = 0 ;
+
+
+ // Gets the number of hulls generated by the specified decompositions stage
+ virtual int getNumHullsFromStage(int stage) = 0;
+
+
+ // Populates hullOut to reference the internal copy of the requested hull
+ // The data will persist only until the next executeStage call for that stage.
+ virtual LLCDResult getHullFromStage( int stage, int hull, LLCDHull* hullOut ) = 0;
+
+ virtual LLCDResult getSingleHull( LLCDHull* hullOut ) = 0 ;
+
+
+ // TODO: Implement lock of some kind to disallow this call if data not yet ready
+ // Populates the meshDataOut to reference the utility's copy of the mesh geometry
+ // for the hull and stage specified.
+ // You must copy this data if you want to continue using it after the next executeStage
+ // call
+ virtual LLCDResult getMeshFromStage( int stage, int hull, LLCDMeshData* meshDataOut) = 0;
+
+
+ // Creates a mesh from hullIn and temporarily stores it internally in the utility.
+ // The mesh data persists only until the next call to getMeshFromHull
+ virtual LLCDResult getMeshFromHull( LLCDHull* hullIn, LLCDMeshData* meshOut ) = 0;
+
+ // Takes meshIn, generates a single convex hull from it, converts that to a mesh
+ // stored internally, and populates meshOut to reference the internally stored data.
+ // The data is persistent only until the next call to generateSingleHullMeshFromMesh
+ virtual LLCDResult generateSingleHullMeshFromMesh( LLCDMeshData* meshIn, LLCDMeshData* meshOut) = 0;
+
+ //
+ /// Debug
+ virtual void loadMeshData(const char* fileIn, LLCDMeshData** meshDataOut) = 0;
+
+private:
+ static bool s_isInitialized;
+};
+
+#endif //LL_CONVEX_DECOMPOSITION
+
diff --git a/indra/llconvexdecomposition/llconvexdecompositionvhacd.cpp b/indra/llconvexdecomposition/llconvexdecompositionvhacd.cpp
new file mode 100644
index 0000000000..78876f9f36
--- /dev/null
+++ b/indra/llconvexdecomposition/llconvexdecompositionvhacd.cpp
@@ -0,0 +1,492 @@
+/**
+* @file llconvexdecompositionvhacd.cpp
+* @author rye@alchemyviewer.org
+* @brief A VHACD based implementation of LLConvexDecomposition
+*
+* $LicenseInfo:firstyear=2025&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2025, 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 "llmath.h"
+#include "v3math.h"
+
+#include <string.h>
+#include <memory>
+
+#define ENABLE_VHACD_IMPLEMENTATION 1
+#include "VHACD.h"
+
+#include "llconvexdecompositionvhacd.h"
+
+constexpr S32 MAX_HULLS = 256;
+constexpr S32 MAX_VERTICES_PER_HULL = 256;
+
+bool LLConvexDecompositionVHACD::isFunctional()
+{
+ return true;
+}
+
+LLConvexDecomposition* LLConvexDecompositionVHACD::getInstance()
+{
+ return LLSimpleton::getInstance();
+}
+
+LLCDResult LLConvexDecompositionVHACD::initSystem()
+{
+ createInstance();
+ return LLCD_OK;
+}
+
+LLCDResult LLConvexDecompositionVHACD::initThread()
+{
+ return LLCD_OK;
+}
+
+LLCDResult LLConvexDecompositionVHACD::quitThread()
+{
+ return LLCD_OK;
+}
+
+LLCDResult LLConvexDecompositionVHACD::quitSystem()
+{
+ deleteSingleton();
+ return LLCD_OK;
+}
+
+LLConvexDecompositionVHACD::LLConvexDecompositionVHACD()
+{
+ //Create our vhacd instance and setup default parameters
+ mVHACD = VHACD::CreateVHACD();
+
+ mVHACDParameters.m_callback = &mVHACDCallback;
+ mVHACDParameters.m_logger = &mVHACDLogger;
+
+ mDecompStages[0].mName = "Analyze";
+ mDecompStages[0].mDescription = nullptr;
+
+ LLCDParam param;
+ param.mName = "Fill Mode";
+ param.mDescription = nullptr;
+ param.mType = LLCDParam::LLCD_ENUM;
+ param.mDetails.mEnumValues.mNumEnums = 3;
+
+ static LLCDParam::LLCDEnumItem fill_enums[3];
+ fill_enums[(size_t)VHACD::FillMode::FLOOD_FILL].mName = "Flood";
+ fill_enums[(size_t)VHACD::FillMode::FLOOD_FILL].mValue = (int)VHACD::FillMode::FLOOD_FILL;
+ fill_enums[(size_t)VHACD::FillMode::SURFACE_ONLY].mName = "Surface Only";
+ fill_enums[(size_t)VHACD::FillMode::SURFACE_ONLY].mValue = (int)VHACD::FillMode::SURFACE_ONLY;
+ fill_enums[(size_t)VHACD::FillMode::RAYCAST_FILL].mName = "Raycast";
+ fill_enums[(size_t)VHACD::FillMode::RAYCAST_FILL].mValue = (int)VHACD::FillMode::RAYCAST_FILL;
+
+ param.mDetails.mEnumValues.mEnumsArray = fill_enums;
+ param.mDefault.mIntOrEnumValue = (int)VHACD::FillMode::FLOOD_FILL;
+ param.mStage = 0;
+ param.mReserved = -1;
+ mDecompParams.push_back(param);
+
+ enum EVoxelQualityLevels
+ {
+ E_LOW_QUALITY = 0,
+ E_NORMAL_QUALITY,
+ E_HIGH_QUALITY,
+ E_VERY_HIGH_QUALITY,
+ E_ULTRA_QUALITY,
+ E_MAX_QUALITY,
+ E_NUM_QUALITY_LEVELS
+ };
+
+ param.mName = "Voxel Resolution";
+ param.mDescription = nullptr;
+ param.mType = LLCDParam::LLCD_ENUM;
+ param.mDetails.mEnumValues.mNumEnums = E_NUM_QUALITY_LEVELS;
+
+ static LLCDParam::LLCDEnumItem voxel_quality_enums[E_NUM_QUALITY_LEVELS];
+ voxel_quality_enums[E_LOW_QUALITY].mName = "Low";
+ voxel_quality_enums[E_LOW_QUALITY].mValue = 200000;
+ voxel_quality_enums[E_NORMAL_QUALITY].mName = "Normal";
+ voxel_quality_enums[E_NORMAL_QUALITY].mValue = 400000;
+ voxel_quality_enums[E_HIGH_QUALITY].mName = "High";
+ voxel_quality_enums[E_HIGH_QUALITY].mValue = 800000;
+ voxel_quality_enums[E_VERY_HIGH_QUALITY].mName = "Very High";
+ voxel_quality_enums[E_VERY_HIGH_QUALITY].mValue = 1200000;
+ voxel_quality_enums[E_ULTRA_QUALITY].mName = "Ultra";
+ voxel_quality_enums[E_ULTRA_QUALITY].mValue = 1600000;
+ voxel_quality_enums[E_MAX_QUALITY].mName = "Maximum";
+ voxel_quality_enums[E_MAX_QUALITY].mValue = 2000000;
+
+ param.mDetails.mEnumValues.mEnumsArray = voxel_quality_enums;
+ param.mDefault.mIntOrEnumValue = 400000;
+ param.mStage = 0;
+ param.mReserved = -1;
+ mDecompParams.push_back(param);
+
+ param.mName = "Num Hulls";
+ param.mDescription = nullptr;
+ param.mType = LLCDParam::LLCD_FLOAT;
+ param.mDetails.mRange.mLow.mFloat = 1.f;
+ param.mDetails.mRange.mHigh.mFloat = MAX_HULLS;
+ param.mDetails.mRange.mDelta.mFloat = 1.f;
+ param.mDefault.mFloat = 8.f;
+ param.mStage = 0;
+ param.mReserved = -1;
+ mDecompParams.push_back(param);
+
+ param.mName = "Num Vertices";
+ param.mDescription = nullptr;
+ param.mType = LLCDParam::LLCD_FLOAT;
+ param.mDetails.mRange.mLow.mFloat = 3.f;
+ param.mDetails.mRange.mHigh.mFloat = MAX_VERTICES_PER_HULL;
+ param.mDetails.mRange.mDelta.mFloat = 1.f;
+ param.mDefault.mFloat = 32.f;
+ param.mStage = 0;
+ param.mReserved = -1;
+ mDecompParams.push_back(param);
+
+ param.mName = "Error Tolerance";
+ param.mDescription = nullptr;
+ param.mType = LLCDParam::LLCD_FLOAT;
+ param.mDetails.mRange.mLow.mFloat = 0.0001f;
+ param.mDetails.mRange.mHigh.mFloat = 99.f;
+ param.mDetails.mRange.mDelta.mFloat = 0.001f;
+ param.mDefault.mFloat = 1.f;
+ param.mStage = 0;
+ param.mReserved = -1;
+ mDecompParams.push_back(param);
+
+ for (const LLCDParam& param : mDecompParams)
+ {
+ const char* const name = param.mName;
+
+ switch (param.mType)
+ {
+ case LLCDParam::LLCD_FLOAT:
+ {
+ setParam(name, param.mDefault.mFloat);
+ break;
+ }
+ case LLCDParam::LLCD_ENUM:
+ case LLCDParam::LLCD_INTEGER:
+ {
+ setParam(name, param.mDefault.mIntOrEnumValue);
+ break;
+ }
+ case LLCDParam::LLCD_BOOLEAN:
+ {
+ setParam(name, (param.mDefault.mBool != 0));
+ break;
+ }
+ case LLCDParam::LLCD_INVALID:
+ default:
+ {
+ break;
+ }
+ }
+ }
+}
+
+LLConvexDecompositionVHACD::~LLConvexDecompositionVHACD()
+{
+ mBoundDecomp = nullptr;
+ mDecompData.clear();
+
+ mVHACD->Release();
+}
+
+void LLConvexDecompositionVHACD::genDecomposition(int& decomp)
+{
+ int new_decomp_id = static_cast<int>(mDecompData.size()) + 1;
+ mDecompData[new_decomp_id] = LLDecompData();
+ decomp = new_decomp_id;
+}
+
+void LLConvexDecompositionVHACD::deleteDecomposition(int decomp)
+{
+ auto iter = mDecompData.find(decomp);
+ if (iter != mDecompData.end())
+ {
+ if (mBoundDecomp == &iter->second)
+ {
+ mBoundDecomp = nullptr;
+ }
+ mDecompData.erase(iter);
+ }
+}
+
+void LLConvexDecompositionVHACD::bindDecomposition(int decomp)
+{
+ auto iter = mDecompData.find(decomp);
+ if (iter != mDecompData.end())
+ {
+ mBoundDecomp = &iter->second;
+ }
+ else
+ {
+ LL_WARNS() << "Failed to bind unknown decomposition: " << decomp << LL_ENDL;
+ mBoundDecomp = nullptr;
+ }
+}
+
+LLCDResult LLConvexDecompositionVHACD::setParam(const char* name, float val)
+{
+ if (name == std::string("Num Hulls"))
+ {
+ mVHACDParameters.m_maxConvexHulls = llclamp(ll_round(val), 1, MAX_HULLS);
+ }
+ else if (name == std::string("Num Vertices"))
+ {
+ mVHACDParameters.m_maxNumVerticesPerCH = llclamp(ll_round(val), 3, MAX_VERTICES_PER_HULL);
+ }
+ else if (name == std::string("Error Tolerance"))
+ {
+ mVHACDParameters.m_minimumVolumePercentErrorAllowed = val;
+ }
+ return LLCD_OK;
+}
+
+LLCDResult LLConvexDecompositionVHACD::setParam(const char* name, bool val)
+{
+ return LLCD_OK;
+}
+
+LLCDResult LLConvexDecompositionVHACD::setParam(const char* name, int val)
+{
+ if (name == std::string("Fill Mode"))
+ {
+ mVHACDParameters.m_fillMode = (VHACD::FillMode)val;
+ }
+ else if (name == std::string("Voxel Resolution"))
+ {
+ mVHACDParameters.m_resolution = val;
+ }
+ return LLCD_OK;
+}
+
+LLCDResult LLConvexDecompositionVHACD::setMeshData( const LLCDMeshData* data, bool vertex_based )
+{
+ if (!mBoundDecomp)
+ {
+ return LLCD_NULL_PTR;
+ }
+
+ return mBoundDecomp->mSourceMesh.from(data, vertex_based);
+}
+
+LLCDResult LLConvexDecompositionVHACD::registerCallback(int stage, llcdCallbackFunc callback )
+{
+ if (stage == 0)
+ {
+ mVHACDCallback.setCallbackFunc(callback);
+ return LLCD_OK;
+ }
+ else
+ {
+ return LLCD_INVALID_STAGE;
+ }
+}
+
+LLCDResult LLConvexDecompositionVHACD::executeStage(int stage)
+{
+ if (!mBoundDecomp)
+ {
+ return LLCD_NULL_PTR;
+ }
+
+ if (stage != 0)
+ {
+ return LLCD_INVALID_STAGE;
+ }
+
+ mBoundDecomp->mDecomposedHulls.clear();
+
+ const auto& decomp_mesh = mBoundDecomp->mSourceMesh;
+ if (!mVHACD->Compute((const double* const)decomp_mesh.mVertices.data(), static_cast<uint32_t>(decomp_mesh.mVertices.size()), (const uint32_t* const)decomp_mesh.mIndices.data(), static_cast<uint32_t>(decomp_mesh.mIndices.size()), mVHACDParameters))
+ {
+ return LLCD_INVALID_HULL_DATA;
+ }
+
+ uint32_t num_nulls = mVHACD->GetNConvexHulls();
+ if (num_nulls == 0)
+ {
+ return LLCD_INVALID_HULL_DATA;
+ }
+
+ for (uint32_t i = 0; num_nulls > i; ++i)
+ {
+ VHACD::IVHACD::ConvexHull ch;
+ if (!mVHACD->GetConvexHull(i, ch))
+ continue;
+
+ LLConvexMesh out_mesh;
+ out_mesh.setVertices(ch.m_points);
+ out_mesh.setIndices(ch.m_triangles);
+
+ mBoundDecomp->mDecomposedHulls.push_back(std::move(out_mesh));
+ }
+
+ mVHACD->Clean();
+
+ return LLCD_OK;
+}
+
+LLCDResult LLConvexDecompositionVHACD::buildSingleHull()
+{
+ LL_INFOS() << "Building single hull mesh" << LL_ENDL;
+ if (!mBoundDecomp || mBoundDecomp->mSourceMesh.mVertices.empty())
+ {
+ return LLCD_NULL_PTR;
+ }
+
+ mBoundDecomp->mSingleHullMesh.clear();
+
+ VHACD::QuickHull quickhull;
+ uint32_t num_tris = quickhull.ComputeConvexHull(mBoundDecomp->mSourceMesh.mVertices, MAX_VERTICES_PER_HULL);
+ if (num_tris > 0)
+ {
+ mBoundDecomp->mSingleHullMesh.setVertices(quickhull.GetVertices());
+ mBoundDecomp->mSingleHullMesh.setIndices(quickhull.GetIndices());
+
+ return LLCD_OK;
+ }
+
+ return LLCD_INVALID_MESH_DATA;
+}
+
+int LLConvexDecompositionVHACD::getNumHullsFromStage(int stage)
+{
+ if (!mBoundDecomp || stage != 0)
+ {
+ return 0;
+ }
+
+ return narrow(mBoundDecomp->mDecomposedHulls.size());
+}
+
+LLCDResult LLConvexDecompositionVHACD::getSingleHull( LLCDHull* hullOut )
+{
+ memset( hullOut, 0, sizeof(LLCDHull) );
+
+ if (!mBoundDecomp)
+ {
+ return LLCD_NULL_PTR;
+ }
+
+ if (mBoundDecomp->mSingleHullMesh.vertices.empty())
+ {
+ return LLCD_INVALID_HULL_DATA;
+ }
+
+ mBoundDecomp->mSingleHullMesh.to(hullOut);
+ return LLCD_OK;
+}
+
+LLCDResult LLConvexDecompositionVHACD::getHullFromStage( int stage, int hull, LLCDHull* hullOut )
+{
+ memset( hullOut, 0, sizeof(LLCDHull) );
+
+ if (!mBoundDecomp)
+ {
+ return LLCD_NULL_PTR;
+ }
+
+ if (stage != 0)
+ {
+ return LLCD_INVALID_STAGE;
+ }
+
+ if (mBoundDecomp->mDecomposedHulls.empty() || mBoundDecomp->mDecomposedHulls.size() <= hull)
+ {
+ return LLCD_REQUEST_OUT_OF_RANGE;
+ }
+
+ mBoundDecomp->mDecomposedHulls[hull].to(hullOut);
+ return LLCD_OK;
+}
+
+LLCDResult LLConvexDecompositionVHACD::getMeshFromStage( int stage, int hull, LLCDMeshData* meshDataOut )
+{
+ memset( meshDataOut, 0, sizeof(LLCDMeshData));
+ if (!mBoundDecomp)
+ {
+ return LLCD_NULL_PTR;
+ }
+
+ if (stage != 0)
+ {
+ return LLCD_INVALID_STAGE;
+ }
+
+ if (mBoundDecomp->mDecomposedHulls.empty() || mBoundDecomp->mDecomposedHulls.size() <= hull)
+ {
+ return LLCD_REQUEST_OUT_OF_RANGE;
+ }
+
+ mBoundDecomp->mDecomposedHulls[hull].to(meshDataOut);
+ return LLCD_OK;
+}
+
+LLCDResult LLConvexDecompositionVHACD::getMeshFromHull( LLCDHull* hullIn, LLCDMeshData* meshOut )
+{
+ memset(meshOut, 0, sizeof(LLCDMeshData));
+
+ LLVHACDMesh inMesh(hullIn);
+
+ VHACD::QuickHull quickhull;
+ uint32_t num_tris = quickhull.ComputeConvexHull(inMesh.mVertices, MAX_VERTICES_PER_HULL);
+ if (num_tris > 0)
+ {
+ mMeshFromHullData.setVertices(quickhull.GetVertices());
+ mMeshFromHullData.setIndices(quickhull.GetIndices());
+
+ mMeshFromHullData.to(meshOut);
+ return LLCD_OK;
+ }
+
+ return LLCD_INVALID_HULL_DATA;
+}
+
+LLCDResult LLConvexDecompositionVHACD::generateSingleHullMeshFromMesh(LLCDMeshData* meshIn, LLCDMeshData* meshOut)
+{
+ memset( meshOut, 0, sizeof(LLCDMeshData) );
+
+ LLVHACDMesh inMesh(meshIn, true);
+
+ VHACD::QuickHull quickhull;
+ uint32_t num_tris = quickhull.ComputeConvexHull(inMesh.mVertices, MAX_VERTICES_PER_HULL);
+ if (num_tris > 0)
+ {
+ mSingleHullMeshFromMeshData.setVertices(quickhull.GetVertices());
+ mSingleHullMeshFromMeshData.setIndices(quickhull.GetIndices());
+
+ mSingleHullMeshFromMeshData.to(meshOut);
+ return LLCD_OK;
+ }
+
+ return LLCD_INVALID_MESH_DATA;
+}
+
+void LLConvexDecompositionVHACD::loadMeshData(const char* fileIn, LLCDMeshData** meshDataOut)
+{
+ static LLCDMeshData meshData;
+ memset( &meshData, 0, sizeof(LLCDMeshData) );
+ *meshDataOut = &meshData;
+}
diff --git a/indra/llconvexdecomposition/llconvexdecompositionvhacd.h b/indra/llconvexdecomposition/llconvexdecompositionvhacd.h
new file mode 100644
index 0000000000..675356629c
--- /dev/null
+++ b/indra/llconvexdecomposition/llconvexdecompositionvhacd.h
@@ -0,0 +1,339 @@
+/**
+* @file llconvexdecompositionvhacd.h
+* @author rye@alchemyviewer.org
+* @brief A VHACD based implementation of LLConvexDecomposition
+*
+* $LicenseInfo:firstyear=2025&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2025, 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_CONVEX_DECOMP_UTIL_VHACD_H
+#define LL_CONVEX_DECOMP_UTIL_VHACD_H
+
+#include "llconvexdecomposition.h"
+#include "llsingleton.h"
+#include "llmath.h"
+
+#include <vector>
+
+#include "VHACD.h"
+
+class LLDecompDataVHACD;
+
+class LLConvexDecompositionVHACD : public LLSimpleton<LLConvexDecompositionVHACD>, public LLConvexDecomposition
+{
+ class VHACDCallback : public VHACD::IVHACD::IUserCallback
+ {
+ public:
+ void Update(const double overallProgress, const double stageProgress, const char* const stage, const char* operation) override
+ {
+ std::string out_msg = llformat("Stage: %s Operation: %s", stage, operation);
+ if (mCurrentStage != stage && mCurrentOperation != operation)
+ {
+ mCurrentStage = stage;
+ mCurrentOperation = operation;
+ LL_INFOS("VHACD") << out_msg << LL_ENDL;
+ }
+
+ if(mCallbackFunc)
+ {
+ mCallbackFunc(out_msg.c_str(), ll_round(static_cast<F32>(stageProgress)), ll_round(static_cast<F32>(overallProgress)));
+ }
+ }
+
+ void setCallbackFunc(llcdCallbackFunc func)
+ {
+ mCallbackFunc = func;
+ }
+
+ private:
+ std::string mCurrentStage;
+ std::string mCurrentOperation;
+ llcdCallbackFunc mCallbackFunc = nullptr;
+ };
+
+ class VHACDLogger : public VHACD::IVHACD::IUserLogger
+ {
+ void Log(const char* const msg) override
+ {
+ LL_INFOS("VHACD") << msg << LL_ENDL;
+ }
+ };
+
+public:
+
+ LLConvexDecompositionVHACD();
+ virtual ~LLConvexDecompositionVHACD();
+
+ static bool isFunctional();
+ static LLConvexDecomposition* getInstance();
+ static LLCDResult initSystem();
+ static LLCDResult initThread();
+ static LLCDResult quitThread();
+ static LLCDResult quitSystem();
+
+ void genDecomposition(int& decomp);
+ void deleteDecomposition(int decomp);
+ void bindDecomposition(int decomp);
+
+ // Sets *paramsOut to the address of the LLCDParam array and returns
+ // the length of the array
+ int getParameters(const LLCDParam** paramsOut)
+ {
+ *paramsOut = mDecompParams.data();
+ return narrow(mDecompParams.size());
+ }
+
+ int getStages(const LLCDStageData** stagesOut)
+ {
+ *stagesOut = mDecompStages.data();
+ return narrow(mDecompStages.size());
+ }
+
+ // Set a parameter by name. Returns false if out of bounds or unsupported parameter
+ LLCDResult setParam(const char* name, float val);
+ LLCDResult setParam(const char* name, int val);
+ LLCDResult setParam(const char* name, bool val);
+ LLCDResult setMeshData( const LLCDMeshData* data, bool vertex_based );
+ LLCDResult registerCallback(int stage, llcdCallbackFunc callback );
+
+ LLCDResult executeStage(int stage);
+ LLCDResult buildSingleHull();
+
+ int getNumHullsFromStage(int stage);
+
+ LLCDResult getHullFromStage( int stage, int hull, LLCDHull* hullOut );
+ LLCDResult getSingleHull( LLCDHull* hullOut ) ;
+
+ // TODO: Implement lock of some kind to disallow this call if data not yet ready
+ LLCDResult getMeshFromStage( int stage, int hull, LLCDMeshData* meshDataOut);
+ LLCDResult getMeshFromHull( LLCDHull* hullIn, LLCDMeshData* meshOut );
+
+ // For visualizing convex hull shapes in the viewer physics shape display
+ LLCDResult generateSingleHullMeshFromMesh( LLCDMeshData* meshIn, LLCDMeshData* meshOut);
+
+ /// Debug
+ void loadMeshData(const char* fileIn, LLCDMeshData** meshDataOut);
+
+private:
+ std::vector<LLCDParam> mDecompParams;
+ std::array<LLCDStageData, 1> mDecompStages;
+
+ struct LLVHACDMesh
+ {
+ using vertex_type = VHACD::Vertex;
+ using index_type = VHACD::Triangle;
+ using vertex_array_type = std::vector<vertex_type>;
+ using index_array_type = std::vector<index_type>;
+
+ LLVHACDMesh() = default;
+ LLVHACDMesh(const LLCDHull* hullIn)
+ {
+ if (hullIn)
+ {
+ from(hullIn);
+ }
+ };
+
+ LLVHACDMesh(const LLCDMeshData* meshIn, bool vertex_based)
+ {
+ if (meshIn)
+ {
+ from(meshIn, vertex_based);
+ }
+ };
+
+ void clear()
+ {
+ mVertices.clear();
+ mIndices.clear();
+ }
+
+ void setVertices(const float* data, int num_vertices, int vertex_stride_bytes)
+ {
+ vertex_array_type vertices;
+ vertices.reserve(num_vertices);
+
+ const int stride = vertex_stride_bytes / sizeof(float);
+ for (int i = 0; i < num_vertices; ++i)
+ {
+ vertices.emplace_back(data[i * stride + 0],
+ data[i * stride + 1],
+ data[i * stride + 2]);
+ }
+
+ mVertices = std::move(vertices);
+ }
+
+ void setIndices(const void* data, int num_indices, int index_stride_bytes, LLCDMeshData::IndexType type)
+ {
+ index_array_type indices;
+ indices.reserve(num_indices);
+
+ if (type == LLCDMeshData::INT_16)
+ {
+ const U16* index_data = static_cast<const U16*>(data);
+ const int stride = index_stride_bytes / sizeof(U16);
+ for (int i = 0; i < num_indices; ++i)
+ {
+ indices.emplace_back(index_data[i * stride + 0],
+ index_data[i * stride + 1],
+ index_data[i * stride + 2]);
+ }
+ }
+ else
+ {
+ const U32* index_data = static_cast<const U32*>(data);
+ const int stride = index_stride_bytes / sizeof(U32);
+ for (int i = 0; i < num_indices; ++i)
+ {
+ indices.emplace_back(index_data[i * stride + 0],
+ index_data[i * stride + 1],
+ index_data[i * stride + 2]);
+ }
+ }
+
+ mIndices = std::move(indices);
+ }
+
+ LLCDResult from(const LLCDHull* hullIn)
+ {
+ clear();
+
+ if (!hullIn || !hullIn->mVertexBase || (hullIn->mNumVertices < 3) || (hullIn->mVertexStrideBytes != 12 && hullIn->mVertexStrideBytes != 16))
+ {
+ return LLCD_INVALID_HULL_DATA;
+ }
+
+ setVertices(hullIn->mVertexBase, hullIn->mNumVertices, hullIn->mVertexStrideBytes);
+
+ return LLCD_OK;
+ }
+
+ LLCDResult from(const LLCDMeshData* meshIn, bool vertex_based)
+ {
+ clear();
+
+ if (!meshIn || !meshIn->mVertexBase || (meshIn->mNumVertices < 3) || (meshIn->mVertexStrideBytes != 12 && meshIn->mVertexStrideBytes != 16))
+ {
+ return LLCD_INVALID_MESH_DATA;
+ }
+
+ if (!vertex_based && ((meshIn->mNumTriangles < 1) || !meshIn->mIndexBase))
+ {
+ return LLCD_INVALID_MESH_DATA;
+ }
+
+ setVertices(meshIn->mVertexBase, meshIn->mNumVertices, meshIn->mVertexStrideBytes);
+ if(!vertex_based)
+ {
+ setIndices(meshIn->mIndexBase, meshIn->mNumTriangles, meshIn->mIndexStrideBytes, meshIn->mIndexType);
+ }
+
+ return LLCD_OK;
+ }
+
+ vertex_array_type mVertices;
+ index_array_type mIndices;
+ };
+
+ struct LLConvexMesh
+ {
+ using vertex_type = glm::vec3;
+ using index_type = glm::u32vec3;
+ using vertex_array_type = std::vector<vertex_type>;
+ using index_array_type = std::vector<index_type>;
+
+ LLConvexMesh() = default;
+
+ void clear()
+ {
+ vertices.clear();
+ indices.clear();
+ }
+
+ void setVertices(const std::vector<VHACD::Vertex>& in_vertices)
+ {
+ vertices.clear();
+ vertices.reserve(in_vertices.size());
+
+ for (const auto& vertex : in_vertices)
+ {
+ vertices.emplace_back(narrow(vertex.mX), narrow(vertex.mY), narrow(vertex.mZ));
+ }
+ }
+
+ void setIndices(const std::vector<VHACD::Triangle>& in_indices)
+ {
+ indices.clear();
+ indices.reserve(in_indices.size());
+
+ for (const auto& triangle : in_indices)
+ {
+ indices.emplace_back(narrow(triangle.mI0), narrow(triangle.mI1), narrow(triangle.mI2));
+ }
+ }
+
+ void to(LLCDHull* meshOut) const
+ {
+ meshOut->mVertexBase = (float*)vertices.data();
+ meshOut->mVertexStrideBytes = sizeof(vertex_type);
+ meshOut->mNumVertices = (int)vertices.size();
+ }
+
+ void to(LLCDMeshData* meshOut) const
+ {
+ meshOut->mVertexBase = (float*)vertices.data();
+ meshOut->mVertexStrideBytes = sizeof(vertex_type);
+ meshOut->mNumVertices = (int)vertices.size();
+
+ meshOut->mIndexType = LLCDMeshData::INT_32;
+ meshOut->mIndexBase = indices.data();
+ meshOut->mIndexStrideBytes = sizeof(index_type);
+ meshOut->mNumTriangles = (int)indices.size();
+ }
+
+ vertex_array_type vertices;
+ index_array_type indices;
+ };
+
+ struct LLDecompData
+ {
+ LLVHACDMesh mSourceMesh;
+ LLConvexMesh mSingleHullMesh;
+
+ std::vector<LLConvexMesh> mDecomposedHulls;
+ };
+
+ std::unordered_map<int, LLDecompData> mDecompData;
+
+ LLDecompData* mBoundDecomp = nullptr;
+
+ VHACD::IVHACD* mVHACD = nullptr;
+ VHACDCallback mVHACDCallback;
+ VHACDLogger mVHACDLogger;
+ VHACD::IVHACD::Parameters mVHACDParameters;
+
+ LLConvexMesh mMeshFromHullData;
+ LLConvexMesh mSingleHullMeshFromMeshData;
+};
+
+#endif //LL_CONVEX_DECOMP_UTIL_VHACD_H
diff --git a/indra/llprimitive/CMakeLists.txt b/indra/llprimitive/CMakeLists.txt
index e13f0bbd96..9e90314a51 100644
--- a/indra/llprimitive/CMakeLists.txt
+++ b/indra/llprimitive/CMakeLists.txt
@@ -70,6 +70,12 @@ target_link_libraries(llprimitive
ll::glm
)
+if (TARGET llconvexdecomposition)
+ target_link_libraries(llprimitive
+ llconvexdecomposition
+ )
+endif ()
+
#add unit tests
if (LL_TESTS)
INCLUDE(LLAddBuildTest)
diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp
index 00ef79ce7f..8055bffd32 100644
--- a/indra/llprimitive/llmodel.cpp
+++ b/indra/llprimitive/llmodel.cpp
@@ -1296,10 +1296,10 @@ LLModel::weight_list& LLModel::getJointInfluences(const LLVector3& pos)
}
void LLModel::setConvexHullDecomposition(
- const LLModel::convex_hull_decomposition& decomp)
+ const LLModel::convex_hull_decomposition& decomp, const std::vector<LLModel::PhysicsMesh>& decomp_mesh)
{
mPhysics.mHull = decomp;
- mPhysics.mMesh.clear();
+ mPhysics.mMesh = decomp_mesh;
updateHullCenters();
}
diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h
index 6501b3dc50..ac88af18f0 100644
--- a/indra/llprimitive/llmodel.h
+++ b/indra/llprimitive/llmodel.h
@@ -305,7 +305,8 @@ public:
S32 mDecompID;
void setConvexHullDecomposition(
- const convex_hull_decomposition& decomp);
+ const convex_hull_decomposition& decomp,
+ const std::vector<LLModel::PhysicsMesh>& decomp_mesh);
void updateHullCenters();
LLVector3 mCenterOfHullCenters;
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index c727d5ae57..0f7670a57a 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -1709,10 +1709,6 @@ if (WINDOWS)
list(APPEND viewer_SOURCE_FILES ${viewer_INSTALLER_FILES})
endif (WINDOWS)
-if (HAVOK OR HAVOK_TPV)
- set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_HAVOK")
-endif (HAVOK OR HAVOK_TPV)
-
if( DEFINED LLSTARTUP_COMPILE_FLAGS )
# progress view disables/enables icons based on available packages
set_source_files_properties(llprogressview.cpp PROPERTIES COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS}")
@@ -2029,6 +2025,10 @@ if( TARGET ll::nvapi )
target_link_libraries(${VIEWER_BINARY_NAME} ll::nvapi )
endif()
+if ( TARGET llconvexdecomposition )
+ target_link_libraries(${VIEWER_BINARY_NAME} llconvexdecomposition )
+endif ()
+
set(ARTWORK_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE PATH
"Path to artwork files.")
diff --git a/indra/newview/llfloatermarketplace.cpp b/indra/newview/llfloatermarketplace.cpp
index 889daf84ab..4abea64302 100644
--- a/indra/newview/llfloatermarketplace.cpp
+++ b/indra/newview/llfloatermarketplace.cpp
@@ -27,10 +27,11 @@
#include "llviewerprecompiledheaders.h"
#include "llfloatermarketplace.h"
+#include "llviewercontrol.h"
#include "lluictrlfactory.h"
LLFloaterMarketplace::LLFloaterMarketplace(const LLSD& key)
- : LLFloater(key)
+ : LLFloaterWebContent(key)
{
}
@@ -38,10 +39,25 @@ LLFloaterMarketplace::~LLFloaterMarketplace()
{
}
+// just to override LLFloaterWebContent
+void LLFloaterMarketplace::onClose(bool app_quitting)
+{
+}
+
bool LLFloaterMarketplace::postBuild()
{
- enableResizeCtrls(true, true, false);
+ LLFloaterWebContent::postBuild();
+ mWebBrowser = getChild<LLMediaCtrl>("marketplace_contents");
+ mWebBrowser->addObserver(this);
+
return true;
}
-
+void LLFloaterMarketplace::openMarketplace()
+{
+ std::string url = gSavedSettings.getString("MarketplaceURL");
+ if (mCurrentURL != url)
+ {
+ mWebBrowser->navigateTo(url, HTTP_CONTENT_TEXT_HTML);
+ }
+}
diff --git a/indra/newview/llfloatermarketplace.h b/indra/newview/llfloatermarketplace.h
index 2ae4d0d64a..9524c94eee 100644
--- a/indra/newview/llfloatermarketplace.h
+++ b/indra/newview/llfloatermarketplace.h
@@ -27,14 +27,20 @@
#pragma once
#include "llfloater.h"
+#include "llfloaterwebcontent.h"
class LLFloaterMarketplace:
- public LLFloater
+ public LLFloaterWebContent
{
friend class LLFloaterReg;
+
+public:
+ void openMarketplace();
+
private:
LLFloaterMarketplace(const LLSD& key);
~LLFloaterMarketplace();
bool postBuild() override;
+ void onClose(bool app_quitting) override;
};
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index f76f39222b..ef29be8200 100644
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -1035,8 +1035,13 @@ void LLFloaterModelPreview::onPhysicsStageExecute(LLUICtrl* ctrl, void* data)
gMeshRepo.mDecompThread->submitRequest(request);
}
}
-
- if (stage == "Decompose")
+ if (stage == "Analyze")
+ {
+ sInstance->setStatusMessage(sInstance->getString("decomposing"));
+ sInstance->childSetVisible("Analyze", false);
+ sInstance->childSetVisible("analyze_cancel", true);
+ }
+ else if (stage == "Decompose")
{
sInstance->setStatusMessage(sInstance->getString("decomposing"));
sInstance->childSetVisible("Decompose", false);
@@ -1137,6 +1142,7 @@ void LLFloaterModelPreview::initDecompControls()
childSetCommitCallback("simplify_cancel", onPhysicsStageCancel, NULL);
childSetCommitCallback("decompose_cancel", onPhysicsStageCancel, NULL);
+ childSetCommitCallback("analyze_cancel", onPhysicsStageCancel, NULL);
childSetCommitCallback("physics_lod_combo", onPhysicsUseLOD, NULL);
childSetCommitCallback("physics_browse", onPhysicsBrowse, NULL);
@@ -2018,7 +2024,7 @@ void LLFloaterModelPreview::DecompRequest::completed()
{ //called from the main thread
if (mContinue)
{
- mModel->setConvexHullDecomposition(mHull);
+ mModel->setConvexHullDecomposition(mHull, mHullMesh);
if (sInstance)
{
diff --git a/indra/newview/llfloatersearch.cpp b/indra/newview/llfloatersearch.cpp
index 8e6a47dce5..7ee1b88f05 100644
--- a/indra/newview/llfloatersearch.cpp
+++ b/indra/newview/llfloatersearch.cpp
@@ -66,7 +66,7 @@ class LLSearchHandler : public LLCommandHandler {
LLSearchHandler gSearchHandler;
LLFloaterSearch::LLFloaterSearch(const LLSD& key)
- : LLFloater(key)
+ : LLFloaterWebContent(key)
{
mSearchType.insert("standard");
mSearchType.insert("land");
@@ -86,6 +86,12 @@ LLFloaterSearch::~LLFloaterSearch()
void LLFloaterSearch::onOpen(const LLSD& tokens)
{
initiateSearch(tokens);
+ mWebBrowser->setFocus(true);
+}
+
+// just to override LLFloaterWebContent
+void LLFloaterSearch::onClose(bool app_quitting)
+{
}
void LLFloaterSearch::initiateSearch(const LLSD& tokens)
@@ -161,7 +167,11 @@ void LLFloaterSearch::initiateSearch(const LLSD& tokens)
bool LLFloaterSearch::postBuild()
{
- enableResizeCtrls(true, true, false);
+ LLFloaterWebContent::postBuild();
+ mWebBrowser = getChild<LLMediaCtrl>("search_contents");
+ mWebBrowser->addObserver(this);
+ getChildView("address")->setEnabled(false);
+ getChildView("popexternal")->setEnabled(false);
// This call is actioned by the preload code in llViewerWindow
// that creates the search floater during the login process
diff --git a/indra/newview/llfloatersearch.h b/indra/newview/llfloatersearch.h
index e8a2be4797..6d93474f4a 100644
--- a/indra/newview/llfloatersearch.h
+++ b/indra/newview/llfloatersearch.h
@@ -27,13 +27,15 @@
#pragma once
#include "llfloater.h"
+#include "llfloaterwebcontent.h"
class LLFloaterSearch:
- public LLFloater {
+ public LLFloaterWebContent {
friend class LLFloaterReg;
public:
void onOpen(const LLSD& key) override;
+ void onClose(bool app_quitting) override;
private:
LLFloaterSearch(const LLSD& key);
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index e0f942b083..413f02b723 100644
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -256,6 +256,7 @@
// mDecompositionRequests mMutex rw.repo.mMutex, ro.repo.none [5]
// mPhysicsShapeRequests mMutex rw.repo.mMutex, ro.repo.none [5]
// mDecompositionQ mMutex rw.repo.mLoadedMutex, rw.main.mLoadedMutex [5] (was: [0])
+// mPhysicsQ mMutex rw.repo.mLoadedMutex, rw.main.mLoadedMutex [5] (was: [0])
// mHeaderReqQ mMutex ro.repo.none [5], rw.repo.mMutex, rw.any.mMutex
// mLODReqQ mMutex ro.repo.none [5], rw.repo.mMutex, rw.any.mMutex
// mUnavailableQ mMutex rw.repo.none [0], ro.main.none [5], rw.main.mLoadedMutex
@@ -982,6 +983,12 @@ LLMeshRepoThread::~LLMeshRepoThread()
mDecompositionQ.pop_front();
}
+ while (!mPhysicsQ.empty())
+ {
+ delete mPhysicsQ.front();
+ mPhysicsQ.pop_front();
+ }
+
delete mHttpRequest;
mHttpRequest = nullptr;
delete mMutex;
@@ -2565,7 +2572,7 @@ EMeshProcessingResult LLMeshRepoThread::physicsShapeReceived(const LLUUID& mesh_
{
LLMutexLock lock(mLoadedMutex);
- mDecompositionQ.push_back(d);
+ mPhysicsQ.push_back(d);
}
return MESH_OK;
}
@@ -3376,13 +3383,14 @@ void LLMeshRepoThread::notifyLoadedMeshes()
}
}
- if (!mSkinInfoQ.empty() || !mSkinUnavailableQ.empty() || ! mDecompositionQ.empty())
+ if (!mSkinInfoQ.empty() || !mSkinUnavailableQ.empty() || !mDecompositionQ.empty() || !mPhysicsQ.empty())
{
if (mLoadedMutex->trylock())
{
std::deque<LLPointer<LLMeshSkinInfo>> skin_info_q;
std::deque<UUIDBasedRequest> skin_info_unavail_q;
std::list<LLModel::Decomposition*> decomp_q;
+ std::list<LLModel::Decomposition*> physics_q;
if (! mSkinInfoQ.empty())
{
@@ -3399,6 +3407,11 @@ void LLMeshRepoThread::notifyLoadedMeshes()
decomp_q.swap(mDecompositionQ);
}
+ if (!mPhysicsQ.empty())
+ {
+ physics_q.swap(mPhysicsQ);
+ }
+
mLoadedMutex->unlock();
// Process the elements free of the lock
@@ -3415,9 +3428,15 @@ void LLMeshRepoThread::notifyLoadedMeshes()
while (! decomp_q.empty())
{
- gMeshRepo.notifyDecompositionReceived(decomp_q.front());
+ gMeshRepo.notifyDecompositionReceived(decomp_q.front(), false);
decomp_q.pop_front();
}
+
+ while (!physics_q.empty())
+ {
+ gMeshRepo.notifyDecompositionReceived(physics_q.front(), true);
+ physics_q.pop_front();
+ }
}
}
@@ -4659,13 +4678,13 @@ void LLMeshRepository::notifySkinInfoUnavailable(const LLUUID& mesh_id)
}
}
-void LLMeshRepository::notifyDecompositionReceived(LLModel::Decomposition* decomp)
+void LLMeshRepository::notifyDecompositionReceived(LLModel::Decomposition* decomp, bool physics_mesh)
{
- decomposition_map::iterator iter = mDecompositionMap.find(decomp->mMeshID);
+ LLUUID decomp_id = decomp->mMeshID; // Copy to avoid invalidation in below deletion
+ decomposition_map::iterator iter = mDecompositionMap.find(decomp_id);
if (iter == mDecompositionMap.end())
{ //just insert decomp into map
- mDecompositionMap[decomp->mMeshID] = decomp;
- mLoadingDecompositions.erase(decomp->mMeshID);
+ mDecompositionMap[decomp_id] = decomp;
sCacheBytesDecomps += decomp->sizeBytes();
}
else
@@ -4673,10 +4692,17 @@ void LLMeshRepository::notifyDecompositionReceived(LLModel::Decomposition* decom
sCacheBytesDecomps -= iter->second->sizeBytes();
iter->second->merge(decomp);
sCacheBytesDecomps += iter->second->sizeBytes();
-
- mLoadingDecompositions.erase(decomp->mMeshID);
delete decomp;
}
+
+ if (physics_mesh)
+ {
+ mLoadingPhysicsShapes.erase(decomp_id);
+ }
+ else
+ {
+ mLoadingDecompositions.erase(decomp_id);
+ }
}
void LLMeshRepository::notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVolume* volume, S32 lod)
@@ -4823,7 +4849,6 @@ void LLMeshRepository::fetchPhysicsShape(const LLUUID& mesh_id)
std::unordered_set<LLUUID>::iterator iter = mLoadingPhysicsShapes.find(mesh_id);
if (iter == mLoadingPhysicsShapes.end())
{ //no request pending for this skin info
- // *FIXME: Nothing ever deletes entries, can't be right
mLoadingPhysicsShapes.insert(mesh_id);
mPendingPhysicsShapeRequests.push(mesh_id);
}
diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h
index 450afd5d5a..01b51e753e 100644
--- a/indra/newview/llmeshrepository.h
+++ b/indra/newview/llmeshrepository.h
@@ -521,6 +521,9 @@ public:
// list of completed Decomposition info requests
std::list<LLModel::Decomposition*> mDecompositionQ;
+ // list of completed Physics Mesh info requests
+ std::list<LLModel::Decomposition*> mPhysicsQ;
+
//queue of requested headers
std::queue<HeaderRequest> mHeaderReqQ;
@@ -871,7 +874,7 @@ public:
void notifyMeshUnavailable(const LLVolumeParams& mesh_params, S32 request_lod, S32 volume_lod);
void notifySkinInfoReceived(LLMeshSkinInfo* info);
void notifySkinInfoUnavailable(const LLUUID& info);
- void notifyDecompositionReceived(LLModel::Decomposition* info);
+ void notifyDecompositionReceived(LLModel::Decomposition* info, bool physics_mesh);
S32 getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod);
static S32 getActualMeshLOD(LLMeshHeader& header, S32 lod);
diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index 46411fc4a0..6b1fbdce4c 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -2626,7 +2626,16 @@ void LLModelPreview::updateStatusMessages()
//enable = enable && !use_hull && fmp->childGetValue("physics_optimize").asBoolean();
//enable/disable "analysis" UI
- LLPanel* panel = fmp->getChild<LLPanel>("physics analysis");
+#if LL_HAVOK
+ LLPanel* panel = fmp->getChild<LLPanel>("physics simplification");
+ panel->setVisible(true);
+
+ panel = fmp->getChild<LLPanel>("physics analysis havok");
+ panel->setVisible(true);
+#else
+ LLPanel* panel = fmp->getChild<LLPanel>("physics analysis vhacd");
+ panel->setVisible(true);
+#endif
LLView* child = panel->getFirstChild();
while (child)
{
@@ -2650,6 +2659,8 @@ void LLModelPreview::updateStatusMessages()
fmp->childSetVisible("simplify_cancel", false);
fmp->childSetVisible("Decompose", true);
fmp->childSetVisible("decompose_cancel", false);
+ fmp->childSetVisible("Analyze", true);
+ fmp->childSetVisible("analyze_cancel", false);
if (phys_hulls > 0)
{
@@ -2659,6 +2670,7 @@ void LLModelPreview::updateStatusMessages()
if (phys_tris || phys_hulls > 0)
{
fmp->childEnable("Decompose");
+ fmp->childEnable("Analyze");
}
}
else
diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp
index 82c959d7f7..2727127633 100644
--- a/indra/newview/llstatusbar.cpp
+++ b/indra/newview/llstatusbar.cpp
@@ -41,6 +41,7 @@
#include "llpanelpresetscamerapulldown.h"
#include "llpanelpresetspulldown.h"
#include "llpanelvolumepulldown.h"
+#include "llfloatermarketplace.h"
#include "llfloaterregioninfo.h"
#include "llfloaterscriptdebug.h"
#include "llhints.h"
@@ -523,7 +524,11 @@ void LLStatusBar::onClickBuyCurrency()
void LLStatusBar::onClickShop()
{
- LLFloaterReg::toggleInstanceOrBringToFront("marketplace");
+ LLFloaterReg::showInstanceOrBringToFront("marketplace");
+ if (LLFloaterMarketplace* marketplace = LLFloaterReg::getTypedInstance<LLFloaterMarketplace>("marketplace"))
+ {
+ marketplace->openMarketplace();
+ }
}
void LLStatusBar::onMouseEnterPresetsCamera()
diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp
index 3695478061..801ff3c212 100644
--- a/indra/newview/llviewermenufile.cpp
+++ b/indra/newview/llviewermenufile.cpp
@@ -912,7 +912,23 @@ class LLFileUploadModel : public view_listener_t
{
bool handleEvent(const LLSD& userdata)
{
- LLFloaterModelPreview::showModelPreview();
+ if (LLConvexDecomposition::isFunctional())
+ {
+ LLFloaterModelPreview::showModelPreview();
+ }
+ else
+ {
+ if (gGLManager.mIsApple)
+ {
+ LLNotificationsUtil::add("ModelUploaderMissingPhysicsApple");
+ }
+ else
+ {
+ // TPV?
+ LLNotificationsUtil::add("ModelUploaderMissingPhysics");
+ LLFloaterModelPreview::showModelPreview();
+ }
+ }
return true;
}
};
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index d72d428c08..fb9e5fd0a9 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -1070,7 +1070,7 @@ void LLViewerObjectList::fetchObjectCostsCoro(std::string url)
if (diff.empty())
{
- LL_INFOS() << "No outstanding object IDs to request. Pending count: " << mPendingObjectCost.size() << LL_ENDL;
+ LL_DEBUGS() << "No outstanding object IDs to request. Pending count: " << mPendingObjectCost.size() << LL_ENDL;
return;
}
@@ -1205,7 +1205,7 @@ void LLViewerObjectList::fetchPhisicsFlagsCoro(std::string url)
if (idList.size() < 1)
{
- LL_INFOS() << "No outstanding object physics flags to request." << LL_ENDL;
+ LL_DEBUGS() << "No outstanding object physics flags to request." << LL_ENDL;
return;
}
diff --git a/indra/newview/skins/default/xui/en/floater_marketplace.xml b/indra/newview/skins/default/xui/en/floater_marketplace.xml
index 2299e02c63..99fb3a1ad8 100644
--- a/indra/newview/skins/default/xui/en/floater_marketplace.xml
+++ b/indra/newview/skins/default/xui/en/floater_marketplace.xml
@@ -1,26 +1,201 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<floater
- positioning="cascading"
- legacy_header_height="225"
- can_minimize="true"
- can_close="true"
- can_resize="true"
- min_height="800"
- min_width="800"
- height="800"
- layout="topleft"
- name="Marketplace"
- single_instance="true"
- help_topic="marketplace"
- save_rect="true"
- save_visibility="true"
- title="MARKETPLACE"
- width="800">
- <web_browser
- top="25"
- height="775"
- width="800"
- follows="all"
- name="marketplace_contents"
- trusted_content="true"/>
+ legacy_header_height="18"
+ can_minimize="true"
+ can_close="true"
+ can_resize="true"
+ height="775"
+ layout="topleft"
+ min_height="500"
+ min_width="600"
+ name="Marketplace"
+ save_rect="true"
+ single_instance="true"
+ save_visibility="true"
+ title="MARKETPLACE"
+ tab_stop="true"
+ width="780">
+ <layout_stack
+ bottom="775"
+ follows="left|right|top|bottom"
+ layout="topleft"
+ left="5"
+ animate="false"
+ name="stack1"
+ orientation="vertical"
+ top="20"
+ width="770">
+ <layout_panel
+ auto_resize="false"
+ default_tab_group="1"
+ height="22"
+ layout="topleft"
+ left="0"
+ min_height="20"
+ name="nav_controls"
+ top="400"
+ width="770">
+ <button
+ image_overlay="Arrow_Left_Off"
+ image_disabled="PushButton_Disabled"
+ image_disabled_selected="PushButton_Disabled"
+ image_selected="PushButton_Selected"
+ image_unselected="PushButton_Off"
+ chrome="true"
+ hover_glow_amount="0.15"
+ tool_tip="Navigate back"
+ follows="left|top"
+ height="22"
+ layout="topleft"
+ left="1"
+ name="back"
+ top="0"
+ width="22">
+ <button.commit_callback
+ function="WebContent.Back" />
+ </button>
+ <button
+ image_overlay="Arrow_Right_Off"
+ image_disabled="PushButton_Disabled"
+ image_disabled_selected="PushButton_Disabled"
+ image_selected="PushButton_Selected"
+ image_unselected="PushButton_Off"
+ chrome="true"
+ tool_tip="Navigate forward"
+ follows="left|top"
+ height="22"
+ layout="topleft"
+ left="27"
+ name="forward"
+ top_delta="0"
+ width="22">
+ <button.commit_callback
+ function="WebContent.Forward" />
+ </button>
+ <button
+ image_overlay="Stop_Off"
+ image_disabled="PushButton_Disabled"
+ image_disabled_selected="PushButton_Disabled"
+ image_selected="PushButton_Selected"
+ image_unselected="PushButton_Off"
+ chrome="true"
+ tool_tip="Stop navigation"
+ enabled="true"
+ follows="left|top"
+ height="22"
+ layout="topleft"
+ left="51"
+ name="stop"
+ top_delta="0"
+ width="22">
+ <button.commit_callback
+ function="WebContent.Stop" />
+ </button>
+ <button
+ image_overlay="Refresh_Off"
+ image_disabled="PushButton_Disabled"
+ image_disabled_selected="PushButton_Disabled"
+ image_selected="PushButton_Selected"
+ image_unselected="PushButton_Off"
+ chrome="true"
+ tool_tip="Reload page"
+ follows="left|top"
+ height="22"
+ layout="topleft"
+ left="51"
+ name="reload"
+ top_delta="0"
+ width="22">
+ <button.commit_callback
+ function="WebContent.Reload" />
+ </button>
+ <combo_box
+ allow_text_entry="true"
+ follows="left|top|right"
+ tab_group="1"
+ height="22"
+ layout="topleft"
+ left_pad="4"
+ max_chars="1024"
+ name="address"
+ combo_editor.select_on_focus="true"
+ tool_tip="Enter URL here"
+ top_delta="0"
+ width="672">
+ <combo_box.commit_callback
+ function="WebContent.EnterAddress" />
+ </combo_box>
+ <icon
+ name="media_secure_lock_flag"
+ height="16"
+ follows="top|left"
+ image_name="Lock2"
+ layout="topleft"
+ left_delta="2"
+ top_delta="2"
+ visible="false"
+ tool_tip="Secured Browsing"
+ width="16" />
+ <button
+ image_overlay="ExternalBrowser_Off"
+ image_disabled="PushButton_Disabled"
+ image_disabled_selected="PushButton_Disabled"
+ image_selected="PushButton_Selected"
+ image_unselected="PushButton_Off"
+ chrome="true"
+ tool_tip="Open current URL in your desktop browser"
+ follows="right|top"
+ enabled="true"
+ height="22"
+ layout="topleft"
+ name="popexternal"
+ right="770"
+ top_delta="-2"
+ width="22">
+ <button.commit_callback
+ function="WebContent.PopExternal" />
+ </button>
+ </layout_panel>
+ <layout_panel
+ height="40"
+ layout="topleft"
+ left_delta="0"
+ name="external_controls"
+ top_delta="0"
+ auto_resize="true"
+ width="585">
+ <web_browser
+ bottom="-2"
+ follows="all"
+ layout="topleft"
+ left="0"
+ name="marketplace_contents"
+ top="0"/>
+ </layout_panel>
+ <layout_panel name="status_bar"
+ height="23"
+ auto_resize="false">
+ <text
+ type="string"
+ length="200"
+ follows="bottom|left"
+ height="20"
+ layout="topleft"
+ left_delta="0"
+ name="statusbartext"
+ parse_urls="false"
+ text_color="0.4 0.4 0.4 1"
+ top_pad="3"
+ width="495"/>
+ <progress_bar
+ color_bar="0.3 1.0 0.3 1"
+ follows="bottom|right"
+ height="16"
+ top_delta="-1"
+ left_pad="24"
+ layout="topleft"
+ name="statusbarprogress"
+ width="64"/>
+ </layout_panel>
+ </layout_stack>
</floater>
diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml
index f11d687840..39e9de0980 100644
--- a/indra/newview/skins/default/xui/en/floater_model_preview.xml
+++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml
@@ -40,7 +40,7 @@
<string name="simplifying">Simplifying...</string>
<string name="tbd">TBD</string>
<string name="ModelTextureScaling">One or more textures in this model were scaled to be within the allowed limits.</string>
-
+
<!-- Warnings and info from model loader-->
<string name="TooManyJoint">Skinning disabled due to too many joints: [JOINTS], maximum: [MAX]</string>
<string name="UnrecognizedJoint">Rigged to unrecognized joint name [NAME]</string>
@@ -807,7 +807,7 @@
help_topic="upload_model_physics"
label="Physics"
name="physics_panel">
-
+
<!-- ==== STEP 1: Level of Detail ==== -->
<view_border
bevel_style="none"
@@ -873,7 +873,7 @@
<!-- <check_box name="physics_optimize" follows="left|top" width="130" left="10" top_pad="5" height="20" label="Optimize"/>
<check_box name="physics_use_hull" follows="left|top" width="130" left_pad="5" height="20" label="Use Convex Hull"/> -->
</panel>
-
+
<!-- ==== STEP 2: Analyze ==== -->
<view_border
bevel_style="none"
@@ -890,9 +890,9 @@
height="65"
follows="top|left"
left="18"
- name="physics analysis"
+ name="physics analysis havok"
top_pad="10"
- visible="true"
+ visible="false"
width="589">
<text
follows="left|top"
@@ -980,7 +980,131 @@
visible="false"
width="90"/>
</panel>
-
+ <panel
+ bg_alpha_color="0 0 0 0"
+ bg_opaque_color="0 0 0 0.3"
+ height="65"
+ follows="top|left"
+ left="18"
+ name="physics analysis vhacd"
+ top_delta="0"
+ visible="false"
+ width="589">
+ <text
+ follows="left|top"
+ font="SansSerif"
+ height="20"
+ layout="topleft"
+ left="0"
+ name="method_label"
+ text_color="White"
+ top_pad="0">
+ Step 2: Convert to hulls (optional)
+ </text>
+ <text
+ follows="top|left"
+ height="15"
+ layout="topleft"
+ name="analysis_method_label"
+ top_pad="10"
+ width="100">
+ Fill Mode:
+ </text>
+ <text
+ follows="top|left"
+ height="15"
+ name="quality_label"
+ layout="topleft"
+ left_pad="5"
+ width="85">
+ Resolution:
+ </text>
+ <text
+ follows="top|left"
+ height="15"
+ name="quality_label"
+ layout="topleft"
+ left_pad="25"
+ width="95">
+ Hulls per Mesh:
+ </text>
+ <text
+ follows="top|left"
+ height="15"
+ name="smooth_method_label"
+ layout="topleft"
+ left_pad="5"
+ width="95">
+ Vertices per hull:
+ </text>
+ <text
+ follows="top|left"
+ height="15"
+ name="tolerance_label"
+ layout="topleft"
+ left_pad="5"
+ width="100">
+ Error tolerance:
+ </text>
+ <combo_box
+ follows="top|left"
+ layout="topleft"
+ left="0"
+ name="Fill Mode"
+ top_pad="0"
+ height="20"
+ width="100"/>
+ <combo_box
+ follows="top|left"
+ layout="topleft"
+ left_pad="5"
+ name="Voxel Resolution"
+ height="20"
+ width="100"/>
+ <spinner
+ follows="top|left"
+ name="Num Hulls"
+ height="20"
+ left_pad="10"
+ width="60"
+ decimal_digits="0"
+ allow_digits_only="true"/>
+ <spinner
+ follows="top|left"
+ name="Num Vertices"
+ height="20"
+ left_pad="40"
+ width="60"
+ decimal_digits="0"
+ allow_digits_only="true"/>
+ <spinner
+ follows="top|left"
+ name="Error Tolerance"
+ height="20"
+ left_pad="40"
+ width="60"
+ decimal_digits="4"
+ allow_digits_only="true"/>
+ <button
+ bottom="1"
+ follows="top|right"
+ height="20"
+ label="Analyze"
+ layout="bottomleft"
+ name="Analyze"
+ right="-1"
+ width="90"/>
+ <button
+ follows="top|left"
+ height="20"
+ label="Cancel"
+ layout="topleft"
+ left_delta="0"
+ name="analyze_cancel"
+ visible="false"
+ width="90"/>
+ </panel>
+
<!-- ==== STEP 3: Simplify ==== -->
<view_border
bevel_style="none"
@@ -999,7 +1123,8 @@
left="18"
name="physics simplification"
top_pad="10"
- width="589">
+ width="589"
+ visible="false">
<text
text_color="White"
follows="left|top"
@@ -1088,7 +1213,7 @@
name="simplify_cancel"
width="90"/>
</panel>
-
+
<!-- ==== Results ==== -->
<view_border
bevel_style="none"
@@ -1186,7 +1311,7 @@
name="modifiers_panel"
help_topic="upload_model_modifiers">
<view_border
- bevel_style="none"
+ bevel_style="none"
follows="top|left"
height="306"
layout="topleft"
@@ -1593,7 +1718,7 @@ Model:
[MODEL]
</text>
</panel>
- <!--
+ <!--
Streaming breakdown numbers are available but not fully understood
uncommenting the following sections will display the numbers for debugging purposes
<text
@@ -1695,7 +1820,7 @@ Analysed:
width="462"
visible="true">
You don't have rights to upload mesh models. [[VURL] Find out how] to get certified.
- </text>
+ </text>
<text
text_color="Yellow"
layout="topleft"
@@ -1706,7 +1831,7 @@ Analysed:
</text>
</panel>
</panel>
-
+
<text
follows="left|top"
layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/floater_search.xml b/indra/newview/skins/default/xui/en/floater_search.xml
index 76a486e211..43c4aa1b9d 100644
--- a/indra/newview/skins/default/xui/en/floater_search.xml
+++ b/indra/newview/skins/default/xui/en/floater_search.xml
@@ -1,26 +1,202 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<floater
- positioning="cascading"
- legacy_header_height="225"
- can_minimize="true"
- can_close="true"
- can_resize="true"
- min_height="800"
- min_width="800"
- height="800"
- layout="topleft"
- name="Search"
- single_instance="true"
- help_topic="search"
- save_rect="true"
- save_visibility="true"
- title="SEARCH"
- width="800">
- <web_browser
- top="25"
- height="775"
- width="800"
- follows="all"
- name="search_contents"
- trusted_content="true"/>
+ legacy_header_height="18"
+ can_minimize="true"
+ can_close="true"
+ can_resize="true"
+ height="775"
+ layout="topleft"
+ min_height="500"
+ min_width="600"
+ name="Search"
+ save_rect="true"
+ single_instance="true"
+ save_visibility="true"
+ title="SEARCH"
+ tab_stop="true"
+ width="780">
+ <layout_stack
+ bottom="775"
+ follows="left|right|top|bottom"
+ layout="topleft"
+ left="5"
+ animate="false"
+ name="stack1"
+ orientation="vertical"
+ top="20"
+ width="770">
+ <layout_panel
+ auto_resize="false"
+ default_tab_group="1"
+ height="22"
+ layout="topleft"
+ left="0"
+ min_height="20"
+ name="nav_controls"
+ top="400"
+ width="770">
+ <button
+ image_overlay="Arrow_Left_Off"
+ image_disabled="PushButton_Disabled"
+ image_disabled_selected="PushButton_Disabled"
+ image_selected="PushButton_Selected"
+ image_unselected="PushButton_Off"
+ chrome="true"
+ hover_glow_amount="0.15"
+ tool_tip="Navigate back"
+ follows="left|top"
+ height="22"
+ layout="topleft"
+ left="1"
+ name="back"
+ top="0"
+ width="22">
+ <button.commit_callback
+ function="WebContent.Back" />
+ </button>
+ <button
+ image_overlay="Arrow_Right_Off"
+ image_disabled="PushButton_Disabled"
+ image_disabled_selected="PushButton_Disabled"
+ image_selected="PushButton_Selected"
+ image_unselected="PushButton_Off"
+ chrome="true"
+ tool_tip="Navigate forward"
+ follows="left|top"
+ height="22"
+ layout="topleft"
+ left="27"
+ name="forward"
+ top_delta="0"
+ width="22">
+ <button.commit_callback
+ function="WebContent.Forward" />
+ </button>
+ <button
+ image_overlay="Stop_Off"
+ image_disabled="PushButton_Disabled"
+ image_disabled_selected="PushButton_Disabled"
+ image_selected="PushButton_Selected"
+ image_unselected="PushButton_Off"
+ chrome="true"
+ tool_tip="Stop navigation"
+ enabled="true"
+ follows="left|top"
+ height="22"
+ layout="topleft"
+ left="51"
+ name="stop"
+ top_delta="0"
+ width="22">
+ <button.commit_callback
+ function="WebContent.Stop" />
+ </button>
+ <button
+ image_overlay="Refresh_Off"
+ image_disabled="PushButton_Disabled"
+ image_disabled_selected="PushButton_Disabled"
+ image_selected="PushButton_Selected"
+ image_unselected="PushButton_Off"
+ chrome="true"
+ tool_tip="Reload page"
+ follows="left|top"
+ height="22"
+ layout="topleft"
+ left="51"
+ name="reload"
+ top_delta="0"
+ width="22">
+ <button.commit_callback
+ function="WebContent.Reload" />
+ </button>
+ <combo_box
+ allow_text_entry="true"
+ follows="left|top|right"
+ tab_group="1"
+ height="22"
+ layout="topleft"
+ left_pad="4"
+ max_chars="1024"
+ name="address"
+ combo_editor.select_on_focus="true"
+ tool_tip="Enter URL here"
+ top_delta="0"
+ width="672">
+ <combo_box.commit_callback
+ function="WebContent.EnterAddress" />
+ </combo_box>
+ <icon
+ name="media_secure_lock_flag"
+ height="16"
+ follows="top|left"
+ image_name="Lock2"
+ layout="topleft"
+ left_delta="2"
+ top_delta="2"
+ visible="false"
+ tool_tip="Secured Browsing"
+ width="16" />
+ <button
+ image_overlay="ExternalBrowser_Off"
+ image_disabled="PushButton_Disabled"
+ image_disabled_selected="PushButton_Disabled"
+ image_selected="PushButton_Selected"
+ image_unselected="PushButton_Off"
+ chrome="true"
+ tool_tip="Open current URL in your desktop browser"
+ follows="right|top"
+ enabled="true"
+ height="22"
+ layout="topleft"
+ name="popexternal"
+ right="770"
+ top_delta="-2"
+ width="22">
+ <button.commit_callback
+ function="WebContent.PopExternal" />
+ </button>
+ </layout_panel>
+ <layout_panel
+ height="40"
+ layout="topleft"
+ left_delta="0"
+ name="external_controls"
+ top_delta="0"
+ auto_resize="true"
+ width="585">
+ <web_browser
+ bottom="-2"
+ follows="all"
+ layout="topleft"
+ left="0"
+ trusted_content="true"
+ name="search_contents"
+ top="0"/>
+ </layout_panel>
+ <layout_panel name="status_bar"
+ height="23"
+ auto_resize="false">
+ <text
+ type="string"
+ length="200"
+ follows="bottom|left"
+ height="20"
+ layout="topleft"
+ left_delta="0"
+ name="statusbartext"
+ parse_urls="false"
+ text_color="0.4 0.4 0.4 1"
+ top_pad="3"
+ width="495"/>
+ <progress_bar
+ color_bar="0.3 1.0 0.3 1"
+ follows="bottom|right"
+ height="16"
+ top_delta="-1"
+ left_pad="24"
+ layout="topleft"
+ name="statusbarprogress"
+ width="64"/>
+ </layout_panel>
+ </layout_stack>
</floater>
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index fa3fd86d59..69df05f6c2 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -2239,6 +2239,25 @@ Couldn&apos;t open uploaded sound file for reading:
<notification
icon="alertmodal.tga"
+ name="ModelUploaderMissingPhysicsApple"
+ type="alertmodal">
+Model upload is not yet available on Apple Silicon, but will be supported in an upcoming release.
+
+Workaround: Right-click the Second Life app in Finder, select
+"Get Info", then check "Open using Rosetta"
+ <tag>fail</tag>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
+ name="ModelUploaderMissingPhysics"
+ type="alertmodal">
+Physics library is not present, some of the model uploader's functionality might not work or might not work correctly.
+ <tag>fail</tag>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
name="SoundFileNotRIFF"
type="alertmodal">
File does not appear to be a RIFF WAVE file: