Merge branch 'develop' of https://github.com/secondlife/viewer
# Conflicts: # autobuild.xml # indra/cmake/LLPhysicsExtensions.cmake # indra/llprimitive/CMakeLists.txt # indra/newview/CMakeLists.txt # indra/newview/lltexturectrl.cpp # indra/newview/llviewerobject.cpp # indra/newview/llviewertexture.cpp # indra/newview/llviewerwindow.cpp # indra/newview/llvovolume.cpp # indra/newview/skins/default/xui/en/floater_marketplace.xml # indra/newview/skins/default/xui/en/floater_model_preview.xml # indra/newview/skins/default/xui/en/floater_search.xmlmaster
commit
e7b3d68cab
|
|
@ -1,6 +1,7 @@
|
|||
name: Build
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
push:
|
||||
branches: ["main", "release/*", "project/*"]
|
||||
|
|
|
|||
116
autobuild.xml
116
autobuild.xml
|
|
@ -185,54 +185,6 @@
|
|||
<key>version</key>
|
||||
<string>5.1.0</string>
|
||||
</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>darwin</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>7d375112b162e32e37262da4a6c0a702</string>
|
||||
<key>url</key>
|
||||
<string>https://3p.firestormviewer.org/ndPhysicsStub-1.0-darwin-202330107.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>
|
||||
<map>
|
||||
<key>copyright</key>
|
||||
|
|
@ -1758,41 +1710,19 @@
|
|||
<map>
|
||||
<key>platforms</key>
|
||||
<map>
|
||||
<key>darwin64</key>
|
||||
<key>common</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>f290b000b31f9e36f2489946cbc99f5e</string>
|
||||
<string>bc41438b10ac6474cf5560465a3662a64f9e65a81342e4c33f18f6694581c7ee28c9ee6f091c36e80a0b1e10c68205be71eb5f8e40fef115d2c744fc2bbfcb43</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>blake2b</string>
|
||||
<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>
|
||||
<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>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>
|
||||
<string>common</string>
|
||||
</map>
|
||||
</map>
|
||||
<key>license</key>
|
||||
|
|
@ -1802,7 +1732,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>
|
||||
|
|
@ -3279,6 +3209,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>
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ else (FS_PF_USER_AGENT)
|
|||
message(STATUS "Compiling with standard Primfeed user-agent")
|
||||
endif (FS_PF_USER_AGENT)
|
||||
# </Beq>
|
||||
|
||||
# <FS:Ansariel> [AVX Optimization]
|
||||
option(USE_AVX_OPTIMIZATION "AVX optimization support" OFF)
|
||||
option(USE_AVX2_OPTIMIZATION "AVX2 optimization support" OFF)
|
||||
|
|
@ -127,6 +128,9 @@ endif (USE_TRACY)
|
|||
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)
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ set(cmake_SOURCE_FILES
|
|||
UI.cmake
|
||||
UnixInstall.cmake
|
||||
Variables.cmake
|
||||
VHACD.cmake
|
||||
ViewerMiscLibs.cmake
|
||||
VisualLeakDetector.cmake
|
||||
LibVLCPlugin.cmake
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ include(Prebuilt)
|
|||
|
||||
# There are three possible solutions to provide the llphysicsextensions:
|
||||
# - The full source package, selected by -DHAVOK:BOOL=ON
|
||||
# - The stub source package, selected by -DHAVOK:BOOL=OFF
|
||||
# - The stub source package, selected by -DHAVOK:BOOL=OFF
|
||||
# - The prebuilt package available to those with sublicenses, selected by -DHAVOK_TPV:BOOL=ON
|
||||
|
||||
if (INSTALL_PROPRIETARY)
|
||||
|
|
@ -23,32 +23,28 @@ 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)
|
||||
# <FS:ND> include paths for LLs version and ours are different.
|
||||
target_include_directories( llphysicsextensions_impl INTERFACE ${LIBS_PREBUILT_DIR}/include/llphysicsextensions)
|
||||
# </FS:ND>
|
||||
|
||||
# <FS:ND> havok lib get installed to packages/lib
|
||||
link_directories( ${LIBS_PREBUILT_DIR}/lib )
|
||||
# </FS:ND>
|
||||
|
||||
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( 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>
|
||||
|
||||
target_link_libraries( llphysicsextensions_impl INTERFACE nd_hacdConvexDecomposition hacd nd_Pathing )
|
||||
|
||||
# <FS:ND> include paths for LLs version and ours are different.
|
||||
target_include_directories( llphysicsextensions_impl INTERFACE ${LIBS_PREBUILT_DIR}/include/ )
|
||||
# </FS:ND>
|
||||
use_prebuilt_binary(llphysicsextensions_stub)
|
||||
set(LLPHYSICSEXTENSIONS_SRC_DIR ${LIBS_PREBUILT_DIR}/llphysicsextensions/stub)
|
||||
target_link_libraries( llphysicsextensions_impl INTERFACE llphysicsextensionsstub)
|
||||
|
||||
# <FS:Ansariel> Hotfix pathing lib header and add missing BOOL typedef
|
||||
file(READ ${LIBS_PREBUILT_DIR}/include/llphysicsextensions/llpathinglib.h PATHINGLIB_HEADER_CONTENTS)
|
||||
string(FIND "${PATHINGLIB_HEADER_CONTENTS}" "typedef int BOOL;" BOOL_TYPEDEF_POS)
|
||||
if (${BOOL_TYPEDEF_POS} EQUAL -1)
|
||||
string(REPLACE "typedef int bool32;" "typedef int bool32;\ntypedef int BOOL;" PATHINGLIB_HEADER_CONTENTS "${PATHINGLIB_HEADER_CONTENTS}")
|
||||
file(WRITE ${LIBS_PREBUILT_DIR}/include/llphysicsextensions/llpathinglib.h "${PATHINGLIB_HEADER_CONTENTS}")
|
||||
endif()
|
||||
# </FS:Ansariel>
|
||||
endif (HAVOK)
|
||||
|
||||
# <FS:ND> include paths for LLs version and ours are different.
|
||||
#target_include_directories( llphysicsextensions_impl INTERFACE ${LIBS_PREBUILT_DIR}/include/llphysicsextensions)
|
||||
# </FS:ND>
|
||||
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/)
|
||||
|
|
@ -200,11 +200,11 @@ set(USE_PRECOMPILED_HEADERS ON CACHE BOOL "Enable use of precompiled header dire
|
|||
# <FS:ND> When using Havok, we have to turn OpenSim support off
|
||||
if (HAVOK_TPV)
|
||||
if (OPENSIM)
|
||||
message("compiling with Havok libraries, disabling OpenSim support")
|
||||
message(STATUS "Compiling with Havok libraries - disabling OpenSim support")
|
||||
endif (OPENSIM)
|
||||
|
||||
if (LINUX)
|
||||
message("compiling with Havok libraries is not supported on Linux - switching to HACD")
|
||||
message(STATUS "Compiling with Havok libraries is not supported on Linux - switching to VHACD")
|
||||
set(HAVOK_TPV OFF)
|
||||
endif (LINUX)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -5762,6 +5762,8 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
|
|||
{
|
||||
try
|
||||
{
|
||||
// providing mIndices should help avoid unused vertices
|
||||
// but those should have been filtered out on upload
|
||||
vert_count = static_cast<S32>(meshopt_generateVertexRemapMulti(&remap[0], nullptr, data.p.size(), data.p.size(), mos, stream_count));
|
||||
}
|
||||
catch (std::bad_alloc&)
|
||||
|
|
@ -5771,10 +5773,16 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
|
|||
}
|
||||
}
|
||||
|
||||
if (vert_count < 65535 && vert_count != 0)
|
||||
// Probably should be using meshopt_remapVertexBuffer instead of remaping manually
|
||||
if (vert_count < 65535 && vert_count > 0)
|
||||
{
|
||||
//copy results back into volume
|
||||
resizeVertices(vert_count);
|
||||
if (mNumVertices == 0)
|
||||
{
|
||||
LLError::LLUserWarningMsg::showOutOfMemory();
|
||||
LL_ERRS("LLCoros") << "Failed to allocate memory for resizeVertices(" << vert_count << ")" << LL_ENDL;
|
||||
}
|
||||
|
||||
if (!data.w.empty())
|
||||
{
|
||||
|
|
@ -5787,13 +5795,27 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
|
|||
{
|
||||
U32 src_idx = i;
|
||||
U32 dst_idx = remap[i];
|
||||
if (dst_idx >= (U32)mNumVertices)
|
||||
if (dst_idx == U32_MAX)
|
||||
{
|
||||
// Unused indices? Probably need to resize mIndices
|
||||
dst_idx = mNumVertices - 1;
|
||||
llassert(false);
|
||||
LL_DEBUGS_ONCE("LLVOLUME") << "U32_MAX destination index, substituting" << LL_ENDL;
|
||||
}
|
||||
else if (dst_idx >= (U32)mNumVertices)
|
||||
{
|
||||
dst_idx = mNumVertices - 1;
|
||||
// Shouldn't happen, figure out what gets returned in remap and why.
|
||||
llassert(false);
|
||||
LL_DEBUGS_ONCE("LLVOLUME") << "Invalid destination index, substituting" << LL_ENDL;
|
||||
}
|
||||
if (src_idx >= (U32)data.p.size())
|
||||
{
|
||||
// data.p.size() is supposed to be equal to mNumIndices
|
||||
src_idx = (U32)(data.p.size() - 1);
|
||||
llassert(false);
|
||||
LL_DEBUGS_ONCE("LLVOLUME") << "Invalid source index, substituting" << LL_ENDL;
|
||||
}
|
||||
mIndices[i] = dst_idx;
|
||||
|
||||
mPositions[dst_idx].load3(data.p[src_idx].mV);
|
||||
|
|
@ -5827,7 +5849,7 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
|
|||
}
|
||||
else
|
||||
{
|
||||
if (vert_count == 0)
|
||||
if (vert_count <= 0)
|
||||
{
|
||||
LL_WARNS_ONCE("LLVOLUME") << "meshopt_generateVertexRemapMulti failed to process a model or model was invalid" << LL_ENDL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -138,7 +138,22 @@ LLCoprocedureManager::LLCoprocedureManager()
|
|||
|
||||
LLCoprocedureManager::~LLCoprocedureManager()
|
||||
{
|
||||
close();
|
||||
try
|
||||
{
|
||||
close();
|
||||
}
|
||||
catch (const boost::fibers::fiber_error&)
|
||||
{
|
||||
LL_WARNS() << "Fiber error during ~LLCoprocedureManager()" << LL_ENDL;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
// Shutting down, just log it
|
||||
LL_WARNS() << "Exception during ~LLCoprocedureManager(): " << e.what() << LL_ENDL;
|
||||
}
|
||||
mPropertyQueryFn.clear();
|
||||
mPropertyDefineFn.clear();
|
||||
mPoolMap.clear();
|
||||
}
|
||||
|
||||
void LLCoprocedureManager::initializePool(const std::string &poolName, size_t queue_size)
|
||||
|
|
@ -365,6 +380,22 @@ LLCoprocedurePool::LLCoprocedurePool(const std::string &poolName, size_t size, s
|
|||
|
||||
LLCoprocedurePool::~LLCoprocedurePool()
|
||||
{
|
||||
try
|
||||
{
|
||||
close(); // should have been closed already, but shouldn't hurt
|
||||
mStatusListener.disconnect();
|
||||
mPendingCoprocs.reset();
|
||||
mCoroMapping.clear();
|
||||
}
|
||||
catch (const boost::fibers::fiber_error&)
|
||||
{
|
||||
LL_WARNS() << "Fiber error during ~LLCoprocedurePool() " << mPoolName << LL_ENDL;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
// Shutting down, just log it
|
||||
LL_WARNS() << "Exception " << e.what() << " during ~LLCoprocedurePool() in " << mPoolName << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -71,6 +71,12 @@ target_link_libraries(llprimitive
|
|||
ll::glm
|
||||
)
|
||||
|
||||
if (TARGET llconvexdecomposition)
|
||||
target_link_libraries(llprimitive
|
||||
llconvexdecomposition
|
||||
)
|
||||
endif ()
|
||||
|
||||
if(LINUX)
|
||||
# GLIB uses pcre, so we need to keep it for Linux
|
||||
target_link_libraries(ll::pcre)
|
||||
|
|
|
|||
|
|
@ -923,3 +923,34 @@ void LLGLTFMaterial::updateTextureTracking()
|
|||
// setTEGLTFMaterialOverride is responsible for tracking
|
||||
// for material overrides editor will set it
|
||||
}
|
||||
|
||||
void LLGLTFMaterial::convertTextureTransformToPBR(
|
||||
F32 tex_scale_s,
|
||||
F32 tex_scale_t,
|
||||
F32 tex_offset_s,
|
||||
F32 tex_offset_t,
|
||||
F32 tex_rotation,
|
||||
LLVector2& pbr_scale,
|
||||
LLVector2& pbr_offset,
|
||||
F32& pbr_rotation)
|
||||
{
|
||||
pbr_scale.set(tex_scale_s, tex_scale_t);
|
||||
pbr_rotation = -(tex_rotation) / 2.f;
|
||||
const F32 adjusted_offset_s = tex_offset_s;
|
||||
const F32 adjusted_offset_t = -tex_offset_t;
|
||||
F32 center_adjust_s = 0.5f * (1.0f - tex_scale_s);
|
||||
F32 center_adjust_t = 0.5f * (1.0f - tex_scale_t);
|
||||
|
||||
if (pbr_rotation != 0.0f)
|
||||
{
|
||||
const F32 c = cosf(pbr_rotation);
|
||||
const F32 s = sinf(pbr_rotation);
|
||||
const F32 tmp_s = center_adjust_s * c - center_adjust_t * s;
|
||||
const F32 tmp_t = center_adjust_s * s + center_adjust_t * c;
|
||||
center_adjust_s = tmp_s;
|
||||
center_adjust_t = tmp_t;
|
||||
}
|
||||
|
||||
pbr_offset.set(adjusted_offset_s + center_adjust_s,
|
||||
adjusted_offset_t + center_adjust_t);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -214,6 +214,14 @@ public:
|
|||
bool hasLocalTextures() { return !mTrackingIdToLocalTexture.empty(); }
|
||||
virtual bool replaceLocalTexture(const LLUUID& tracking_id, const LLUUID &old_id, const LLUUID& new_id);
|
||||
virtual void updateTextureTracking();
|
||||
|
||||
// Convert legacy TE transform values to PBR transform values.
|
||||
static void convertTextureTransformToPBR(F32 tex_scale_s, F32 tex_scale_t,
|
||||
F32 tex_offset_s, F32 tex_offset_t,
|
||||
F32 tex_rotation,
|
||||
LLVector2& pbr_scale,
|
||||
LLVector2& pbr_offset,
|
||||
F32& pbr_rotation);
|
||||
protected:
|
||||
static LLVector2 vec2FromJson(const std::map<std::string, tinygltf::Value>& object, const char* key, const LLVector2& default_value);
|
||||
static F32 floatFromJson(const std::map<std::string, tinygltf::Value>& object, const char* key, const F32 default_value);
|
||||
|
|
|
|||
|
|
@ -1314,10 +1314,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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -307,7 +307,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;
|
||||
|
|
|
|||
|
|
@ -2216,10 +2216,14 @@ void LLFolderViewFolder::setOpen(bool openitem)
|
|||
{
|
||||
// navigateToFolder can destroy this view
|
||||
// delay it in case setOpen was called from click or key processing
|
||||
doOnIdleOneTime([this]()
|
||||
{
|
||||
getViewModelItem()->navigateToFolder();
|
||||
});
|
||||
LLPointer<LLFolderViewModelItem> view_model_item = mViewModelItem;
|
||||
doOnIdleOneTime([view_model_item]()
|
||||
{
|
||||
if (view_model_item.notNull())
|
||||
{
|
||||
view_model_item.get()->navigateToFolder();
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -374,8 +374,6 @@ void LLWebRTCImpl::terminate()
|
|||
|
||||
mSignalingThread->BlockingCall([this]() { mPeerConnectionFactory = nullptr; });
|
||||
|
||||
mPeerConnections.clear();
|
||||
|
||||
mWorkerThread->BlockingCall(
|
||||
[this]()
|
||||
{
|
||||
|
|
@ -386,6 +384,14 @@ void LLWebRTCImpl::terminate()
|
|||
mDeviceModule = nullptr;
|
||||
mTaskQueueFactory = nullptr;
|
||||
});
|
||||
|
||||
// In case peer connections still somehow have jobs in workers,
|
||||
// only clear connections up after clearing workers.
|
||||
mNetworkThread = nullptr;
|
||||
mWorkerThread = nullptr;
|
||||
mSignalingThread = nullptr;
|
||||
|
||||
mPeerConnections.clear();
|
||||
webrtc::LogMessage::RemoveLogToStream(mLogSink);
|
||||
}
|
||||
|
||||
|
|
@ -635,6 +641,13 @@ void LLWebRTCImpl::OnDevicesUpdated()
|
|||
void LLWebRTCImpl::setTuningMode(bool enable)
|
||||
{
|
||||
mTuningMode = enable;
|
||||
if (!mTuningMode
|
||||
&& !mMute
|
||||
&& mPeerCustomProcessor
|
||||
&& mPeerCustomProcessor->getGain() != mGain)
|
||||
{
|
||||
mPeerCustomProcessor->setGain(mGain);
|
||||
}
|
||||
mWorkerThread->PostTask(
|
||||
[this]
|
||||
{
|
||||
|
|
@ -766,6 +779,7 @@ void LLWebRTCImpl::freePeerConnection(LLWebRTCPeerConnectionInterface* peer_conn
|
|||
std::find(mPeerConnections.begin(), mPeerConnections.end(), peer_connection);
|
||||
if (it != mPeerConnections.end())
|
||||
{
|
||||
// Todo: make sure conection had no jobs in workers
|
||||
mPeerConnections.erase(it);
|
||||
if (mPeerConnections.empty())
|
||||
{
|
||||
|
|
@ -785,7 +799,8 @@ LLWebRTCPeerConnectionImpl::LLWebRTCPeerConnectionImpl() :
|
|||
mWebRTCImpl(nullptr),
|
||||
mPeerConnection(nullptr),
|
||||
mMute(MUTE_INITIAL),
|
||||
mAnswerReceived(false)
|
||||
mAnswerReceived(false),
|
||||
mPendingJobs(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -793,6 +808,10 @@ LLWebRTCPeerConnectionImpl::~LLWebRTCPeerConnectionImpl()
|
|||
{
|
||||
mSignalingObserverList.clear();
|
||||
mDataObserverList.clear();
|
||||
if (mPendingJobs > 0)
|
||||
{
|
||||
RTC_LOG(LS_ERROR) << __FUNCTION__ << "Destroying a connection that has " << std::to_string(mPendingJobs) << " unfinished jobs that might cause workers to crash";
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -804,8 +823,10 @@ void LLWebRTCPeerConnectionImpl::init(LLWebRTCImpl * webrtc_impl)
|
|||
mWebRTCImpl = webrtc_impl;
|
||||
mPeerConnectionFactory = mWebRTCImpl->getPeerConnectionFactory();
|
||||
}
|
||||
|
||||
void LLWebRTCPeerConnectionImpl::terminate()
|
||||
{
|
||||
mPendingJobs++;
|
||||
mWebRTCImpl->PostSignalingTask(
|
||||
[this]()
|
||||
{
|
||||
|
|
@ -848,7 +869,9 @@ void LLWebRTCPeerConnectionImpl::terminate()
|
|||
observer->OnPeerConnectionClosed();
|
||||
}
|
||||
}
|
||||
mPendingJobs--;
|
||||
});
|
||||
mPeerConnectionFactory.release();
|
||||
}
|
||||
|
||||
void LLWebRTCPeerConnectionImpl::setSignalingObserver(LLWebRTCSignalingObserver *observer) { mSignalingObserverList.emplace_back(observer); }
|
||||
|
|
@ -869,6 +892,7 @@ bool LLWebRTCPeerConnectionImpl::initializeConnection(const LLWebRTCPeerConnecti
|
|||
RTC_DCHECK(!mPeerConnection);
|
||||
mAnswerReceived = false;
|
||||
|
||||
mPendingJobs++;
|
||||
mWebRTCImpl->PostSignalingTask(
|
||||
[this,options]()
|
||||
{
|
||||
|
|
@ -890,6 +914,13 @@ bool LLWebRTCPeerConnectionImpl::initializeConnection(const LLWebRTCPeerConnecti
|
|||
config.set_max_port(60100);
|
||||
|
||||
webrtc::PeerConnectionDependencies pc_dependencies(this);
|
||||
if (mPeerConnectionFactory == nullptr)
|
||||
{
|
||||
RTC_LOG(LS_ERROR) << __FUNCTION__ << "Error creating peer connection, factory doesn't exist";
|
||||
// Too early?
|
||||
mPendingJobs--;
|
||||
return;
|
||||
}
|
||||
auto error_or_peer_connection = mPeerConnectionFactory->CreatePeerConnectionOrError(config, std::move(pc_dependencies));
|
||||
if (error_or_peer_connection.ok())
|
||||
{
|
||||
|
|
@ -902,6 +933,7 @@ bool LLWebRTCPeerConnectionImpl::initializeConnection(const LLWebRTCPeerConnecti
|
|||
{
|
||||
observer->OnRenegotiationNeeded();
|
||||
}
|
||||
mPendingJobs--;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -964,6 +996,7 @@ bool LLWebRTCPeerConnectionImpl::initializeConnection(const LLWebRTCPeerConnecti
|
|||
|
||||
webrtc::PeerConnectionInterface::RTCOfferAnswerOptions offerOptions;
|
||||
mPeerConnection->CreateOffer(this, offerOptions);
|
||||
mPendingJobs--;
|
||||
});
|
||||
|
||||
return true;
|
||||
|
|
@ -1006,6 +1039,7 @@ void LLWebRTCPeerConnectionImpl::AnswerAvailable(const std::string &sdp)
|
|||
{
|
||||
RTC_LOG(LS_INFO) << __FUNCTION__ << " Remote SDP: " << sdp;
|
||||
|
||||
mPendingJobs++;
|
||||
mWebRTCImpl->PostSignalingTask(
|
||||
[this, sdp]()
|
||||
{
|
||||
|
|
@ -1015,6 +1049,7 @@ void LLWebRTCPeerConnectionImpl::AnswerAvailable(const std::string &sdp)
|
|||
mPeerConnection->SetRemoteDescription(webrtc::CreateSessionDescription(webrtc::SdpType::kAnswer, sdp),
|
||||
webrtc::scoped_refptr<webrtc::SetRemoteDescriptionObserverInterface>(this));
|
||||
}
|
||||
mPendingJobs--;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -1037,6 +1072,7 @@ void LLWebRTCPeerConnectionImpl::setMute(bool mute)
|
|||
mMute = new_state;
|
||||
|
||||
|
||||
mPendingJobs++;
|
||||
mWebRTCImpl->PostSignalingTask(
|
||||
[this, force_reset, enable]()
|
||||
{
|
||||
|
|
@ -1060,6 +1096,7 @@ void LLWebRTCPeerConnectionImpl::setMute(bool mute)
|
|||
track->set_enabled(enable);
|
||||
}
|
||||
}
|
||||
mPendingJobs--;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -1081,6 +1118,7 @@ void LLWebRTCPeerConnectionImpl::resetMute()
|
|||
|
||||
void LLWebRTCPeerConnectionImpl::setReceiveVolume(float volume)
|
||||
{
|
||||
mPendingJobs++;
|
||||
mWebRTCImpl->PostSignalingTask(
|
||||
[this, volume]()
|
||||
{
|
||||
|
|
@ -1099,11 +1137,13 @@ void LLWebRTCPeerConnectionImpl::setReceiveVolume(float volume)
|
|||
}
|
||||
}
|
||||
}
|
||||
mPendingJobs--;
|
||||
});
|
||||
}
|
||||
|
||||
void LLWebRTCPeerConnectionImpl::setSendVolume(float volume)
|
||||
{
|
||||
mPendingJobs++;
|
||||
mWebRTCImpl->PostSignalingTask(
|
||||
[this, volume]()
|
||||
{
|
||||
|
|
@ -1114,6 +1154,7 @@ void LLWebRTCPeerConnectionImpl::setSendVolume(float volume)
|
|||
track->GetSource()->SetVolume(volume*5.0);
|
||||
}
|
||||
}
|
||||
mPendingJobs--;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -1190,11 +1231,13 @@ void LLWebRTCPeerConnectionImpl::OnConnectionChange(webrtc::PeerConnectionInterf
|
|||
{
|
||||
case webrtc::PeerConnectionInterface::PeerConnectionState::kConnected:
|
||||
{
|
||||
mPendingJobs++;
|
||||
mWebRTCImpl->PostWorkerTask([this]() {
|
||||
for (auto &observer : mSignalingObserverList)
|
||||
{
|
||||
observer->OnAudioEstablished(this);
|
||||
}
|
||||
mPendingJobs--;
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
|
@ -1452,11 +1495,13 @@ void LLWebRTCPeerConnectionImpl::sendData(const std::string& data, bool binary)
|
|||
{
|
||||
webrtc::CopyOnWriteBuffer cowBuffer(data.data(), data.length());
|
||||
webrtc::DataBuffer buffer(cowBuffer, binary);
|
||||
mPendingJobs++;
|
||||
mWebRTCImpl->PostNetworkTask([this, buffer]() {
|
||||
if (mDataChannel)
|
||||
{
|
||||
mDataChannel->Send(buffer);
|
||||
}
|
||||
mPendingJobs--;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -422,6 +422,9 @@ class LLWebRTCImpl : public LLWebRTCDeviceInterface, public webrtc::AudioDeviceO
|
|||
~LLWebRTCImpl()
|
||||
{
|
||||
delete mLogSink;
|
||||
|
||||
// Explicit cleanup for the sake of debugging and crash stacks
|
||||
mPeerCustomProcessor = nullptr;
|
||||
}
|
||||
|
||||
void init();
|
||||
|
|
@ -669,6 +672,8 @@ class LLWebRTCPeerConnectionImpl : public LLWebRTCPeerConnectionInterface,
|
|||
// data
|
||||
std::vector<LLWebRTCDataObserver *> mDataObserverList;
|
||||
webrtc::scoped_refptr<webrtc::DataChannelInterface> mDataChannel;
|
||||
|
||||
std::atomic<int> mPendingJobs;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2228,10 +2228,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}")
|
||||
|
|
@ -2601,6 +2597,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 ()
|
||||
|
||||
if (LINUX)
|
||||
# <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
|
||||
|
|
|
|||
|
|
@ -11312,7 +11312,7 @@ Change of this parameter will affect the layout of buttons in notification toast
|
|||
<key>RenderMaxOpenGLVersion</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Maximum OpenGL version to attempt use (minimum 3.1 maximum 4.6). Requires restart.</string>
|
||||
<string>Maximum OpenGL version to attempt use (minimum 3.1 maximum 4.6). Requires restart. Windows only.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
|
|
|
|||
|
|
@ -412,17 +412,14 @@ void LLGLTFLoader::processNodeHierarchy(S32 node_idx, std::map<std::string, S32>
|
|||
// Process this node's mesh if it has one
|
||||
if (node.mMesh >= 0 && node.mMesh < mGLTFAsset.mMeshes.size())
|
||||
{
|
||||
LLMatrix4 transformation;
|
||||
material_map mats;
|
||||
|
||||
LLModel* pModel = new LLModel(volume_params, 0.f);
|
||||
const LL::GLTF::Mesh& mesh = mGLTFAsset.mMeshes[node.mMesh];
|
||||
|
||||
// Get base mesh name and track usage
|
||||
std::string base_name = getLodlessLabel(mesh);
|
||||
// Get base node name and track usage
|
||||
// Potentially multiple nodes can reuse the same mesh and Collada used
|
||||
// node name instead of mesh name, so for consistency use node name if
|
||||
// avaliable, node index otherwise.
|
||||
std::string base_name = getLodlessLabel(node);
|
||||
if (base_name.empty())
|
||||
{
|
||||
base_name = "mesh_" + std::to_string(node.mMesh);
|
||||
base_name = "node_" + std::to_string(node_idx);
|
||||
}
|
||||
|
||||
S32 instance_count = mesh_name_counts[base_name]++;
|
||||
|
|
@ -433,6 +430,12 @@ void LLGLTFLoader::processNodeHierarchy(S32 node_idx, std::map<std::string, S32>
|
|||
base_name = base_name + "_copy_" + std::to_string(instance_count);
|
||||
}
|
||||
|
||||
LLMatrix4 transformation;
|
||||
material_map mats;
|
||||
|
||||
LLModel* pModel = new LLModel(volume_params, 0.f);
|
||||
const LL::GLTF::Mesh& mesh = mGLTFAsset.mMeshes[node.mMesh];
|
||||
|
||||
if (populateModelFromMesh(pModel, base_name, mesh, node, mats) &&
|
||||
(LLModel::NO_ERRORS == pModel->getStatus()) &&
|
||||
validate_model(pModel))
|
||||
|
|
@ -1818,13 +1821,13 @@ size_t LLGLTFLoader::getSuffixPosition(const std::string &label)
|
|||
return -1;
|
||||
}
|
||||
|
||||
std::string LLGLTFLoader::getLodlessLabel(const LL::GLTF::Mesh& mesh)
|
||||
std::string LLGLTFLoader::getLodlessLabel(const LL::GLTF::Node& node)
|
||||
{
|
||||
size_t ext_pos = getSuffixPosition(mesh.mName);
|
||||
size_t ext_pos = getSuffixPosition(node.mName);
|
||||
if (ext_pos != -1)
|
||||
{
|
||||
return mesh.mName.substr(0, ext_pos);
|
||||
return node.mName.substr(0, ext_pos);
|
||||
}
|
||||
return mesh.mName;
|
||||
return node.mName;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ private:
|
|||
void notifyUnsupportedExtension(bool unsupported);
|
||||
|
||||
static size_t getSuffixPosition(const std::string& label);
|
||||
static std::string getLodlessLabel(const LL::GLTF::Mesh& mesh);
|
||||
static std::string getLodlessLabel(const LL::GLTF::Node& mesh);
|
||||
|
||||
// bool mPreprocessGLTF;
|
||||
|
||||
|
|
|
|||
|
|
@ -1542,6 +1542,27 @@ void wear_on_avatar_cb(const LLUUID& inv_item, bool do_replace = false)
|
|||
}
|
||||
}
|
||||
|
||||
bool needs_to_replace(LLViewerInventoryItem* item_to_wear, bool & first_for_object, std::vector<bool>& first_for_type, bool replace)
|
||||
{
|
||||
bool res = false;
|
||||
LLAssetType::EType type = item_to_wear->getType();
|
||||
if (type == LLAssetType::AT_OBJECT)
|
||||
{
|
||||
res = first_for_object && replace;
|
||||
first_for_object = false;
|
||||
}
|
||||
else if (type == LLAssetType::AT_CLOTHING)
|
||||
{
|
||||
LLWearableType::EType wtype = item_to_wear->getWearableType();
|
||||
if (wtype >= 0 && wtype < LLWearableType::WT_COUNT)
|
||||
{
|
||||
res = first_for_type[wtype] && replace;
|
||||
first_for_type[wtype] = false;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void LLAppearanceMgr::wearItemsOnAvatar(const uuid_vec_t& item_ids_to_wear,
|
||||
bool do_update,
|
||||
bool replace,
|
||||
|
|
@ -1550,7 +1571,8 @@ void LLAppearanceMgr::wearItemsOnAvatar(const uuid_vec_t& item_ids_to_wear,
|
|||
LL_DEBUGS("UIUsage") << "wearItemsOnAvatar" << LL_ENDL;
|
||||
LLUIUsage::instance().logCommand("Avatar.WearItem");
|
||||
|
||||
bool first = true;
|
||||
bool first_for_object = true;
|
||||
std::vector<bool> first_for_type(LLWearableType::WT_COUNT, true);
|
||||
|
||||
LLInventoryObject::const_object_list_t items_to_link;
|
||||
|
||||
|
|
@ -1558,9 +1580,6 @@ void LLAppearanceMgr::wearItemsOnAvatar(const uuid_vec_t& item_ids_to_wear,
|
|||
it != item_ids_to_wear.end();
|
||||
++it)
|
||||
{
|
||||
replace = first && replace;
|
||||
first = false;
|
||||
|
||||
const LLUUID& item_id_to_wear = *it;
|
||||
|
||||
if (item_id_to_wear.isNull())
|
||||
|
|
@ -1579,8 +1598,9 @@ void LLAppearanceMgr::wearItemsOnAvatar(const uuid_vec_t& item_ids_to_wear,
|
|||
if (gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.getLibraryRootFolderID()))
|
||||
{
|
||||
LL_DEBUGS("Avatar") << "inventory item in library, will copy and wear "
|
||||
<< item_to_wear->getName() << " id " << item_id_to_wear << LL_ENDL;
|
||||
LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(wear_on_avatar_cb,_1,replace));
|
||||
<< item_to_wear->getName() << " id " << item_id_to_wear << LL_ENDL;
|
||||
bool replace_item = needs_to_replace(item_to_wear, first_for_object, first_for_type, replace);
|
||||
LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(wear_on_avatar_cb, _1, replace_item));
|
||||
copy_inventory_item(gAgent.getID(), item_to_wear->getPermissions().getOwner(),
|
||||
item_to_wear->getUUID(), LLUUID::null, std::string(), cb);
|
||||
continue;
|
||||
|
|
@ -1627,7 +1647,8 @@ void LLAppearanceMgr::wearItemsOnAvatar(const uuid_vec_t& item_ids_to_wear,
|
|||
}
|
||||
LLWearableType::EType type = item_to_wear->getWearableType();
|
||||
S32 wearable_count = gAgentWearables.getWearableCount(type);
|
||||
if ((replace && wearable_count != 0) || !gAgentWearables.canAddWearable(type))
|
||||
bool replace_item = needs_to_replace(item_to_wear, first_for_object, first_for_type, replace);
|
||||
if ((replace_item && wearable_count != 0) || !gAgentWearables.canAddWearable(type))
|
||||
{
|
||||
LLUUID item_id = gAgentWearables.getWearableItemID(item_to_wear->getWearableType(),
|
||||
wearable_count-1);
|
||||
|
|
@ -1659,7 +1680,13 @@ void LLAppearanceMgr::wearItemsOnAvatar(const uuid_vec_t& item_ids_to_wear,
|
|||
|
||||
case LLAssetType::AT_OBJECT:
|
||||
{
|
||||
rez_attachment(item_to_wear, NULL, replace);
|
||||
// Note that this will replace only first attachment regardless of attachment point,
|
||||
// so if user is wearing two items over other two on different attachment points,
|
||||
// only one will be replaced.
|
||||
// Unfortunately we have no way to determine attachment point from inventory item.
|
||||
// We might want to forbid wearing multiple objects with replace option in future.
|
||||
bool replace_item = needs_to_replace(item_to_wear, first_for_object, first_for_type, replace);
|
||||
rez_attachment(item_to_wear, NULL, replace_item);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
|||
|
|
@ -6462,7 +6462,10 @@ void LLAppViewer::idleNetwork()
|
|||
add(LLStatViewer::NUM_NEW_OBJECTS, gObjectList.mNumNewObjects);
|
||||
|
||||
// Retransmit unacknowledged packets.
|
||||
gXferManager->retransmitUnackedPackets();
|
||||
if (gXferManager)
|
||||
{
|
||||
gXferManager->retransmitUnackedPackets();
|
||||
}
|
||||
gAssetStorage->checkForTimeouts();
|
||||
gViewerThrottle.setBufferLoadRate(gMessageSystem->getBufferLoadRate());
|
||||
gViewerThrottle.updateDynamicThrottle();
|
||||
|
|
|
|||
|
|
@ -222,6 +222,14 @@ void LLFetchedGLTFMaterial::updateTextureTracking()
|
|||
}
|
||||
}
|
||||
|
||||
void LLFetchedGLTFMaterial::clearFetchedTextures()
|
||||
{
|
||||
mBaseColorTexture = nullptr;
|
||||
mNormalTexture = nullptr;
|
||||
mMetallicRoughnessTexture = nullptr;
|
||||
mEmissiveTexture = nullptr;
|
||||
}
|
||||
|
||||
void LLFetchedGLTFMaterial::materialBegin()
|
||||
{
|
||||
llassert(!mFetching);
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ public:
|
|||
LLPointer<LLViewerFetchedTexture> mNormalTexture;
|
||||
LLPointer<LLViewerFetchedTexture> mMetallicRoughnessTexture;
|
||||
LLPointer<LLViewerFetchedTexture> mEmissiveTexture;
|
||||
void clearFetchedTextures();
|
||||
|
||||
std::set<LLTextureEntry*> mTextureEntires;
|
||||
|
||||
|
|
|
|||
|
|
@ -134,12 +134,15 @@ void LLFloaterFixedEnvironment::onClose(bool app_quitting)
|
|||
{
|
||||
doCloseInventoryFloater(app_quitting);
|
||||
|
||||
LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL);
|
||||
LLEnvironment::instance().setCurrentEnvironmentSelection(LLEnvironment::ENV_LOCAL);
|
||||
LLEnvironment::instance().clearEnvironment(LLEnvironment::ENV_EDIT);
|
||||
if (!app_quitting)
|
||||
{
|
||||
LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL);
|
||||
LLEnvironment::instance().setCurrentEnvironmentSelection(LLEnvironment::ENV_LOCAL);
|
||||
LLEnvironment::instance().clearEnvironment(LLEnvironment::ENV_EDIT);
|
||||
|
||||
mSettings.reset();
|
||||
syncronizeTabs();
|
||||
mSettings.reset();
|
||||
syncronizeTabs();
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterFixedEnvironment::refresh()
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -328,7 +328,7 @@ bool LLFloaterModelPreview::postBuild()
|
|||
// </Ansariel>
|
||||
|
||||
// <FS:CR> Show an alert dialog if using the Opensim viewer as functionality will be limited without Havok
|
||||
#ifndef HAVOK_TPV
|
||||
#if !LL_HAVOK
|
||||
LLSD args;
|
||||
args["FEATURE"] = getString("no_havok");
|
||||
LLNotificationsUtil::add("NoHavok", args);
|
||||
|
|
@ -1136,8 +1136,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);
|
||||
|
|
@ -1320,6 +1325,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);
|
||||
|
|
@ -2214,7 +2220,7 @@ void LLFloaterModelPreview::DecompRequest::completed()
|
|||
{ //called from the main thread
|
||||
if (mContinue)
|
||||
{
|
||||
mModel->setConvexHullDecomposition(mHull);
|
||||
mModel->setConvexHullDecomposition(mHull, mHullMesh);
|
||||
|
||||
if (sInstance)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ class LLSearchHandler : public LLCommandHandler {
|
|||
LLSearchHandler gSearchHandler;
|
||||
|
||||
LLFloaterSearch::LLFloaterSearch(const LLSD& key)
|
||||
: LLFloater(key)
|
||||
: LLFloaterWebContent(key)
|
||||
{
|
||||
mSearchType.insert("standard");
|
||||
mSearchType.insert("land");
|
||||
|
|
@ -89,6 +89,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)
|
||||
|
|
@ -179,7 +185,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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -959,6 +959,10 @@ void LLIMModel::LLIMSession::initVoiceChannel(const LLSD& voiceChannelInfo)
|
|||
{
|
||||
if (mVoiceChannel)
|
||||
{
|
||||
if (!voiceChannelInfo.isMap())
|
||||
{
|
||||
LL_WARNS() << "initVoiceChannel called without voiceChannelInfo" << LL_ENDL;
|
||||
}
|
||||
if (mVoiceChannel->isThisVoiceChannel(voiceChannelInfo))
|
||||
{
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -261,6 +261,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
|
||||
|
|
@ -1014,6 +1015,12 @@ LLMeshRepoThread::~LLMeshRepoThread()
|
|||
mDecompositionQ.pop_front();
|
||||
}
|
||||
|
||||
while (!mPhysicsQ.empty())
|
||||
{
|
||||
delete mPhysicsQ.front();
|
||||
mPhysicsQ.pop_front();
|
||||
}
|
||||
|
||||
delete mHttpRequest;
|
||||
mHttpRequest = nullptr;
|
||||
delete mMutex;
|
||||
|
|
@ -2672,7 +2679,7 @@ EMeshProcessingResult LLMeshRepoThread::physicsShapeReceived(const LLUUID& mesh_
|
|||
|
||||
{
|
||||
LLMutexLock lock(mLoadedMutex);
|
||||
mDecompositionQ.push_back(d);
|
||||
mPhysicsQ.push_back(d);
|
||||
}
|
||||
return MESH_OK;
|
||||
}
|
||||
|
|
@ -3483,13 +3490,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())
|
||||
{
|
||||
|
|
@ -3506,6 +3514,11 @@ void LLMeshRepoThread::notifyLoadedMeshes()
|
|||
decomp_q.swap(mDecompositionQ);
|
||||
}
|
||||
|
||||
if (!mPhysicsQ.empty())
|
||||
{
|
||||
physics_q.swap(mPhysicsQ);
|
||||
}
|
||||
|
||||
mLoadedMutex->unlock();
|
||||
|
||||
// Process the elements free of the lock
|
||||
|
|
@ -3522,9 +3535,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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4837,13 +4856,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
|
||||
|
|
@ -4851,10 +4870,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)
|
||||
|
|
@ -5001,7 +5027,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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -531,6 +531,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;
|
||||
|
||||
|
|
@ -902,7 +905,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);
|
||||
|
|
|
|||
|
|
@ -3387,7 +3387,7 @@ void LLModelPreview::updateStatusMessages()
|
|||
// physStatusIcon->setImage(img);
|
||||
// }
|
||||
//}
|
||||
#ifndef HAVOK_TPV
|
||||
#if !LL_HAVOK
|
||||
has_physics_error |= PhysicsError::NOHAVOK;
|
||||
#endif
|
||||
|
||||
|
|
@ -3627,7 +3627,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)
|
||||
{
|
||||
|
|
@ -3651,6 +3660,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)
|
||||
{
|
||||
|
|
@ -3660,6 +3671,7 @@ void LLModelPreview::updateStatusMessages()
|
|||
if (phys_tris || phys_hulls > 0)
|
||||
{
|
||||
fmp->childEnable("Decompose");
|
||||
fmp->childEnable("Analyze");
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -230,11 +230,7 @@ LLPathfindingPathTool::EPathStatus LLPathfindingPathTool::getPathStatus() const
|
|||
|
||||
F32 LLPathfindingPathTool::getCharacterWidth() const
|
||||
{
|
||||
#ifdef HAVOK_TPV
|
||||
return mFinalPathData.mCharacterWidth;
|
||||
#else
|
||||
return (F32)mFinalPathData.mCharacterWidth;
|
||||
#endif
|
||||
}
|
||||
|
||||
void LLPathfindingPathTool::setCharacterWidth(F32 pCharacterWidth)
|
||||
|
|
|
|||
|
|
@ -2140,9 +2140,96 @@ bool LLSelectMgr::selectionSetGLTFMaterial(const LLUUID& mat_id)
|
|||
asset_id = BLANK_MATERIAL_ASSET_ID;
|
||||
}
|
||||
}
|
||||
|
||||
// If this face already has the target material ID, do nothing.
|
||||
// This prevents re-sending the same ID on OK, which can cause the server
|
||||
// to drop overrides when queueApply is invoked with the OLD id.
|
||||
if (objectp->getRenderMaterialID(te) == asset_id)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Preserve existing texture transforms when switching to PBR material
|
||||
LLTextureEntry* tep = objectp->getTE(te);
|
||||
bool should_preserve_transforms = false;
|
||||
LLGLTFMaterial* preserved_override = nullptr;
|
||||
|
||||
if (tep && asset_id.notNull())
|
||||
{
|
||||
// Only preserve transforms from existing GLTF material override
|
||||
// Do not fall back to texture entry transforms when switching between PBR materials
|
||||
LLGLTFMaterial* existing_override = tep->getGLTFMaterialOverride();
|
||||
if (existing_override)
|
||||
{
|
||||
// Check if existing override has non-default transforms
|
||||
const LLGLTFMaterial::TextureTransform& existing_transform = existing_override->mTextureTransform[0];
|
||||
const LLGLTFMaterial::TextureTransform& default_transform = LLGLTFMaterial::TextureTransform();
|
||||
|
||||
if (existing_transform.mScale != default_transform.mScale ||
|
||||
existing_transform.mOffset != default_transform.mOffset ||
|
||||
existing_transform.mRotation != default_transform.mRotation)
|
||||
{
|
||||
// Preserve non-default transforms from current PBR material
|
||||
preserved_override = new LLGLTFMaterial();
|
||||
for (U32 i = 0; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++i)
|
||||
{
|
||||
preserved_override->mTextureTransform[i].mScale = existing_transform.mScale;
|
||||
preserved_override->mTextureTransform[i].mOffset = existing_transform.mOffset;
|
||||
preserved_override->mTextureTransform[i].mRotation = existing_transform.mRotation;
|
||||
}
|
||||
should_preserve_transforms = true;
|
||||
}
|
||||
// If existing override has default transforms, don't preserve anything
|
||||
}
|
||||
else
|
||||
{
|
||||
// No existing PBR material override - check texture entry transforms
|
||||
// This handles the case of switching from Blinn-Phong to PBR material
|
||||
F32 existing_scale_s, existing_scale_t, existing_offset_s, existing_offset_t, existing_rotation;
|
||||
tep->getScale(&existing_scale_s, &existing_scale_t);
|
||||
tep->getOffset(&existing_offset_s, &existing_offset_t);
|
||||
existing_rotation = tep->getRotation();
|
||||
|
||||
const LLGLTFMaterial::TextureTransform& default_transform = LLGLTFMaterial::TextureTransform();
|
||||
if (existing_scale_s != default_transform.mScale.mV[0] || existing_scale_t != default_transform.mScale.mV[1] ||
|
||||
existing_offset_s != default_transform.mOffset.mV[0] || existing_offset_t != default_transform.mOffset.mV[1] ||
|
||||
existing_rotation != default_transform.mRotation)
|
||||
{
|
||||
// Preserve non-default transforms from texture entry
|
||||
preserved_override = new LLGLTFMaterial();
|
||||
for (U32 i = 0; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++i)
|
||||
{
|
||||
LLVector2 pbr_scale, pbr_offset;
|
||||
F32 pbr_rotation;
|
||||
LLGLTFMaterial::convertTextureTransformToPBR(
|
||||
existing_scale_s, existing_scale_t,
|
||||
existing_offset_s, existing_offset_t,
|
||||
existing_rotation,
|
||||
pbr_scale, pbr_offset, pbr_rotation);
|
||||
preserved_override->mTextureTransform[i].mScale = pbr_scale;
|
||||
preserved_override->mTextureTransform[i].mOffset = pbr_offset;
|
||||
preserved_override->mTextureTransform[i].mRotation = pbr_rotation;
|
||||
}
|
||||
should_preserve_transforms = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
objectp->clearTEWaterExclusion(te);
|
||||
// Blank out most override data on the object and send to server
|
||||
objectp->setRenderMaterialID(te, asset_id);
|
||||
if (should_preserve_transforms && preserved_override)
|
||||
{
|
||||
// Apply material with preserved transforms
|
||||
LLGLTFMaterialList::queueApply(objectp, te, asset_id, preserved_override);
|
||||
// Update local state
|
||||
objectp->setRenderMaterialID(te, asset_id, false, true);
|
||||
tep->setGLTFMaterialOverride(preserved_override);
|
||||
}
|
||||
else
|
||||
{
|
||||
objectp->setRenderMaterialID(te, asset_id);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@
|
|||
#include "llpanelpresetscamerapulldown.h"
|
||||
#include "llpanelpresetspulldown.h"
|
||||
#include "llpanelvolumepulldown.h"
|
||||
#include "llfloatermarketplace.h"
|
||||
#include "llfloaterregioninfo.h"
|
||||
#include "llfloaterscriptdebug.h"
|
||||
#include "llhints.h"
|
||||
|
|
@ -971,7 +972,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()
|
||||
|
|
|
|||
|
|
@ -1866,9 +1866,17 @@ LLTextureCtrl::LLTextureCtrl(const LLTextureCtrl::Params& p)
|
|||
mIsPreviewDisabled(false)
|
||||
{
|
||||
mCaptionHeight = p.show_caption ? BTN_HEIGHT_SMALL : 0; // <FS:Zi> leave some room underneath the image for the caption
|
||||
// Default of defaults is white image for diff tex
|
||||
//
|
||||
setBlankImageAssetID(IMG_WHITE);
|
||||
|
||||
if (mInventoryPickType == PICK_MATERIAL)
|
||||
{
|
||||
setBlankImageAssetID(BLANK_MATERIAL_ASSET_ID);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Default of defaults is white image for diff tex
|
||||
//
|
||||
setBlankImageAssetID(IMG_WHITE);
|
||||
}
|
||||
|
||||
setAllowNoTexture(p.allow_no_texture);
|
||||
setCanApplyImmediately(p.can_apply_immediately);
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@
|
|||
|
||||
// library headers
|
||||
#include "llnotificationsutil.h"
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
// project headers
|
||||
#include "llagent.h"
|
||||
#include "llagentcamera.h"
|
||||
|
|
@ -1311,7 +1313,89 @@ void LLToolDragAndDrop::dropMaterialOneFace(LLViewerObject* hit_obj,
|
|||
asset_id = BLANK_MATERIAL_ASSET_ID;
|
||||
}
|
||||
|
||||
hit_obj->setRenderMaterialID(hit_face, asset_id);
|
||||
// Preserve existing texture transforms when switching to PBR material
|
||||
LLTextureEntry* tep = hit_obj->getTE(hit_face);
|
||||
F32 existing_scale_s = LLGLTFMaterial::TextureTransform().mScale.mV[0];
|
||||
F32 existing_scale_t = LLGLTFMaterial::TextureTransform().mScale.mV[1];
|
||||
F32 existing_offset_s = LLGLTFMaterial::TextureTransform().mOffset.mV[0];
|
||||
F32 existing_offset_t = LLGLTFMaterial::TextureTransform().mOffset.mV[1];
|
||||
F32 existing_rotation = LLGLTFMaterial::TextureTransform().mRotation;
|
||||
bool should_preserve_transforms = false;
|
||||
LLGLTFMaterial* preserved_override = nullptr;
|
||||
|
||||
if (tep && asset_id.notNull())
|
||||
{
|
||||
// Only preserve transforms from existing GLTF material override
|
||||
// Do not fall back to texture entry transforms when switching between PBR materials
|
||||
LLGLTFMaterial* existing_override = tep->getGLTFMaterialOverride();
|
||||
if (existing_override)
|
||||
{
|
||||
// Check if existing override has non-default transforms
|
||||
const LLGLTFMaterial::TextureTransform& existing_transform = existing_override->mTextureTransform[0];
|
||||
const LLGLTFMaterial::TextureTransform& default_transform = LLGLTFMaterial::TextureTransform();
|
||||
|
||||
if (existing_transform.mScale != default_transform.mScale ||
|
||||
existing_transform.mOffset != default_transform.mOffset ||
|
||||
existing_transform.mRotation != default_transform.mRotation)
|
||||
{
|
||||
// Preserve non-default transforms from current PBR material
|
||||
preserved_override = new LLGLTFMaterial();
|
||||
for (U32 i = 0; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++i)
|
||||
{
|
||||
preserved_override->mTextureTransform[i].mScale = existing_transform.mScale;
|
||||
preserved_override->mTextureTransform[i].mOffset = existing_transform.mOffset;
|
||||
preserved_override->mTextureTransform[i].mRotation = existing_transform.mRotation;
|
||||
}
|
||||
should_preserve_transforms = true;
|
||||
}
|
||||
// If existing override has default transforms, don't preserve anything
|
||||
}
|
||||
else
|
||||
{
|
||||
// No existing PBR material override - check texture entry transforms
|
||||
// This handles the case of switching from Blinn-Phong to PBR material
|
||||
F32 existing_scale_s, existing_scale_t, existing_offset_s, existing_offset_t, existing_rotation;
|
||||
tep->getScale(&existing_scale_s, &existing_scale_t);
|
||||
tep->getOffset(&existing_offset_s, &existing_offset_t);
|
||||
existing_rotation = tep->getRotation();
|
||||
|
||||
const LLGLTFMaterial::TextureTransform& default_transform = LLGLTFMaterial::TextureTransform();
|
||||
if (existing_scale_s != default_transform.mScale.mV[0] || existing_scale_t != default_transform.mScale.mV[1] ||
|
||||
existing_offset_s != default_transform.mOffset.mV[0] || existing_offset_t != default_transform.mOffset.mV[1] ||
|
||||
existing_rotation != default_transform.mRotation)
|
||||
{
|
||||
// Preserve non-default transforms from texture entry
|
||||
preserved_override = new LLGLTFMaterial();
|
||||
for (U32 i = 0; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++i)
|
||||
{
|
||||
LLVector2 pbr_scale, pbr_offset;
|
||||
F32 pbr_rotation;
|
||||
LLGLTFMaterial::convertTextureTransformToPBR(
|
||||
existing_scale_s, existing_scale_t,
|
||||
existing_offset_s, existing_offset_t,
|
||||
existing_rotation,
|
||||
pbr_scale, pbr_offset, pbr_rotation);
|
||||
preserved_override->mTextureTransform[i].mScale = pbr_scale;
|
||||
preserved_override->mTextureTransform[i].mOffset = pbr_offset;
|
||||
preserved_override->mTextureTransform[i].mRotation = pbr_rotation;
|
||||
}
|
||||
should_preserve_transforms = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (should_preserve_transforms && preserved_override)
|
||||
{
|
||||
// Apply material with preserved transforms
|
||||
LLGLTFMaterialList::queueApply(hit_obj, hit_face, asset_id, preserved_override);
|
||||
// Update local state
|
||||
hit_obj->setRenderMaterialID(hit_face, asset_id, false, true);
|
||||
tep->setGLTFMaterialOverride(preserved_override);
|
||||
}
|
||||
else
|
||||
{
|
||||
hit_obj->setRenderMaterialID(hit_face, asset_id);
|
||||
}
|
||||
|
||||
dialog_refresh_all();
|
||||
|
||||
|
|
@ -1347,7 +1431,134 @@ void LLToolDragAndDrop::dropMaterialAllFaces(LLViewerObject* hit_obj,
|
|||
asset_id = BLANK_MATERIAL_ASSET_ID;
|
||||
}
|
||||
|
||||
hit_obj->setRenderMaterialIDs(asset_id);
|
||||
// Preserve existing texture transforms when switching to PBR material for all faces
|
||||
std::vector<std::pair<bool, LLGLTFMaterial*>> preserved_transforms(hit_obj->getNumTEs());
|
||||
|
||||
if (asset_id.notNull())
|
||||
{
|
||||
for (S32 te = 0; te < hit_obj->getNumTEs(); ++te)
|
||||
{
|
||||
LLTextureEntry* tep = hit_obj->getTE(te);
|
||||
if (!tep) continue;
|
||||
|
||||
bool should_preserve = false;
|
||||
LLGLTFMaterial* preserved_override = nullptr;
|
||||
|
||||
// Only preserve transforms from existing GLTF material override
|
||||
// Do not fall back to texture entry transforms when switching between PBR materials
|
||||
LLGLTFMaterial* existing_override = tep->getGLTFMaterialOverride();
|
||||
if (existing_override)
|
||||
{
|
||||
// Check if existing override has non-default transforms
|
||||
const LLGLTFMaterial::TextureTransform& existing_transform = existing_override->mTextureTransform[0];
|
||||
const LLGLTFMaterial::TextureTransform& default_transform = LLGLTFMaterial::TextureTransform();
|
||||
|
||||
if (existing_transform.mScale != default_transform.mScale ||
|
||||
existing_transform.mOffset != default_transform.mOffset ||
|
||||
existing_transform.mRotation != default_transform.mRotation)
|
||||
{
|
||||
// Preserve non-default transforms from current PBR material
|
||||
preserved_override = new LLGLTFMaterial();
|
||||
for (U32 i = 0; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++i)
|
||||
{
|
||||
preserved_override->mTextureTransform[i].mScale = existing_transform.mScale;
|
||||
preserved_override->mTextureTransform[i].mOffset = existing_transform.mOffset;
|
||||
preserved_override->mTextureTransform[i].mRotation = existing_transform.mRotation;
|
||||
}
|
||||
should_preserve = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Existing override has default transforms, fall back to texture entry
|
||||
F32 existing_scale_s, existing_scale_t, existing_offset_s, existing_offset_t, existing_rotation;
|
||||
tep->getScale(&existing_scale_s, &existing_scale_t);
|
||||
tep->getOffset(&existing_offset_s, &existing_offset_t);
|
||||
existing_rotation = tep->getRotation();
|
||||
|
||||
if (existing_scale_s != default_transform.mScale.mV[0] || existing_scale_t != default_transform.mScale.mV[1] ||
|
||||
existing_offset_s != default_transform.mOffset.mV[0] || existing_offset_t != default_transform.mOffset.mV[1] ||
|
||||
existing_rotation != default_transform.mRotation)
|
||||
{
|
||||
// Preserve non-default transforms from texture entry
|
||||
preserved_override = new LLGLTFMaterial();
|
||||
for (U32 i = 0; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++i)
|
||||
{
|
||||
LLVector2 pbr_scale, pbr_offset;
|
||||
F32 pbr_rotation;
|
||||
LLGLTFMaterial::convertTextureTransformToPBR(
|
||||
existing_scale_s, existing_scale_t,
|
||||
existing_offset_s, existing_offset_t,
|
||||
existing_rotation,
|
||||
pbr_scale, pbr_offset, pbr_rotation);
|
||||
preserved_override->mTextureTransform[i].mScale = pbr_scale;
|
||||
preserved_override->mTextureTransform[i].mOffset = pbr_offset;
|
||||
preserved_override->mTextureTransform[i].mRotation = pbr_rotation;
|
||||
}
|
||||
should_preserve = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// No existing PBR material override - check texture entry transforms
|
||||
// This handles the case of switching from Blinn-Phong to PBR material
|
||||
F32 existing_scale_s, existing_scale_t, existing_offset_s, existing_offset_t, existing_rotation;
|
||||
tep->getScale(&existing_scale_s, &existing_scale_t);
|
||||
tep->getOffset(&existing_offset_s, &existing_offset_t);
|
||||
existing_rotation = tep->getRotation();
|
||||
|
||||
const LLGLTFMaterial::TextureTransform& default_transform = LLGLTFMaterial::TextureTransform();
|
||||
if (existing_scale_s != default_transform.mScale.mV[0] || existing_scale_t != default_transform.mScale.mV[1] ||
|
||||
existing_offset_s != default_transform.mOffset.mV[0] || existing_offset_t != default_transform.mOffset.mV[1] ||
|
||||
existing_rotation != default_transform.mRotation)
|
||||
{
|
||||
// Preserve non-default transforms from texture entry
|
||||
preserved_override = new LLGLTFMaterial();
|
||||
for (U32 i = 0; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++i)
|
||||
{
|
||||
LLVector2 pbr_scale, pbr_offset;
|
||||
F32 pbr_rotation;
|
||||
LLGLTFMaterial::convertTextureTransformToPBR(
|
||||
existing_scale_s, existing_scale_t,
|
||||
existing_offset_s, existing_offset_t,
|
||||
existing_rotation,
|
||||
pbr_scale, pbr_offset, pbr_rotation);
|
||||
preserved_override->mTextureTransform[i].mScale = pbr_scale;
|
||||
preserved_override->mTextureTransform[i].mOffset = pbr_offset;
|
||||
preserved_override->mTextureTransform[i].mRotation = pbr_rotation;
|
||||
}
|
||||
should_preserve = true;
|
||||
}
|
||||
}
|
||||
|
||||
preserved_transforms[te] = std::make_pair(should_preserve, preserved_override);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply materials with preserved transforms
|
||||
if (asset_id.notNull())
|
||||
{
|
||||
for (S32 te = 0; te < hit_obj->getNumTEs(); ++te)
|
||||
{
|
||||
LLGLTFMaterial* preserved_override = preserved_transforms[te].second;
|
||||
if (preserved_override)
|
||||
{
|
||||
// Apply material with preserved transforms
|
||||
LLGLTFMaterialList::queueApply(hit_obj, te, asset_id, preserved_override);
|
||||
// Update local state
|
||||
hit_obj->setRenderMaterialID(te, asset_id, false, true);
|
||||
hit_obj->getTE(te)->setGLTFMaterialOverride(preserved_override);
|
||||
}
|
||||
else
|
||||
{
|
||||
hit_obj->setRenderMaterialID(te, asset_id, false, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hit_obj->setRenderMaterialIDs(asset_id);
|
||||
}
|
||||
dialog_refresh_all();
|
||||
// send the update to the simulator
|
||||
hit_obj->sendTEUpdate();
|
||||
|
|
|
|||
|
|
@ -940,7 +940,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;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5259,11 +5259,10 @@ void LLViewerObject::setNumTEs(const U8 num_tes)
|
|||
if (base_material && override_material)
|
||||
{
|
||||
tep->setGLTFMaterialOverride(new LLGLTFMaterial(*override_material));
|
||||
|
||||
LLGLTFMaterial* render_material = new LLFetchedGLTFMaterial();
|
||||
*render_material = *base_material;
|
||||
render_material->applyOverride(*override_material);
|
||||
tep->setGLTFRenderMaterial(render_material);
|
||||
}
|
||||
if (base_material)
|
||||
{
|
||||
initRenderMaterial(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5449,6 +5448,9 @@ void LLViewerObject::updateTEMaterialTextures(U8 te)
|
|||
});
|
||||
}
|
||||
getTE(te)->setGLTFMaterial(mat);
|
||||
initRenderMaterial(te);
|
||||
mat = (LLFetchedGLTFMaterial*) getTE(te)->getGLTFRenderMaterial();
|
||||
llassert(mat == nullptr || dynamic_cast<LLFetchedGLTFMaterial*>(getTE(te)->getGLTFRenderMaterial()) != nullptr);
|
||||
}
|
||||
else if (mat_id.isNull() && mat != nullptr)
|
||||
{
|
||||
|
|
@ -5838,6 +5840,42 @@ S32 LLViewerObject::setTEMaterialParams(const U8 te, const LLMaterialPtr pMateri
|
|||
return retval;
|
||||
}
|
||||
|
||||
// Set render material if there are overrides or if the base material is has a
|
||||
// baked texture. Otherwise, set it to null.
|
||||
// If you are setting the material override and not sending an update message,
|
||||
// you should probably call this function.
|
||||
S32 LLViewerObject::initRenderMaterial(U8 te)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
|
||||
LLTextureEntry* tep = getTE(te);
|
||||
if (!tep) { return 0; }
|
||||
const LLFetchedGLTFMaterial* base_material = static_cast<LLFetchedGLTFMaterial*>(tep->getGLTFMaterial());
|
||||
llassert(base_material);
|
||||
if (!base_material) { return 0; }
|
||||
const LLGLTFMaterial* override_material = tep->getGLTFMaterialOverride();
|
||||
LLFetchedGLTFMaterial* render_material = nullptr;
|
||||
bool need_render_material = override_material;
|
||||
if (!need_render_material)
|
||||
{
|
||||
for (const LLUUID& texture_id : base_material->mTextureId)
|
||||
{
|
||||
if (LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::isBakedImageId(texture_id))
|
||||
{
|
||||
need_render_material = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (need_render_material)
|
||||
{
|
||||
render_material = new LLFetchedGLTFMaterial(*base_material);
|
||||
if (override_material) { render_material->applyOverride(*override_material); }
|
||||
render_material->clearFetchedTextures();
|
||||
}
|
||||
return tep->setGLTFRenderMaterial(render_material);
|
||||
}
|
||||
|
||||
S32 LLViewerObject::setTEGLTFMaterialOverride(U8 te, LLGLTFMaterial* override_mat)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
|
|
@ -5871,22 +5909,13 @@ S32 LLViewerObject::setTEGLTFMaterialOverride(U8 te, LLGLTFMaterial* override_ma
|
|||
|
||||
if (retval)
|
||||
{
|
||||
retval = initRenderMaterial(te) | retval;
|
||||
if (override_mat)
|
||||
{
|
||||
LLFetchedGLTFMaterial* render_mat = new LLFetchedGLTFMaterial(*src_mat);
|
||||
render_mat->applyOverride(*override_mat);
|
||||
tep->setGLTFRenderMaterial(render_mat);
|
||||
retval = TEM_CHANGE_TEXTURE;
|
||||
|
||||
for (LLGLTFMaterial::local_tex_map_t::value_type &val : override_mat->mTrackingIdToLocalTexture)
|
||||
{
|
||||
LLLocalBitmapMgr::getInstance()->associateGLTFMaterial(val.first, override_mat);
|
||||
}
|
||||
|
||||
}
|
||||
else if (tep->setGLTFRenderMaterial(nullptr))
|
||||
{
|
||||
retval = TEM_CHANGE_TEXTURE;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -7824,26 +7853,16 @@ void LLViewerObject::setRenderMaterialID(S32 te_in, const LLUUID& id, bool updat
|
|||
// the overrides have not changed due to being only texture
|
||||
// transforms. Re-apply the overrides to the render material here,
|
||||
// if present.
|
||||
const LLGLTFMaterial* override_material = tep->getGLTFMaterialOverride();
|
||||
if (override_material)
|
||||
// Also, sometimes, the material has baked textures, which requires
|
||||
// a copy unique to this object.
|
||||
// Currently, we do not deduplicate render materials.
|
||||
new_material->onMaterialComplete([obj_id = getID(), te]()
|
||||
{
|
||||
new_material->onMaterialComplete([obj_id = getID(), te]()
|
||||
{
|
||||
LLViewerObject* obj = gObjectList.findObject(obj_id);
|
||||
if (!obj) { return; }
|
||||
LLTextureEntry* tep = obj->getTE(te);
|
||||
if (!tep) { return; }
|
||||
const LLGLTFMaterial* new_material = tep->getGLTFMaterial();
|
||||
if (!new_material) { return; }
|
||||
const LLGLTFMaterial* override_material = tep->getGLTFMaterialOverride();
|
||||
if (!override_material) { return; }
|
||||
LLGLTFMaterial* render_material = new LLFetchedGLTFMaterial();
|
||||
*render_material = *new_material;
|
||||
render_material->applyOverride(*override_material);
|
||||
tep->setGLTFRenderMaterial(render_material);
|
||||
});
|
||||
LLViewerObject* obj = gObjectList.findObject(obj_id);
|
||||
if (!obj) { return; }
|
||||
obj->initRenderMaterial(te);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// <FS> [FIRE-35138] Update the saved GLTF material since we got an update
|
||||
if (material_changed)
|
||||
|
|
|
|||
|
|
@ -413,6 +413,7 @@ public:
|
|||
/*virtual*/ S32 setTEGlow(const U8 te, const F32 glow);
|
||||
/*virtual*/ S32 setTEMaterialID(const U8 te, const LLMaterialID& pMaterialID);
|
||||
/*virtual*/ S32 setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams);
|
||||
S32 initRenderMaterial(const U8 te);
|
||||
virtual S32 setTEGLTFMaterialOverride(U8 te, LLGLTFMaterial* mat);
|
||||
|
||||
// Used by Materials update functions to properly kick off rebuilds
|
||||
|
|
|
|||
|
|
@ -2039,7 +2039,7 @@ LLViewerWindow::LLViewerWindow(const Params& p)
|
|||
p.ignore_pixel_depth,
|
||||
0,
|
||||
max_core_count,
|
||||
max_gl_version, //don't use window level anti-aliasing
|
||||
max_gl_version, //don't use window level anti-aliasing, windows only
|
||||
useLegacyCursors); // <FS:LO> Legacy cursor setting from main program
|
||||
|
||||
if (NULL == mWindow)
|
||||
|
|
|
|||
|
|
@ -291,9 +291,8 @@ void LLWebRTCVoiceClient::terminate()
|
|||
LL_INFOS("Voice") << "Terminating WebRTC" << LL_ENDL;
|
||||
|
||||
mVoiceEnabled = false;
|
||||
sShuttingDown = true; // so that coroutines won't post more work.
|
||||
llwebrtc::terminate();
|
||||
|
||||
sShuttingDown = true;
|
||||
}
|
||||
|
||||
//---------------------------------------------------
|
||||
|
|
@ -2669,6 +2668,11 @@ void LLVoiceWebRTCConnection::breakVoiceConnectionCoro(connectionPtr_t connectio
|
|||
void LLVoiceWebRTCSpatialConnection::requestVoiceConnection()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_VOICE;
|
||||
if (LLWebRTCVoiceClient::isShuttingDown())
|
||||
{
|
||||
mOutstandingRequests--;
|
||||
return;
|
||||
}
|
||||
|
||||
LLViewerRegion *regionp = LLWorld::instance().getRegionFromID(mRegionID);
|
||||
|
||||
|
|
@ -3276,6 +3280,12 @@ void LLVoiceWebRTCAdHocConnection::requestVoiceConnection()
|
|||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_VOICE;
|
||||
|
||||
if (LLWebRTCVoiceClient::isShuttingDown())
|
||||
{
|
||||
mOutstandingRequests--;
|
||||
return;
|
||||
}
|
||||
|
||||
LLViewerRegion *regionp = LLWorld::instance().getRegionFromID(mRegionID);
|
||||
|
||||
LL_DEBUGS("Voice") << "Requesting voice connection." << LL_ENDL;
|
||||
|
|
|
|||
|
|
@ -7088,7 +7088,7 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
|
|||
&& te->getShiny()
|
||||
&& can_be_shiny)
|
||||
{ //shiny
|
||||
if (tex && tex->getPrimaryFormat() == GL_ALPHA) // <FS:Beq/> [FIRE-34534] guard additional cases of tex == null
|
||||
if (tex && tex->getPrimaryFormat() == GL_ALPHA)
|
||||
{ //invisiprim+shiny
|
||||
if (!facep->getViewerObject()->isAttachment() && !facep->getViewerObject()->isRiggedMesh())
|
||||
{
|
||||
|
|
@ -7128,7 +7128,7 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
|
|||
}
|
||||
else
|
||||
{ //not alpha and not shiny
|
||||
if (!is_alpha && tex && tex->getPrimaryFormat() == GL_ALPHA) // <FS:Beq/> FIRE-34540 bugsplat crash caused by tex==nullptr. This stops the crash, but should we continue and leave the face unregistered instead of falling through?
|
||||
if (!is_alpha && tex && tex->getPrimaryFormat() == GL_ALPHA)
|
||||
{ //invisiprim
|
||||
if (!facep->getViewerObject()->isAttachment() && !facep->getViewerObject()->isRiggedMesh())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@
|
|||
</combo_box>
|
||||
<button label="İcmal..." name="physics_browse"/>
|
||||
</panel>
|
||||
<panel name="physics analysis">
|
||||
<panel name="physics analysis havok">
|
||||
<text name="method_label">Addım 2. Analiz</text>
|
||||
<text name="analysis_method_label">Üsul:</text>
|
||||
<text name="quality_label">Keyfiyyət:</text>
|
||||
|
|
|
|||
|
|
@ -191,7 +191,7 @@
|
|||
</combo_box>
|
||||
<button label="Browse..." name="physics_browse"/>
|
||||
</panel>
|
||||
<panel name="physics analysis">
|
||||
<panel name="physics analysis havok">
|
||||
<slider label="Smooth:" name="Smooth"/>
|
||||
<check_box label="Close Holes (slow)" name="Close Holes (Slow)"/>
|
||||
<button label="Analyze" name="Decompose"/>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
<floater name="Marketplace" title="Marktplatz">
|
||||
<layout_stack name="stack1">
|
||||
<layout_panel name="nav_controls">
|
||||
<button name="back" tool_tip="Rückwärts"/>
|
||||
<button name="forward" tool_tip="Vorwärts"/>
|
||||
<button name="stop" tool_tip="Navigation stoppen"/>
|
||||
<button name="reload" tool_tip="Seite neu laden"/>
|
||||
<combo_box name="address" tool_tip="URL hier eingeben"/>
|
||||
<icon name="media_secure_lock_flag" tool_tip="Sicheres Browsen"/>
|
||||
<button name="popexternal" tool_tip="Aktuelle URL im Desktop-Browser öffnen"/>
|
||||
</layout_panel>
|
||||
</layout_stack>
|
||||
</floater>
|
||||
|
|
@ -282,7 +282,7 @@
|
|||
</combo_box>
|
||||
<button label="Auswählen" name="physics_browse"/>
|
||||
</panel>
|
||||
<panel name="physics analysis">
|
||||
<panel name="physics analysis havok">
|
||||
<text name="method_label">
|
||||
Schritt 2: Zu Hüllen konvertieren (optional)
|
||||
</text>
|
||||
|
|
@ -299,6 +299,28 @@
|
|||
<button label="Analysieren" name="Decompose"/>
|
||||
<button label="Abbrechen" name="decompose_cancel"/>
|
||||
</panel>
|
||||
<panel name="physics analysis vhacd">
|
||||
<text name="method_label">
|
||||
Schritt 2: Zu Hüllen konvertieren (optional)
|
||||
</text>
|
||||
<text name="fill_mode_label">
|
||||
Füllmodus:
|
||||
</text>
|
||||
<text name="resolution_label">
|
||||
Aufösung:
|
||||
</text>
|
||||
<text name="hulls_per_mesh_label">
|
||||
Hüllen pro Mesh:
|
||||
</text>
|
||||
<text name="vertices_per_hull_label">
|
||||
Kanten pro Mesh:
|
||||
</text>
|
||||
<text name="tolerance_label">
|
||||
Fehlertoleranz:
|
||||
</text>
|
||||
<button label="Analysieren" name="Decompose"/>
|
||||
<button label="Abbrechen" name="decompose_cancel"/>
|
||||
</panel>
|
||||
<panel name="physics simplification">
|
||||
<text name="second_step_label">
|
||||
Schritt 3: Vereinfachen
|
||||
|
|
|
|||
|
|
@ -1,2 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
<floater name="floater_search" title="Suche"/>
|
||||
<floater name="floater_search" title="Suche">
|
||||
<layout_stack name="stack1">
|
||||
<layout_panel name="nav_controls">
|
||||
<button name="back" tool_tip="Rückwärts"/>
|
||||
<button name="forward" tool_tip="Vorwärts"/>
|
||||
<button name="stop" tool_tip="Navigation stoppen"/>
|
||||
<button name="reload" tool_tip="Seite neu laden"/>
|
||||
<combo_box name="address" tool_tip="URL hier eingeben"/>
|
||||
<icon name="media_secure_lock_flag" tool_tip="Sicheres Browsen"/>
|
||||
<button name="popexternal" tool_tip="Aktuelle URL im Desktop-Browser öffnen"/>
|
||||
</layout_panel>
|
||||
</layout_stack>
|
||||
</floater>
|
||||
|
|
|
|||
|
|
@ -881,6 +881,14 @@ Erwartet wurde [VALIDS]
|
|||
Sounddatei konnte nicht hochgeladen werden:
|
||||
[FILE]
|
||||
</notification>
|
||||
<notification name="ModelUploaderMissingPhysicsApple">
|
||||
Das Hochladen von Modellen wird derzeit auf Apple Silicon-Systemen nicht verfügbar, wird jedoch in einem späteren Release unterstützt.
|
||||
|
||||
Workaround: Im Finder auf die [APP_NAME] App rechtsklicken, dann "Info anzeigen" wählen und anschließend "Mit Rosette öffnen" aktivieren.
|
||||
</notification>
|
||||
<notification name="ModelUploaderMissingPhysics">
|
||||
Physik-Bibliothek ist nicht vorhanden - einzelne Funktionen für das Hochladen des Modells funktionieren möglicherweise nicht oder nicht korrekt.
|
||||
</notification>
|
||||
<notification name="SoundFileNotRIFF">
|
||||
Die Datei ist anscheinend keine RIFF WAVE-Datei:
|
||||
[FILE]
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -45,7 +45,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>
|
||||
|
|
@ -831,7 +831,7 @@
|
|||
help_topic="upload_model_physics"
|
||||
label="Physics"
|
||||
name="physics_panel">
|
||||
|
||||
|
||||
<!-- ==== STEP 1: Level of Detail ==== -->
|
||||
<view_border
|
||||
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_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"
|
||||
|
|
@ -917,9 +917,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"
|
||||
|
|
@ -1007,7 +1007,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="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 ==== -->
|
||||
<view_border
|
||||
bevel_style="none"
|
||||
|
|
@ -1026,7 +1150,8 @@
|
|||
left="18"
|
||||
name="physics simplification"
|
||||
top_pad="10"
|
||||
width="589">
|
||||
width="589"
|
||||
visible="false">
|
||||
<text
|
||||
text_color="White"
|
||||
follows="left|top"
|
||||
|
|
@ -1115,7 +1240,7 @@
|
|||
name="simplify_cancel"
|
||||
width="90"/>
|
||||
</panel>
|
||||
|
||||
|
||||
<!-- ==== Results ==== -->
|
||||
<view_border
|
||||
bevel_style="none"
|
||||
|
|
@ -1988,7 +2113,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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -2331,6 +2331,25 @@ Could not open uploaded sound file for reading:
|
|||
<tag>fail</tag>
|
||||
</notification>
|
||||
|
||||
<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 [APP_NAME] 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"
|
||||
|
|
|
|||
|
|
@ -178,7 +178,7 @@
|
|||
</combo_box>
|
||||
<button label="Buscar..." name="physics_browse"/>
|
||||
</panel>
|
||||
<panel name="physics analysis">
|
||||
<panel name="physics analysis havok">
|
||||
<text name="method_label">
|
||||
Paso 2: Analizar
|
||||
</text>
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@
|
|||
</combo_box>
|
||||
<button label="Parcourir..." name="physics_browse"/>
|
||||
</panel>
|
||||
<panel name="physics analysis">
|
||||
<panel name="physics analysis havok">
|
||||
<text name="method_label">
|
||||
Étape 2 : Analyser
|
||||
</text>
|
||||
|
|
|
|||
|
|
@ -256,7 +256,7 @@
|
|||
</combo_box>
|
||||
<button label="Scegli..." name="physics_browse"/>
|
||||
</panel>
|
||||
<panel name="physics analysis">
|
||||
<panel name="physics analysis havok">
|
||||
<text name="method_label">
|
||||
Passaggio 2: Analizza
|
||||
</text>
|
||||
|
|
|
|||
|
|
@ -335,7 +335,7 @@
|
|||
-->
|
||||
</panel>
|
||||
<!-- ==== STEP 2: Analyze ==== -->
|
||||
<panel name="physics analysis">
|
||||
<panel name="physics analysis havok">
|
||||
<text name="method_label">
|
||||
ステップ2:分析
|
||||
</text>
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@
|
|||
</combo_box>
|
||||
<button name="physics_browse" label="Przeglądaj"/>
|
||||
</panel>
|
||||
<panel name="physics analysis">
|
||||
<panel name="physics analysis havok">
|
||||
<text name="method_label">
|
||||
Krok 2: Konwersja na powłoki (opcjonalne)
|
||||
</text>
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@
|
|||
</combo_box>
|
||||
<button label="Procurar..." name="physics_browse"/>
|
||||
</panel>
|
||||
<panel name="physics analysis">
|
||||
<panel name="physics analysis havok">
|
||||
<text name="method_label">
|
||||
Etapa 2: Analisar
|
||||
</text>
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@
|
|||
</combo_box>
|
||||
<button label="Обзор..." name="physics_browse"/>
|
||||
</panel>
|
||||
<panel name="physics analysis">
|
||||
<panel name="physics analysis havok">
|
||||
<text name="method_label">2 этап. Анализ</text>
|
||||
<text name="analysis_method_label">Метод:</text>
|
||||
<text name="quality_label">Качество:</text>
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@
|
|||
</combo_box>
|
||||
<button label="Gözat..." name="physics_browse"/>
|
||||
</panel>
|
||||
<panel name="physics analysis">
|
||||
<panel name="physics analysis havok">
|
||||
<text name="method_label">
|
||||
2. Adım: Çözümle
|
||||
</text>
|
||||
|
|
|
|||
|
|
@ -341,7 +341,7 @@
|
|||
</combo_box>
|
||||
<button label="瀏覽…" name="physics_browse" />
|
||||
</panel>
|
||||
<panel name="physics analysis">
|
||||
<panel name="physics analysis havok">
|
||||
<text name="method_label">
|
||||
步驟 2:分析
|
||||
</text>
|
||||
|
|
|
|||
Loading…
Reference in New Issue