Merge branch 'DRTVWR-542-meshopt' into DRTVWR-546
commit
27e4e245d9
150
autobuild.xml
150
autobuild.xml
|
|
@ -1047,100 +1047,6 @@
|
|||
<key>version</key>
|
||||
<string>0.0.0</string>
|
||||
</map>
|
||||
<key>glod</key>
|
||||
<map>
|
||||
<key>copyright</key>
|
||||
<string>Copyright 2003 Jonathan Cohen, Nat Duca, David Luebke, Brenden Schubert - Johns Hopkins University and University of Virginia</string>
|
||||
<key>license</key>
|
||||
<string>GLOD Open-Source License Version 1.0</string>
|
||||
<key>license_file</key>
|
||||
<string>LICENSES/GLOD.txt</string>
|
||||
<key>name</key>
|
||||
<string>glod</string>
|
||||
<key>platforms</key>
|
||||
<map>
|
||||
<key>darwin</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>71e678d70e276fc42a56926fc28a7abd</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>md5</string>
|
||||
<key>url</key>
|
||||
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/glod_3p-update-glod/rev/296895/arch/Darwin/installer/glod-1.0pre4.296895-darwin-296895.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>darwin</string>
|
||||
</map>
|
||||
<key>darwin64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>a9eaa005ff9d387f946283fbcb69b3c8</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/76353/727324/glod-1.0pre3.555522-darwin64-555522.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>darwin64</string>
|
||||
</map>
|
||||
<key>linux</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>58113bcbbacbaeb2d278f745867ae6f0</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>md5</string>
|
||||
<key>url</key>
|
||||
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-glod/rev/314201/arch/Linux/installer/glod-1.0pre4.314201-linux-314201.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>linux</string>
|
||||
</map>
|
||||
<key>linux64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>9aef5cd576ace19568da01d9bc3db29c</string>
|
||||
<key>url</key>
|
||||
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/1625/3628/glod-1.0pre3.501614-linux64-501614.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>linux64</string>
|
||||
</map>
|
||||
<key>windows</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>e36c95b0d0fbaa3ff3392facaf5de447</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>md5</string>
|
||||
<key>url</key>
|
||||
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55008/511893/glod-1.0pre3.538980-windows-538980.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows</string>
|
||||
</map>
|
||||
<key>windows64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>6302ee1903ab419e76565d9eb6acd274</string>
|
||||
<key>url</key>
|
||||
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55004/511885/glod-1.0pre3.538980-windows64-538980.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows64</string>
|
||||
</map>
|
||||
</map>
|
||||
<key>version</key>
|
||||
<string>1.0pre3.555522</string>
|
||||
</map>
|
||||
<key>googlemock</key>
|
||||
<map>
|
||||
<key>copyright</key>
|
||||
|
|
@ -2304,6 +2210,62 @@
|
|||
<key>version</key>
|
||||
<string>7.11.1.297294</string>
|
||||
</map>
|
||||
<key>meshoptimizer</key>
|
||||
<map>
|
||||
<key>canonical_repo</key>
|
||||
<string>https://bitbucket.org/lindenlab/3p-meshoptimizer</string>
|
||||
<key>copyright</key>
|
||||
<string>Copyright (c) 2016-2021 Arseny Kapoulkine</string>
|
||||
<key>description</key>
|
||||
<string>Meshoptimizer. Mesh optimization library.</string>
|
||||
<key>license</key>
|
||||
<string>meshoptimizer</string>
|
||||
<key>license_file</key>
|
||||
<string>LICENSES/meshoptimizer.txt</string>
|
||||
<key>name</key>
|
||||
<string>meshoptimizer</string>
|
||||
<key>platforms</key>
|
||||
<map>
|
||||
<key>darwin64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>30bc37db57bbd87c4b5f62634964242a</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/84218/784918/meshoptimizer-0.16.561408-darwin64-561408.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>darwin64</string>
|
||||
</map>
|
||||
<key>windows</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>ca3684bcf0447746cd2844e94f6d1fc7</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/84219/784924/meshoptimizer-0.16.561408-windows-561408.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows</string>
|
||||
</map>
|
||||
<key>windows64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>aef28c089d20f69d13c9c3e113fb3895</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/84220/784931/meshoptimizer-0.16.561408-windows64-561408.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows64</string>
|
||||
</map>
|
||||
</map>
|
||||
<key>version</key>
|
||||
<string>0.16.561408</string>
|
||||
</map>
|
||||
<key>nghttp2</key>
|
||||
<map>
|
||||
<key>copyright</key>
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ add_subdirectory(${LIBS_OPEN_PREFIX}llkdu)
|
|||
add_subdirectory(${LIBS_OPEN_PREFIX}llimagej2coj)
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}llinventory)
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}llmath)
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}llmeshoptimizer)
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}llmessage)
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}llprimitive)
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}llrender)
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ set(cmake_SOURCE_FILES
|
|||
FreeType.cmake
|
||||
GLEXT.cmake
|
||||
GLH.cmake
|
||||
GLOD.cmake
|
||||
## GStreamer010Plugin.cmake
|
||||
GoogleMock.cmake
|
||||
Havok.cmake
|
||||
|
|
@ -59,6 +58,7 @@ set(cmake_SOURCE_FILES
|
|||
LLKDU.cmake
|
||||
LLLogin.cmake
|
||||
LLMath.cmake
|
||||
LLMeshOptimizer.cmake
|
||||
LLMessage.cmake
|
||||
LLPhysicsExtensions.cmake
|
||||
LLPlugin.cmake
|
||||
|
|
@ -72,6 +72,7 @@ set(cmake_SOURCE_FILES
|
|||
LLXML.cmake
|
||||
Linking.cmake
|
||||
MediaPluginBase.cmake
|
||||
MESHOPTIMIZER.cmake
|
||||
NDOF.cmake
|
||||
OPENAL.cmake
|
||||
OpenGL.cmake
|
||||
|
|
|
|||
|
|
@ -57,7 +57,6 @@ if(WINDOWS)
|
|||
libaprutil-1.dll
|
||||
libapriconv-1.dll
|
||||
nghttp2.dll
|
||||
glod.dll
|
||||
libhunspell.dll
|
||||
uriparser.dll
|
||||
)
|
||||
|
|
@ -168,7 +167,6 @@ elseif(DARWIN)
|
|||
libaprutil-1.0.dylib
|
||||
libaprutil-1.dylib
|
||||
${EXPAT_COPY}
|
||||
libGLOD.dylib
|
||||
libhunspell-1.3.0.dylib
|
||||
libndofdev.dylib
|
||||
libnghttp2.dylib
|
||||
|
|
@ -217,7 +215,6 @@ elseif(LINUX)
|
|||
${EXPAT_COPY}
|
||||
libfreetype.so.6.6.2
|
||||
libfreetype.so.6
|
||||
libGLOD.so
|
||||
libgmodule-2.0.so
|
||||
libgobject-2.0.so
|
||||
libhunspell-1.3.so.0.0.0
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
# -*- cmake -*-
|
||||
include(Prebuilt)
|
||||
|
||||
if (NOT USESYSTEMLIBS)
|
||||
use_prebuilt_binary(glod)
|
||||
endif (NOT USESYSTEMLIBS)
|
||||
|
||||
set(GLOD_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include)
|
||||
set(GLOD_LIBRARIES GLOD)
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
# -*- cmake -*-
|
||||
|
||||
set(LLMESHOPTIMIZER_INCLUDE_DIRS
|
||||
${LIBS_OPEN_DIR}/llmeshoptimizer
|
||||
)
|
||||
|
||||
set(LLMESHOPTIMIZER_LIBRARIES llmeshoptimizer)
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
# -*- cmake -*-
|
||||
|
||||
include(Linking)
|
||||
include(Prebuilt)
|
||||
|
||||
use_prebuilt_binary(meshoptimizer)
|
||||
|
||||
if (WINDOWS)
|
||||
set(MESHOPTIMIZER_LIBRARIES meshoptimizer.lib)
|
||||
elseif (LINUX)
|
||||
set(MESHOPTIMIZER_LIBRARIES meshoptimizer.o)
|
||||
elseif (DARWIN)
|
||||
set(MESHOPTIMIZER_LIBRARIES libmeshoptimizer.a)
|
||||
endif (WINDOWS)
|
||||
|
||||
set(MESHOPTIMIZER_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/meshoptimizer)
|
||||
|
|
@ -6348,9 +6348,9 @@ void LLVolumeFace::resizeVertices(S32 num_verts)
|
|||
if (num_verts)
|
||||
{
|
||||
//pad texture coordinate block end to allow for QWORD reads
|
||||
S32 size = ((num_verts*sizeof(LLVector2)) + 0xF) & ~0xF;
|
||||
S32 tc_size = ((num_verts*sizeof(LLVector2)) + 0xF) & ~0xF;
|
||||
|
||||
mPositions = (LLVector4a*) ll_aligned_malloc<64>(sizeof(LLVector4a)*2*num_verts+size);
|
||||
mPositions = (LLVector4a*) ll_aligned_malloc<64>(sizeof(LLVector4a)*2*num_verts+tc_size);
|
||||
mNormals = mPositions+num_verts;
|
||||
mTexCoords = (LLVector2*) (mNormals+num_verts);
|
||||
|
||||
|
|
|
|||
|
|
@ -936,17 +936,23 @@ public:
|
|||
LLVector4a* mCenter;
|
||||
LLVector2 mTexCoordExtents[2]; //minimum and maximum of texture coordinates of the face.
|
||||
|
||||
S32 mNumVertices;
|
||||
S32 mNumVertices; // num vertices == num normals == num texcoords
|
||||
S32 mNumAllocatedVertices;
|
||||
S32 mNumIndices;
|
||||
|
||||
LLVector4a* mPositions;
|
||||
LLVector4a* mNormals;
|
||||
LLVector4a* mPositions; // Contains vertices, nortmals and texcoords
|
||||
LLVector4a* mNormals; // pointer into mPositions
|
||||
LLVector4a* mTangents;
|
||||
LLVector2* mTexCoords;
|
||||
LLVector2* mTexCoords; // pointer into mPositions
|
||||
|
||||
// mIndices contains mNumIndices amount of elements.
|
||||
// It contains triangles, each 3 indices describe one triangle.
|
||||
// If mIndices contains {0, 2, 3, 1, 2, 4}, it means there
|
||||
// are two triangles {0, 2, 3} and {1, 2, 4} with values being
|
||||
// indexes for mPositions/mNormals/mTexCoords
|
||||
U16* mIndices;
|
||||
|
||||
//vertex buffer filled in by LLFace to cache this volume face geometry in vram
|
||||
// vertex buffer filled in by LLFace to cache this volume face geometry in vram
|
||||
// (declared as a LLPointer to LLRefCount to avoid dependency on LLVertexBuffer)
|
||||
mutable LLPointer<LLRefCount> mVertexBuffer;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
# -*- cmake -*-
|
||||
|
||||
project(llmeshoptimizer)
|
||||
|
||||
include(MESHOPTIMIZER)
|
||||
|
||||
include(00-Common)
|
||||
include(LLCommon)
|
||||
include(LLMath)
|
||||
|
||||
include_directories(
|
||||
${LLCOMMON_INCLUDE_DIRS}
|
||||
${LLMATH_INCLUDE_DIRS}
|
||||
${LLMESHOPTIMIZER_INCLUDE_DIR}
|
||||
${MESHOPTIMIZER_INCLUDE_DIRS}
|
||||
${LIBS_PREBUILT_DIR}/include #access to boost headers, needed for LLError
|
||||
)
|
||||
|
||||
set(llmeshoptimizer_SOURCE_FILES
|
||||
llmeshoptimizer.cpp
|
||||
)
|
||||
|
||||
set(llmeshoptimizer_HEADER_FILES
|
||||
CMakeLists.txt
|
||||
|
||||
llmeshoptimizer.h
|
||||
)
|
||||
|
||||
set_source_files_properties(${llmeshoptimizer_HEADER_FILES}
|
||||
PROPERTIES HEADER_FILE_ONLY TRUE)
|
||||
|
||||
list(APPEND llmeshoptimizer_SOURCE_FILES ${llmeshoptimizer_HEADER_FILES})
|
||||
|
||||
#if (USE_MESHOPT)
|
||||
add_library (llmeshoptimizer ${llmeshoptimizer_SOURCE_FILES})
|
||||
|
||||
target_link_libraries(llmeshoptimizer
|
||||
${LLCOMMON_LIBRARIES}
|
||||
${LLMATH_LIBRARIES}
|
||||
${MESHOPTIMIZER_LIBRARIES})
|
||||
|
||||
# Add tests
|
||||
|
||||
#endif (USE_MESHOPT)
|
||||
|
|
@ -0,0 +1,142 @@
|
|||
/**
|
||||
* @file llmeshoptimizer.cpp
|
||||
* @brief Wrapper around meshoptimizer
|
||||
*
|
||||
* $LicenseInfo:firstyear=2021&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2021, 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 "llmeshoptimizer.h"
|
||||
|
||||
#include "meshoptimizer.h"
|
||||
|
||||
LLMeshOptimizer::LLMeshOptimizer()
|
||||
{
|
||||
// Todo: Looks like for memory management, we can add allocator and deallocator callbacks
|
||||
// Should be one time
|
||||
// meshopt_setAllocator(allocate, deallocate);
|
||||
}
|
||||
|
||||
LLMeshOptimizer::~LLMeshOptimizer()
|
||||
{
|
||||
}
|
||||
|
||||
//static
|
||||
void LLMeshOptimizer::generateShadowIndexBuffer(U16 *destination,
|
||||
const U16 *indices,
|
||||
U64 index_count,
|
||||
const LLVector4a *vertex_positions,
|
||||
U64 vertex_count,
|
||||
U64 vertex_positions_stride
|
||||
)
|
||||
{
|
||||
meshopt_generateShadowIndexBuffer<unsigned short>(destination,
|
||||
indices,
|
||||
index_count,
|
||||
(const float*)vertex_positions, // verify that it is correct to convert to float
|
||||
vertex_count,
|
||||
sizeof(LLVector4a),
|
||||
vertex_positions_stride
|
||||
);
|
||||
}
|
||||
|
||||
//static
|
||||
U64 LLMeshOptimizer::simplifyU32(U32 *destination,
|
||||
const U32 *indices,
|
||||
U64 index_count,
|
||||
const LLVector4a *vertex_positions,
|
||||
U64 vertex_count,
|
||||
U64 vertex_positions_stride,
|
||||
U64 target_index_count,
|
||||
F32 target_error,
|
||||
bool sloppy,
|
||||
F32* result_error
|
||||
)
|
||||
{
|
||||
if (sloppy)
|
||||
{
|
||||
return meshopt_simplifySloppy<unsigned int>(destination,
|
||||
indices,
|
||||
index_count,
|
||||
(const float*)vertex_positions,
|
||||
vertex_count,
|
||||
vertex_positions_stride,
|
||||
target_index_count,
|
||||
target_error,
|
||||
result_error
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
return meshopt_simplify<unsigned int>(destination,
|
||||
indices,
|
||||
index_count,
|
||||
(const float*)vertex_positions,
|
||||
vertex_count,
|
||||
vertex_positions_stride,
|
||||
target_index_count,
|
||||
target_error,
|
||||
result_error
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
U64 LLMeshOptimizer::simplify(U16 *destination,
|
||||
const U16 *indices,
|
||||
U64 index_count,
|
||||
const LLVector4a *vertex_positions,
|
||||
U64 vertex_count,
|
||||
U64 vertex_positions_stride,
|
||||
U64 target_index_count,
|
||||
F32 target_error,
|
||||
bool sloppy,
|
||||
F32* result_error
|
||||
)
|
||||
{
|
||||
if (sloppy)
|
||||
{
|
||||
return meshopt_simplifySloppy<unsigned short>(destination,
|
||||
indices,
|
||||
index_count,
|
||||
(const float*)vertex_positions,
|
||||
vertex_count,
|
||||
vertex_positions_stride,
|
||||
target_index_count,
|
||||
target_error,
|
||||
result_error
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
return meshopt_simplify<unsigned short>(destination,
|
||||
indices,
|
||||
index_count,
|
||||
(const float*)vertex_positions,
|
||||
vertex_count,
|
||||
vertex_positions_stride,
|
||||
target_index_count,
|
||||
target_error,
|
||||
result_error
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
/**
|
||||
* @file llmeshoptimizer.h
|
||||
* @brief Wrapper around meshoptimizer
|
||||
*
|
||||
* $LicenseInfo:firstyear=2021&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2021, 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 LLMESHOPTIMIZER_H
|
||||
#define LLMESHOPTIMIZER_H
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llmath.h"
|
||||
|
||||
class LLMeshOptimizer
|
||||
{
|
||||
public:
|
||||
LLMeshOptimizer();
|
||||
~LLMeshOptimizer();
|
||||
|
||||
static void generateShadowIndexBuffer(
|
||||
U16 *destination,
|
||||
const U16 *indices,
|
||||
U64 index_count,
|
||||
const LLVector4a *vertex_positions,
|
||||
U64 vertex_count,
|
||||
U64 vertex_positions_stride);
|
||||
|
||||
// returns amount of indices in destiantion
|
||||
// sloppy engages a variant of a mechanizm that does not respect topology as much
|
||||
// but is much more efective for simpler models
|
||||
// result_error returns how far from original the model is in % if not NULL
|
||||
// Works with U32 indices (LLFace uses U16 indices)
|
||||
static U64 simplifyU32(
|
||||
U32 *destination,
|
||||
const U32 *indices,
|
||||
U64 index_count,
|
||||
const LLVector4a *vertex_positions,
|
||||
U64 vertex_count,
|
||||
U64 vertex_positions_stride,
|
||||
U64 target_index_count,
|
||||
F32 target_error,
|
||||
bool sloppy,
|
||||
F32* result_error);
|
||||
|
||||
// Returns amount of indices in destiantion
|
||||
// sloppy engages a variant of a mechanizm that does not respect topology as much
|
||||
// but is much better for simpler models
|
||||
// result_error returns how far from original the model is in % if not NULL
|
||||
// Meant for U16 indices (LLFace uses U16 indices)
|
||||
static U64 simplify(
|
||||
U16 *destination,
|
||||
const U16 *indices,
|
||||
U64 index_count,
|
||||
const LLVector4a *vertex_positions,
|
||||
U64 vertex_count,
|
||||
U64 vertex_positions_stride,
|
||||
U64 target_index_count,
|
||||
F32 target_error,
|
||||
bool sloppy,
|
||||
F32* result_error);
|
||||
private:
|
||||
};
|
||||
|
||||
#endif //LLMESHOPTIMIZER_H
|
||||
|
|
@ -149,7 +149,11 @@ bool get_dom_sources(const domInputLocalOffset_Array& inputs, S32& pos_offset, S
|
|||
return true;
|
||||
}
|
||||
|
||||
LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& face_list, std::vector<std::string>& materials, domTrianglesRef& tri)
|
||||
LLModel::EModelStatus load_face_from_dom_triangles(
|
||||
std::vector<LLVolumeFace>& face_list,
|
||||
std::vector<std::string>& materials,
|
||||
domTrianglesRef& tri,
|
||||
LLSD& log_msg)
|
||||
{
|
||||
LLVolumeFace face;
|
||||
std::vector<LLVolumeFace::VertexData> verts;
|
||||
|
|
@ -169,12 +173,18 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa
|
|||
|
||||
if ( !get_dom_sources(inputs, pos_offset, tc_offset, norm_offset, idx_stride, pos_source, tc_source, norm_source))
|
||||
{
|
||||
LLSD args;
|
||||
args["Message"] = "ParsingErrorBadElement";
|
||||
log_msg.append(args);
|
||||
return LLModel::BAD_ELEMENT;
|
||||
}
|
||||
|
||||
if (!pos_source || !pos_source->getFloat_array())
|
||||
{
|
||||
LL_WARNS() << "Unable to process mesh without position data; invalid model; invalid model." << LL_ENDL;
|
||||
LLSD args;
|
||||
args["Message"] = "ParsingErrorPositionInvalidModel";
|
||||
log_msg.append(args);
|
||||
return LLModel::BAD_ELEMENT;
|
||||
}
|
||||
|
||||
|
|
@ -343,7 +353,11 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa
|
|||
return LLModel::NO_ERRORS ;
|
||||
}
|
||||
|
||||
LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& face_list, std::vector<std::string>& materials, domPolylistRef& poly, LLSD& log_msg)
|
||||
LLModel::EModelStatus load_face_from_dom_polylist(
|
||||
std::vector<LLVolumeFace>& face_list,
|
||||
std::vector<std::string>& materials,
|
||||
domPolylistRef& poly,
|
||||
LLSD& log_msg)
|
||||
{
|
||||
domPRef p = poly->getP();
|
||||
domListOfUInts& idx = p->getValue();
|
||||
|
|
@ -370,6 +384,10 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac
|
|||
|
||||
if (!get_dom_sources(inputs, pos_offset, tc_offset, norm_offset, idx_stride, pos_source, tc_source, norm_source))
|
||||
{
|
||||
LL_WARNS() << "Bad element." << LL_ENDL;
|
||||
LLSD args;
|
||||
args["Message"] = "ParsingErrorBadElement";
|
||||
log_msg.append(args);
|
||||
return LLModel::BAD_ELEMENT;
|
||||
}
|
||||
|
||||
|
|
@ -421,6 +439,9 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac
|
|||
if (!cv.getPosition().isFinite3())
|
||||
{
|
||||
LL_WARNS() << "Found NaN while loading position data from DAE-Model, invalid model." << LL_ENDL;
|
||||
LLSD args;
|
||||
args["Message"] = "PositionNaN";
|
||||
log_msg.append(args);
|
||||
return LLModel::BAD_ELEMENT;
|
||||
}
|
||||
}
|
||||
|
|
@ -453,6 +474,10 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac
|
|||
if (!cv.getNormal().isFinite3())
|
||||
{
|
||||
LL_WARNS() << "Found NaN while loading normals from DAE-Model, invalid model." << LL_ENDL;
|
||||
LLSD args;
|
||||
args["Message"] = "NormalsNaN";
|
||||
log_msg.append(args);
|
||||
|
||||
return LLModel::BAD_ELEMENT;
|
||||
}
|
||||
}
|
||||
|
|
@ -770,6 +795,9 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac
|
|||
}
|
||||
}
|
||||
|
||||
// Viewer can only fit U16 vertices, shouldn't we do some checks here and return overflow if result has more?
|
||||
llassert(vert_idx.size() < U16_MAX);
|
||||
|
||||
//build vertex array from map
|
||||
std::vector<LLVolumeFace::VertexData> new_verts;
|
||||
new_verts.resize(vert_idx.size());
|
||||
|
|
@ -787,7 +815,12 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac
|
|||
for (U32 i = 0; i < verts.size(); ++i)
|
||||
{
|
||||
indices[i] = vert_idx[verts[i]];
|
||||
llassert(!i || (indices[i-1] != indices[i]));
|
||||
if (i % 3 != 0) // assumes GL_TRIANGLES, compare 0-1, 1-2, 3-4, 4-5 but not 2-3 or 5-6
|
||||
{
|
||||
// A faulty degenerate triangle detection (triangle with 0 area),
|
||||
// probably should be a warning and not an assert
|
||||
llassert(!i || (indices[i-1] != indices[i]));
|
||||
}
|
||||
}
|
||||
|
||||
// DEBUG just build an expanded triangle list
|
||||
|
|
@ -907,6 +940,9 @@ bool LLDAELoader::OpenFile(const std::string& filename)
|
|||
if (!dom)
|
||||
{
|
||||
LL_INFOS() <<" Error with dae - traditionally indicates a corrupt file."<<LL_ENDL;
|
||||
LLSD args;
|
||||
args["Message"] = "ParsingErrorCorrupt";
|
||||
mWarningsArray.append(args);
|
||||
setLoadState( ERROR_PARSING );
|
||||
return false;
|
||||
}
|
||||
|
|
@ -934,6 +970,9 @@ bool LLDAELoader::OpenFile(const std::string& filename)
|
|||
if (!doc)
|
||||
{
|
||||
LL_WARNS() << "can't find internal doc" << LL_ENDL;
|
||||
LLSD args;
|
||||
args["Message"] = "ParsingErrorNoDoc";
|
||||
mWarningsArray.append(args);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -941,6 +980,9 @@ bool LLDAELoader::OpenFile(const std::string& filename)
|
|||
if (!root)
|
||||
{
|
||||
LL_WARNS() << "document has no root" << LL_ENDL;
|
||||
LLSD args;
|
||||
args["Message"] = "ParsingErrorNoRoot";
|
||||
mWarningsArray.append(args);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -956,6 +998,9 @@ bool LLDAELoader::OpenFile(const std::string& filename)
|
|||
if (!result)
|
||||
{
|
||||
LL_INFOS() << "Could not verify controller" << LL_ENDL;
|
||||
LLSD args;
|
||||
args["Message"] = "ParsingErrorBadElement";
|
||||
mWarningsArray.append(args);
|
||||
setLoadState( ERROR_PARSING );
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1089,6 +1134,9 @@ bool LLDAELoader::OpenFile(const std::string& filename)
|
|||
if (!scene)
|
||||
{
|
||||
LL_WARNS() << "document has no visual_scene" << LL_ENDL;
|
||||
LLSD args;
|
||||
args["Message"] = "ParsingErrorNoScene";
|
||||
mWarningsArray.append(args);
|
||||
setLoadState( ERROR_PARSING );
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1097,11 +1145,14 @@ bool LLDAELoader::OpenFile(const std::string& filename)
|
|||
|
||||
bool badElement = false;
|
||||
|
||||
processElement( scene, badElement, &dae );
|
||||
processElement( scene, badElement, &dae);
|
||||
|
||||
if ( badElement )
|
||||
{
|
||||
LL_INFOS()<<"Scene could not be parsed"<<LL_ENDL;
|
||||
LLSD args;
|
||||
args["Message"] = "ParsingErrorCantParseScene";
|
||||
mWarningsArray.append(args);
|
||||
setLoadState( ERROR_PARSING );
|
||||
}
|
||||
|
||||
|
|
@ -1942,7 +1993,7 @@ daeElement* LLDAELoader::getChildFromElement( daeElement* pElement, std::string
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void LLDAELoader::processElement( daeElement* element, bool& badElement, DAE* dae )
|
||||
void LLDAELoader::processElement( daeElement* element, bool& badElement, DAE* dae)
|
||||
{
|
||||
LLMatrix4 saved_transform;
|
||||
bool pushed_mat = false;
|
||||
|
|
@ -2036,6 +2087,11 @@ void LLDAELoader::processElement( daeElement* element, bool& badElement, DAE* da
|
|||
if (mTransform.determinant() < 0)
|
||||
{ //negative scales are not supported
|
||||
LL_INFOS() << "Negative scale detected, unsupported transform. domInstance_geometry: " << getElementLabel(instance_geo) << LL_ENDL;
|
||||
LLSD args;
|
||||
args["Message"] = "NegativeScaleTrans";
|
||||
args["LABEL"] = getElementLabel(instance_geo);
|
||||
mWarningsArray.append(args);
|
||||
|
||||
badElement = true;
|
||||
}
|
||||
|
||||
|
|
@ -2059,6 +2115,10 @@ void LLDAELoader::processElement( daeElement* element, bool& badElement, DAE* da
|
|||
if (transformation.determinant() < 0)
|
||||
{ //negative scales are not supported
|
||||
LL_INFOS() << "Negative scale detected, unsupported post-normalization transform. domInstance_geometry: " << getElementLabel(instance_geo) << LL_ENDL;
|
||||
LLSD args;
|
||||
args["Message"] = "NegativeScaleNormTrans";
|
||||
args["LABEL"] = getElementLabel(instance_geo);
|
||||
mWarningsArray.append(args);
|
||||
badElement = true;
|
||||
}
|
||||
|
||||
|
|
@ -2100,6 +2160,9 @@ void LLDAELoader::processElement( daeElement* element, bool& badElement, DAE* da
|
|||
else
|
||||
{
|
||||
LL_INFOS()<<"Unable to resolve geometry URL."<<LL_ENDL;
|
||||
LLSD args;
|
||||
args["Message"] = "CantResolveGeometryUrl";
|
||||
mWarningsArray.append(args);
|
||||
badElement = true;
|
||||
}
|
||||
|
||||
|
|
@ -2390,7 +2453,7 @@ bool LLDAELoader::addVolumeFacesFromDomMesh(LLModel* pModel,domMesh* mesh, LLSD&
|
|||
{
|
||||
domTrianglesRef& tri = tris.get(i);
|
||||
|
||||
status = load_face_from_dom_triangles(pModel->getVolumeFaces(), pModel->getMaterialList(), tri);
|
||||
status = load_face_from_dom_triangles(pModel->getVolumeFaces(), pModel->getMaterialList(), tri, log_msg);
|
||||
pModel->mStatus = status;
|
||||
if(status != LLModel::NO_ERRORS)
|
||||
{
|
||||
|
|
@ -2417,6 +2480,7 @@ bool LLDAELoader::addVolumeFacesFromDomMesh(LLModel* pModel,domMesh* mesh, LLSD&
|
|||
for (U32 i = 0; i < polygons.getCount(); ++i)
|
||||
{
|
||||
domPolygonsRef& poly = polygons.get(i);
|
||||
|
||||
status = load_face_from_dom_polygons(pModel->getVolumeFaces(), pModel->getMaterialList(), poly);
|
||||
|
||||
if(status != LLModel::NO_ERRORS)
|
||||
|
|
|
|||
|
|
@ -291,6 +291,8 @@ public:
|
|||
|
||||
EModelStatus mStatus ;
|
||||
|
||||
// A model/object can only have 8 faces, spillover faces will
|
||||
// be moved to new model/object and assigned a submodel id.
|
||||
int mSubmodelID;
|
||||
} LL_ALIGN_POSTFIX(16);
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ include(DBusGlib)
|
|||
include(DragDrop)
|
||||
include(EXPAT)
|
||||
include(FMODSTUDIO)
|
||||
include(GLOD)
|
||||
include(Hunspell)
|
||||
include(JsonCpp)
|
||||
include(LLAppearance)
|
||||
|
|
@ -31,6 +30,7 @@ include(LLInventory)
|
|||
include(LLKDU)
|
||||
include(LLLogin)
|
||||
include(LLMath)
|
||||
include(LLMeshOptimizer)
|
||||
include(LLMessage)
|
||||
include(LLPhysicsExtensions)
|
||||
include(LLPlugin)
|
||||
|
|
@ -68,7 +68,6 @@ endif(FMODSTUDIO)
|
|||
include_directories(
|
||||
${DBUSGLIB_INCLUDE_DIRS}
|
||||
${JSONCPP_INCLUDE_DIR}
|
||||
${GLOD_INCLUDE_DIR}
|
||||
${LLAUDIO_INCLUDE_DIRS}
|
||||
${LLCHARACTER_INCLUDE_DIRS}
|
||||
${LLCOMMON_INCLUDE_DIRS}
|
||||
|
|
@ -78,6 +77,7 @@ include_directories(
|
|||
${LLKDU_INCLUDE_DIRS}
|
||||
${LLINVENTORY_INCLUDE_DIRS}
|
||||
${LLMATH_INCLUDE_DIRS}
|
||||
${LLMESHOPTIMIZER_INCLUDE_DIRS}
|
||||
${LLMESSAGE_INCLUDE_DIRS}
|
||||
${LLPLUGIN_INCLUDE_DIRS}
|
||||
${LLPRIMITIVE_INCLUDE_DIRS}
|
||||
|
|
@ -1813,9 +1813,6 @@ if (WINDOWS)
|
|||
${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/libapr-1.dll
|
||||
${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/libaprutil-1.dll
|
||||
${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/libapriconv-1.dll
|
||||
${SHARED_LIB_STAGING_DIR}/Release/glod.dll
|
||||
${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/glod.dll
|
||||
${SHARED_LIB_STAGING_DIR}/Debug/glod.dll
|
||||
${SHARED_LIB_STAGING_DIR}/Release/libcollada14dom22.dll
|
||||
${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/libcollada14dom22.dll
|
||||
${SHARED_LIB_STAGING_DIR}/Debug/libcollada14dom22-d.dll
|
||||
|
|
@ -2027,6 +2024,7 @@ target_link_libraries(${VIEWER_BINARY_NAME}
|
|||
${LLCHARACTER_LIBRARIES}
|
||||
${LLIMAGE_LIBRARIES}
|
||||
${LLINVENTORY_LIBRARIES}
|
||||
${LLMESHOPTIMIZER_LIBRARIES}
|
||||
${LLMESSAGE_LIBRARIES}
|
||||
${LLPLUGIN_LIBRARIES}
|
||||
${LLPRIMITIVE_LIBRARIES}
|
||||
|
|
@ -2050,7 +2048,6 @@ target_link_libraries(${VIEWER_BINARY_NAME}
|
|||
${DBUSGLIB_LIBRARIES}
|
||||
${OPENGL_LIBRARIES}
|
||||
${FMODWRAPPER_LIBRARY} # must come after LLAudio
|
||||
${GLOD_LIBRARIES}
|
||||
${OPENGL_LIBRARIES}
|
||||
${JSONCPP_LIBRARIES}
|
||||
${SDL_LIBRARY}
|
||||
|
|
|
|||
|
|
@ -693,3 +693,29 @@ From Vivox:
|
|||
Attn: customer support
|
||||
40 Speen Street Suite 402
|
||||
Framingham, MA 01701
|
||||
|
||||
|
||||
=============
|
||||
meshoptimizer
|
||||
=============
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2016-2021 Arseny Kapoulkine
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
|
|
|||
|
|
@ -770,71 +770,29 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
=============
|
||||
GLOD license
|
||||
meshoptimizer
|
||||
=============
|
||||
The GLOD Open-Source License Version 1.0 June 16, 2004
|
||||
MIT License
|
||||
|
||||
Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns
|
||||
Hopkins University and David Luebke, Brenden Schubert, University of
|
||||
Virginia. All rights reserved.
|
||||
Copyright (c) 2016-2021 Arseny Kapoulkine
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, is permitted provided that the following conditions are
|
||||
met:
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer and
|
||||
request.
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer and
|
||||
request in the documentation and/or other materials provided with
|
||||
the distribution.
|
||||
|
||||
3. The name "GLOD" must not be used to endorse or promote products
|
||||
derived from this software without prior written permission.
|
||||
|
||||
4. Redistributions of any modified version of this source, whether in
|
||||
source or binary form , must include a form of the following
|
||||
acknowledgment: "This product is derived from the GLOD library,
|
||||
which is available from http://www.cs.jhu.edu/~graphics/GLOD."
|
||||
|
||||
5. Redistributions of any modified version of this source in binary
|
||||
form must provide, free of charge, access to the modified version
|
||||
of the code.
|
||||
|
||||
6. This license shall be governed by and construed and enforced in
|
||||
accordance with the laws of the State of Maryland, without
|
||||
reference to its conflicts of law provisions. The exclusive
|
||||
jurisdiction and venue for all legal actions relating to this
|
||||
license shall be in courts of competent subject matter jurisdiction
|
||||
located in the State of Maryland.
|
||||
|
||||
TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, GLOD IS PROVIDED
|
||||
UNDER THIS LICENSE ON AN AS IS BASIS, WITHOUT WARRANTY OF ANY KIND,
|
||||
EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
|
||||
THAT GLOD IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR
|
||||
PURPOSE OR NON-INFRINGING. ALL WARRANTIES ARE DISCLAIMED AND THE
|
||||
ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE CODE IS WITH
|
||||
YOU. SHOULD ANY CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE
|
||||
COPYRIGHT HOLDER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY
|
||||
NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY
|
||||
CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY CODE IS
|
||||
AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
|
||||
|
||||
TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL
|
||||
THE COPYRIGHT HOLDER OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
|
||||
SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES FOR LOSS OF
|
||||
PROFITS, REVENUE, OR FOR LOSS OF INFORMATION OR ANY OTHER LOSS.
|
||||
|
||||
YOU EXPRESSLY AGREE TO FOREVER INDEMNIFY, DEFEND AND HOLD HARMLESS THE
|
||||
COPYRIGHT HOLDERS AND CONTRIBUTORS OF GLOD AGAINST ALL CLAIMS,
|
||||
DEMANDS, SUITS OR OTHER ACTIONS ARISING DIRECTLY OR INDIRECTLY FROM
|
||||
YOUR ACCEPTANCE AND USE OF GLOD.
|
||||
|
||||
Although NOT REQUIRED, we would appreciate it if active users of GLOD
|
||||
put a link on their web site to the GLOD web site when possible.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -136,10 +136,10 @@ mAvatarTabIndex(0)
|
|||
mStatusLock = new LLMutex();
|
||||
mModelPreview = NULL;
|
||||
|
||||
mLODMode[LLModel::LOD_HIGH] = 0;
|
||||
mLODMode[LLModel::LOD_HIGH] = LLModelPreview::LOD_FROM_FILE;
|
||||
for (U32 i = 0; i < LLModel::LOD_HIGH; i++)
|
||||
{
|
||||
mLODMode[i] = 1;
|
||||
mLODMode[i] = LLModelPreview::MESH_OPTIMIZER_AUTO;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -722,7 +722,20 @@ void LLFloaterModelPreview::onAutoFillCommit(LLUICtrl* ctrl, void* userdata)
|
|||
|
||||
void LLFloaterModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit)
|
||||
{
|
||||
mModelPreview->onLODParamCommit(lod, enforce_tri_limit);
|
||||
LLComboBox* lod_source_combo = getChild<LLComboBox>("lod_source_" + lod_name[lod]);
|
||||
S32 mode = lod_source_combo->getCurrentIndex();
|
||||
switch (mode)
|
||||
{
|
||||
case LLModelPreview::MESH_OPTIMIZER_AUTO:
|
||||
case LLModelPreview::MESH_OPTIMIZER:
|
||||
case LLModelPreview::MESH_OPTIMIZER_SLOPPY:
|
||||
case LLModelPreview::MESH_OPTIMIZER_COMBINE:
|
||||
mModelPreview->onLODMeshOptimizerParamCommit(lod, enforce_tri_limit, mode);
|
||||
break;
|
||||
default:
|
||||
LL_ERRS() << "Only supposed to be called to generate models" << LL_ENDL;
|
||||
break;
|
||||
}
|
||||
|
||||
//refresh LoDs that reference this one
|
||||
for (S32 i = lod - 1; i >= 0; --i)
|
||||
|
|
@ -1721,7 +1734,11 @@ void LLFloaterModelPreview::onLoDSourceCommit(S32 lod)
|
|||
refresh();
|
||||
|
||||
LLComboBox* lod_source_combo = getChild<LLComboBox>("lod_source_" + lod_name[lod]);
|
||||
if (lod_source_combo->getCurrentIndex() == LLModelPreview::GENERATE)
|
||||
S32 index = lod_source_combo->getCurrentIndex();
|
||||
if (index == LLModelPreview::MESH_OPTIMIZER_AUTO
|
||||
|| index == LLModelPreview::MESH_OPTIMIZER
|
||||
|| index == LLModelPreview::MESH_OPTIMIZER_SLOPPY
|
||||
|| index == LLModelPreview::MESH_OPTIMIZER_COMBINE)
|
||||
{ //rebuild LoD to update triangle counts
|
||||
onLODParamCommit(lod, true);
|
||||
}
|
||||
|
|
@ -1752,7 +1769,7 @@ void LLFloaterModelPreview::resetUploadOptions()
|
|||
getChild<LLComboBox>("lod_source_" + lod_name[NUM_LOD - 1])->setCurrentByIndex(LLModelPreview::LOD_FROM_FILE);
|
||||
for (S32 lod = 0; lod < NUM_LOD - 1; ++lod)
|
||||
{
|
||||
getChild<LLComboBox>("lod_source_" + lod_name[lod])->setCurrentByIndex(LLModelPreview::GENERATE);
|
||||
getChild<LLComboBox>("lod_source_" + lod_name[lod])->setCurrentByIndex(LLModelPreview::MESH_OPTIMIZER_AUTO);
|
||||
childSetValue("lod_file_" + lod_name[lod], "");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -196,9 +196,7 @@ protected:
|
|||
std::map<std::string, bool> mViewOptionDisabled;
|
||||
|
||||
//store which lod mode each LOD is using
|
||||
// 0 - load from file
|
||||
// 1 - auto generate
|
||||
// 2 - use LoD above
|
||||
// See eLoDMode
|
||||
S32 mLODMode[4];
|
||||
|
||||
LLMutex* mStatusLock;
|
||||
|
|
|
|||
|
|
@ -730,13 +730,19 @@ void LLKeyConflictHandler::resetToDefault(const std::string &control_name, U32 i
|
|||
{
|
||||
return;
|
||||
}
|
||||
LLKeyConflict &type_data = mControlsMap[control_name];
|
||||
if (!type_data.mAssignable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
LLKeyData data = getDefaultControl(control_name, index);
|
||||
|
||||
if (data != mControlsMap[control_name].getKeyData(index))
|
||||
if (data != type_data.getKeyData(index))
|
||||
{
|
||||
// reset controls that might have been switched to our current control
|
||||
removeConflicts(data, mControlsMap[control_name].mConflictMask);
|
||||
mControlsMap[control_name].setKeyData(data, index);
|
||||
mHasUnsavedChanges = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
#include "lliconctrl.h"
|
||||
#include "llmatrix4a.h"
|
||||
#include "llmeshrepository.h"
|
||||
#include "llmeshoptimizer.h"
|
||||
#include "llrender.h"
|
||||
#include "llsdutil_math.h"
|
||||
#include "llskinningutil.h"
|
||||
|
|
@ -66,7 +67,6 @@
|
|||
#include "lltabcontainer.h"
|
||||
#include "lltextbox.h"
|
||||
|
||||
#include "glod/glod.h"
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
bool LLModelPreview::sIgnoreLoadedCallback = false;
|
||||
|
|
@ -89,19 +89,6 @@ static const F32 PREVIEW_ZOOM_LIMIT(10.f);
|
|||
|
||||
const F32 SKIN_WEIGHT_CAMERA_DISTANCE = 16.f;
|
||||
|
||||
BOOL stop_gloderror()
|
||||
{
|
||||
GLuint error = glodGetError();
|
||||
|
||||
if (error != GLOD_NO_ERROR)
|
||||
{
|
||||
LL_WARNS() << "GLOD error detected, cannot generate LOD: " << std::hex << error << LL_ENDL;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
LLViewerFetchedTexture* bindMaterialDiffuseTexture(const LLImportMaterial& material)
|
||||
{
|
||||
LLViewerFetchedTexture *texture = LLViewerTextureManager::getFetchedTexture(material.getDiffuseMap(), FTT_DEFAULT, TRUE, LLGLTexture::BOOST_PREVIEW);
|
||||
|
|
@ -193,6 +180,7 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp)
|
|||
mPreviewLOD = 0;
|
||||
mModelLoader = NULL;
|
||||
mMaxTriangleLimit = 0;
|
||||
mMinTriangleLimit = 0;
|
||||
mDirty = false;
|
||||
mGenLOD = false;
|
||||
mLoading = false;
|
||||
|
|
@ -200,10 +188,6 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp)
|
|||
mLoadState = LLModelLoader::STARTING;
|
||||
mGroup = 0;
|
||||
mLODFrozen = false;
|
||||
mBuildShareTolerance = 0.f;
|
||||
mBuildQueueMode = GLOD_QUEUE_GREEDY;
|
||||
mBuildBorderMode = GLOD_BORDER_UNLOCK;
|
||||
mBuildOperator = GLOD_OPERATOR_EDGE_COLLAPSE;
|
||||
|
||||
for (U32 i = 0; i < LLModel::NUM_LODS; ++i)
|
||||
{
|
||||
|
|
@ -211,10 +195,6 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp)
|
|||
mRequestedCreaseAngle[i] = -1.f;
|
||||
mRequestedLoDMode[i] = 0;
|
||||
mRequestedErrorThreshold[i] = 0.f;
|
||||
mRequestedBuildOperator[i] = 0;
|
||||
mRequestedQueueMode[i] = 0;
|
||||
mRequestedBorderMode[i] = 0;
|
||||
mRequestedShareTolerance[i] = 0.f;
|
||||
}
|
||||
|
||||
mViewOption["show_textures"] = false;
|
||||
|
|
@ -224,23 +204,11 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp)
|
|||
mHasPivot = false;
|
||||
mModelPivot = LLVector3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
glodInit();
|
||||
|
||||
createPreviewAvatar();
|
||||
}
|
||||
|
||||
LLModelPreview::~LLModelPreview()
|
||||
{
|
||||
// glod apparently has internal mem alignment issues that are angering
|
||||
// the heap-check code in windows, these should be hunted down in that
|
||||
// TP code, if possible
|
||||
//
|
||||
// kernel32.dll!HeapFree() + 0x14 bytes
|
||||
// msvcr100.dll!free(void * pBlock) Line 51 C
|
||||
// glod.dll!glodGetGroupParameteriv() + 0x119 bytes
|
||||
// glod.dll!glodShutdown() + 0x77 bytes
|
||||
//
|
||||
//glodShutdown();
|
||||
if (mModelLoader)
|
||||
{
|
||||
mModelLoader->shutdown();
|
||||
|
|
@ -826,11 +794,6 @@ void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable
|
|||
|
||||
mLODFile[lod] = filename;
|
||||
|
||||
if (lod == LLModel::LOD_HIGH)
|
||||
{
|
||||
clearGLODGroup();
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> joint_alias_map;
|
||||
getJointAliases(joint_alias_map);
|
||||
|
||||
|
|
@ -931,7 +894,6 @@ void LLModelPreview::clearIncompatible(S32 lod)
|
|||
if (i == LLModel::LOD_HIGH)
|
||||
{
|
||||
mBaseModel = mModel[lod];
|
||||
clearGLODGroup();
|
||||
mBaseScene = mScene[lod];
|
||||
mVertexBuffer[5].clear();
|
||||
}
|
||||
|
|
@ -940,23 +902,6 @@ void LLModelPreview::clearIncompatible(S32 lod)
|
|||
}
|
||||
}
|
||||
|
||||
void LLModelPreview::clearGLODGroup()
|
||||
{
|
||||
if (mGroup)
|
||||
{
|
||||
for (std::map<LLPointer<LLModel>, U32>::iterator iter = mObject.begin(); iter != mObject.end(); ++iter)
|
||||
{
|
||||
glodDeleteObject(iter->second);
|
||||
stop_gloderror();
|
||||
}
|
||||
mObject.clear();
|
||||
|
||||
glodDeleteGroup(mGroup);
|
||||
stop_gloderror();
|
||||
mGroup = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void LLModelPreview::loadModelCallback(S32 loaded_lod)
|
||||
{
|
||||
assert_main_thread();
|
||||
|
|
@ -1108,7 +1053,6 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod)
|
|||
}
|
||||
|
||||
mBaseModel = mModel[loaded_lod];
|
||||
clearGLODGroup();
|
||||
|
||||
mBaseScene = mScene[loaded_lod];
|
||||
mVertexBuffer[5].clear();
|
||||
|
|
@ -1339,8 +1283,328 @@ void LLModelPreview::restoreNormals()
|
|||
updateStatusMessages();
|
||||
}
|
||||
|
||||
void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_limit)
|
||||
// Runs per object, but likely it is a better way to run per model+submodels
|
||||
// returns a ratio of base model indices to resulting indices
|
||||
// returns -1 in case of failure
|
||||
F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *target_model, F32 indices_decimator, F32 error_threshold, bool sloppy)
|
||||
{
|
||||
// Figure out buffer size
|
||||
S32 size_indices = 0;
|
||||
S32 size_vertices = 0;
|
||||
|
||||
for (U32 face_idx = 0; face_idx < base_model->getNumVolumeFaces(); ++face_idx)
|
||||
{
|
||||
const LLVolumeFace &face = base_model->getVolumeFace(face_idx);
|
||||
size_indices += face.mNumIndices;
|
||||
size_vertices += face.mNumVertices;
|
||||
}
|
||||
|
||||
// Allocate buffers, note that we are using U32 buffer instead of U16
|
||||
U32* combined_indices = (U32*)ll_aligned_malloc_32(size_indices * sizeof(U32));
|
||||
U32* output_indices = (U32*)ll_aligned_malloc_32(size_indices * sizeof(U32));
|
||||
|
||||
// extra space for normals and text coords
|
||||
S32 tc_bytes_size = ((size_vertices * sizeof(LLVector2)) + 0xF) & ~0xF;
|
||||
LLVector4a* combined_positions = (LLVector4a*)ll_aligned_malloc<64>(sizeof(LLVector4a) * 2 * size_vertices + tc_bytes_size);
|
||||
LLVector4a* combined_normals = combined_positions + size_vertices;
|
||||
LLVector2* combined_tex_coords = (LLVector2*)(combined_normals + size_vertices);
|
||||
|
||||
// copy indices and vertices into new buffers
|
||||
S32 combined_positions_shift = 0;
|
||||
S32 indices_idx_shift = 0;
|
||||
S32 combined_indices_shift = 0;
|
||||
for (U32 face_idx = 0; face_idx < base_model->getNumVolumeFaces(); ++face_idx)
|
||||
{
|
||||
const LLVolumeFace &face = base_model->getVolumeFace(face_idx);
|
||||
|
||||
// vertices
|
||||
S32 copy_bytes = face.mNumVertices * sizeof(LLVector4a);
|
||||
LLVector4a::memcpyNonAliased16((F32*)(combined_positions + combined_positions_shift), (F32*)face.mPositions, copy_bytes);
|
||||
|
||||
// normals
|
||||
LLVector4a::memcpyNonAliased16((F32*)(combined_normals + combined_positions_shift), (F32*)face.mNormals, copy_bytes);
|
||||
|
||||
// tex coords
|
||||
copy_bytes = (face.mNumVertices * sizeof(LLVector2) + 0xF) & ~0xF;
|
||||
LLVector4a::memcpyNonAliased16((F32*)(combined_tex_coords + combined_positions_shift), (F32*)face.mTexCoords, copy_bytes);
|
||||
|
||||
combined_positions_shift += face.mNumVertices;
|
||||
|
||||
// indices, sadly can't do dumb memcpy for indices, need to adjust each value
|
||||
for (S32 i = 0; i < face.mNumIndices; ++i)
|
||||
{
|
||||
U16 idx = face.mIndices[i];
|
||||
|
||||
combined_indices[combined_indices_shift] = idx + indices_idx_shift;
|
||||
combined_indices_shift++;
|
||||
}
|
||||
indices_idx_shift += face.mNumVertices;
|
||||
}
|
||||
|
||||
// Now that we have buffers, optimize
|
||||
S32 target_indices = 0;
|
||||
F32 result_code = 0; // how far from original the model is, 1 == 100%
|
||||
S32 new_indices = 0;
|
||||
|
||||
target_indices = llmax(3, llfloor(size_indices / indices_decimator)); // leave at least one triangle
|
||||
new_indices = LLMeshOptimizer::simplifyU32(
|
||||
output_indices,
|
||||
combined_indices,
|
||||
size_indices,
|
||||
combined_positions,
|
||||
size_vertices,
|
||||
LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_VERTEX],
|
||||
target_indices,
|
||||
error_threshold,
|
||||
sloppy,
|
||||
&result_code);
|
||||
|
||||
|
||||
if (result_code < 0)
|
||||
{
|
||||
LL_WARNS() << "Negative result code from meshoptimizer for model " << target_model->mLabel
|
||||
<< " target Indices: " << target_indices
|
||||
<< " new Indices: " << new_indices
|
||||
<< " original count: " << size_indices << LL_ENDL;
|
||||
}
|
||||
|
||||
// repack back into individual faces
|
||||
|
||||
LLVector4a* buffer_positions = (LLVector4a*)ll_aligned_malloc<64>(sizeof(LLVector4a) * 2 * size_vertices + tc_bytes_size);
|
||||
LLVector4a* buffer_normals = buffer_positions + size_vertices;
|
||||
LLVector2* buffer_tex_coords = (LLVector2*)(buffer_normals + size_vertices);
|
||||
S32 buffer_idx_size = (size_indices * sizeof(U16) + 0xF) & ~0xF;
|
||||
U16* buffer_indices = (U16*)ll_aligned_malloc_16(buffer_idx_size);
|
||||
S32* old_to_new_positions_map = new S32[size_vertices];
|
||||
|
||||
S32 buf_positions_copied = 0;
|
||||
S32 buf_indices_copied = 0;
|
||||
indices_idx_shift = 0;
|
||||
|
||||
// Crude method to copy indices back into face
|
||||
for (U32 face_idx = 0; face_idx < base_model->getNumVolumeFaces(); ++face_idx)
|
||||
{
|
||||
const LLVolumeFace &face = base_model->getVolumeFace(face_idx);
|
||||
|
||||
// reset data for new run
|
||||
buf_positions_copied = 0;
|
||||
buf_indices_copied = 0;
|
||||
bool copy_triangle = false;
|
||||
S32 range = indices_idx_shift + face.mNumVertices;
|
||||
|
||||
for (S32 i = 0; i < size_vertices; i++)
|
||||
{
|
||||
old_to_new_positions_map[i] = -1;
|
||||
}
|
||||
|
||||
// Copy relevant indices and vertices
|
||||
for (S32 i = 0; i < new_indices; ++i)
|
||||
{
|
||||
U32 idx = output_indices[i];
|
||||
|
||||
if ((i % 3) == 0)
|
||||
{
|
||||
copy_triangle = idx >= indices_idx_shift && idx < range;
|
||||
}
|
||||
|
||||
if (copy_triangle)
|
||||
{
|
||||
if (old_to_new_positions_map[idx] == -1)
|
||||
{
|
||||
// New position, need to copy it
|
||||
// Validate size
|
||||
if (buf_positions_copied >= U16_MAX)
|
||||
{
|
||||
// Normally this shouldn't happen since the whole point is to reduce amount of vertices
|
||||
// but it might happen if user tries to run optimization with too large triangle or error value
|
||||
// so fallback to 'per face' mode or verify requested limits and copy base model as is.
|
||||
LL_WARNS() << "Over triangle limit. Failed to optimize in 'per object' mode, falling back to per face variant for"
|
||||
<< " model " << target_model->mLabel
|
||||
<< " target Indices: " << target_indices
|
||||
<< " new Indices: " << new_indices
|
||||
<< " original count: " << size_indices
|
||||
<< " error treshold: " << error_threshold
|
||||
<< LL_ENDL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Copy vertice, normals, tcs
|
||||
buffer_positions[buf_positions_copied] = combined_positions[idx];
|
||||
buffer_normals[buf_positions_copied] = combined_normals[idx];
|
||||
buffer_tex_coords[buf_positions_copied] = combined_tex_coords[idx];
|
||||
|
||||
old_to_new_positions_map[idx] = buf_positions_copied;
|
||||
|
||||
buffer_indices[buf_indices_copied] = (U16)buf_positions_copied;
|
||||
buf_positions_copied++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// existing position
|
||||
buffer_indices[buf_indices_copied] = (U16)old_to_new_positions_map[idx];
|
||||
}
|
||||
buf_indices_copied++;
|
||||
}
|
||||
}
|
||||
|
||||
if (buf_positions_copied >= U16_MAX)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
LLVolumeFace &new_face = target_model->getVolumeFace(face_idx);
|
||||
//new_face = face; //temp
|
||||
|
||||
if (buf_indices_copied < 3)
|
||||
{
|
||||
// face was optimized away
|
||||
new_face.resizeIndices(3);
|
||||
new_face.resizeVertices(1);
|
||||
memset(new_face.mIndices, 0, sizeof(U16) * 3);
|
||||
new_face.mPositions[0].clear(); // set first vertice to 0
|
||||
new_face.mNormals[0].clear();
|
||||
new_face.mTexCoords[0].setZero();
|
||||
}
|
||||
else
|
||||
{
|
||||
new_face.resizeIndices(buf_indices_copied);
|
||||
new_face.resizeVertices(buf_positions_copied);
|
||||
|
||||
S32 idx_size = (buf_indices_copied * sizeof(U16) + 0xF) & ~0xF;
|
||||
LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)buffer_indices, idx_size);
|
||||
|
||||
LLVector4a::memcpyNonAliased16((F32*)new_face.mPositions, (F32*)buffer_positions, buf_positions_copied * sizeof(LLVector4a));
|
||||
LLVector4a::memcpyNonAliased16((F32*)new_face.mNormals, (F32*)buffer_normals, buf_positions_copied * sizeof(LLVector4a));
|
||||
|
||||
U32 tex_size = (buf_positions_copied * sizeof(LLVector2) + 0xF)&~0xF;
|
||||
LLVector4a::memcpyNonAliased16((F32*)new_face.mTexCoords, (F32*)buffer_tex_coords, tex_size);
|
||||
}
|
||||
|
||||
indices_idx_shift += face.mNumVertices;
|
||||
}
|
||||
|
||||
delete[]old_to_new_positions_map;
|
||||
ll_aligned_free<64>(combined_positions);
|
||||
ll_aligned_free<64>(buffer_positions);
|
||||
ll_aligned_free_32(output_indices);
|
||||
ll_aligned_free_16(buffer_indices);
|
||||
ll_aligned_free_32(combined_indices);
|
||||
|
||||
if (new_indices < 3)
|
||||
{
|
||||
// Model should have at least one visible triangle
|
||||
|
||||
if (!sloppy)
|
||||
{
|
||||
// Should only happen with sloppy
|
||||
// non sloppy shouldn't be capable of optimizing mesh away
|
||||
LL_WARNS() << "Failed to generate triangles"
|
||||
<< " model " << target_model->mLabel
|
||||
<< " target Indices: " << target_indices
|
||||
<< " new Indices: " << new_indices
|
||||
<< " original count: " << size_indices
|
||||
<< " error treshold: " << error_threshold
|
||||
<< LL_ENDL;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (F32)size_indices / (F32)new_indices;
|
||||
}
|
||||
|
||||
F32 LLModelPreview::genMeshOptimizerPerFace(LLModel *base_model, LLModel *target_model, U32 face_idx, F32 indices_decimator, F32 error_threshold, bool sloppy)
|
||||
{
|
||||
const LLVolumeFace &face = base_model->getVolumeFace(face_idx);
|
||||
S32 size_indices = face.mNumIndices;
|
||||
// todo: do not allocate per each face, add one large buffer somewhere
|
||||
// faces have limited amount of indices
|
||||
S32 size = (size_indices * sizeof(U16) + 0xF) & ~0xF;
|
||||
U16* output = (U16*)ll_aligned_malloc_16(size);
|
||||
|
||||
S32 target_indices = 0;
|
||||
F32 result_code = 0; // how far from original the model is, 1 == 100%
|
||||
S32 new_indices = 0;
|
||||
|
||||
target_indices = llmax(3, llfloor(size_indices / indices_decimator)); // leave at least one triangle
|
||||
new_indices = LLMeshOptimizer::simplify(
|
||||
output,
|
||||
face.mIndices,
|
||||
size_indices,
|
||||
face.mPositions,
|
||||
face.mNumVertices,
|
||||
LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_VERTEX],
|
||||
target_indices,
|
||||
error_threshold,
|
||||
sloppy,
|
||||
&result_code);
|
||||
|
||||
|
||||
if (result_code < 0)
|
||||
{
|
||||
LL_WARNS() << "Negative result code from meshoptimizer for face " << face_idx
|
||||
<< " of model " << target_model->mLabel
|
||||
<< " target Indices: " << target_indices
|
||||
<< " new Indices: " << new_indices
|
||||
<< " original count: " << size_indices
|
||||
<< " error treshold: " << error_threshold
|
||||
<< LL_ENDL;
|
||||
}
|
||||
|
||||
LLVolumeFace &new_face = target_model->getVolumeFace(face_idx);
|
||||
|
||||
// Copy old values
|
||||
new_face = face;
|
||||
|
||||
|
||||
if (new_indices < 3)
|
||||
{
|
||||
if (!sloppy)
|
||||
{
|
||||
// meshopt_optimizeSloppy() can optimize triangles away even if target_indices is > 2,
|
||||
// but optimize() isn't supposed to
|
||||
LL_INFOS() << "No indices generated by meshoptimizer for face " << face_idx
|
||||
<< " of model " << target_model->mLabel
|
||||
<< " target Indices: " << target_indices
|
||||
<< " original count: " << size_indices
|
||||
<< " error treshold: " << error_threshold
|
||||
<< LL_ENDL;
|
||||
}
|
||||
|
||||
// Face got optimized away
|
||||
// Generate empty triangle
|
||||
new_face.resizeIndices(3);
|
||||
new_face.resizeVertices(1);
|
||||
memset(new_face.mIndices, 0, sizeof(U16) * 3);
|
||||
new_face.mPositions[0].clear(); // set first vertice to 0
|
||||
new_face.mNormals[0].clear();
|
||||
new_face.mTexCoords[0].setZero();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Assign new values
|
||||
new_face.resizeIndices(new_indices); // will wipe out mIndices, so new_face can't substitute output
|
||||
S32 idx_size = (new_indices * sizeof(U16) + 0xF) & ~0xF;
|
||||
LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)output, idx_size);
|
||||
|
||||
// clear unused values
|
||||
new_face.optimize();
|
||||
}
|
||||
|
||||
ll_aligned_free_16(output);
|
||||
|
||||
if (new_indices < 3)
|
||||
{
|
||||
// At least one triangle is needed
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (F32)size_indices / (F32)new_indices;
|
||||
}
|
||||
|
||||
void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 decimation, bool enforce_tri_limit)
|
||||
{
|
||||
LL_INFOS() << "Generating lod " << which_lod << " using meshoptimizer" << LL_ENDL;
|
||||
// Allow LoD from -1 to LLModel::LOD_PHYSICS
|
||||
if (which_lod < -1 || which_lod > LLModel::NUM_LODS - 1)
|
||||
{
|
||||
|
|
@ -1348,7 +1612,7 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim
|
|||
out << "Invalid level of detail: " << which_lod;
|
||||
LL_WARNS() << out.str() << LL_ENDL;
|
||||
LLFloaterModelPreview::addStringToLog(out, false);
|
||||
assert(which_lod >= -1 && which_lod < LLModel::NUM_LODS);
|
||||
assert(lod >= -1 && lod < LLModel::NUM_LODS);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1357,57 +1621,22 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim
|
|||
return;
|
||||
}
|
||||
|
||||
LLVertexBuffer::unbind();
|
||||
|
||||
bool no_ff = LLGLSLShader::sNoFixedFunction;
|
||||
LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
|
||||
LLGLSLShader::sNoFixedFunction = false;
|
||||
|
||||
if (shader)
|
||||
//get the triangle count for all base models
|
||||
S32 base_triangle_count = 0;
|
||||
for (S32 i = 0; i < mBaseModel.size(); ++i)
|
||||
{
|
||||
shader->unbind();
|
||||
base_triangle_count += mBaseModel[i]->getNumTriangles();
|
||||
}
|
||||
|
||||
stop_gloderror();
|
||||
static U32 cur_name = 1;
|
||||
// Urgh...
|
||||
// TODO: add interface to mFMP to get error treshold or let mFMP write one into LLModelPreview
|
||||
// We should not be accesing views from other class!
|
||||
U32 lod_mode = LIMIT_TRIANGLES;
|
||||
F32 indices_decimator = 0;
|
||||
F32 triangle_limit = 0;
|
||||
F32 lod_error_threshold = 1; //100%
|
||||
|
||||
S32 limit = -1;
|
||||
|
||||
U32 triangle_count = 0;
|
||||
|
||||
U32 instanced_triangle_count = 0;
|
||||
|
||||
//get the triangle count for the whole scene
|
||||
for (LLModelLoader::scene::iterator iter = mBaseScene.begin(), endIter = mBaseScene.end(); iter != endIter; ++iter)
|
||||
{
|
||||
for (LLModelLoader::model_instance_list::iterator instance = iter->second.begin(), end_instance = iter->second.end(); instance != end_instance; ++instance)
|
||||
{
|
||||
LLModel* mdl = instance->mModel;
|
||||
if (mdl)
|
||||
{
|
||||
instanced_triangle_count += mdl->getNumTriangles();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//get the triangle count for the non-instanced set of models
|
||||
for (U32 i = 0; i < mBaseModel.size(); ++i)
|
||||
{
|
||||
triangle_count += mBaseModel[i]->getNumTriangles();
|
||||
}
|
||||
|
||||
//get ratio of uninstanced triangles to instanced triangles
|
||||
F32 triangle_ratio = (F32)triangle_count / (F32)instanced_triangle_count;
|
||||
|
||||
U32 base_triangle_count = triangle_count;
|
||||
|
||||
U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0;
|
||||
|
||||
U32 lod_mode = 0;
|
||||
|
||||
F32 lod_error_threshold = 0;
|
||||
|
||||
// The LoD should be in range from Lowest to High
|
||||
// If requesting a single lod
|
||||
if (which_lod > -1 && which_lod < NUM_LOD)
|
||||
{
|
||||
LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode_" + lod_name[which_lod]);
|
||||
|
|
@ -1416,163 +1645,83 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim
|
|||
lod_mode = iface->getFirstSelectedIndex();
|
||||
}
|
||||
|
||||
lod_error_threshold = mFMP->childGetValue("lod_error_threshold_" + lod_name[which_lod]).asReal();
|
||||
}
|
||||
|
||||
if (which_lod != -1)
|
||||
{
|
||||
mRequestedLoDMode[which_lod] = lod_mode;
|
||||
}
|
||||
|
||||
if (lod_mode == 0)
|
||||
{
|
||||
lod_mode = GLOD_TRIANGLE_BUDGET;
|
||||
|
||||
// The LoD should be in range from Lowest to High
|
||||
if (which_lod > -1 && which_lod < NUM_LOD)
|
||||
if (lod_mode == LIMIT_TRIANGLES)
|
||||
{
|
||||
limit = mFMP->childGetValue("lod_triangle_limit_" + lod_name[which_lod]).asInteger();
|
||||
//convert from "scene wide" to "non-instanced" triangle limit
|
||||
limit = (S32)((F32)limit*triangle_ratio);
|
||||
if (!enforce_tri_limit)
|
||||
{
|
||||
triangle_limit = base_triangle_count;
|
||||
// reset to default value for this lod
|
||||
F32 pw = pow((F32)decimation, (F32)(LLModel::LOD_HIGH - which_lod));
|
||||
|
||||
triangle_limit /= pw; //indices_ratio can be 1/pw
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// UI spacifies limit for all models of single lod
|
||||
triangle_limit = mFMP->childGetValue("lod_triangle_limit_" + lod_name[which_lod]).asInteger();
|
||||
|
||||
}
|
||||
// meshoptimizer doesn't use triangle limit, it uses indices limit, so convert it to aproximate ratio
|
||||
indices_decimator = (F32)base_triangle_count / triangle_limit;
|
||||
}
|
||||
else
|
||||
{
|
||||
lod_error_threshold = mFMP->childGetValue("lod_error_threshold_" + lod_name[which_lod]).asReal();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lod_mode = GLOD_ERROR_THRESHOLD;
|
||||
// we are genrating all lods and each lod will get own indices_decimator
|
||||
indices_decimator = 1;
|
||||
triangle_limit = base_triangle_count;
|
||||
}
|
||||
|
||||
bool object_dirty = false;
|
||||
|
||||
if (mGroup == 0)
|
||||
{
|
||||
object_dirty = true;
|
||||
mGroup = cur_name++;
|
||||
glodNewGroup(mGroup);
|
||||
}
|
||||
|
||||
if (object_dirty)
|
||||
{
|
||||
for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter)
|
||||
{ //build GLOD objects for each model in base model list
|
||||
LLModel* mdl = *iter;
|
||||
|
||||
if (mObject[mdl] != 0)
|
||||
{
|
||||
glodDeleteObject(mObject[mdl]);
|
||||
}
|
||||
|
||||
mObject[mdl] = cur_name++;
|
||||
|
||||
glodNewObject(mObject[mdl], mGroup, GLOD_DISCRETE);
|
||||
stop_gloderror();
|
||||
|
||||
if (iter == mBaseModel.begin() && !mdl->mSkinWeights.empty())
|
||||
{ //regenerate vertex buffer for skinned models to prevent animation feedback during LOD generation
|
||||
mVertexBuffer[5].clear();
|
||||
}
|
||||
|
||||
if (mVertexBuffer[5].empty())
|
||||
{
|
||||
genBuffers(5, false);
|
||||
}
|
||||
|
||||
U32 tri_count = 0;
|
||||
for (U32 i = 0; i < mVertexBuffer[5][mdl].size(); ++i)
|
||||
{
|
||||
LLVertexBuffer* buff = mVertexBuffer[5][mdl][i];
|
||||
buff->setBuffer(type_mask & buff->getTypeMask());
|
||||
|
||||
U32 num_indices = mVertexBuffer[5][mdl][i]->getNumIndices();
|
||||
if (num_indices > 2)
|
||||
{
|
||||
glodInsertElements(mObject[mdl], i, GL_TRIANGLES, num_indices, GL_UNSIGNED_SHORT, (U8*)mVertexBuffer[5][mdl][i]->getIndicesPointer(), 0, 0.f);
|
||||
}
|
||||
tri_count += num_indices / 3;
|
||||
stop_gloderror();
|
||||
}
|
||||
|
||||
glodBuildObject(mObject[mdl]);
|
||||
stop_gloderror();
|
||||
}
|
||||
}
|
||||
mMaxTriangleLimit = base_triangle_count;
|
||||
mMinTriangleLimit = mBaseModel.size();
|
||||
|
||||
// Build models
|
||||
|
||||
S32 start = LLModel::LOD_HIGH;
|
||||
S32 end = 0;
|
||||
|
||||
if (which_lod != -1)
|
||||
{
|
||||
start = end = which_lod;
|
||||
start = which_lod;
|
||||
end = which_lod;
|
||||
}
|
||||
|
||||
mMaxTriangleLimit = base_triangle_count;
|
||||
LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
|
||||
if (shader)
|
||||
{
|
||||
shader->unbind();
|
||||
}
|
||||
|
||||
for (S32 lod = start; lod >= end; --lod)
|
||||
{
|
||||
if (which_lod == -1)
|
||||
{
|
||||
// we are genrating all lods and each lod gets own indices_ratio
|
||||
if (lod < start)
|
||||
{
|
||||
triangle_count /= decimation;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (enforce_tri_limit)
|
||||
{
|
||||
triangle_count = limit;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (S32 j = LLModel::LOD_HIGH; j>which_lod; --j)
|
||||
{
|
||||
triangle_count /= decimation;
|
||||
}
|
||||
indices_decimator *= decimation;
|
||||
triangle_limit /= decimation;
|
||||
}
|
||||
}
|
||||
|
||||
mRequestedTriangleCount[lod] = llmax(mMinTriangleLimit, (S32)triangle_limit);
|
||||
mRequestedErrorThreshold[lod] = lod_error_threshold;
|
||||
mRequestedLoDMode[lod] = lod_mode;
|
||||
|
||||
mModel[lod].clear();
|
||||
mModel[lod].resize(mBaseModel.size());
|
||||
mVertexBuffer[lod].clear();
|
||||
|
||||
U32 actual_tris = 0;
|
||||
U32 actual_verts = 0;
|
||||
U32 submeshes = 0;
|
||||
|
||||
mRequestedTriangleCount[lod] = (S32)((F32)triangle_count / triangle_ratio);
|
||||
mRequestedErrorThreshold[lod] = lod_error_threshold;
|
||||
|
||||
glodGroupParameteri(mGroup, GLOD_ADAPT_MODE, lod_mode);
|
||||
stop_gloderror();
|
||||
|
||||
glodGroupParameteri(mGroup, GLOD_ERROR_MODE, GLOD_OBJECT_SPACE_ERROR);
|
||||
stop_gloderror();
|
||||
|
||||
glodGroupParameterf(mGroup, GLOD_OBJECT_SPACE_ERROR_THRESHOLD, lod_error_threshold);
|
||||
stop_gloderror();
|
||||
|
||||
if (lod_mode != GLOD_TRIANGLE_BUDGET)
|
||||
{
|
||||
glodGroupParameteri(mGroup, GLOD_MAX_TRIANGLES, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
//SH-632: always add 1 to desired amount to avoid decimating below desired amount
|
||||
glodGroupParameteri(mGroup, GLOD_MAX_TRIANGLES, triangle_count + 1);
|
||||
}
|
||||
|
||||
stop_gloderror();
|
||||
glodAdaptGroup(mGroup);
|
||||
stop_gloderror();
|
||||
|
||||
for (U32 mdl_idx = 0; mdl_idx < mBaseModel.size(); ++mdl_idx)
|
||||
{
|
||||
LLModel* base = mBaseModel[mdl_idx];
|
||||
|
||||
GLint patch_count = 0;
|
||||
glodGetObjectParameteriv(mObject[base], GLOD_NUM_PATCHES, &patch_count);
|
||||
stop_gloderror();
|
||||
|
||||
LLVolumeParams volume_params;
|
||||
volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
|
||||
mModel[lod][mdl_idx] = new LLModel(volume_params, 0.f);
|
||||
|
|
@ -1581,74 +1730,87 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim
|
|||
|
||||
mModel[lod][mdl_idx]->mLabel = name;
|
||||
mModel[lod][mdl_idx]->mSubmodelID = base->mSubmodelID;
|
||||
|
||||
GLint* sizes = new GLint[patch_count * 2];
|
||||
glodGetObjectParameteriv(mObject[base], GLOD_PATCH_SIZES, sizes);
|
||||
stop_gloderror();
|
||||
|
||||
GLint* names = new GLint[patch_count];
|
||||
glodGetObjectParameteriv(mObject[base], GLOD_PATCH_NAMES, names);
|
||||
stop_gloderror();
|
||||
|
||||
mModel[lod][mdl_idx]->setNumVolumeFaces(patch_count);
|
||||
mModel[lod][mdl_idx]->setNumVolumeFaces(base->getNumVolumeFaces());
|
||||
|
||||
LLModel* target_model = mModel[lod][mdl_idx];
|
||||
|
||||
for (GLint i = 0; i < patch_count; ++i)
|
||||
S32 model_meshopt_mode = meshopt_mode;
|
||||
|
||||
// Ideally this should run not per model,
|
||||
// but combine all submodels with origin model as well
|
||||
if (model_meshopt_mode == MESH_OPTIMIZER_COMBINE)
|
||||
{
|
||||
type_mask = mVertexBuffer[5][base][i]->getTypeMask();
|
||||
// Run meshoptimizer for each model/object, up to 8 faces in one model
|
||||
|
||||
LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(type_mask, 0);
|
||||
|
||||
if (sizes[i * 2 + 1] > 0 && sizes[i * 2] > 0)
|
||||
// Ideally this should run not per model,
|
||||
// but combine all submodels with origin model as well
|
||||
F32 res = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false);
|
||||
if (res < 0)
|
||||
{
|
||||
if (!buff->allocateBuffer(sizes[i * 2 + 1], sizes[i * 2], true))
|
||||
// U16 vertices overflow, shouldn't happen, but just in case
|
||||
for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
|
||||
{
|
||||
// Todo: find a way to stop preview in this case instead of crashing
|
||||
LL_ERRS() << "Failed buffer allocation during preview LOD generation."
|
||||
<< " Vertices: " << sizes[i * 2 + 1]
|
||||
<< " Indices: " << sizes[i * 2] << LL_ENDL;
|
||||
genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (model_meshopt_mode == MESH_OPTIMIZER)
|
||||
{
|
||||
// Run meshoptimizer for each face
|
||||
for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
|
||||
{
|
||||
genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (model_meshopt_mode == MESH_OPTIMIZER_SLOPPY)
|
||||
{
|
||||
// Run meshoptimizer for each face
|
||||
for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
|
||||
{
|
||||
genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (model_meshopt_mode == MESH_OPTIMIZER_AUTO)
|
||||
{
|
||||
F32 allowed_ratio_drift = 2.f;
|
||||
F32 res_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false);
|
||||
|
||||
if (res_ratio < 0)
|
||||
{
|
||||
// U16 vertices overflow, shouldn't happen, but just in case
|
||||
for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
|
||||
{
|
||||
genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, false);
|
||||
}
|
||||
LL_INFOS() << "Model " << target_model->getName()
|
||||
<< " lod " << which_lod
|
||||
<< " per model method overflow, defaulting to per face." << LL_ENDL;
|
||||
}
|
||||
else if (res_ratio * allowed_ratio_drift < indices_decimator)
|
||||
{
|
||||
// Try sloppy variant if normal one failed to simplify model enough.
|
||||
res_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, true);
|
||||
LL_INFOS() << "Model " << target_model->getName()
|
||||
<< " lod " << which_lod
|
||||
<< " sloppily simplified using per model method." << LL_ENDL;
|
||||
|
||||
|
||||
if (res_ratio < 0)
|
||||
{
|
||||
// Sloppy variant failed to generate triangles.
|
||||
// Can happen with models that are too simple as is.
|
||||
// Fallback to normal method.
|
||||
genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false);
|
||||
}
|
||||
buff->setBuffer(type_mask);
|
||||
glodFillElements(mObject[base], names[i], GL_UNSIGNED_SHORT, (U8*)buff->getIndicesPointer());
|
||||
stop_gloderror();
|
||||
}
|
||||
else
|
||||
{
|
||||
// This face was eliminated or we failed to allocate buffer,
|
||||
// attempt to create a dummy triangle (one vertex, 3 indices, all 0)
|
||||
buff->allocateBuffer(1, 3, true);
|
||||
memset((U8*)buff->getMappedData(), 0, buff->getSize());
|
||||
memset((U8*)buff->getIndicesPointer(), 0, buff->getIndicesSize());
|
||||
}
|
||||
|
||||
buff->validateRange(0, buff->getNumVerts() - 1, buff->getNumIndices(), 0);
|
||||
|
||||
LLStrider<LLVector3> pos;
|
||||
LLStrider<LLVector3> norm;
|
||||
LLStrider<LLVector2> tc;
|
||||
LLStrider<U16> index;
|
||||
|
||||
buff->getVertexStrider(pos);
|
||||
if (type_mask & LLVertexBuffer::MAP_NORMAL)
|
||||
{
|
||||
buff->getNormalStrider(norm);
|
||||
}
|
||||
if (type_mask & LLVertexBuffer::MAP_TEXCOORD0)
|
||||
{
|
||||
buff->getTexCoord0Strider(tc);
|
||||
}
|
||||
|
||||
buff->getIndexStrider(index);
|
||||
|
||||
target_model->setVolumeFaceData(names[i], pos, norm, tc, index, buff->getNumVerts(), buff->getNumIndices());
|
||||
actual_tris += buff->getNumIndices() / 3;
|
||||
actual_verts += buff->getNumVerts();
|
||||
++submeshes;
|
||||
|
||||
if (!validate_face(target_model->getVolumeFace(names[i])))
|
||||
{
|
||||
LL_ERRS() << "Invalid face generated during LOD generation." << LL_ENDL;
|
||||
LL_INFOS() << "Model " << target_model->getName()
|
||||
<< " lod " << which_lod
|
||||
<< " simplified using per model method." << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1658,6 +1820,7 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim
|
|||
target_model->mPosition = base->mPosition;
|
||||
target_model->mSkinWeights = base->mSkinWeights;
|
||||
target_model->mSkinInfo = base->mSkinInfo;
|
||||
|
||||
//copy material list
|
||||
target_model->mMaterialList = base->mMaterialList;
|
||||
|
||||
|
|
@ -1665,9 +1828,6 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim
|
|||
{
|
||||
LL_ERRS() << "Invalid model generated when creating LODs" << LL_ENDL;
|
||||
}
|
||||
|
||||
delete[] sizes;
|
||||
delete[] names;
|
||||
}
|
||||
|
||||
//rebuild scene based on mBaseScene
|
||||
|
|
@ -1697,7 +1857,6 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim
|
|||
mResourceCost = calcResourceCost();
|
||||
|
||||
LLVertexBuffer::unbind();
|
||||
LLGLSLShader::sNoFixedFunction = no_ff;
|
||||
if (shader)
|
||||
{
|
||||
shader->bind();
|
||||
|
|
@ -1821,6 +1980,7 @@ void LLModelPreview::updateStatusMessages()
|
|||
if (mMaxTriangleLimit == 0)
|
||||
{
|
||||
mMaxTriangleLimit = total_tris[LLModel::LOD_HIGH];
|
||||
mMinTriangleLimit = mUploadData.size();
|
||||
}
|
||||
|
||||
mHasDegenerate = false;
|
||||
|
|
@ -2264,7 +2424,7 @@ void LLModelPreview::updateLodControls(S32 lod)
|
|||
S32 lod_mode = lod_combo->getCurrentIndex();
|
||||
if (lod_mode == LOD_FROM_FILE) // LoD from file
|
||||
{
|
||||
fmp->mLODMode[lod] = 0;
|
||||
fmp->mLODMode[lod] = LOD_FROM_FILE;
|
||||
for (U32 i = 0; i < num_file_controls; ++i)
|
||||
{
|
||||
mFMP->childSetVisible(file_controls[i] + lod_name[lod], true);
|
||||
|
|
@ -2277,7 +2437,7 @@ void LLModelPreview::updateLodControls(S32 lod)
|
|||
}
|
||||
else if (lod_mode == USE_LOD_ABOVE) // use LoD above
|
||||
{
|
||||
fmp->mLODMode[lod] = 2;
|
||||
fmp->mLODMode[lod] = USE_LOD_ABOVE;
|
||||
for (U32 i = 0; i < num_file_controls; ++i)
|
||||
{
|
||||
mFMP->childSetVisible(file_controls[i] + lod_name[lod], false);
|
||||
|
|
@ -2303,7 +2463,7 @@ void LLModelPreview::updateLodControls(S32 lod)
|
|||
}
|
||||
else // auto generate, the default case for all LoDs except High
|
||||
{
|
||||
fmp->mLODMode[lod] = 1;
|
||||
fmp->mLODMode[lod] = MESH_OPTIMIZER_AUTO;
|
||||
|
||||
//don't actually regenerate lod when refreshing UI
|
||||
mLODFrozen = true;
|
||||
|
|
@ -2323,6 +2483,7 @@ void LLModelPreview::updateLodControls(S32 lod)
|
|||
LLSpinCtrl* limit = mFMP->getChild<LLSpinCtrl>("lod_triangle_limit_" + lod_name[lod]);
|
||||
|
||||
limit->setMaxValue(mMaxTriangleLimit);
|
||||
limit->setMinValue(mMinTriangleLimit);
|
||||
limit->forceSetValue(mRequestedTriangleCount[lod]);
|
||||
|
||||
threshold->forceSetValue(mRequestedErrorThreshold[lod]);
|
||||
|
|
@ -2335,7 +2496,8 @@ void LLModelPreview::updateLodControls(S32 lod)
|
|||
threshold->setVisible(false);
|
||||
|
||||
limit->setMaxValue(mMaxTriangleLimit);
|
||||
limit->setIncrement(mMaxTriangleLimit / 32);
|
||||
limit->setMinValue(mMinTriangleLimit);
|
||||
limit->setIncrement(llmax((U32)1, mMaxTriangleLimit / 32));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -2957,7 +3119,6 @@ BOOL LLModelPreview::render()
|
|||
{
|
||||
genBuffers(-1, skin_weight);
|
||||
//genBuffers(3);
|
||||
//genLODs();
|
||||
}
|
||||
|
||||
if (!mModel[mPreviewLOD].empty())
|
||||
|
|
@ -3543,7 +3704,7 @@ bool LLModelPreview::lodQueryCallback()
|
|||
{
|
||||
S32 lod = preview->mLodsQuery.back();
|
||||
preview->mLodsQuery.pop_back();
|
||||
preview->genLODs(lod);
|
||||
preview->genMeshOptimizerLODs(lod, MESH_OPTIMIZER_AUTO);
|
||||
|
||||
if (preview->mLookUpLodFiles && (lod == LLModel::LOD_HIGH))
|
||||
{
|
||||
|
|
@ -3558,11 +3719,11 @@ bool LLModelPreview::lodQueryCallback()
|
|||
return true;
|
||||
}
|
||||
|
||||
void LLModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit)
|
||||
void LLModelPreview::onLODMeshOptimizerParamCommit(S32 requested_lod, bool enforce_tri_limit, S32 mode)
|
||||
{
|
||||
if (!mLODFrozen)
|
||||
{
|
||||
genLODs(lod, 3, enforce_tri_limit);
|
||||
genMeshOptimizerLODs(requested_lod, mode, 3, enforce_tri_limit);
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -124,10 +124,19 @@ public:
|
|||
typedef enum
|
||||
{
|
||||
LOD_FROM_FILE = 0,
|
||||
GENERATE,
|
||||
MESH_OPTIMIZER_AUTO, // automatically selects method based on model or face
|
||||
MESH_OPTIMIZER_COMBINE,
|
||||
MESH_OPTIMIZER,
|
||||
MESH_OPTIMIZER_SLOPPY,
|
||||
USE_LOD_ABOVE,
|
||||
} eLoDMode;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LIMIT_TRIANGLES = 0,
|
||||
LIMIT_ERROR_TRESHOLD,
|
||||
} eLoDLimit;
|
||||
|
||||
public:
|
||||
// Todo: model preview shouldn't need floater dependency, it
|
||||
// should just expose data to floater, not control flaoter like it does
|
||||
|
|
@ -155,7 +164,7 @@ public:
|
|||
void loadModelCallback(S32 lod);
|
||||
bool lodsReady() { return !mGenLOD && mLodsQuery.empty(); }
|
||||
void queryLODs() { mGenLOD = true; };
|
||||
void genLODs(S32 which_lod = -1, U32 decimation = 3, bool enforce_tri_limit = false);
|
||||
void genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 decimation = 3, bool enforce_tri_limit = false);
|
||||
void generateNormals();
|
||||
void restoreNormals();
|
||||
U32 calcResourceCost();
|
||||
|
|
@ -165,8 +174,7 @@ public:
|
|||
void clearIncompatible(S32 lod);
|
||||
void updateStatusMessages();
|
||||
void updateLodControls(S32 lod);
|
||||
void clearGLODGroup();
|
||||
void onLODParamCommit(S32 lod, bool enforce_tri_limit);
|
||||
void onLODMeshOptimizerParamCommit(S32 lod, bool enforce_tri_limit, S32 mode);
|
||||
void addEmptyFace(LLModel* pTarget);
|
||||
|
||||
const bool getModelPivot(void) const { return mHasPivot; }
|
||||
|
|
@ -218,6 +226,10 @@ private:
|
|||
// Count amount of original models, excluding sub-models
|
||||
static U32 countRootModels(LLModelLoader::model_list models);
|
||||
|
||||
// functions for meshoptimizer, return reached simplification ratio
|
||||
F32 genMeshOptimizerPerModel(LLModel *base_model, LLModel *target_model, F32 indices_ratio, F32 error_threshold, bool sloppy);
|
||||
F32 genMeshOptimizerPerFace(LLModel *base_model, LLModel *target_model, U32 face_idx, F32 indices_ratio, F32 error_threshold, bool sloppy);
|
||||
|
||||
protected:
|
||||
friend class LLModelLoader;
|
||||
friend class LLFloaterModelPreview;
|
||||
|
|
@ -249,19 +261,11 @@ protected:
|
|||
|
||||
std::map<std::string, bool> mViewOption;
|
||||
|
||||
//GLOD object parameters (must rebuild object if these change)
|
||||
// Model generation parameters (must rebuild object if these change)
|
||||
bool mLODFrozen;
|
||||
F32 mBuildShareTolerance;
|
||||
U32 mBuildQueueMode;
|
||||
U32 mBuildOperator;
|
||||
U32 mBuildBorderMode;
|
||||
U32 mRequestedLoDMode[LLModel::NUM_LODS];
|
||||
S32 mRequestedTriangleCount[LLModel::NUM_LODS];
|
||||
F32 mRequestedErrorThreshold[LLModel::NUM_LODS];
|
||||
U32 mRequestedBuildOperator[LLModel::NUM_LODS];
|
||||
U32 mRequestedQueueMode[LLModel::NUM_LODS];
|
||||
U32 mRequestedBorderMode[LLModel::NUM_LODS];
|
||||
F32 mRequestedShareTolerance[LLModel::NUM_LODS];
|
||||
F32 mRequestedCreaseAngle[LLModel::NUM_LODS];
|
||||
|
||||
LLModelLoader* mModelLoader;
|
||||
|
|
@ -280,8 +284,14 @@ protected:
|
|||
|
||||
U32 mGroup;
|
||||
std::map<LLPointer<LLModel>, U32> mObject;
|
||||
|
||||
// Amount of triangles in original(base) model
|
||||
U32 mMaxTriangleLimit;
|
||||
|
||||
// Minimum amount of allowed triangles in lod for spin cntrl.
|
||||
// Leave at least one triangle per model.
|
||||
S32 mMinTriangleLimit;
|
||||
|
||||
LLMeshUploadThread::instance_list mUploadData;
|
||||
std::set<LLViewerFetchedTexture * > mTextureSet;
|
||||
|
||||
|
|
|
|||
|
|
@ -101,11 +101,11 @@ Dummy Name replaced at run time
|
|||
expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd.
|
||||
FreeType Copyright (C) 1996-2002, 2006 David Turner, Robert Wilhelm, and Werner Lemberg.
|
||||
GL Copyright (C) 1999-2004 Brian Paul.
|
||||
GLOD Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University and David Luebke, Brenden Schubert, University of Virginia.
|
||||
google-perftools Copyright (c) 2005, Google Inc.
|
||||
Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited.
|
||||
jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW)
|
||||
jpeglib Copyright (C) 1991-1998, Thomas G. Lane.
|
||||
meshoptimizer Copyright (c) 2016-2021 Arseny Kapoulkine
|
||||
ogg/vorbis Copyright (C) 2002, Xiphophorus
|
||||
OpenSSL Copyright (C) 1998-2008 The OpenSSL Project.
|
||||
PCRE Copyright (c) 1997-2012 University of Cambridge
|
||||
|
|
|
|||
|
|
@ -45,7 +45,21 @@
|
|||
<string name="UnrecognizedJoint">Rigged to unrecognized joint name [NAME]</string>
|
||||
<string name="UnknownJoints">Skinning disabled due to [COUNT] unknown joints</string>
|
||||
<string name="ModelLoaded">Model [MODEL_NAME] loaded</string>
|
||||
|
||||
<string name="IncompleteTC">Texture coordinates data is not complete.</string>
|
||||
<string name="PositionNaN">Found NaN while loading position data from DAE-Model, invalid model.</string>
|
||||
<string name="NormalsNaN">Found NaN while loading normals from DAE-Model, invalid model.</string>
|
||||
<string name="NegativeScaleTrans">Negative scale detected, unsupported transform. domInstance_geometry: [LABEL]</string>
|
||||
<string name="NegativeScaleNormTrans">Negative scale detected, unsupported post-normalization transform. domInstance_geometry: [LABEL]</string>
|
||||
<string name="CantResolveGeometryUrl">Unable to resolve geometry URL.</string>
|
||||
<string name="ParsingErrorBadElement">Bad element</string>
|
||||
<string name="ParsingErrorCantParseScene">Scene could not be parsed</string>
|
||||
<string name="ParsingErrorCorrupt">Error with dae - traditionally indicates a corrupt file.</string>
|
||||
<string name="ParsingErrorNoController">Could not verify controller</string>
|
||||
<string name="ParsingErrorNoDoc">Can't find internal doc</string>
|
||||
<string name="ParsingErrorNoRoot">Document has no root</string>
|
||||
<string name="ParsingErrorNoScene">Document has no visual_scene</string>
|
||||
<string name="ParsingErrorPositionInvalidModel">Unable to process mesh without position data. Invalid model.</string>
|
||||
|
||||
<panel
|
||||
follows="top|left"
|
||||
|
|
@ -173,9 +187,21 @@
|
|||
label="Load from file"
|
||||
value="Load from file" />
|
||||
<item
|
||||
name="Generate"
|
||||
label="Generate"
|
||||
value="Generate" />
|
||||
name="MeshOpt Auto"
|
||||
label="Generate Auto"
|
||||
value="MeshOpt Auto" />
|
||||
<item
|
||||
name="MeshOptCombine"
|
||||
label="Generate Precise"
|
||||
value="MeshOptCombine" />
|
||||
<item
|
||||
name="MeshOpt"
|
||||
label="Generate per face"
|
||||
value="MeshOpt" />
|
||||
<item
|
||||
name="MeshOptSloppy"
|
||||
label="Generate Sloppy"
|
||||
value="MeshOptSloppy" />
|
||||
</combo_box>
|
||||
<line_editor
|
||||
follows="left|top"
|
||||
|
|
@ -302,9 +328,21 @@
|
|||
label="Load from file"
|
||||
value="Load from file" />
|
||||
<item
|
||||
name="Generate"
|
||||
label="Generate"
|
||||
value="Generate" />
|
||||
name="MeshOpt Auto"
|
||||
label="Generate Auto"
|
||||
value="MeshOpt Auto" />
|
||||
<item
|
||||
name="MeshOptCombine"
|
||||
label="Generate Precise"
|
||||
value="MeshOptCombine" />
|
||||
<item
|
||||
name="MeshOpt"
|
||||
label="Generate per face"
|
||||
value="MeshOpt" />
|
||||
<item
|
||||
name="MeshOptSloppy"
|
||||
label="Generate Sloppy"
|
||||
value="MeshOptSloppy" />
|
||||
<item
|
||||
name="Use LoD above"
|
||||
label="Use LoD above"
|
||||
|
|
@ -435,9 +473,21 @@
|
|||
label="Load from file"
|
||||
value="Load from file" />
|
||||
<item
|
||||
name="Generate"
|
||||
label="Generate"
|
||||
value="Generate" />
|
||||
name="MeshOpt Auto"
|
||||
label="Generate Auto"
|
||||
value="MeshOpt Auto" />
|
||||
<item
|
||||
name="MeshOptCombine"
|
||||
label="Generate Precise"
|
||||
value="MeshOptCombine" />
|
||||
<item
|
||||
name="MeshOpt"
|
||||
label="Generate per face"
|
||||
value="MeshOpt" />
|
||||
<item
|
||||
name="MeshOptSloppy"
|
||||
label="Generate Sloppy"
|
||||
value="MeshOptSloppy" />
|
||||
<item
|
||||
name="Use LoD above"
|
||||
label="Use LoD above"
|
||||
|
|
@ -568,9 +618,21 @@
|
|||
label="Load from file"
|
||||
value="Load from file" />
|
||||
<item
|
||||
name="Generate"
|
||||
label="Generate"
|
||||
value="Generate" />
|
||||
name="MeshOpt Auto"
|
||||
label="Generate Auto"
|
||||
value="MeshOpt Auto" />
|
||||
<item
|
||||
name="MeshOptCombine"
|
||||
label="Generate Precise"
|
||||
value="MeshOptCombine" />
|
||||
<item
|
||||
name="MeshOpt"
|
||||
label="Generate per face"
|
||||
value="MeshOpt" />
|
||||
<item
|
||||
name="MeshOptSloppy"
|
||||
label="Generate Sloppy"
|
||||
value="MeshOptSloppy" />
|
||||
<item
|
||||
name="Use LoD above"
|
||||
label="Use LoD above"
|
||||
|
|
|
|||
|
|
@ -510,14 +510,6 @@ class WindowsManifest(ViewerManifest):
|
|||
# Get shared libs from the shared libs staging directory
|
||||
with self.prefix(src=os.path.join(self.args['build'], os.pardir,
|
||||
'sharedlibs', self.args['configuration'])):
|
||||
|
||||
# Mesh 3rd party libs needed for auto LOD and collada reading
|
||||
try:
|
||||
self.path("glod.dll")
|
||||
except RuntimeError as err:
|
||||
print err.message
|
||||
print "Skipping GLOD library (assumming linked statically)"
|
||||
|
||||
# Get fmodstudio dll if needed
|
||||
if self.args['fmodstudio'] == 'ON':
|
||||
if(self.args['configuration'].lower() == 'debug'):
|
||||
|
|
@ -1029,7 +1021,6 @@ class DarwinManifest(ViewerManifest):
|
|||
"libapr-1.0.dylib",
|
||||
"libaprutil-1.0.dylib",
|
||||
"libexpat.1.dylib",
|
||||
"libGLOD.dylib",
|
||||
# libnghttp2.dylib is a symlink to
|
||||
# libnghttp2.major.dylib, which is a symlink to
|
||||
# libnghttp2.version.dylib. Get all of them.
|
||||
|
|
@ -1475,7 +1466,6 @@ class Linux_i686_Manifest(LinuxManifest):
|
|||
self.path("libaprutil-1.so.0.4.1")
|
||||
self.path("libdb*.so")
|
||||
self.path("libexpat.so.*")
|
||||
self.path("libGLOD.so")
|
||||
self.path("libuuid.so*")
|
||||
self.path("libSDL-1.2.so.*")
|
||||
self.path("libdirectfb-1.*.so.*")
|
||||
|
|
|
|||
Loading…
Reference in New Issue