Merge branch 'master' into deprecated_gltfpbr_macros

pull/4203/head
RichardTea 2022-03-01 10:01:43 +00:00
commit d704824be3
54 changed files with 959 additions and 768 deletions

View File

@ -1,67 +0,0 @@
#---------------------------------------------------------------------------
#Open Asset Import Library (assimp)
#---------------------------------------------------------------------------
# Copyright (c) 2006-2020, assimp team
#
# License see LICENSE file
#
function generate() {
OPTIONS="-DASSIMP_WERROR=ON"
OPTIONS="$OPTIONS -DASSIMP_NO_EXPORT=NO"
if [ "$DISABLE_EXPORTERS" = "YES" ] ; then
OPTIONS="$OPTIONS -DASSIMP_NO_EXPORT=YES"
else
OPTIONS="$OPTIONS -DASSIMP_NO_EXPORT=NO"
fi
if [ "$SHARED_BUILD" = "ON" ] ; then
OPTIONS="$OPTIONS -DBUILD_SHARED_LIBS=ON"
else
OPTIONS="$OPTIONS -DBUILD_SHARED_LIBS=OFF"
fi
if [ "$ENABLE_COVERALLS" = "ON" ] ; then
OPTIONS="$OPTIONS -DASSIMP_COVERALLS=ON"
else
OPTIONS="$OPTIONS -DASSIMP_COVERALLS=OFF"
fi
if [ "$ASAN" = "ON" ] ; then
OPTIONS="$OPTIONS -DASSIMP_ASAN=ON"
else
OPTIONS="$OPTIONS -DASSIMP_ASAN=OFF"
fi
if [ "$UBSAN" = "ON" ] ; then
OPTIONS="$OPTIONS -DASSIMP_UBSAN=ON"
fi
cmake -G "Unix Makefiles" $OPTIONS
}
# build and run unittests, if not android
if [ $ANDROID ]; then
ant -v -Dmy.dir=${TRAVIS_BUILD_DIR} -f ${TRAVIS_BUILD_DIR}/port/jassimp/build.xml ndk-jni
fi
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
if [ $ANALYZE = "ON" ] ; then
if [ "$CC" = "clang" ]; then
scan-build cmake -G "Unix Makefiles" -DBUILD_SHARED_LIBS=OFF -DASSIMP_BUILD_TESTS=OFF
scan-build --status-bugs make -j2
else
cppcheck --version
generate \
&& cppcheck --error-exitcode=1 -j2 -Iinclude -Icode code 2> cppcheck.txt
if [ -s cppcheck.txt ]; then
cat cppcheck.txt
exit 1
fi
fi
else
generate \
&& make -j4 \
&& sudo make install \
&& sudo ldconfig \
&& (cd test/unit; ../../bin/unit)
fi
fi

View File

@ -1,78 +0,0 @@
sudo: required
language: cpp
cache: ccache
before_install:
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get update -qq && sudo apt-get install cmake cppcheck && sudo apt-get install cmake python3 && sudo apt-get install -qq freeglut3-dev libxmu-dev libxi-dev ; echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca- ; fi
- 'if [ "$TRAVIS_OS_NAME" = "osx" ]; then
if brew ls --versions cmake > /dev/null; then
echo cmake already installed.;
else
brew install cmake;
fi;
brew install python3;
brew install homebrew/x11/freeglut;
fi'
- echo -e "#ifndef A_R_H_INC\n#define A_R_H_INC\n#define GitVersion ${TRAVIS_JOB_ID}\n#define GitBranch \"${TRAVIS_BRANCH}\"\n#endif // A_R_H_INC" > revision.h
# install latest LCOV (1.9 was failing)
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then cd ${TRAVIS_BUILD_DIR} && wget http://ftp.de.debian.org/debian/pool/main/l/lcov/lcov_1.11.orig.tar.gz && tar xf lcov_1.11.orig.tar.gz && sudo make -C lcov-1.11/ install && gem install coveralls-lcov && lcov --version && g++ --version ; fi
os:
- linux
compiler:
- gcc
- clang
env:
global:
- secure: "lZ7pHQvl5dpZWzBQAaIMf0wqrvtcZ4wiZKeIZjf83TEsflW8+z0uTpIuN30ZV6Glth/Sq1OhLnTP5+N57fZU/1ebA5twHdvP4bS5CIUUg71/CXQZNl36xeaqvxsG/xRrdpKOsPdjAOsQ9KPTQulsX43XDLS7CasMiLvYOpqKcPc="
- PV=r8e PLATF=linux-x86_64 NDK_HOME=${TRAVIS_BUILD_DIR}/android-ndk-${PV} PATH=${PATH}:${NDK_HOME}
git:
depth: 1
matrix:
include:
- os: linux
compiler: clang
env: ASAN=ON
- os: linux
compiler: clang
env: UBSAN=ON
- os: linux
compiler: clang
env: SHARED_BUILD=ON
- os: linux
compiler: gcc
env: ANALYZE=ON
- os: linux
compiler: gcc
env: ENABLE_COVERALLS=ON
- os: linux
compiler: gcc
env: SHARED_BUILD=ON
install:
- if [ $ANDROID ]; then wget -c http://dl.google.com/android/ndk/android-ndk-${PV}-${PLATF}.tar.bz2 && tar xf android-ndk-${PV}-${PLATF}.tar.bz2 ; fi
before_script:
cmake . -DASSIMP_ENABLE_BOOST_WORKAROUND=YES
script:
- export COVERALLS_SERVICE_NAME=travis-ci
- export COVERALLS_REPO_TOKEN=abc12345
- . ./.travis.sh
after_success:
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then cd ${TRAVIS_BUILD_DIR} && lcov --directory . --capture --output-file coverage.info && lcov --remove coverage.info '/usr/*' 'contrib/*' 'test/*' --output-file coverage.info && lcov --list coverage.info && coveralls-lcov --source-encoding=ISO-8859-1 --repo-token=${COVERALLS_TOKEN} coverage.info ; fi
addons:
coverity_scan:
project:
name: "assimp/assimp"
notification_email: kim.kulling@googlemail.com
build_command_prepend: "cmake ./"
build_command: "make -j4"
branch_pattern: coverity_scan

View File

@ -10,16 +10,15 @@
:: Also see: https://github.com/assimp/assimp/pull/2646 :: Also see: https://github.com/assimp/assimp/pull/2646
SET SOURCE_DIR=. SET SOURCE_DIR=.
SET GENERATOR=Visual Studio 16 2019
:: For generators see "cmake --help" SET BINARIES_DIR="./build/Win32"
SET GENERATOR=Visual Studio 15 2017 cmake . -G "%GENERATOR%" -A Win32 -S %SOURCE_DIR% -B %BINARIES_DIR%
cmake --build %BINARIES_DIR% --config debug
SET BINARIES_DIR="./BINARIES/Win32"
cmake CMakeLists.txt -G "%GENERATOR%" -S %SOURCE_DIR% -B %BINARIES_DIR%
cmake --build %BINARIES_DIR% --config release cmake --build %BINARIES_DIR% --config release
SET BINARIES_DIR="./BINARIES/x64" SET BINARIES_DIR="./build/x64"
cmake CMakeLists.txt -G "%GENERATOR% Win64" -S %SOURCE_DIR% -B %BINARIES_DIR% cmake . -G "%GENERATOR%" -A x64 -S %SOURCE_DIR% -B %BINARIES_DIR%
cmake --build %BINARIES_DIR% --config debug cmake --build %BINARIES_DIR% --config debug
cmake --build %BINARIES_DIR% --config release cmake --build %BINARIES_DIR% --config release

View File

@ -49,14 +49,14 @@ option(ASSIMP_HUNTER_ENABLED "Enable Hunter package manager support" OFF)
IF(ASSIMP_HUNTER_ENABLED) IF(ASSIMP_HUNTER_ENABLED)
include("cmake-modules/HunterGate.cmake") include("cmake-modules/HunterGate.cmake")
HunterGate( HunterGate(
URL "https://github.com/cpp-pm/hunter/archive/v0.23.311.tar.gz" URL "https://github.com/cpp-pm/hunter/archive/v0.24.0.tar.gz"
SHA1 "1a82b9b73055879181cb1466b2ab5d48ee8ae410" SHA1 "a3d7f4372b1dcd52faa6ff4a3bd5358e1d0e5efd"
) )
add_definitions(-DASSIMP_USE_HUNTER) add_definitions(-DASSIMP_USE_HUNTER)
ENDIF() ENDIF()
PROJECT(Assimp VERSION 5.1.6) PROJECT(Assimp VERSION 5.2.0)
# All supported options ############################################### # All supported options ###############################################
@ -134,12 +134,12 @@ OPTION ( ASSIMP_IGNORE_GIT_HASH
OFF OFF
) )
IF ( WIN32 ) IF (WIN32)
# Use subset of Windows.h # Use subset of Windows.h
ADD_DEFINITIONS( -DWIN32_LEAN_AND_MEAN ) ADD_DEFINITIONS( -DWIN32_LEAN_AND_MEAN )
IF(MSVC) IF(MSVC)
OPTION ( ASSIMP_BUILD_ASSIMP_VIEW OPTION (ASSIMP_BUILD_ASSIMP_VIEW
"If the Assimp view tool is built. (requires DirectX)" "If the Assimp view tool is built. (requires DirectX)"
OFF ) OFF )
@ -243,6 +243,13 @@ SET(ASSIMP_LIBRARY_SUFFIX "" CACHE STRING "Suffix to append to library names")
IF( UNIX ) IF( UNIX )
# Use GNUInstallDirs for Unix predefined directories # Use GNUInstallDirs for Unix predefined directories
INCLUDE(GNUInstallDirs) INCLUDE(GNUInstallDirs)
# Ensure that we do not run into issues like http://www.tcm.phy.cam.ac.uk/sw/inodes64.html on 32 bit linux
IF( ${OPERATING_SYSTEM} MATCHES "Android")
ELSE()
IF ( CMAKE_SIZEOF_VOID_P EQUAL 4) # only necessary for 32-bit linux
ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64 )
ENDIF()
ENDIF()
ENDIF() ENDIF()
# Grouped compiler settings ######################################## # Grouped compiler settings ########################################
@ -341,9 +348,24 @@ INCLUDE (FindPkgMacros)
INCLUDE (PrecompiledHeader) INCLUDE (PrecompiledHeader)
# Set Assimp project output directory variables. # Set Assimp project output directory variables.
SET(ASSIMP_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin" CACHE STRING "Path for runtime output files") # Will respect top-level CMAKE_*_OUTPUT_DIRECTORY variables if any are set.
SET(ASSIMP_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin" CACHE STRING "Path for library output files") IF(NOT DEFINED CMAKE_RUNTIME_OUTPUT_DIRECTORY)
SET(ASSIMP_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib" CACHE STRING "Path for archive output files") SET(ASSIMP_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin" CACHE STRING "Path for runtime output files")
ELSE()
SET(ASSIMP_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} CACHE STRING "Path for runtime output files")
ENDIF()
IF(NOT DEFINED CMAKE_LIBRARY_OUTPUT_DIRECTORY)
SET(ASSIMP_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin" CACHE STRING "Path for library output files")
ELSE()
SET(ASSIMP_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} CACHE STRING "Path for runtime output files")
ENDIF()
IF(NOT DEFINED CMAKE_ARCHIVE_OUTPUT_DIRECTORY)
SET(ASSIMP_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib" CACHE STRING "Path for library output files")
ELSE()
SET(ASSIMP_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY} CACHE STRING "Path for runtime output files")
ENDIF()
# Macro used to set the output directories of a target to the # Macro used to set the output directories of a target to the
# respective Assimp output directories. # respective Assimp output directories.
@ -672,11 +694,13 @@ ENDIF()
ADD_SUBDIRECTORY( code/ ) ADD_SUBDIRECTORY( code/ )
IF ( ASSIMP_BUILD_ASSIMP_TOOLS ) IF ( ASSIMP_BUILD_ASSIMP_TOOLS )
# The viewer for windows only # The viewer for windows only
IF ( WIN32 ) IF (WIN32)
OPTION ( ASSIMP_BUILD_ASSIMP_VIEW "If the Assimp view tool is built. (requires DirectX)" OFF ) OPTION ( ASSIMP_BUILD_ASSIMP_VIEW "If the Assimp view tool is built. (requires DirectX)" OFF )
IF ( ASSIMP_BUILD_ASSIMP_VIEW ) IF ( ASSIMP_BUILD_ASSIMP_VIEW )
ADD_SUBDIRECTORY( tools/assimp_view/ ) ADD_SUBDIRECTORY( tools/assimp_view/ )
ENDIF () ENDIF ()
ELSE()
MESSAGE("Building Assimp Viewer only supported on Windows.")
ENDIF () ENDIF ()
# The command line tool # The command line tool
ADD_SUBDIRECTORY( tools/assimp_cmd/ ) ADD_SUBDIRECTORY( tools/assimp_cmd/ )

View File

@ -112,6 +112,7 @@ using namespace Assimp::ASE;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Parser::Parser(const char *szFile, unsigned int fileFormatDefault) { Parser::Parser(const char *szFile, unsigned int fileFormatDefault) {
ai_assert(nullptr != szFile); ai_assert(nullptr != szFile);
filePtr = szFile; filePtr = szFile;
iFileFormat = fileFormatDefault; iFileFormat = fileFormatDefault;
@ -486,7 +487,7 @@ void Parser::ParseLV1MaterialListBlock() {
ParseLV4MeshLong(iIndex); ParseLV4MeshLong(iIndex);
if (iIndex >= iMaterialCount) { if (iIndex >= iMaterialCount) {
LogError("Out of range: material index is too large"); LogWarning("Out of range: material index is too large");
iIndex = iMaterialCount - 1; iIndex = iMaterialCount - 1;
return; return;
} }
@ -905,7 +906,6 @@ void Parser::ParseLV2LightSettingsBlock(ASE::Light &light) {
} }
AI_ASE_HANDLE_SECTION("2", "LIGHT_SETTINGS"); AI_ASE_HANDLE_SECTION("2", "LIGHT_SETTINGS");
} }
return;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -1782,7 +1782,9 @@ void Parser::ParseLV4MeshFace(ASE::Face &out) {
// *MESH_MTLID is optional, too // *MESH_MTLID is optional, too
while (true) { while (true) {
if ('*' == *filePtr) break; if ('*' == *filePtr) {
break;
}
if (IsLineEnd(*filePtr)) { if (IsLineEnd(*filePtr)) {
return; return;
} }
@ -1831,8 +1833,9 @@ void Parser::ParseLV4MeshFloatTriple(ai_real *apOut, unsigned int &rIndexOut) {
void Parser::ParseLV4MeshFloatTriple(ai_real *apOut) { void Parser::ParseLV4MeshFloatTriple(ai_real *apOut) {
ai_assert(nullptr != apOut); ai_assert(nullptr != apOut);
for (unsigned int i = 0; i < 3; ++i) for (unsigned int i = 0; i < 3; ++i) {
ParseLV4MeshFloat(apOut[i]); ParseLV4MeshFloat(apOut[i]);
}
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Parser::ParseLV4MeshFloat(ai_real &fOut) { void Parser::ParseLV4MeshFloat(ai_real &fOut) {

View File

@ -182,6 +182,8 @@ inline size_t Write<aiVertexWeight>(IOStream *stream, const aiVertexWeight &v) {
return t + Write<float>(stream, v.mWeight); return t + Write<float>(stream, v.mWeight);
} }
constexpr size_t MatrixSize = 64;
// ----------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------
// Serialize a mat4x4 // Serialize a mat4x4
template <> template <>
@ -192,7 +194,7 @@ inline size_t Write<aiMatrix4x4>(IOStream *stream, const aiMatrix4x4 &m) {
} }
} }
return 64; return MatrixSize;
} }
// ----------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------

View File

@ -66,11 +66,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// zlib is needed for compressed blend files // zlib is needed for compressed blend files
#ifndef ASSIMP_BUILD_NO_COMPRESSED_BLEND #ifndef ASSIMP_BUILD_NO_COMPRESSED_BLEND
# ifdef ASSIMP_BUILD_NO_OWN_ZLIB #include "Common/Compression.h"
/* #ifdef ASSIMP_BUILD_NO_OWN_ZLIB
# include <zlib.h> # include <zlib.h>
# else # else
# include "../contrib/zlib/zlib.h" # include "../contrib/zlib/zlib.h"
# endif # endif*/
#endif #endif
namespace Assimp { namespace Assimp {
@ -141,7 +142,7 @@ void BlenderImporter::SetupProperties(const Importer * /*pImp*/) {
void BlenderImporter::InternReadFile(const std::string &pFile, void BlenderImporter::InternReadFile(const std::string &pFile,
aiScene *pScene, IOSystem *pIOHandler) { aiScene *pScene, IOSystem *pIOHandler) {
#ifndef ASSIMP_BUILD_NO_COMPRESSED_BLEND #ifndef ASSIMP_BUILD_NO_COMPRESSED_BLEND
std::vector<Bytef> uncompressed; std::vector<char> uncompressed;
#endif #endif
FileDatabase file; FileDatabase file;
@ -159,7 +160,6 @@ void BlenderImporter::InternReadFile(const std::string &pFile,
#ifdef ASSIMP_BUILD_NO_COMPRESSED_BLEND #ifdef ASSIMP_BUILD_NO_COMPRESSED_BLEND
ThrowException("BLENDER magic bytes are missing, is this file compressed (Assimp was built without decompression support)?"); ThrowException("BLENDER magic bytes are missing, is this file compressed (Assimp was built without decompression support)?");
#else #else
if (magic[0] != 0x1f || static_cast<uint8_t>(magic[1]) != 0x8b) { if (magic[0] != 0x1f || static_cast<uint8_t>(magic[1]) != 0x8b) {
ThrowException("BLENDER magic bytes are missing, couldn't find GZIP header either"); ThrowException("BLENDER magic bytes are missing, couldn't find GZIP header either");
} }
@ -173,42 +173,12 @@ void BlenderImporter::InternReadFile(const std::string &pFile,
stream->Seek(0L, aiOrigin_SET); stream->Seek(0L, aiOrigin_SET);
std::shared_ptr<StreamReaderLE> reader = std::shared_ptr<StreamReaderLE>(new StreamReaderLE(stream)); std::shared_ptr<StreamReaderLE> reader = std::shared_ptr<StreamReaderLE>(new StreamReaderLE(stream));
// build a zlib stream size_t total = 0;
z_stream zstream; Compression compression;
zstream.opaque = Z_NULL; if (compression.open(Compression::Format::Binary, Compression::FlushMode::NoFlush, 16 + Compression::MaxWBits)) {
zstream.zalloc = Z_NULL; total = compression.decompress((unsigned char *)reader->GetPtr(), reader->GetRemainingSize(), uncompressed);
zstream.zfree = Z_NULL; compression.close();
zstream.data_type = Z_BINARY; }
// http://hewgill.com/journal/entries/349-how-to-decompress-gzip-stream-with-zlib
inflateInit2(&zstream, 16 + MAX_WBITS);
zstream.next_in = reinterpret_cast<Bytef *>(reader->GetPtr());
zstream.avail_in = (uInt)reader->GetRemainingSize();
size_t total = 0l;
// TODO: be smarter about this, decompress directly into heap buffer
// and decompress the data .... do 1k chunks in the hope that we won't kill the stack
#define MYBLOCK 1024
Bytef block[MYBLOCK];
int ret;
do {
zstream.avail_out = MYBLOCK;
zstream.next_out = block;
ret = inflate(&zstream, Z_NO_FLUSH);
if (ret != Z_STREAM_END && ret != Z_OK) {
ThrowException("Failure decompressing this file using gzip, seemingly it is NOT a compressed .BLEND file");
}
const size_t have = MYBLOCK - zstream.avail_out;
total += have;
uncompressed.resize(total);
memcpy(uncompressed.data() + total - have, block, have);
} while (ret != Z_STREAM_END);
// terminate zlib
inflateEnd(&zstream);
// replace the input stream with a memory stream // replace the input stream with a memory stream
stream.reset(new MemoryIOStream(reinterpret_cast<uint8_t *>(uncompressed.data()), total)); stream.reset(new MemoryIOStream(reinterpret_cast<uint8_t *>(uncompressed.data()), total));

View File

@ -357,9 +357,9 @@ void ColladaLoader::BuildLightsForNode(const ColladaParser &pParser, const Node
out->mAngleInnerCone = AI_DEG_TO_RAD(srcLight->mFalloffAngle); out->mAngleInnerCone = AI_DEG_TO_RAD(srcLight->mFalloffAngle);
// ... some extension magic. // ... some extension magic.
if (srcLight->mOuterAngle >= ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET * (1 - 1e-6f)) { if (srcLight->mOuterAngle >= ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET * (1 - ai_epsilon)) {
// ... some deprecation magic. // ... some deprecation magic.
if (srcLight->mPenumbraAngle >= ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET * (1 - 1e-6f)) { if (srcLight->mPenumbraAngle >= ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET * (1 - ai_epsilon)) {
// Need to rely on falloff_exponent. I don't know how to interpret it, so I need to guess .... // Need to rely on falloff_exponent. I don't know how to interpret it, so I need to guess ....
// epsilon chosen to be 0.1 // epsilon chosen to be 0.1
float f = 1.0f; float f = 1.0f;
@ -1065,7 +1065,7 @@ void insertMorphTimeValue(std::vector<MorphTimeValues> &values, float time, floa
return; return;
} }
for (unsigned int i = 0; i < values.size(); i++) { for (unsigned int i = 0; i < values.size(); i++) {
if (std::abs(time - values[i].mTime) < 1e-6f) { if (std::abs(time - values[i].mTime) < ai_epsilon) {
values[i].mKeys.push_back(k); values[i].mKeys.push_back(k);
return; return;
} else if (time > values[i].mTime && time < values[i + 1].mTime) { } else if (time > values[i].mTime && time < values[i + 1].mTime) {

View File

@ -80,8 +80,10 @@ enum TransformInheritance {
TransformInheritance_MAX // end-of-enum sentinel TransformInheritance_MAX // end-of-enum sentinel
}; };
} // namespace FBX } // namespace FBX
} // namespace Assimp } // namespace Assimp
#endif // ASSIMP_BUILD_NO_FBX_EXPORTER #endif // ASSIMP_BUILD_NO_FBX_EXPORTER
#endif // AI_FBXCOMMON_H_INC #endif // AI_FBXCOMMON_H_INC

View File

@ -653,7 +653,7 @@ bool FBXConverter::NeedsComplexTransformationChain(const Model &model) {
const PropertyTable &props = model.Props(); const PropertyTable &props = model.Props();
bool ok; bool ok;
const float zero_epsilon = 1e-6f; const float zero_epsilon = ai_epsilon;
const aiVector3D all_ones(1.0f, 1.0f, 1.0f); const aiVector3D all_ones(1.0f, 1.0f, 1.0f);
for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) { for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) {
const TransformationComp comp = static_cast<TransformationComp>(i); const TransformationComp comp = static_cast<TransformationComp>(i);
@ -1267,7 +1267,7 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co
const std::vector<aiVector3D> &normals = mesh.GetNormals(); const std::vector<aiVector3D> &normals = mesh.GetNormals();
if (normals.size()) { if (normals.size()) {
ai_assert(normals.size() == vertices.size()); ai_assert(normals.size() == vertices.size());
out_mesh->mNormals = new aiVector3D[vertices.size()]; out_mesh->mNormals = new aiVector3D[count_vertices];
} }
// allocate tangents, binormals. // allocate tangents, binormals.
@ -1295,8 +1295,8 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co
ai_assert(tangents.size() == vertices.size()); ai_assert(tangents.size() == vertices.size());
ai_assert(binormals->size() == vertices.size()); ai_assert(binormals->size() == vertices.size());
out_mesh->mTangents = new aiVector3D[vertices.size()]; out_mesh->mTangents = new aiVector3D[count_vertices];
out_mesh->mBitangents = new aiVector3D[vertices.size()]; out_mesh->mBitangents = new aiVector3D[count_vertices];
} }
} }
@ -1308,7 +1308,7 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co
break; break;
} }
out_mesh->mTextureCoords[i] = new aiVector3D[vertices.size()]; out_mesh->mTextureCoords[i] = new aiVector3D[count_vertices];
out_mesh->mNumUVComponents[i] = 2; out_mesh->mNumUVComponents[i] = 2;
} }
@ -1320,7 +1320,7 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co
break; break;
} }
out_mesh->mColors[i] = new aiColor4D[vertices.size()]; out_mesh->mColors[i] = new aiColor4D[count_vertices];
} }
unsigned int cursor = 0, in_cursor = 0; unsigned int cursor = 0, in_cursor = 0;
@ -3187,7 +3187,8 @@ aiNodeAnim* FBXConverter::GenerateSimpleNodeAnim(const std::string& name,
} }
bool ok = false; bool ok = false;
const float zero_epsilon = 1e-6f;
const float zero_epsilon = ai_epsilon;
const aiVector3D& preRotation = PropertyGet<aiVector3D>(props, "PreRotation", ok); const aiVector3D& preRotation = PropertyGet<aiVector3D>(props, "PreRotation", ok);
if (ok && preRotation.SquareLength() > zero_epsilon) { if (ok && preRotation.SquareLength() > zero_epsilon) {

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -46,11 +45,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER #ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
#ifdef ASSIMP_BUILD_NO_OWN_ZLIB //#ifdef ASSIMP_BUILD_NO_OWN_ZLIB
# include <zlib.h> #include "Common/Compression.h"
#else //# include <zlib.h>
# include "../contrib/zlib/zlib.h" //#else
#endif //# include "../contrib/zlib/zlib.h"
//#endif
#include "FBXTokenizer.h" #include "FBXTokenizer.h"
#include "FBXParser.h" #include "FBXParser.h"
@ -115,9 +115,7 @@ namespace Assimp {
namespace FBX { namespace FBX {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Element::Element(const Token& key_token, Parser& parser) Element::Element(const Token& key_token, Parser& parser) : key_token(key_token) {
: key_token(key_token)
{
TokenPtr n = nullptr; TokenPtr n = nullptr;
do { do {
n = parser.AdvanceToNextToken(); n = parser.AdvanceToNextToken();
@ -210,8 +208,7 @@ Scope::Scope(Parser& parser,bool topLevel)
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Scope::~Scope() Scope::~Scope() {
{
for(ElementMap::value_type& v : elements) { for(ElementMap::value_type& v : elements) {
delete v.second; delete v.second;
} }
@ -527,9 +524,7 @@ void ReadBinaryDataArrayHead(const char*& data, const char* end, char& type, uin
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// read binary data array, assume cursor points to the 'compression mode' field (i.e. behind the header) // read binary data array, assume cursor points to the 'compression mode' field (i.e. behind the header)
void ReadBinaryDataArray(char type, uint32_t count, const char*& data, const char* end, void ReadBinaryDataArray(char type, uint32_t count, const char*& data, const char* end,
std::vector<char>& buff, std::vector<char>& buff, const Element& /*el*/) {
const Element& /*el*/)
{
BE_NCONST uint32_t encmode = SafeParse<uint32_t>(data, end); BE_NCONST uint32_t encmode = SafeParse<uint32_t>(data, end);
AI_SWAP4(encmode); AI_SWAP4(encmode);
data += 4; data += 4;
@ -571,31 +566,11 @@ void ReadBinaryDataArray(char type, uint32_t count, const char*& data, const cha
else if(encmode == 1) { else if(encmode == 1) {
// zlib/deflate, next comes ZIP head (0x78 0x01) // zlib/deflate, next comes ZIP head (0x78 0x01)
// see http://www.ietf.org/rfc/rfc1950.txt // see http://www.ietf.org/rfc/rfc1950.txt
Compression compress;
z_stream zstream; if (compress.open(Compression::Format::Binary, Compression::FlushMode::Finish, 0)) {
zstream.opaque = Z_NULL; compress.decompress(data, comp_len, buff);
zstream.zalloc = Z_NULL; compress.close();
zstream.zfree = Z_NULL;
zstream.data_type = Z_BINARY;
// http://hewgill.com/journal/entries/349-how-to-decompress-gzip-stream-with-zlib
if(Z_OK != inflateInit(&zstream)) {
ParseError("failure initializing zlib");
} }
zstream.next_in = reinterpret_cast<Bytef*>( const_cast<char*>(data) );
zstream.avail_in = comp_len;
zstream.avail_out = static_cast<uInt>(buff.size());
zstream.next_out = reinterpret_cast<Bytef*>(&*buff.begin());
const int ret = inflate(&zstream, Z_FINISH);
if (ret != Z_STREAM_END && ret != Z_OK) {
ParseError("failure decompressing compressed data section");
}
// terminate zlib
inflateEnd(&zstream);
} }
#ifdef ASSIMP_BUILD_DEBUG #ifdef ASSIMP_BUILD_DEBUG
else { else {
@ -701,7 +676,6 @@ void ParseVectorDataArray(std::vector<aiVector3D>& out, const Element& el)
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// read an array of color4 tuples // read an array of color4 tuples
void ParseVectorDataArray(std::vector<aiColor4D>& out, const Element& el) void ParseVectorDataArray(std::vector<aiColor4D>& out, const Element& el)
@ -786,8 +760,7 @@ void ParseVectorDataArray(std::vector<aiColor4D>& out, const Element& el)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// read an array of float2 tuples // read an array of float2 tuples
void ParseVectorDataArray(std::vector<aiVector2D>& out, const Element& el) void ParseVectorDataArray(std::vector<aiVector2D>& out, const Element& el) {
{
out.resize( 0 ); out.resize( 0 );
const TokenList& tok = el.Tokens(); const TokenList& tok = el.Tokens();
if(tok.empty()) { if(tok.empty()) {
@ -831,8 +804,7 @@ void ParseVectorDataArray(std::vector<aiVector2D>& out, const Element& el)
out.push_back(aiVector2D(static_cast<float>(d[0]), out.push_back(aiVector2D(static_cast<float>(d[0]),
static_cast<float>(d[1]))); static_cast<float>(d[1])));
} }
} } else if (type == 'f') {
else if (type == 'f') {
const float* f = reinterpret_cast<const float*>(&buff[0]); const float* f = reinterpret_cast<const float*>(&buff[0]);
for (unsigned int i = 0; i < count2; ++i, f += 2) { for (unsigned int i = 0; i < count2; ++i, f += 2) {
out.push_back(aiVector2D(f[0],f[1])); out.push_back(aiVector2D(f[0],f[1]));
@ -865,8 +837,7 @@ void ParseVectorDataArray(std::vector<aiVector2D>& out, const Element& el)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// read an array of ints // read an array of ints
void ParseVectorDataArray(std::vector<int>& out, const Element& el) void ParseVectorDataArray(std::vector<int>& out, const Element& el) {
{
out.resize( 0 ); out.resize( 0 );
const TokenList& tok = el.Tokens(); const TokenList& tok = el.Tokens();
if(tok.empty()) { if(tok.empty()) {

View File

@ -275,7 +275,9 @@ void HMPImporter::InternReadFile_HMP7() {
// now load all vertices from the file // now load all vertices from the file
aiVector3D *pcVertOut = pcMesh->mVertices; aiVector3D *pcVertOut = pcMesh->mVertices;
ai_assert(pcVertOut != nullptr);
aiVector3D *pcNorOut = pcMesh->mNormals; aiVector3D *pcNorOut = pcMesh->mNormals;
ai_assert(pcNorOut != nullptr);
const HMP::Vertex_HMP7 *src = (const HMP::Vertex_HMP7 *)szCurrent; const HMP::Vertex_HMP7 *src = (const HMP::Vertex_HMP7 *)szCurrent;
for (unsigned int y = 0; y < height; ++y) { for (unsigned int y = 0; y < height; ++y) {
for (unsigned int x = 0; x < width; ++x) { for (unsigned int x = 0; x < width; ++x) {
@ -327,29 +329,31 @@ void HMPImporter::CreateMaterial(const unsigned char *szCurrent,
// now read the first skin and skip all others // now read the first skin and skip all others
ReadFirstSkin(pcHeader->numskins, szCurrent, &szCurrent); ReadFirstSkin(pcHeader->numskins, szCurrent, &szCurrent);
} else { *szCurrentOut = szCurrent;
// generate a default material return;
const int iMode = (int)aiShadingMode_Gouraud; }
aiMaterial *pcHelper = new aiMaterial();
pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
aiColor3D clr; // generate a default material
clr.b = clr.g = clr.r = 0.6f; const int iMode = (int)aiShadingMode_Gouraud;
pcHelper->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_DIFFUSE); aiMaterial *pcHelper = new aiMaterial();
pcHelper->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_SPECULAR); pcHelper->AddProperty<int>(&iMode, 1, AI_MATKEY_SHADING_MODEL);
clr.b = clr.g = clr.r = 0.05f; aiColor3D clr;
pcHelper->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_AMBIENT); clr.b = clr.g = clr.r = 0.6f;
pcHelper->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_DIFFUSE);
pcHelper->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_SPECULAR);
aiString szName; clr.b = clr.g = clr.r = 0.05f;
szName.Set(AI_DEFAULT_MATERIAL_NAME); pcHelper->AddProperty<aiColor3D>(&clr, 1, AI_MATKEY_COLOR_AMBIENT);
pcHelper->AddProperty(&szName, AI_MATKEY_NAME);
// add the material to the scene aiString szName;
pScene->mNumMaterials = 1; szName.Set(AI_DEFAULT_MATERIAL_NAME);
pScene->mMaterials = new aiMaterial *[1]; pcHelper->AddProperty(&szName, AI_MATKEY_NAME);
pScene->mMaterials[0] = pcHelper;
} // add the material to the scene
pScene->mNumMaterials = 1;
pScene->mMaterials = new aiMaterial *[1];
pScene->mMaterials[0] = pcHelper;
*szCurrentOut = szCurrent; *szCurrentOut = szCurrent;
} }
@ -373,27 +377,36 @@ void HMPImporter::CreateOutputFaceList(unsigned int width, unsigned int height)
aiVector3D *pcUVOut(pcUVs); aiVector3D *pcUVOut(pcUVs);
// Build the terrain square // Build the terrain square
const unsigned int upperBound = pcMesh->mNumVertices;
unsigned int iCurrent = 0; unsigned int iCurrent = 0;
for (unsigned int y = 0; y < height - 1; ++y) { for (unsigned int y = 0; y < height - 1; ++y) {
const size_t offset0 = y * width;
const size_t offset1 = (y + 1) * width;
for (unsigned int x = 0; x < width - 1; ++x, ++pcFaceOut) { for (unsigned int x = 0; x < width - 1; ++x, ++pcFaceOut) {
pcFaceOut->mNumIndices = 4; pcFaceOut->mNumIndices = 4;
pcFaceOut->mIndices = new unsigned int[4]; pcFaceOut->mIndices = new unsigned int[4];
if ((offset0 + x + 1) >= upperBound){
continue;
}
if ((offset1 + x + 1) >= upperBound){
continue;
}
*pcVertOut++ = pcMesh->mVertices[y * width + x]; *pcVertOut++ = pcMesh->mVertices[offset0 + x];
*pcVertOut++ = pcMesh->mVertices[(y + 1) * width + x]; *pcVertOut++ = pcMesh->mVertices[offset1 + x];
*pcVertOut++ = pcMesh->mVertices[(y + 1) * width + x + 1]; *pcVertOut++ = pcMesh->mVertices[offset1 + x + 1];
*pcVertOut++ = pcMesh->mVertices[y * width + x + 1]; *pcVertOut++ = pcMesh->mVertices[offset0 + x + 1];
*pcNorOut++ = pcMesh->mNormals[y * width + x]; *pcNorOut++ = pcMesh->mNormals[offset0 + x];
*pcNorOut++ = pcMesh->mNormals[(y + 1) * width + x]; *pcNorOut++ = pcMesh->mNormals[offset1 + x];
*pcNorOut++ = pcMesh->mNormals[(y + 1) * width + x + 1]; *pcNorOut++ = pcMesh->mNormals[offset1 + x + 1];
*pcNorOut++ = pcMesh->mNormals[y * width + x + 1]; *pcNorOut++ = pcMesh->mNormals[offset0 + x + 1];
if (pcMesh->mTextureCoords[0]) { if (pcMesh->mTextureCoords[0]) {
*pcUVOut++ = pcMesh->mTextureCoords[0][y * width + x]; *pcUVOut++ = pcMesh->mTextureCoords[0][offset0 + x];
*pcUVOut++ = pcMesh->mTextureCoords[0][(y + 1) * width + x]; *pcUVOut++ = pcMesh->mTextureCoords[0][offset1 + x];
*pcUVOut++ = pcMesh->mTextureCoords[0][(y + 1) * width + x + 1]; *pcUVOut++ = pcMesh->mTextureCoords[0][offset1 + x + 1];
*pcUVOut++ = pcMesh->mTextureCoords[0][y * width + x + 1]; *pcUVOut++ = pcMesh->mTextureCoords[0][offset0 + x + 1];
} }
for (unsigned int i = 0; i < 4; ++i) for (unsigned int i = 0; i < 4; ++i)

View File

@ -66,12 +66,12 @@ bool IntersectSegmentPlane(const IfcVector3 &p, const IfcVector3 &n, const IfcVe
// if segment ends on plane, do not report a hit. We stay on that side until a following segment starting at this // if segment ends on plane, do not report a hit. We stay on that side until a following segment starting at this
// point leaves the plane through the other side // point leaves the plane through the other side
if (std::abs(dotOne + dotTwo) < 1e-6) if (std::abs(dotOne + dotTwo) < ai_epsilon)
return false; return false;
// if segment starts on the plane, report a hit only if the end lies on the *other* side // if segment starts on the plane, report a hit only if the end lies on the *other* side
if (std::abs(dotTwo) < 1e-6) { if (std::abs(dotTwo) < ai_epsilon) {
if ((assumeStartOnWhiteSide && dotOne + dotTwo < 1e-6) || (!assumeStartOnWhiteSide && dotOne + dotTwo > -1e-6)) { if ((assumeStartOnWhiteSide && dotOne + dotTwo < ai_epsilon) || (!assumeStartOnWhiteSide && dotOne + dotTwo > -ai_epsilon)) {
out = e0; out = e0;
return true; return true;
} else { } else {
@ -81,7 +81,7 @@ bool IntersectSegmentPlane(const IfcVector3 &p, const IfcVector3 &n, const IfcVe
// ignore if segment is parallel to plane and far away from it on either side // ignore if segment is parallel to plane and far away from it on either side
// Warning: if there's a few thousand of such segments which slowly accumulate beyond the epsilon, no hit would be registered // Warning: if there's a few thousand of such segments which slowly accumulate beyond the epsilon, no hit would be registered
if (std::abs(dotOne) < 1e-6) if (std::abs(dotOne) < ai_epsilon)
return false; return false;
// t must be in [0..1] if the intersection point is within the given segment // t must be in [0..1] if the intersection point is within the given segment
@ -163,7 +163,7 @@ void ProcessBooleanHalfSpaceDifference(const Schema_2x3::IfcHalfSpaceSolid *hs,
for (iit = begin; iit != end; vidx += *iit++) { for (iit = begin; iit != end; vidx += *iit++) {
unsigned int newcount = 0; unsigned int newcount = 0;
bool isAtWhiteSide = (in[vidx] - p) * n > -1e-6; bool isAtWhiteSide = (in[vidx] - p) * n > -ai_epsilon;
for (unsigned int i = 0; i < *iit; ++i) { for (unsigned int i = 0; i < *iit; ++i) {
const IfcVector3 &e0 = in[vidx + i], e1 = in[vidx + (i + 1) % *iit]; const IfcVector3 &e0 = in[vidx + i], e1 = in[vidx + (i + 1) % *iit];
@ -259,7 +259,7 @@ bool IntersectsBoundaryProfile(const IfcVector3 &e0, const IfcVector3 &e1, const
// segment-segment intersection // segment-segment intersection
// solve b0 + b*s = e0 + e*t for (s,t) // solve b0 + b*s = e0 + e*t for (s,t)
const IfcFloat det = (-b.x * e.y + e.x * b.y); const IfcFloat det = (-b.x * e.y + e.x * b.y);
if (std::abs(det) < 1e-6) { if (std::abs(det) < ai_epsilon) {
// no solutions (parallel lines) // no solutions (parallel lines)
continue; continue;
} }
@ -316,7 +316,7 @@ bool IntersectsBoundaryProfile(const IfcVector3 &e0, const IfcVector3 &e1, const
// for a valid intersection, s and t should be in range [0,1]. Including a bit of epsilon on s, potential double // for a valid intersection, s and t should be in range [0,1]. Including a bit of epsilon on s, potential double
// hits on two consecutive boundary segments are filtered // hits on two consecutive boundary segments are filtered
if (s >= -1e-6 * b_sqlen_inv && s <= 1.0 + 1e-6 * b_sqlen_inv && t >= 0.0 && (t <= 1.0 || halfOpen)) { if (s >= -ai_epsilon * b_sqlen_inv && s <= 1.0 + ai_epsilon * b_sqlen_inv && t >= 0.0 && (t <= 1.0 || halfOpen)) {
// only insert the point into the list if it is sufficiently far away from the previous intersection point. // only insert the point into the list if it is sufficiently far away from the previous intersection point.
// This way, we avoid duplicate detection if the intersection is directly on the vertex between two segments. // This way, we avoid duplicate detection if the intersection is directly on the vertex between two segments.
if (!intersect_results.empty() && intersect_results.back().first == i - 1) { if (!intersect_results.empty() && intersect_results.back().first == i - 1) {
@ -431,14 +431,14 @@ void ProcessPolygonalBoundedBooleanHalfSpaceDifference(const Schema_2x3::IfcPoly
// if the poly is parallel to the plane, put it completely on the black or white side // if the poly is parallel to the plane, put it completely on the black or white side
if (std::abs(polyNormal * n) > 0.9999) { if (std::abs(polyNormal * n) > 0.9999) {
bool isOnWhiteSide = (srcVertices[0] - p) * n > -1e-6; bool isOnWhiteSide = (srcVertices[0] - p) * n > -ai_epsilon;
std::vector<IfcVector3> &targetSide = isOnWhiteSide ? whiteside : blackside; std::vector<IfcVector3> &targetSide = isOnWhiteSide ? whiteside : blackside;
targetSide.insert(targetSide.end(), srcVertices, srcVertices + srcVtxCount); targetSide.insert(targetSide.end(), srcVertices, srcVertices + srcVtxCount);
} else { } else {
// otherwise start building one polygon for each side. Whenever the current line segment intersects the plane // otherwise start building one polygon for each side. Whenever the current line segment intersects the plane
// we put a point there as an end of the current segment. Then we switch to the other side, put a point there, too, // we put a point there as an end of the current segment. Then we switch to the other side, put a point there, too,
// as a beginning of the current segment, and simply continue accumulating vertices. // as a beginning of the current segment, and simply continue accumulating vertices.
bool isCurrentlyOnWhiteSide = ((srcVertices[0]) - p) * n > -1e-6; bool isCurrentlyOnWhiteSide = ((srcVertices[0]) - p) * n > -ai_epsilon;
for (size_t a = 0; a < srcVtxCount; ++a) { for (size_t a = 0; a < srcVtxCount; ++a) {
IfcVector3 e0 = srcVertices[a]; IfcVector3 e0 = srcVertices[a];
IfcVector3 e1 = srcVertices[(a + 1) % srcVtxCount]; IfcVector3 e1 = srcVertices[(a + 1) % srcVtxCount];

View File

@ -380,21 +380,19 @@ void ProcessSweptDiskSolid(const Schema_2x3::IfcSweptDiskSolid &solid, TempMesh&
bool take_any = false; bool take_any = false;
for (unsigned int j = 0; j < 2; ++j, take_any = true) { for (unsigned int j = 0; j < 2; ++j, take_any = true) {
if ((last_dir == 0 || take_any) && std::abs(d.x) > 1e-6) { if ((last_dir == 0 || take_any) && std::abs(d.x) > ai_epsilon) {
q.y = startvec.y; q.y = startvec.y;
q.z = startvec.z; q.z = startvec.z;
q.x = -(d.y * q.y + d.z * q.z) / d.x; q.x = -(d.y * q.y + d.z * q.z) / d.x;
last_dir = 0; last_dir = 0;
break; break;
} } else if ((last_dir == 1 || take_any) && std::abs(d.y) > ai_epsilon) {
else if ((last_dir == 1 || take_any) && std::abs(d.y) > 1e-6) {
q.x = startvec.x; q.x = startvec.x;
q.z = startvec.z; q.z = startvec.z;
q.y = -(d.x * q.x + d.z * q.z) / d.y; q.y = -(d.x * q.x + d.z * q.z) / d.y;
last_dir = 1; last_dir = 1;
break; break;
} } else if ((last_dir == 2 && std::abs(d.z) > ai_epsilon) || take_any) {
else if ((last_dir == 2 && std::abs(d.z) > 1e-6) || take_any) {
q.y = startvec.y; q.y = startvec.y;
q.x = startvec.x; q.x = startvec.x;
q.z = -(d.y * q.y + d.x * q.x) / d.z; q.z = -(d.y * q.y + d.x * q.x) / d.z;
@ -529,7 +527,7 @@ IfcMatrix3 DerivePlaneCoordinateSpace(const TempMesh& curmesh, bool& ok, IfcVect
return m; return m;
} }
const auto closeDistance = 1e-6; const auto closeDistance = ai_epsilon;
bool areClose(Schema_2x3::IfcCartesianPoint pt1,Schema_2x3::IfcCartesianPoint pt2) { bool areClose(Schema_2x3::IfcCartesianPoint pt1,Schema_2x3::IfcCartesianPoint pt2) {
if(pt1.Coordinates.size() != pt2.Coordinates.size()) if(pt1.Coordinates.size() != pt2.Coordinates.size())
@ -561,7 +559,7 @@ void ProcessExtrudedArea(const Schema_2x3::IfcExtrudedAreaSolid& solid, const Te
// Outline: 'curve' is now a list of vertex points forming the underlying profile, extrude along the given axis, // Outline: 'curve' is now a list of vertex points forming the underlying profile, extrude along the given axis,
// forming new triangles. // forming new triangles.
const bool has_area = solid.SweptArea->ProfileType == "AREA" && curve.mVerts.size() > 2; const bool has_area = solid.SweptArea->ProfileType == "AREA" && curve.mVerts.size() > 2;
if( solid.Depth < 1e-6 ) { if (solid.Depth < ai_epsilon) {
if( has_area ) { if( has_area ) {
result.Append(curve); result.Append(curve);
} }

View File

@ -1133,7 +1133,7 @@ IfcMatrix4 ProjectOntoPlane(std::vector<IfcVector2>& out_contour, const TempMesh
} }
for(size_t i = 0; i < out_contour.size(); ++i) { for(size_t i = 0; i < out_contour.size(); ++i) {
ai_assert((out_contour[i]-out_contour2[i]).SquareLength() < 1e-6); ai_assert((out_contour[i] - out_contour2[i]).SquareLength() < ai_epsilon);
} }
#endif #endif
@ -1435,7 +1435,7 @@ std::vector<IfcVector2> GetContourInPlane2D(std::shared_ptr<TempMesh> mesh,IfcMa
const auto outernor = ((mesh->mVerts[2] - mesh->mVerts[0]) ^ (mesh->mVerts[1] - mesh->mVerts[0])).Normalize(); const auto outernor = ((mesh->mVerts[2] - mesh->mVerts[0]) ^ (mesh->mVerts[1] - mesh->mVerts[0])).Normalize();
const IfcFloat dot = planeNor * outernor; const IfcFloat dot = planeNor * outernor;
if(std::fabs(dot) < 1.f - 1e-6f) { if (std::fabs(dot) < 1.f - ai_epsilon) {
std::stringstream msg; std::stringstream msg;
msg << "Skipping: Unaligned opening (" << planeNor.x << ", " << planeNor.y << ", " << planeNor.z << ")"; msg << "Skipping: Unaligned opening (" << planeNor.x << ", " << planeNor.y << ", " << planeNor.z << ")";
msg << " . ( " << outernor.x << ", " << outernor.y << ", " << outernor.z << ") = " << dot; msg << " . ( " << outernor.x << ", " << outernor.y << ", " << outernor.z << ") = " << dot;
@ -1476,7 +1476,7 @@ std::vector<IfcVector2> GetContourInPlane2D(std::shared_ptr<TempMesh> mesh,IfcMa
return contour; return contour;
} }
const float close { 1e-6f }; const float close{ ai_epsilon };
static bool isClose(IfcVector2 first,IfcVector2 second) { static bool isClose(IfcVector2 first,IfcVector2 second) {
auto diff = (second - first); auto diff = (second - first);

View File

@ -228,25 +228,24 @@ void TempMesh::ComputePolygonNormals(std::vector<IfcVector3>& normals,
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Compute the normal of the last polygon in the given mesh // Compute the normal of the last polygon in the given mesh
IfcVector3 TempMesh::ComputeLastPolygonNormal(bool normalize) const IfcVector3 TempMesh::ComputeLastPolygonNormal(bool normalize) const {
{
return ComputePolygonNormal(&mVerts[mVerts.size() - mVertcnt.back()], mVertcnt.back(), normalize); return ComputePolygonNormal(&mVerts[mVerts.size() - mVertcnt.back()], mVertcnt.back(), normalize);
} }
struct CompareVector struct CompareVector {
{ bool operator () (const IfcVector3& a, const IfcVector3& b) const {
bool operator () (const IfcVector3& a, const IfcVector3& b) const
{
IfcVector3 d = a - b; IfcVector3 d = a - b;
IfcFloat eps = 1e-6; IfcFloat eps = ai_epsilon;
return d.x < -eps || (std::abs(d.x) < eps && d.y < -eps) || (std::abs(d.x) < eps && std::abs(d.y) < eps && d.z < -eps); return d.x < -eps || (std::abs(d.x) < eps && d.y < -eps) || (std::abs(d.x) < eps && std::abs(d.y) < eps && d.z < -eps);
} }
}; };
struct FindVector
{ struct FindVector {
IfcVector3 v; IfcVector3 v;
FindVector(const IfcVector3& p) : v(p) { } FindVector(const IfcVector3& p) : v(p) { }
bool operator () (const IfcVector3& p) { return FuzzyVectorCompare(1e-6)(p, v); } bool operator()(const IfcVector3 &p) {
return FuzzyVectorCompare(ai_epsilon)(p, v);
}
}; };
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -357,8 +356,7 @@ void TempMesh::FixupFaceOrientation()
// to reverse the neighbour // to reverse the neighbour
nb_vidx = (nb_vidx + 1) % nbvc; nb_vidx = (nb_vidx + 1) % nbvc;
size_t oursideidx = (a + 1) % vc; size_t oursideidx = (a + 1) % vc;
if( FuzzyVectorCompare(1e-6)(mVerts[vsi + oursideidx], mVerts[nbvsi + nb_vidx]) ) if (FuzzyVectorCompare(ai_epsilon)(mVerts[vsi + oursideidx], mVerts[nbvsi + nb_vidx])) {
{
std::reverse(mVerts.begin() + nbvsi, mVerts.begin() + nbvsi + nbvc); std::reverse(mVerts.begin() + nbvsi, mVerts.begin() + nbvsi + nbvc);
std::reverse(neighbour.begin() + nbvsi, neighbour.begin() + nbvsi + nbvc); std::reverse(neighbour.begin() + nbvsi, neighbour.begin() + nbvsi + nbvc);
for (size_t aa = 0; aa < nbvc - 1; ++aa) { for (size_t aa = 0; aa < nbvc - 1; ++aa) {
@ -564,7 +562,7 @@ void ConvertDirection(IfcVector3& out, const Schema_2x3::IfcDirection& in)
out[static_cast<unsigned int>(i)] = in.DirectionRatios[i]; out[static_cast<unsigned int>(i)] = in.DirectionRatios[i];
} }
const IfcFloat len = out.Length(); const IfcFloat len = out.Length();
if (len<1e-6) { if (len < ai_epsilon) {
IFCImporter::LogWarn("direction vector magnitude too small, normalization would result in a division by zero"); IFCImporter::LogWarn("direction vector magnitude too small, normalization would result in a division by zero");
return; return;
} }

View File

@ -83,9 +83,13 @@ AnimResolver::AnimResolver(std::list<Envelope> &_envelopes, double tick) :
(*it).old_first = 0; (*it).old_first = 0;
(*it).old_last = (*it).keys.size() - 1; (*it).old_last = (*it).keys.size() - 1;
if ((*it).keys.empty()) continue; if ((*it).keys.empty()) {
continue;
}
if ((int)(*it).type < 1 || (int)(*it).type>EnvelopeType_Unknown) {
continue;
}
switch ((*it).type) { switch ((*it).type) {
// translation // translation
case LWO::EnvelopeType_Position_X: case LWO::EnvelopeType_Position_X:
trans_x = &*it; trans_x = &*it;

View File

@ -195,6 +195,9 @@ struct Material {
//! PBR Anisotropy //! PBR Anisotropy
ai_real anisotropy; ai_real anisotropy;
//! bump map multipler (normal map scalar)(-bm)
ai_real bump_multiplier;
//! Constructor //! Constructor
Material() : Material() :
diffuse(ai_real(0.6), ai_real(0.6), ai_real(0.6)), diffuse(ai_real(0.6), ai_real(0.6), ai_real(0.6)),
@ -208,7 +211,8 @@ struct Material {
sheen(ai_real(1.0), ai_real(1.0), ai_real(1.0)), sheen(ai_real(1.0), ai_real(1.0), ai_real(1.0)),
clearcoat_thickness(ai_real(0.0)), clearcoat_thickness(ai_real(0.0)),
clearcoat_roughness(ai_real(0.0)), clearcoat_roughness(ai_real(0.0)),
anisotropy(ai_real(0.0)) { anisotropy(ai_real(0.0)),
bump_multiplier(ai_real(1.0)) {
std::fill_n(clamp, static_cast<unsigned int>(TextureTypeCount), false); std::fill_n(clamp, static_cast<unsigned int>(TextureTypeCount), false);
} }

View File

@ -51,6 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/scene.h> #include <assimp/scene.h>
#include <assimp/DefaultLogger.hpp> #include <assimp/DefaultLogger.hpp>
#include <assimp/Importer.hpp> #include <assimp/Importer.hpp>
#include <assimp/ObjMaterial.h>
#include <memory> #include <memory>
static const aiImporterDesc desc = { static const aiImporterDesc desc = {
@ -604,6 +605,9 @@ void ObjFileImporter::createMaterials(const ObjFile::Model *pModel, aiScene *pSc
mat->AddProperty<int>(&sm, 1, AI_MATKEY_SHADING_MODEL); mat->AddProperty<int>(&sm, 1, AI_MATKEY_SHADING_MODEL);
// Preserve the original illum value
mat->AddProperty<int>(&pCurrentMaterial->illumination_model, 1, AI_MATKEY_OBJ_ILLUM);
// Adding material colors // Adding material colors
mat->AddProperty(&pCurrentMaterial->ambient, 1, AI_MATKEY_COLOR_AMBIENT); mat->AddProperty(&pCurrentMaterial->ambient, 1, AI_MATKEY_COLOR_AMBIENT);
mat->AddProperty(&pCurrentMaterial->diffuse, 1, AI_MATKEY_COLOR_DIFFUSE); mat->AddProperty(&pCurrentMaterial->diffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
@ -657,6 +661,9 @@ void ObjFileImporter::createMaterials(const ObjFile::Model *pModel, aiScene *pSc
if (0 != pCurrentMaterial->textureBump.length) { if (0 != pCurrentMaterial->textureBump.length) {
mat->AddProperty(&pCurrentMaterial->textureBump, AI_MATKEY_TEXTURE_HEIGHT(0)); mat->AddProperty(&pCurrentMaterial->textureBump, AI_MATKEY_TEXTURE_HEIGHT(0));
mat->AddProperty(&uvwIndex, 1, AI_MATKEY_UVWSRC_HEIGHT(0)); mat->AddProperty(&uvwIndex, 1, AI_MATKEY_UVWSRC_HEIGHT(0));
if (pCurrentMaterial->bump_multiplier != 1.0) {
mat->AddProperty(&pCurrentMaterial->bump_multiplier, 1, AI_MATKEY_OBJ_BUMPMULT_HEIGHT(0));
}
if (pCurrentMaterial->clamp[ObjFile::Material::TextureBumpType]) { if (pCurrentMaterial->clamp[ObjFile::Material::TextureBumpType]) {
addTextureMappingModeProperty(mat, aiTextureType_HEIGHT); addTextureMappingModeProperty(mat, aiTextureType_HEIGHT);
} }
@ -665,6 +672,9 @@ void ObjFileImporter::createMaterials(const ObjFile::Model *pModel, aiScene *pSc
if (0 != pCurrentMaterial->textureNormal.length) { if (0 != pCurrentMaterial->textureNormal.length) {
mat->AddProperty(&pCurrentMaterial->textureNormal, AI_MATKEY_TEXTURE_NORMALS(0)); mat->AddProperty(&pCurrentMaterial->textureNormal, AI_MATKEY_TEXTURE_NORMALS(0));
mat->AddProperty(&uvwIndex, 1, AI_MATKEY_UVWSRC_NORMALS(0)); mat->AddProperty(&uvwIndex, 1, AI_MATKEY_UVWSRC_NORMALS(0));
if (pCurrentMaterial->bump_multiplier != 1.0) {
mat->AddProperty(&pCurrentMaterial->bump_multiplier, 1, AI_MATKEY_OBJ_BUMPMULT_NORMALS(0));
}
if (pCurrentMaterial->clamp[ObjFile::Material::TextureNormalType]) { if (pCurrentMaterial->clamp[ObjFile::Material::TextureNormalType]) {
addTextureMappingModeProperty(mat, aiTextureType_NORMALS); addTextureMappingModeProperty(mat, aiTextureType_NORMALS);
} }

View File

@ -472,7 +472,11 @@ void ObjFileMtlImporter::getTextureOption(bool &clamp, int &clampIndex, aiString
} }
skipToken = 2; skipToken = 2;
} else if (!ASSIMP_strincmp(pPtr, BlendUOption.c_str(), static_cast<unsigned int>(BlendUOption.size())) || !ASSIMP_strincmp(pPtr, BlendVOption.c_str(), static_cast<unsigned int>(BlendVOption.size())) || !ASSIMP_strincmp(pPtr, BoostOption.c_str(), static_cast<unsigned int>(BoostOption.size())) || !ASSIMP_strincmp(pPtr, ResolutionOption.c_str(), static_cast<unsigned int>(ResolutionOption.size())) || !ASSIMP_strincmp(pPtr, BumpOption.c_str(), static_cast<unsigned int>(BumpOption.size())) || !ASSIMP_strincmp(pPtr, ChannelOption.c_str(), static_cast<unsigned int>(ChannelOption.size()))) { } else if (!ASSIMP_strincmp(pPtr, BumpOption.c_str(), static_cast<unsigned int>(BumpOption.size()))) {
DataArrayIt it = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
getFloat(it, m_DataItEnd, m_pModel->m_pCurrentMaterial->bump_multiplier);
skipToken = 2;
} else if (!ASSIMP_strincmp(pPtr, BlendUOption.c_str(), static_cast<unsigned int>(BlendUOption.size())) || !ASSIMP_strincmp(pPtr, BlendVOption.c_str(), static_cast<unsigned int>(BlendVOption.size())) || !ASSIMP_strincmp(pPtr, BoostOption.c_str(), static_cast<unsigned int>(BoostOption.size())) || !ASSIMP_strincmp(pPtr, ResolutionOption.c_str(), static_cast<unsigned int>(ResolutionOption.size())) || !ASSIMP_strincmp(pPtr, ChannelOption.c_str(), static_cast<unsigned int>(ChannelOption.size()))) {
skipToken = 2; skipToken = 2;
} else if (!ASSIMP_strincmp(pPtr, ModifyMapOption.c_str(), static_cast<unsigned int>(ModifyMapOption.size()))) { } else if (!ASSIMP_strincmp(pPtr, ModifyMapOption.c_str(), static_cast<unsigned int>(ModifyMapOption.size()))) {
skipToken = 3; skipToken = 3;

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -60,25 +58,11 @@ using namespace Assimp::Formatter;
#ifndef ASSIMP_BUILD_NO_COMPRESSED_X #ifndef ASSIMP_BUILD_NO_COMPRESSED_X
#ifdef ASSIMP_BUILD_NO_OWN_ZLIB #include "Common/Compression.h"
#include <zlib.h>
#else
#include "../contrib/zlib/zlib.h"
#endif
// Magic identifier for MSZIP compressed data // Magic identifier for MSZIP compressed data
#define MSZIP_MAGIC 0x4B43 constexpr unsigned int MSZIP_MAGIC = 0x4B43;
#define MSZIP_BLOCK 32786 constexpr size_t MSZIP_BLOCK = 32786l;
// ------------------------------------------------------------------------------------------------
// Dummy memory wrappers for use with zlib
static void *dummy_alloc(void * /*opaque*/, unsigned int items, unsigned int size) {
return ::operator new(items *size);
}
static void dummy_free(void * /*opaque*/, void *address) {
return ::operator delete(address);
}
#endif // !! ASSIMP_BUILD_NO_COMPRESSED_X #endif // !! ASSIMP_BUILD_NO_COMPRESSED_X
@ -133,13 +117,13 @@ XFileParser::XFileParser(const std::vector<char> &pBuffer) :
mIsBinaryFormat = true; mIsBinaryFormat = true;
compressed = true; compressed = true;
} else } else
ThrowException("Unsupported xfile format '", mP[8], mP[9], mP[10], mP[11], "'"); ThrowException("Unsupported x-file format '", mP[8], mP[9], mP[10], mP[11], "'");
// float size // float size
mBinaryFloatSize = (unsigned int)(mP[12] - 48) * 1000 + (unsigned int)(mP[13] - 48) * 100 + (unsigned int)(mP[14] - 48) * 10 + (unsigned int)(mP[15] - 48); mBinaryFloatSize = (unsigned int)(mP[12] - 48) * 1000 + (unsigned int)(mP[13] - 48) * 100 + (unsigned int)(mP[14] - 48) * 10 + (unsigned int)(mP[15] - 48);
if (mBinaryFloatSize != 32 && mBinaryFloatSize != 64) if (mBinaryFloatSize != 32 && mBinaryFloatSize != 64)
ThrowException("Unknown float size ", mBinaryFloatSize, " specified in xfile header."); ThrowException("Unknown float size ", mBinaryFloatSize, " specified in x-file header.");
// The x format specifies size in bits, but we work in bytes // The x format specifies size in bits, but we work in bytes
mBinaryFloatSize /= 8; mBinaryFloatSize /= 8;
@ -171,16 +155,6 @@ XFileParser::XFileParser(const std::vector<char> &pBuffer) :
* /////////////////////////////////////////////////////////////////////// * ///////////////////////////////////////////////////////////////////////
*/ */
// build a zlib stream
z_stream stream;
stream.opaque = nullptr;
stream.zalloc = &dummy_alloc;
stream.zfree = &dummy_free;
stream.data_type = (mIsBinaryFormat ? Z_BINARY : Z_ASCII);
// initialize the inflation algorithm
::inflateInit2(&stream, -MAX_WBITS);
// skip unknown data (checksum, flags?) // skip unknown data (checksum, flags?)
mP += 6; mP += 6;
@ -207,43 +181,29 @@ XFileParser::XFileParser(const std::vector<char> &pBuffer) :
// and advance to the next offset // and advance to the next offset
P1 += ofs; P1 += ofs;
est_out += MSZIP_BLOCK; // one decompressed block is 32786 in size est_out += MSZIP_BLOCK; // one decompressed block is 327861 in size
} }
// Allocate storage and terminating zero and do the actual uncompressing // Allocate storage and terminating zero and do the actual uncompressing
Compression compression;
uncompressed.resize(est_out + 1); uncompressed.resize(est_out + 1);
char *out = &uncompressed.front(); char *out = &uncompressed.front();
while (mP + 3 < mEnd) { if (compression.open(mIsBinaryFormat ? Compression::Format::Binary : Compression::Format::ASCII,
uint16_t ofs = *((uint16_t *)mP); Compression::FlushMode::SyncFlush, -Compression::MaxWBits)) {
AI_SWAP2(ofs); while (mP + 3 < mEnd) {
mP += 4; uint16_t ofs = *((uint16_t *)mP);
AI_SWAP2(ofs);
mP += 4;
if (mP + ofs > mEnd + 2) { if (mP + ofs > mEnd + 2) {
throw DeadlyImportError("X: Unexpected EOF in compressed chunk"); throw DeadlyImportError("X: Unexpected EOF in compressed chunk");
}
out += compression.decompressBlock(mP, ofs, out, MSZIP_BLOCK);
mP += ofs;
} }
compression.close();
// push data to the stream
stream.next_in = (Bytef *)mP;
stream.avail_in = ofs;
stream.next_out = (Bytef *)out;
stream.avail_out = MSZIP_BLOCK;
// and decompress the data ....
int ret = ::inflate(&stream, Z_SYNC_FLUSH);
if (ret != Z_OK && ret != Z_STREAM_END)
throw DeadlyImportError("X: Failed to decompress MSZIP-compressed data");
::inflateReset(&stream);
::inflateSetDictionary(&stream, (const Bytef *)out, MSZIP_BLOCK - stream.avail_out);
// and advance to the next offset
out += MSZIP_BLOCK - stream.avail_out;
mP += ofs;
} }
// terminate zlib
::inflateEnd(&stream);
// ok, update pointers to point to the uncompressed file data // ok, update pointers to point to the uncompressed file data
mP = &uncompressed[0]; mP = &uncompressed[0];
mEnd = out; mEnd = out;
@ -279,15 +239,16 @@ void XFileParser::ParseFile() {
while (running) { while (running) {
// read name of next object // read name of next object
std::string objectName = GetNextToken(); std::string objectName = GetNextToken();
if (objectName.length() == 0) if (objectName.length() == 0) {
break; break;
}
// parse specific object // parse specific object
if (objectName == "template") if (objectName == "template") {
ParseDataObjectTemplate(); ParseDataObjectTemplate();
else if (objectName == "Frame") } else if (objectName == "Frame") {
ParseDataObjectFrame(nullptr); ParseDataObjectFrame(nullptr);
else if (objectName == "Mesh") { } else if (objectName == "Mesh") {
// some meshes have no frames at all // some meshes have no frames at all
Mesh *mesh = new Mesh; Mesh *mesh = new Mesh;
ParseDataObjectMesh(mesh); ParseDataObjectMesh(mesh);
@ -326,11 +287,13 @@ void XFileParser::ParseDataObjectTemplate() {
while (running) { while (running) {
std::string s = GetNextToken(); std::string s = GetNextToken();
if (s == "}") if (s == "}") {
break; break;
}
if (s.length() == 0) if (s.length() == 0) {
ThrowException("Unexpected end of file reached while parsing template definition"); ThrowException("Unexpected end of file reached while parsing template definition");
}
} }
} }
@ -500,7 +463,7 @@ void XFileParser::ParseDataObjectSkinWeights(Mesh *pMesh) {
bone.mWeights.reserve(numWeights); bone.mWeights.reserve(numWeights);
for (unsigned int a = 0; a < numWeights; a++) { for (unsigned int a = 0; a < numWeights; a++) {
BoneWeight weight; BoneWeight weight = {};
weight.mVertex = ReadInt(); weight.mVertex = ReadInt();
bone.mWeights.push_back(weight); bone.mWeights.push_back(weight);
} }

View File

@ -44,28 +44,20 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef ASSIMP_BUILD_NO_XGL_IMPORTER #ifndef ASSIMP_BUILD_NO_XGL_IMPORTER
#include "XGLLoader.h" #include "XGLLoader.h"
#include "Common/Compression.h"
#include <assimp/ParsingUtils.h> #include <assimp/ParsingUtils.h>
#include <assimp/fast_atof.h> #include <assimp/fast_atof.h>
#include <assimp/MemoryIOWrapper.h> #include <assimp/MemoryIOWrapper.h>
#include <assimp/StreamReader.h> #include <assimp/StreamReader.h>
#include <assimp/importerdesc.h> #include <assimp/importerdesc.h>
#include <assimp/mesh.h> #include <assimp/mesh.h>
#include <assimp/scene.h> #include <assimp/scene.h>
#include <cctype> //#include <cctype>
#include <memory> //#include <memory>
using namespace Assimp; using namespace Assimp;
// zlib is needed for compressed XGL files
#ifndef ASSIMP_BUILD_NO_COMPRESSED_XGL
# ifdef ASSIMP_BUILD_NO_OWN_ZLIB
# include <zlib.h>
# else
# include <contrib/zlib/zlib.h>
# endif
#endif
namespace Assimp { // this has to be in here because LogFunctions is in ::Assimp namespace Assimp { // this has to be in here because LogFunctions is in ::Assimp
template <> template <>
@ -73,6 +65,7 @@ const char *LogFunctions<XGLImporter>::Prefix() {
static auto prefix = "XGL: "; static auto prefix = "XGL: ";
return prefix; return prefix;
} }
} // namespace Assimp } // namespace Assimp
static const aiImporterDesc desc = { static const aiImporterDesc desc = {
@ -118,8 +111,8 @@ const aiImporterDesc *XGLImporter::GetInfo() const {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure. // Imports the given file into the given scene structure.
void XGLImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) { void XGLImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
#ifndef ASSIMP_BUILD_NO_COMPRESSED_XGL #ifndef ASSIMP_BUILD_NO_COMPRESSED_XGL
std::vector<Bytef> uncompressed; std::vector<char> uncompressed;
#endif #endif
m_scene = pScene; m_scene = pScene;
@ -137,48 +130,16 @@ void XGLImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
#else #else
std::unique_ptr<StreamReaderLE> raw_reader(new StreamReaderLE(stream)); std::unique_ptr<StreamReaderLE> raw_reader(new StreamReaderLE(stream));
// build a zlib stream Compression compression;
z_stream zstream; size_t total = 0l;
zstream.opaque = Z_NULL; if (compression.open(Compression::Format::Binary, Compression::FlushMode::NoFlush, -Compression::MaxWBits)) {
zstream.zalloc = Z_NULL; // skip two extra bytes, zgl files do carry a crc16 upfront (I think)
zstream.zfree = Z_NULL; raw_reader->IncPtr(2);
zstream.data_type = Z_BINARY; total = compression.decompress((unsigned char *)raw_reader->GetPtr(), raw_reader->GetRemainingSize(), uncompressed);
compression.close();
// raw decompression without a zlib or gzip header }
inflateInit2(&zstream, -MAX_WBITS);
// skip two extra bytes, zgl files do carry a crc16 upfront (I think)
raw_reader->IncPtr(2);
zstream.next_in = reinterpret_cast<Bytef *>(raw_reader->GetPtr());
zstream.avail_in = (uInt) raw_reader->GetRemainingSize();
size_t total = 0l;
// TODO: be smarter about this, decompress directly into heap buffer
// and decompress the data .... do 1k chunks in the hope that we won't kill the stack
#define MYBLOCK 1024
Bytef block[MYBLOCK];
int ret;
do {
zstream.avail_out = MYBLOCK;
zstream.next_out = block;
ret = inflate(&zstream, Z_NO_FLUSH);
if (ret != Z_STREAM_END && ret != Z_OK) {
ThrowException("Failure decompressing this file using gzip, seemingly it is NOT a compressed .XGL file");
}
const size_t have = MYBLOCK - zstream.avail_out;
total += have;
uncompressed.resize(total);
memcpy(uncompressed.data() + total - have, block, have);
} while (ret != Z_STREAM_END);
// terminate zlib
inflateEnd(&zstream);
// replace the input stream with a memory stream // replace the input stream with a memory stream
stream.reset(new MemoryIOStream(reinterpret_cast<uint8_t *>(uncompressed.data()), total)); stream.reset(new MemoryIOStream(reinterpret_cast<uint8_t*>(uncompressed.data()), total));
#endif #endif
} }
@ -239,7 +200,7 @@ void XGLImporter::ReadWorld(XmlNode &node, TempScope &scope) {
if (!nd) { if (!nd) {
ThrowException("failure reading <world>"); ThrowException("failure reading <world>");
} }
if (!nd->mName.length) { if (nd->mName.length == 0) {
nd->mName.Set("WORLD"); nd->mName.Set("WORLD");
} }
@ -291,7 +252,8 @@ aiNode *XGLImporter::ReadObject(XmlNode &node, TempScope &scope) {
const std::string &s = ai_stdStrToLower(child.name()); const std::string &s = ai_stdStrToLower(child.name());
if (s == "mesh") { if (s == "mesh") {
const size_t prev = scope.meshes_linear.size(); const size_t prev = scope.meshes_linear.size();
if (ReadMesh(child, scope)) { bool empty;
if (ReadMesh(child, scope, empty)) {
const size_t newc = scope.meshes_linear.size(); const size_t newc = scope.meshes_linear.size();
for (size_t i = 0; i < newc - prev; ++i) { for (size_t i = 0; i < newc - prev; ++i) {
meshes.push_back(static_cast<unsigned int>(i + prev)); meshes.push_back(static_cast<unsigned int>(i + prev));
@ -475,12 +437,12 @@ aiMesh *XGLImporter::ToOutputMesh(const TempMaterialMesh &m) {
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
bool XGLImporter::ReadMesh(XmlNode &node, TempScope &scope) { bool XGLImporter::ReadMesh(XmlNode &node, TempScope &scope, bool &empty) {
TempMesh t; TempMesh t;
std::map<unsigned int, TempMaterialMesh> bymat; std::map<unsigned int, TempMaterialMesh> bymat;
const unsigned int mesh_id = ReadIDAttr(node); const unsigned int mesh_id = ReadIDAttr(node);
bool empty_mesh = true;
for (XmlNode &child : node.children()) { for (XmlNode &child : node.children()) {
const std::string &s = ai_stdStrToLower(child.name()); const std::string &s = ai_stdStrToLower(child.name());
@ -539,6 +501,9 @@ bool XGLImporter::ReadMesh(XmlNode &node, TempScope &scope) {
mid = ResolveMaterialRef(sub_child, scope); mid = ResolveMaterialRef(sub_child, scope);
} }
} }
if (has[0] || has[1] || has[2]) {
empty_mesh = false;
}
if (mid == ~0u) { if (mid == ~0u) {
ThrowException("missing material index"); ThrowException("missing material index");
@ -590,6 +555,11 @@ bool XGLImporter::ReadMesh(XmlNode &node, TempScope &scope) {
scope.meshes.insert(std::pair<unsigned int, aiMesh *>(mesh_id, m)); scope.meshes.insert(std::pair<unsigned int, aiMesh *>(mesh_id, m));
} }
} }
if (empty_mesh) {
LogWarn("Mesh is empty, skipping.");
empty = empty_mesh;
return false;
}
// no id == not a reference, insert this mesh right *here* // no id == not a reference, insert this mesh right *here*
return mesh_id == ~0u; return mesh_id == ~0u;
@ -759,7 +729,7 @@ aiVector2D XGLImporter::ReadVec2(XmlNode &node) {
std::string val; std::string val;
XmlParser::getValueAsString(node, val); XmlParser::getValueAsString(node, val);
const char *s = val.c_str(); const char *s = val.c_str();
ai_real v[2]; ai_real v[2] = {};
for (int i = 0; i < 2; ++i) { for (int i = 0; i < 2; ++i) {
if (!SkipSpaces(&s)) { if (!SkipSpaces(&s)) {
LogError("unexpected EOL, failed to parse vec2"); LogError("unexpected EOL, failed to parse vec2");
@ -814,4 +784,4 @@ aiColor3D XGLImporter::ReadCol3(XmlNode &node) {
return aiColor3D(v.x, v.y, v.z); return aiColor3D(v.x, v.y, v.z);
} }
#endif #endif // ASSIMP_BUILD_NO_XGL_IMPORTER

View File

@ -186,7 +186,7 @@ private:
void ReadLighting(XmlNode &node, TempScope &scope); void ReadLighting(XmlNode &node, TempScope &scope);
aiLight *ReadDirectionalLight(XmlNode &node); aiLight *ReadDirectionalLight(XmlNode &node);
aiNode *ReadObject(XmlNode &node, TempScope &scope); aiNode *ReadObject(XmlNode &node, TempScope &scope);
bool ReadMesh(XmlNode &node, TempScope &scope); bool ReadMesh(XmlNode &node, TempScope &scope, bool &empty);
void ReadMaterial(XmlNode &node, TempScope &scope); void ReadMaterial(XmlNode &node, TempScope &scope);
aiVector2D ReadVec2(XmlNode &node); aiVector2D ReadVec2(XmlNode &node);
aiVector3D ReadVec3(XmlNode &node); aiVector3D ReadVec3(XmlNode &node);

View File

@ -260,20 +260,9 @@ public:
VEC4, VEC4,
MAT2, MAT2,
MAT3, MAT3,
MAT4 }; MAT4
private:
static const size_t NUM_VALUES = static_cast<size_t>(MAT4) + 1;
struct Info {
const char *name;
unsigned int numComponents;
}; };
template <int N>
struct data { static const Info infos[NUM_VALUES]; };
public:
inline static Value FromString(const char *str) { inline static Value FromString(const char *str) {
for (size_t i = 0; i < NUM_VALUES; ++i) { for (size_t i = 0; i < NUM_VALUES; ++i) {
if (strcmp(data<0>::infos[i].name, str) == 0) { if (strcmp(data<0>::infos[i].name, str) == 0) {
@ -290,40 +279,31 @@ public:
inline static unsigned int GetNumComponents(Value type) { inline static unsigned int GetNumComponents(Value type) {
return data<0>::infos[static_cast<size_t>(type)].numComponents; return data<0>::infos[static_cast<size_t>(type)].numComponents;
} }
private:
static const size_t NUM_VALUES = static_cast<size_t>(MAT4) + 1;
struct Info {
const char *name;
unsigned int numComponents;
};
template <int N>
struct data {
static const Info infos[NUM_VALUES];
};
}; };
// must match the order of the AttribTypeTraits::Value enum! // must match the order of the AttribTypeTraits::Value enum!
template <int N> template <int N>
const AttribType::Info const AttribType::Info AttribType::data<N>::infos[AttribType::NUM_VALUES] = {
AttribType::data<N>::infos[AttribType::NUM_VALUES] = { { "SCALAR", 1 },
{ "SCALAR", 1 }, { "VEC2", 2 }, { "VEC3", 3 }, { "VEC4", 4 }, { "MAT2", 4 }, { "MAT3", 9 }, { "MAT4", 16 } { "VEC2", 2 },
}; { "VEC3", 3 },
{ "VEC4", 4 },
/* { "MAT2", 4 },
//! A reference to one top-level object, which is valid { "MAT3", 9 },
//! until the Asset instance is destroyed { "MAT4", 16 }
template<class T> };
class Ref
{
std::vector<T*>* vector;
unsigned int index;
public:
Ref() : vector(0), index(0) {}
Ref(std::vector<T*>& vec, unsigned int idx) : vector(&vec), index(idx) {}
inline unsigned int GetIndex() const
{ return index; }
operator bool() const
{ return vector != 0; }
T* operator->()
{ return (*vector)[index]; }
T& operator*()
{ return *((*vector)[index]); }
};*/
//! Base class for all glTF top-level objects //! Base class for all glTF top-level objects
struct Object { struct Object {
@ -333,6 +313,7 @@ struct Object {
//! Objects marked as special are not exported (used to emulate the binary body buffer) //! Objects marked as special are not exported (used to emulate the binary body buffer)
virtual bool IsSpecial() const { return false; } virtual bool IsSpecial() const { return false; }
Object() = default;
virtual ~Object() {} virtual ~Object() {}
//! Maps special IDs to another ID, where needed. Subclasses may override it (statically) //! Maps special IDs to another ID, where needed. Subclasses may override it (statically)
@ -401,21 +382,19 @@ struct Accessor : public Object {
return Indexer(*this); return Indexer(*this);
} }
Accessor() {} Accessor() = default;
void Read(Value &obj, Asset &r); void Read(Value &obj, Asset &r);
}; };
//! A buffer points to binary geometry, animation, or skins. //! A buffer points to binary geometry, animation, or skins.
struct Buffer : public Object { struct Buffer : public Object {
/********************* Types *********************/ /********************* Types *********************/
public:
enum Type { enum Type {
Type_arraybuffer, Type_arraybuffer,
Type_text Type_text
}; };
/// \struct SEncodedRegion /// @brief Descriptor of encoded region in "bufferView".
/// Descriptor of encoded region in "bufferView".
struct SEncodedRegion { struct SEncodedRegion {
const size_t Offset; ///< Offset from begin of "bufferView" to encoded region, in bytes. const size_t Offset; ///< Offset from begin of "bufferView" to encoded region, in bytes.
const size_t EncodedData_Length; ///< Size of encoded region, in bytes. const size_t EncodedData_Length; ///< Size of encoded region, in bytes.
@ -423,8 +402,7 @@ public:
const size_t DecodedData_Length; ///< Size of decoded region, in bytes. const size_t DecodedData_Length; ///< Size of decoded region, in bytes.
const std::string ID; ///< ID of the region. const std::string ID; ///< ID of the region.
/// \fn SEncodedRegion(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string pID) /// @brief Constructor.
/// Constructor.
/// \param [in] pOffset - offset from begin of "bufferView" to encoded region, in bytes. /// \param [in] pOffset - offset from begin of "bufferView" to encoded region, in bytes.
/// \param [in] pEncodedData_Length - size of encoded region, in bytes. /// \param [in] pEncodedData_Length - size of encoded region, in bytes.
/// \param [in] pDecodedData - pointer to decoded data array. /// \param [in] pDecodedData - pointer to decoded data array.
@ -433,16 +411,13 @@ public:
SEncodedRegion(const size_t pOffset, const size_t pEncodedData_Length, uint8_t *pDecodedData, const size_t pDecodedData_Length, const std::string &pID) : SEncodedRegion(const size_t pOffset, const size_t pEncodedData_Length, uint8_t *pDecodedData, const size_t pDecodedData_Length, const std::string &pID) :
Offset(pOffset), EncodedData_Length(pEncodedData_Length), DecodedData(pDecodedData), DecodedData_Length(pDecodedData_Length), ID(pID) {} Offset(pOffset), EncodedData_Length(pEncodedData_Length), DecodedData(pDecodedData), DecodedData_Length(pDecodedData_Length), ID(pID) {}
/// \fn ~SEncodedRegion()
/// Destructor. /// Destructor.
~SEncodedRegion() { delete[] DecodedData; } ~SEncodedRegion() { delete[] DecodedData; }
}; };
/******************* Variables *******************/ /******************* Variables *******************/
//std::string uri; //!< The uri of the buffer. Can be a filepath, a data uri, etc. (required)
size_t byteLength; //!< The length of the buffer in bytes. (default: 0) size_t byteLength; //!< The length of the buffer in bytes. (default: 0)
//std::string type; //!< XMLHttpRequest responseType (default: "arraybuffer")
Type type; Type type;
@ -486,7 +461,6 @@ public:
bool LoadFromStream(IOStream &stream, size_t length = 0, size_t baseOffset = 0); bool LoadFromStream(IOStream &stream, size_t length = 0, size_t baseOffset = 0);
/// \fn void EncodedRegion_Mark(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string& pID)
/// Mark region of "bufferView" as encoded. When data is request from such region then "bufferView" use decoded data. /// Mark region of "bufferView" as encoded. When data is request from such region then "bufferView" use decoded data.
/// \param [in] pOffset - offset from begin of "bufferView" to encoded region, in bytes. /// \param [in] pOffset - offset from begin of "bufferView" to encoded region, in bytes.
/// \param [in] pEncodedData_Length - size of encoded region, in bytes. /// \param [in] pEncodedData_Length - size of encoded region, in bytes.
@ -495,12 +469,10 @@ public:
/// \param [in] pID - ID of the region. /// \param [in] pID - ID of the region.
void EncodedRegion_Mark(const size_t pOffset, const size_t pEncodedData_Length, uint8_t *pDecodedData, const size_t pDecodedData_Length, const std::string &pID); void EncodedRegion_Mark(const size_t pOffset, const size_t pEncodedData_Length, uint8_t *pDecodedData, const size_t pDecodedData_Length, const std::string &pID);
/// \fn void EncodedRegion_SetCurrent(const std::string& pID)
/// Select current encoded region by ID. \sa EncodedRegion_Current. /// Select current encoded region by ID. \sa EncodedRegion_Current.
/// \param [in] pID - ID of the region. /// \param [in] pID - ID of the region.
void EncodedRegion_SetCurrent(const std::string &pID); void EncodedRegion_SetCurrent(const std::string &pID);
/// \fn bool ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t* pReplace_Data, const size_t pReplace_Count)
/// Replace part of buffer data. Pay attention that function work with original array of data (\ref mData) not with encoded regions. /// Replace part of buffer data. Pay attention that function work with original array of data (\ref mData) not with encoded regions.
/// \param [in] pBufferData_Offset - index of first element in buffer from which new data will be placed. /// \param [in] pBufferData_Offset - index of first element in buffer from which new data will be placed.
/// \param [in] pBufferData_Count - count of bytes in buffer which will be replaced. /// \param [in] pBufferData_Count - count of bytes in buffer which will be replaced.
@ -558,37 +530,29 @@ struct Camera : public Object {
} ortographic; } ortographic;
}; };
Camera() {} Camera() = default;
void Read(Value &obj, Asset &r); void Read(Value &obj, Asset &r);
}; };
//! Image data used to create a texture. //! Image data used to create a texture.
struct Image : public Object { struct Image : public Object {
std::string uri; //! The uri of the image, that can be a file path, a data URI, etc.. (required) std::string uri; //! The uri of the image, that can be a file path, a data URI, etc.. (required)
Ref<BufferView> bufferView; Ref<BufferView> bufferView;
std::string mimeType; std::string mimeType;
int width, height; int width, height;
private:
std::unique_ptr<uint8_t[]> mData;
size_t mDataLength;
public: public:
Image(); Image();
void Read(Value &obj, Asset &r); void Read(Value &obj, Asset &r);
inline bool HasData() const { return mDataLength > 0; } inline bool HasData() const { return mDataLength > 0; }
inline size_t GetDataLength() const { return mDataLength; } inline size_t GetDataLength() const { return mDataLength; }
inline const uint8_t *GetData() const { return mData.get(); } inline const uint8_t *GetData() const { return mData.get(); }
inline uint8_t *StealData(); inline uint8_t *StealData();
inline void SetData(uint8_t *data, size_t length, Asset &r); inline void SetData(uint8_t *data, size_t length, Asset &r);
private:
std::unique_ptr<uint8_t[]> mData;
size_t mDataLength;
}; };
//! Holds a material property that can be a texture or a color //! Holds a material property that can be a texture or a color
@ -671,6 +635,7 @@ struct Mesh : public Object {
}; };
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC #ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
/// \struct SCompression_Open3DGC /// \struct SCompression_Open3DGC
/// Compression of mesh data using Open3DGC algorithm. /// Compression of mesh data using Open3DGC algorithm.
struct SCompression_Open3DGC : public SExtension { struct SCompression_Open3DGC : public SExtension {
@ -703,7 +668,6 @@ struct Mesh : public Object {
Mesh() {} Mesh() {}
/// \fn ~Mesh()
/// Destructor. /// Destructor.
~Mesh() { ~Mesh() {
for (std::list<SExtension *>::iterator it = Extension.begin(), it_end = Extension.end(); it != it_end; it++) { for (std::list<SExtension *>::iterator it = Extension.begin(), it_end = Extension.end(); it != it_end; it++) {
@ -711,15 +675,13 @@ struct Mesh : public Object {
}; };
} }
/// \fn void Read(Value& pJSON_Object, Asset& pAsset_Root) /// @brief Get mesh data from JSON-object and place them to root asset.
/// Get mesh data from JSON-object and place them to root asset.
/// \param [in] pJSON_Object - reference to pJSON-object from which data are read. /// \param [in] pJSON_Object - reference to pJSON-object from which data are read.
/// \param [out] pAsset_Root - reference to root asset where data will be stored. /// \param [out] pAsset_Root - reference to root asset where data will be stored.
void Read(Value &pJSON_Object, Asset &pAsset_Root); void Read(Value &pJSON_Object, Asset &pAsset_Root);
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC #ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
/// \fn void Decode_O3DGC(const SCompression_Open3DGC& pCompression_Open3DGC, Asset& pAsset_Root) /// @brief Decode part of "buffer" which encoded with Open3DGC algorithm.
/// Decode part of "buffer" which encoded with Open3DGC algorithm.
/// \param [in] pCompression_Open3DGC - reference to structure which describe encoded region. /// \param [in] pCompression_Open3DGC - reference to structure which describe encoded region.
/// \param [out] pAsset_Root - reference to root assed where data will be stored. /// \param [out] pAsset_Root - reference to root assed where data will be stored.
void Decode_O3DGC(const SCompression_Open3DGC &pCompression_Open3DGC, Asset &pAsset_Root); void Decode_O3DGC(const SCompression_Open3DGC &pCompression_Open3DGC, Asset &pAsset_Root);
@ -759,7 +721,7 @@ struct Sampler : public Object {
SamplerWrap wrapS; //!< The texture wrapping in the S direction. (required) SamplerWrap wrapS; //!< The texture wrapping in the S direction. (required)
SamplerWrap wrapT; //!< The texture wrapping in the T direction. (required) SamplerWrap wrapT; //!< The texture wrapping in the T direction. (required)
Sampler() {} Sampler() = default;
void Read(Value &obj, Asset &r); void Read(Value &obj, Asset &r);
void SetDefaults(); void SetDefaults();
}; };
@ -767,12 +729,12 @@ struct Sampler : public Object {
struct Scene : public Object { struct Scene : public Object {
std::vector<Ref<Node>> nodes; std::vector<Ref<Node>> nodes;
Scene() {} Scene() = default;
void Read(Value &obj, Asset &r); void Read(Value &obj, Asset &r);
}; };
struct Shader : public Object { struct Shader : public Object {
Shader() {} Shader() = default;
void Read(Value &obj, Asset &r); void Read(Value &obj, Asset &r);
}; };
@ -782,7 +744,7 @@ struct Skin : public Object {
std::vector<Ref<Node>> jointNames; //!< Joint names of the joints (nodes with a jointName property) in this skin. std::vector<Ref<Node>> jointNames; //!< Joint names of the joints (nodes with a jointName property) in this skin.
std::string name; //!< The user-defined name of this object. std::string name; //!< The user-defined name of this object.
Skin() {} Skin() = default;
void Read(Value &obj, Asset &r); void Read(Value &obj, Asset &r);
}; };
@ -796,7 +758,7 @@ struct Technique : public Object {
struct Functions { struct Functions {
}; };
Technique() {} Technique() = default;
void Read(Value &obj, Asset &r); void Read(Value &obj, Asset &r);
}; };
@ -805,13 +767,7 @@ struct Texture : public Object {
Ref<Sampler> sampler; //!< The ID of the sampler used by this texture. (required) Ref<Sampler> sampler; //!< The ID of the sampler used by this texture. (required)
Ref<Image> source; //!< The ID of the image used by this texture. (required) Ref<Image> source; //!< The ID of the image used by this texture. (required)
//TextureFormat format; //!< The texture's format. (default: TextureFormat_RGBA) Texture() = default;
//TextureFormat internalFormat; //!< The texture's internal format. (default: TextureFormat_RGBA)
//TextureTarget target; //!< The target that the WebGL texture should be bound to. (default: TextureTarget_TEXTURE_2D)
//TextureType type; //!< Texel datatype. (default: TextureType_UNSIGNED_BYTE)
Texture() {}
void Read(Value &obj, Asset &r); void Read(Value &obj, Asset &r);
}; };
@ -826,7 +782,6 @@ struct Light : public Object {
}; };
Type type; Type type;
vec4 color; vec4 color;
float distance; float distance;
float constantAttenuation; float constantAttenuation;
@ -835,9 +790,8 @@ struct Light : public Object {
float falloffAngle; float falloffAngle;
float falloffExponent; float falloffExponent;
Light() {} Light() = default;
void Read(Value &obj, Asset &r); void Read(Value &obj, Asset &r);
void SetDefaults(); void SetDefaults();
}; };
@ -865,15 +819,11 @@ struct Animation : public Object {
Ref<Accessor> translation; //!< Accessor reference to a buffer storing a array of three-component floating-point vectors. Ref<Accessor> translation; //!< Accessor reference to a buffer storing a array of three-component floating-point vectors.
}; };
// AnimChannel Channels[3]; //!< Connect the output values of the key-frame animation to a specific node in the hierarchy.
// AnimParameters Parameters; //!< The samplers that interpolate between the key-frames.
// AnimSampler Samplers[3]; //!< The parameterized inputs representing the key-frame data.
std::vector<AnimChannel> Channels; //!< Connect the output values of the key-frame animation to a specific node in the hierarchy. std::vector<AnimChannel> Channels; //!< Connect the output values of the key-frame animation to a specific node in the hierarchy.
AnimParameters Parameters; //!< The samplers that interpolate between the key-frames. AnimParameters Parameters; //!< The samplers that interpolate between the key-frames.
std::vector<AnimSampler> Samplers; //!< The parameterized inputs representing the key-frame data. std::vector<AnimSampler> Samplers; //!< The parameterized inputs representing the key-frame data.
Animation() {} Animation() = default;
void Read(Value &obj, Asset &r); void Read(Value &obj, Asset &r);
}; };
@ -963,13 +913,11 @@ struct AssetMetadata {
//! Root object for a glTF asset //! Root object for a glTF asset
class Asset { class Asset {
typedef std::gltf_unordered_map<std::string, int> IdMap; using IdMap = std::gltf_unordered_map<std::string, int>;
template <class T> template <class T>
friend class LazyDict; friend class LazyDict;
friend struct Buffer; // To access OpenFile friend struct Buffer; // To access OpenFile
friend class AssetWriter; friend class AssetWriter;
private: private:
@ -1010,12 +958,9 @@ public:
LazyDict<Material> materials; LazyDict<Material> materials;
LazyDict<Mesh> meshes; LazyDict<Mesh> meshes;
LazyDict<Node> nodes; LazyDict<Node> nodes;
//LazyDict<Program> programs;
LazyDict<Sampler> samplers; LazyDict<Sampler> samplers;
LazyDict<Scene> scenes; LazyDict<Scene> scenes;
//LazyDict<Shader> shaders;
LazyDict<Skin> skins; LazyDict<Skin> skins;
//LazyDict<Technique> techniques;
LazyDict<Texture> textures; LazyDict<Texture> textures;
LazyDict<Light> lights; // KHR_materials_common ext LazyDict<Light> lights; // KHR_materials_common ext
@ -1024,16 +969,20 @@ public:
public: public:
Asset(IOSystem *io = 0) : Asset(IOSystem *io = 0) :
mIOSystem(io), asset(), accessors(*this, "accessors"), animations(*this, "animations"), buffers(*this, "buffers"), bufferViews(*this, "bufferViews"), cameras(*this, "cameras"), images(*this, "images"), materials(*this, "materials"), meshes(*this, "meshes"), nodes(*this, "nodes") mIOSystem(io),
//, programs (*this, "programs") asset(),
, accessors(*this, "accessors"),
animations(*this, "animations"),
buffers(*this, "buffers"),
bufferViews(*this, "bufferViews"),
cameras(*this, "cameras"),
images(*this, "images"),
materials(*this, "materials"),
meshes(*this, "meshes"),
nodes(*this, "nodes"),
samplers(*this, "samplers"), samplers(*this, "samplers"),
scenes(*this, "scenes") scenes(*this, "scenes"),
//, shaders (*this, "shaders") skins(*this, "skins"),
,
skins(*this, "skins")
//, techniques (*this, "techniques")
,
textures(*this, "textures"), textures(*this, "textures"),
lights(*this, "lights", "KHR_materials_common") { lights(*this, "lights", "KHR_materials_common") {
memset(&extensionsUsed, 0, sizeof(extensionsUsed)); memset(&extensionsUsed, 0, sizeof(extensionsUsed));

View File

@ -237,8 +237,6 @@ bool ParseDataURI(const char *const_uri, size_t uriLen, DataURI &out);
#define CHECK_EXT(EXT) \ #define CHECK_EXT(EXT) \
if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true; if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true;
//! Helper struct to represent values that might not be present //! Helper struct to represent values that might not be present
template <class T> template <class T>
struct Nullable { struct Nullable {

View File

@ -106,7 +106,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# define gltf_unordered_map tr1::unordered_map # define gltf_unordered_map tr1::unordered_map
# define gltf_unordered_set tr1::unordered_set # define gltf_unordered_set tr1::unordered_set
# else # else
# define gltf_unordered_map unordered_map # define gltf_unordered_map unordered_map
# define gltf_unordered_set unordered_set # define gltf_unordered_set unordered_set
# endif # endif
#endif #endif
@ -1087,29 +1087,11 @@ class Asset {
template <class T> template <class T>
friend class LazyDict; friend class LazyDict;
friend struct Buffer; // To access OpenFile friend struct Buffer; // To access OpenFile
friend class AssetWriter; friend class AssetWriter;
private:
IOSystem *mIOSystem;
rapidjson::IRemoteSchemaDocumentProvider *mSchemaDocumentProvider;
std::string mCurrentAssetDir;
size_t mSceneLength;
size_t mBodyOffset, mBodyLength;
std::vector<LazyDictBase *> mDicts; std::vector<LazyDictBase *> mDicts;
IdMap mUsedIds;
Ref<Buffer> mBodyBuffer;
Asset(Asset &);
Asset &operator=(const Asset &);
public: public:
//! Keeps info about the enabled extensions //! Keeps info about the enabled extensions
struct Extensions { struct Extensions {
@ -1125,16 +1107,36 @@ public:
bool KHR_draco_mesh_compression; bool KHR_draco_mesh_compression;
bool FB_ngon_encoding; bool FB_ngon_encoding;
bool KHR_texture_basisu; bool KHR_texture_basisu;
Extensions() :
KHR_materials_pbrSpecularGlossiness(false),
KHR_materials_unlit(false),
KHR_lights_punctual(false),
KHR_texture_transform(false),
KHR_materials_sheen(false),
KHR_materials_clearcoat(false),
KHR_materials_transmission(false),
KHR_materials_volume(false),
KHR_materials_ior(false),
KHR_draco_mesh_compression(false),
FB_ngon_encoding(false),
KHR_texture_basisu(false) {
// empty
}
} extensionsUsed; } extensionsUsed;
//! Keeps info about the required extensions //! Keeps info about the required extensions
struct RequiredExtensions { struct RequiredExtensions {
bool KHR_draco_mesh_compression; bool KHR_draco_mesh_compression;
bool KHR_texture_basisu; bool KHR_texture_basisu;
RequiredExtensions() : KHR_draco_mesh_compression(false), KHR_texture_basisu(false) {
// empty
}
} extensionsRequired; } extensionsRequired;
AssetMetadata asset; AssetMetadata asset;
Value *extras = nullptr; Value *extras;
// Dictionaries for each type of object // Dictionaries for each type of object
@ -1156,10 +1158,12 @@ public:
Ref<Scene> scene; Ref<Scene> scene;
public: public:
Asset(IOSystem *io = nullptr, rapidjson::IRemoteSchemaDocumentProvider *schemaDocumentProvider = nullptr) : Asset(IOSystem *io = nullptr, rapidjson::IRemoteSchemaDocumentProvider *schemaDocumentProvider = nullptr) :
mIOSystem(io), mDicts(),
mSchemaDocumentProvider(schemaDocumentProvider), extensionsUsed(),
extensionsRequired(),
asset(), asset(),
extras(nullptr),
accessors(*this, "accessors"), accessors(*this, "accessors"),
animations(*this, "animations"), animations(*this, "animations"),
buffers(*this, "buffers"), buffers(*this, "buffers"),
@ -1173,9 +1177,10 @@ public:
samplers(*this, "samplers"), samplers(*this, "samplers"),
scenes(*this, "scenes"), scenes(*this, "scenes"),
skins(*this, "skins"), skins(*this, "skins"),
textures(*this, "textures") { textures(*this, "textures") ,
memset(&extensionsUsed, 0, sizeof(extensionsUsed)); mIOSystem(io),
memset(&extensionsRequired, 0, sizeof(extensionsRequired)); mSchemaDocumentProvider(schemaDocumentProvider) {
// empty
} }
//! Main function //! Main function
@ -1192,18 +1197,31 @@ public:
Ref<Buffer> GetBodyBuffer() { return mBodyBuffer; } Ref<Buffer> GetBodyBuffer() { return mBodyBuffer; }
Asset(Asset &) = delete;
Asset &operator=(const Asset &) = delete;
private: private:
void ReadBinaryHeader(IOStream &stream, std::vector<char> &sceneData); void ReadBinaryHeader(IOStream &stream, std::vector<char> &sceneData);
//! Obtain a JSON document from the stream. /// Obtain a JSON document from the stream.
// \param second argument is a buffer used by the document. It must be kept /// \param second argument is a buffer used by the document. It must be kept
// alive while the document is in use. /// alive while the document is in use.
Document ReadDocument(IOStream& stream, bool isBinary, std::vector<char>& sceneData); Document ReadDocument(IOStream& stream, bool isBinary, std::vector<char>& sceneData);
void ReadExtensionsUsed(Document &doc); void ReadExtensionsUsed(Document &doc);
void ReadExtensionsRequired(Document &doc); void ReadExtensionsRequired(Document &doc);
IOStream *OpenFile(const std::string &path, const char *mode, bool absolute = false); IOStream *OpenFile(const std::string &path, const char *mode, bool absolute = false);
private:
IOSystem *mIOSystem;
rapidjson::IRemoteSchemaDocumentProvider *mSchemaDocumentProvider;
std::string mCurrentAssetDir;
size_t mSceneLength;
size_t mBodyOffset;
size_t mBodyLength;
IdMap mUsedIds;
Ref<Buffer> mBodyBuffer;
}; };
inline std::string getContextForErrorMessages(const std::string &id, const std::string &name) { inline std::string getContextForErrorMessages(const std::string &id, const std::string &name) {

View File

@ -515,72 +515,74 @@ void glTF2Exporter::GetMatTexProp(const aiMaterial &mat, float &prop, const char
} }
void glTF2Exporter::GetMatTex(const aiMaterial &mat, Ref<Texture> &texture, unsigned int &texCoord, aiTextureType tt, unsigned int slot = 0) { void glTF2Exporter::GetMatTex(const aiMaterial &mat, Ref<Texture> &texture, unsigned int &texCoord, aiTextureType tt, unsigned int slot = 0) {
if (mat.GetTextureCount(tt) > 0) { if (mat.GetTextureCount(tt) == 0) {
aiString tex; return;
}
aiString tex;
// Read texcoord (UV map index) // Read texcoord (UV map index)
mat.Get(AI_MATKEY_UVWSRC(tt, slot), texCoord); mat.Get(AI_MATKEY_UVWSRC(tt, slot), texCoord);
if (mat.Get(AI_MATKEY_TEXTURE(tt, slot), tex) == AI_SUCCESS) { if (mat.Get(AI_MATKEY_TEXTURE(tt, slot), tex) == AI_SUCCESS) {
std::string path = tex.C_Str(); std::string path = tex.C_Str();
if (path.size() > 0) { if (path.size() > 0) {
std::map<std::string, unsigned int>::iterator it = mTexturesByPath.find(path); std::map<std::string, unsigned int>::iterator it = mTexturesByPath.find(path);
if (it != mTexturesByPath.end()) { if (it != mTexturesByPath.end()) {
texture = mAsset->textures.Get(it->second); texture = mAsset->textures.Get(it->second);
} }
bool useBasisUniversal = false; bool useBasisUniversal = false;
if (!texture) { if (!texture) {
std::string texId = mAsset->FindUniqueID("", "texture"); std::string texId = mAsset->FindUniqueID("", "texture");
texture = mAsset->textures.Create(texId); texture = mAsset->textures.Create(texId);
mTexturesByPath[path] = texture.GetIndex(); mTexturesByPath[path] = texture.GetIndex();
std::string imgId = mAsset->FindUniqueID("", "image"); std::string imgId = mAsset->FindUniqueID("", "image");
texture->source = mAsset->images.Create(imgId); texture->source = mAsset->images.Create(imgId);
const aiTexture *curTex = mScene->GetEmbeddedTexture(path.c_str()); const aiTexture *curTex = mScene->GetEmbeddedTexture(path.c_str());
if (curTex != nullptr) { // embedded if (curTex != nullptr) { // embedded
texture->source->name = curTex->mFilename.C_Str(); texture->source->name = curTex->mFilename.C_Str();
//basisu: embedded ktx2, bu //basisu: embedded ktx2, bu
if (curTex->achFormatHint[0]) { if (curTex->achFormatHint[0]) {
std::string mimeType = "image/"; std::string mimeType = "image/";
if (memcmp(curTex->achFormatHint, "jpg", 3) == 0) if (memcmp(curTex->achFormatHint, "jpg", 3) == 0)
mimeType += "jpeg"; mimeType += "jpeg";
else if (memcmp(curTex->achFormatHint, "ktx", 3) == 0) { else if (memcmp(curTex->achFormatHint, "ktx", 3) == 0) {
useBasisUniversal = true;
mimeType += "ktx";
} else if (memcmp(curTex->achFormatHint, "kx2", 3) == 0) {
useBasisUniversal = true;
mimeType += "ktx2";
} else if (memcmp(curTex->achFormatHint, "bu", 2) == 0) {
useBasisUniversal = true;
mimeType += "basis";
} else
mimeType += curTex->achFormatHint;
texture->source->mimeType = mimeType;
}
// The asset has its own buffer, see Image::SetData
//basisu: "image/ktx2", "image/basis" as is
texture->source->SetData(reinterpret_cast<uint8_t *>(curTex->pcData), curTex->mWidth, *mAsset);
} else {
texture->source->uri = path;
if (texture->source->uri.find(".ktx") != std::string::npos ||
texture->source->uri.find(".basis") != std::string::npos) {
useBasisUniversal = true; useBasisUniversal = true;
} mimeType += "ktx";
} else if (memcmp(curTex->achFormatHint, "kx2", 3) == 0) {
useBasisUniversal = true;
mimeType += "ktx2";
} else if (memcmp(curTex->achFormatHint, "bu", 2) == 0) {
useBasisUniversal = true;
mimeType += "basis";
} else
mimeType += curTex->achFormatHint;
texture->source->mimeType = mimeType;
} }
//basisu // The asset has its own buffer, see Image::SetData
if (useBasisUniversal) { //basisu: "image/ktx2", "image/basis" as is
mAsset->extensionsUsed.KHR_texture_basisu = true; texture->source->SetData(reinterpret_cast<uint8_t *>(curTex->pcData), curTex->mWidth, *mAsset);
mAsset->extensionsRequired.KHR_texture_basisu = true; } else {
texture->source->uri = path;
if (texture->source->uri.find(".ktx") != std::string::npos ||
texture->source->uri.find(".basis") != std::string::npos) {
useBasisUniversal = true;
} }
GetTexSampler(mat, texture, tt, slot);
} }
//basisu
if (useBasisUniversal) {
mAsset->extensionsUsed.KHR_texture_basisu = true;
mAsset->extensionsRequired.KHR_texture_basisu = true;
}
GetTexSampler(mat, texture, tt, slot);
} }
} }
} }
@ -588,12 +590,7 @@ void glTF2Exporter::GetMatTex(const aiMaterial &mat, Ref<Texture> &texture, unsi
void glTF2Exporter::GetMatTex(const aiMaterial &mat, TextureInfo &prop, aiTextureType tt, unsigned int slot = 0) { void glTF2Exporter::GetMatTex(const aiMaterial &mat, TextureInfo &prop, aiTextureType tt, unsigned int slot = 0) {
Ref<Texture> &texture = prop.texture; Ref<Texture> &texture = prop.texture;
GetMatTex(mat, texture, prop.texCoord, tt, slot); GetMatTex(mat, texture, prop.texCoord, tt, slot);
//if (texture) {
// GetMatTexProp(mat, prop.texCoord, "texCoord", tt, slot);
//}
} }
void glTF2Exporter::GetMatTex(const aiMaterial &mat, NormalTextureInfo &prop, aiTextureType tt, unsigned int slot = 0) { void glTF2Exporter::GetMatTex(const aiMaterial &mat, NormalTextureInfo &prop, aiTextureType tt, unsigned int slot = 0) {
@ -681,12 +678,14 @@ bool glTF2Exporter::GetMatSpecGloss(const aiMaterial &mat, glTF2::PbrSpecularGlo
bool glTF2Exporter::GetMatSheen(const aiMaterial &mat, glTF2::MaterialSheen &sheen) { bool glTF2Exporter::GetMatSheen(const aiMaterial &mat, glTF2::MaterialSheen &sheen) {
// Return true if got any valid Sheen properties or textures // Return true if got any valid Sheen properties or textures
if (GetMatColor(mat, sheen.sheenColorFactor, AI_MATKEY_SHEEN_COLOR_FACTOR) != aiReturn_SUCCESS) if (GetMatColor(mat, sheen.sheenColorFactor, AI_MATKEY_SHEEN_COLOR_FACTOR) != aiReturn_SUCCESS) {
return false; return false;
}
// Default Sheen color factor {0,0,0} disables Sheen, so do not export // Default Sheen color factor {0,0,0} disables Sheen, so do not export
if (sheen.sheenColorFactor == defaultSheenFactor) if (sheen.sheenColorFactor == defaultSheenFactor) {
return false; return false;
}
mat.Get(AI_MATKEY_SHEEN_ROUGHNESS_FACTOR, sheen.sheenRoughnessFactor); mat.Get(AI_MATKEY_SHEEN_ROUGHNESS_FACTOR, sheen.sheenRoughnessFactor);
@ -781,9 +780,7 @@ void glTF2Exporter::ExportMaterials() {
aiColor4D specularColor; aiColor4D specularColor;
ai_real shininess; ai_real shininess;
if ( if (mat.Get(AI_MATKEY_COLOR_SPECULAR, specularColor) == AI_SUCCESS && mat.Get(AI_MATKEY_SHININESS, shininess) == AI_SUCCESS) {
mat.Get(AI_MATKEY_COLOR_SPECULAR, specularColor) == AI_SUCCESS &&
mat.Get(AI_MATKEY_SHININESS, shininess) == AI_SUCCESS) {
// convert specular color to luminance // convert specular color to luminance
float specularIntensity = specularColor[0] * 0.2125f + specularColor[1] * 0.7154f + specularColor[2] * 0.0721f; float specularIntensity = specularColor[0] * 0.2125f + specularColor[1] * 0.7154f + specularColor[2] * 0.0721f;
//normalize shininess (assuming max is 1000) with an inverse exponentional curve //normalize shininess (assuming max is 1000) with an inverse exponentional curve
@ -916,7 +913,8 @@ Ref<Node> FindSkeletonRootJoint(Ref<Skin> &skinRef) {
return parentNodeRef; return parentNodeRef;
} }
void ExportSkin(Asset &mAsset, const aiMesh *aimesh, Ref<Mesh> &meshRef, Ref<Buffer> &bufferRef, Ref<Skin> &skinRef, std::vector<aiMatrix4x4> &inverseBindMatricesData) { void ExportSkin(Asset &mAsset, const aiMesh *aimesh, Ref<Mesh> &meshRef, Ref<Buffer> &bufferRef, Ref<Skin> &skinRef,
std::vector<aiMatrix4x4> &inverseBindMatricesData) {
if (aimesh->mNumBones < 1) { if (aimesh->mNumBones < 1) {
return; return;
} }
@ -986,7 +984,8 @@ void ExportSkin(Asset &mAsset, const aiMesh *aimesh, Ref<Mesh> &meshRef, Ref<Buf
} // End: for-loop mNumMeshes } // End: for-loop mNumMeshes
Mesh::Primitive &p = meshRef->primitives.back(); Mesh::Primitive &p = meshRef->primitives.back();
Ref<Accessor> vertexJointAccessor = ExportData(mAsset, skinRef->id, bufferRef, aimesh->mNumVertices, vertexJointData, AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT); Ref<Accessor> vertexJointAccessor = ExportData(mAsset, skinRef->id, bufferRef, aimesh->mNumVertices,
vertexJointData, AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT);
if (vertexJointAccessor) { if (vertexJointAccessor) {
size_t offset = vertexJointAccessor->bufferView->byteOffset; size_t offset = vertexJointAccessor->bufferView->byteOffset;
size_t bytesLen = vertexJointAccessor->bufferView->byteLength; size_t bytesLen = vertexJointAccessor->bufferView->byteLength;
@ -1069,8 +1068,11 @@ void glTF2Exporter::ExportMeshes() {
p.ngonEncoded = (aim->mPrimitiveTypes & aiPrimitiveType_NGONEncodingFlag) != 0; p.ngonEncoded = (aim->mPrimitiveTypes & aiPrimitiveType_NGONEncodingFlag) != 0;
/******************* Vertices ********************/ /******************* Vertices ********************/
Ref<Accessor> v = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mVertices, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER); Ref<Accessor> v = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mVertices, AttribType::VEC3,
if (v) p.attributes.position.push_back(v); AttribType::VEC3, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
if (v) {
p.attributes.position.push_back(v);
}
/******************** Normals ********************/ /******************** Normals ********************/
// Normalize all normals as the validator can emit a warning otherwise // Normalize all normals as the validator can emit a warning otherwise
@ -1080,13 +1082,17 @@ void glTF2Exporter::ExportMeshes() {
} }
} }
Ref<Accessor> n = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mNormals, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER); Ref<Accessor> n = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mNormals, AttribType::VEC3,
if (n) p.attributes.normal.push_back(n); AttribType::VEC3, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
if (n) {
p.attributes.normal.push_back(n);
}
/************** Texture coordinates **************/ /************** Texture coordinates **************/
for (int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { for (int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
if (!aim->HasTextureCoords(i)) if (!aim->HasTextureCoords(i)) {
continue; continue;
}
// Flip UV y coords // Flip UV y coords
if (aim->mNumUVComponents[i] > 1) { if (aim->mNumUVComponents[i] > 1) {
@ -1098,16 +1104,21 @@ void glTF2Exporter::ExportMeshes() {
if (aim->mNumUVComponents[i] > 0) { if (aim->mNumUVComponents[i] > 0) {
AttribType::Value type = (aim->mNumUVComponents[i] == 2) ? AttribType::VEC2 : AttribType::VEC3; AttribType::Value type = (aim->mNumUVComponents[i] == 2) ? AttribType::VEC2 : AttribType::VEC3;
Ref<Accessor> tc = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mTextureCoords[i], AttribType::VEC3, type, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER); Ref<Accessor> tc = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mTextureCoords[i],
if (tc) p.attributes.texcoord.push_back(tc); AttribType::VEC3, type, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
if (tc) {
p.attributes.texcoord.push_back(tc);
}
} }
} }
/*************** Vertex colors ****************/ /*************** Vertex colors ****************/
for (unsigned int indexColorChannel = 0; indexColorChannel < aim->GetNumColorChannels(); ++indexColorChannel) { for (unsigned int indexColorChannel = 0; indexColorChannel < aim->GetNumColorChannels(); ++indexColorChannel) {
Ref<Accessor> c = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mColors[indexColorChannel], AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER); Ref<Accessor> c = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mColors[indexColorChannel],
if (c) AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER);
if (c) {
p.attributes.color.push_back(c); p.attributes.color.push_back(c);
}
} }
/*************** Vertices indices ****************/ /*************** Vertices indices ****************/
@ -1121,7 +1132,8 @@ void glTF2Exporter::ExportMeshes() {
} }
} }
p.indices = ExportData(*mAsset, meshId, b, indices.size(), &indices[0], AttribType::SCALAR, AttribType::SCALAR, ComponentType_UNSIGNED_INT, BufferViewTarget_ELEMENT_ARRAY_BUFFER); p.indices = ExportData(*mAsset, meshId, b, indices.size(), &indices[0], AttribType::SCALAR, AttribType::SCALAR,
ComponentType_UNSIGNED_INT, BufferViewTarget_ELEMENT_ARRAY_BUFFER);
} }
switch (aim->mPrimitiveTypes) { switch (aim->mPrimitiveTypes) {
@ -1136,6 +1148,7 @@ void glTF2Exporter::ExportMeshes() {
break; break;
default: // aiPrimitiveType_TRIANGLE default: // aiPrimitiveType_TRIANGLE
p.mode = PrimitiveMode_TRIANGLES; p.mode = PrimitiveMode_TRIANGLES;
break;
} }
/*************** Skins ****************/ /*************** Skins ****************/
@ -1155,8 +1168,9 @@ void glTF2Exporter::ExportMeshes() {
p.targets.resize(aim->mNumAnimMeshes); p.targets.resize(aim->mNumAnimMeshes);
for (unsigned int am = 0; am < aim->mNumAnimMeshes; ++am) { for (unsigned int am = 0; am < aim->mNumAnimMeshes; ++am) {
aiAnimMesh *pAnimMesh = aim->mAnimMeshes[am]; aiAnimMesh *pAnimMesh = aim->mAnimMeshes[am];
if (bExportTargetNames) if (bExportTargetNames) {
m->targetNames.push_back(pAnimMesh->mName.data); m->targetNames.emplace_back(pAnimMesh->mName.data);
}
// position // position
if (pAnimMesh->HasPositions()) { if (pAnimMesh->HasPositions()) {
// NOTE: in gltf it is the diff stored // NOTE: in gltf it is the diff stored
@ -1319,12 +1333,12 @@ unsigned int glTF2Exporter::ExportNodeHierarchy(const aiNode *n) {
} }
for (unsigned int i = 0; i < n->mNumMeshes; ++i) { for (unsigned int i = 0; i < n->mNumMeshes; ++i) {
node->meshes.push_back(mAsset->meshes.Get(n->mMeshes[i])); node->meshes.emplace_back(mAsset->meshes.Get(n->mMeshes[i]));
} }
for (unsigned int i = 0; i < n->mNumChildren; ++i) { for (unsigned int i = 0; i < n->mNumChildren; ++i) {
unsigned int idx = ExportNode(n->mChildren[i], node); unsigned int idx = ExportNode(n->mChildren[i], node);
node->children.push_back(mAsset->nodes.Get(idx)); node->children.emplace_back(mAsset->nodes.Get(idx));
} }
return node.GetIndex(); return node.GetIndex();
@ -1366,12 +1380,12 @@ unsigned int glTF2Exporter::ExportNode(const aiNode *n, Ref<Node> &parent) {
} }
for (unsigned int i = 0; i < n->mNumMeshes; ++i) { for (unsigned int i = 0; i < n->mNumMeshes; ++i) {
node->meshes.push_back(mAsset->meshes.Get(n->mMeshes[i])); node->meshes.emplace_back(mAsset->meshes.Get(n->mMeshes[i]));
} }
for (unsigned int i = 0; i < n->mNumChildren; ++i) { for (unsigned int i = 0; i < n->mNumChildren; ++i) {
unsigned int idx = ExportNode(n->mChildren[i], node); unsigned int idx = ExportNode(n->mChildren[i], node);
node->children.push_back(mAsset->nodes.Get(idx)); node->children.emplace_back(mAsset->nodes.Get(idx));
} }
return node.GetIndex(); return node.GetIndex();
@ -1386,7 +1400,7 @@ void glTF2Exporter::ExportScene() {
// root node will be the first one exported (idx 0) // root node will be the first one exported (idx 0)
if (mAsset->nodes.Size() > 0) { if (mAsset->nodes.Size() > 0) {
scene->nodes.push_back(mAsset->nodes.Get(0u)); scene->nodes.emplace_back(mAsset->nodes.Get(0u));
} }
// set as the default scene // set as the default scene
@ -1521,12 +1535,6 @@ void glTF2Exporter::ExportAnimations() {
AddSampler(animRef, animNode, scaleSampler, AnimationPath_SCALE); AddSampler(animRef, animNode, scaleSampler, AnimationPath_SCALE);
} }
} }
// Assimp documentation states this is not used (not implemented)
// for (unsigned int channelIndex = 0; channelIndex < anim->mNumMeshChannels; ++channelIndex) {
// const aiMeshAnim* meshChannel = anim->mMeshChannels[channelIndex];
// }
} // End: for-loop mNumAnimations } // End: for-loop mNumAnimations
} }

View File

@ -166,6 +166,8 @@ SET( Logging_SRCS
SOURCE_GROUP(Logging FILES ${Logging_SRCS}) SOURCE_GROUP(Logging FILES ${Logging_SRCS})
SET( Common_SRCS SET( Common_SRCS
Common/Compression.cpp
Common/Compression.h
Common/BaseImporter.cpp Common/BaseImporter.cpp
Common/BaseProcess.cpp Common/BaseProcess.cpp
Common/BaseProcess.h Common/BaseProcess.h
@ -1315,11 +1317,10 @@ ENDIF ()
INSTALL( TARGETS assimp INSTALL( TARGETS assimp
EXPORT "${TARGETS_EXPORT_NAME}" EXPORT "${TARGETS_EXPORT_NAME}"
LIBRARY DESTINATION ${ASSIMP_LIB_INSTALL_DIR} LIBRARY DESTINATION ${ASSIMP_LIB_INSTALL_DIR} COMPONENT ${LIBASSIMP_COMPONENT}
ARCHIVE DESTINATION ${ASSIMP_LIB_INSTALL_DIR} ARCHIVE DESTINATION ${ASSIMP_LIB_INSTALL_DIR} COMPONENT ${LIBASSIMP-DEV_COMPONENT}
RUNTIME DESTINATION ${ASSIMP_BIN_INSTALL_DIR} RUNTIME DESTINATION ${ASSIMP_BIN_INSTALL_DIR} COMPONENT ${LIBASSIMP_COMPONENT}
FRAMEWORK DESTINATION ${ASSIMP_LIB_INSTALL_DIR} FRAMEWORK DESTINATION ${ASSIMP_LIB_INSTALL_DIR} COMPONENT ${LIBASSIMP_COMPONENT}
COMPONENT ${LIBASSIMP_COMPONENT}
INCLUDES DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR} INCLUDES DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}
) )
INSTALL( FILES ${PUBLIC_HEADERS} DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}/assimp COMPONENT assimp-dev) INSTALL( FILES ${PUBLIC_HEADERS} DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}/assimp COMPONENT assimp-dev)

View File

@ -3,7 +3,7 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
Copyright (c) 2006-2021, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
@ -57,7 +57,7 @@ static const uint8_t tableDecodeBase64[128] = {
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, 0 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, 0
}; };
static const char* tableEncodeBase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; static const char *tableEncodeBase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
static inline char EncodeChar(uint8_t b) { static inline char EncodeChar(uint8_t b) {
return tableEncodeBase64[size_t(b)]; return tableEncodeBase64[size_t(b)];
@ -104,17 +104,16 @@ void Encode(const uint8_t *in, size_t inLength, std::string &out) {
} }
} }
void Encode(const std::vector<uint8_t>& in, std::string &out) { void Encode(const std::vector<uint8_t> &in, std::string &out) {
Encode (in.data (), in.size (), out); Encode(in.data(), in.size(), out);
} }
std::string Encode (const std::vector<uint8_t>& in) { std::string Encode(const std::vector<uint8_t> &in) {
std::string encoded; std::string encoded;
Encode (in, encoded); Encode(in, encoded);
return encoded; return encoded;
} }
size_t Decode(const char *in, size_t inLength, uint8_t *&out) { size_t Decode(const char *in, size_t inLength, uint8_t *&out) {
if (inLength % 4 != 0) { if (inLength % 4 != 0) {
throw DeadlyImportError("Invalid base64 encoded data: \"", std::string(in, std::min(size_t(32), inLength)), "\", length:", inLength); throw DeadlyImportError("Invalid base64 encoded data: \"", std::string(in, std::min(size_t(32), inLength)), "\", length:", inLength);
@ -159,23 +158,22 @@ size_t Decode(const char *in, size_t inLength, uint8_t *&out) {
return outLength; return outLength;
} }
size_t Decode(const std::string& in, std::vector<uint8_t>& out) { size_t Decode(const std::string &in, std::vector<uint8_t> &out) {
uint8_t* outPtr = nullptr; uint8_t *outPtr = nullptr;
size_t decodedSize = Decode (in.data (), in.size (), outPtr); size_t decodedSize = Decode(in.data(), in.size(), outPtr);
if (outPtr == nullptr) { if (outPtr == nullptr) {
return 0; return 0;
} }
out.assign (outPtr, outPtr + decodedSize); out.assign(outPtr, outPtr + decodedSize);
delete[] outPtr; delete[] outPtr;
return decodedSize; return decodedSize;
} }
std::vector<uint8_t> Decode (const std::string& in) { std::vector<uint8_t> Decode(const std::string &in) {
std::vector<uint8_t> result; std::vector<uint8_t> result;
Decode (in, result); Decode(in, result);
return result; return result;
} }
} } // namespace Base64
} // namespace Assimp
}

View File

@ -0,0 +1,214 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
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.
----------------------------------------------------------------------
*/
#include "Compression.h"
#include <assimp/ai_assert.h>
#include <assimp/Exceptional.h>
namespace Assimp {
struct Compression::impl {
bool mOpen;
z_stream mZSstream;
FlushMode mFlushMode;
impl() :
mOpen(false),
mZSstream(),
mFlushMode(Compression::FlushMode::NoFlush) {
// empty
}
};
Compression::Compression() :
mImpl(new impl) {
// empty
}
Compression::~Compression() {
ai_assert(mImpl != nullptr);
delete mImpl;
}
bool Compression::open(Format format, FlushMode flush, int windowBits) {
ai_assert(mImpl != nullptr);
if (mImpl->mOpen) {
return false;
}
// build a zlib stream
mImpl->mZSstream.opaque = Z_NULL;
mImpl->mZSstream.zalloc = Z_NULL;
mImpl->mZSstream.zfree = Z_NULL;
mImpl->mFlushMode = flush;
if (format == Format::Binary) {
mImpl->mZSstream.data_type = Z_BINARY;
} else {
mImpl->mZSstream.data_type = Z_ASCII;
}
// raw decompression without a zlib or gzip header
if (windowBits == 0) {
inflateInit(&mImpl->mZSstream);
} else {
inflateInit2(&mImpl->mZSstream, windowBits);
}
mImpl->mOpen = true;
return mImpl->mOpen;
}
static int getFlushMode(Compression::FlushMode flush) {
int z_flush = 0;
switch (flush) {
case Compression::FlushMode::NoFlush:
z_flush = Z_NO_FLUSH;
break;
case Compression::FlushMode::Block:
z_flush = Z_BLOCK;
break;
case Compression::FlushMode::Tree:
z_flush = Z_TREES;
break;
case Compression::FlushMode::SyncFlush:
z_flush = Z_SYNC_FLUSH;
break;
case Compression::FlushMode::Finish:
z_flush = Z_FINISH;
break;
default:
ai_assert(false);
break;
}
return z_flush;
}
constexpr size_t MYBLOCK = 32786;
size_t Compression::decompress(const void *data, size_t in, std::vector<char> &uncompressed) {
ai_assert(mImpl != nullptr);
if (data == nullptr || in == 0) {
return 0l;
}
mImpl->mZSstream.next_in = (Bytef*)(data);
mImpl->mZSstream.avail_in = (uInt)in;
int ret = 0;
size_t total = 0l;
const int flushMode = getFlushMode(mImpl->mFlushMode);
if (flushMode == Z_FINISH) {
mImpl->mZSstream.avail_out = static_cast<uInt>(uncompressed.size());
mImpl->mZSstream.next_out = reinterpret_cast<Bytef *>(&*uncompressed.begin());
ret = inflate(&mImpl->mZSstream, Z_FINISH);
if (ret != Z_STREAM_END && ret != Z_OK) {
throw DeadlyImportError("Compression", "Failure decompressing this file using gzip.");
}
total = mImpl->mZSstream.avail_out;
} else {
do {
Bytef block[MYBLOCK] = {};
mImpl->mZSstream.avail_out = MYBLOCK;
mImpl->mZSstream.next_out = block;
ret = inflate(&mImpl->mZSstream, flushMode);
if (ret != Z_STREAM_END && ret != Z_OK) {
throw DeadlyImportError("Compression", "Failure decompressing this file using gzip.");
}
const size_t have = MYBLOCK - mImpl->mZSstream.avail_out;
total += have;
uncompressed.resize(total);
::memcpy(uncompressed.data() + total - have, block, have);
} while (ret != Z_STREAM_END);
}
return total;
}
size_t Compression::decompressBlock(const void *data, size_t in, char *out, size_t availableOut) {
ai_assert(mImpl != nullptr);
if (data == nullptr || in == 0 || out == nullptr || availableOut == 0) {
return 0l;
}
// push data to the stream
mImpl->mZSstream.next_in = (Bytef *)data;
mImpl->mZSstream.avail_in = (uInt)in;
mImpl->mZSstream.next_out = (Bytef *)out;
mImpl->mZSstream.avail_out = (uInt)availableOut;
// and decompress the data ....
int ret = ::inflate(&mImpl->mZSstream, Z_SYNC_FLUSH);
if (ret != Z_OK && ret != Z_STREAM_END) {
throw DeadlyImportError("X: Failed to decompress MSZIP-compressed data");
}
::inflateReset(&mImpl->mZSstream);
::inflateSetDictionary(&mImpl->mZSstream, (const Bytef *)out, (uInt)availableOut - mImpl->mZSstream.avail_out);
return availableOut - (size_t)mImpl->mZSstream.avail_out;
}
bool Compression::isOpen() const {
ai_assert(mImpl != nullptr);
return mImpl->mOpen;
}
bool Compression::close() {
ai_assert(mImpl != nullptr);
if (!mImpl->mOpen) {
return false;
}
inflateEnd(&mImpl->mZSstream);
mImpl->mOpen = false;
return true;
}
} // namespace Assimp

View File

@ -0,0 +1,121 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
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.
----------------------------------------------------------------------
*/
#pragma once
#ifdef ASSIMP_BUILD_NO_OWN_ZLIB
#include <zlib.h>
#else
#include "../contrib/zlib/zlib.h"
#endif
#include <vector>
#include <cstddef> // size_t
namespace Assimp {
/// @brief This class provides the decompression of zlib-compressed data.
class Compression {
public:
static const int MaxWBits = MAX_WBITS;
/// @brief Describes the format data type
enum class Format {
InvalidFormat = -1, ///< Invalid enum type.
Binary = 0, ///< Binary format.
ASCII, ///< ASCII format.
NumFormats ///< The number of supported formats.
};
/// @brief The supported flush mode, used for blocked access.
enum class FlushMode {
InvalidFormat = -1, ///< Invalid enum type.
NoFlush = 0, ///< No flush, will be done on inflate end.
Block, ///< Assists in combination of compress.
Tree, ///< Assists in combination of compress and returns if stream is finish.
SyncFlush, ///< Synced flush mode.
Finish, ///< Finish mode, all in once, no block access.
NumModes ///< The number of supported modes.
};
/// @brief The class constructor.
Compression();
/// @brief The class destructor.
~Compression();
/// @brief Will open the access to the compression.
/// @param[in] format The format type
/// @param[in] flush The flush mode.
/// @param[in] windowBits The windows history working size, shall be between 8 and 15.
/// @return true if close was successful, false if not.
bool open(Format format, FlushMode flush, int windowBits);
/// @brief Will return the open state.
/// @return true if the access is opened, false if not.
bool isOpen() const;
/// @brief Will close the decompress access.
/// @return true if close was successful, false if not.
bool close();
/// @brief Will decompress the data buffer in one step.
/// @param[in] data The data to decompress
/// @param[in] in The size of the data.
/// @param[out uncompressed A std::vector containing the decompressed data.
size_t decompress(const void *data, size_t in, std::vector<char> &uncompressed);
/// @brief Will decompress the data buffer block-wise.
/// @param[in] data The compressed data
/// @param[in] in The size of the data buffer
/// @param[out] out The output buffer
/// @param[out] availableOut The upper limit of the output buffer.
/// @return The size of the decompressed data buffer.
size_t decompressBlock(const void *data, size_t in, char *out, size_t availableOut);
private:
struct impl;
impl *mImpl;
};
} // namespace Assimp

View File

@ -3,7 +3,7 @@
Open Asset Import Library (assimp) Open Asset Import Library (assimp)
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
Copyright (c) 2006-2019, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.

View File

@ -5,7 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -53,7 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
static const char *LEGAL_INFORMATION = static const char *LEGAL_INFORMATION =
"Open Asset Import Library (Assimp).\n" "Open Asset Import Library (Assimp).\n"
"A free C/C++ library to import various 3D file formats into applications\n\n" "A free C/C++ library to import various 3D file formats into applications\n\n"
"(c) 2006-2021, Assimp team\n" "(c) 2006-2022, Assimp team\n"
"License under the terms and conditions of the 3-clause BSD license\n" "License under the terms and conditions of the 3-clause BSD license\n"
"https://www.assimp.org\n"; "https://www.assimp.org\n";

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,

View File

@ -191,9 +191,9 @@ bool CalcTangentsProcess::ProcessMesh(aiMesh *pMesh, unsigned int meshIndex) {
tangent.x = (w.x * sy - v.x * ty) * dirCorrection; tangent.x = (w.x * sy - v.x * ty) * dirCorrection;
tangent.y = (w.y * sy - v.y * ty) * dirCorrection; tangent.y = (w.y * sy - v.y * ty) * dirCorrection;
tangent.z = (w.z * sy - v.z * ty) * dirCorrection; tangent.z = (w.z * sy - v.z * ty) * dirCorrection;
bitangent.x = (w.x * sx - v.x * tx) * dirCorrection; bitangent.x = (- w.x * sx + v.x * tx) * dirCorrection;
bitangent.y = (w.y * sx - v.y * tx) * dirCorrection; bitangent.y = (- w.y * sx + v.y * tx) * dirCorrection;
bitangent.z = (w.z * sx - v.z * tx) * dirCorrection; bitangent.z = (- w.z * sx + v.z * tx) * dirCorrection;
// store for every vertex of that face // store for every vertex of that face
for (unsigned int b = 0; b < face.mNumIndices; ++b) { for (unsigned int b = 0; b < face.mNumIndices; ++b) {
@ -201,7 +201,7 @@ bool CalcTangentsProcess::ProcessMesh(aiMesh *pMesh, unsigned int meshIndex) {
// project tangent and bitangent into the plane formed by the vertex' normal // project tangent and bitangent into the plane formed by the vertex' normal
aiVector3D localTangent = tangent - meshNorm[p] * (tangent * meshNorm[p]); aiVector3D localTangent = tangent - meshNorm[p] * (tangent * meshNorm[p]);
aiVector3D localBitangent = bitangent - meshNorm[p] * (bitangent * meshNorm[p]); aiVector3D localBitangent = bitangent - meshNorm[p] * (bitangent * meshNorm[p]) - localTangent * (bitangent * localTangent);
localTangent.NormalizeSafe(); localTangent.NormalizeSafe();
localBitangent.NormalizeSafe(); localBitangent.NormalizeSafe();

View File

@ -221,7 +221,7 @@ bool FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) {
if ( mConfigCheckAreaOfTriangle ) { if ( mConfigCheckAreaOfTriangle ) {
if ( face.mNumIndices == 3 ) { if ( face.mNumIndices == 3 ) {
ai_real area = calculateAreaOfTriangle( face, mesh ); ai_real area = calculateAreaOfTriangle( face, mesh );
if ( area < 1e-6 ) { if (area < ai_epsilon) {
if ( mConfigRemoveDegenerates ) { if ( mConfigRemoveDegenerates ) {
remove_me[ a ] = true; remove_me[ a ] = true;
++deg; ++deg;

View File

@ -50,6 +50,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace Assimp { namespace Assimp {
namespace Base64 { namespace Base64 {
/// @brief Will encode the given
/// @param in
/// @param inLength
/// @param out
void Encode(const uint8_t *in, size_t inLength, std::string &out); void Encode(const uint8_t *in, size_t inLength, std::string &out);
void Encode(const std::vector<uint8_t>& in, std::string &out); void Encode(const std::vector<uint8_t>& in, std::string &out);
std::string Encode(const std::vector<uint8_t>& in); std::string Encode(const std::vector<uint8_t>& in);

View File

@ -211,7 +211,7 @@ template <typename T> struct ByteSwap::_swapper<T,8> {
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
#if (defined AI_BUILD_BIG_ENDIAN) #if (defined AI_BUILD_BIG_ENDIAN)
# define AI_LE(t) (t) # define AI_LE(t) (t)
# define AI_BE(t) ByteSwap::Swapped(t) # define AI_BE(t) Assimp::ByteSwap::Swapped(t)
# define AI_LSWAP2(p) # define AI_LSWAP2(p)
# define AI_LSWAP4(p) # define AI_LSWAP4(p)
# define AI_LSWAP8(p) # define AI_LSWAP8(p)
@ -219,16 +219,16 @@ template <typename T> struct ByteSwap::_swapper<T,8> {
# define AI_LSWAP4P(p) # define AI_LSWAP4P(p)
# define AI_LSWAP8P(p) # define AI_LSWAP8P(p)
# define LE_NCONST const # define LE_NCONST const
# define AI_SWAP2(p) ByteSwap::Swap2(&(p)) # define AI_SWAP2(p) Assimp::ByteSwap::Swap2(&(p))
# define AI_SWAP4(p) ByteSwap::Swap4(&(p)) # define AI_SWAP4(p) Assimp::ByteSwap::Swap4(&(p))
# define AI_SWAP8(p) ByteSwap::Swap8(&(p)) # define AI_SWAP8(p) Assimp::ByteSwap::Swap8(&(p))
# define AI_SWAP2P(p) ByteSwap::Swap2((p)) # define AI_SWAP2P(p) Assimp::ByteSwap::Swap2((p))
# define AI_SWAP4P(p) ByteSwap::Swap4((p)) # define AI_SWAP4P(p) Assimp::ByteSwap::Swap4((p))
# define AI_SWAP8P(p) ByteSwap::Swap8((p)) # define AI_SWAP8P(p) Assimp::ByteSwap::Swap8((p))
# define BE_NCONST # define BE_NCONST
#else #else
# define AI_BE(t) (t) # define AI_BE(t) (t)
# define AI_LE(t) ByteSwap::Swapped(t) # define AI_LE(t) Assimp::ByteSwap::Swapped(t)
# define AI_SWAP2(p) # define AI_SWAP2(p)
# define AI_SWAP4(p) # define AI_SWAP4(p)
# define AI_SWAP8(p) # define AI_SWAP8(p)
@ -236,12 +236,12 @@ template <typename T> struct ByteSwap::_swapper<T,8> {
# define AI_SWAP4P(p) # define AI_SWAP4P(p)
# define AI_SWAP8P(p) # define AI_SWAP8P(p)
# define BE_NCONST const # define BE_NCONST const
# define AI_LSWAP2(p) ByteSwap::Swap2(&(p)) # define AI_LSWAP2(p) Assimp::ByteSwap::Swap2(&(p))
# define AI_LSWAP4(p) ByteSwap::Swap4(&(p)) # define AI_LSWAP4(p) Assimp::ByteSwap::Swap4(&(p))
# define AI_LSWAP8(p) ByteSwap::Swap8(&(p)) # define AI_LSWAP8(p) Assimp::ByteSwap::Swap8(&(p))
# define AI_LSWAP2P(p) ByteSwap::Swap2((p)) # define AI_LSWAP2P(p) Assimp::ByteSwap::Swap2((p))
# define AI_LSWAP4P(p) ByteSwap::Swap4((p)) # define AI_LSWAP4P(p) Assimp::ByteSwap::Swap4((p))
# define AI_LSWAP8P(p) ByteSwap::Swap8((p)) # define AI_LSWAP8P(p) Assimp::ByteSwap::Swap8((p))
# define LE_NCONST # define LE_NCONST
#endif #endif

View File

@ -98,10 +98,6 @@ public:
DeadlyErrorBase(Assimp::Formatter::format(), std::forward<T>(args)...) { DeadlyErrorBase(Assimp::Formatter::format(), std::forward<T>(args)...) {
// empty // empty
} }
#if defined(_MSC_VER) && defined(__clang__)
DeadlyImportError(DeadlyImportError& other) = delete;
#endif
}; };
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -114,10 +110,6 @@ public:
template<typename... T> template<typename... T>
explicit DeadlyExportError(T&&... args) : explicit DeadlyExportError(T&&... args) :
DeadlyErrorBase(Assimp::Formatter::format(), std::forward<T>(args)...) {} DeadlyErrorBase(Assimp::Formatter::format(), std::forward<T>(args)...) {}
#if defined(_MSC_VER) && defined(__clang__)
DeadlyExportError(DeadlyExportError& other) = delete;
#endif
}; };
#ifdef _MSC_VER #ifdef _MSC_VER

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2022, assimp team Copyright (c) 2006-2022, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -76,7 +75,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
inline uint32_t SuperFastHash (const char * data, uint32_t len = 0, uint32_t hash = 0) { inline uint32_t SuperFastHash (const char * data, uint32_t len = 0, uint32_t hash = 0) {
uint32_t tmp; uint32_t tmp;
int rem; int rem;
size_t offset;
if (!data) return 0; if (!data) return 0;
if (!len)len = (uint32_t)::strlen(data); if (!len)len = (uint32_t)::strlen(data);
@ -96,7 +96,11 @@ int rem;
switch (rem) { switch (rem) {
case 3: hash += get16bits (data); case 3: hash += get16bits (data);
hash ^= hash << 16; hash ^= hash << 16;
hash ^= data[sizeof (uint16_t)] << 18; offset = static_cast<size_t>(sizeof(uint16_t));
if (offset < 0) {
return 0;
}
hash ^= data[offset] << 18;
hash += hash >> 11; hash += hash >> 11;
break; break;
case 2: hash += get16bits (data); case 2: hash += get16bits (data);

View File

@ -0,0 +1,84 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2022, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the following
conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
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.
---------------------------------------------------------------------------
*/
/** @file OBJMATERIAL.h
* @brief Obj-specific material macros
*
*/
#ifndef AI_OBJMATERIAL_H_INC
#define AI_OBJMATERIAL_H_INC
#ifdef __GNUC__
# pragma GCC system_header
#endif
#include <assimp/material.h>
// ---------------------------------------------------------------------------
// the original illum property
#define AI_MATKEY_OBJ_ILLUM "$mat.illum", 0, 0
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// Pure key names for all obj texture-related properties
//! @cond MATS_DOC_FULL
// support for bump -bm
#define _AI_MATKEY_OBJ_BUMPMULT_BASE "$tex.bumpmult"
//! @endcond
// ---------------------------------------------------------------------------
#define AI_MATKEY_OBJ_BUMPMULT(type, N) _AI_MATKEY_OBJ_BUMPMULT_BASE, type, N
//! @cond MATS_DOC_FULL
#define AI_MATKEY_OBJ_BUMPMULT_NORMALS(N) \
AI_MATKEY_OBJ_BUMPMULT(aiTextureType_NORMALS, N)
#define AI_MATKEY_OBJ_BUMPMULT_HEIGHT(N) \
AI_MATKEY_OBJ_BUMPMULT(aiTextureType_HEIGHT, N)
//! @endcond
#endif

View File

@ -119,29 +119,41 @@ public:
* work for const references, so many function prototypes will * work for const references, so many function prototypes will
* include const basic_formatter<T>& s but might still want to * include const basic_formatter<T>& s but might still want to
* modify the formatted string without the need for a full copy.*/ * modify the formatted string without the need for a full copy.*/
template <typename TToken> template <typename TToken, typename std::enable_if<!std::is_base_of<std::exception, TToken>::value>::type * = nullptr>
const basic_formatter& operator << (const TToken& s) const { const basic_formatter &operator<<(const TToken &s) const {
underlying << s; underlying << s;
return *this; return *this;
} }
template <typename TToken> template <typename TToken, typename std::enable_if<std::is_base_of<std::exception, TToken>::value>::type * = nullptr>
basic_formatter& operator << (const TToken& s) { const basic_formatter &operator<<(const TToken &s) const {
underlying << s.what();
return *this;
}
template <typename TToken, typename std::enable_if<!std::is_base_of<std::exception, TToken>::value>::type * = nullptr>
basic_formatter &operator<<(const TToken &s) {
underlying << s; underlying << s;
return *this; return *this;
} }
template <typename TToken, typename std::enable_if<std::is_base_of<std::exception, TToken>::value>::type * = nullptr>
basic_formatter &operator<<(const TToken &s) {
underlying << s.what();
return *this;
}
// comma operator overloaded as well, choose your preferred way. // comma operator overloaded as well, choose your preferred way.
template <typename TToken> template <typename TToken>
const basic_formatter& operator, (const TToken& s) const { const basic_formatter& operator, (const TToken& s) const {
underlying << s; *this << s;
return *this; return *this;
} }
template <typename TToken> template <typename TToken>
basic_formatter& operator, (const TToken& s) { basic_formatter& operator, (const TToken& s) {
underlying << s; *this << s;
return *this; return *this;
} }
@ -149,7 +161,7 @@ public:
// See https://sourceforge.net/projects/assimp/forums/forum/817654/topic/4372824 // See https://sourceforge.net/projects/assimp/forums/forum/817654/topic/4372824
template <typename TToken> template <typename TToken>
basic_formatter& operator, (TToken& s) { basic_formatter& operator, (TToken& s) {
underlying << s; *this << s;
return *this; return *this;
} }

View File

@ -279,11 +279,11 @@ typedef unsigned int ai_uint;
#define AI_MATH_HALF_PI_F (AI_MATH_PI_F * 0.5f) #define AI_MATH_HALF_PI_F (AI_MATH_PI_F * 0.5f)
/* Tiny macro to convert from radians to degrees and back */ /* Tiny macro to convert from radians to degrees and back */
#define AI_DEG_TO_RAD(x) ((x) * (ai_real)0.0174532925) #define AI_DEG_TO_RAD(x) ((x) * (ai_real) 0.0174532925)
#define AI_RAD_TO_DEG(x) ((x) * (ai_real)57.2957795) #define AI_RAD_TO_DEG(x) ((x) * (ai_real) 57.2957795)
/* Numerical limits */ /* Numerical limits */
static const ai_real ai_epsilon = (ai_real)0.00001; static const ai_real ai_epsilon = (ai_real) 1e-6;
/* Support for big-endian builds */ /* Support for big-endian builds */
#if defined(__BYTE_ORDER__) #if defined(__BYTE_ORDER__)

View File

@ -95,7 +95,7 @@ public:
bool operator== (const aiMatrix3x3t<TReal>& m) const; bool operator== (const aiMatrix3x3t<TReal>& m) const;
bool operator!= (const aiMatrix3x3t<TReal>& m) const; bool operator!= (const aiMatrix3x3t<TReal>& m) const;
bool Equal(const aiMatrix3x3t<TReal>& m, TReal epsilon = 1e-6) const; bool Equal(const aiMatrix3x3t<TReal> &m, TReal epsilon = ai_epsilon) const;
template <typename TOther> template <typename TOther>
operator aiMatrix3x3t<TOther> () const; operator aiMatrix3x3t<TOther> () const;

View File

@ -110,7 +110,7 @@ public:
bool operator== (const aiMatrix4x4t& m) const; bool operator== (const aiMatrix4x4t& m) const;
bool operator!= (const aiMatrix4x4t& m) const; bool operator!= (const aiMatrix4x4t& m) const;
bool Equal(const aiMatrix4x4t& m, TReal epsilon = 1e-6) const; bool Equal(const aiMatrix4x4t &m, TReal epsilon = ai_epsilon) const;
// matrix multiplication. // matrix multiplication.
aiMatrix4x4t& operator *= (const aiMatrix4x4t& m); aiMatrix4x4t& operator *= (const aiMatrix4x4t& m);

View File

@ -92,7 +92,7 @@ public:
// transform vector by matrix // transform vector by matrix
aiQuaterniont& operator *= (const aiMatrix4x4t<TReal>& mat); aiQuaterniont& operator *= (const aiMatrix4x4t<TReal>& mat);
bool Equal(const aiQuaterniont& o, TReal epsilon = 1e-6) const; bool Equal(const aiQuaterniont &o, TReal epsilon = ai_epsilon) const;
public: public:

View File

@ -85,7 +85,7 @@ public:
bool operator== (const aiVector2t& other) const; bool operator== (const aiVector2t& other) const;
bool operator!= (const aiVector2t& other) const; bool operator!= (const aiVector2t& other) const;
bool Equal(const aiVector2t& other, TReal epsilon = 1e-6) const; bool Equal(const aiVector2t &other, TReal epsilon = ai_epsilon) const;
aiVector2t& operator= (TReal f); aiVector2t& operator= (TReal f);
const aiVector2t SymMul(const aiVector2t& o); const aiVector2t SymMul(const aiVector2t& o);

View File

@ -114,7 +114,7 @@ public:
bool operator < (const aiVector3t& other) const; bool operator < (const aiVector3t& other) const;
/// @brief /// @brief
bool Equal(const aiVector3t& other, TReal epsilon = 1e-6) const; bool Equal(const aiVector3t &other, TReal epsilon = ai_epsilon) const;
template <typename TOther> template <typename TOther>
operator aiVector3t<TOther> () const; operator aiVector3t<TOther> () const;

View File

@ -60,7 +60,7 @@ protected:
}; };
TEST_F(utMesh, emptyMeshHasNoContentTest) { TEST_F(utMesh, emptyMeshHasNoContentTest) {
EXPECT_EQ(0, mesh->mName.length); EXPECT_EQ(0u, mesh->mName.length);
EXPECT_FALSE(mesh->HasPositions()); EXPECT_FALSE(mesh->HasPositions());
EXPECT_FALSE(mesh->HasFaces()); EXPECT_FALSE(mesh->HasFaces());
EXPECT_FALSE(mesh->HasNormals()); EXPECT_FALSE(mesh->HasNormals());
@ -69,8 +69,8 @@ TEST_F(utMesh, emptyMeshHasNoContentTest) {
EXPECT_FALSE(mesh->HasVertexColors(AI_MAX_NUMBER_OF_COLOR_SETS)); EXPECT_FALSE(mesh->HasVertexColors(AI_MAX_NUMBER_OF_COLOR_SETS));
EXPECT_FALSE(mesh->HasTextureCoords(0)); EXPECT_FALSE(mesh->HasTextureCoords(0));
EXPECT_FALSE(mesh->HasTextureCoords(AI_MAX_NUMBER_OF_TEXTURECOORDS)); EXPECT_FALSE(mesh->HasTextureCoords(AI_MAX_NUMBER_OF_TEXTURECOORDS));
EXPECT_EQ(0, mesh->GetNumUVChannels()); EXPECT_EQ(0u, mesh->GetNumUVChannels());
EXPECT_EQ(0, mesh->GetNumColorChannels()); EXPECT_EQ(0u, mesh->GetNumColorChannels());
EXPECT_FALSE(mesh->HasBones()); EXPECT_FALSE(mesh->HasBones());
EXPECT_FALSE(mesh->HasTextureCoordsName(0)); EXPECT_FALSE(mesh->HasTextureCoordsName(0));
EXPECT_FALSE(mesh->HasTextureCoordsName(AI_MAX_NUMBER_OF_TEXTURECOORDS)); EXPECT_FALSE(mesh->HasTextureCoordsName(AI_MAX_NUMBER_OF_TEXTURECOORDS));
@ -80,8 +80,8 @@ TEST_F(utMesh, setTextureCoordsName) {
EXPECT_FALSE(mesh->HasTextureCoordsName(0)); EXPECT_FALSE(mesh->HasTextureCoordsName(0));
const aiString texcoords_name("texcoord_name"); const aiString texcoords_name("texcoord_name");
mesh->SetTextureCoordsName(0, texcoords_name); mesh->SetTextureCoordsName(0, texcoords_name);
EXPECT_TRUE(mesh->HasTextureCoordsName(0)); EXPECT_TRUE(mesh->HasTextureCoordsName(0u));
EXPECT_FALSE(mesh->HasTextureCoordsName(1)); EXPECT_FALSE(mesh->HasTextureCoordsName(1u));
ASSERT_NE(nullptr, mesh->mTextureCoordsNames); ASSERT_NE(nullptr, mesh->mTextureCoordsNames);
ASSERT_NE(nullptr, mesh->mTextureCoordsNames[0]); ASSERT_NE(nullptr, mesh->mTextureCoordsNames[0]);
EXPECT_STREQ(texcoords_name.C_Str(), mesh->mTextureCoordsNames[0]->C_Str()); EXPECT_STREQ(texcoords_name.C_Str(), mesh->mTextureCoordsNames[0]->C_Str());
@ -94,3 +94,4 @@ TEST_F(utMesh, setTextureCoordsName) {
EXPECT_EQ(nullptr, mesh->mTextureCoordsNames[0]); EXPECT_EQ(nullptr, mesh->mTextureCoordsNames[0]);
EXPECT_EQ(nullptr, mesh->GetTextureCoordsName(0)); EXPECT_EQ(nullptr, mesh->GetTextureCoordsName(0));
} }

View File

@ -124,9 +124,9 @@ TEST_F(utColladaExport, testExportLight) {
ASSERT_NE(pTest, nullptr); ASSERT_NE(pTest, nullptr);
ASSERT_TRUE(pTest->HasLights()); ASSERT_TRUE(pTest->HasLights());
const unsigned int origNumLights(pTest->mNumLights); const unsigned int origNumLights = pTest->mNumLights;
// There are FIVE!!! LIGHTS!!! // There are FIVE!!! LIGHTS!!!
EXPECT_EQ(5, origNumLights) << "lights.dae should contain five lights"; EXPECT_EQ(5u, origNumLights) << "lights.dae should contain five lights";
std::vector<aiLight> origLights(5); std::vector<aiLight> origLights(5);
for (size_t i = 0; i < origNumLights; i++) { for (size_t i = 0; i < origNumLights; i++) {

View File

@ -53,7 +53,7 @@ using namespace Assimp;
class utFBXImporterExporter : public AbstractImportExportBase { class utFBXImporterExporter : public AbstractImportExportBase {
public: public:
virtual bool importerTest() { bool importerTest() override {
Assimp::Importer importer; Assimp::Importer importer;
const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/spider.fbx", aiProcess_ValidateDataStructure); const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/spider.fbx", aiProcess_ValidateDataStructure);
return nullptr != scene; return nullptr != scene;

View File

@ -48,12 +48,12 @@ TEST_F( utVersion, aiGetLegalStringTest ) {
EXPECT_NE( lv, nullptr ); EXPECT_NE( lv, nullptr );
std::string text( lv ); std::string text( lv );
size_t pos = text.find(std::string("2021")); size_t pos = text.find(std::string("2022"));
EXPECT_NE(pos, std::string::npos); EXPECT_NE(pos, std::string::npos);
} }
TEST_F( utVersion, aiGetVersionMinorTest ) { TEST_F( utVersion, aiGetVersionMinorTest ) {
EXPECT_EQ(aiGetVersionMinor(), 1U); EXPECT_EQ(aiGetVersionMinor(), 2U);
} }
TEST_F( utVersion, aiGetVersionMajorTest ) { TEST_F( utVersion, aiGetVersionMajorTest ) {
@ -61,7 +61,7 @@ TEST_F( utVersion, aiGetVersionMajorTest ) {
} }
TEST_F( utVersion, aiGetVersionPatchTest ) { TEST_F( utVersion, aiGetVersionPatchTest ) {
EXPECT_EQ(aiGetVersionPatch(), 6U ); EXPECT_EQ(aiGetVersionPatch(), 0U );
} }
TEST_F( utVersion, aiGetCompileFlagsTest ) { TEST_F( utVersion, aiGetCompileFlagsTest ) {

View File

@ -573,7 +573,7 @@ TEST_F(utglTF2ImportExport, export_normalized_normals) {
scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxBadNormals-glTF-Binary/BoxBadNormals_out.glb", aiProcess_ValidateDataStructure); scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxBadNormals-glTF-Binary/BoxBadNormals_out.glb", aiProcess_ValidateDataStructure);
for ( auto i = 0u; i < scene->mMeshes[0]->mNumVertices; ++i ) { for ( auto i = 0u; i < scene->mMeshes[0]->mNumVertices; ++i ) {
const auto length = scene->mMeshes[0]->mNormals[i].Length(); const auto length = scene->mMeshes[0]->mNormals[i].Length();
EXPECT_TRUE(abs(length) < 1e-6 || abs(length - 1) < 1e-6); EXPECT_TRUE(abs(length) < 1e-6 || abs(length - 1) < ai_epsilon);
} }
} }