diff --git a/.travis.sh b/.travis.sh deleted file mode 100755 index 3be5d26b4..000000000 --- a/.travis.sh +++ /dev/null @@ -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 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 79ccf5b1a..000000000 --- a/.travis.yml +++ /dev/null @@ -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 diff --git a/BUILDBINARIES_EXAMPLE.bat b/BUILDBINARIES_EXAMPLE.bat index 2dd13a542..0752b3b47 100644 --- a/BUILDBINARIES_EXAMPLE.bat +++ b/BUILDBINARIES_EXAMPLE.bat @@ -10,16 +10,15 @@ :: Also see: https://github.com/assimp/assimp/pull/2646 SET SOURCE_DIR=. +SET GENERATOR=Visual Studio 16 2019 -:: For generators see "cmake --help" -SET GENERATOR=Visual Studio 15 2017 - -SET BINARIES_DIR="./BINARIES/Win32" -cmake CMakeLists.txt -G "%GENERATOR%" -S %SOURCE_DIR% -B %BINARIES_DIR% +SET BINARIES_DIR="./build/Win32" +cmake . -G "%GENERATOR%" -A Win32 -S %SOURCE_DIR% -B %BINARIES_DIR% +cmake --build %BINARIES_DIR% --config debug cmake --build %BINARIES_DIR% --config release -SET BINARIES_DIR="./BINARIES/x64" -cmake CMakeLists.txt -G "%GENERATOR% Win64" -S %SOURCE_DIR% -B %BINARIES_DIR% +SET BINARIES_DIR="./build/x64" +cmake . -G "%GENERATOR%" -A x64 -S %SOURCE_DIR% -B %BINARIES_DIR% cmake --build %BINARIES_DIR% --config debug cmake --build %BINARIES_DIR% --config release diff --git a/CMakeLists.txt b/CMakeLists.txt index cd12d3a9d..5cbbfef2c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,14 +49,14 @@ option(ASSIMP_HUNTER_ENABLED "Enable Hunter package manager support" OFF) IF(ASSIMP_HUNTER_ENABLED) include("cmake-modules/HunterGate.cmake") HunterGate( - URL "https://github.com/cpp-pm/hunter/archive/v0.23.311.tar.gz" - SHA1 "1a82b9b73055879181cb1466b2ab5d48ee8ae410" + URL "https://github.com/cpp-pm/hunter/archive/v0.24.0.tar.gz" + SHA1 "a3d7f4372b1dcd52faa6ff4a3bd5358e1d0e5efd" ) add_definitions(-DASSIMP_USE_HUNTER) ENDIF() -PROJECT(Assimp VERSION 5.1.6) +PROJECT(Assimp VERSION 5.2.0) # All supported options ############################################### @@ -134,12 +134,12 @@ OPTION ( ASSIMP_IGNORE_GIT_HASH OFF ) -IF ( WIN32 ) +IF (WIN32) # Use subset of Windows.h ADD_DEFINITIONS( -DWIN32_LEAN_AND_MEAN ) IF(MSVC) - OPTION ( ASSIMP_BUILD_ASSIMP_VIEW + OPTION (ASSIMP_BUILD_ASSIMP_VIEW "If the Assimp view tool is built. (requires DirectX)" OFF ) @@ -243,6 +243,13 @@ SET(ASSIMP_LIBRARY_SUFFIX "" CACHE STRING "Suffix to append to library names") IF( UNIX ) # Use GNUInstallDirs for Unix predefined directories 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() # Grouped compiler settings ######################################## @@ -341,9 +348,24 @@ INCLUDE (FindPkgMacros) INCLUDE (PrecompiledHeader) # Set Assimp project output directory variables. -SET(ASSIMP_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin" CACHE STRING "Path for runtime output files") -SET(ASSIMP_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin" CACHE STRING "Path for library output files") -SET(ASSIMP_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib" CACHE STRING "Path for archive output files") +# Will respect top-level CMAKE_*_OUTPUT_DIRECTORY variables if any are set. +IF(NOT DEFINED CMAKE_RUNTIME_OUTPUT_DIRECTORY) + 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 # respective Assimp output directories. @@ -672,11 +694,13 @@ ENDIF() ADD_SUBDIRECTORY( code/ ) IF ( ASSIMP_BUILD_ASSIMP_TOOLS ) # The viewer for windows only - IF ( WIN32 ) + IF (WIN32) OPTION ( ASSIMP_BUILD_ASSIMP_VIEW "If the Assimp view tool is built. (requires DirectX)" OFF ) IF ( ASSIMP_BUILD_ASSIMP_VIEW ) ADD_SUBDIRECTORY( tools/assimp_view/ ) ENDIF () + ELSE() + MESSAGE("Building Assimp Viewer only supported on Windows.") ENDIF () # The command line tool ADD_SUBDIRECTORY( tools/assimp_cmd/ ) diff --git a/code/AssetLib/ASE/ASEParser.cpp b/code/AssetLib/ASE/ASEParser.cpp index f684b56d3..14eb720f4 100644 --- a/code/AssetLib/ASE/ASEParser.cpp +++ b/code/AssetLib/ASE/ASEParser.cpp @@ -112,6 +112,7 @@ using namespace Assimp::ASE; // ------------------------------------------------------------------------------------------------ Parser::Parser(const char *szFile, unsigned int fileFormatDefault) { ai_assert(nullptr != szFile); + filePtr = szFile; iFileFormat = fileFormatDefault; @@ -486,7 +487,7 @@ void Parser::ParseLV1MaterialListBlock() { ParseLV4MeshLong(iIndex); if (iIndex >= iMaterialCount) { - LogError("Out of range: material index is too large"); + LogWarning("Out of range: material index is too large"); iIndex = iMaterialCount - 1; return; } @@ -905,7 +906,6 @@ void Parser::ParseLV2LightSettingsBlock(ASE::Light &light) { } AI_ASE_HANDLE_SECTION("2", "LIGHT_SETTINGS"); } - return; } // ------------------------------------------------------------------------------------------------ @@ -1782,7 +1782,9 @@ void Parser::ParseLV4MeshFace(ASE::Face &out) { // *MESH_MTLID is optional, too while (true) { - if ('*' == *filePtr) break; + if ('*' == *filePtr) { + break; + } if (IsLineEnd(*filePtr)) { return; } @@ -1831,8 +1833,9 @@ void Parser::ParseLV4MeshFloatTriple(ai_real *apOut, unsigned int &rIndexOut) { void Parser::ParseLV4MeshFloatTriple(ai_real *apOut) { ai_assert(nullptr != apOut); - for (unsigned int i = 0; i < 3; ++i) + for (unsigned int i = 0; i < 3; ++i) { ParseLV4MeshFloat(apOut[i]); + } } // ------------------------------------------------------------------------------------------------ void Parser::ParseLV4MeshFloat(ai_real &fOut) { diff --git a/code/AssetLib/Assbin/AssbinFileWriter.cpp b/code/AssetLib/Assbin/AssbinFileWriter.cpp index 72fbfdcb1..1d16f179e 100644 --- a/code/AssetLib/Assbin/AssbinFileWriter.cpp +++ b/code/AssetLib/Assbin/AssbinFileWriter.cpp @@ -182,6 +182,8 @@ inline size_t Write(IOStream *stream, const aiVertexWeight &v) { return t + Write(stream, v.mWeight); } +constexpr size_t MatrixSize = 64; + // ----------------------------------------------------------------------------------- // Serialize a mat4x4 template <> @@ -192,7 +194,7 @@ inline size_t Write(IOStream *stream, const aiMatrix4x4 &m) { } } - return 64; + return MatrixSize; } // ----------------------------------------------------------------------------------- diff --git a/code/AssetLib/Blender/BlenderLoader.cpp b/code/AssetLib/Blender/BlenderLoader.cpp index 3d9e8017b..b3591b4f1 100644 --- a/code/AssetLib/Blender/BlenderLoader.cpp +++ b/code/AssetLib/Blender/BlenderLoader.cpp @@ -66,11 +66,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // zlib is needed for compressed blend files #ifndef ASSIMP_BUILD_NO_COMPRESSED_BLEND -# ifdef ASSIMP_BUILD_NO_OWN_ZLIB +#include "Common/Compression.h" +/* #ifdef ASSIMP_BUILD_NO_OWN_ZLIB # include # else # include "../contrib/zlib/zlib.h" -# endif +# endif*/ #endif namespace Assimp { @@ -141,7 +142,7 @@ void BlenderImporter::SetupProperties(const Importer * /*pImp*/) { void BlenderImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) { #ifndef ASSIMP_BUILD_NO_COMPRESSED_BLEND - std::vector uncompressed; + std::vector uncompressed; #endif FileDatabase file; @@ -159,7 +160,6 @@ void BlenderImporter::InternReadFile(const std::string &pFile, #ifdef ASSIMP_BUILD_NO_COMPRESSED_BLEND ThrowException("BLENDER magic bytes are missing, is this file compressed (Assimp was built without decompression support)?"); #else - if (magic[0] != 0x1f || static_cast(magic[1]) != 0x8b) { 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); std::shared_ptr reader = std::shared_ptr(new StreamReaderLE(stream)); - // build a zlib stream - z_stream zstream; - zstream.opaque = Z_NULL; - zstream.zalloc = Z_NULL; - zstream.zfree = Z_NULL; - 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(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); + size_t total = 0; + Compression compression; + if (compression.open(Compression::Format::Binary, Compression::FlushMode::NoFlush, 16 + Compression::MaxWBits)) { + total = compression.decompress((unsigned char *)reader->GetPtr(), reader->GetRemainingSize(), uncompressed); + compression.close(); + } // replace the input stream with a memory stream stream.reset(new MemoryIOStream(reinterpret_cast(uncompressed.data()), total)); diff --git a/code/AssetLib/Collada/ColladaLoader.cpp b/code/AssetLib/Collada/ColladaLoader.cpp index 447055082..775ba44d2 100644 --- a/code/AssetLib/Collada/ColladaLoader.cpp +++ b/code/AssetLib/Collada/ColladaLoader.cpp @@ -357,9 +357,9 @@ void ColladaLoader::BuildLightsForNode(const ColladaParser &pParser, const Node out->mAngleInnerCone = AI_DEG_TO_RAD(srcLight->mFalloffAngle); // ... 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. - 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 .... // epsilon chosen to be 0.1 float f = 1.0f; @@ -1065,7 +1065,7 @@ void insertMorphTimeValue(std::vector &values, float time, floa return; } 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); return; } else if (time > values[i].mTime && time < values[i + 1].mTime) { diff --git a/code/AssetLib/FBX/FBXCommon.h b/code/AssetLib/FBX/FBXCommon.h index 54e2e9e50..ec7459c9e 100644 --- a/code/AssetLib/FBX/FBXCommon.h +++ b/code/AssetLib/FBX/FBXCommon.h @@ -80,8 +80,10 @@ enum TransformInheritance { TransformInheritance_MAX // end-of-enum sentinel }; + } // namespace FBX } // namespace Assimp + #endif // ASSIMP_BUILD_NO_FBX_EXPORTER #endif // AI_FBXCOMMON_H_INC diff --git a/code/AssetLib/FBX/FBXConverter.cpp b/code/AssetLib/FBX/FBXConverter.cpp index 3cefed023..32872108b 100644 --- a/code/AssetLib/FBX/FBXConverter.cpp +++ b/code/AssetLib/FBX/FBXConverter.cpp @@ -653,7 +653,7 @@ bool FBXConverter::NeedsComplexTransformationChain(const Model &model) { const PropertyTable &props = model.Props(); bool ok; - const float zero_epsilon = 1e-6f; + const float zero_epsilon = ai_epsilon; const aiVector3D all_ones(1.0f, 1.0f, 1.0f); for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) { const TransformationComp comp = static_cast(i); @@ -1267,7 +1267,7 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co const std::vector &normals = mesh.GetNormals(); if (normals.size()) { ai_assert(normals.size() == vertices.size()); - out_mesh->mNormals = new aiVector3D[vertices.size()]; + out_mesh->mNormals = new aiVector3D[count_vertices]; } // allocate tangents, binormals. @@ -1295,8 +1295,8 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co ai_assert(tangents.size() == vertices.size()); ai_assert(binormals->size() == vertices.size()); - out_mesh->mTangents = new aiVector3D[vertices.size()]; - out_mesh->mBitangents = new aiVector3D[vertices.size()]; + out_mesh->mTangents = new aiVector3D[count_vertices]; + out_mesh->mBitangents = new aiVector3D[count_vertices]; } } @@ -1308,7 +1308,7 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co break; } - out_mesh->mTextureCoords[i] = new aiVector3D[vertices.size()]; + out_mesh->mTextureCoords[i] = new aiVector3D[count_vertices]; out_mesh->mNumUVComponents[i] = 2; } @@ -1320,7 +1320,7 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co break; } - out_mesh->mColors[i] = new aiColor4D[vertices.size()]; + out_mesh->mColors[i] = new aiColor4D[count_vertices]; } unsigned int cursor = 0, in_cursor = 0; @@ -3187,7 +3187,8 @@ aiNodeAnim* FBXConverter::GenerateSimpleNodeAnim(const std::string& name, } bool ok = false; - const float zero_epsilon = 1e-6f; + + const float zero_epsilon = ai_epsilon; const aiVector3D& preRotation = PropertyGet(props, "PreRotation", ok); if (ok && preRotation.SquareLength() > zero_epsilon) { diff --git a/code/AssetLib/FBX/FBXParser.cpp b/code/AssetLib/FBX/FBXParser.cpp index ef26f5322..e20377a3c 100644 --- a/code/AssetLib/FBX/FBXParser.cpp +++ b/code/AssetLib/FBX/FBXParser.cpp @@ -4,7 +4,6 @@ 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, @@ -46,11 +45,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_FBX_IMPORTER -#ifdef ASSIMP_BUILD_NO_OWN_ZLIB -# include -#else -# include "../contrib/zlib/zlib.h" -#endif +//#ifdef ASSIMP_BUILD_NO_OWN_ZLIB +#include "Common/Compression.h" +//# include +//#else +//# include "../contrib/zlib/zlib.h" +//#endif #include "FBXTokenizer.h" #include "FBXParser.h" @@ -115,9 +115,7 @@ namespace Assimp { namespace FBX { // ------------------------------------------------------------------------------------------------ -Element::Element(const Token& key_token, Parser& parser) -: key_token(key_token) -{ +Element::Element(const Token& key_token, Parser& parser) : key_token(key_token) { TokenPtr n = nullptr; do { n = parser.AdvanceToNextToken(); @@ -210,8 +208,7 @@ Scope::Scope(Parser& parser,bool topLevel) } // ------------------------------------------------------------------------------------------------ -Scope::~Scope() -{ +Scope::~Scope() { for(ElementMap::value_type& v : elements) { 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) void ReadBinaryDataArray(char type, uint32_t count, const char*& data, const char* end, - std::vector& buff, - const Element& /*el*/) -{ + std::vector& buff, const Element& /*el*/) { BE_NCONST uint32_t encmode = SafeParse(data, end); AI_SWAP4(encmode); data += 4; @@ -571,31 +566,11 @@ void ReadBinaryDataArray(char type, uint32_t count, const char*& data, const cha else if(encmode == 1) { // zlib/deflate, next comes ZIP head (0x78 0x01) // see http://www.ietf.org/rfc/rfc1950.txt - - z_stream zstream; - zstream.opaque = Z_NULL; - zstream.zalloc = Z_NULL; - 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"); + Compression compress; + if (compress.open(Compression::Format::Binary, Compression::FlushMode::Finish, 0)) { + compress.decompress(data, comp_len, buff); + compress.close(); } - - zstream.next_in = reinterpret_cast( const_cast(data) ); - zstream.avail_in = comp_len; - - zstream.avail_out = static_cast(buff.size()); - zstream.next_out = reinterpret_cast(&*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 else { @@ -701,7 +676,6 @@ void ParseVectorDataArray(std::vector& out, const Element& el) } } - // ------------------------------------------------------------------------------------------------ // read an array of color4 tuples void ParseVectorDataArray(std::vector& out, const Element& el) @@ -786,8 +760,7 @@ void ParseVectorDataArray(std::vector& out, const Element& el) // ------------------------------------------------------------------------------------------------ // read an array of float2 tuples -void ParseVectorDataArray(std::vector& out, const Element& el) -{ +void ParseVectorDataArray(std::vector& out, const Element& el) { out.resize( 0 ); const TokenList& tok = el.Tokens(); if(tok.empty()) { @@ -831,8 +804,7 @@ void ParseVectorDataArray(std::vector& out, const Element& el) out.push_back(aiVector2D(static_cast(d[0]), static_cast(d[1]))); } - } - else if (type == 'f') { + } else if (type == 'f') { const float* f = reinterpret_cast(&buff[0]); for (unsigned int i = 0; i < count2; ++i, f += 2) { out.push_back(aiVector2D(f[0],f[1])); @@ -865,8 +837,7 @@ void ParseVectorDataArray(std::vector& out, const Element& el) // ------------------------------------------------------------------------------------------------ // read an array of ints -void ParseVectorDataArray(std::vector& out, const Element& el) -{ +void ParseVectorDataArray(std::vector& out, const Element& el) { out.resize( 0 ); const TokenList& tok = el.Tokens(); if(tok.empty()) { diff --git a/code/AssetLib/HMP/HMPLoader.cpp b/code/AssetLib/HMP/HMPLoader.cpp index 93d69dbcd..1625cb359 100644 --- a/code/AssetLib/HMP/HMPLoader.cpp +++ b/code/AssetLib/HMP/HMPLoader.cpp @@ -275,7 +275,9 @@ void HMPImporter::InternReadFile_HMP7() { // now load all vertices from the file aiVector3D *pcVertOut = pcMesh->mVertices; + ai_assert(pcVertOut != nullptr); aiVector3D *pcNorOut = pcMesh->mNormals; + ai_assert(pcNorOut != nullptr); const HMP::Vertex_HMP7 *src = (const HMP::Vertex_HMP7 *)szCurrent; for (unsigned int y = 0; y < height; ++y) { 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 ReadFirstSkin(pcHeader->numskins, szCurrent, &szCurrent); - } else { - // generate a default material - const int iMode = (int)aiShadingMode_Gouraud; - aiMaterial *pcHelper = new aiMaterial(); - pcHelper->AddProperty(&iMode, 1, AI_MATKEY_SHADING_MODEL); + *szCurrentOut = szCurrent; + return; + } - aiColor3D clr; - clr.b = clr.g = clr.r = 0.6f; - pcHelper->AddProperty(&clr, 1, AI_MATKEY_COLOR_DIFFUSE); - pcHelper->AddProperty(&clr, 1, AI_MATKEY_COLOR_SPECULAR); + // generate a default material + const int iMode = (int)aiShadingMode_Gouraud; + aiMaterial *pcHelper = new aiMaterial(); + pcHelper->AddProperty(&iMode, 1, AI_MATKEY_SHADING_MODEL); - clr.b = clr.g = clr.r = 0.05f; - pcHelper->AddProperty(&clr, 1, AI_MATKEY_COLOR_AMBIENT); + aiColor3D clr; + clr.b = clr.g = clr.r = 0.6f; + pcHelper->AddProperty(&clr, 1, AI_MATKEY_COLOR_DIFFUSE); + pcHelper->AddProperty(&clr, 1, AI_MATKEY_COLOR_SPECULAR); - aiString szName; - szName.Set(AI_DEFAULT_MATERIAL_NAME); - pcHelper->AddProperty(&szName, AI_MATKEY_NAME); + clr.b = clr.g = clr.r = 0.05f; + pcHelper->AddProperty(&clr, 1, AI_MATKEY_COLOR_AMBIENT); - // add the material to the scene - pScene->mNumMaterials = 1; - pScene->mMaterials = new aiMaterial *[1]; - pScene->mMaterials[0] = pcHelper; - } + aiString szName; + szName.Set(AI_DEFAULT_MATERIAL_NAME); + pcHelper->AddProperty(&szName, AI_MATKEY_NAME); + + // add the material to the scene + pScene->mNumMaterials = 1; + pScene->mMaterials = new aiMaterial *[1]; + pScene->mMaterials[0] = pcHelper; *szCurrentOut = szCurrent; } @@ -373,27 +377,36 @@ void HMPImporter::CreateOutputFaceList(unsigned int width, unsigned int height) aiVector3D *pcUVOut(pcUVs); // Build the terrain square + const unsigned int upperBound = pcMesh->mNumVertices; unsigned int iCurrent = 0; 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) { pcFaceOut->mNumIndices = 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[(y + 1) * width + x]; - *pcVertOut++ = pcMesh->mVertices[(y + 1) * width + x + 1]; - *pcVertOut++ = pcMesh->mVertices[y * width + x + 1]; + *pcVertOut++ = pcMesh->mVertices[offset0 + x]; + *pcVertOut++ = pcMesh->mVertices[offset1 + x]; + *pcVertOut++ = pcMesh->mVertices[offset1 + x + 1]; + *pcVertOut++ = pcMesh->mVertices[offset0 + x + 1]; - *pcNorOut++ = pcMesh->mNormals[y * width + x]; - *pcNorOut++ = pcMesh->mNormals[(y + 1) * width + x]; - *pcNorOut++ = pcMesh->mNormals[(y + 1) * width + x + 1]; - *pcNorOut++ = pcMesh->mNormals[y * width + x + 1]; + *pcNorOut++ = pcMesh->mNormals[offset0 + x]; + *pcNorOut++ = pcMesh->mNormals[offset1 + x]; + *pcNorOut++ = pcMesh->mNormals[offset1 + x + 1]; + *pcNorOut++ = pcMesh->mNormals[offset0 + x + 1]; if (pcMesh->mTextureCoords[0]) { - *pcUVOut++ = pcMesh->mTextureCoords[0][y * width + x]; - *pcUVOut++ = pcMesh->mTextureCoords[0][(y + 1) * width + x]; - *pcUVOut++ = pcMesh->mTextureCoords[0][(y + 1) * width + x + 1]; - *pcUVOut++ = pcMesh->mTextureCoords[0][y * width + x + 1]; + *pcUVOut++ = pcMesh->mTextureCoords[0][offset0 + x]; + *pcUVOut++ = pcMesh->mTextureCoords[0][offset1 + x]; + *pcUVOut++ = pcMesh->mTextureCoords[0][offset1 + x + 1]; + *pcUVOut++ = pcMesh->mTextureCoords[0][offset0 + x + 1]; } for (unsigned int i = 0; i < 4; ++i) diff --git a/code/AssetLib/IFC/IFCBoolean.cpp b/code/AssetLib/IFC/IFCBoolean.cpp index ee255e612..36912a7d8 100644 --- a/code/AssetLib/IFC/IFCBoolean.cpp +++ b/code/AssetLib/IFC/IFCBoolean.cpp @@ -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 // point leaves the plane through the other side - if (std::abs(dotOne + dotTwo) < 1e-6) + if (std::abs(dotOne + dotTwo) < ai_epsilon) return false; // 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 ((assumeStartOnWhiteSide && dotOne + dotTwo < 1e-6) || (!assumeStartOnWhiteSide && dotOne + dotTwo > -1e-6)) { + if (std::abs(dotTwo) < ai_epsilon) { + if ((assumeStartOnWhiteSide && dotOne + dotTwo < ai_epsilon) || (!assumeStartOnWhiteSide && dotOne + dotTwo > -ai_epsilon)) { out = e0; return true; } 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 // 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; // 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++) { 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) { 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 // solve b0 + b*s = e0 + e*t for (s,t) 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) 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 // 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. // 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) { @@ -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 (std::abs(polyNormal * n) > 0.9999) { - bool isOnWhiteSide = (srcVertices[0] - p) * n > -1e-6; + bool isOnWhiteSide = (srcVertices[0] - p) * n > -ai_epsilon; std::vector &targetSide = isOnWhiteSide ? whiteside : blackside; targetSide.insert(targetSide.end(), srcVertices, srcVertices + srcVtxCount); } else { // 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, // 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) { IfcVector3 e0 = srcVertices[a]; IfcVector3 e1 = srcVertices[(a + 1) % srcVtxCount]; diff --git a/code/AssetLib/IFC/IFCGeometry.cpp b/code/AssetLib/IFC/IFCGeometry.cpp index 4c088955f..ef5954251 100644 --- a/code/AssetLib/IFC/IFCGeometry.cpp +++ b/code/AssetLib/IFC/IFCGeometry.cpp @@ -380,21 +380,19 @@ void ProcessSweptDiskSolid(const Schema_2x3::IfcSweptDiskSolid &solid, TempMesh& bool take_any = false; 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.z = startvec.z; q.x = -(d.y * q.y + d.z * q.z) / d.x; last_dir = 0; break; - } - else if ((last_dir == 1 || take_any) && std::abs(d.y) > 1e-6) { + } else if ((last_dir == 1 || take_any) && std::abs(d.y) > ai_epsilon) { q.x = startvec.x; q.z = startvec.z; q.y = -(d.x * q.x + d.z * q.z) / d.y; last_dir = 1; break; - } - else if ((last_dir == 2 && std::abs(d.z) > 1e-6) || take_any) { + } else if ((last_dir == 2 && std::abs(d.z) > ai_epsilon) || take_any) { q.y = startvec.y; q.x = startvec.x; 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; } -const auto closeDistance = 1e-6; +const auto closeDistance = ai_epsilon; bool areClose(Schema_2x3::IfcCartesianPoint pt1,Schema_2x3::IfcCartesianPoint pt2) { 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, // forming new triangles. 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 ) { result.Append(curve); } diff --git a/code/AssetLib/IFC/IFCOpenings.cpp b/code/AssetLib/IFC/IFCOpenings.cpp index c261a24b0..74200195b 100644 --- a/code/AssetLib/IFC/IFCOpenings.cpp +++ b/code/AssetLib/IFC/IFCOpenings.cpp @@ -1133,7 +1133,7 @@ IfcMatrix4 ProjectOntoPlane(std::vector& out_contour, const TempMesh } 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 @@ -1435,7 +1435,7 @@ std::vector GetContourInPlane2D(std::shared_ptr mesh,IfcMa const auto outernor = ((mesh->mVerts[2] - mesh->mVerts[0]) ^ (mesh->mVerts[1] - mesh->mVerts[0])).Normalize(); const IfcFloat dot = planeNor * outernor; - if(std::fabs(dot) < 1.f - 1e-6f) { + if (std::fabs(dot) < 1.f - ai_epsilon) { std::stringstream msg; msg << "Skipping: Unaligned opening (" << planeNor.x << ", " << planeNor.y << ", " << planeNor.z << ")"; msg << " . ( " << outernor.x << ", " << outernor.y << ", " << outernor.z << ") = " << dot; @@ -1476,7 +1476,7 @@ std::vector GetContourInPlane2D(std::shared_ptr mesh,IfcMa return contour; } -const float close { 1e-6f }; +const float close{ ai_epsilon }; static bool isClose(IfcVector2 first,IfcVector2 second) { auto diff = (second - first); diff --git a/code/AssetLib/IFC/IFCUtil.cpp b/code/AssetLib/IFC/IFCUtil.cpp index 2ff0d6a58..6b378c1da 100644 --- a/code/AssetLib/IFC/IFCUtil.cpp +++ b/code/AssetLib/IFC/IFCUtil.cpp @@ -228,25 +228,24 @@ void TempMesh::ComputePolygonNormals(std::vector& normals, // ------------------------------------------------------------------------------------------------ // 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); } -struct CompareVector -{ - bool operator () (const IfcVector3& a, const IfcVector3& b) const - { +struct CompareVector { + bool operator () (const IfcVector3& a, const IfcVector3& b) const { 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); } }; -struct FindVector -{ + +struct FindVector { IfcVector3 v; 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 nb_vidx = (nb_vidx + 1) % nbvc; 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(neighbour.begin() + nbvsi, neighbour.begin() + nbvsi + nbvc); 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(i)] = in.DirectionRatios[i]; } 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"); return; } diff --git a/code/AssetLib/LWO/LWOAnimation.cpp b/code/AssetLib/LWO/LWOAnimation.cpp index 49fa45746..c2ee2d9c0 100644 --- a/code/AssetLib/LWO/LWOAnimation.cpp +++ b/code/AssetLib/LWO/LWOAnimation.cpp @@ -83,9 +83,13 @@ AnimResolver::AnimResolver(std::list &_envelopes, double tick) : (*it).old_first = 0; (*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) { - // translation case LWO::EnvelopeType_Position_X: trans_x = &*it; diff --git a/code/AssetLib/Obj/ObjFileData.h b/code/AssetLib/Obj/ObjFileData.h index bc65058ac..3d504d0bb 100644 --- a/code/AssetLib/Obj/ObjFileData.h +++ b/code/AssetLib/Obj/ObjFileData.h @@ -195,6 +195,9 @@ struct Material { //! PBR Anisotropy ai_real anisotropy; + //! bump map multipler (normal map scalar)(-bm) + ai_real bump_multiplier; + //! Constructor Material() : 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)), clearcoat_thickness(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(TextureTypeCount), false); } diff --git a/code/AssetLib/Obj/ObjFileImporter.cpp b/code/AssetLib/Obj/ObjFileImporter.cpp index fd062552f..68fdb2172 100644 --- a/code/AssetLib/Obj/ObjFileImporter.cpp +++ b/code/AssetLib/Obj/ObjFileImporter.cpp @@ -51,6 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include static const aiImporterDesc desc = { @@ -604,6 +605,9 @@ void ObjFileImporter::createMaterials(const ObjFile::Model *pModel, aiScene *pSc mat->AddProperty(&sm, 1, AI_MATKEY_SHADING_MODEL); + // Preserve the original illum value + mat->AddProperty(&pCurrentMaterial->illumination_model, 1, AI_MATKEY_OBJ_ILLUM); + // Adding material colors mat->AddProperty(&pCurrentMaterial->ambient, 1, AI_MATKEY_COLOR_AMBIENT); 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) { mat->AddProperty(&pCurrentMaterial->textureBump, AI_MATKEY_TEXTURE_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]) { addTextureMappingModeProperty(mat, aiTextureType_HEIGHT); } @@ -665,6 +672,9 @@ void ObjFileImporter::createMaterials(const ObjFile::Model *pModel, aiScene *pSc if (0 != pCurrentMaterial->textureNormal.length) { mat->AddProperty(&pCurrentMaterial->textureNormal, AI_MATKEY_TEXTURE_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]) { addTextureMappingModeProperty(mat, aiTextureType_NORMALS); } diff --git a/code/AssetLib/Obj/ObjFileMtlImporter.cpp b/code/AssetLib/Obj/ObjFileMtlImporter.cpp index 7d5930594..2441c17f2 100644 --- a/code/AssetLib/Obj/ObjFileMtlImporter.cpp +++ b/code/AssetLib/Obj/ObjFileMtlImporter.cpp @@ -472,7 +472,11 @@ void ObjFileMtlImporter::getTextureOption(bool &clamp, int &clampIndex, aiString } skipToken = 2; - } else if (!ASSIMP_strincmp(pPtr, BlendUOption.c_str(), static_cast(BlendUOption.size())) || !ASSIMP_strincmp(pPtr, BlendVOption.c_str(), static_cast(BlendVOption.size())) || !ASSIMP_strincmp(pPtr, BoostOption.c_str(), static_cast(BoostOption.size())) || !ASSIMP_strincmp(pPtr, ResolutionOption.c_str(), static_cast(ResolutionOption.size())) || !ASSIMP_strincmp(pPtr, BumpOption.c_str(), static_cast(BumpOption.size())) || !ASSIMP_strincmp(pPtr, ChannelOption.c_str(), static_cast(ChannelOption.size()))) { + } else if (!ASSIMP_strincmp(pPtr, BumpOption.c_str(), static_cast(BumpOption.size()))) { + DataArrayIt it = getNextToken(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(BlendUOption.size())) || !ASSIMP_strincmp(pPtr, BlendVOption.c_str(), static_cast(BlendVOption.size())) || !ASSIMP_strincmp(pPtr, BoostOption.c_str(), static_cast(BoostOption.size())) || !ASSIMP_strincmp(pPtr, ResolutionOption.c_str(), static_cast(ResolutionOption.size())) || !ASSIMP_strincmp(pPtr, ChannelOption.c_str(), static_cast(ChannelOption.size()))) { skipToken = 2; } else if (!ASSIMP_strincmp(pPtr, ModifyMapOption.c_str(), static_cast(ModifyMapOption.size()))) { skipToken = 3; diff --git a/code/AssetLib/X/XFileParser.cpp b/code/AssetLib/X/XFileParser.cpp index adcb7c8f4..558b97958 100644 --- a/code/AssetLib/X/XFileParser.cpp +++ b/code/AssetLib/X/XFileParser.cpp @@ -5,8 +5,6 @@ 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, @@ -60,25 +58,11 @@ using namespace Assimp::Formatter; #ifndef ASSIMP_BUILD_NO_COMPRESSED_X -#ifdef ASSIMP_BUILD_NO_OWN_ZLIB -#include -#else -#include "../contrib/zlib/zlib.h" -#endif +#include "Common/Compression.h" // Magic identifier for MSZIP compressed data -#define MSZIP_MAGIC 0x4B43 -#define MSZIP_BLOCK 32786 - -// ------------------------------------------------------------------------------------------------ -// 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); -} +constexpr unsigned int MSZIP_MAGIC = 0x4B43; +constexpr size_t MSZIP_BLOCK = 32786l; #endif // !! ASSIMP_BUILD_NO_COMPRESSED_X @@ -133,13 +117,13 @@ XFileParser::XFileParser(const std::vector &pBuffer) : mIsBinaryFormat = true; compressed = true; } 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 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) - 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 mBinaryFloatSize /= 8; @@ -171,16 +155,6 @@ XFileParser::XFileParser(const std::vector &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?) mP += 6; @@ -207,43 +181,29 @@ XFileParser::XFileParser(const std::vector &pBuffer) : // and advance to the next offset 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 + Compression compression; uncompressed.resize(est_out + 1); char *out = &uncompressed.front(); - while (mP + 3 < mEnd) { - uint16_t ofs = *((uint16_t *)mP); - AI_SWAP2(ofs); - mP += 4; + if (compression.open(mIsBinaryFormat ? Compression::Format::Binary : Compression::Format::ASCII, + Compression::FlushMode::SyncFlush, -Compression::MaxWBits)) { + while (mP + 3 < mEnd) { + uint16_t ofs = *((uint16_t *)mP); + AI_SWAP2(ofs); + mP += 4; - if (mP + ofs > mEnd + 2) { - throw DeadlyImportError("X: Unexpected EOF in compressed chunk"); + if (mP + ofs > mEnd + 2) { + throw DeadlyImportError("X: Unexpected EOF in compressed chunk"); + } + out += compression.decompressBlock(mP, ofs, out, MSZIP_BLOCK); + mP += ofs; } - - // 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; + compression.close(); } - // terminate zlib - ::inflateEnd(&stream); - // ok, update pointers to point to the uncompressed file data mP = &uncompressed[0]; mEnd = out; @@ -279,15 +239,16 @@ void XFileParser::ParseFile() { while (running) { // read name of next object std::string objectName = GetNextToken(); - if (objectName.length() == 0) + if (objectName.length() == 0) { break; + } // parse specific object - if (objectName == "template") + if (objectName == "template") { ParseDataObjectTemplate(); - else if (objectName == "Frame") + } else if (objectName == "Frame") { ParseDataObjectFrame(nullptr); - else if (objectName == "Mesh") { + } else if (objectName == "Mesh") { // some meshes have no frames at all Mesh *mesh = new Mesh; ParseDataObjectMesh(mesh); @@ -326,11 +287,13 @@ void XFileParser::ParseDataObjectTemplate() { while (running) { std::string s = GetNextToken(); - if (s == "}") + if (s == "}") { break; + } - if (s.length() == 0) + if (s.length() == 0) { ThrowException("Unexpected end of file reached while parsing template definition"); + } } } @@ -500,7 +463,7 @@ void XFileParser::ParseDataObjectSkinWeights(Mesh *pMesh) { bone.mWeights.reserve(numWeights); for (unsigned int a = 0; a < numWeights; a++) { - BoneWeight weight; + BoneWeight weight = {}; weight.mVertex = ReadInt(); bone.mWeights.push_back(weight); } diff --git a/code/AssetLib/XGL/XGLLoader.cpp b/code/AssetLib/XGL/XGLLoader.cpp index b003f852a..154af9854 100644 --- a/code/AssetLib/XGL/XGLLoader.cpp +++ b/code/AssetLib/XGL/XGLLoader.cpp @@ -44,28 +44,20 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_XGL_IMPORTER #include "XGLLoader.h" +#include "Common/Compression.h" + #include #include - #include #include #include #include #include -#include -#include +//#include +//#include using namespace Assimp; -// zlib is needed for compressed XGL files -#ifndef ASSIMP_BUILD_NO_COMPRESSED_XGL -# ifdef ASSIMP_BUILD_NO_OWN_ZLIB -# include -# else -# include -# endif -#endif - namespace Assimp { // this has to be in here because LogFunctions is in ::Assimp template <> @@ -73,6 +65,7 @@ const char *LogFunctions::Prefix() { static auto prefix = "XGL: "; return prefix; } + } // namespace Assimp static const aiImporterDesc desc = { @@ -118,8 +111,8 @@ const aiImporterDesc *XGLImporter::GetInfo() const { // ------------------------------------------------------------------------------------------------ // Imports the given file into the given scene structure. void XGLImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) { -#ifndef ASSIMP_BUILD_NO_COMPRESSED_XGL - std::vector uncompressed; + #ifndef ASSIMP_BUILD_NO_COMPRESSED_XGL + std::vector uncompressed; #endif m_scene = pScene; @@ -137,48 +130,16 @@ void XGLImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy #else std::unique_ptr raw_reader(new StreamReaderLE(stream)); - // build a zlib stream - z_stream zstream; - zstream.opaque = Z_NULL; - zstream.zalloc = Z_NULL; - zstream.zfree = Z_NULL; - zstream.data_type = Z_BINARY; - - // 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(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); - + Compression compression; + size_t total = 0l; + if (compression.open(Compression::Format::Binary, Compression::FlushMode::NoFlush, -Compression::MaxWBits)) { + // skip two extra bytes, zgl files do carry a crc16 upfront (I think) + raw_reader->IncPtr(2); + total = compression.decompress((unsigned char *)raw_reader->GetPtr(), raw_reader->GetRemainingSize(), uncompressed); + compression.close(); + } // replace the input stream with a memory stream - stream.reset(new MemoryIOStream(reinterpret_cast(uncompressed.data()), total)); + stream.reset(new MemoryIOStream(reinterpret_cast(uncompressed.data()), total)); #endif } @@ -239,7 +200,7 @@ void XGLImporter::ReadWorld(XmlNode &node, TempScope &scope) { if (!nd) { ThrowException("failure reading "); } - if (!nd->mName.length) { + if (nd->mName.length == 0) { nd->mName.Set("WORLD"); } @@ -291,7 +252,8 @@ aiNode *XGLImporter::ReadObject(XmlNode &node, TempScope &scope) { const std::string &s = ai_stdStrToLower(child.name()); if (s == "mesh") { 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(); for (size_t i = 0; i < newc - prev; ++i) { meshes.push_back(static_cast(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; std::map bymat; const unsigned int mesh_id = ReadIDAttr(node); - + bool empty_mesh = true; for (XmlNode &child : node.children()) { const std::string &s = ai_stdStrToLower(child.name()); @@ -539,6 +501,9 @@ bool XGLImporter::ReadMesh(XmlNode &node, TempScope &scope) { mid = ResolveMaterialRef(sub_child, scope); } } + if (has[0] || has[1] || has[2]) { + empty_mesh = false; + } if (mid == ~0u) { ThrowException("missing material index"); @@ -590,6 +555,11 @@ bool XGLImporter::ReadMesh(XmlNode &node, TempScope &scope) { scope.meshes.insert(std::pair(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* return mesh_id == ~0u; @@ -759,7 +729,7 @@ aiVector2D XGLImporter::ReadVec2(XmlNode &node) { std::string val; XmlParser::getValueAsString(node, val); const char *s = val.c_str(); - ai_real v[2]; + ai_real v[2] = {}; for (int i = 0; i < 2; ++i) { if (!SkipSpaces(&s)) { LogError("unexpected EOL, failed to parse vec2"); @@ -814,4 +784,4 @@ aiColor3D XGLImporter::ReadCol3(XmlNode &node) { return aiColor3D(v.x, v.y, v.z); } -#endif +#endif // ASSIMP_BUILD_NO_XGL_IMPORTER diff --git a/code/AssetLib/XGL/XGLLoader.h b/code/AssetLib/XGL/XGLLoader.h index 903f114cf..ae7ccddc2 100644 --- a/code/AssetLib/XGL/XGLLoader.h +++ b/code/AssetLib/XGL/XGLLoader.h @@ -186,7 +186,7 @@ private: void ReadLighting(XmlNode &node, TempScope &scope); aiLight *ReadDirectionalLight(XmlNode &node); 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); aiVector2D ReadVec2(XmlNode &node); aiVector3D ReadVec3(XmlNode &node); diff --git a/code/AssetLib/glTF/glTFAsset.h b/code/AssetLib/glTF/glTFAsset.h index 4cd11aa4f..1a42e9020 100644 --- a/code/AssetLib/glTF/glTFAsset.h +++ b/code/AssetLib/glTF/glTFAsset.h @@ -260,20 +260,9 @@ public: VEC4, MAT2, MAT3, - MAT4 }; - -private: - static const size_t NUM_VALUES = static_cast(MAT4) + 1; - - struct Info { - const char *name; - unsigned int numComponents; + MAT4 }; - template - struct data { static const Info infos[NUM_VALUES]; }; - -public: inline static Value FromString(const char *str) { for (size_t i = 0; i < NUM_VALUES; ++i) { if (strcmp(data<0>::infos[i].name, str) == 0) { @@ -290,40 +279,31 @@ public: inline static unsigned int GetNumComponents(Value type) { return data<0>::infos[static_cast(type)].numComponents; } + +private: + static const size_t NUM_VALUES = static_cast(MAT4) + 1; + struct Info { + const char *name; + unsigned int numComponents; + }; + + template + struct data { + static const Info infos[NUM_VALUES]; + }; }; // must match the order of the AttribTypeTraits::Value enum! template -const AttribType::Info - AttribType::data::infos[AttribType::NUM_VALUES] = { - { "SCALAR", 1 }, { "VEC2", 2 }, { "VEC3", 3 }, { "VEC4", 4 }, { "MAT2", 4 }, { "MAT3", 9 }, { "MAT4", 16 } - }; - -/* - //! A reference to one top-level object, which is valid - //! until the Asset instance is destroyed - template - class Ref - { - std::vector* vector; - unsigned int index; - - public: - Ref() : vector(0), index(0) {} - Ref(std::vector& 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]); } - };*/ +const AttribType::Info AttribType::data::infos[AttribType::NUM_VALUES] = { + { "SCALAR", 1 }, + { "VEC2", 2 }, + { "VEC3", 3 }, + { "VEC4", 4 }, + { "MAT2", 4 }, + { "MAT3", 9 }, + { "MAT4", 16 } +}; //! Base class for all glTF top-level objects struct Object { @@ -333,6 +313,7 @@ struct Object { //! Objects marked as special are not exported (used to emulate the binary body buffer) virtual bool IsSpecial() const { return false; } + Object() = default; virtual ~Object() {} //! Maps special IDs to another ID, where needed. Subclasses may override it (statically) @@ -401,21 +382,19 @@ struct Accessor : public Object { return Indexer(*this); } - Accessor() {} + Accessor() = default; void Read(Value &obj, Asset &r); }; //! A buffer points to binary geometry, animation, or skins. struct Buffer : public Object { /********************* Types *********************/ -public: enum Type { Type_arraybuffer, Type_text }; - /// \struct SEncodedRegion - /// Descriptor of encoded region in "bufferView". + /// @brief Descriptor of encoded region in "bufferView". struct SEncodedRegion { 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. @@ -423,8 +402,7 @@ public: const size_t DecodedData_Length; ///< Size of decoded region, in bytes. 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) - /// Constructor. + /// @brief Constructor. /// \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] 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) : Offset(pOffset), EncodedData_Length(pEncodedData_Length), DecodedData(pDecodedData), DecodedData_Length(pDecodedData_Length), ID(pID) {} - /// \fn ~SEncodedRegion() /// Destructor. ~SEncodedRegion() { delete[] DecodedData; } }; /******************* 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) - //std::string type; //!< XMLHttpRequest responseType (default: "arraybuffer") Type type; @@ -486,7 +461,6 @@ public: 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. /// \param [in] pOffset - offset from begin of "bufferView" to 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. 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. /// \param [in] pID - ID of the region. 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. /// \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. @@ -558,37 +530,29 @@ struct Camera : public Object { } ortographic; }; - Camera() {} + Camera() = default; void Read(Value &obj, Asset &r); }; //! Image data used to create a texture. struct Image : public Object { std::string uri; //! The uri of the image, that can be a file path, a data URI, etc.. (required) - Ref bufferView; - std::string mimeType; - int width, height; -private: - std::unique_ptr mData; - size_t mDataLength; - public: Image(); void Read(Value &obj, Asset &r); - inline bool HasData() const { return mDataLength > 0; } - inline size_t GetDataLength() const { return mDataLength; } - inline const uint8_t *GetData() const { return mData.get(); } - inline uint8_t *StealData(); - inline void SetData(uint8_t *data, size_t length, Asset &r); + +private: + std::unique_ptr mData; + size_t mDataLength; }; //! 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 + /// \struct SCompression_Open3DGC /// Compression of mesh data using Open3DGC algorithm. struct SCompression_Open3DGC : public SExtension { @@ -703,7 +668,6 @@ struct Mesh : public Object { Mesh() {} - /// \fn ~Mesh() /// Destructor. ~Mesh() { for (std::list::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) - /// Get mesh data from JSON-object and place them to root asset. + /// @brief 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 [out] pAsset_Root - reference to root asset where data will be stored. void Read(Value &pJSON_Object, Asset &pAsset_Root); #ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC - /// \fn void Decode_O3DGC(const SCompression_Open3DGC& pCompression_Open3DGC, Asset& pAsset_Root) - /// Decode part of "buffer" which encoded with Open3DGC algorithm. + /// @brief Decode part of "buffer" which encoded with Open3DGC algorithm. /// \param [in] pCompression_Open3DGC - reference to structure which describe encoded region. /// \param [out] pAsset_Root - reference to root assed where data will be stored. 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 wrapT; //!< The texture wrapping in the T direction. (required) - Sampler() {} + Sampler() = default; void Read(Value &obj, Asset &r); void SetDefaults(); }; @@ -767,12 +729,12 @@ struct Sampler : public Object { struct Scene : public Object { std::vector> nodes; - Scene() {} + Scene() = default; void Read(Value &obj, Asset &r); }; struct Shader : public Object { - Shader() {} + Shader() = default; void Read(Value &obj, Asset &r); }; @@ -782,7 +744,7 @@ struct Skin : public Object { std::vector> jointNames; //!< Joint names of the joints (nodes with a jointName property) in this skin. std::string name; //!< The user-defined name of this object. - Skin() {} + Skin() = default; void Read(Value &obj, Asset &r); }; @@ -796,7 +758,7 @@ struct Technique : public Object { struct Functions { }; - Technique() {} + Technique() = default; void Read(Value &obj, Asset &r); }; @@ -805,13 +767,7 @@ struct Texture : public Object { Ref sampler; //!< The ID of the sampler used by this texture. (required) Ref source; //!< The ID of the image used by this texture. (required) - //TextureFormat format; //!< The texture's format. (default: TextureFormat_RGBA) - //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() {} + Texture() = default; void Read(Value &obj, Asset &r); }; @@ -826,7 +782,6 @@ struct Light : public Object { }; Type type; - vec4 color; float distance; float constantAttenuation; @@ -835,9 +790,8 @@ struct Light : public Object { float falloffAngle; float falloffExponent; - Light() {} + Light() = default; void Read(Value &obj, Asset &r); - void SetDefaults(); }; @@ -865,15 +819,11 @@ struct Animation : public Object { Ref 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 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. std::vector Samplers; //!< The parameterized inputs representing the key-frame data. - Animation() {} + Animation() = default; void Read(Value &obj, Asset &r); }; @@ -963,13 +913,11 @@ struct AssetMetadata { //! Root object for a glTF asset class Asset { - typedef std::gltf_unordered_map IdMap; + using IdMap = std::gltf_unordered_map; template friend class LazyDict; - friend struct Buffer; // To access OpenFile - friend class AssetWriter; private: @@ -1010,12 +958,9 @@ public: LazyDict materials; LazyDict meshes; LazyDict nodes; - //LazyDict programs; LazyDict samplers; LazyDict scenes; - //LazyDict shaders; LazyDict skins; - //LazyDict techniques; LazyDict textures; LazyDict lights; // KHR_materials_common ext @@ -1024,16 +969,20 @@ public: public: 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") - //, programs (*this, "programs") - , + 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"), samplers(*this, "samplers"), - scenes(*this, "scenes") - //, shaders (*this, "shaders") - , - skins(*this, "skins") - //, techniques (*this, "techniques") - , + scenes(*this, "scenes"), + skins(*this, "skins"), textures(*this, "textures"), lights(*this, "lights", "KHR_materials_common") { memset(&extensionsUsed, 0, sizeof(extensionsUsed)); diff --git a/code/AssetLib/glTF/glTFCommon.h b/code/AssetLib/glTF/glTFCommon.h index caf33009e..edc3c7e03 100644 --- a/code/AssetLib/glTF/glTFCommon.h +++ b/code/AssetLib/glTF/glTFCommon.h @@ -237,8 +237,6 @@ bool ParseDataURI(const char *const_uri, size_t uriLen, DataURI &out); #define CHECK_EXT(EXT) \ if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true; - - //! Helper struct to represent values that might not be present template struct Nullable { diff --git a/code/AssetLib/glTF2/glTF2Asset.h b/code/AssetLib/glTF2/glTF2Asset.h index e4fb2dc84..c597fc951 100644 --- a/code/AssetLib/glTF2/glTF2Asset.h +++ b/code/AssetLib/glTF2/glTF2Asset.h @@ -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_set tr1::unordered_set # else -# define gltf_unordered_map unordered_map +# define gltf_unordered_map unordered_map # define gltf_unordered_set unordered_set # endif #endif @@ -1087,29 +1087,11 @@ class Asset { template friend class LazyDict; - friend struct Buffer; // To access OpenFile - friend class AssetWriter; -private: - IOSystem *mIOSystem; - rapidjson::IRemoteSchemaDocumentProvider *mSchemaDocumentProvider; - - std::string mCurrentAssetDir; - - size_t mSceneLength; - size_t mBodyOffset, mBodyLength; - std::vector mDicts; - IdMap mUsedIds; - - Ref mBodyBuffer; - - Asset(Asset &); - Asset &operator=(const Asset &); - public: //! Keeps info about the enabled extensions struct Extensions { @@ -1125,16 +1107,36 @@ public: bool KHR_draco_mesh_compression; bool FB_ngon_encoding; 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; //! Keeps info about the required extensions struct RequiredExtensions { bool KHR_draco_mesh_compression; bool KHR_texture_basisu; + + RequiredExtensions() : KHR_draco_mesh_compression(false), KHR_texture_basisu(false) { + // empty + } } extensionsRequired; AssetMetadata asset; - Value *extras = nullptr; + Value *extras; // Dictionaries for each type of object @@ -1156,10 +1158,12 @@ public: Ref scene; public: - Asset(IOSystem *io = nullptr, rapidjson::IRemoteSchemaDocumentProvider *schemaDocumentProvider = nullptr) : - mIOSystem(io), - mSchemaDocumentProvider(schemaDocumentProvider), + Asset(IOSystem *io = nullptr, rapidjson::IRemoteSchemaDocumentProvider *schemaDocumentProvider = nullptr) : + mDicts(), + extensionsUsed(), + extensionsRequired(), asset(), + extras(nullptr), accessors(*this, "accessors"), animations(*this, "animations"), buffers(*this, "buffers"), @@ -1173,9 +1177,10 @@ public: samplers(*this, "samplers"), scenes(*this, "scenes"), skins(*this, "skins"), - textures(*this, "textures") { - memset(&extensionsUsed, 0, sizeof(extensionsUsed)); - memset(&extensionsRequired, 0, sizeof(extensionsRequired)); + textures(*this, "textures") , + mIOSystem(io), + mSchemaDocumentProvider(schemaDocumentProvider) { + // empty } //! Main function @@ -1192,18 +1197,31 @@ public: Ref GetBodyBuffer() { return mBodyBuffer; } + Asset(Asset &) = delete; + Asset &operator=(const Asset &) = delete; + private: void ReadBinaryHeader(IOStream &stream, std::vector &sceneData); - //! Obtain a JSON document from the stream. - // \param second argument is a buffer used by the document. It must be kept - // alive while the document is in use. + /// Obtain a JSON document from the stream. + /// \param second argument is a buffer used by the document. It must be kept + /// alive while the document is in use. Document ReadDocument(IOStream& stream, bool isBinary, std::vector& sceneData); void ReadExtensionsUsed(Document &doc); void ReadExtensionsRequired(Document &doc); 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 mBodyBuffer; }; inline std::string getContextForErrorMessages(const std::string &id, const std::string &name) { diff --git a/code/AssetLib/glTF2/glTF2Exporter.cpp b/code/AssetLib/glTF2/glTF2Exporter.cpp index e779a7be4..ffd8d223e 100644 --- a/code/AssetLib/glTF2/glTF2Exporter.cpp +++ b/code/AssetLib/glTF2/glTF2Exporter.cpp @@ -515,72 +515,74 @@ void glTF2Exporter::GetMatTexProp(const aiMaterial &mat, float &prop, const char } void glTF2Exporter::GetMatTex(const aiMaterial &mat, Ref &texture, unsigned int &texCoord, aiTextureType tt, unsigned int slot = 0) { - if (mat.GetTextureCount(tt) > 0) { - aiString tex; + if (mat.GetTextureCount(tt) == 0) { + return; + } + + aiString tex; - // Read texcoord (UV map index) - mat.Get(AI_MATKEY_UVWSRC(tt, slot), texCoord); + // Read texcoord (UV map index) + mat.Get(AI_MATKEY_UVWSRC(tt, slot), texCoord); - if (mat.Get(AI_MATKEY_TEXTURE(tt, slot), tex) == AI_SUCCESS) { - std::string path = tex.C_Str(); + if (mat.Get(AI_MATKEY_TEXTURE(tt, slot), tex) == AI_SUCCESS) { + std::string path = tex.C_Str(); - if (path.size() > 0) { - std::map::iterator it = mTexturesByPath.find(path); - if (it != mTexturesByPath.end()) { - texture = mAsset->textures.Get(it->second); - } + if (path.size() > 0) { + std::map::iterator it = mTexturesByPath.find(path); + if (it != mTexturesByPath.end()) { + texture = mAsset->textures.Get(it->second); + } - bool useBasisUniversal = false; - if (!texture) { - std::string texId = mAsset->FindUniqueID("", "texture"); - texture = mAsset->textures.Create(texId); - mTexturesByPath[path] = texture.GetIndex(); + bool useBasisUniversal = false; + if (!texture) { + std::string texId = mAsset->FindUniqueID("", "texture"); + texture = mAsset->textures.Create(texId); + mTexturesByPath[path] = texture.GetIndex(); - std::string imgId = mAsset->FindUniqueID("", "image"); - texture->source = mAsset->images.Create(imgId); + std::string imgId = mAsset->FindUniqueID("", "image"); + texture->source = mAsset->images.Create(imgId); - const aiTexture *curTex = mScene->GetEmbeddedTexture(path.c_str()); - if (curTex != nullptr) { // embedded - texture->source->name = curTex->mFilename.C_Str(); + const aiTexture *curTex = mScene->GetEmbeddedTexture(path.c_str()); + if (curTex != nullptr) { // embedded + texture->source->name = curTex->mFilename.C_Str(); - //basisu: embedded ktx2, bu - if (curTex->achFormatHint[0]) { - std::string mimeType = "image/"; - if (memcmp(curTex->achFormatHint, "jpg", 3) == 0) - mimeType += "jpeg"; - 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(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) { + //basisu: embedded ktx2, bu + if (curTex->achFormatHint[0]) { + std::string mimeType = "image/"; + if (memcmp(curTex->achFormatHint, "jpg", 3) == 0) + mimeType += "jpeg"; + 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; } - //basisu - if (useBasisUniversal) { - mAsset->extensionsUsed.KHR_texture_basisu = true; - mAsset->extensionsRequired.KHR_texture_basisu = true; + // The asset has its own buffer, see Image::SetData + //basisu: "image/ktx2", "image/basis" as is + texture->source->SetData(reinterpret_cast(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; } - - 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, unsi void glTF2Exporter::GetMatTex(const aiMaterial &mat, TextureInfo &prop, aiTextureType tt, unsigned int slot = 0) { Ref &texture = prop.texture; - 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) { @@ -681,12 +678,14 @@ bool glTF2Exporter::GetMatSpecGloss(const aiMaterial &mat, glTF2::PbrSpecularGlo bool glTF2Exporter::GetMatSheen(const aiMaterial &mat, glTF2::MaterialSheen &sheen) { // 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; + } // Default Sheen color factor {0,0,0} disables Sheen, so do not export - if (sheen.sheenColorFactor == defaultSheenFactor) + if (sheen.sheenColorFactor == defaultSheenFactor) { return false; + } mat.Get(AI_MATKEY_SHEEN_ROUGHNESS_FACTOR, sheen.sheenRoughnessFactor); @@ -781,9 +780,7 @@ void glTF2Exporter::ExportMaterials() { aiColor4D specularColor; ai_real shininess; - if ( - mat.Get(AI_MATKEY_COLOR_SPECULAR, specularColor) == AI_SUCCESS && - mat.Get(AI_MATKEY_SHININESS, shininess) == AI_SUCCESS) { + if (mat.Get(AI_MATKEY_COLOR_SPECULAR, specularColor) == AI_SUCCESS && mat.Get(AI_MATKEY_SHININESS, shininess) == AI_SUCCESS) { // convert specular color to luminance 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 @@ -916,7 +913,8 @@ Ref FindSkeletonRootJoint(Ref &skinRef) { return parentNodeRef; } -void ExportSkin(Asset &mAsset, const aiMesh *aimesh, Ref &meshRef, Ref &bufferRef, Ref &skinRef, std::vector &inverseBindMatricesData) { +void ExportSkin(Asset &mAsset, const aiMesh *aimesh, Ref &meshRef, Ref &bufferRef, Ref &skinRef, + std::vector &inverseBindMatricesData) { if (aimesh->mNumBones < 1) { return; } @@ -986,7 +984,8 @@ void ExportSkin(Asset &mAsset, const aiMesh *aimesh, Ref &meshRef, Refprimitives.back(); - Ref vertexJointAccessor = ExportData(mAsset, skinRef->id, bufferRef, aimesh->mNumVertices, vertexJointData, AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT); + Ref vertexJointAccessor = ExportData(mAsset, skinRef->id, bufferRef, aimesh->mNumVertices, + vertexJointData, AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT); if (vertexJointAccessor) { size_t offset = vertexJointAccessor->bufferView->byteOffset; size_t bytesLen = vertexJointAccessor->bufferView->byteLength; @@ -1069,8 +1068,11 @@ void glTF2Exporter::ExportMeshes() { p.ngonEncoded = (aim->mPrimitiveTypes & aiPrimitiveType_NGONEncodingFlag) != 0; /******************* Vertices ********************/ - Ref v = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mVertices, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER); - if (v) p.attributes.position.push_back(v); + Ref v = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mVertices, AttribType::VEC3, + AttribType::VEC3, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER); + if (v) { + p.attributes.position.push_back(v); + } /******************** Normals ********************/ // Normalize all normals as the validator can emit a warning otherwise @@ -1080,13 +1082,17 @@ void glTF2Exporter::ExportMeshes() { } } - Ref n = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mNormals, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER); - if (n) p.attributes.normal.push_back(n); + Ref n = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mNormals, AttribType::VEC3, + AttribType::VEC3, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER); + if (n) { + p.attributes.normal.push_back(n); + } /************** Texture coordinates **************/ for (int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { - if (!aim->HasTextureCoords(i)) + if (!aim->HasTextureCoords(i)) { continue; + } // Flip UV y coords if (aim->mNumUVComponents[i] > 1) { @@ -1098,16 +1104,21 @@ void glTF2Exporter::ExportMeshes() { if (aim->mNumUVComponents[i] > 0) { AttribType::Value type = (aim->mNumUVComponents[i] == 2) ? AttribType::VEC2 : AttribType::VEC3; - Ref tc = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mTextureCoords[i], AttribType::VEC3, type, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER); - if (tc) p.attributes.texcoord.push_back(tc); + Ref tc = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mTextureCoords[i], + AttribType::VEC3, type, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER); + if (tc) { + p.attributes.texcoord.push_back(tc); + } } } /*************** Vertex colors ****************/ for (unsigned int indexColorChannel = 0; indexColorChannel < aim->GetNumColorChannels(); ++indexColorChannel) { - Ref c = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mColors[indexColorChannel], AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER); - if (c) + Ref c = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mColors[indexColorChannel], + AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT, BufferViewTarget_ARRAY_BUFFER); + if (c) { p.attributes.color.push_back(c); + } } /*************** 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) { @@ -1136,6 +1148,7 @@ void glTF2Exporter::ExportMeshes() { break; default: // aiPrimitiveType_TRIANGLE p.mode = PrimitiveMode_TRIANGLES; + break; } /*************** Skins ****************/ @@ -1155,8 +1168,9 @@ void glTF2Exporter::ExportMeshes() { p.targets.resize(aim->mNumAnimMeshes); for (unsigned int am = 0; am < aim->mNumAnimMeshes; ++am) { aiAnimMesh *pAnimMesh = aim->mAnimMeshes[am]; - if (bExportTargetNames) - m->targetNames.push_back(pAnimMesh->mName.data); + if (bExportTargetNames) { + m->targetNames.emplace_back(pAnimMesh->mName.data); + } // position if (pAnimMesh->HasPositions()) { // 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) { - 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) { 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(); @@ -1366,12 +1380,12 @@ unsigned int glTF2Exporter::ExportNode(const aiNode *n, Ref &parent) { } 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) { 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(); @@ -1386,7 +1400,7 @@ void glTF2Exporter::ExportScene() { // root node will be the first one exported (idx 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 @@ -1521,12 +1535,6 @@ void glTF2Exporter::ExportAnimations() { 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 } diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 7ce933585..7a2f8a109 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -166,6 +166,8 @@ SET( Logging_SRCS SOURCE_GROUP(Logging FILES ${Logging_SRCS}) SET( Common_SRCS + Common/Compression.cpp + Common/Compression.h Common/BaseImporter.cpp Common/BaseProcess.cpp Common/BaseProcess.h @@ -1315,11 +1317,10 @@ ENDIF () INSTALL( TARGETS assimp EXPORT "${TARGETS_EXPORT_NAME}" - LIBRARY DESTINATION ${ASSIMP_LIB_INSTALL_DIR} - ARCHIVE DESTINATION ${ASSIMP_LIB_INSTALL_DIR} - RUNTIME DESTINATION ${ASSIMP_BIN_INSTALL_DIR} - FRAMEWORK DESTINATION ${ASSIMP_LIB_INSTALL_DIR} - COMPONENT ${LIBASSIMP_COMPONENT} + LIBRARY DESTINATION ${ASSIMP_LIB_INSTALL_DIR} COMPONENT ${LIBASSIMP_COMPONENT} + ARCHIVE DESTINATION ${ASSIMP_LIB_INSTALL_DIR} COMPONENT ${LIBASSIMP-DEV_COMPONENT} + RUNTIME DESTINATION ${ASSIMP_BIN_INSTALL_DIR} COMPONENT ${LIBASSIMP_COMPONENT} + FRAMEWORK DESTINATION ${ASSIMP_LIB_INSTALL_DIR} COMPONENT ${LIBASSIMP_COMPONENT} INCLUDES DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR} ) INSTALL( FILES ${PUBLIC_HEADERS} DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}/assimp COMPONENT assimp-dev) diff --git a/code/Common/Base64.cpp b/code/Common/Base64.cpp index 2916cae7f..3e9c47405 100644 --- a/code/Common/Base64.cpp +++ b/code/Common/Base64.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2021, assimp team +Copyright (c) 2006-2022, assimp team 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 }; -static const char* tableEncodeBase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; +static const char *tableEncodeBase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; static inline char EncodeChar(uint8_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& in, std::string &out) { - Encode (in.data (), in.size (), out); +void Encode(const std::vector &in, std::string &out) { + Encode(in.data(), in.size(), out); } -std::string Encode (const std::vector& in) { +std::string Encode(const std::vector &in) { std::string encoded; - Encode (in, encoded); + Encode(in, encoded); return encoded; } - size_t Decode(const char *in, size_t inLength, uint8_t *&out) { if (inLength % 4 != 0) { 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; } -size_t Decode(const std::string& in, std::vector& out) { - uint8_t* outPtr = nullptr; - size_t decodedSize = Decode (in.data (), in.size (), outPtr); +size_t Decode(const std::string &in, std::vector &out) { + uint8_t *outPtr = nullptr; + size_t decodedSize = Decode(in.data(), in.size(), outPtr); if (outPtr == nullptr) { return 0; } - out.assign (outPtr, outPtr + decodedSize); + out.assign(outPtr, outPtr + decodedSize); delete[] outPtr; return decodedSize; } -std::vector Decode (const std::string& in) { +std::vector Decode(const std::string &in) { std::vector result; - Decode (in, result); + Decode(in, result); return result; } -} - -} +} // namespace Base64 +} // namespace Assimp diff --git a/code/Common/Compression.cpp b/code/Common/Compression.cpp new file mode 100644 index 000000000..3bf306dee --- /dev/null +++ b/code/Common/Compression.cpp @@ -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 +#include + +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 &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(uncompressed.size()); + mImpl->mZSstream.next_out = reinterpret_cast(&*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 diff --git a/code/Common/Compression.h b/code/Common/Compression.h new file mode 100644 index 000000000..edf1d232f --- /dev/null +++ b/code/Common/Compression.h @@ -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 +#else +#include "../contrib/zlib/zlib.h" +#endif + +#include +#include // 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 &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 diff --git a/code/Common/IOSystem.cpp b/code/Common/IOSystem.cpp index 77305d193..1e63827ba 100644 --- a/code/Common/IOSystem.cpp +++ b/code/Common/IOSystem.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2019, assimp team +Copyright (c) 2006-2022, assimp team All rights reserved. diff --git a/code/Common/Version.cpp b/code/Common/Version.cpp index 20533ab80..86d3f2220 100644 --- a/code/Common/Version.cpp +++ b/code/Common/Version.cpp @@ -5,7 +5,6 @@ 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, @@ -53,7 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. static const char *LEGAL_INFORMATION = "Open Asset Import Library (Assimp).\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" "https://www.assimp.org\n"; diff --git a/code/Common/material.cpp b/code/Common/material.cpp index 8f791a313..a7541d4f1 100644 --- a/code/Common/material.cpp +++ b/code/Common/material.cpp @@ -4,7 +4,6 @@ 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, diff --git a/code/Common/simd.cpp b/code/Common/simd.cpp index 9eb547f9a..0dd437d26 100644 --- a/code/Common/simd.cpp +++ b/code/Common/simd.cpp @@ -5,8 +5,6 @@ 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, diff --git a/code/PostProcessing/CalcTangentsProcess.cpp b/code/PostProcessing/CalcTangentsProcess.cpp index 0ebad91df..b8847e473 100644 --- a/code/PostProcessing/CalcTangentsProcess.cpp +++ b/code/PostProcessing/CalcTangentsProcess.cpp @@ -191,9 +191,9 @@ bool CalcTangentsProcess::ProcessMesh(aiMesh *pMesh, unsigned int meshIndex) { tangent.x = (w.x * sy - v.x * ty) * dirCorrection; tangent.y = (w.y * sy - v.y * ty) * dirCorrection; tangent.z = (w.z * sy - v.z * ty) * dirCorrection; - bitangent.x = (w.x * sx - v.x * tx) * dirCorrection; - bitangent.y = (w.y * sx - v.y * tx) * dirCorrection; - bitangent.z = (w.z * sx - v.z * tx) * dirCorrection; + bitangent.x = (- w.x * sx + v.x * tx) * dirCorrection; + bitangent.y = (- w.y * sx + v.y * tx) * dirCorrection; + bitangent.z = (- w.z * sx + v.z * tx) * dirCorrection; // store for every vertex of that face 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 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(); localBitangent.NormalizeSafe(); diff --git a/code/PostProcessing/FindDegenerates.cpp b/code/PostProcessing/FindDegenerates.cpp index de46d5630..0bbf421d2 100644 --- a/code/PostProcessing/FindDegenerates.cpp +++ b/code/PostProcessing/FindDegenerates.cpp @@ -221,7 +221,7 @@ bool FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) { if ( mConfigCheckAreaOfTriangle ) { if ( face.mNumIndices == 3 ) { ai_real area = calculateAreaOfTriangle( face, mesh ); - if ( area < 1e-6 ) { + if (area < ai_epsilon) { if ( mConfigRemoveDegenerates ) { remove_me[ a ] = true; ++deg; diff --git a/include/assimp/Base64.hpp b/include/assimp/Base64.hpp index 894eb449b..ee319aceb 100644 --- a/include/assimp/Base64.hpp +++ b/include/assimp/Base64.hpp @@ -50,6 +50,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace Assimp { 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 std::vector& in, std::string &out); std::string Encode(const std::vector& in); diff --git a/include/assimp/ByteSwapper.h b/include/assimp/ByteSwapper.h index cf3a703b0..488f7a51d 100644 --- a/include/assimp/ByteSwapper.h +++ b/include/assimp/ByteSwapper.h @@ -211,7 +211,7 @@ template struct ByteSwap::_swapper { // -------------------------------------------------------------------------------------- #if (defined AI_BUILD_BIG_ENDIAN) # 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_LSWAP4(p) # define AI_LSWAP8(p) @@ -219,16 +219,16 @@ template struct ByteSwap::_swapper { # define AI_LSWAP4P(p) # define AI_LSWAP8P(p) # define LE_NCONST const -# define AI_SWAP2(p) ByteSwap::Swap2(&(p)) -# define AI_SWAP4(p) ByteSwap::Swap4(&(p)) -# define AI_SWAP8(p) ByteSwap::Swap8(&(p)) -# define AI_SWAP2P(p) ByteSwap::Swap2((p)) -# define AI_SWAP4P(p) ByteSwap::Swap4((p)) -# define AI_SWAP8P(p) ByteSwap::Swap8((p)) +# define AI_SWAP2(p) Assimp::ByteSwap::Swap2(&(p)) +# define AI_SWAP4(p) Assimp::ByteSwap::Swap4(&(p)) +# define AI_SWAP8(p) Assimp::ByteSwap::Swap8(&(p)) +# define AI_SWAP2P(p) Assimp::ByteSwap::Swap2((p)) +# define AI_SWAP4P(p) Assimp::ByteSwap::Swap4((p)) +# define AI_SWAP8P(p) Assimp::ByteSwap::Swap8((p)) # define BE_NCONST #else # 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_SWAP4(p) # define AI_SWAP8(p) @@ -236,12 +236,12 @@ template struct ByteSwap::_swapper { # define AI_SWAP4P(p) # define AI_SWAP8P(p) # define BE_NCONST const -# define AI_LSWAP2(p) ByteSwap::Swap2(&(p)) -# define AI_LSWAP4(p) ByteSwap::Swap4(&(p)) -# define AI_LSWAP8(p) ByteSwap::Swap8(&(p)) -# define AI_LSWAP2P(p) ByteSwap::Swap2((p)) -# define AI_LSWAP4P(p) ByteSwap::Swap4((p)) -# define AI_LSWAP8P(p) ByteSwap::Swap8((p)) +# define AI_LSWAP2(p) Assimp::ByteSwap::Swap2(&(p)) +# define AI_LSWAP4(p) Assimp::ByteSwap::Swap4(&(p)) +# define AI_LSWAP8(p) Assimp::ByteSwap::Swap8(&(p)) +# define AI_LSWAP2P(p) Assimp::ByteSwap::Swap2((p)) +# define AI_LSWAP4P(p) Assimp::ByteSwap::Swap4((p)) +# define AI_LSWAP8P(p) Assimp::ByteSwap::Swap8((p)) # define LE_NCONST #endif diff --git a/include/assimp/Exceptional.h b/include/assimp/Exceptional.h index e753a8ba1..ec3d38c5a 100644 --- a/include/assimp/Exceptional.h +++ b/include/assimp/Exceptional.h @@ -98,10 +98,6 @@ public: DeadlyErrorBase(Assimp::Formatter::format(), std::forward(args)...) { // empty } - -#if defined(_MSC_VER) && defined(__clang__) - DeadlyImportError(DeadlyImportError& other) = delete; -#endif }; // --------------------------------------------------------------------------- @@ -114,10 +110,6 @@ public: template explicit DeadlyExportError(T&&... args) : DeadlyErrorBase(Assimp::Formatter::format(), std::forward(args)...) {} - -#if defined(_MSC_VER) && defined(__clang__) - DeadlyExportError(DeadlyExportError& other) = delete; -#endif }; #ifdef _MSC_VER diff --git a/include/assimp/Hash.h b/include/assimp/Hash.h index 1f2baedac..5a02f5f31 100644 --- a/include/assimp/Hash.h +++ b/include/assimp/Hash.h @@ -4,7 +4,6 @@ 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, @@ -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) { uint32_t tmp; int rem; - +size_t offset; + if (!data) return 0; if (!len)len = (uint32_t)::strlen(data); @@ -96,7 +96,11 @@ int rem; switch (rem) { case 3: hash += get16bits (data); hash ^= hash << 16; - hash ^= data[sizeof (uint16_t)] << 18; + offset = static_cast(sizeof(uint16_t)); + if (offset < 0) { + return 0; + } + hash ^= data[offset] << 18; hash += hash >> 11; break; case 2: hash += get16bits (data); diff --git a/include/assimp/ObjMaterial.h b/include/assimp/ObjMaterial.h new file mode 100644 index 000000000..bba207638 --- /dev/null +++ b/include/assimp/ObjMaterial.h @@ -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 + +// --------------------------------------------------------------------------- + +// 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 diff --git a/include/assimp/TinyFormatter.h b/include/assimp/TinyFormatter.h index 6356bbae6..df2a32eca 100644 --- a/include/assimp/TinyFormatter.h +++ b/include/assimp/TinyFormatter.h @@ -119,29 +119,41 @@ public: * work for const references, so many function prototypes will * include const basic_formatter& s but might still want to * modify the formatted string without the need for a full copy.*/ - template - const basic_formatter& operator << (const TToken& s) const { + template ::value>::type * = nullptr> + const basic_formatter &operator<<(const TToken &s) const { underlying << s; return *this; } - template - basic_formatter& operator << (const TToken& s) { + template ::value>::type * = nullptr> + const basic_formatter &operator<<(const TToken &s) const { + underlying << s.what(); + return *this; + } + + template ::value>::type * = nullptr> + basic_formatter &operator<<(const TToken &s) { underlying << s; return *this; } + template ::value>::type * = nullptr> + basic_formatter &operator<<(const TToken &s) { + underlying << s.what(); + return *this; + } + // comma operator overloaded as well, choose your preferred way. template const basic_formatter& operator, (const TToken& s) const { - underlying << s; + *this << s; return *this; } template basic_formatter& operator, (const TToken& s) { - underlying << s; + *this << s; return *this; } @@ -149,7 +161,7 @@ public: // See https://sourceforge.net/projects/assimp/forums/forum/817654/topic/4372824 template basic_formatter& operator, (TToken& s) { - underlying << s; + *this << s; return *this; } diff --git a/include/assimp/defs.h b/include/assimp/defs.h index 9c4422584..0626a8d8a 100644 --- a/include/assimp/defs.h +++ b/include/assimp/defs.h @@ -279,11 +279,11 @@ typedef unsigned int ai_uint; #define AI_MATH_HALF_PI_F (AI_MATH_PI_F * 0.5f) /* Tiny macro to convert from radians to degrees and back */ -#define AI_DEG_TO_RAD(x) ((x) * (ai_real)0.0174532925) -#define AI_RAD_TO_DEG(x) ((x) * (ai_real)57.2957795) +#define AI_DEG_TO_RAD(x) ((x) * (ai_real) 0.0174532925) +#define AI_RAD_TO_DEG(x) ((x) * (ai_real) 57.2957795) /* 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 */ #if defined(__BYTE_ORDER__) diff --git a/include/assimp/matrix3x3.h b/include/assimp/matrix3x3.h index 5ae31bbeb..74382e263 100644 --- a/include/assimp/matrix3x3.h +++ b/include/assimp/matrix3x3.h @@ -95,7 +95,7 @@ public: bool operator== (const aiMatrix3x3t& m) const; bool operator!= (const aiMatrix3x3t& m) const; - bool Equal(const aiMatrix3x3t& m, TReal epsilon = 1e-6) const; + bool Equal(const aiMatrix3x3t &m, TReal epsilon = ai_epsilon) const; template operator aiMatrix3x3t () const; diff --git a/include/assimp/matrix4x4.h b/include/assimp/matrix4x4.h index 07abf4711..67e0e356e 100644 --- a/include/assimp/matrix4x4.h +++ b/include/assimp/matrix4x4.h @@ -110,7 +110,7 @@ public: 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. aiMatrix4x4t& operator *= (const aiMatrix4x4t& m); diff --git a/include/assimp/quaternion.h b/include/assimp/quaternion.h index aa92ea577..b6d0a5681 100644 --- a/include/assimp/quaternion.h +++ b/include/assimp/quaternion.h @@ -92,7 +92,7 @@ public: // transform vector by matrix aiQuaterniont& operator *= (const aiMatrix4x4t& mat); - bool Equal(const aiQuaterniont& o, TReal epsilon = 1e-6) const; + bool Equal(const aiQuaterniont &o, TReal epsilon = ai_epsilon) const; public: diff --git a/include/assimp/vector2.h b/include/assimp/vector2.h index 333c094d4..f06e9441d 100644 --- a/include/assimp/vector2.h +++ b/include/assimp/vector2.h @@ -85,7 +85,7 @@ public: 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); const aiVector2t SymMul(const aiVector2t& o); diff --git a/include/assimp/vector3.h b/include/assimp/vector3.h index c191e1ee7..a886def1d 100644 --- a/include/assimp/vector3.h +++ b/include/assimp/vector3.h @@ -114,7 +114,7 @@ public: bool operator < (const aiVector3t& other) const; /// @brief - bool Equal(const aiVector3t& other, TReal epsilon = 1e-6) const; + bool Equal(const aiVector3t &other, TReal epsilon = ai_epsilon) const; template operator aiVector3t () const; diff --git a/test/unit/Common/utMesh.cpp b/test/unit/Common/utMesh.cpp index edb3de3de..77a711394 100644 --- a/test/unit/Common/utMesh.cpp +++ b/test/unit/Common/utMesh.cpp @@ -60,7 +60,7 @@ protected: }; TEST_F(utMesh, emptyMeshHasNoContentTest) { - EXPECT_EQ(0, mesh->mName.length); + EXPECT_EQ(0u, mesh->mName.length); EXPECT_FALSE(mesh->HasPositions()); EXPECT_FALSE(mesh->HasFaces()); 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->HasTextureCoords(0)); EXPECT_FALSE(mesh->HasTextureCoords(AI_MAX_NUMBER_OF_TEXTURECOORDS)); - EXPECT_EQ(0, mesh->GetNumUVChannels()); - EXPECT_EQ(0, mesh->GetNumColorChannels()); + EXPECT_EQ(0u, mesh->GetNumUVChannels()); + EXPECT_EQ(0u, mesh->GetNumColorChannels()); EXPECT_FALSE(mesh->HasBones()); EXPECT_FALSE(mesh->HasTextureCoordsName(0)); EXPECT_FALSE(mesh->HasTextureCoordsName(AI_MAX_NUMBER_OF_TEXTURECOORDS)); @@ -80,8 +80,8 @@ TEST_F(utMesh, setTextureCoordsName) { EXPECT_FALSE(mesh->HasTextureCoordsName(0)); const aiString texcoords_name("texcoord_name"); mesh->SetTextureCoordsName(0, texcoords_name); - EXPECT_TRUE(mesh->HasTextureCoordsName(0)); - EXPECT_FALSE(mesh->HasTextureCoordsName(1)); + EXPECT_TRUE(mesh->HasTextureCoordsName(0u)); + EXPECT_FALSE(mesh->HasTextureCoordsName(1u)); ASSERT_NE(nullptr, mesh->mTextureCoordsNames); ASSERT_NE(nullptr, mesh->mTextureCoordsNames[0]); 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->GetTextureCoordsName(0)); } + diff --git a/test/unit/utColladaExport.cpp b/test/unit/utColladaExport.cpp index 4488f9f90..bb87071bb 100644 --- a/test/unit/utColladaExport.cpp +++ b/test/unit/utColladaExport.cpp @@ -124,9 +124,9 @@ TEST_F(utColladaExport, testExportLight) { ASSERT_NE(pTest, nullptr); ASSERT_TRUE(pTest->HasLights()); - const unsigned int origNumLights(pTest->mNumLights); + const unsigned int origNumLights = pTest->mNumLights; // 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 origLights(5); for (size_t i = 0; i < origNumLights; i++) { diff --git a/test/unit/utFBXImporterExporter.cpp b/test/unit/utFBXImporterExporter.cpp index 679f6ded3..9b8f2fa0d 100644 --- a/test/unit/utFBXImporterExporter.cpp +++ b/test/unit/utFBXImporterExporter.cpp @@ -53,7 +53,7 @@ using namespace Assimp; class utFBXImporterExporter : public AbstractImportExportBase { public: - virtual bool importerTest() { + bool importerTest() override { Assimp::Importer importer; const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/spider.fbx", aiProcess_ValidateDataStructure); return nullptr != scene; diff --git a/test/unit/utVersion.cpp b/test/unit/utVersion.cpp index 0fc338f02..7548417e7 100644 --- a/test/unit/utVersion.cpp +++ b/test/unit/utVersion.cpp @@ -48,12 +48,12 @@ TEST_F( utVersion, aiGetLegalStringTest ) { EXPECT_NE( lv, nullptr ); 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); } TEST_F( utVersion, aiGetVersionMinorTest ) { - EXPECT_EQ(aiGetVersionMinor(), 1U); + EXPECT_EQ(aiGetVersionMinor(), 2U); } TEST_F( utVersion, aiGetVersionMajorTest ) { @@ -61,7 +61,7 @@ TEST_F( utVersion, aiGetVersionMajorTest ) { } TEST_F( utVersion, aiGetVersionPatchTest ) { - EXPECT_EQ(aiGetVersionPatch(), 6U ); + EXPECT_EQ(aiGetVersionPatch(), 0U ); } TEST_F( utVersion, aiGetCompileFlagsTest ) { diff --git a/test/unit/utglTF2ImportExport.cpp b/test/unit/utglTF2ImportExport.cpp index 84f940c66..00f76aa47 100644 --- a/test/unit/utglTF2ImportExport.cpp +++ b/test/unit/utglTF2ImportExport.cpp @@ -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); for ( auto i = 0u; i < scene->mMeshes[0]->mNumVertices; ++i ) { 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); } }