Initial VHACD based llconvexdecomposition
parent
fba445762f
commit
b6ba43bed5
116
autobuild.xml
116
autobuild.xml
|
|
@ -185,54 +185,6 @@
|
||||||
<key>version</key>
|
<key>version</key>
|
||||||
<string>5.1.0</string>
|
<string>5.1.0</string>
|
||||||
</map>
|
</map>
|
||||||
<key>ndPhysicsStub</key>
|
|
||||||
<map>
|
|
||||||
<key>license</key>
|
|
||||||
<string>HACD/LGPL</string>
|
|
||||||
<key>license_file</key>
|
|
||||||
<string>LICENSES/ndPhysicsStub.txt</string>
|
|
||||||
<key>name</key>
|
|
||||||
<string>ndPhysicsStub</string>
|
|
||||||
<key>platforms</key>
|
|
||||||
<map>
|
|
||||||
<key>darwin64</key>
|
|
||||||
<map>
|
|
||||||
<key>archive</key>
|
|
||||||
<map>
|
|
||||||
<key>hash</key>
|
|
||||||
<string>b0f4fd59a72cf04db2cc426241a3850c</string>
|
|
||||||
<key>url</key>
|
|
||||||
<string>https://3p.firestormviewer.org/ndPhysicsStub-1.0-darwin64-252581439.tar.bz2</string>
|
|
||||||
</map>
|
|
||||||
<key>name</key>
|
|
||||||
<string>darwin</string>
|
|
||||||
</map>
|
|
||||||
<key>linux64</key>
|
|
||||||
<map>
|
|
||||||
<key>archive</key>
|
|
||||||
<map>
|
|
||||||
<key>hash</key>
|
|
||||||
<string>c266a8d6124fc11e41a82c288f2bf8e4</string>
|
|
||||||
<key>url</key>
|
|
||||||
<string>https://3p.firestormviewer.org/ndPhysicsStub-1.202321033-linux64-202321033.tar.bz2</string>
|
|
||||||
</map>
|
|
||||||
<key>name</key>
|
|
||||||
<string>linux64</string>
|
|
||||||
</map>
|
|
||||||
<key>windows64</key>
|
|
||||||
<map>
|
|
||||||
<key>archive</key>
|
|
||||||
<map>
|
|
||||||
<key>hash</key>
|
|
||||||
<string>02f70159e14c7b7213b22a0225508c46</string>
|
|
||||||
<key>url</key>
|
|
||||||
<string>https://3p.firestormviewer.org/ndPhysicsStub-1.0-windows64-202121823.tar.bz2</string>
|
|
||||||
</map>
|
|
||||||
<key>name</key>
|
|
||||||
<string>windows64</string>
|
|
||||||
</map>
|
|
||||||
</map>
|
|
||||||
</map>
|
|
||||||
<key>glod</key>
|
<key>glod</key>
|
||||||
<map>
|
<map>
|
||||||
<key>copyright</key>
|
<key>copyright</key>
|
||||||
|
|
@ -1726,41 +1678,19 @@
|
||||||
<map>
|
<map>
|
||||||
<key>platforms</key>
|
<key>platforms</key>
|
||||||
<map>
|
<map>
|
||||||
<key>darwin64</key>
|
<key>common</key>
|
||||||
<map>
|
<map>
|
||||||
<key>archive</key>
|
<key>archive</key>
|
||||||
<map>
|
<map>
|
||||||
<key>hash</key>
|
<key>hash</key>
|
||||||
<string>f290b000b31f9e36f2489946cbc99f5e</string>
|
<string>bc41438b10ac6474cf5560465a3662a64f9e65a81342e4c33f18f6694581c7ee28c9ee6f091c36e80a0b1e10c68205be71eb5f8e40fef115d2c744fc2bbfcb43</string>
|
||||||
|
<key>hash_algorithm</key>
|
||||||
|
<string>blake2b</string>
|
||||||
<key>url</key>
|
<key>url</key>
|
||||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/59995/563653/llphysicsextensions_stub-1.0.542456-darwin64-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>
|
</map>
|
||||||
<key>name</key>
|
<key>name</key>
|
||||||
<string>darwin64</string>
|
<string>common</string>
|
||||||
</map>
|
|
||||||
<key>linux64</key>
|
|
||||||
<map>
|
|
||||||
<key>archive</key>
|
|
||||||
<map>
|
|
||||||
<key>hash</key>
|
|
||||||
<string>711f4ec769e4b5f59ba25ee43c11bcbc</string>
|
|
||||||
<key>url</key>
|
|
||||||
<string>https://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>
|
|
||||||
<map>
|
|
||||||
<key>archive</key>
|
|
||||||
<map>
|
|
||||||
<key>hash</key>
|
|
||||||
<string>2e5f1f7046a49d8b0bc295aa878116bc</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>
|
|
||||||
</map>
|
|
||||||
<key>name</key>
|
|
||||||
<string>windows64</string>
|
|
||||||
</map>
|
</map>
|
||||||
</map>
|
</map>
|
||||||
<key>license</key>
|
<key>license</key>
|
||||||
|
|
@ -1770,7 +1700,7 @@
|
||||||
<key>copyright</key>
|
<key>copyright</key>
|
||||||
<string>Copyright (c) 2010, Linden Research, Inc.</string>
|
<string>Copyright (c) 2010, Linden Research, Inc.</string>
|
||||||
<key>version</key>
|
<key>version</key>
|
||||||
<string>1.0.542456</string>
|
<string>1.0</string>
|
||||||
<key>name</key>
|
<key>name</key>
|
||||||
<string>llphysicsextensions_stub</string>
|
<string>llphysicsextensions_stub</string>
|
||||||
</map>
|
</map>
|
||||||
|
|
@ -3247,6 +3177,38 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
||||||
<key>description</key>
|
<key>description</key>
|
||||||
<string>Discord Social SDK</string>
|
<string>Discord Social SDK</string>
|
||||||
</map>
|
</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>
|
</map>
|
||||||
<key>package_description</key>
|
<key>package_description</key>
|
||||||
<map>
|
<map>
|
||||||
|
|
|
||||||
|
|
@ -127,6 +127,9 @@ endif (USE_TRACY)
|
||||||
add_subdirectory(${LIBS_OPEN_PREFIX}llaudio)
|
add_subdirectory(${LIBS_OPEN_PREFIX}llaudio)
|
||||||
add_subdirectory(${LIBS_OPEN_PREFIX}llappearance)
|
add_subdirectory(${LIBS_OPEN_PREFIX}llappearance)
|
||||||
add_subdirectory(${LIBS_OPEN_PREFIX}llcharacter)
|
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}llcommon)
|
||||||
add_subdirectory(${LIBS_OPEN_PREFIX}llcorehttp)
|
add_subdirectory(${LIBS_OPEN_PREFIX}llcorehttp)
|
||||||
add_subdirectory(${LIBS_OPEN_PREFIX}llimage)
|
add_subdirectory(${LIBS_OPEN_PREFIX}llimage)
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,7 @@ set(cmake_SOURCE_FILES
|
||||||
UI.cmake
|
UI.cmake
|
||||||
UnixInstall.cmake
|
UnixInstall.cmake
|
||||||
Variables.cmake
|
Variables.cmake
|
||||||
|
VHACD.cmake
|
||||||
ViewerMiscLibs.cmake
|
ViewerMiscLibs.cmake
|
||||||
VisualLeakDetector.cmake
|
VisualLeakDetector.cmake
|
||||||
LibVLCPlugin.cmake
|
LibVLCPlugin.cmake
|
||||||
|
|
|
||||||
|
|
@ -22,69 +22,21 @@ if (HAVOK)
|
||||||
include(Havok)
|
include(Havok)
|
||||||
use_prebuilt_binary(llphysicsextensions_source)
|
use_prebuilt_binary(llphysicsextensions_source)
|
||||||
set(LLPHYSICSEXTENSIONS_SRC_DIR ${LIBS_PREBUILT_DIR}/llphysicsextensions/src)
|
set(LLPHYSICSEXTENSIONS_SRC_DIR ${LIBS_PREBUILT_DIR}/llphysicsextensions/src)
|
||||||
if(DARWIN)
|
target_link_libraries( llphysicsextensions_impl INTERFACE llphysicsextensions)
|
||||||
set(LLPHYSICSEXTENSIONS_STUB_DIR ${LIBS_PREBUILT_DIR}/llphysicsextensions/stub)
|
target_compile_definitions( llphysicsextensions_impl INTERFACE LL_HAVOK=1 )
|
||||||
# can't set these library dependencies per-arch here, need to do it using XCODE_ATTRIBUTE_OTHER_LDFLAGS[arch=*] in newview/CMakeLists.txt
|
|
||||||
#target_link_libraries( llphysicsextensions_impl INTERFACE llphysicsextensions)
|
|
||||||
#target_link_libraries( llphysicsextensions_impl INTERFACE llphysicsextensionsstub)
|
|
||||||
else()
|
|
||||||
target_link_libraries( llphysicsextensions_impl INTERFACE llphysicsextensions)
|
|
||||||
target_compile_definitions( llphysicsextensions_impl INTERFACE LL_HAVOK=1 )
|
|
||||||
endif()
|
|
||||||
elseif (HAVOK_TPV)
|
elseif (HAVOK_TPV)
|
||||||
use_prebuilt_binary(llphysicsextensions_tpv)
|
use_prebuilt_binary(llphysicsextensions_tpv)
|
||||||
# <FS:TJ> Done in newview/CMakeLists.txt for darwin if Havok is enabled
|
if(WINDOWS)
|
||||||
if (NOT DARWIN)
|
target_link_libraries( llphysicsextensions_impl INTERFACE ${ARCH_PREBUILT_DIRS}/llphysicsextensions_tpv.lib)
|
||||||
target_link_libraries( llphysicsextensions_impl INTERFACE llphysicsextensions_tpv)
|
else()
|
||||||
target_compile_definitions( llphysicsextensions_impl INTERFACE LL_HAVOK=1 )
|
target_link_libraries( llphysicsextensions_impl INTERFACE ${ARCH_PREBUILT_DIRS}/libllphysicsextensions_tpv.a)
|
||||||
endif()
|
endif()
|
||||||
# </FS:TJ>
|
target_compile_definitions( llphysicsextensions_impl INTERFACE LL_HAVOK=1 )
|
||||||
# <FS:ND> include paths for LLs version and ours are different.
|
else (HAVOK)
|
||||||
target_include_directories( llphysicsextensions_impl INTERFACE ${LIBS_PREBUILT_DIR}/include/llphysicsextensions)
|
use_prebuilt_binary(llphysicsextensions_stub)
|
||||||
# </FS:ND>
|
set(LLPHYSICSEXTENSIONS_SRC_DIR ${LIBS_PREBUILT_DIR}/llphysicsextensions/stub)
|
||||||
|
target_link_libraries( llphysicsextensions_impl INTERFACE llphysicsextensionsstub)
|
||||||
# <FS:ND> havok lib get installed to packages/lib
|
endif (HAVOK)
|
||||||
link_directories( ${LIBS_PREBUILT_DIR}/lib )
|
|
||||||
# </FS:ND>
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
if ((NOT HAVOK AND NOT HAVOK_TPV) OR DARWIN) # <FS:TJ/> ARM64 requires ndPhysicsStub
|
|
||||||
use_prebuilt_binary( ndPhysicsStub )
|
|
||||||
|
|
||||||
# <FS:ND> Don't set this variable, there is no need to build any stub source if using ndPhysicsStub
|
|
||||||
# set(LLPHYSICSEXTENSIONS_SRC_DIR ${LIBS_PREBUILT_DIR}/llphysicsextensions/stub)
|
|
||||||
# </FS:ND>
|
|
||||||
|
|
||||||
# <FS:TJ> Use find_library to make our lives easier
|
|
||||||
find_library(ND_HACDCONVEXDECOMPOSITION_LIBRARY
|
|
||||||
NAMES
|
|
||||||
nd_hacdConvexDecomposition.lib
|
|
||||||
libnd_hacdConvexDecomposition.a
|
|
||||||
PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
|
|
||||||
|
|
||||||
find_library(HACD_LIBRARY
|
|
||||||
NAMES
|
|
||||||
hacd.lib
|
|
||||||
libhacd.a
|
|
||||||
PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
|
|
||||||
|
|
||||||
find_library(ND_PATHING_LIBRARY
|
|
||||||
NAMES
|
|
||||||
nd_pathing.lib
|
|
||||||
libnd_pathing.a
|
|
||||||
libnd_Pathing.a
|
|
||||||
PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
|
|
||||||
|
|
||||||
if (NOT HAVOK AND NOT HAVOK_TPV) # <FS:TJ/> Done in newview/CMakeLists.txt for darwin if Havok is enabled
|
|
||||||
target_link_libraries(llphysicsextensions_impl INTERFACE ${ND_HACDCONVEXDECOMPOSITION_LIBRARY} ${HACD_LIBRARY} ${ND_PATHING_LIBRARY})
|
|
||||||
endif()
|
|
||||||
# </FS:TJ>
|
|
||||||
|
|
||||||
# <FS:ND> include paths for LLs version and ours are different.
|
|
||||||
target_include_directories( llphysicsextensions_impl INTERFACE ${LIBS_PREBUILT_DIR}/include/ )
|
|
||||||
# </FS:ND>
|
|
||||||
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
# <FS:ND> include paths for LLs version and ours are different.
|
# <FS:ND> include paths for LLs version and ours are different.
|
||||||
#target_include_directories( llphysicsextensions_impl INTERFACE ${LIBS_PREBUILT_DIR}/include/llphysicsextensions)
|
#target_include_directories( llphysicsextensions_impl INTERFACE ${LIBS_PREBUILT_DIR}/include/llphysicsextensions)
|
||||||
|
|
|
||||||
|
|
@ -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/)
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
|
@ -71,6 +71,12 @@ target_link_libraries(llprimitive
|
||||||
ll::glm
|
ll::glm
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (TARGET llconvexdecomposition)
|
||||||
|
target_link_libraries(llprimitive
|
||||||
|
llconvexdecomposition
|
||||||
|
)
|
||||||
|
endif ()
|
||||||
|
|
||||||
if(LINUX)
|
if(LINUX)
|
||||||
# GLIB uses pcre, so we need to keep it for Linux
|
# GLIB uses pcre, so we need to keep it for Linux
|
||||||
target_link_libraries(ll::pcre)
|
target_link_libraries(ll::pcre)
|
||||||
|
|
|
||||||
|
|
@ -1314,10 +1314,10 @@ LLModel::weight_list& LLModel::getJointInfluences(const LLVector3& pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLModel::setConvexHullDecomposition(
|
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.mHull = decomp;
|
||||||
mPhysics.mMesh.clear();
|
mPhysics.mMesh = decomp_mesh;
|
||||||
updateHullCenters();
|
updateHullCenters();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -307,7 +307,8 @@ public:
|
||||||
S32 mDecompID;
|
S32 mDecompID;
|
||||||
|
|
||||||
void setConvexHullDecomposition(
|
void setConvexHullDecomposition(
|
||||||
const convex_hull_decomposition& decomp);
|
const convex_hull_decomposition& decomp,
|
||||||
|
const std::vector<LLModel::PhysicsMesh>& decomp_mesh);
|
||||||
void updateHullCenters();
|
void updateHullCenters();
|
||||||
|
|
||||||
LLVector3 mCenterOfHullCenters;
|
LLVector3 mCenterOfHullCenters;
|
||||||
|
|
|
||||||
|
|
@ -2627,6 +2627,10 @@ if( TARGET ll::nvapi )
|
||||||
target_link_libraries(${VIEWER_BINARY_NAME} ll::nvapi )
|
target_link_libraries(${VIEWER_BINARY_NAME} ll::nvapi )
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if ( TARGET llconvexdecomposition )
|
||||||
|
target_link_libraries(${VIEWER_BINARY_NAME} llconvexdecomposition )
|
||||||
|
endif ()
|
||||||
|
|
||||||
if (LINUX)
|
if (LINUX)
|
||||||
# <FS:Zi> put these additional libraries in the viewer build target here as it didn't
|
# <FS:Zi> put these additional libraries in the viewer build target here as it didn't
|
||||||
# work to put them in via their cmake/* files
|
# work to put them in via their cmake/* files
|
||||||
|
|
|
||||||
|
|
@ -1136,8 +1136,13 @@ void LLFloaterModelPreview::onPhysicsStageExecute(LLUICtrl* ctrl, void* data)
|
||||||
gMeshRepo.mDecompThread->submitRequest(request);
|
gMeshRepo.mDecompThread->submitRequest(request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (stage == "Analyze")
|
||||||
if (stage == "Decompose")
|
{
|
||||||
|
sInstance->setStatusMessage(sInstance->getString("decomposing"));
|
||||||
|
sInstance->childSetVisible("Analyze", false);
|
||||||
|
sInstance->childSetVisible("analyze_cancel", true);
|
||||||
|
}
|
||||||
|
else if (stage == "Decompose")
|
||||||
{
|
{
|
||||||
sInstance->setStatusMessage(sInstance->getString("decomposing"));
|
sInstance->setStatusMessage(sInstance->getString("decomposing"));
|
||||||
sInstance->childSetVisible("Decompose", false);
|
sInstance->childSetVisible("Decompose", false);
|
||||||
|
|
@ -1320,6 +1325,7 @@ void LLFloaterModelPreview::initDecompControls()
|
||||||
|
|
||||||
childSetCommitCallback("simplify_cancel", onPhysicsStageCancel, NULL);
|
childSetCommitCallback("simplify_cancel", onPhysicsStageCancel, NULL);
|
||||||
childSetCommitCallback("decompose_cancel", onPhysicsStageCancel, NULL);
|
childSetCommitCallback("decompose_cancel", onPhysicsStageCancel, NULL);
|
||||||
|
childSetCommitCallback("analyze_cancel", onPhysicsStageCancel, NULL);
|
||||||
|
|
||||||
childSetCommitCallback("physics_lod_combo", onPhysicsUseLOD, NULL);
|
childSetCommitCallback("physics_lod_combo", onPhysicsUseLOD, NULL);
|
||||||
childSetCommitCallback("physics_browse", onPhysicsBrowse, NULL);
|
childSetCommitCallback("physics_browse", onPhysicsBrowse, NULL);
|
||||||
|
|
@ -2214,7 +2220,7 @@ void LLFloaterModelPreview::DecompRequest::completed()
|
||||||
{ //called from the main thread
|
{ //called from the main thread
|
||||||
if (mContinue)
|
if (mContinue)
|
||||||
{
|
{
|
||||||
mModel->setConvexHullDecomposition(mHull);
|
mModel->setConvexHullDecomposition(mHull, mHullMesh);
|
||||||
|
|
||||||
if (sInstance)
|
if (sInstance)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -3627,7 +3627,16 @@ void LLModelPreview::updateStatusMessages()
|
||||||
//enable = enable && !use_hull && fmp->childGetValue("physics_optimize").asBoolean();
|
//enable = enable && !use_hull && fmp->childGetValue("physics_optimize").asBoolean();
|
||||||
|
|
||||||
//enable/disable "analysis" UI
|
//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();
|
LLView* child = panel->getFirstChild();
|
||||||
while (child)
|
while (child)
|
||||||
{
|
{
|
||||||
|
|
@ -3651,6 +3660,8 @@ void LLModelPreview::updateStatusMessages()
|
||||||
fmp->childSetVisible("simplify_cancel", false);
|
fmp->childSetVisible("simplify_cancel", false);
|
||||||
fmp->childSetVisible("Decompose", true);
|
fmp->childSetVisible("Decompose", true);
|
||||||
fmp->childSetVisible("decompose_cancel", false);
|
fmp->childSetVisible("decompose_cancel", false);
|
||||||
|
fmp->childSetVisible("Analyze", true);
|
||||||
|
fmp->childSetVisible("analyze_cancel", false);
|
||||||
|
|
||||||
if (phys_hulls > 0)
|
if (phys_hulls > 0)
|
||||||
{
|
{
|
||||||
|
|
@ -3660,6 +3671,7 @@ void LLModelPreview::updateStatusMessages()
|
||||||
if (phys_tris || phys_hulls > 0)
|
if (phys_tris || phys_hulls > 0)
|
||||||
{
|
{
|
||||||
fmp->childEnable("Decompose");
|
fmp->childEnable("Decompose");
|
||||||
|
fmp->childEnable("Analyze");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@
|
||||||
<string name="simplifying">Simplifying...</string>
|
<string name="simplifying">Simplifying...</string>
|
||||||
<string name="tbd">TBD</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>
|
<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-->
|
<!-- Warnings and info from model loader-->
|
||||||
<string name="TooManyJoint">Skinning disabled due to too many joints: [JOINTS], maximum: [MAX]</string>
|
<string name="TooManyJoint">Skinning disabled due to too many joints: [JOINTS], maximum: [MAX]</string>
|
||||||
<string name="UnrecognizedJoint">Rigged to unrecognized joint name [NAME]</string>
|
<string name="UnrecognizedJoint">Rigged to unrecognized joint name [NAME]</string>
|
||||||
|
|
@ -831,7 +831,7 @@
|
||||||
help_topic="upload_model_physics"
|
help_topic="upload_model_physics"
|
||||||
label="Physics"
|
label="Physics"
|
||||||
name="physics_panel">
|
name="physics_panel">
|
||||||
|
|
||||||
<!-- ==== STEP 1: Level of Detail ==== -->
|
<!-- ==== STEP 1: Level of Detail ==== -->
|
||||||
<view_border
|
<view_border
|
||||||
bevel_style="none"
|
bevel_style="none"
|
||||||
|
|
@ -900,7 +900,7 @@
|
||||||
<!-- <check_box name="physics_optimize" follows="left|top" width="130" left="10" top_pad="5" height="20" label="Optimize"/>
|
<!-- <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"/> -->
|
<check_box name="physics_use_hull" follows="left|top" width="130" left_pad="5" height="20" label="Use Convex Hull"/> -->
|
||||||
</panel>
|
</panel>
|
||||||
|
|
||||||
<!-- ==== STEP 2: Analyze ==== -->
|
<!-- ==== STEP 2: Analyze ==== -->
|
||||||
<view_border
|
<view_border
|
||||||
bevel_style="none"
|
bevel_style="none"
|
||||||
|
|
@ -917,9 +917,9 @@
|
||||||
height="65"
|
height="65"
|
||||||
follows="top|left"
|
follows="top|left"
|
||||||
left="18"
|
left="18"
|
||||||
name="physics analysis"
|
name="physics analysis havok"
|
||||||
top_pad="10"
|
top_pad="10"
|
||||||
visible="true"
|
visible="false"
|
||||||
width="589">
|
width="589">
|
||||||
<text
|
<text
|
||||||
follows="left|top"
|
follows="left|top"
|
||||||
|
|
@ -1007,7 +1007,131 @@
|
||||||
visible="false"
|
visible="false"
|
||||||
width="90"/>
|
width="90"/>
|
||||||
</panel>
|
</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="fill_mode_label"
|
||||||
|
top_pad="10"
|
||||||
|
width="100">
|
||||||
|
Fill Mode:
|
||||||
|
</text>
|
||||||
|
<text
|
||||||
|
follows="top|left"
|
||||||
|
height="15"
|
||||||
|
name="resolution_label"
|
||||||
|
layout="topleft"
|
||||||
|
left_pad="5"
|
||||||
|
width="85">
|
||||||
|
Resolution:
|
||||||
|
</text>
|
||||||
|
<text
|
||||||
|
follows="top|left"
|
||||||
|
height="15"
|
||||||
|
name="hulls_per_mesh_label"
|
||||||
|
layout="topleft"
|
||||||
|
left_pad="25"
|
||||||
|
width="95">
|
||||||
|
Hulls per Mesh:
|
||||||
|
</text>
|
||||||
|
<text
|
||||||
|
follows="top|left"
|
||||||
|
height="15"
|
||||||
|
name="vertices_per_hull_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 ==== -->
|
<!-- ==== STEP 3: Simplify ==== -->
|
||||||
<view_border
|
<view_border
|
||||||
bevel_style="none"
|
bevel_style="none"
|
||||||
|
|
@ -1026,7 +1150,8 @@
|
||||||
left="18"
|
left="18"
|
||||||
name="physics simplification"
|
name="physics simplification"
|
||||||
top_pad="10"
|
top_pad="10"
|
||||||
width="589">
|
width="589"
|
||||||
|
visible="false">
|
||||||
<text
|
<text
|
||||||
text_color="White"
|
text_color="White"
|
||||||
follows="left|top"
|
follows="left|top"
|
||||||
|
|
@ -1115,7 +1240,7 @@
|
||||||
name="simplify_cancel"
|
name="simplify_cancel"
|
||||||
width="90"/>
|
width="90"/>
|
||||||
</panel>
|
</panel>
|
||||||
|
|
||||||
<!-- ==== Results ==== -->
|
<!-- ==== Results ==== -->
|
||||||
<view_border
|
<view_border
|
||||||
bevel_style="none"
|
bevel_style="none"
|
||||||
|
|
@ -1988,7 +2113,7 @@ Model:
|
||||||
[MODEL]
|
[MODEL]
|
||||||
</text>
|
</text>
|
||||||
</panel>
|
</panel>
|
||||||
<!--
|
<!--
|
||||||
Streaming breakdown numbers are available but not fully understood
|
Streaming breakdown numbers are available but not fully understood
|
||||||
uncommenting the following sections will display the numbers for debugging purposes
|
uncommenting the following sections will display the numbers for debugging purposes
|
||||||
<text
|
<text
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue