diff --git a/.clang-format b/.clang-format index c8b8ab856..c700d9700 100644 --- a/.clang-format +++ b/.clang-format @@ -70,8 +70,8 @@ IncludeCategories: - Regex: '^<.*' Priority: 3 # IncludeIsMainRegex: '(Test)?$' -IndentCaseLabels: true -IndentPPDirectives: AfterHash +IndentCaseLabels: false +#IndentPPDirectives: AfterHash IndentWidth: 4 # IndentWrappedFunctionNames: false # JavaScriptQuotes: Leave diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml new file mode 100644 index 000000000..61e804b2e --- /dev/null +++ b/.github/workflows/ccpp.yml @@ -0,0 +1,22 @@ +name: C/C++ CI + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build-ubuntu: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + - name: configure + run: cmake CMakeLists.txt + - name: build + run: cmake --build . + - name: test + run: cd bin && ./unit + diff --git a/CMakeLists.txt b/CMakeLists.txt index 42f975c79..ecd131b8c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,9 +39,9 @@ SET(CMAKE_POLICY_DEFAULT_CMP0074 NEW) CMAKE_MINIMUM_REQUIRED( VERSION 3.0 ) # Toggles the use of the hunter package manager -option(HUNTER_ENABLED "Enable Hunter package manager support" OFF) +option(ASSIMP_HUNTER_ENABLED "Enable Hunter package manager support" OFF) -IF(HUNTER_ENABLED) +IF(ASSIMP_HUNTER_ENABLED) include("cmake/HunterGate.cmake") HunterGate( URL "https://github.com/ruslo/hunter/archive/v0.23.176.tar.gz" @@ -60,7 +60,7 @@ OPTION( BUILD_SHARED_LIBS ON ) -OPTION( BUILD_FRAMEWORK +OPTION( ASSIMP_BUILD_FRAMEWORK "Build package as Mac OS X Framework bundle." OFF ) @@ -101,7 +101,7 @@ OPTION ( ASSIMP_COVERALLS OFF ) OPTION( ASSIMP_INSTALL - "DIsable this if you want to use assimp as a submodule." + "Disable this if you want to use assimp as a submodule." ON ) OPTION ( ASSIMP_ERROR_MAX @@ -120,25 +120,25 @@ OPTION ( ASSIMP_UBSAN "Enable Undefined Behavior sanitizer." OFF ) -OPTION ( SYSTEM_IRRXML +OPTION ( ASSIMP_SYSTEM_IRRXML "Use system installed Irrlicht/IrrXML library." OFF ) -OPTION ( BUILD_DOCS +OPTION ( ASSIMP_BUILD_DOCS "Build documentation using Doxygen." OFF ) -OPTION( INJECT_DEBUG_POSTFIX +OPTION( ASSIMP_INJECT_DEBUG_POSTFIX "Inject debug postfix in .a/.so/.dll lib names" ON ) -OPTION ( IGNORE_GIT_HASH +OPTION ( ASSIMP_IGNORE_GIT_HASH "Don't call git to get the hash." OFF ) -IF (IOS AND NOT HUNTER_ENABLED) +IF (IOS AND NOT ASSIMP_HUNTER_ENABLED) IF (NOT CMAKE_BUILD_TYPE) SET(CMAKE_BUILD_TYPE "Release") ENDIF () @@ -161,7 +161,7 @@ IF(MSVC) ENDIF() ENDIF() -IF (BUILD_FRAMEWORK) +IF (ASSIMP_BUILD_FRAMEWORK) SET (BUILD_SHARED_LIBS ON) MESSAGE(STATUS "Framework bundle building enabled") ENDIF() @@ -181,12 +181,12 @@ SET (ASSIMP_VERSION ${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}.${ASSIMP_VER SET (ASSIMP_SOVERSION 5) SET( ASSIMP_PACKAGE_VERSION "0" CACHE STRING "the package-specific version used for uploading the sources" ) -if(NOT HUNTER_ENABLED) +if(NOT ASSIMP_HUNTER_ENABLED) # Enable C++11 support globally set_property( GLOBAL PROPERTY CXX_STANDARD 11 ) endif() -IF(NOT IGNORE_GIT_HASH) +IF(NOT ASSIMP_IGNORE_GIT_HASH) # Get the current working branch EXECUTE_PROCESS( COMMAND git rev-parse --abbrev-ref HEAD @@ -245,7 +245,7 @@ ENDIF() # Grouped compiler settings IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT CMAKE_COMPILER_IS_MINGW) - IF(NOT HUNTER_ENABLED) + IF(NOT ASSIMP_HUNTER_ENABLED) SET(CMAKE_CXX_FLAGS "-fPIC -std=c++0x ${CMAKE_CXX_FLAGS}") SET(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}") ENDIF() @@ -255,15 +255,14 @@ IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT CMAKE_COMPILER_IS_MINGW) SET(LIBSTDC++_LIBRARIES -lstdc++) ELSEIF(MSVC) # enable multi-core compilation with MSVC - ADD_COMPILE_OPTIONS(/MP) - ADD_COMPILE_OPTIONS( /bigobj ) + ADD_COMPILE_OPTIONS(/MP /bigobj /W4 /WX ) # disable "elements of array '' will be default initialized" warning on MSVC2013 IF(MSVC12) ADD_COMPILE_OPTIONS(/wd4351) ENDIF() SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /D_DEBUG /Zi /Od") ELSEIF ( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" ) - IF(NOT HUNTER_ENABLED) + IF(NOT ASSIMP_HUNTER_ENABLED) SET(CMAKE_CXX_FLAGS "-fPIC -std=c++11 ${CMAKE_CXX_FLAGS}") SET(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}") ENDIF() @@ -275,7 +274,7 @@ ELSEIF( CMAKE_COMPILER_IS_MINGW ) ELSEIF(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.3) message(WARNING "MinGW is old, if you experience errors, update MinGW.") ENDIF() - IF(NOT HUNTER_ENABLED) + IF(NOT ASSIMP_HUNTER_ENABLED) SET(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}") SET(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}") ENDIF() @@ -284,7 +283,7 @@ ELSEIF( CMAKE_COMPILER_IS_MINGW ) ADD_DEFINITIONS( -U__STRICT_ANSI__ ) ENDIF() -IF ( IOS AND NOT HUNTER_ENABLED) +IF ( IOS AND NOT ASSIMP_HUNTER_ENABLED) IF (CMAKE_BUILD_TYPE STREQUAL "Debug") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fembed-bitcode -Og") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fembed-bitcode -Og") @@ -361,7 +360,7 @@ SET( ASSIMP_BIN_INSTALL_DIR "bin" CACHE STRING get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG) -IF (INJECT_DEBUG_POSTFIX AND (is_multi_config OR CMAKE_BUILD_TYPE STREQUAL "Debug")) +IF (ASSIMP_INJECT_DEBUG_POSTFIX AND (is_multi_config OR CMAKE_BUILD_TYPE STREQUAL "Debug")) SET(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "Debug Postfix for lib, samples and tools") ELSE() SET(CMAKE_DEBUG_POSTFIX "" CACHE STRING "Debug Postfix for lib, samples and tools") @@ -374,7 +373,7 @@ IF (NOT TARGET uninstall) ADD_CUSTOM_TARGET(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") ENDIF() -IF(HUNTER_ENABLED) +IF(ASSIMP_HUNTER_ENABLED) set(CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}") set(INCLUDE_INSTALL_DIR "include") @@ -441,18 +440,18 @@ ELSE() DESTINATION "${ASSIMP_LIB_INSTALL_DIR}/cmake/assimp-${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}" COMPONENT ${LIBASSIMP-DEV_COMPONENT}) ENDIF() -IF( BUILD_DOCS ) +IF( ASSIMP_BUILD_DOCS ) ADD_SUBDIRECTORY(doc) ENDIF() # Look for system installed irrXML -IF ( SYSTEM_IRRXML ) +IF ( ASSIMP_SYSTEM_IRRXML ) FIND_PACKAGE( IrrXML REQUIRED ) ENDIF() # Search for external dependencies, and build them from source if not found # Search for zlib -IF(HUNTER_ENABLED) +IF(ASSIMP_HUNTER_ENABLED) hunter_add_package(ZLIB) find_package(ZLIB CONFIG REQUIRED) @@ -576,7 +575,7 @@ ELSE () ADD_DEFINITIONS( -DASSIMP_BUILD_NO_C4D_IMPORTER ) ENDIF () -IF(NOT HUNTER_ENABLED) +IF(NOT ASSIMP_HUNTER_ENABLED) ADD_SUBDIRECTORY(contrib) ENDIF() diff --git a/Readme.md b/Readme.md index 7e0a8cccc..61fff538f 100644 --- a/Readme.md +++ b/Readme.md @@ -2,6 +2,7 @@ Open Asset Import Library (assimp) ================================== A library to import and export various 3d-model-formats including scene-post-processing to generate missing render data. ### Current project status ### +![C/C++ CI](https://github.com/assimp/assimp/workflows/C/C++%20CI/badge.svg) [![Linux Build Status](https://travis-ci.org/assimp/assimp.svg)](https://travis-ci.org/assimp/assimp) [![Windows Build Status](https://ci.appveyor.com/api/projects/status/tmo433wax6u6cjp4?svg=true)](https://ci.appveyor.com/project/kimkulling/assimp) diff --git a/code/3DS/3DSExporter.cpp b/code/3DS/3DSExporter.cpp index 14810cbff..403ca20a2 100644 --- a/code/3DS/3DSExporter.cpp +++ b/code/3DS/3DSExporter.cpp @@ -80,7 +80,7 @@ namespace { { chunk_start_pos = writer.GetCurrentPos(); writer.PutU2(chunk_type); - writer.PutU4(CHUNK_SIZE_NOT_SET); + writer.PutU4((uint32_t)CHUNK_SIZE_NOT_SET); } ~ChunkWriter() { @@ -193,21 +193,21 @@ Discreet3DSExporter:: Discreet3DSExporter(std::shared_ptr &outfile, co CollectTrafos(scene->mRootNode, trafos); CollectMeshes(scene->mRootNode, meshes); - ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAIN); + ChunkWriter curRootChunk(writer, Discreet3DS::CHUNK_MAIN); { - ChunkWriter chunk(writer, Discreet3DS::CHUNK_OBJMESH); + ChunkWriter curChunk(writer, Discreet3DS::CHUNK_OBJMESH); WriteMaterials(); WriteMeshes(); { - ChunkWriter chunk(writer, Discreet3DS::CHUNK_MASTER_SCALE); + ChunkWriter curChunk1(writer, Discreet3DS::CHUNK_MASTER_SCALE); writer.PutF4(1.0f); } } { - ChunkWriter chunk(writer, Discreet3DS::CHUNK_KEYFRAMER); + ChunkWriter curChunk(writer, Discreet3DS::CHUNK_KEYFRAMER); WriteHierarchy(*scene->mRootNode, -1, -1); } } @@ -223,9 +223,9 @@ int Discreet3DSExporter::WriteHierarchy(const aiNode& node, int seq, int sibling { // 3DS scene hierarchy is serialized as in http://www.martinreddy.net/gfx/3d/3DS.spec { - ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKINFO); + ChunkWriter curRootChunk(writer, Discreet3DS::CHUNK_TRACKINFO); { - ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKOBJNAME); + ChunkWriter curChunk(writer, Discreet3DS::CHUNK_TRACKOBJNAME); // Assimp node names are unique and distinct from all mesh-node // names we generate; thus we can use them as-is @@ -237,7 +237,7 @@ int Discreet3DSExporter::WriteHierarchy(const aiNode& node, int seq, int sibling int16_t hierarchy_pos = static_cast(seq); if (sibling_level != -1) { - hierarchy_pos = sibling_level; + hierarchy_pos =(uint16_t) sibling_level; } // Write the hierarchy position @@ -262,7 +262,7 @@ int Discreet3DSExporter::WriteHierarchy(const aiNode& node, int seq, int sibling const unsigned int mesh_idx = node.mMeshes[i]; const aiMesh& mesh = *scene->mMeshes[mesh_idx]; - ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKINFO); + ChunkWriter curChunk(writer, Discreet3DS::CHUNK_TRACKINFO); { ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRACKOBJNAME); WriteString(GetMeshName(mesh, mesh_idx, node)); @@ -279,7 +279,7 @@ int Discreet3DSExporter::WriteHierarchy(const aiNode& node, int seq, int sibling void Discreet3DSExporter::WriteMaterials() { for (unsigned int i = 0; i < scene->mNumMaterials; ++i) { - ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_MATERIAL); + ChunkWriter curRootChunk(writer, Discreet3DS::CHUNK_MAT_MATERIAL); const aiMaterial& mat = *scene->mMaterials[i]; { @@ -290,22 +290,22 @@ void Discreet3DSExporter::WriteMaterials() aiColor3D color; if (mat.Get(AI_MATKEY_COLOR_DIFFUSE, color) == AI_SUCCESS) { - ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_DIFFUSE); + ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAT_DIFFUSE); WriteColor(color); } if (mat.Get(AI_MATKEY_COLOR_SPECULAR, color) == AI_SUCCESS) { - ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SPECULAR); + ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAT_SPECULAR); WriteColor(color); } if (mat.Get(AI_MATKEY_COLOR_AMBIENT, color) == AI_SUCCESS) { - ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_AMBIENT); + ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAT_AMBIENT); WriteColor(color); } if (mat.Get(AI_MATKEY_COLOR_EMISSIVE, color) == AI_SUCCESS) { - ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SELF_ILLUM); + ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAT_SELF_ILLUM); WriteColor(color); } @@ -389,14 +389,14 @@ void Discreet3DSExporter::WriteTexture(const aiMaterial& mat, aiTextureType type ChunkWriter chunk(writer, chunk_flags); { - ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAPFILE); + ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAPFILE); WriteString(path); } WritePercentChunk(blend); { - ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_MAP_TILING); + ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAT_MAP_TILING); uint16_t val = 0; // WRAP if (map_mode[0] == aiTextureMapMode_Mirror) { val = 0x2; @@ -447,7 +447,7 @@ void Discreet3DSExporter::WriteMeshes() // Vertices in world space { - ChunkWriter chunk(writer, Discreet3DS::CHUNK_VERTLIST); + ChunkWriter curChunk(writer, Discreet3DS::CHUNK_VERTLIST); const uint16_t count = static_cast(mesh.mNumVertices); writer.PutU2(count); @@ -461,7 +461,7 @@ void Discreet3DSExporter::WriteMeshes() // UV coordinates if (mesh.HasTextureCoords(0)) { - ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAPLIST); + ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAPLIST); const uint16_t count = static_cast(mesh.mNumVertices); writer.PutU2(count); @@ -474,7 +474,7 @@ void Discreet3DSExporter::WriteMeshes() // Faces (indices) { - ChunkWriter chunk(writer, Discreet3DS::CHUNK_FACELIST); + ChunkWriter curChunk(writer, Discreet3DS::CHUNK_FACELIST); ai_assert(mesh.mNumFaces <= 0xffff); @@ -513,7 +513,7 @@ void Discreet3DSExporter::WriteMeshes() // Transformation matrix by which the mesh vertices have been pre-transformed with. { - ChunkWriter chunk(writer, Discreet3DS::CHUNK_TRMATRIX); + ChunkWriter curChunk(writer, Discreet3DS::CHUNK_TRMATRIX); for (unsigned int r = 0; r < 4; ++r) { for (unsigned int c = 0; c < 3; ++c) { writer.PutF4(trafo[r][c]); @@ -526,7 +526,7 @@ void Discreet3DSExporter::WriteMeshes() // ------------------------------------------------------------------------------------------------ void Discreet3DSExporter::WriteFaceMaterialChunk(const aiMesh& mesh) { - ChunkWriter chunk(writer, Discreet3DS::CHUNK_FACEMAT); + ChunkWriter curChunk(writer, Discreet3DS::CHUNK_FACEMAT); const std::string& name = GetMaterialName(*scene->mMaterials[mesh.mMaterialIndex], mesh.mMaterialIndex); WriteString(name); @@ -559,7 +559,7 @@ void Discreet3DSExporter::WriteString(const aiString& s) { // ------------------------------------------------------------------------------------------------ void Discreet3DSExporter::WriteColor(const aiColor3D& color) { - ChunkWriter chunk(writer, Discreet3DS::CHUNK_RGBF); + ChunkWriter curChunk(writer, Discreet3DS::CHUNK_RGBF); writer.PutF4(color.r); writer.PutF4(color.g); writer.PutF4(color.b); @@ -567,13 +567,13 @@ void Discreet3DSExporter::WriteColor(const aiColor3D& color) { // ------------------------------------------------------------------------------------------------ void Discreet3DSExporter::WritePercentChunk(float f) { - ChunkWriter chunk(writer, Discreet3DS::CHUNK_PERCENTF); + ChunkWriter curChunk(writer, Discreet3DS::CHUNK_PERCENTF); writer.PutF4(f); } // ------------------------------------------------------------------------------------------------ void Discreet3DSExporter::WritePercentChunk(double f) { - ChunkWriter chunk(writer, Discreet3DS::CHUNK_PERCENTD); + ChunkWriter ccurChunkhunk(writer, Discreet3DS::CHUNK_PERCENTD); writer.PutF8(f); } diff --git a/code/3DS/3DSHelper.h b/code/3DS/3DSHelper.h index e483f1a25..633cfbbf0 100644 --- a/code/3DS/3DSHelper.h +++ b/code/3DS/3DSHelper.h @@ -45,18 +45,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_3DSFILEHELPER_H_INC #define AI_3DSFILEHELPER_H_INC -#include #include +#include #include -#include -#include +#include #include #include -#include +#include +#include #include //sprintf -namespace Assimp { -namespace D3DS { +namespace Assimp { +namespace D3DS { #include @@ -77,15 +77,13 @@ private: public: //! data structure for a single chunk in a .3ds file struct Chunk { - uint16_t Flag; - uint32_t Size; + uint16_t Flag; + uint32_t Size; } PACK_STRUCT; - //! Used for shading field in material3ds structure //! From AutoDesk 3ds SDK - typedef enum - { + typedef enum { // translated to gouraud shading with wireframe active Wire = 0x0, @@ -109,59 +107,57 @@ public: } shadetype3ds; // Flags for animated keys - enum - { - KEY_USE_TENS = 0x1, - KEY_USE_CONT = 0x2, - KEY_USE_BIAS = 0x4, - KEY_USE_EASE_TO = 0x8, - KEY_USE_EASE_FROM = 0x10 - } ; + enum { + KEY_USE_TENS = 0x1, + KEY_USE_CONT = 0x2, + KEY_USE_BIAS = 0x4, + KEY_USE_EASE_TO = 0x8, + KEY_USE_EASE_FROM = 0x10 + }; - enum - { + enum { // ******************************************************************** // Basic chunks which can be found everywhere in the file - CHUNK_VERSION = 0x0002, - CHUNK_RGBF = 0x0010, // float4 R; float4 G; float4 B - CHUNK_RGBB = 0x0011, // int1 R; int1 G; int B + CHUNK_VERSION = 0x0002, + CHUNK_RGBF = 0x0010, // float4 R; float4 G; float4 B + CHUNK_RGBB = 0x0011, // int1 R; int1 G; int B // Linear color values (gamma = 2.2?) - CHUNK_LINRGBF = 0x0013, // float4 R; float4 G; float4 B - CHUNK_LINRGBB = 0x0012, // int1 R; int1 G; int B + CHUNK_LINRGBF = 0x0013, // float4 R; float4 G; float4 B + CHUNK_LINRGBB = 0x0012, // int1 R; int1 G; int B - CHUNK_PERCENTW = 0x0030, // int2 percentage - CHUNK_PERCENTF = 0x0031, // float4 percentage - CHUNK_PERCENTD = 0x0032, // float8 percentage + CHUNK_PERCENTW = 0x0030, // int2 percentage + CHUNK_PERCENTF = 0x0031, // float4 percentage + CHUNK_PERCENTD = 0x0032, // float8 percentage // ******************************************************************** // Prj master chunk - CHUNK_PRJ = 0xC23D, + CHUNK_PRJ = 0xC23D, // MDLI master chunk - CHUNK_MLI = 0x3DAA, + CHUNK_MLI = 0x3DAA, // Primary main chunk of the .3ds file - CHUNK_MAIN = 0x4D4D, + CHUNK_MAIN = 0x4D4D, // Mesh main chunk - CHUNK_OBJMESH = 0x3D3D, + CHUNK_OBJMESH = 0x3D3D, // Specifies the background color of the .3ds file // This is passed through the material system for // viewing purposes. - CHUNK_BKGCOLOR = 0x1200, + CHUNK_BKGCOLOR = 0x1200, // Specifies the ambient base color of the scene. // This is added to all materials in the file - CHUNK_AMBCOLOR = 0x2100, + CHUNK_AMBCOLOR = 0x2100, // Specifies the background image for the whole scene // This value is passed through the material system // to the viewer - CHUNK_BIT_MAP = 0x1100, - CHUNK_BIT_MAP_EXISTS = 0x1101, + CHUNK_BIT_MAP = 0x1100, + CHUNK_BIT_MAP_EXISTS = 0x1101, // ******************************************************************** // Viewport related stuff. Ignored @@ -177,171 +173,222 @@ public: // ******************************************************************** // Mesh chunks - CHUNK_OBJBLOCK = 0x4000, - CHUNK_TRIMESH = 0x4100, - CHUNK_VERTLIST = 0x4110, + CHUNK_OBJBLOCK = 0x4000, + CHUNK_TRIMESH = 0x4100, + CHUNK_VERTLIST = 0x4110, CHUNK_VERTFLAGS = 0x4111, - CHUNK_FACELIST = 0x4120, - CHUNK_FACEMAT = 0x4130, - CHUNK_MAPLIST = 0x4140, - CHUNK_SMOOLIST = 0x4150, - CHUNK_TRMATRIX = 0x4160, + CHUNK_FACELIST = 0x4120, + CHUNK_FACEMAT = 0x4130, + CHUNK_MAPLIST = 0x4140, + CHUNK_SMOOLIST = 0x4150, + CHUNK_TRMATRIX = 0x4160, CHUNK_MESHCOLOR = 0x4165, - CHUNK_TXTINFO = 0x4170, - CHUNK_LIGHT = 0x4600, - CHUNK_CAMERA = 0x4700, + CHUNK_TXTINFO = 0x4170, + CHUNK_LIGHT = 0x4600, + CHUNK_CAMERA = 0x4700, CHUNK_HIERARCHY = 0x4F00, // Specifies the global scaling factor. This is applied // to the root node's transformation matrix - CHUNK_MASTER_SCALE = 0x0100, + CHUNK_MASTER_SCALE = 0x0100, // ******************************************************************** // Material chunks - CHUNK_MAT_MATERIAL = 0xAFFF, + CHUNK_MAT_MATERIAL = 0xAFFF, - // asciiz containing the name of the material - CHUNK_MAT_MATNAME = 0xA000, - CHUNK_MAT_AMBIENT = 0xA010, // followed by color chunk - CHUNK_MAT_DIFFUSE = 0xA020, // followed by color chunk - CHUNK_MAT_SPECULAR = 0xA030, // followed by color chunk + // asciiz containing the name of the material + CHUNK_MAT_MATNAME = 0xA000, + CHUNK_MAT_AMBIENT = 0xA010, // followed by color chunk + CHUNK_MAT_DIFFUSE = 0xA020, // followed by color chunk + CHUNK_MAT_SPECULAR = 0xA030, // followed by color chunk - // Specifies the shininess of the material - // followed by percentage chunk - CHUNK_MAT_SHININESS = 0xA040, - CHUNK_MAT_SHININESS_PERCENT = 0xA041 , + // Specifies the shininess of the material + // followed by percentage chunk + CHUNK_MAT_SHININESS = 0xA040, + CHUNK_MAT_SHININESS_PERCENT = 0xA041, - // Specifies the shading mode to be used - // followed by a short - CHUNK_MAT_SHADING = 0xA100, + // Specifies the shading mode to be used + // followed by a short + CHUNK_MAT_SHADING = 0xA100, - // NOTE: Emissive color (self illumination) seems not - // to be a color but a single value, type is unknown. - // Make the parser accept both of them. - // followed by percentage chunk (?) - CHUNK_MAT_SELF_ILLUM = 0xA080, + // NOTE: Emissive color (self illumination) seems not + // to be a color but a single value, type is unknown. + // Make the parser accept both of them. + // followed by percentage chunk (?) + CHUNK_MAT_SELF_ILLUM = 0xA080, - // Always followed by percentage chunk (?) - CHUNK_MAT_SELF_ILPCT = 0xA084, + // Always followed by percentage chunk (?) + CHUNK_MAT_SELF_ILPCT = 0xA084, - // Always followed by percentage chunk - CHUNK_MAT_TRANSPARENCY = 0xA050, + // Always followed by percentage chunk + CHUNK_MAT_TRANSPARENCY = 0xA050, - // Diffuse texture channel 0 - CHUNK_MAT_TEXTURE = 0xA200, + // Diffuse texture channel 0 + CHUNK_MAT_TEXTURE = 0xA200, - // Contains opacity information for each texel - CHUNK_MAT_OPACMAP = 0xA210, + // Contains opacity information for each texel + CHUNK_MAT_OPACMAP = 0xA210, - // Contains a reflection map to be used to reflect - // the environment. This is partially supported. - CHUNK_MAT_REFLMAP = 0xA220, + // Contains a reflection map to be used to reflect + // the environment. This is partially supported. + CHUNK_MAT_REFLMAP = 0xA220, - // Self Illumination map (emissive colors) - CHUNK_MAT_SELFIMAP = 0xA33d, + // Self Illumination map (emissive colors) + CHUNK_MAT_SELFIMAP = 0xA33d, - // Bumpmap. Not specified whether it is a heightmap - // or a normal map. Assme it is a heightmap since - // artist normally prefer this format. - CHUNK_MAT_BUMPMAP = 0xA230, + // Bumpmap. Not specified whether it is a heightmap + // or a normal map. Assme it is a heightmap since + // artist normally prefer this format. + CHUNK_MAT_BUMPMAP = 0xA230, - // Specular map. Seems to influence the specular color - CHUNK_MAT_SPECMAP = 0xA204, + // Specular map. Seems to influence the specular color + CHUNK_MAT_SPECMAP = 0xA204, - // Holds shininess data. - CHUNK_MAT_MAT_SHINMAP = 0xA33C, + // Holds shininess data. + CHUNK_MAT_MAT_SHINMAP = 0xA33C, - // Scaling in U/V direction. - // (need to gen separate UV coordinate set - // and do this by hand) - CHUNK_MAT_MAP_USCALE = 0xA354, - CHUNK_MAT_MAP_VSCALE = 0xA356, + // Scaling in U/V direction. + // (need to gen separate UV coordinate set + // and do this by hand) + CHUNK_MAT_MAP_USCALE = 0xA354, + CHUNK_MAT_MAP_VSCALE = 0xA356, - // Translation in U/V direction. - // (need to gen separate UV coordinate set - // and do this by hand) - CHUNK_MAT_MAP_UOFFSET = 0xA358, - CHUNK_MAT_MAP_VOFFSET = 0xA35a, + // Translation in U/V direction. + // (need to gen separate UV coordinate set + // and do this by hand) + CHUNK_MAT_MAP_UOFFSET = 0xA358, + CHUNK_MAT_MAP_VOFFSET = 0xA35a, - // UV-coordinates rotation around the z-axis - // Assumed to be in radians. - CHUNK_MAT_MAP_ANG = 0xA35C, + // UV-coordinates rotation around the z-axis + // Assumed to be in radians. + CHUNK_MAT_MAP_ANG = 0xA35C, - // Tiling flags for 3DS files - CHUNK_MAT_MAP_TILING = 0xa351, + // Tiling flags for 3DS files + CHUNK_MAT_MAP_TILING = 0xa351, - // Specifies the file name of a texture - CHUNK_MAPFILE = 0xA300, + // Specifies the file name of a texture + CHUNK_MAPFILE = 0xA300, - // Specifies whether a materail requires two-sided rendering - CHUNK_MAT_TWO_SIDE = 0xA081, + // Specifies whether a materail requires two-sided rendering + CHUNK_MAT_TWO_SIDE = 0xA081, // ******************************************************************** // Main keyframer chunk. Contains translation/rotation/scaling data - CHUNK_KEYFRAMER = 0xB000, + CHUNK_KEYFRAMER = 0xB000, // Supported sub chunks - CHUNK_TRACKINFO = 0xB002, - CHUNK_TRACKOBJNAME = 0xB010, - CHUNK_TRACKDUMMYOBJNAME = 0xB011, - CHUNK_TRACKPIVOT = 0xB013, - CHUNK_TRACKPOS = 0xB020, - CHUNK_TRACKROTATE = 0xB021, - CHUNK_TRACKSCALE = 0xB022, + CHUNK_TRACKINFO = 0xB002, + CHUNK_TRACKOBJNAME = 0xB010, + CHUNK_TRACKDUMMYOBJNAME = 0xB011, + CHUNK_TRACKPIVOT = 0xB013, + CHUNK_TRACKPOS = 0xB020, + CHUNK_TRACKROTATE = 0xB021, + CHUNK_TRACKSCALE = 0xB022, // ******************************************************************** // Keyframes for various other stuff in the file // Partially ignored - CHUNK_AMBIENTKEY = 0xB001, - CHUNK_TRACKMORPH = 0xB026, - CHUNK_TRACKHIDE = 0xB029, - CHUNK_OBJNUMBER = 0xB030, - CHUNK_TRACKCAMERA = 0xB003, - CHUNK_TRACKFOV = 0xB023, - CHUNK_TRACKROLL = 0xB024, - CHUNK_TRACKCAMTGT = 0xB004, - CHUNK_TRACKLIGHT = 0xB005, - CHUNK_TRACKLIGTGT = 0xB006, - CHUNK_TRACKSPOTL = 0xB007, - CHUNK_FRAMES = 0xB008, + CHUNK_AMBIENTKEY = 0xB001, + CHUNK_TRACKMORPH = 0xB026, + CHUNK_TRACKHIDE = 0xB029, + CHUNK_OBJNUMBER = 0xB030, + CHUNK_TRACKCAMERA = 0xB003, + CHUNK_TRACKFOV = 0xB023, + CHUNK_TRACKROLL = 0xB024, + CHUNK_TRACKCAMTGT = 0xB004, + CHUNK_TRACKLIGHT = 0xB005, + CHUNK_TRACKLIGTGT = 0xB006, + CHUNK_TRACKSPOTL = 0xB007, + CHUNK_FRAMES = 0xB008, // ******************************************************************** // light sub-chunks - CHUNK_DL_OFF = 0x4620, - CHUNK_DL_OUTER_RANGE = 0x465A, - CHUNK_DL_INNER_RANGE = 0x4659, - CHUNK_DL_MULTIPLIER = 0x465B, - CHUNK_DL_EXCLUDE = 0x4654, - CHUNK_DL_ATTENUATE = 0x4625, - CHUNK_DL_SPOTLIGHT = 0x4610, + CHUNK_DL_OFF = 0x4620, + CHUNK_DL_OUTER_RANGE = 0x465A, + CHUNK_DL_INNER_RANGE = 0x4659, + CHUNK_DL_MULTIPLIER = 0x465B, + CHUNK_DL_EXCLUDE = 0x4654, + CHUNK_DL_ATTENUATE = 0x4625, + CHUNK_DL_SPOTLIGHT = 0x4610, // camera sub-chunks - CHUNK_CAM_RANGES = 0x4720 + CHUNK_CAM_RANGES = 0x4720 }; }; // --------------------------------------------------------------------------- /** Helper structure representing a 3ds mesh face */ -struct Face : public FaceWithSmoothingGroup -{ +struct Face : public FaceWithSmoothingGroup { }; +#ifdef _WIN32 +# pragma warning(disable : 4315) +#endif + // --------------------------------------------------------------------------- /** Helper structure representing a texture */ struct Texture { //! Default constructor Texture() AI_NO_EXCEPT - : mOffsetU (0.0) - , mOffsetV (0.0) - , mScaleU (1.0) - , mScaleV (1.0) - , mRotation (0.0) - , mMapMode (aiTextureMapMode_Wrap) - , bPrivate() - , iUVSrc (0) { + : mTextureBlend(0.0f), + mMapName(), + mOffsetU(0.0), + mOffsetV(0.0), + mScaleU(1.0), + mScaleV(1.0), + mRotation(0.0), + mMapMode(aiTextureMapMode_Wrap), + bPrivate(), + iUVSrc(0) { mTextureBlend = get_qnan(); } + Texture(const Texture &other) : + mTextureBlend(other.mTextureBlend), + mMapName(other.mMapName), + mOffsetU(other.mOffsetU), + mOffsetV(other.mOffsetV), + mScaleU(other.mScaleU), + mScaleV(other.mScaleV), + mRotation(other.mRotation), + mMapMode(other.mMapMode), + bPrivate(other.bPrivate), + iUVSrc(other.iUVSrc) { + // empty + } + + Texture(Texture &&other) AI_NO_EXCEPT : mTextureBlend(std::move(other.mTextureBlend)), + mMapName(std::move(other.mMapName)), + mOffsetU(std::move(other.mOffsetU)), + mOffsetV(std::move(other.mOffsetV)), + mScaleU(std::move(other.mScaleU)), + mScaleV(std::move(other.mScaleV)), + mRotation(std::move(other.mRotation)), + mMapMode(std::move(other.mMapMode)), + bPrivate(std::move(other.bPrivate)), + iUVSrc(std::move(other.iUVSrc)) { + // empty + } + + Texture &operator=(Texture &&other) AI_NO_EXCEPT { + if (this == &other) { + return *this; + } + + mTextureBlend = std::move(other.mTextureBlend); + mMapName = std::move(other.mMapName); + mOffsetU = std::move(other.mOffsetU); + mOffsetV = std::move(other.mOffsetV); + mScaleU = std::move(other.mScaleU); + mScaleV = std::move(other.mScaleV); + mRotation = std::move(other.mRotation); + mMapMode = std::move(other.mMapMode); + bPrivate = std::move(other.bPrivate); + iUVSrc = std::move(other.iUVSrc); + + return *this; + } + //! Specifies the blend factor for the texture ai_real mTextureBlend; @@ -367,55 +414,59 @@ struct Texture { // --------------------------------------------------------------------------- /** Helper structure representing a 3ds material */ -struct Material -{ +struct Material { //! Default constructor has been deleted - Material() = delete; - - - //! Constructor with explicit name - explicit Material(const std::string &name) - : mName(name) - , mDiffuse ( ai_real( 0.6 ), ai_real( 0.6 ), ai_real( 0.6 ) ) // FIX ... we won't want object to be black - , mSpecularExponent ( ai_real( 0.0 ) ) - , mShininessStrength ( ai_real( 1.0 ) ) - , mShading(Discreet3DS::Gouraud) - , mTransparency ( ai_real( 1.0 ) ) - , mBumpHeight ( ai_real( 1.0 ) ) - , mTwoSided (false) - { + Material() : + mName(), + mDiffuse(ai_real(0.6), ai_real(0.6), ai_real(0.6)), + mSpecularExponent(ai_real(0.0)), + mShininessStrength(ai_real(1.0)), + mShading(Discreet3DS::Gouraud), + mTransparency(ai_real(1.0)), + mBumpHeight(ai_real(1.0)), + mTwoSided(false) { + // empty } + //! Constructor with explicit name + explicit Material(const std::string &name) : + mName(name), + mDiffuse(ai_real(0.6), ai_real(0.6), ai_real(0.6)), + mSpecularExponent(ai_real(0.0)), + mShininessStrength(ai_real(1.0)), + mShading(Discreet3DS::Gouraud), + mTransparency(ai_real(1.0)), + mBumpHeight(ai_real(1.0)), + mTwoSided(false) { + // empty + } - Material(const Material &other) = default; + Material(const Material &other) = default; Material &operator=(const Material &other) = default; - //! Move constructor. This is explicitly written because MSVC doesn't support defaulting it Material(Material &&other) AI_NO_EXCEPT - : mName(std::move(other.mName)) - , mDiffuse(std::move(other.mDiffuse)) - , mSpecularExponent(std::move(other.mSpecularExponent)) - , mShininessStrength(std::move(other.mShininessStrength)) - , mSpecular(std::move(other.mSpecular)) - , mAmbient(std::move(other.mAmbient)) - , mShading(std::move(other.mShading)) - , mTransparency(std::move(other.mTransparency)) - , sTexDiffuse(std::move(other.sTexDiffuse)) - , sTexOpacity(std::move(other.sTexOpacity)) - , sTexSpecular(std::move(other.sTexSpecular)) - , sTexReflective(std::move(other.sTexReflective)) - , sTexBump(std::move(other.sTexBump)) - , sTexEmissive(std::move(other.sTexEmissive)) - , sTexShininess(std::move(other.sTexShininess)) - , mBumpHeight(std::move(other.mBumpHeight)) - , mEmissive(std::move(other.mEmissive)) - , sTexAmbient(std::move(other.sTexAmbient)) - , mTwoSided(std::move(other.mTwoSided)) - { + : mName(std::move(other.mName)), + mDiffuse(std::move(other.mDiffuse)), + mSpecularExponent(std::move(other.mSpecularExponent)), + mShininessStrength(std::move(other.mShininessStrength)), + mSpecular(std::move(other.mSpecular)), + mAmbient(std::move(other.mAmbient)), + mShading(std::move(other.mShading)), + mTransparency(std::move(other.mTransparency)), + sTexDiffuse(std::move(other.sTexDiffuse)), + sTexOpacity(std::move(other.sTexOpacity)), + sTexSpecular(std::move(other.sTexSpecular)), + sTexReflective(std::move(other.sTexReflective)), + sTexBump(std::move(other.sTexBump)), + sTexEmissive(std::move(other.sTexEmissive)), + sTexShininess(std::move(other.sTexShininess)), + mBumpHeight(std::move(other.mBumpHeight)), + mEmissive(std::move(other.mEmissive)), + sTexAmbient(std::move(other.sTexAmbient)), + mTwoSided(std::move(other.mTwoSided)) { } - Material &operator=(Material &&other) AI_NO_EXCEPT { if (this == &other) { return *this; @@ -444,9 +495,9 @@ struct Material return *this; } - - virtual ~Material() {} - + virtual ~Material() { + // empty + } //! Name of the material std::string mName; @@ -491,18 +542,15 @@ struct Material // --------------------------------------------------------------------------- /** Helper structure to represent a 3ds file mesh */ -struct Mesh : public MeshWithSmoothingGroups -{ +struct Mesh : public MeshWithSmoothingGroups { //! Default constructor has been deleted Mesh() = delete; //! Constructor with explicit name - explicit Mesh(const std::string &name) - : mName(name) - { + explicit Mesh(const std::string &name) : + mName(name) { } - //! Name of the mesh std::string mName; @@ -519,62 +567,48 @@ struct Mesh : public MeshWithSmoothingGroups // --------------------------------------------------------------------------- /** Float key - quite similar to aiVectorKey and aiQuatKey. Both are in the C-API, so it would be difficult to make them a template. */ -struct aiFloatKey -{ - double mTime; ///< The time of this key - ai_real mValue; ///< The value of this key +struct aiFloatKey { + double mTime; ///< The time of this key + ai_real mValue; ///< The value of this key #ifdef __cplusplus // time is not compared - bool operator == (const aiFloatKey& o) const - {return o.mValue == this->mValue;} + bool operator==(const aiFloatKey &o) const { return o.mValue == this->mValue; } - bool operator != (const aiFloatKey& o) const - {return o.mValue != this->mValue;} + bool operator!=(const aiFloatKey &o) const { return o.mValue != this->mValue; } // Only time is compared. This operator is defined // for use with std::sort - bool operator < (const aiFloatKey& o) const - {return mTime < o.mTime;} + bool operator<(const aiFloatKey &o) const { return mTime < o.mTime; } - bool operator > (const aiFloatKey& o) const - {return mTime > o.mTime;} + bool operator>(const aiFloatKey &o) const { return mTime > o.mTime; } #endif }; // --------------------------------------------------------------------------- /** Helper structure to represent a 3ds file node */ -struct Node -{ +struct Node { Node() = delete; - explicit Node(const std::string &name) - : mParent(NULL) - , mName(name) - , mInstanceNumber(0) - , mHierarchyPos (0) - , mHierarchyIndex (0) - , mInstanceCount (1) - { - aRotationKeys.reserve (20); - aPositionKeys.reserve (20); - aScalingKeys.reserve (20); + explicit Node(const std::string &name) : + mParent(NULL), mName(name), mInstanceNumber(0), mHierarchyPos(0), mHierarchyIndex(0), mInstanceCount(1) { + aRotationKeys.reserve(20); + aPositionKeys.reserve(20); + aScalingKeys.reserve(20); } - - ~Node() - { - for (unsigned int i = 0; i < mChildren.size();++i) + ~Node() { + for (unsigned int i = 0; i < mChildren.size(); ++i) delete mChildren[i]; } //! Pointer to the parent node - Node* mParent; + Node *mParent; //! Holds all child nodes - std::vector mChildren; + std::vector mChildren; //! Name of the node std::string mName; @@ -600,13 +634,12 @@ struct Node //! Scaling keys loaded from the file std::vector aScalingKeys; - // For target lights (spot lights and directional lights): // The position of the target - std::vector< aiVectorKey > aTargetPositionKeys; + std::vector aTargetPositionKeys; // For cameras: the camera roll angle - std::vector< aiFloatKey > aCameraRollKeys; + std::vector aCameraRollKeys; //! Pivot position loaded from the file aiVector3D vPivot; @@ -616,8 +649,7 @@ struct Node //! Add a child node, setup the right parent node for it //! \param pc Node to be 'adopted' - inline Node& push_back(Node* pc) - { + inline Node &push_back(Node *pc) { mChildren.push_back(pc); pc->mParent = this; return *this; @@ -625,8 +657,7 @@ struct Node }; // --------------------------------------------------------------------------- /** Helper structure analogue to aiScene */ -struct Scene -{ +struct Scene { //! List of all materials loaded //! NOTE: 3ds references materials globally std::vector mMaterials; @@ -635,17 +666,16 @@ struct Scene std::vector mMeshes; //! List of all cameras loaded - std::vector mCameras; + std::vector mCameras; //! List of all lights loaded - std::vector mLights; + std::vector mLights; //! Pointer to the root node of the scene // --- moved to main class // Node* pcRootNode; }; - } // end of namespace D3DS } // end of namespace Assimp diff --git a/code/3DS/3DSLoader.cpp b/code/3DS/3DSLoader.cpp index 3e8e08967..0b4a93a2b 100644 --- a/code/3DS/3DSLoader.cpp +++ b/code/3DS/3DSLoader.cpp @@ -158,13 +158,13 @@ void Discreet3DSImporter::SetupProperties(const Importer* /*pImp*/) void Discreet3DSImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) { - StreamReaderLE stream(pIOHandler->Open(pFile,"rb")); + StreamReaderLE theStream(pIOHandler->Open(pFile,"rb")); // We should have at least one chunk - if (stream.GetRemainingSize() < 16) { + if (theStream.GetRemainingSize() < 16) { throw DeadlyImportError("3DS file is either empty or corrupt: " + pFile); } - this->stream = &stream; + this->stream = &theStream; // Allocate our temporary 3DS representation D3DS::Scene _scene; @@ -599,16 +599,19 @@ void Discreet3DSImporter::InverseNodeSearch(D3DS::Node* pcNode,D3DS::Node* pcCur // ------------------------------------------------------------------------------------------------ // Find a node with a specific name in the import hierarchy -D3DS::Node* FindNode(D3DS::Node* root, const std::string& name) -{ - if (root->mName == name) +D3DS::Node* FindNode(D3DS::Node* root, const std::string& name) { + if (root->mName == name) { return root; - for (std::vector::iterator it = root->mChildren.begin();it != root->mChildren.end(); ++it) { - D3DS::Node* nd; - if (( nd = FindNode(*it,name))) - return nd; } - return NULL; + + for (std::vector::iterator it = root->mChildren.begin();it != root->mChildren.end(); ++it) { + D3DS::Node *nd = FindNode(*it, name); + if (nullptr != nd) { + return nd; + } + } + + return nullptr; } // ------------------------------------------------------------------------------------------------ diff --git a/code/3MF/D3MFExporter.cpp b/code/3MF/D3MFExporter.cpp index 9d71a54f2..092b947e9 100644 --- a/code/3MF/D3MFExporter.cpp +++ b/code/3MF/D3MFExporter.cpp @@ -256,13 +256,13 @@ void D3MFExporter::writeBaseMaterials() { tmp.clear(); hexDiffuseColor = "#"; - tmp = DecimalToHexa( color.r ); + tmp = DecimalToHexa( (ai_real) color.r ); hexDiffuseColor += tmp; - tmp = DecimalToHexa( color.g ); + tmp = DecimalToHexa((ai_real)color.g); hexDiffuseColor += tmp; - tmp = DecimalToHexa( color.b ); + tmp = DecimalToHexa((ai_real)color.b); hexDiffuseColor += tmp; - tmp = DecimalToHexa( color.a ); + tmp = DecimalToHexa((ai_real)color.a); hexDiffuseColor += tmp; } else { hexDiffuseColor = "#FFFFFFFF"; diff --git a/code/AC/ACLoader.cpp b/code/AC/ACLoader.cpp index ea533743f..85aee7e3a 100644 --- a/code/AC/ACLoader.cpp +++ b/code/AC/ACLoader.cpp @@ -1,4 +1,3 @@ - /* --------------------------------------------------------------------------- Open Asset Import Library (assimp) @@ -6,8 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2020, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -44,25 +41,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file Implementation of the AC3D importer class */ - - #ifndef ASSIMP_BUILD_NO_AC_IMPORTER // internal headers #include "ACLoader.h" -#include -#include -#include #include "Common/Importer.h" #include -#include +#include +#include +#include +#include +#include #include -#include #include #include -#include +#include #include -#include +#include #include using namespace Assimp; @@ -82,116 +77,112 @@ static const aiImporterDesc desc = { // ------------------------------------------------------------------------------------------------ // skip to the next token -#define AI_AC_SKIP_TO_NEXT_TOKEN() \ - if (!SkipSpaces(&buffer)) \ - { \ - ASSIMP_LOG_ERROR("AC3D: Unexpected EOF/EOL"); \ - continue; \ +inline const char *AcSkipToNextToken(const char *buffer) { + if (!SkipSpaces(&buffer)) { + ASSIMP_LOG_ERROR("AC3D: Unexpected EOF/EOL"); } + return buffer; +} // ------------------------------------------------------------------------------------------------ // read a string (may be enclosed in double quotation marks). buffer must point to " -#define AI_AC_GET_STRING(out) \ - if (*buffer == '\0') { \ - throw DeadlyImportError("AC3D: Unexpected EOF in string"); \ - } \ - ++buffer; \ - const char* sz = buffer; \ - while ('\"' != *buffer) \ - { \ - if (IsLineEnd( *buffer )) \ - { \ - ASSIMP_LOG_ERROR("AC3D: Unexpected EOF/EOL in string"); \ - out = "ERROR"; \ - break; \ - } \ - ++buffer; \ - } \ - if (IsLineEnd( *buffer ))continue; \ - out = std::string(sz,(unsigned int)(buffer-sz)); \ +inline const char *AcGetString(const char *buffer, std::string &out) { + if (*buffer == '\0') { + throw DeadlyImportError("AC3D: Unexpected EOF in string"); + } + ++buffer; + const char *sz = buffer; + while ('\"' != *buffer) { + if (IsLineEnd(*buffer)) { + ASSIMP_LOG_ERROR("AC3D: Unexpected EOF/EOL in string"); + out = "ERROR"; + break; + } + ++buffer; + } + if (IsLineEnd(*buffer)) { + return buffer; + } + out = std::string(sz, (unsigned int)(buffer - sz)); ++buffer; + return buffer; +} // ------------------------------------------------------------------------------------------------ // read 1 to n floats prefixed with an optional predefined identifier -#define AI_AC_CHECKED_LOAD_FLOAT_ARRAY(name,name_length,num,out) \ - AI_AC_SKIP_TO_NEXT_TOKEN(); \ - if (name_length) \ - { \ - if (strncmp(buffer,name,name_length) || !IsSpace(buffer[name_length])) \ - { \ - ASSIMP_LOG_ERROR("AC3D: Unexpexted token. " name " was expected."); \ - continue; \ - } \ - buffer += name_length+1; \ - } \ - for (unsigned int i = 0; i < num;++i) \ - { \ - AI_AC_SKIP_TO_NEXT_TOKEN(); \ - buffer = fast_atoreal_move(buffer,((float*)out)[i]); \ +template +inline const char *TAcCheckedLoadFloatArray(const char *buffer, const char *name, size_t name_length, size_t num, T *out) { + buffer = AcSkipToNextToken(buffer); + if (0 != name_length) { + if (0 != strncmp(buffer, name, name_length) || !IsSpace(buffer[name_length])) { + ASSIMP_LOG_ERROR("AC3D: Unexpexted token. " + std::string(name) + " was expected."); + return buffer; + } + buffer += name_length + 1; + } + for (unsigned int _i = 0; _i < num; ++_i) { + buffer = AcSkipToNextToken(buffer); + buffer = fast_atoreal_move(buffer, ((float *)out)[_i]); } + return buffer; +} // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer -AC3DImporter::AC3DImporter() - : buffer(), - configSplitBFCull(), - configEvalSubdivision(), - mNumMeshes(), - mLights(), - lights(), - groups(), - polys(), - worlds() -{ +AC3DImporter::AC3DImporter() : + buffer(), + configSplitBFCull(), + configEvalSubdivision(), + mNumMeshes(), + mLights(), + mLightsCounter(0), + mGroupsCounter(0), + mPolysCounter(0), + mWorldsCounter(0) { // nothing to be done here } // ------------------------------------------------------------------------------------------------ // Destructor, private as well -AC3DImporter::~AC3DImporter() -{ +AC3DImporter::~AC3DImporter() { // nothing to be done here } // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. -bool AC3DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const -{ +bool AC3DImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const { std::string extension = GetExtension(pFile); // fixme: are acc and ac3d *really* used? Some sources say they are - if(extension == "ac" || extension == "ac3d" || extension == "acc") { + if (extension == "ac" || extension == "ac3d" || extension == "acc") { return true; } if (!extension.length() || checkSig) { uint32_t token = AI_MAKE_MAGIC("AC3D"); - return CheckMagicToken(pIOHandler,pFile,&token,1,0); + return CheckMagicToken(pIOHandler, pFile, &token, 1, 0); } return false; } // ------------------------------------------------------------------------------------------------ // Loader meta information -const aiImporterDesc* AC3DImporter::GetInfo () const -{ +const aiImporterDesc *AC3DImporter::GetInfo() const { return &desc; } // ------------------------------------------------------------------------------------------------ // Get a pointer to the next line from the file -bool AC3DImporter::GetNextLine( ) -{ +bool AC3DImporter::GetNextLine() { SkipLine(&buffer); return SkipSpaces(&buffer); } // ------------------------------------------------------------------------------------------------ // Parse an object section in an AC file -void AC3DImporter::LoadObjectSection(std::vector& objects) -{ - if (!TokenMatch(buffer,"OBJECT",6)) +void AC3DImporter::LoadObjectSection(std::vector &objects) { + if (!TokenMatch(buffer, "OBJECT", 6)) return; SkipSpaces(&buffer); @@ -199,145 +190,109 @@ void AC3DImporter::LoadObjectSection(std::vector& objects) ++mNumMeshes; objects.push_back(Object()); - Object& obj = objects.back(); + Object &obj = objects.back(); - aiLight* light = NULL; - if (!ASSIMP_strincmp(buffer,"light",5)) - { + aiLight *light = NULL; + if (!ASSIMP_strincmp(buffer, "light", 5)) { // This is a light source. Add it to the list mLights->push_back(light = new aiLight()); // Return a point light with no attenuation light->mType = aiLightSource_POINT; - light->mColorDiffuse = light->mColorSpecular = aiColor3D(1.f,1.f,1.f); + light->mColorDiffuse = light->mColorSpecular = aiColor3D(1.f, 1.f, 1.f); light->mAttenuationConstant = 1.f; // Generate a default name for both the light source and the node // FIXME - what's the right way to print a size_t? Is 'zu' universally available? stick with the safe version. - light->mName.length = ::ai_snprintf(light->mName.data, MAXLEN, "ACLight_%i",static_cast(mLights->size())-1); - obj.name = std::string( light->mName.data ); + light->mName.length = ::ai_snprintf(light->mName.data, MAXLEN, "ACLight_%i", static_cast(mLights->size()) - 1); + obj.name = std::string(light->mName.data); ASSIMP_LOG_DEBUG("AC3D: Light source encountered"); obj.type = Object::Light; - } - else if (!ASSIMP_strincmp(buffer,"group",5)) - { + } else if (!ASSIMP_strincmp(buffer, "group", 5)) { obj.type = Object::Group; - } - else if (!ASSIMP_strincmp(buffer,"world",5)) - { + } else if (!ASSIMP_strincmp(buffer, "world", 5)) { obj.type = Object::World; - } - else obj.type = Object::Poly; - while (GetNextLine()) - { - if (TokenMatch(buffer,"kids",4)) - { + } else + obj.type = Object::Poly; + while (GetNextLine()) { + if (TokenMatch(buffer, "kids", 4)) { SkipSpaces(&buffer); - unsigned int num = strtoul10(buffer,&buffer); + unsigned int num = strtoul10(buffer, &buffer); GetNextLine(); - if (num) - { + if (num) { // load the children of this object recursively obj.children.reserve(num); for (unsigned int i = 0; i < num; ++i) LoadObjectSection(obj.children); } return; - } - else if (TokenMatch(buffer,"name",4)) - { + } else if (TokenMatch(buffer, "name", 4)) { SkipSpaces(&buffer); - AI_AC_GET_STRING(obj.name); + buffer = AcGetString(buffer, obj.name); // If this is a light source, we'll also need to store // the name of the node in it. - if (light) - { + if (light) { light->mName.Set(obj.name); } - } - else if (TokenMatch(buffer,"texture",7)) - { + } else if (TokenMatch(buffer, "texture", 7)) { SkipSpaces(&buffer); - AI_AC_GET_STRING(obj.texture); - } - else if (TokenMatch(buffer,"texrep",6)) - { + buffer = AcGetString(buffer, obj.texture); + } else if (TokenMatch(buffer, "texrep", 6)) { SkipSpaces(&buffer); - AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,2,&obj.texRepeat); + buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 2, &obj.texRepeat); if (!obj.texRepeat.x || !obj.texRepeat.y) - obj.texRepeat = aiVector2D (1.f,1.f); - } - else if (TokenMatch(buffer,"texoff",6)) - { + obj.texRepeat = aiVector2D(1.f, 1.f); + } else if (TokenMatch(buffer, "texoff", 6)) { SkipSpaces(&buffer); - AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,2,&obj.texOffset); - } - else if (TokenMatch(buffer,"rot",3)) - { + buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 2, &obj.texOffset); + } else if (TokenMatch(buffer, "rot", 3)) { SkipSpaces(&buffer); - AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,9,&obj.rotation); - } - else if (TokenMatch(buffer,"loc",3)) - { + buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 9, &obj.rotation); + } else if (TokenMatch(buffer, "loc", 3)) { SkipSpaces(&buffer); - AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,3,&obj.translation); - } - else if (TokenMatch(buffer,"subdiv",6)) - { + buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 3, &obj.translation); + } else if (TokenMatch(buffer, "subdiv", 6)) { SkipSpaces(&buffer); - obj.subDiv = strtoul10(buffer,&buffer); - } - else if (TokenMatch(buffer,"crease",6)) - { + obj.subDiv = strtoul10(buffer, &buffer); + } else if (TokenMatch(buffer, "crease", 6)) { SkipSpaces(&buffer); obj.crease = fast_atof(buffer); - } - else if (TokenMatch(buffer,"numvert",7)) - { + } else if (TokenMatch(buffer, "numvert", 7)) { SkipSpaces(&buffer); - unsigned int t = strtoul10(buffer,&buffer); + unsigned int t = strtoul10(buffer, &buffer); if (t >= AI_MAX_ALLOC(aiVector3D)) { throw DeadlyImportError("AC3D: Too many vertices, would run out of memory"); } obj.vertices.reserve(t); - for (unsigned int i = 0; i < t;++i) - { - if (!GetNextLine()) - { + for (unsigned int i = 0; i < t; ++i) { + if (!GetNextLine()) { ASSIMP_LOG_ERROR("AC3D: Unexpected EOF: not all vertices have been parsed yet"); break; - } - else if (!IsNumeric(*buffer)) - { + } else if (!IsNumeric(*buffer)) { ASSIMP_LOG_ERROR("AC3D: Unexpected token: not all vertices have been parsed yet"); --buffer; // make sure the line is processed a second time break; } obj.vertices.push_back(aiVector3D()); - aiVector3D& v = obj.vertices.back(); - AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,3,&v.x); + aiVector3D &v = obj.vertices.back(); + buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 3, &v.x); } - } - else if (TokenMatch(buffer,"numsurf",7)) - { + } else if (TokenMatch(buffer, "numsurf", 7)) { SkipSpaces(&buffer); bool Q3DWorkAround = false; - const unsigned int t = strtoul10(buffer,&buffer); + const unsigned int t = strtoul10(buffer, &buffer); obj.surfaces.reserve(t); - for (unsigned int i = 0; i < t;++i) - { + for (unsigned int i = 0; i < t; ++i) { GetNextLine(); - if (!TokenMatch(buffer,"SURF",4)) - { + if (!TokenMatch(buffer, "SURF", 4)) { // FIX: this can occur for some files - Quick 3D for // example writes no surf chunks - if (!Q3DWorkAround) - { + if (!Q3DWorkAround) { ASSIMP_LOG_WARN("AC3D: SURF token was expected"); ASSIMP_LOG_DEBUG("Continuing with Quick3D Workaround enabled"); } @@ -348,27 +303,20 @@ void AC3DImporter::LoadObjectSection(std::vector& objects) } SkipSpaces(&buffer); obj.surfaces.push_back(Surface()); - Surface& surf = obj.surfaces.back(); + Surface &surf = obj.surfaces.back(); surf.flags = strtoul_cppstyle(buffer); - while (1) - { - if(!GetNextLine()) - { + while (1) { + if (!GetNextLine()) { throw DeadlyImportError("AC3D: Unexpected EOF: surface is incomplete"); } - if (TokenMatch(buffer,"mat",3)) - { + if (TokenMatch(buffer, "mat", 3)) { SkipSpaces(&buffer); surf.mat = strtoul10(buffer); - } - else if (TokenMatch(buffer,"refs",4)) - { + } else if (TokenMatch(buffer, "refs", 4)) { // --- see fix notes above - if (Q3DWorkAround) - { - if (!surf.entries.empty()) - { + if (Q3DWorkAround) { + if (!surf.entries.empty()) { buffer -= 6; break; } @@ -380,24 +328,19 @@ void AC3DImporter::LoadObjectSection(std::vector& objects) obj.numRefs += m; - for (unsigned int k = 0; k < m; ++k) - { - if(!GetNextLine()) - { + for (unsigned int k = 0; k < m; ++k) { + if (!GetNextLine()) { ASSIMP_LOG_ERROR("AC3D: Unexpected EOF: surface references are incomplete"); break; } surf.entries.push_back(Surface::SurfaceEntry()); - Surface::SurfaceEntry& entry = surf.entries.back(); + Surface::SurfaceEntry &entry = surf.entries.back(); - entry.first = strtoul10(buffer,&buffer); + entry.first = strtoul10(buffer, &buffer); SkipSpaces(&buffer); - AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,2,&entry.second); + buffer = TAcCheckedLoadFloatArray(buffer, "", 0, 2, &entry.second); } - } - else - { - + } else { --buffer; // make sure the line is processed a second time break; } @@ -410,65 +353,58 @@ void AC3DImporter::LoadObjectSection(std::vector& objects) // ------------------------------------------------------------------------------------------------ // Convert a material from AC3DImporter::Material to aiMaterial -void AC3DImporter::ConvertMaterial(const Object& object, - const Material& matSrc, - aiMaterial& matDest) -{ +void AC3DImporter::ConvertMaterial(const Object &object, + const Material &matSrc, + aiMaterial &matDest) { aiString s; - if (matSrc.name.length()) - { + if (matSrc.name.length()) { s.Set(matSrc.name); - matDest.AddProperty(&s,AI_MATKEY_NAME); + matDest.AddProperty(&s, AI_MATKEY_NAME); } - if (object.texture.length()) - { + if (object.texture.length()) { s.Set(object.texture); - matDest.AddProperty(&s,AI_MATKEY_TEXTURE_DIFFUSE(0)); + matDest.AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(0)); // UV transformation if (1.f != object.texRepeat.x || 1.f != object.texRepeat.y || - object.texOffset.x || object.texOffset.y) - { + object.texOffset.x || object.texOffset.y) { aiUVTransform transform; transform.mScaling = object.texRepeat; transform.mTranslation = object.texOffset; - matDest.AddProperty(&transform,1,AI_MATKEY_UVTRANSFORM_DIFFUSE(0)); + matDest.AddProperty(&transform, 1, AI_MATKEY_UVTRANSFORM_DIFFUSE(0)); } } - matDest.AddProperty(&matSrc.rgb,1, AI_MATKEY_COLOR_DIFFUSE); - matDest.AddProperty(&matSrc.amb,1, AI_MATKEY_COLOR_AMBIENT); - matDest.AddProperty(&matSrc.emis,1,AI_MATKEY_COLOR_EMISSIVE); - matDest.AddProperty(&matSrc.spec,1,AI_MATKEY_COLOR_SPECULAR); + matDest.AddProperty(&matSrc.rgb, 1, AI_MATKEY_COLOR_DIFFUSE); + matDest.AddProperty(&matSrc.amb, 1, AI_MATKEY_COLOR_AMBIENT); + matDest.AddProperty(&matSrc.emis, 1, AI_MATKEY_COLOR_EMISSIVE); + matDest.AddProperty(&matSrc.spec, 1, AI_MATKEY_COLOR_SPECULAR); - int n; - if (matSrc.shin) - { + int n = -1; + if (matSrc.shin) { n = aiShadingMode_Phong; - matDest.AddProperty(&matSrc.shin,1,AI_MATKEY_SHININESS); + matDest.AddProperty(&matSrc.shin, 1, AI_MATKEY_SHININESS); + } else { + n = aiShadingMode_Gouraud; } - else n = aiShadingMode_Gouraud; - matDest.AddProperty(&n,1,AI_MATKEY_SHADING_MODEL); + matDest.AddProperty(&n, 1, AI_MATKEY_SHADING_MODEL); float f = 1.f - matSrc.trans; - matDest.AddProperty(&f,1,AI_MATKEY_OPACITY); + matDest.AddProperty(&f, 1, AI_MATKEY_OPACITY); } // ------------------------------------------------------------------------------------------------ // Converts the loaded data to the internal verbose representation -aiNode* AC3DImporter::ConvertObjectSection(Object& object, - std::vector& meshes, - std::vector& outMaterials, - const std::vector& materials, - aiNode* parent) -{ - aiNode* node = new aiNode(); +aiNode *AC3DImporter::ConvertObjectSection(Object &object, + std::vector &meshes, + std::vector &outMaterials, + const std::vector &materials, + aiNode *parent) { + aiNode *node = new aiNode(); node->mParent = parent; - if (object.vertices.size()) - { - if (!object.surfaces.size() || !object.numRefs) - { + if (object.vertices.size()) { + if (!object.surfaces.size() || !object.numRefs) { /* " An object with 7 vertices (no surfaces, no materials defined). This is a good way of getting point data into AC3D. The Vertex->create convex-surface/object can be used on these @@ -479,17 +415,16 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object, */ ASSIMP_LOG_INFO("AC3D: No surfaces defined in object definition, " - "a point list is returned"); + "a point list is returned"); meshes.push_back(new aiMesh()); - aiMesh* mesh = meshes.back(); + aiMesh *mesh = meshes.back(); mesh->mNumFaces = mesh->mNumVertices = (unsigned int)object.vertices.size(); - aiFace* faces = mesh->mFaces = new aiFace[mesh->mNumFaces]; - aiVector3D* verts = mesh->mVertices = new aiVector3D[mesh->mNumVertices]; + aiFace *faces = mesh->mFaces = new aiFace[mesh->mNumFaces]; + aiVector3D *verts = mesh->mVertices = new aiVector3D[mesh->mNumVertices]; - for (unsigned int i = 0; i < mesh->mNumVertices;++i,++faces,++verts) - { + for (unsigned int i = 0; i < mesh->mNumVertices; ++i, ++faces, ++verts) { *verts = object.vertices[i]; faces->mNumIndices = 1; faces->mIndices = new unsigned int[1]; @@ -502,89 +437,81 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object, mesh->mMaterialIndex = 0; outMaterials.push_back(new aiMaterial()); ConvertMaterial(object, materials[0], *outMaterials.back()); - } - else - { + } else { // need to generate one or more meshes for this object. // find out how many different materials we have - typedef std::pair< unsigned int, unsigned int > IntPair; - typedef std::vector< IntPair > MatTable; - MatTable needMat(materials.size(),IntPair(0,0)); + typedef std::pair IntPair; + typedef std::vector MatTable; + MatTable needMat(materials.size(), IntPair(0, 0)); - std::vector::iterator it,end = object.surfaces.end(); - std::vector::iterator it2,end2; + std::vector::iterator it, end = object.surfaces.end(); + std::vector::iterator it2, end2; - for (it = object.surfaces.begin(); it != end; ++it) - { + for (it = object.surfaces.begin(); it != end; ++it) { unsigned int idx = (*it).mat; - if (idx >= needMat.size()) - { + if (idx >= needMat.size()) { ASSIMP_LOG_ERROR("AC3D: material index is out of range"); idx = 0; } - if ((*it).entries.empty()) - { + if ((*it).entries.empty()) { ASSIMP_LOG_WARN("AC3D: surface her zero vertex references"); } // validate all vertex indices to make sure we won't crash here - for (it2 = (*it).entries.begin(), - end2 = (*it).entries.end(); it2 != end2; ++it2) - { - if ((*it2).first >= object.vertices.size()) - { + for (it2 = (*it).entries.begin(), + end2 = (*it).entries.end(); + it2 != end2; ++it2) { + if ((*it2).first >= object.vertices.size()) { ASSIMP_LOG_WARN("AC3D: Invalid vertex reference"); (*it2).first = 0; } } - if (!needMat[idx].first)++node->mNumMeshes; + if (!needMat[idx].first) { + ++node->mNumMeshes; + } - switch ((*it).flags & 0xf) - { - // closed line - case 0x1: + switch ((*it).flags & 0xf) { + // closed line + case 0x1: + needMat[idx].first += (unsigned int)(*it).entries.size(); + needMat[idx].second += (unsigned int)(*it).entries.size() << 1u; + break; - needMat[idx].first += (unsigned int)(*it).entries.size(); - needMat[idx].second += (unsigned int)(*it).entries.size()<<1u; - break; + // unclosed line + case 0x2: + needMat[idx].first += (unsigned int)(*it).entries.size() - 1; + needMat[idx].second += ((unsigned int)(*it).entries.size() - 1) << 1u; + break; - // unclosed line - case 0x2: + // 0 == polygon, else unknown + default: + if ((*it).flags & 0xf) { + ASSIMP_LOG_WARN("AC3D: The type flag of a surface is unknown"); + (*it).flags &= ~(0xf); + } - needMat[idx].first += (unsigned int)(*it).entries.size()-1; - needMat[idx].second += ((unsigned int)(*it).entries.size()-1)<<1u; - break; - - // 0 == polygon, else unknown - default: - - if ((*it).flags & 0xf) - { - ASSIMP_LOG_WARN("AC3D: The type flag of a surface is unknown"); - (*it).flags &= ~(0xf); - } - - // the number of faces increments by one, the number - // of vertices by surface.numref. - needMat[idx].first++; - needMat[idx].second += (unsigned int)(*it).entries.size(); + // the number of faces increments by one, the number + // of vertices by surface.numref. + needMat[idx].first++; + needMat[idx].second += (unsigned int)(*it).entries.size(); }; } - unsigned int* pip = node->mMeshes = new unsigned int[node->mNumMeshes]; + unsigned int *pip = node->mMeshes = new unsigned int[node->mNumMeshes]; unsigned int mat = 0; const size_t oldm = meshes.size(); for (MatTable::const_iterator cit = needMat.begin(), cend = needMat.end(); - cit != cend; ++cit, ++mat) - { - if (!(*cit).first)continue; + cit != cend; ++cit, ++mat) { + if (!(*cit).first) { + continue; + } // allocate a new aiMesh object *pip++ = (unsigned int)meshes.size(); - aiMesh* mesh = new aiMesh(); + aiMesh *mesh = new aiMesh(); meshes.push_back(mesh); - mesh->mMaterialIndex = (unsigned int)outMaterials.size(); + mesh->mMaterialIndex = static_cast(outMaterials.size()); outMaterials.push_back(new aiMaterial()); ConvertMaterial(object, materials[mat], *outMaterials.back()); @@ -595,7 +522,7 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object, } else if (mesh->mNumFaces > AI_MAX_ALLOC(aiFace)) { throw DeadlyImportError("AC3D: Too many faces, would run out of memory"); } - aiFace* faces = mesh->mFaces = new aiFace[mesh->mNumFaces]; + aiFace *faces = mesh->mFaces = new aiFace[mesh->mNumFaces]; mesh->mNumVertices = (*cit).second; if (mesh->mNumVertices == 0) { @@ -603,35 +530,30 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object, } else if (mesh->mNumVertices > AI_MAX_ALLOC(aiVector3D)) { throw DeadlyImportError("AC3D: Too many vertices, would run out of memory"); } - aiVector3D* vertices = mesh->mVertices = new aiVector3D[mesh->mNumVertices]; + aiVector3D *vertices = mesh->mVertices = new aiVector3D[mesh->mNumVertices]; unsigned int cur = 0; // allocate UV coordinates, but only if the texture name for the // surface is not empty - aiVector3D* uv = NULL; - if(object.texture.length()) - { + aiVector3D *uv = NULL; + if (object.texture.length()) { uv = mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices]; mesh->mNumUVComponents[0] = 2; } - for (it = object.surfaces.begin(); it != end; ++it) - { - if (mat == (*it).mat) - { - const Surface& src = *it; + for (it = object.surfaces.begin(); it != end; ++it) { + if (mat == (*it).mat) { + const Surface &src = *it; // closed polygon unsigned int type = (*it).flags & 0xf; - if (!type) - { - aiFace& face = *faces++; - if((face.mNumIndices = (unsigned int)src.entries.size())) - { + if (!type) { + aiFace &face = *faces++; + face.mNumIndices = (unsigned int)src.entries.size(); + if (0 != face.mNumIndices) { face.mIndices = new unsigned int[face.mNumIndices]; - for (unsigned int i = 0; i < face.mNumIndices;++i,++vertices) - { - const Surface::SurfaceEntry& entry = src.entries[i]; + for (unsigned int i = 0; i < face.mNumIndices; ++i, ++vertices) { + const Surface::SurfaceEntry &entry = src.entries[i]; face.mIndices[i] = cur++; // copy vertex positions @@ -640,28 +562,23 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object, } *vertices = object.vertices[entry.first] + object.translation; - // copy texture coordinates - if (uv) - { - uv->x = entry.second.x; - uv->y = entry.second.y; + if (uv) { + uv->x = entry.second.x; + uv->y = entry.second.y; ++uv; } } } - } - else - { + } else { - it2 = (*it).entries.begin(); + it2 = (*it).entries.begin(); // either a closed or an unclosed line unsigned int tmp = (unsigned int)(*it).entries.size(); - if (0x2 == type)--tmp; - for (unsigned int m = 0; m < tmp;++m) - { - aiFace& face = *faces++; + if (0x2 == type) --tmp; + for (unsigned int m = 0; m < tmp; ++m) { + aiFace &face = *faces++; face.mNumIndices = 2; face.mIndices = new unsigned int[2]; @@ -669,35 +586,31 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object, face.mIndices[1] = cur++; // copy vertex positions - if (it2 == (*it).entries.end() ) { + if (it2 == (*it).entries.end()) { throw DeadlyImportError("AC3D: Bad line"); } ai_assert((*it2).first < object.vertices.size()); *vertices++ = object.vertices[(*it2).first]; // copy texture coordinates - if (uv) - { - uv->x = (*it2).second.x; - uv->y = (*it2).second.y; + if (uv) { + uv->x = (*it2).second.x; + uv->y = (*it2).second.y; ++uv; } - - if (0x1 == type && tmp-1 == m) - { + if (0x1 == type && tmp - 1 == m) { // if this is a closed line repeat its beginning now - it2 = (*it).entries.begin(); - } - else ++it2; + it2 = (*it).entries.begin(); + } else + ++it2; // second point *vertices++ = object.vertices[(*it2).first]; - if (uv) - { - uv->x = (*it2).second.x; - uv->y = (*it2).second.y; + if (uv) { + uv->x = (*it2).second.x; + uv->y = (*it2).second.y; ++uv; } } @@ -709,20 +622,18 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object, // Now apply catmull clark subdivision if necessary. We split meshes into // materials which is not done by AC3D during smoothing, so we need to // collect all meshes using the same material group. - if (object.subDiv) { + if (object.subDiv) { if (configEvalSubdivision) { std::unique_ptr div(Subdivider::Create(Subdivider::CATMULL_CLARKE)); - ASSIMP_LOG_INFO("AC3D: Evaluating subdivision surface: "+object.name); + ASSIMP_LOG_INFO("AC3D: Evaluating subdivision surface: " + object.name); - std::vector cpy(meshes.size()-oldm,NULL); - div->Subdivide(&meshes[oldm],cpy.size(),&cpy.front(),object.subDiv,true); - std::copy(cpy.begin(),cpy.end(),meshes.begin()+oldm); + std::vector cpy(meshes.size() - oldm, NULL); + div->Subdivide(&meshes[oldm], cpy.size(), &cpy.front(), object.subDiv, true); + std::copy(cpy.begin(), cpy.end(), meshes.begin() + oldm); // previous meshes are deleted vy Subdivide(). - } - else { - ASSIMP_LOG_INFO("AC3D: Letting the subdivision surface untouched due to my configuration: " - +object.name); + } else { + ASSIMP_LOG_INFO("AC3D: Letting the subdivision surface untouched due to my configuration: " + object.name); } } } @@ -730,48 +641,42 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object, if (object.name.length()) node->mName.Set(object.name); - else - { + else { // generate a name depending on the type of the node - switch (object.type) - { - case Object::Group: - node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACGroup_%i",groups++); - break; - case Object::Poly: - node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACPoly_%i",polys++); - break; - case Object::Light: - node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACLight_%i",lights++); - break; + switch (object.type) { + case Object::Group: + node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACGroup_%i", mGroupsCounter++); + break; + case Object::Poly: + node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACPoly_%i", mPolysCounter++); + break; + case Object::Light: + node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACLight_%i", mLightsCounter++); + break; - // there shouldn't be more than one world, but we don't care - case Object::World: - node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACWorld_%i",worlds++); - break; + // there shouldn't be more than one world, but we don't care + case Object::World: + node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACWorld_%i", mWorldsCounter++); + break; } } - // setup the local transformation matrix of the object // compute the transformation offset to the parent node - node->mTransformation = aiMatrix4x4 ( object.rotation ); + node->mTransformation = aiMatrix4x4(object.rotation); - if (object.type == Object::Group || !object.numRefs) - { + if (object.type == Object::Group || !object.numRefs) { node->mTransformation.a4 = object.translation.x; node->mTransformation.b4 = object.translation.y; node->mTransformation.c4 = object.translation.z; } // add children to the object - if (object.children.size()) - { + if (object.children.size()) { node->mNumChildren = (unsigned int)object.children.size(); - node->mChildren = new aiNode*[node->mNumChildren]; - for (unsigned int i = 0; i < node->mNumChildren;++i) - { - node->mChildren[i] = ConvertObjectSection(object.children[i],meshes,outMaterials,materials,node); + node->mChildren = new aiNode *[node->mNumChildren]; + for (unsigned int i = 0; i < node->mNumChildren; ++i) { + node->mChildren[i] = ConvertObjectSection(object.children[i], meshes, outMaterials, materials, node); } } @@ -779,40 +684,39 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object, } // ------------------------------------------------------------------------------------------------ -void AC3DImporter::SetupProperties(const Importer* pImp) -{ - configSplitBFCull = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_AC_SEPARATE_BFCULL,1) ? true : false; - configEvalSubdivision = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_AC_EVAL_SUBDIVISION,1) ? true : false; +void AC3DImporter::SetupProperties(const Importer *pImp) { + configSplitBFCull = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_AC_SEPARATE_BFCULL, 1) ? true : false; + configEvalSubdivision = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_AC_EVAL_SUBDIVISION, 1) ? true : false; } // ------------------------------------------------------------------------------------------------ // Imports the given file into the given scene structure. -void AC3DImporter::InternReadFile( const std::string& pFile, - aiScene* pScene, IOSystem* pIOHandler) -{ - std::unique_ptr file( pIOHandler->Open( pFile, "rb")); +void AC3DImporter::InternReadFile(const std::string &pFile, + aiScene *pScene, IOSystem *pIOHandler) { + std::unique_ptr file(pIOHandler->Open(pFile, "rb")); // Check whether we can read from the file - if( file.get() == NULL) - throw DeadlyImportError( "Failed to open AC3D file " + pFile + "."); + if ( file.get() == nullptr ) { + throw DeadlyImportError("Failed to open AC3D file " + pFile + "."); + } // allocate storage and copy the contents of the file to a memory buffer std::vector mBuffer2; - TextFileToBuffer(file.get(),mBuffer2); + TextFileToBuffer(file.get(), mBuffer2); buffer = &mBuffer2[0]; mNumMeshes = 0; - lights = polys = worlds = groups = 0; + mLightsCounter = mPolysCounter = mWorldsCounter = mGroupsCounter = 0; - if (::strncmp(buffer,"AC3D",4)) { + if (::strncmp(buffer, "AC3D", 4)) { throw DeadlyImportError("AC3D: No valid AC3D file, magic sequence not found"); } // print the file format version to the console - unsigned int version = HexDigitToDecimal( buffer[4] ); + unsigned int version = HexDigitToDecimal(buffer[4]); char msg[3]; - ASSIMP_itoa10(msg,3,version); + ASSIMP_itoa10(msg, 3, version); ASSIMP_LOG_INFO_F("AC3D file format version: ", msg); std::vector materials; @@ -821,89 +725,84 @@ void AC3DImporter::InternReadFile( const std::string& pFile, std::vector rootObjects; rootObjects.reserve(5); - std::vector lights; - mLights = & lights; + std::vector lights; + mLights = &lights; - while (GetNextLine()) - { - if (TokenMatch(buffer,"MATERIAL",8)) - { + while (GetNextLine()) { + if (TokenMatch(buffer, "MATERIAL", 8)) { materials.push_back(Material()); - Material& mat = materials.back(); + Material &mat = materials.back(); // manually parse the material ... sscanf would use the buldin atof ... // Format: (name) rgb %f %f %f amb %f %f %f emis %f %f %f spec %f %f %f shi %d trans %f - AI_AC_SKIP_TO_NEXT_TOKEN(); - if ('\"' == *buffer) - { - AI_AC_GET_STRING(mat.name); - AI_AC_SKIP_TO_NEXT_TOKEN(); + buffer = AcSkipToNextToken(buffer); + if ('\"' == *buffer) { + buffer = AcGetString(buffer, mat.name); + buffer = AcSkipToNextToken(buffer); } - AI_AC_CHECKED_LOAD_FLOAT_ARRAY("rgb",3,3,&mat.rgb); - AI_AC_CHECKED_LOAD_FLOAT_ARRAY("amb",3,3,&mat.amb); - AI_AC_CHECKED_LOAD_FLOAT_ARRAY("emis",4,3,&mat.emis); - AI_AC_CHECKED_LOAD_FLOAT_ARRAY("spec",4,3,&mat.spec); - AI_AC_CHECKED_LOAD_FLOAT_ARRAY("shi",3,1,&mat.shin); - AI_AC_CHECKED_LOAD_FLOAT_ARRAY("trans",5,1,&mat.trans); + buffer = TAcCheckedLoadFloatArray(buffer, "rgb", 3, 3, &mat.rgb); + buffer = TAcCheckedLoadFloatArray(buffer, "amb", 3, 3, &mat.amb); + buffer = TAcCheckedLoadFloatArray(buffer, "emis", 4, 3, &mat.emis); + buffer = TAcCheckedLoadFloatArray(buffer, "spec", 4, 3, &mat.spec); + buffer = TAcCheckedLoadFloatArray(buffer, "shi", 3, 1, &mat.shin); + buffer = TAcCheckedLoadFloatArray(buffer, "trans", 5, 1, &mat.trans); } LoadObjectSection(rootObjects); } - if (rootObjects.empty() || !mNumMeshes) - { + if (rootObjects.empty() || !mNumMeshes) { throw DeadlyImportError("AC3D: No meshes have been loaded"); } - if (materials.empty()) - { + if (materials.empty()) { ASSIMP_LOG_WARN("AC3D: No material has been found"); materials.push_back(Material()); } - mNumMeshes += (mNumMeshes>>2u) + 1; - std::vector meshes; + mNumMeshes += (mNumMeshes >> 2u) + 1; + std::vector meshes; meshes.reserve(mNumMeshes); - std::vector omaterials; + std::vector omaterials; materials.reserve(mNumMeshes); // generate a dummy root if there are multiple objects on the top layer - Object* root; + Object *root; if (1 == rootObjects.size()) root = &rootObjects[0]; - else - { + else { root = new Object(); } // now convert the imported stuff to our output data structure - pScene->mRootNode = ConvertObjectSection(*root,meshes,omaterials,materials); - if (1 != rootObjects.size())delete root; + pScene->mRootNode = ConvertObjectSection(*root, meshes, omaterials, materials); + if (1 != rootObjects.size()) { + delete root; + } - if (!::strncmp( pScene->mRootNode->mName.data, "Node", 4)) + if (!::strncmp(pScene->mRootNode->mName.data, "Node", 4)) { pScene->mRootNode->mName.Set(""); + } // copy meshes - if (meshes.empty()) - { + if (meshes.empty()) { throw DeadlyImportError("An unknown error occurred during converting"); } pScene->mNumMeshes = (unsigned int)meshes.size(); - pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; - ::memcpy(pScene->mMeshes,&meshes[0],pScene->mNumMeshes*sizeof(void*)); + pScene->mMeshes = new aiMesh *[pScene->mNumMeshes]; + ::memcpy(pScene->mMeshes, &meshes[0], pScene->mNumMeshes * sizeof(void *)); // copy materials pScene->mNumMaterials = (unsigned int)omaterials.size(); - pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials]; - ::memcpy(pScene->mMaterials,&omaterials[0],pScene->mNumMaterials*sizeof(void*)); + pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials]; + ::memcpy(pScene->mMaterials, &omaterials[0], pScene->mNumMaterials * sizeof(void *)); // copy lights pScene->mNumLights = (unsigned int)lights.size(); - if (lights.size()) - { - pScene->mLights = new aiLight*[lights.size()]; - ::memcpy(pScene->mLights,&lights[0],lights.size()*sizeof(void*)); + if (lights.size()) { + pScene->mLights = new aiLight *[lights.size()]; + ::memcpy(pScene->mLights, &lights[0], lights.size() * sizeof(void *)); } } diff --git a/code/AC/ACLoader.h b/code/AC/ACLoader.h index 1fc654f3c..b32cc7ee3 100644 --- a/code/AC/ACLoader.h +++ b/code/AC/ACLoader.h @@ -68,8 +68,6 @@ public: AC3DImporter(); ~AC3DImporter(); - - // Represents an AC3D material struct Material { @@ -245,8 +243,6 @@ private: aiMaterial& matDest); private: - - // points to the next data line const char* buffer; @@ -268,7 +264,7 @@ private: std::vector* mLights; // name counters - unsigned int lights, groups, polys, worlds; + unsigned int mLightsCounter, mGroupsCounter, mPolysCounter, mWorldsCounter; }; } // end of namespace Assimp diff --git a/code/AMF/AMFImporter_Postprocess.cpp b/code/AMF/AMFImporter_Postprocess.cpp index 8496d8ded..273b8e0c4 100644 --- a/code/AMF/AMFImporter_Postprocess.cpp +++ b/code/AMF/AMFImporter_Postprocess.cpp @@ -465,7 +465,7 @@ std::list mesh_idx; { auto VertexIndex_GetMinimal = [](const std::list& pFaceList, const size_t* pBiggerThan) -> size_t { - size_t rv; + size_t rv=0; if(pBiggerThan != nullptr) { diff --git a/code/ASE/ASEParser.h b/code/ASE/ASEParser.h index e55949f99..aba37d38f 100644 --- a/code/ASE/ASEParser.h +++ b/code/ASE/ASEParser.h @@ -80,7 +80,18 @@ struct Material : public D3DS::Material } Material(const Material &other) = default; - Material &operator=(const Material &other) = default; + + Material &operator=(const Material &other) { + if (this == &other) { + return *this; + } + + avSubMaterials = other.avSubMaterials; + pcInstance = other.pcInstance; + bNeed = other.bNeed; + + return *this; + } //! Move constructor. This is explicitly written because MSVC doesn't support defaulting it @@ -94,12 +105,12 @@ struct Material : public D3DS::Material } - Material &operator=(Material &&other) AI_NO_EXCEPT { + Material &operator=( Material &&other) AI_NO_EXCEPT { if (this == &other) { return *this; } - D3DS::Material::operator=(std::move(other)); + //D3DS::Material::operator=(std::move(other)); avSubMaterials = std::move(other.avSubMaterials); pcInstance = std::move(other.pcInstance); diff --git a/code/Assbin/AssbinExporter.cpp b/code/Assbin/AssbinExporter.cpp index 496b39d49..0b99afbda 100644 --- a/code/Assbin/AssbinExporter.cpp +++ b/code/Assbin/AssbinExporter.cpp @@ -49,19 +49,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "AssbinFileWriter.h" #include -#include #include +#include namespace Assimp { -void ExportSceneAssbin(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/) { +void ExportSceneAssbin(const char *pFile, IOSystem *pIOSystem, const aiScene *pScene, const ExportProperties * /*pProperties*/) { DumpSceneToAssbin( - pFile, - "\0", // no command(s). - pIOSystem, - pScene, - false, // shortened? - false); // compressed? + pFile, + "\0", // no command(s). + pIOSystem, + pScene, + false, // shortened? + false); // compressed? } } // end of namespace Assimp diff --git a/code/Assbin/AssbinFileWriter.cpp b/code/Assbin/AssbinFileWriter.cpp index 4bc8f7cac..7fceaa1ad 100644 --- a/code/Assbin/AssbinFileWriter.cpp +++ b/code/Assbin/AssbinFileWriter.cpp @@ -48,50 +48,53 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "Common/assbin_chunks.h" #include "PostProcessing/ProcessHelper.h" -#include -#include -#include #include +#include +#include +#include #ifdef ASSIMP_BUILD_NO_OWN_ZLIB -# include +# include #else -# include "../contrib/zlib/zlib.h" +# include "../contrib/zlib/zlib.h" #endif #include +#ifdef _WIN32 +# pragma warning(push) +# pragma warning(disable : 4706) +#endif // _WIN32 + namespace Assimp { template -size_t Write(IOStream * stream, const T& v) { - return stream->Write( &v, sizeof(T), 1 ); +size_t Write(IOStream *stream, const T &v) { + return stream->Write(&v, sizeof(T), 1); } // ----------------------------------------------------------------------------------- // Serialize an aiString template <> -inline -size_t Write(IOStream * stream, const aiString& s) { +inline size_t Write(IOStream *stream, const aiString &s) { const size_t s2 = (uint32_t)s.length; - stream->Write(&s,4,1); - stream->Write(s.data,s2,1); + stream->Write(&s, 4, 1); + stream->Write(s.data, s2, 1); - return s2+4; + return s2 + 4; } // ----------------------------------------------------------------------------------- // Serialize an unsigned int as uint32_t template <> -inline -size_t Write(IOStream * stream, const unsigned int& w) { +inline size_t Write(IOStream *stream, const unsigned int &w) { const uint32_t t = (uint32_t)w; if (w > t) { // this shouldn't happen, integers in Assimp data structures never exceed 2^32 throw DeadlyExportError("loss of data due to 64 -> 32 bit integer conversion"); } - stream->Write(&t,4,1); + stream->Write(&t, 4, 1); return 4; } @@ -99,10 +102,9 @@ size_t Write(IOStream * stream, const unsigned int& w) { // ----------------------------------------------------------------------------------- // Serialize an unsigned int as uint16_t template <> -inline -size_t Write(IOStream * stream, const uint16_t& w) { - static_assert(sizeof(uint16_t)==2, "sizeof(uint16_t)==2"); - stream->Write(&w,2,1); +inline size_t Write(IOStream *stream, const uint16_t &w) { + static_assert(sizeof(uint16_t) == 2, "sizeof(uint16_t)==2"); + stream->Write(&w, 2, 1); return 2; } @@ -110,10 +112,9 @@ size_t Write(IOStream * stream, const uint16_t& w) { // ----------------------------------------------------------------------------------- // Serialize a float template <> -inline -size_t Write(IOStream * stream, const float& f) { - static_assert(sizeof(float)==4, "sizeof(float)==4"); - stream->Write(&f,4,1); +inline size_t Write(IOStream *stream, const float &f) { + static_assert(sizeof(float) == 4, "sizeof(float)==4"); + stream->Write(&f, 4, 1); return 4; } @@ -121,10 +122,9 @@ size_t Write(IOStream * stream, const float& f) { // ----------------------------------------------------------------------------------- // Serialize a double template <> -inline -size_t Write(IOStream * stream, const double& f) { - static_assert(sizeof(double)==8, "sizeof(double)==8"); - stream->Write(&f,8,1); +inline size_t Write(IOStream *stream, const double &f) { + static_assert(sizeof(double) == 8, "sizeof(double)==8"); + stream->Write(&f, 8, 1); return 8; } @@ -132,11 +132,10 @@ size_t Write(IOStream * stream, const double& f) { // ----------------------------------------------------------------------------------- // Serialize a vec3 template <> -inline -size_t Write(IOStream * stream, const aiVector3D& v) { - size_t t = Write(stream,v.x); - t += Write(stream,v.y); - t += Write(stream,v.z); +inline size_t Write(IOStream *stream, const aiVector3D &v) { + size_t t = Write(stream, v.x); + t += Write(stream, v.y); + t += Write(stream, v.z); return t; } @@ -144,11 +143,10 @@ size_t Write(IOStream * stream, const aiVector3D& v) { // ----------------------------------------------------------------------------------- // Serialize a color value template <> -inline -size_t Write(IOStream * stream, const aiColor3D& v) { - size_t t = Write(stream,v.r); - t += Write(stream,v.g); - t += Write(stream,v.b); +inline size_t Write(IOStream *stream, const aiColor3D &v) { + size_t t = Write(stream, v.r); + t += Write(stream, v.g); + t += Write(stream, v.b); return t; } @@ -156,12 +154,11 @@ size_t Write(IOStream * stream, const aiColor3D& v) { // ----------------------------------------------------------------------------------- // Serialize a color value template <> -inline -size_t Write(IOStream * stream, const aiColor4D& v) { - size_t t = Write(stream,v.r); - t += Write(stream,v.g); - t += Write(stream,v.b); - t += Write(stream,v.a); +inline size_t Write(IOStream *stream, const aiColor4D &v) { + size_t t = Write(stream, v.r); + t += Write(stream, v.g); + t += Write(stream, v.b); + t += Write(stream, v.a); return t; } @@ -169,12 +166,11 @@ size_t Write(IOStream * stream, const aiColor4D& v) { // ----------------------------------------------------------------------------------- // Serialize a quaternion template <> -inline -size_t Write(IOStream * stream, const aiQuaternion& v) { - size_t t = Write(stream,v.w); - t += Write(stream,v.x); - t += Write(stream,v.y); - t += Write(stream,v.z); +inline size_t Write(IOStream *stream, const aiQuaternion &v) { + size_t t = Write(stream, v.w); + t += Write(stream, v.x); + t += Write(stream, v.y); + t += Write(stream, v.z); ai_assert(t == 16); return 16; @@ -183,21 +179,19 @@ size_t Write(IOStream * stream, const aiQuaternion& v) { // ----------------------------------------------------------------------------------- // Serialize a vertex weight template <> -inline -size_t Write(IOStream * stream, const aiVertexWeight& v) { - size_t t = Write(stream,v.mVertexId); +inline size_t Write(IOStream *stream, const aiVertexWeight &v) { + size_t t = Write(stream, v.mVertexId); - return t+Write(stream,v.mWeight); + return t + Write(stream, v.mWeight); } // ----------------------------------------------------------------------------------- // Serialize a mat4x4 template <> -inline -size_t Write(IOStream * stream, const aiMatrix4x4& m) { - for (unsigned int i = 0; i < 4;++i) { - for (unsigned int i2 = 0; i2 < 4;++i2) { - Write(stream,m[i][i2]); +inline size_t Write(IOStream *stream, const aiMatrix4x4 &m) { + for (unsigned int i = 0; i < 4; ++i) { + for (unsigned int i2 = 0; i2 < 4; ++i2) { + Write(stream, m[i][i2]); } } @@ -207,38 +201,35 @@ size_t Write(IOStream * stream, const aiMatrix4x4& m) { // ----------------------------------------------------------------------------------- // Serialize an aiVectorKey template <> -inline -size_t Write(IOStream * stream, const aiVectorKey& v) { - const size_t t = Write(stream,v.mTime); - return t + Write(stream,v.mValue); +inline size_t Write(IOStream *stream, const aiVectorKey &v) { + const size_t t = Write(stream, v.mTime); + return t + Write(stream, v.mValue); } // ----------------------------------------------------------------------------------- // Serialize an aiQuatKey template <> -inline -size_t Write(IOStream * stream, const aiQuatKey& v) { - const size_t t = Write(stream,v.mTime); - return t + Write(stream,v.mValue); +inline size_t Write(IOStream *stream, const aiQuatKey &v) { + const size_t t = Write(stream, v.mTime); + return t + Write(stream, v.mValue); } template -inline -size_t WriteBounds(IOStream * stream, const T* in, unsigned int size) { +inline size_t WriteBounds(IOStream *stream, const T *in, unsigned int size) { T minc, maxc; - ArrayBounds(in,size,minc,maxc); + ArrayBounds(in, size, minc, maxc); - const size_t t = Write(stream,minc); - return t + Write(stream,maxc); + const size_t t = Write(stream, minc); + return t + Write(stream, maxc); } // We use this to write out non-byte arrays so that we write using the specializations. // This way we avoid writing out extra bytes that potentially come from struct alignment. template -inline -size_t WriteArray(IOStream * stream, const T* in, unsigned int size) { +inline size_t WriteArray(IOStream *stream, const T *in, unsigned int size) { size_t n = 0; - for (unsigned int i=0; i(stream,in[i]); + for (unsigned int i = 0; i < size; i++) + n += Write(stream, in[i]); return n; } @@ -253,26 +244,23 @@ size_t WriteArray(IOStream * stream, const T* in, unsigned int size) { * and the chunk contents to the container stream. This allows relatively easy chunk * chunk construction, even recursively. */ -class AssbinChunkWriter : public IOStream -{ +class AssbinChunkWriter : public IOStream { private: - - uint8_t* buffer; + uint8_t *buffer; uint32_t magic; - IOStream * container; + IOStream *container; size_t cur_size, cursor, initial; private: // ------------------------------------------------------------------- - void Grow(size_t need = 0) - { - size_t new_size = std::max(initial, std::max( need, cur_size+(cur_size>>1) )); + void Grow(size_t need = 0) { + size_t new_size = std::max(initial, std::max(need, cur_size + (cur_size >> 1))); - const uint8_t* const old = buffer; + const uint8_t *const old = buffer; buffer = new uint8_t[new_size]; if (old) { - memcpy(buffer,old,cur_size); + memcpy(buffer, old, cur_size); delete[] old; } @@ -280,26 +268,29 @@ private: } public: - - AssbinChunkWriter( IOStream * container, uint32_t magic, size_t initial = 4096) - : buffer(NULL), magic(magic), container(container), cur_size(0), cursor(0), initial(initial) - { + AssbinChunkWriter(IOStream *container, uint32_t magic, size_t initial = 4096) : + buffer(NULL), + magic(magic), + container(container), + cur_size(0), + cursor(0), + initial(initial) { + // empty } - virtual ~AssbinChunkWriter() - { + virtual ~AssbinChunkWriter() { if (container) { - container->Write( &magic, sizeof(uint32_t), 1 ); - container->Write( &cursor, sizeof(uint32_t), 1 ); - container->Write( buffer, 1, cursor ); + container->Write(&magic, sizeof(uint32_t), 1); + container->Write(&cursor, sizeof(uint32_t), 1); + container->Write(buffer, 1, cursor); } if (buffer) delete[] buffer; } - void * GetBufferPointer() { return buffer; } + void *GetBufferPointer() { return buffer; } // ------------------------------------------------------------------- - virtual size_t Read(void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) { + virtual size_t Read(void * /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) { return 0; } virtual aiReturn Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/) { @@ -317,18 +308,17 @@ public: } // ------------------------------------------------------------------- - virtual size_t Write(const void* pvBuffer, size_t pSize, size_t pCount) { + virtual size_t Write(const void *pvBuffer, size_t pSize, size_t pCount) { pSize *= pCount; if (cursor + pSize > cur_size) { Grow(cursor + pSize); } - memcpy(buffer+cursor, pvBuffer, pSize); + memcpy(buffer + cursor, pvBuffer, pSize); cursor += pSize; return pCount; } - }; // ---------------------------------------------------------------------------------- @@ -337,63 +327,61 @@ public: * * This class writes an .assbin file, and is responsible for the file layout. */ -class AssbinFileWriter -{ +class AssbinFileWriter { private: bool shortened; bool compressed; protected: // ----------------------------------------------------------------------------------- - void WriteBinaryNode( IOStream * container, const aiNode* node) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AINODE ); + void WriteBinaryNode(IOStream *container, const aiNode *node) { + AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AINODE); unsigned int nb_metadata = (node->mMetaData != NULL ? node->mMetaData->mNumProperties : 0); - Write(&chunk,node->mName); - Write(&chunk,node->mTransformation); - Write(&chunk,node->mNumChildren); - Write(&chunk,node->mNumMeshes); - Write(&chunk,nb_metadata); + Write(&chunk, node->mName); + Write(&chunk, node->mTransformation); + Write(&chunk, node->mNumChildren); + Write(&chunk, node->mNumMeshes); + Write(&chunk, nb_metadata); - for (unsigned int i = 0; i < node->mNumMeshes;++i) { - Write(&chunk,node->mMeshes[i]); + for (unsigned int i = 0; i < node->mNumMeshes; ++i) { + Write(&chunk, node->mMeshes[i]); } - for (unsigned int i = 0; i < node->mNumChildren;++i) { - WriteBinaryNode( &chunk, node->mChildren[i] ); + for (unsigned int i = 0; i < node->mNumChildren; ++i) { + WriteBinaryNode(&chunk, node->mChildren[i]); } for (unsigned int i = 0; i < nb_metadata; ++i) { - const aiString& key = node->mMetaData->mKeys[i]; + const aiString &key = node->mMetaData->mKeys[i]; aiMetadataType type = node->mMetaData->mValues[i].mType; - void* value = node->mMetaData->mValues[i].mData; + void *value = node->mMetaData->mValues[i].mData; Write(&chunk, key); - Write(&chunk, type); + Write(&chunk, (uint16_t)type); switch (type) { case AI_BOOL: - Write(&chunk, *((bool*) value)); + Write(&chunk, *((bool *)value)); break; case AI_INT32: - Write(&chunk, *((int32_t*) value)); + Write(&chunk, *((int32_t *)value)); break; case AI_UINT64: - Write(&chunk, *((uint64_t*) value)); + Write(&chunk, *((uint64_t *)value)); break; case AI_FLOAT: - Write(&chunk, *((float*) value)); + Write(&chunk, *((float *)value)); break; case AI_DOUBLE: - Write(&chunk, *((double*) value)); + Write(&chunk, *((double *)value)); break; case AI_AISTRING: - Write(&chunk, *((aiString*) value)); + Write(&chunk, *((aiString *)value)); break; case AI_AIVECTOR3D: - Write(&chunk, *((aiVector3D*) value)); + Write(&chunk, *((aiVector3D *)value)); break; #ifdef SWIG case FORCE_32BIT: @@ -405,53 +393,49 @@ protected: } // ----------------------------------------------------------------------------------- - void WriteBinaryTexture(IOStream * container, const aiTexture* tex) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AITEXTURE ); + void WriteBinaryTexture(IOStream *container, const aiTexture *tex) { + AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AITEXTURE); - Write(&chunk,tex->mWidth); - Write(&chunk,tex->mHeight); + Write(&chunk, tex->mWidth); + Write(&chunk, tex->mHeight); // Write the texture format, but don't include the null terminator. - chunk.Write( tex->achFormatHint, sizeof(char), HINTMAXTEXTURELEN - 1 ); + chunk.Write(tex->achFormatHint, sizeof(char), HINTMAXTEXTURELEN - 1); - if(!shortened) { + if (!shortened) { if (!tex->mHeight) { - chunk.Write(tex->pcData,1,tex->mWidth); - } - else { - chunk.Write(tex->pcData,1,tex->mWidth*tex->mHeight*4); + chunk.Write(tex->pcData, 1, tex->mWidth); + } else { + chunk.Write(tex->pcData, 1, tex->mWidth * tex->mHeight * 4); } } - } // ----------------------------------------------------------------------------------- - void WriteBinaryBone(IOStream * container, const aiBone* b) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIBONE ); + void WriteBinaryBone(IOStream *container, const aiBone *b) { + AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AIBONE); - Write(&chunk,b->mName); - Write(&chunk,b->mNumWeights); - Write(&chunk,b->mOffsetMatrix); + Write(&chunk, b->mName); + Write(&chunk, b->mNumWeights); + Write(&chunk, b->mOffsetMatrix); // for the moment we write dumb min/max values for the bones, too. // maybe I'll add a better, hash-like solution later if (shortened) { - WriteBounds(&chunk,b->mWeights,b->mNumWeights); + WriteBounds(&chunk, b->mWeights, b->mNumWeights); } // else write as usual - else WriteArray(&chunk,b->mWeights,b->mNumWeights); + else + WriteArray(&chunk, b->mWeights, b->mNumWeights); } // ----------------------------------------------------------------------------------- - void WriteBinaryMesh(IOStream * container, const aiMesh* mesh) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMESH ); + void WriteBinaryMesh(IOStream *container, const aiMesh *mesh) { + AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AIMESH); - Write(&chunk,mesh->mPrimitiveTypes); - Write(&chunk,mesh->mNumVertices); - Write(&chunk,mesh->mNumFaces); - Write(&chunk,mesh->mNumBones); - Write(&chunk,mesh->mMaterialIndex); + Write(&chunk, mesh->mPrimitiveTypes); + Write(&chunk, mesh->mNumVertices); + Write(&chunk, mesh->mNumFaces); + Write(&chunk, mesh->mNumBones); + Write(&chunk, mesh->mMaterialIndex); // first of all, write bits for all existent vertex components unsigned int c = 0; @@ -464,63 +448,67 @@ protected: if (mesh->mTangents && mesh->mBitangents) { c |= ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS; } - for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) { + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++n) { if (!mesh->mTextureCoords[n]) { break; } c |= ASSBIN_MESH_HAS_TEXCOORD(n); } - for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) { + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS; ++n) { if (!mesh->mColors[n]) { break; } c |= ASSBIN_MESH_HAS_COLOR(n); } - Write(&chunk,c); + Write(&chunk, c); aiVector3D minVec, maxVec; if (mesh->mVertices) { if (shortened) { - WriteBounds(&chunk,mesh->mVertices,mesh->mNumVertices); + WriteBounds(&chunk, mesh->mVertices, mesh->mNumVertices); } // else write as usual - else WriteArray(&chunk,mesh->mVertices,mesh->mNumVertices); + else + WriteArray(&chunk, mesh->mVertices, mesh->mNumVertices); } if (mesh->mNormals) { if (shortened) { - WriteBounds(&chunk,mesh->mNormals,mesh->mNumVertices); + WriteBounds(&chunk, mesh->mNormals, mesh->mNumVertices); } // else write as usual - else WriteArray(&chunk,mesh->mNormals,mesh->mNumVertices); + else + WriteArray(&chunk, mesh->mNormals, mesh->mNumVertices); } if (mesh->mTangents && mesh->mBitangents) { if (shortened) { - WriteBounds(&chunk,mesh->mTangents,mesh->mNumVertices); - WriteBounds(&chunk,mesh->mBitangents,mesh->mNumVertices); + WriteBounds(&chunk, mesh->mTangents, mesh->mNumVertices); + WriteBounds(&chunk, mesh->mBitangents, mesh->mNumVertices); } // else write as usual else { - WriteArray(&chunk,mesh->mTangents,mesh->mNumVertices); - WriteArray(&chunk,mesh->mBitangents,mesh->mNumVertices); + WriteArray(&chunk, mesh->mTangents, mesh->mNumVertices); + WriteArray(&chunk, mesh->mBitangents, mesh->mNumVertices); } } - for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) { + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS; ++n) { if (!mesh->mColors[n]) break; if (shortened) { - WriteBounds(&chunk,mesh->mColors[n],mesh->mNumVertices); + WriteBounds(&chunk, mesh->mColors[n], mesh->mNumVertices); } // else write as usual - else WriteArray(&chunk,mesh->mColors[n],mesh->mNumVertices); + else + WriteArray(&chunk, mesh->mColors[n], mesh->mNumVertices); } - for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) { + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++n) { if (!mesh->mTextureCoords[n]) break; // write number of UV components - Write(&chunk,mesh->mNumUVComponents[n]); + Write(&chunk, mesh->mNumUVComponents[n]); if (shortened) { - WriteBounds(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices); + WriteBounds(&chunk, mesh->mTextureCoords[n], mesh->mNumVertices); } // else write as usual - else WriteArray(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices); + else + WriteArray(&chunk, mesh->mTextureCoords[n], mesh->mNumVertices); } // write faces. There are no floating-point calculations involved @@ -529,234 +517,223 @@ protected: // using Assimp's standard hashing function. if (shortened) { unsigned int processed = 0; - for (unsigned int job;(job = std::min(mesh->mNumFaces-processed,512u));processed += job) { - + for (unsigned int job; (job = std::min(mesh->mNumFaces - processed, 512u)); processed += job) { uint32_t hash = 0; - for (unsigned int a = 0; a < job;++a) { + for (unsigned int a = 0; a < job; ++a) { - const aiFace& f = mesh->mFaces[processed+a]; + const aiFace &f = mesh->mFaces[processed + a]; uint32_t tmp = f.mNumIndices; - hash = SuperFastHash(reinterpret_cast(&tmp),sizeof tmp,hash); + hash = SuperFastHash(reinterpret_cast(&tmp), sizeof tmp, hash); for (unsigned int i = 0; i < f.mNumIndices; ++i) { static_assert(AI_MAX_VERTICES <= 0xffffffff, "AI_MAX_VERTICES <= 0xffffffff"); - tmp = static_cast( f.mIndices[i] ); - hash = SuperFastHash(reinterpret_cast(&tmp),sizeof tmp,hash); + tmp = static_cast(f.mIndices[i]); + hash = SuperFastHash(reinterpret_cast(&tmp), sizeof tmp, hash); } } - Write(&chunk,hash); + Write(&chunk, hash); } - } - else // else write as usual + } else // else write as usual { // if there are less than 2^16 vertices, we can simply use 16 bit integers ... - for (unsigned int i = 0; i < mesh->mNumFaces;++i) { - const aiFace& f = mesh->mFaces[i]; + for (unsigned int i = 0; i < mesh->mNumFaces; ++i) { + const aiFace &f = mesh->mFaces[i]; static_assert(AI_MAX_FACE_INDICES <= 0xffff, "AI_MAX_FACE_INDICES <= 0xffff"); - Write(&chunk,f.mNumIndices); + Write(&chunk, static_cast(f.mNumIndices)); - for (unsigned int a = 0; a < f.mNumIndices;++a) { - if (mesh->mNumVertices < (1u<<16)) { - Write(&chunk,f.mIndices[a]); + for (unsigned int a = 0; a < f.mNumIndices; ++a) { + if (mesh->mNumVertices < (1u << 16)) { + Write(&chunk, static_cast(f.mIndices[a])); + } else { + Write(&chunk, f.mIndices[a]); } - else Write(&chunk,f.mIndices[a]); } } } // write bones if (mesh->mNumBones) { - for (unsigned int a = 0; a < mesh->mNumBones;++a) { - const aiBone* b = mesh->mBones[a]; - WriteBinaryBone(&chunk,b); + for (unsigned int a = 0; a < mesh->mNumBones; ++a) { + const aiBone *b = mesh->mBones[a]; + WriteBinaryBone(&chunk, b); } } } // ----------------------------------------------------------------------------------- - void WriteBinaryMaterialProperty(IOStream * container, const aiMaterialProperty* prop) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMATERIALPROPERTY ); + void WriteBinaryMaterialProperty(IOStream *container, const aiMaterialProperty *prop) { + AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AIMATERIALPROPERTY); - Write(&chunk,prop->mKey); - Write(&chunk,prop->mSemantic); - Write(&chunk,prop->mIndex); + Write(&chunk, prop->mKey); + Write(&chunk, prop->mSemantic); + Write(&chunk, prop->mIndex); - Write(&chunk,prop->mDataLength); - Write(&chunk,(unsigned int)prop->mType); - chunk.Write(prop->mData,1,prop->mDataLength); + Write(&chunk, prop->mDataLength); + Write(&chunk, (unsigned int)prop->mType); + chunk.Write(prop->mData, 1, prop->mDataLength); } // ----------------------------------------------------------------------------------- - void WriteBinaryMaterial(IOStream * container, const aiMaterial* mat) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMATERIAL); + void WriteBinaryMaterial(IOStream *container, const aiMaterial *mat) { + AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AIMATERIAL); - Write(&chunk,mat->mNumProperties); - for (unsigned int i = 0; i < mat->mNumProperties;++i) { - WriteBinaryMaterialProperty( &chunk, mat->mProperties[i]); + Write(&chunk, mat->mNumProperties); + for (unsigned int i = 0; i < mat->mNumProperties; ++i) { + WriteBinaryMaterialProperty(&chunk, mat->mProperties[i]); } } // ----------------------------------------------------------------------------------- - void WriteBinaryNodeAnim(IOStream * container, const aiNodeAnim* nd) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AINODEANIM ); + void WriteBinaryNodeAnim(IOStream *container, const aiNodeAnim *nd) { + AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AINODEANIM); - Write(&chunk,nd->mNodeName); - Write(&chunk,nd->mNumPositionKeys); - Write(&chunk,nd->mNumRotationKeys); - Write(&chunk,nd->mNumScalingKeys); - Write(&chunk,nd->mPreState); - Write(&chunk,nd->mPostState); + Write(&chunk, nd->mNodeName); + Write(&chunk, nd->mNumPositionKeys); + Write(&chunk, nd->mNumRotationKeys); + Write(&chunk, nd->mNumScalingKeys); + Write(&chunk, nd->mPreState); + Write(&chunk, nd->mPostState); if (nd->mPositionKeys) { if (shortened) { - WriteBounds(&chunk,nd->mPositionKeys,nd->mNumPositionKeys); + WriteBounds(&chunk, nd->mPositionKeys, nd->mNumPositionKeys); } // else write as usual - else WriteArray(&chunk,nd->mPositionKeys,nd->mNumPositionKeys); + else + WriteArray(&chunk, nd->mPositionKeys, nd->mNumPositionKeys); } if (nd->mRotationKeys) { if (shortened) { - WriteBounds(&chunk,nd->mRotationKeys,nd->mNumRotationKeys); + WriteBounds(&chunk, nd->mRotationKeys, nd->mNumRotationKeys); } // else write as usual - else WriteArray(&chunk,nd->mRotationKeys,nd->mNumRotationKeys); + else + WriteArray(&chunk, nd->mRotationKeys, nd->mNumRotationKeys); } if (nd->mScalingKeys) { if (shortened) { - WriteBounds(&chunk,nd->mScalingKeys,nd->mNumScalingKeys); + WriteBounds(&chunk, nd->mScalingKeys, nd->mNumScalingKeys); } // else write as usual - else WriteArray(&chunk,nd->mScalingKeys,nd->mNumScalingKeys); - } - } - - - // ----------------------------------------------------------------------------------- - void WriteBinaryAnim( IOStream * container, const aiAnimation* anim ) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIANIMATION ); - - Write(&chunk,anim->mName); - Write(&chunk,anim->mDuration); - Write(&chunk,anim->mTicksPerSecond); - Write(&chunk,anim->mNumChannels); - - for (unsigned int a = 0; a < anim->mNumChannels;++a) { - const aiNodeAnim* nd = anim->mChannels[a]; - WriteBinaryNodeAnim(&chunk,nd); + else + WriteArray(&chunk, nd->mScalingKeys, nd->mNumScalingKeys); } } // ----------------------------------------------------------------------------------- - void WriteBinaryLight( IOStream * container, const aiLight* l ) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AILIGHT ); + void WriteBinaryAnim(IOStream *container, const aiAnimation *anim) { + AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AIANIMATION); - Write(&chunk,l->mName); - Write(&chunk,l->mType); + Write(&chunk, anim->mName); + Write(&chunk, anim->mDuration); + Write(&chunk, anim->mTicksPerSecond); + Write(&chunk, anim->mNumChannels); + + for (unsigned int a = 0; a < anim->mNumChannels; ++a) { + const aiNodeAnim *nd = anim->mChannels[a]; + WriteBinaryNodeAnim(&chunk, nd); + } + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryLight(IOStream *container, const aiLight *l) { + AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AILIGHT); + + Write(&chunk, l->mName); + Write(&chunk, l->mType); if (l->mType != aiLightSource_DIRECTIONAL) { - Write(&chunk,l->mAttenuationConstant); - Write(&chunk,l->mAttenuationLinear); - Write(&chunk,l->mAttenuationQuadratic); + Write(&chunk, l->mAttenuationConstant); + Write(&chunk, l->mAttenuationLinear); + Write(&chunk, l->mAttenuationQuadratic); } - Write(&chunk,l->mColorDiffuse); - Write(&chunk,l->mColorSpecular); - Write(&chunk,l->mColorAmbient); + Write(&chunk, l->mColorDiffuse); + Write(&chunk, l->mColorSpecular); + Write(&chunk, l->mColorAmbient); if (l->mType == aiLightSource_SPOT) { - Write(&chunk,l->mAngleInnerCone); - Write(&chunk,l->mAngleOuterCone); + Write(&chunk, l->mAngleInnerCone); + Write(&chunk, l->mAngleOuterCone); } - } // ----------------------------------------------------------------------------------- - void WriteBinaryCamera( IOStream * container, const aiCamera* cam ) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AICAMERA ); + void WriteBinaryCamera(IOStream *container, const aiCamera *cam) { + AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AICAMERA); - Write(&chunk,cam->mName); - Write(&chunk,cam->mPosition); - Write(&chunk,cam->mLookAt); - Write(&chunk,cam->mUp); - Write(&chunk,cam->mHorizontalFOV); - Write(&chunk,cam->mClipPlaneNear); - Write(&chunk,cam->mClipPlaneFar); - Write(&chunk,cam->mAspect); + Write(&chunk, cam->mName); + Write(&chunk, cam->mPosition); + Write(&chunk, cam->mLookAt); + Write(&chunk, cam->mUp); + Write(&chunk, cam->mHorizontalFOV); + Write(&chunk, cam->mClipPlaneNear); + Write(&chunk, cam->mClipPlaneFar); + Write(&chunk, cam->mAspect); } // ----------------------------------------------------------------------------------- - void WriteBinaryScene( IOStream * container, const aiScene* scene) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AISCENE ); + void WriteBinaryScene(IOStream *container, const aiScene *scene) { + AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AISCENE); // basic scene information - Write(&chunk,scene->mFlags); - Write(&chunk,scene->mNumMeshes); - Write(&chunk,scene->mNumMaterials); - Write(&chunk,scene->mNumAnimations); - Write(&chunk,scene->mNumTextures); - Write(&chunk,scene->mNumLights); - Write(&chunk,scene->mNumCameras); + Write(&chunk, scene->mFlags); + Write(&chunk, scene->mNumMeshes); + Write(&chunk, scene->mNumMaterials); + Write(&chunk, scene->mNumAnimations); + Write(&chunk, scene->mNumTextures); + Write(&chunk, scene->mNumLights); + Write(&chunk, scene->mNumCameras); // write node graph - WriteBinaryNode( &chunk, scene->mRootNode ); + WriteBinaryNode(&chunk, scene->mRootNode); // write all meshes - for (unsigned int i = 0; i < scene->mNumMeshes;++i) { - const aiMesh* mesh = scene->mMeshes[i]; - WriteBinaryMesh( &chunk,mesh); + for (unsigned int i = 0; i < scene->mNumMeshes; ++i) { + const aiMesh *mesh = scene->mMeshes[i]; + WriteBinaryMesh(&chunk, mesh); } // write materials - for (unsigned int i = 0; i< scene->mNumMaterials; ++i) { - const aiMaterial* mat = scene->mMaterials[i]; - WriteBinaryMaterial(&chunk,mat); + for (unsigned int i = 0; i < scene->mNumMaterials; ++i) { + const aiMaterial *mat = scene->mMaterials[i]; + WriteBinaryMaterial(&chunk, mat); } // write all animations - for (unsigned int i = 0; i < scene->mNumAnimations;++i) { - const aiAnimation* anim = scene->mAnimations[i]; - WriteBinaryAnim(&chunk,anim); + for (unsigned int i = 0; i < scene->mNumAnimations; ++i) { + const aiAnimation *anim = scene->mAnimations[i]; + WriteBinaryAnim(&chunk, anim); } - // write all textures - for (unsigned int i = 0; i < scene->mNumTextures;++i) { - const aiTexture* mesh = scene->mTextures[i]; - WriteBinaryTexture(&chunk,mesh); + for (unsigned int i = 0; i < scene->mNumTextures; ++i) { + const aiTexture *mesh = scene->mTextures[i]; + WriteBinaryTexture(&chunk, mesh); } // write lights - for (unsigned int i = 0; i < scene->mNumLights;++i) { - const aiLight* l = scene->mLights[i]; - WriteBinaryLight(&chunk,l); + for (unsigned int i = 0; i < scene->mNumLights; ++i) { + const aiLight *l = scene->mLights[i]; + WriteBinaryLight(&chunk, l); } // write cameras - for (unsigned int i = 0; i < scene->mNumCameras;++i) { - const aiCamera* cam = scene->mCameras[i]; - WriteBinaryCamera(&chunk,cam); + for (unsigned int i = 0; i < scene->mNumCameras; ++i) { + const aiCamera *cam = scene->mCameras[i]; + WriteBinaryCamera(&chunk, cam); } - } public: - AssbinFileWriter(bool shortened, bool compressed) - : shortened(shortened), compressed(compressed) - { + AssbinFileWriter(bool shortened, bool compressed) : + shortened(shortened), compressed(compressed) { } // ----------------------------------------------------------------------------------- // Write a binary model dump - void WriteBinaryDump(const char* pFile, const char* cmd, IOSystem* pIOSystem, const aiScene* pScene) - { - IOStream * out = pIOSystem->Open( pFile, "wb" ); + void WriteBinaryDump(const char *pFile, const char *cmd, IOSystem *pIOSystem, const aiScene *pScene) { + IOStream *out = pIOSystem->Open(pFile, "wb"); if (!out) throw std::runtime_error("Unable to open output file " + std::string(pFile) + '\n'); @@ -770,10 +747,10 @@ public: try { time_t tt = time(NULL); #if _WIN32 - tm* p = gmtime(&tt); + tm *p = gmtime(&tt); #else struct tm now; - tm* p = gmtime_r(&tt, &now); + tm *p = gmtime_r(&tt, &now); #endif // header @@ -795,14 +772,14 @@ public: Write(out, compressed); // == 20 bytes - char buff[256] = {0}; + char buff[256] = { 0 }; ai_snprintf(buff, 256, "%s", pFile); out->Write(buff, sizeof(char), 256); memset(buff, 0, sizeof(buff)); ai_snprintf(buff, 128, "%s", cmd); out->Write(buff, sizeof(char), 128); - + // leave 64 bytes free for future extensions memset(buff, 0xcd, 64); out->Write(buff, sizeof(char), 64); @@ -813,18 +790,16 @@ public: // Up to here the data is uncompressed. For compressed files, the rest // is compressed using standard DEFLATE from zlib. - if (compressed) - { + if (compressed) { AssbinChunkWriter uncompressedStream(NULL, 0); WriteBinaryScene(&uncompressedStream, pScene); uLongf uncompressedSize = static_cast(uncompressedStream.Tell()); uLongf compressedSize = (uLongf)compressBound(uncompressedSize); - uint8_t* compressedBuffer = new uint8_t[compressedSize]; + uint8_t *compressedBuffer = new uint8_t[compressedSize]; - int res = compress2(compressedBuffer, &compressedSize, (const Bytef*)uncompressedStream.GetBufferPointer(), uncompressedSize, 9); - if (res != Z_OK) - { + int res = compress2(compressedBuffer, &compressedSize, (const Bytef *)uncompressedStream.GetBufferPointer(), uncompressedSize, 9); + if (res != Z_OK) { delete[] compressedBuffer; throw DeadlyExportError("Compression failed."); } @@ -833,15 +808,12 @@ public: out->Write(compressedBuffer, sizeof(char), compressedSize); delete[] compressedBuffer; - } - else - { + } else { WriteBinaryScene(out, pScene); } CloseIOStream(); - } - catch (...) { + } catch (...) { CloseIOStream(); throw; } @@ -849,10 +821,13 @@ public: }; void DumpSceneToAssbin( - const char* pFile, const char* cmd, IOSystem* pIOSystem, - const aiScene* pScene, bool shortened, bool compressed) { + const char *pFile, const char *cmd, IOSystem *pIOSystem, + const aiScene *pScene, bool shortened, bool compressed) { AssbinFileWriter fileWriter(shortened, compressed); fileWriter.WriteBinaryDump(pFile, cmd, pIOSystem, pScene); } +#ifdef _WIN32 +# pragma warning(pop) +#endif // _WIN32 } // end of namespace Assimp diff --git a/code/Assbin/AssbinLoader.cpp b/code/Assbin/AssbinLoader.cpp index 71e35cb6a..4293cae29 100644 --- a/code/Assbin/AssbinLoader.cpp +++ b/code/Assbin/AssbinLoader.cpp @@ -5,8 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2020, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -53,16 +51,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "Assbin/AssbinLoader.h" #include "Common/assbin_chunks.h" #include -#include #include -#include #include +#include +#include #include #ifdef ASSIMP_BUILD_NO_OWN_ZLIB -# include +#include #else -# include +#include #endif using namespace Assimp; @@ -81,94 +79,97 @@ static const aiImporterDesc desc = { }; // ----------------------------------------------------------------------------------- -const aiImporterDesc* AssbinImporter::GetInfo() const { +const aiImporterDesc *AssbinImporter::GetInfo() const { return &desc; } // ----------------------------------------------------------------------------------- -bool AssbinImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool /*checkSig*/ ) const { - IOStream * in = pIOHandler->Open(pFile); +bool AssbinImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const { + IOStream *in = pIOHandler->Open(pFile); if (nullptr == in) { return false; } char s[32]; - in->Read( s, sizeof(char), 32 ); + in->Read(s, sizeof(char), 32); pIOHandler->Close(in); - return strncmp( s, "ASSIMP.binary-dump.", 19 ) == 0; + return strncmp(s, "ASSIMP.binary-dump.", 19) == 0; } // ----------------------------------------------------------------------------------- template -T Read(IOStream * stream) { +T Read(IOStream *stream) { T t; - size_t res = stream->Read( &t, sizeof(T), 1 ); - if(res != 1) + size_t res = stream->Read(&t, sizeof(T), 1); + if (res != 1) { throw DeadlyImportError("Unexpected EOF"); + } return t; } // ----------------------------------------------------------------------------------- template <> -aiVector3D Read(IOStream * stream) { +aiVector3D Read(IOStream *stream) { aiVector3D v; - v.x = Read(stream); - v.y = Read(stream); - v.z = Read(stream); + v.x = Read(stream); + v.y = Read(stream); + v.z = Read(stream); return v; } // ----------------------------------------------------------------------------------- template <> -aiColor4D Read(IOStream * stream) { +aiColor4D Read(IOStream *stream) { aiColor4D c; - c.r = Read(stream); - c.g = Read(stream); - c.b = Read(stream); - c.a = Read(stream); + c.r = Read(stream); + c.g = Read(stream); + c.b = Read(stream); + c.a = Read(stream); return c; } // ----------------------------------------------------------------------------------- template <> -aiQuaternion Read(IOStream * stream) { +aiQuaternion Read(IOStream *stream) { aiQuaternion v; - v.w = Read(stream); - v.x = Read(stream); - v.y = Read(stream); - v.z = Read(stream); + v.w = Read(stream); + v.x = Read(stream); + v.y = Read(stream); + v.z = Read(stream); return v; } // ----------------------------------------------------------------------------------- template <> -aiString Read(IOStream * stream) { +aiString Read(IOStream *stream) { aiString s; - stream->Read(&s.length,4,1); - if(s.length) - stream->Read(s.data,s.length,1); + stream->Read(&s.length, 4, 1); + if (s.length) { + stream->Read(s.data, s.length, 1); + } s.data[s.length] = 0; + return s; } // ----------------------------------------------------------------------------------- template <> -aiVertexWeight Read(IOStream * stream) { +aiVertexWeight Read(IOStream *stream) { aiVertexWeight w; w.mVertexId = Read(stream); - w.mWeight = Read(stream); + w.mWeight = Read(stream); return w; } // ----------------------------------------------------------------------------------- template <> -aiMatrix4x4 Read(IOStream * stream) { +aiMatrix4x4 Read(IOStream *stream) { aiMatrix4x4 m; - for (unsigned int i = 0; i < 4;++i) { - for (unsigned int i2 = 0; i2 < 4;++i2) { - m[i][i2] = Read(stream); + for (unsigned int i = 0; i < 4; ++i) { + for (unsigned int i2 = 0; i2 < 4; ++i2) { + m[i][i2] = Read(stream); } } return m; @@ -176,7 +177,7 @@ aiMatrix4x4 Read(IOStream * stream) { // ----------------------------------------------------------------------------------- template <> -aiVectorKey Read(IOStream * stream) { +aiVectorKey Read(IOStream *stream) { aiVectorKey v; v.mTime = Read(stream); v.mValue = Read(stream); @@ -185,7 +186,7 @@ aiVectorKey Read(IOStream * stream) { // ----------------------------------------------------------------------------------- template <> -aiQuatKey Read(IOStream * stream) { +aiQuatKey Read(IOStream *stream) { aiQuatKey v; v.mTime = Read(stream); v.mValue = Read(stream); @@ -194,27 +195,27 @@ aiQuatKey Read(IOStream * stream) { // ----------------------------------------------------------------------------------- template -void ReadArray( IOStream *stream, T * out, unsigned int size) { - ai_assert( nullptr != stream ); - ai_assert( nullptr != out ); +void ReadArray(IOStream *stream, T *out, unsigned int size) { + ai_assert(nullptr != stream); + ai_assert(nullptr != out); - for (unsigned int i=0; i(stream); } } // ----------------------------------------------------------------------------------- template -void ReadBounds( IOStream * stream, T* /*p*/, unsigned int n ) { +void ReadBounds(IOStream *stream, T * /*p*/, unsigned int n) { // not sure what to do here, the data isn't really useful. - stream->Seek( sizeof(T) * n, aiOrigin_CUR ); + stream->Seek(sizeof(T) * n, aiOrigin_CUR); } // ----------------------------------------------------------------------------------- -void AssbinImporter::ReadBinaryNode( IOStream * stream, aiNode** onode, aiNode* parent ) { - if(Read(stream) != ASSBIN_CHUNK_AINODE) +void AssbinImporter::ReadBinaryNode(IOStream *stream, aiNode **onode, aiNode *parent) { + if (Read(stream) != ASSBIN_CHUNK_AINODE) throw DeadlyImportError("Magic chunk identifiers are wrong!"); - /*uint32_t size =*/ Read(stream); + /*uint32_t size =*/Read(stream); std::unique_ptr node(new aiNode()); @@ -222,14 +223,13 @@ void AssbinImporter::ReadBinaryNode( IOStream * stream, aiNode** onode, aiNode* node->mTransformation = Read(stream); unsigned numChildren = Read(stream); unsigned numMeshes = Read(stream); - unsigned int nb_metadata = Read(stream); + unsigned int nb_metadata = Read(stream); - if(parent) { + if (parent) { node->mParent = parent; } - if (numMeshes) - { + if (numMeshes) { node->mMeshes = new unsigned int[numMeshes]; for (unsigned int i = 0; i < numMeshes; ++i) { node->mMeshes[i] = Read(stream); @@ -238,19 +238,19 @@ void AssbinImporter::ReadBinaryNode( IOStream * stream, aiNode** onode, aiNode* } if (numChildren) { - node->mChildren = new aiNode*[numChildren]; + node->mChildren = new aiNode *[numChildren]; for (unsigned int i = 0; i < numChildren; ++i) { - ReadBinaryNode( stream, &node->mChildren[i], node.get() ); + ReadBinaryNode(stream, &node->mChildren[i], node.get()); node->mNumChildren++; } } - if ( nb_metadata > 0 ) { + if (nb_metadata > 0) { node->mMetaData = aiMetadata::Alloc(nb_metadata); for (unsigned int i = 0; i < nb_metadata; ++i) { node->mMetaData->mKeys[i] = Read(stream); - node->mMetaData->mValues[i].mType = (aiMetadataType) Read(stream); - void* data = nullptr; + node->mMetaData->mValues[i].mType = (aiMetadataType)Read(stream); + void *data = nullptr; switch (node->mMetaData->mValues[i].mType) { case AI_BOOL: @@ -263,7 +263,7 @@ void AssbinImporter::ReadBinaryNode( IOStream * stream, aiNode** onode, aiNode* data = new uint64_t(Read(stream)); break; case AI_FLOAT: - data = new float(Read(stream)); + data = new ai_real(Read(stream)); break; case AI_DOUBLE: data = new double(Read(stream)); @@ -281,17 +281,17 @@ void AssbinImporter::ReadBinaryNode( IOStream * stream, aiNode** onode, aiNode* break; } - node->mMetaData->mValues[i].mData = data; - } - } + node->mMetaData->mValues[i].mData = data; + } + } *onode = node.release(); } // ----------------------------------------------------------------------------------- -void AssbinImporter::ReadBinaryBone( IOStream * stream, aiBone* b ) { - if(Read(stream) != ASSBIN_CHUNK_AIBONE) +void AssbinImporter::ReadBinaryBone(IOStream *stream, aiBone *b) { + if (Read(stream) != ASSBIN_CHUNK_AIBONE) throw DeadlyImportError("Magic chunk identifiers are wrong!"); - /*uint32_t size =*/ Read(stream); + /*uint32_t size =*/Read(stream); b->mName = Read(stream); b->mNumWeights = Read(stream); @@ -300,23 +300,24 @@ void AssbinImporter::ReadBinaryBone( IOStream * stream, aiBone* b ) { // for the moment we write dumb min/max values for the bones, too. // maybe I'll add a better, hash-like solution later if (shortened) { - ReadBounds(stream,b->mWeights,b->mNumWeights); + ReadBounds(stream, b->mWeights, b->mNumWeights); } else { // else write as usual b->mWeights = new aiVertexWeight[b->mNumWeights]; - ReadArray(stream,b->mWeights,b->mNumWeights); + ReadArray(stream, b->mWeights, b->mNumWeights); } } // ----------------------------------------------------------------------------------- static bool fitsIntoUI16(unsigned int mNumVertices) { - return ( mNumVertices < (1u<<16) ); + return (mNumVertices < (1u << 16)); } + // ----------------------------------------------------------------------------------- -void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh ) { - if(Read(stream) != ASSBIN_CHUNK_AIMESH) +void AssbinImporter::ReadBinaryMesh(IOStream *stream, aiMesh *mesh) { + if (Read(stream) != ASSBIN_CHUNK_AIMESH) throw DeadlyImportError("Magic chunk identifiers are wrong!"); - /*uint32_t size =*/ Read(stream); + /*uint32_t size =*/Read(stream); mesh->mPrimitiveTypes = Read(stream); mesh->mNumVertices = Read(stream); @@ -329,48 +330,48 @@ void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh ) { if (c & ASSBIN_MESH_HAS_POSITIONS) { if (shortened) { - ReadBounds(stream,mesh->mVertices,mesh->mNumVertices); - } else { + ReadBounds(stream, mesh->mVertices, mesh->mNumVertices); + } else { // else write as usual mesh->mVertices = new aiVector3D[mesh->mNumVertices]; - ReadArray(stream,mesh->mVertices,mesh->mNumVertices); + ReadArray(stream, mesh->mVertices, mesh->mNumVertices); } } if (c & ASSBIN_MESH_HAS_NORMALS) { if (shortened) { - ReadBounds(stream,mesh->mNormals,mesh->mNumVertices); - } else { + ReadBounds(stream, mesh->mNormals, mesh->mNumVertices); + } else { // else write as usual mesh->mNormals = new aiVector3D[mesh->mNumVertices]; - ReadArray(stream,mesh->mNormals,mesh->mNumVertices); + ReadArray(stream, mesh->mNormals, mesh->mNumVertices); } } if (c & ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS) { if (shortened) { - ReadBounds(stream,mesh->mTangents,mesh->mNumVertices); - ReadBounds(stream,mesh->mBitangents,mesh->mNumVertices); - } else { + ReadBounds(stream, mesh->mTangents, mesh->mNumVertices); + ReadBounds(stream, mesh->mBitangents, mesh->mNumVertices); + } else { // else write as usual mesh->mTangents = new aiVector3D[mesh->mNumVertices]; - ReadArray(stream,mesh->mTangents,mesh->mNumVertices); + ReadArray(stream, mesh->mTangents, mesh->mNumVertices); mesh->mBitangents = new aiVector3D[mesh->mNumVertices]; - ReadArray(stream,mesh->mBitangents,mesh->mNumVertices); + ReadArray(stream, mesh->mBitangents, mesh->mNumVertices); } } - for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) { + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS; ++n) { if (!(c & ASSBIN_MESH_HAS_COLOR(n))) { break; } if (shortened) { - ReadBounds(stream,mesh->mColors[n],mesh->mNumVertices); - } else { + ReadBounds(stream, mesh->mColors[n], mesh->mNumVertices); + } else { // else write as usual mesh->mColors[n] = new aiColor4D[mesh->mNumVertices]; - ReadArray(stream,mesh->mColors[n],mesh->mNumVertices); + ReadArray(stream, mesh->mColors[n], mesh->mNumVertices); } } - for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) { + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++n) { if (!(c & ASSBIN_MESH_HAS_TEXCOORD(n))) { break; } @@ -379,11 +380,11 @@ void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh ) { mesh->mNumUVComponents[n] = Read(stream); if (shortened) { - ReadBounds(stream,mesh->mTextureCoords[n],mesh->mNumVertices); - } else { + ReadBounds(stream, mesh->mTextureCoords[n], mesh->mNumVertices); + } else { // else write as usual mesh->mTextureCoords[n] = new aiVector3D[mesh->mNumVertices]; - ReadArray(stream,mesh->mTextureCoords[n],mesh->mNumVertices); + ReadArray(stream, mesh->mTextureCoords[n], mesh->mNumVertices); } } @@ -393,20 +394,20 @@ void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh ) { // using Assimp's standard hashing function. if (shortened) { Read(stream); - } else { + } else { // else write as usual // if there are less than 2^16 vertices, we can simply use 16 bit integers ... mesh->mFaces = new aiFace[mesh->mNumFaces]; - for (unsigned int i = 0; i < mesh->mNumFaces;++i) { - aiFace& f = mesh->mFaces[i]; + for (unsigned int i = 0; i < mesh->mNumFaces; ++i) { + aiFace &f = mesh->mFaces[i]; static_assert(AI_MAX_FACE_INDICES <= 0xffff, "AI_MAX_FACE_INDICES <= 0xffff"); f.mNumIndices = Read(stream); f.mIndices = new unsigned int[f.mNumIndices]; - for (unsigned int a = 0; a < f.mNumIndices;++a) { + for (unsigned int a = 0; a < f.mNumIndices; ++a) { // Check if unsigned short ( 16 bit ) are big enought for the indices - if ( fitsIntoUI16( mesh->mNumVertices ) ) { + if (fitsIntoUI16(mesh->mNumVertices)) { f.mIndices[a] = Read(stream); } else { f.mIndices[a] = Read(stream); @@ -417,19 +418,19 @@ void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh ) { // write bones if (mesh->mNumBones) { - mesh->mBones = new C_STRUCT aiBone*[mesh->mNumBones]; - for (unsigned int a = 0; a < mesh->mNumBones;++a) { + mesh->mBones = new C_STRUCT aiBone *[mesh->mNumBones]; + for (unsigned int a = 0; a < mesh->mNumBones; ++a) { mesh->mBones[a] = new aiBone(); - ReadBinaryBone(stream,mesh->mBones[a]); + ReadBinaryBone(stream, mesh->mBones[a]); } } } // ----------------------------------------------------------------------------------- -void AssbinImporter::ReadBinaryMaterialProperty(IOStream * stream, aiMaterialProperty* prop) { - if(Read(stream) != ASSBIN_CHUNK_AIMATERIALPROPERTY) +void AssbinImporter::ReadBinaryMaterialProperty(IOStream *stream, aiMaterialProperty *prop) { + if (Read(stream) != ASSBIN_CHUNK_AIMATERIALPROPERTY) throw DeadlyImportError("Magic chunk identifiers are wrong!"); - /*uint32_t size =*/ Read(stream); + /*uint32_t size =*/Read(stream); prop->mKey = Read(stream); prop->mSemantic = Read(stream); @@ -437,36 +438,34 @@ void AssbinImporter::ReadBinaryMaterialProperty(IOStream * stream, aiMaterialPro prop->mDataLength = Read(stream); prop->mType = (aiPropertyTypeInfo)Read(stream); - prop->mData = new char [ prop->mDataLength ]; - stream->Read(prop->mData,1,prop->mDataLength); + prop->mData = new char[prop->mDataLength]; + stream->Read(prop->mData, 1, prop->mDataLength); } // ----------------------------------------------------------------------------------- -void AssbinImporter::ReadBinaryMaterial(IOStream * stream, aiMaterial* mat) { - if(Read(stream) != ASSBIN_CHUNK_AIMATERIAL) +void AssbinImporter::ReadBinaryMaterial(IOStream *stream, aiMaterial *mat) { + if (Read(stream) != ASSBIN_CHUNK_AIMATERIAL) throw DeadlyImportError("Magic chunk identifiers are wrong!"); - /*uint32_t size =*/ Read(stream); + /*uint32_t size =*/Read(stream); mat->mNumAllocated = mat->mNumProperties = Read(stream); - if (mat->mNumProperties) - { - if (mat->mProperties) - { + if (mat->mNumProperties) { + if (mat->mProperties) { delete[] mat->mProperties; } - mat->mProperties = new aiMaterialProperty*[mat->mNumProperties]; - for (unsigned int i = 0; i < mat->mNumProperties;++i) { + mat->mProperties = new aiMaterialProperty *[mat->mNumProperties]; + for (unsigned int i = 0; i < mat->mNumProperties; ++i) { mat->mProperties[i] = new aiMaterialProperty(); - ReadBinaryMaterialProperty( stream, mat->mProperties[i]); + ReadBinaryMaterialProperty(stream, mat->mProperties[i]); } } } // ----------------------------------------------------------------------------------- -void AssbinImporter::ReadBinaryNodeAnim(IOStream * stream, aiNodeAnim* nd) { - if(Read(stream) != ASSBIN_CHUNK_AINODEANIM) +void AssbinImporter::ReadBinaryNodeAnim(IOStream *stream, aiNodeAnim *nd) { + if (Read(stream) != ASSBIN_CHUNK_AINODEANIM) throw DeadlyImportError("Magic chunk identifiers are wrong!"); - /*uint32_t size =*/ Read(stream); + /*uint32_t size =*/Read(stream); nd->mNodeName = Read(stream); nd->mNumPositionKeys = Read(stream); @@ -477,82 +476,82 @@ void AssbinImporter::ReadBinaryNodeAnim(IOStream * stream, aiNodeAnim* nd) { if (nd->mNumPositionKeys) { if (shortened) { - ReadBounds(stream,nd->mPositionKeys,nd->mNumPositionKeys); + ReadBounds(stream, nd->mPositionKeys, nd->mNumPositionKeys); } // else write as usual else { nd->mPositionKeys = new aiVectorKey[nd->mNumPositionKeys]; - ReadArray(stream,nd->mPositionKeys,nd->mNumPositionKeys); + ReadArray(stream, nd->mPositionKeys, nd->mNumPositionKeys); } } if (nd->mNumRotationKeys) { if (shortened) { - ReadBounds(stream,nd->mRotationKeys,nd->mNumRotationKeys); + ReadBounds(stream, nd->mRotationKeys, nd->mNumRotationKeys); - } else { + } else { // else write as usual nd->mRotationKeys = new aiQuatKey[nd->mNumRotationKeys]; - ReadArray(stream,nd->mRotationKeys,nd->mNumRotationKeys); + ReadArray(stream, nd->mRotationKeys, nd->mNumRotationKeys); } } if (nd->mNumScalingKeys) { if (shortened) { - ReadBounds(stream,nd->mScalingKeys,nd->mNumScalingKeys); + ReadBounds(stream, nd->mScalingKeys, nd->mNumScalingKeys); - } else { + } else { // else write as usual nd->mScalingKeys = new aiVectorKey[nd->mNumScalingKeys]; - ReadArray(stream,nd->mScalingKeys,nd->mNumScalingKeys); + ReadArray(stream, nd->mScalingKeys, nd->mNumScalingKeys); } } } // ----------------------------------------------------------------------------------- -void AssbinImporter::ReadBinaryAnim( IOStream * stream, aiAnimation* anim ) { - if(Read(stream) != ASSBIN_CHUNK_AIANIMATION) +void AssbinImporter::ReadBinaryAnim(IOStream *stream, aiAnimation *anim) { + if (Read(stream) != ASSBIN_CHUNK_AIANIMATION) throw DeadlyImportError("Magic chunk identifiers are wrong!"); - /*uint32_t size =*/ Read(stream); + /*uint32_t size =*/Read(stream); - anim->mName = Read (stream); - anim->mDuration = Read (stream); - anim->mTicksPerSecond = Read (stream); + anim->mName = Read(stream); + anim->mDuration = Read(stream); + anim->mTicksPerSecond = Read(stream); anim->mNumChannels = Read(stream); if (anim->mNumChannels) { - anim->mChannels = new aiNodeAnim*[ anim->mNumChannels ]; - for (unsigned int a = 0; a < anim->mNumChannels;++a) { + anim->mChannels = new aiNodeAnim *[anim->mNumChannels]; + for (unsigned int a = 0; a < anim->mNumChannels; ++a) { anim->mChannels[a] = new aiNodeAnim(); - ReadBinaryNodeAnim(stream,anim->mChannels[a]); + ReadBinaryNodeAnim(stream, anim->mChannels[a]); } } } // ----------------------------------------------------------------------------------- -void AssbinImporter::ReadBinaryTexture(IOStream * stream, aiTexture* tex) { - if(Read(stream) != ASSBIN_CHUNK_AITEXTURE) +void AssbinImporter::ReadBinaryTexture(IOStream *stream, aiTexture *tex) { + if (Read(stream) != ASSBIN_CHUNK_AITEXTURE) throw DeadlyImportError("Magic chunk identifiers are wrong!"); - /*uint32_t size =*/ Read(stream); + /*uint32_t size =*/Read(stream); tex->mWidth = Read(stream); tex->mHeight = Read(stream); - stream->Read( tex->achFormatHint, sizeof(char), HINTMAXTEXTURELEN - 1 ); + stream->Read(tex->achFormatHint, sizeof(char), HINTMAXTEXTURELEN - 1); - if(!shortened) { + if (!shortened) { if (!tex->mHeight) { - tex->pcData = new aiTexel[ tex->mWidth ]; - stream->Read(tex->pcData,1,tex->mWidth); + tex->pcData = new aiTexel[tex->mWidth]; + stream->Read(tex->pcData, 1, tex->mWidth); } else { - tex->pcData = new aiTexel[ tex->mWidth*tex->mHeight ]; - stream->Read(tex->pcData,1,tex->mWidth*tex->mHeight*4); + tex->pcData = new aiTexel[tex->mWidth * tex->mHeight]; + stream->Read(tex->pcData, 1, tex->mWidth * tex->mHeight * 4); } } } // ----------------------------------------------------------------------------------- -void AssbinImporter::ReadBinaryLight( IOStream * stream, aiLight* l ) { - if(Read(stream) != ASSBIN_CHUNK_AILIGHT) +void AssbinImporter::ReadBinaryLight(IOStream *stream, aiLight *l) { + if (Read(stream) != ASSBIN_CHUNK_AILIGHT) throw DeadlyImportError("Magic chunk identifiers are wrong!"); - /*uint32_t size =*/ Read(stream); + /*uint32_t size =*/Read(stream); l->mName = Read(stream); l->mType = (aiLightSourceType)Read(stream); @@ -574,10 +573,10 @@ void AssbinImporter::ReadBinaryLight( IOStream * stream, aiLight* l ) { } // ----------------------------------------------------------------------------------- -void AssbinImporter::ReadBinaryCamera( IOStream * stream, aiCamera* cam ) { - if(Read(stream) != ASSBIN_CHUNK_AICAMERA) +void AssbinImporter::ReadBinaryCamera(IOStream *stream, aiCamera *cam) { + if (Read(stream) != ASSBIN_CHUNK_AICAMERA) throw DeadlyImportError("Magic chunk identifiers are wrong!"); - /*uint32_t size =*/ Read(stream); + /*uint32_t size =*/Read(stream); cam->mName = Read(stream); cam->mPosition = Read(stream); @@ -590,141 +589,139 @@ void AssbinImporter::ReadBinaryCamera( IOStream * stream, aiCamera* cam ) { } // ----------------------------------------------------------------------------------- -void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene ) { - if(Read(stream) != ASSBIN_CHUNK_AISCENE) +void AssbinImporter::ReadBinaryScene(IOStream *stream, aiScene *scene) { + if (Read(stream) != ASSBIN_CHUNK_AISCENE) throw DeadlyImportError("Magic chunk identifiers are wrong!"); - /*uint32_t size =*/ Read(stream); + /*uint32_t size =*/Read(stream); - scene->mFlags = Read(stream); - scene->mNumMeshes = Read(stream); - scene->mNumMaterials = Read(stream); + scene->mFlags = Read(stream); + scene->mNumMeshes = Read(stream); + scene->mNumMaterials = Read(stream); scene->mNumAnimations = Read(stream); - scene->mNumTextures = Read(stream); - scene->mNumLights = Read(stream); - scene->mNumCameras = Read(stream); + scene->mNumTextures = Read(stream); + scene->mNumLights = Read(stream); + scene->mNumCameras = Read(stream); // Read node graph //scene->mRootNode = new aiNode[1]; - ReadBinaryNode( stream, &scene->mRootNode, (aiNode*)NULL ); + ReadBinaryNode(stream, &scene->mRootNode, (aiNode *)NULL); // Read all meshes if (scene->mNumMeshes) { - scene->mMeshes = new aiMesh*[scene->mNumMeshes]; - memset(scene->mMeshes, 0, scene->mNumMeshes*sizeof(aiMesh*)); - for (unsigned int i = 0; i < scene->mNumMeshes;++i) { + scene->mMeshes = new aiMesh *[scene->mNumMeshes]; + memset(scene->mMeshes, 0, scene->mNumMeshes * sizeof(aiMesh *)); + for (unsigned int i = 0; i < scene->mNumMeshes; ++i) { scene->mMeshes[i] = new aiMesh(); - ReadBinaryMesh( stream,scene->mMeshes[i]); + ReadBinaryMesh(stream, scene->mMeshes[i]); } } // Read materials if (scene->mNumMaterials) { - scene->mMaterials = new aiMaterial*[scene->mNumMaterials]; - memset(scene->mMaterials, 0, scene->mNumMaterials*sizeof(aiMaterial*)); - for (unsigned int i = 0; i< scene->mNumMaterials; ++i) { + scene->mMaterials = new aiMaterial *[scene->mNumMaterials]; + memset(scene->mMaterials, 0, scene->mNumMaterials * sizeof(aiMaterial *)); + for (unsigned int i = 0; i < scene->mNumMaterials; ++i) { scene->mMaterials[i] = new aiMaterial(); - ReadBinaryMaterial(stream,scene->mMaterials[i]); + ReadBinaryMaterial(stream, scene->mMaterials[i]); } } // Read all animations if (scene->mNumAnimations) { - scene->mAnimations = new aiAnimation*[scene->mNumAnimations]; - memset(scene->mAnimations, 0, scene->mNumAnimations*sizeof(aiAnimation*)); - for (unsigned int i = 0; i < scene->mNumAnimations;++i) { + scene->mAnimations = new aiAnimation *[scene->mNumAnimations]; + memset(scene->mAnimations, 0, scene->mNumAnimations * sizeof(aiAnimation *)); + for (unsigned int i = 0; i < scene->mNumAnimations; ++i) { scene->mAnimations[i] = new aiAnimation(); - ReadBinaryAnim(stream,scene->mAnimations[i]); + ReadBinaryAnim(stream, scene->mAnimations[i]); } } // Read all textures if (scene->mNumTextures) { - scene->mTextures = new aiTexture*[scene->mNumTextures]; - memset(scene->mTextures, 0, scene->mNumTextures*sizeof(aiTexture*)); - for (unsigned int i = 0; i < scene->mNumTextures;++i) { + scene->mTextures = new aiTexture *[scene->mNumTextures]; + memset(scene->mTextures, 0, scene->mNumTextures * sizeof(aiTexture *)); + for (unsigned int i = 0; i < scene->mNumTextures; ++i) { scene->mTextures[i] = new aiTexture(); - ReadBinaryTexture(stream,scene->mTextures[i]); + ReadBinaryTexture(stream, scene->mTextures[i]); } } // Read lights if (scene->mNumLights) { - scene->mLights = new aiLight*[scene->mNumLights]; - memset(scene->mLights, 0, scene->mNumLights*sizeof(aiLight*)); - for (unsigned int i = 0; i < scene->mNumLights;++i) { + scene->mLights = new aiLight *[scene->mNumLights]; + memset(scene->mLights, 0, scene->mNumLights * sizeof(aiLight *)); + for (unsigned int i = 0; i < scene->mNumLights; ++i) { scene->mLights[i] = new aiLight(); - ReadBinaryLight(stream,scene->mLights[i]); + ReadBinaryLight(stream, scene->mLights[i]); } } // Read cameras if (scene->mNumCameras) { - scene->mCameras = new aiCamera*[scene->mNumCameras]; - memset(scene->mCameras, 0, scene->mNumCameras*sizeof(aiCamera*)); - for (unsigned int i = 0; i < scene->mNumCameras;++i) { + scene->mCameras = new aiCamera *[scene->mNumCameras]; + memset(scene->mCameras, 0, scene->mNumCameras * sizeof(aiCamera *)); + for (unsigned int i = 0; i < scene->mNumCameras; ++i) { scene->mCameras[i] = new aiCamera(); - ReadBinaryCamera(stream,scene->mCameras[i]); + ReadBinaryCamera(stream, scene->mCameras[i]); } } - } // ----------------------------------------------------------------------------------- -void AssbinImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler ) { - IOStream * stream = pIOHandler->Open(pFile,"rb"); +void AssbinImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) { + IOStream *stream = pIOHandler->Open(pFile, "rb"); if (nullptr == stream) { return; } // signature - stream->Seek( 44, aiOrigin_CUR ); + stream->Seek(44, aiOrigin_CUR); unsigned int versionMajor = Read(stream); unsigned int versionMinor = Read(stream); if (versionMinor != ASSBIN_VERSION_MINOR || versionMajor != ASSBIN_VERSION_MAJOR) { - throw DeadlyImportError( "Invalid version, data format not compatible!" ); + throw DeadlyImportError("Invalid version, data format not compatible!"); } - /*unsigned int versionRevision =*/ Read(stream); - /*unsigned int compileFlags =*/ Read(stream); + /*unsigned int versionRevision =*/Read(stream); + /*unsigned int compileFlags =*/Read(stream); shortened = Read(stream) > 0; compressed = Read(stream) > 0; if (shortened) - throw DeadlyImportError( "Shortened binaries are not supported!" ); + throw DeadlyImportError("Shortened binaries are not supported!"); - stream->Seek( 256, aiOrigin_CUR ); // original filename - stream->Seek( 128, aiOrigin_CUR ); // options - stream->Seek( 64, aiOrigin_CUR ); // padding + stream->Seek(256, aiOrigin_CUR); // original filename + stream->Seek(128, aiOrigin_CUR); // options + stream->Seek(64, aiOrigin_CUR); // padding if (compressed) { uLongf uncompressedSize = Read(stream); uLongf compressedSize = static_cast(stream->FileSize() - stream->Tell()); - unsigned char * compressedData = new unsigned char[ compressedSize ]; - size_t len = stream->Read( compressedData, 1, compressedSize ); + unsigned char *compressedData = new unsigned char[compressedSize]; + size_t len = stream->Read(compressedData, 1, compressedSize); ai_assert(len == compressedSize); - unsigned char * uncompressedData = new unsigned char[ uncompressedSize ]; + unsigned char *uncompressedData = new unsigned char[uncompressedSize]; - int res = uncompress( uncompressedData, &uncompressedSize, compressedData, (uLong) len ); - if(res != Z_OK) - { - delete [] uncompressedData; - delete [] compressedData; + int res = uncompress(uncompressedData, &uncompressedSize, compressedData, (uLong)len); + if (res != Z_OK) { + delete[] uncompressedData; + delete[] compressedData; pIOHandler->Close(stream); throw DeadlyImportError("Zlib decompression failed."); } - MemoryIOStream io( uncompressedData, uncompressedSize ); + MemoryIOStream io(uncompressedData, uncompressedSize); - ReadBinaryScene(&io,pScene); + ReadBinaryScene(&io, pScene); delete[] uncompressedData; delete[] compressedData; } else { - ReadBinaryScene(stream,pScene); + ReadBinaryScene(stream, pScene); } pIOHandler->Close(stream); diff --git a/code/Assjson/cencode.h b/code/Assjson/cencode.h index c1e3464af..6bf76724e 100644 --- a/code/Assjson/cencode.h +++ b/code/Assjson/cencode.h @@ -8,6 +8,10 @@ For details, see http://sourceforge.net/projects/libb64 #ifndef BASE64_CENCODE_H #define BASE64_CENCODE_H +#ifdef _WIN32 +#pragma warning(disable : 4127 ) +#endif // _WIN32 + typedef enum { step_A, step_B, step_C diff --git a/code/Assjson/json_exporter.cpp b/code/Assjson/json_exporter.cpp index e9fa72496..4a8e4599e 100644 --- a/code/Assjson/json_exporter.cpp +++ b/code/Assjson/json_exporter.cpp @@ -91,20 +91,20 @@ public: base64_encodestate s; base64_init_encodestate(&s); - char* const out = new char[std::max(len * 2, static_cast(16u))]; - const int n = base64_encode_block(reinterpret_cast(buffer), static_cast(len), out, &s); - out[n + base64_encode_blockend(out + n, &s)] = '\0'; + char* const cur_out = new char[std::max(len * 2, static_cast(16u))]; + const int n = base64_encode_block(reinterpret_cast(buffer), static_cast(len), cur_out, &s); + cur_out[n + base64_encode_blockend(cur_out + n, &s)] = '\0'; // base64 encoding may add newlines, but JSON strings may not contain 'real' newlines // (only escaped ones). Remove any newlines in out. - for (char* cur = out; *cur; ++cur) { + for (char *cur = cur_out; *cur; ++cur) { if (*cur == '\n') { *cur = ' '; } } - buff << '\"' << out << "\"\n"; - delete[] out; + buff << '\"' << cur_out << "\"\n"; + delete[] cur_out; } void StartObj(bool is_element = false) { @@ -464,8 +464,8 @@ void Write(JSONWriter& out, const aiMaterial& ai, bool is_elem = true) { case aiPTI_Float: if (prop->mDataLength / sizeof(float) > 1) { out.StartArray(); - for (unsigned int i = 0; i < prop->mDataLength / sizeof(float); ++i) { - out.Element(reinterpret_cast(prop->mData)[i]); + for (unsigned int ii = 0; ii < prop->mDataLength / sizeof(float); ++ii) { + out.Element(reinterpret_cast(prop->mData)[ii]); } out.EndArray(); } @@ -477,8 +477,8 @@ void Write(JSONWriter& out, const aiMaterial& ai, bool is_elem = true) { case aiPTI_Integer: if (prop->mDataLength / sizeof(int) > 1) { out.StartArray(); - for (unsigned int i = 0; i < prop->mDataLength / sizeof(int); ++i) { - out.Element(reinterpret_cast(prop->mData)[i]); + for (unsigned int ii = 0; ii < prop->mDataLength / sizeof(int); ++ii) { + out.Element(reinterpret_cast(prop->mData)[ii]); } out.EndArray(); } else { diff --git a/code/Assxml/AssxmlFileWriter.cpp b/code/Assxml/AssxmlFileWriter.cpp index 0ed59e509..3a88d5052 100644 --- a/code/Assxml/AssxmlFileWriter.cpp +++ b/code/Assxml/AssxmlFileWriter.cpp @@ -373,25 +373,25 @@ void WriteDump(const char* pFile, const char* cmd, const aiScene* scene, IOStrea ioprintf(io," size=\"%i\">\n\t\t\t\t", static_cast(prop->mDataLength/sizeof(float))); - for (unsigned int p = 0; p < prop->mDataLength/sizeof(float);++p) { - ioprintf(io,"%f ",*((float*)(prop->mData+p*sizeof(float)))); + for (unsigned int pp = 0; pp < prop->mDataLength/sizeof(float);++pp) { + ioprintf(io,"%f ",*((float*)(prop->mData+pp*sizeof(float)))); } } else if (prop->mType == aiPTI_Integer) { ioprintf(io," size=\"%i\">\n\t\t\t\t", static_cast(prop->mDataLength/sizeof(int))); - for (unsigned int p = 0; p < prop->mDataLength/sizeof(int);++p) { - ioprintf(io,"%i ",*((int*)(prop->mData+p*sizeof(int)))); + for (unsigned int pp = 0; pp < prop->mDataLength/sizeof(int);++pp) { + ioprintf(io,"%i ",*((int*)(prop->mData+pp*sizeof(int)))); } } else if (prop->mType == aiPTI_Buffer) { ioprintf(io," size=\"%i\">\n\t\t\t\t", static_cast(prop->mDataLength)); - for (unsigned int p = 0; p < prop->mDataLength;++p) { - ioprintf(io,"%2x ",prop->mData[p]); - if (p && 0 == p%30) { + for (unsigned int pp = 0; pp< prop->mDataLength;++pp) { + ioprintf(io,"%2x ",prop->mData[pp]); + if (pp && 0 == pp%30) { ioprintf(io,"\n\t\t\t\t"); } } diff --git a/code/B3D/B3DImporter.cpp b/code/B3D/B3DImporter.cpp index 07336df65..dbf002bd1 100644 --- a/code/B3D/B3DImporter.cpp +++ b/code/B3D/B3DImporter.cpp @@ -155,36 +155,37 @@ AI_WONT_RETURN void B3DImporter::Fail( string str ){ // ------------------------------------------------------------------------------------------------ int B3DImporter::ReadByte(){ - if( _pos<_buf.size() ) { - return _buf[_pos++]; - } - - Fail( "EOF" ); - return 0; + if (_pos > _buf.size()) { + Fail("EOF"); + } + + return _buf[_pos++]; } // ------------------------------------------------------------------------------------------------ int B3DImporter::ReadInt(){ - if( _pos+4<=_buf.size() ){ - int n; - memcpy(&n, &_buf[_pos], 4); - _pos+=4; - return n; + if (_pos + 4 > _buf.size()) { + Fail("EOF"); } - Fail( "EOF" ); - return 0; + + int n; + memcpy(&n, &_buf[_pos], 4); + _pos+=4; + + return n; } // ------------------------------------------------------------------------------------------------ -float B3DImporter::ReadFloat(){ - if( _pos+4<=_buf.size() ){ - float n; - memcpy(&n, &_buf[_pos], 4); - _pos+=4; - return n; - } - Fail( "EOF" ); - return 0.0f; +float B3DImporter::ReadFloat() { + if (_pos + 4 > _buf.size()) { + Fail("EOF"); + } + + float n; + memcpy(&n, &_buf[_pos], 4); + _pos+=4; + + return n; } // ------------------------------------------------------------------------------------------------ @@ -214,6 +215,9 @@ aiQuaternion B3DImporter::ReadQuat(){ // ------------------------------------------------------------------------------------------------ string B3DImporter::ReadString(){ + if (_pos > _buf.size()) { + Fail("EOF"); + } string str; while( _pos<_buf.size() ){ char c=(char)ReadByte(); @@ -222,7 +226,6 @@ string B3DImporter::ReadString(){ } str+=c; } - Fail( "EOF" ); return string(); } @@ -247,7 +250,7 @@ void B3DImporter::ExitChunk(){ } // ------------------------------------------------------------------------------------------------ -unsigned B3DImporter::ChunkSize(){ +size_t B3DImporter::ChunkSize(){ return _stack.back()-_pos; } // ------------------------------------------------------------------------------------------------ @@ -355,13 +358,13 @@ void B3DImporter::ReadVRTS(){ Fail( "Bad texcoord data" ); } - int sz=12+(_vflags&1?12:0)+(_vflags&2?16:0)+(_tcsets*_tcsize*4); - int n_verts=ChunkSize()/sz; + int sz = 12+(_vflags&1?12:0)+(_vflags&2?16:0)+(_tcsets*_tcsize*4); + size_t n_verts = ChunkSize()/sz; int v0=static_cast(_vertices.size()); _vertices.resize( v0+n_verts ); - for( int i=0;imNumFaces = 0; mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; - int n_tris = ChunkSize() / 12; + size_t n_tris = ChunkSize() / 12; aiFace *face = mesh->mFaces = new aiFace[n_tris]; - for (int i = 0; i < n_tris; ++i) { + for (unsigned int i = 0; i < n_tris; ++i) { int i0 = ReadInt() + v0; int i1 = ReadInt() + v0; int i2 = ReadInt() + v0; @@ -463,7 +466,7 @@ void B3DImporter::ReadBONE(int id) { Vertex &v = _vertices[vertex]; for (int i = 0; i < 4; ++i) { if (!v.weights[i]) { - v.bones[i] = id; + v.bones[i] = static_cast(id); v.weights[i] = weight; break; } @@ -547,24 +550,24 @@ aiNode *B3DImporter::ReadNODE( aiNode *parent ){ vector children; while( ChunkSize() ){ - string t=ReadChunk(); - if( t=="MESH" ){ + const string chunk = ReadChunk(); + if (chunk == "MESH") { unsigned int n= static_cast(_meshes.size()); ReadMESH(); for( unsigned int i=n;i(_meshes.size());++i ){ meshes.push_back( i ); } - }else if( t=="BONE" ){ + } else if (chunk == "BONE") { ReadBONE( nodeid ); - }else if( t=="ANIM" ){ + } else if (chunk == "ANIM") { ReadANIM(); - }else if( t=="KEYS" ){ + } else if (chunk == "KEYS") { if( !nodeAnim ){ nodeAnim.reset(new aiNodeAnim); nodeAnim->mNodeName=node->mName; } ReadKEYS( nodeAnim.get() ); - }else if( t=="NODE" ){ + } else if (chunk == "NODE") { aiNode *child=ReadNODE( node ); children.push_back( child ); } @@ -613,12 +616,12 @@ void B3DImporter::ReadBB3D( aiScene *scene ){ } while( ChunkSize() ){ - string t=ReadChunk(); - if( t=="TEXS" ){ + const string chunk = ReadChunk(); + if (chunk == "TEXS") { ReadTEXS(); - }else if( t=="BRUS" ){ + } else if (chunk == "BRUS") { ReadBRUS(); - }else if( t=="NODE" ){ + } else if (chunk == "NODE") { ReadNODE( 0 ); } ExitChunk(); @@ -656,48 +659,51 @@ void B3DImporter::ReadBB3D( aiScene *scene ){ vector< vector > vweights( _nodes.size() ); - for( int i=0;imIndices[j]]; + for (int vertIdx = 0; vertIdx < n_verts; vertIdx += 3) { + for (int faceIndex = 0; faceIndex < 3; ++faceIndex) { + Vertex &v = _vertices[face->mIndices[faceIndex]]; *mv++=v.vertex; if( mn ) *mn++=v.normal; if( mc ) *mc++=v.texcoords; - face->mIndices[j]=i+j; + face->mIndices[faceIndex] = vertIdx + faceIndex; for( int k=0;k<4;++k ){ - if( !v.weights[k] ) break; + if( !v.weights[k] ) + break; - int bone=v.bones[k]; - float weight=v.weights[k]; + int bone = v.bones[k]; + float weight = v.weights[k]; - vweights[bone].push_back( aiVertexWeight(i+j,weight) ); + vweights[bone].push_back(aiVertexWeight(vertIdx + faceIndex, weight)); } } ++face; } vector bones; - for(size_t i=0;i &weights=vweights[i]; - if( !weights.size() ) continue; + for (size_t weightIndx = 0; weightIndx < vweights.size(); ++weightIndx) { + vector &weights = vweights[weightIndx]; + if (!weights.size()) { + continue; + } - aiBone *bone=new aiBone; + aiBone *bone = new aiBone; bones.push_back( bone ); - aiNode *bnode=_nodes[i]; + aiNode *bnode = _nodes[weightIndx]; - bone->mName=bnode->mName; - bone->mNumWeights= static_cast(weights.size()); - bone->mWeights=to_array( weights ); + bone->mName = bnode->mName; + bone->mNumWeights = static_cast(weights.size()); + bone->mWeights = to_array( weights ); - aiMatrix4x4 mat=bnode->mTransformation; + aiMatrix4x4 mat = bnode->mTransformation; while( bnode->mParent ){ bnode=bnode->mParent; mat=bnode->mTransformation * mat; } - bone->mOffsetMatrix=mat.Inverse(); + bone->mOffsetMatrix = mat.Inverse(); } mesh->mNumBones= static_cast(bones.size()); mesh->mBones=to_array( bones ); diff --git a/code/B3D/B3DImporter.h b/code/B3D/B3DImporter.h index f0568dd16..17f15963d 100644 --- a/code/B3D/B3DImporter.h +++ b/code/B3D/B3DImporter.h @@ -82,7 +82,7 @@ private: std::string ReadString(); std::string ReadChunk(); void ExitChunk(); - unsigned ChunkSize(); + size_t ChunkSize(); template T *to_array( const std::vector &v ); @@ -112,10 +112,10 @@ private: void ReadBB3D( aiScene *scene ); - unsigned _pos; + size_t _pos; // unsigned _size; std::vector _buf; - std::vector _stack; + std::vector _stack; std::vector _textures; std::vector > _materials; diff --git a/code/Blender/BlenderLoader.cpp b/code/Blender/BlenderLoader.cpp index 93e6d1589..b4e07617a 100644 --- a/code/Blender/BlenderLoader.cpp +++ b/code/Blender/BlenderLoader.cpp @@ -429,7 +429,7 @@ void BlenderImporter::ResolveImage(aiMaterial* out, const Material* mat, const M name.length = 1+ ASSIMP_itoa10(name.data+1,static_cast(MAXLEN-1), static_cast(conv_data.textures->size())); conv_data.textures->push_back(new aiTexture()); - aiTexture* tex = conv_data.textures->back(); + aiTexture* curTex = conv_data.textures->back(); // usually 'img->name' will be the original file name of the embedded textures, // so we can extract the file extension from it. @@ -439,19 +439,19 @@ void BlenderImporter::ResolveImage(aiMaterial* out, const Material* mat, const M --s; } - tex->achFormatHint[0] = s+1>e ? '\0' : ::tolower( s[1] ); - tex->achFormatHint[1] = s+2>e ? '\0' : ::tolower( s[2] ); - tex->achFormatHint[2] = s+3>e ? '\0' : ::tolower( s[3] ); - tex->achFormatHint[3] = '\0'; + curTex->achFormatHint[0] = s + 1 > e ? '\0' : (char)::tolower(s[1]); + curTex->achFormatHint[1] = s + 2 > e ? '\0' : (char)::tolower(s[2]); + curTex->achFormatHint[2] = s + 3 > e ? '\0' : (char)::tolower(s[3]); + curTex->achFormatHint[3] = '\0'; // tex->mHeight = 0; - tex->mWidth = img->packedfile->size; - uint8_t* ch = new uint8_t[tex->mWidth]; + curTex->mWidth = img->packedfile->size; + uint8_t *ch = new uint8_t[curTex->mWidth]; conv_data.db.reader->SetCurrentPos(static_cast( img->packedfile->data->val)); - conv_data.db.reader->CopyAndAdvance(ch,tex->mWidth); + conv_data.db.reader->CopyAndAdvance(ch, curTex->mWidth); - tex->pcData = reinterpret_cast(ch); + curTex->pcData = reinterpret_cast(ch); LogInfo("Reading embedded texture, original file was "+std::string(img->name)); } else { @@ -1078,9 +1078,9 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co const aiFace& f = out->mFaces[out->mNumFaces++]; aiVector3D* vo = &out->mTextureCoords[0][out->mNumVertices]; - for (unsigned int i = 0; i < f.mNumIndices; ++i,++vo,++out->mNumVertices) { - vo->x = v->uv[i][0]; - vo->y = v->uv[i][1]; + for (unsigned int j = 0; j < f.mNumIndices; ++j,++vo,++out->mNumVertices) { + vo->x = v->uv[j][0]; + vo->y = v->uv[j][1]; } } @@ -1098,8 +1098,7 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co vo->x = uv.uv[0]; vo->y = uv.uv[1]; } - } - else { + } else { // create textureCoords for every mapped tex for (uint32_t m = 0; m < itMatTexUvMapping->second.size(); ++m) { const MLoopUV *tm = itMatTexUvMapping->second[m]; @@ -1139,9 +1138,9 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co const aiFace& f = out->mFaces[out->mNumFaces++]; aiVector3D* vo = &out->mTextureCoords[0][out->mNumVertices]; - for (unsigned int i = 0; i < f.mNumIndices; ++i,++vo,++out->mNumVertices) { - vo->x = v->uv[i][0]; - vo->y = v->uv[i][1]; + for (unsigned int j = 0; j < f.mNumIndices; ++j,++vo,++out->mNumVertices) { + vo->x = v->uv[j][0]; + vo->y = v->uv[j][1]; } } } diff --git a/code/Blender/BlenderModifier.cpp b/code/Blender/BlenderModifier.cpp index 6f8a5d7ee..2d99fbbc9 100644 --- a/code/Blender/BlenderModifier.cpp +++ b/code/Blender/BlenderModifier.cpp @@ -57,52 +57,51 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using namespace Assimp; using namespace Assimp::Blender; -template BlenderModifier* god() { +template +BlenderModifier *god() { return new T(); } // add all available modifiers here -typedef BlenderModifier* (*fpCreateModifier)(); +typedef BlenderModifier *(*fpCreateModifier)(); static const fpCreateModifier creators[] = { - &god, - &god, + &god, + &god, - NULL // sentinel + NULL // sentinel }; // ------------------------------------------------------------------------------------------------ -struct SharedModifierData : ElemBase -{ +struct SharedModifierData : ElemBase { ModifierData modifier; }; // ------------------------------------------------------------------------------------------------ -void BlenderModifierShowcase::ApplyModifiers(aiNode& out, ConversionData& conv_data, const Scene& in, const Object& orig_object ) -{ +void BlenderModifierShowcase::ApplyModifiers(aiNode &out, ConversionData &conv_data, const Scene &in, const Object &orig_object) { size_t cnt = 0u, ful = 0u; // NOTE: this cast is potentially unsafe by design, so we need to perform type checks before // we're allowed to dereference the pointers without risking to crash. We might still be // invoking UB btw - we're assuming that the ModifierData member of the respective modifier // structures is at offset sizeof(vftable) with no padding. - const SharedModifierData* cur = static_cast ( orig_object.modifiers.first.get() ); - for (; cur; cur = static_cast ( cur->modifier.next.get() ), ++ful) { + const SharedModifierData *cur = static_cast(orig_object.modifiers.first.get()); + for (; cur; cur = static_cast(cur->modifier.next.get()), ++ful) { ai_assert(cur->dna_type); - const Structure* s = conv_data.db.dna.Get( cur->dna_type ); + const Structure *s = conv_data.db.dna.Get(cur->dna_type); if (!s) { - ASSIMP_LOG_WARN_F("BlendModifier: could not resolve DNA name: ",cur->dna_type); + ASSIMP_LOG_WARN_F("BlendModifier: could not resolve DNA name: ", cur->dna_type); continue; } // this is a common trait of all XXXMirrorData structures in BlenderDNA - const Field* f = s->Get("modifier"); + const Field *f = s->Get("modifier"); if (!f || f->offset != 0) { ASSIMP_LOG_WARN("BlendModifier: expected a `modifier` member at offset 0"); continue; } - s = conv_data.db.dna.Get( f->type ); + s = conv_data.db.dna.Get(f->type); if (!s || s->name != "ModifierData") { ASSIMP_LOG_WARN("BlendModifier: expected a ModifierData structure as first member"); continue; @@ -110,22 +109,22 @@ void BlenderModifierShowcase::ApplyModifiers(aiNode& out, ConversionData& conv_d // now, we can be sure that we should be fine to dereference *cur* as // ModifierData (with the above note). - const ModifierData& dat = cur->modifier; + const ModifierData &dat = cur->modifier; - const fpCreateModifier* curgod = creators; - std::vector< BlenderModifier* >::iterator curmod = cached_modifiers->begin(), endmod = cached_modifiers->end(); + const fpCreateModifier *curgod = creators; + std::vector::iterator curmod = cached_modifiers->begin(), endmod = cached_modifiers->end(); - for (;*curgod;++curgod,++curmod) { // allocate modifiers on the fly + for (; *curgod; ++curgod, ++curmod) { // allocate modifiers on the fly if (curmod == endmod) { cached_modifiers->push_back((*curgod)()); endmod = cached_modifiers->end(); - curmod = endmod-1; + curmod = endmod - 1; } - BlenderModifier* const modifier = *curmod; - if(modifier->IsActive(dat)) { - modifier->DoIt(out,conv_data,*static_cast(cur),in,orig_object); + BlenderModifier *const modifier = *curmod; + if (modifier->IsActive(dat)) { + modifier->DoIt(out, conv_data, *static_cast(cur), in, orig_object); cnt++; curgod = NULL; @@ -133,7 +132,7 @@ void BlenderModifierShowcase::ApplyModifiers(aiNode& out, ConversionData& conv_d } } if (curgod) { - ASSIMP_LOG_WARN_F("Couldn't find a handler for modifier: ",dat.name); + ASSIMP_LOG_WARN_F("Couldn't find a handler for modifier: ", dat.name); } } @@ -141,26 +140,22 @@ void BlenderModifierShowcase::ApplyModifiers(aiNode& out, ConversionData& conv_d // object, we still can't say whether our modifier implementations were // able to fully do their job. if (ful) { - ASSIMP_LOG_DEBUG_F("BlendModifier: found handlers for ",cnt," of ",ful," modifiers on `",orig_object.id.name, - "`, check log messages above for errors"); + ASSIMP_LOG_DEBUG_F("BlendModifier: found handlers for ", cnt, " of ", ful, " modifiers on `", orig_object.id.name, + "`, check log messages above for errors"); } } - - // ------------------------------------------------------------------------------------------------ -bool BlenderModifier_Mirror :: IsActive (const ModifierData& modin) -{ +bool BlenderModifier_Mirror ::IsActive(const ModifierData &modin) { return modin.type == ModifierData::eModifierType_Mirror; } // ------------------------------------------------------------------------------------------------ -void BlenderModifier_Mirror :: DoIt(aiNode& out, ConversionData& conv_data, const ElemBase& orig_modifier, - const Scene& /*in*/, - const Object& orig_object ) -{ +void BlenderModifier_Mirror ::DoIt(aiNode &out, ConversionData &conv_data, const ElemBase &orig_modifier, + const Scene & /*in*/, + const Object &orig_object) { // hijacking the ABI, see the big note in BlenderModifierShowcase::ApplyModifiers() - const MirrorModifierData& mir = static_cast(orig_modifier); + const MirrorModifierData &mir = static_cast(orig_modifier); ai_assert(mir.modifier.type == ModifierData::eModifierType_Mirror); conv_data.meshes->reserve(conv_data.meshes->size() + out.mNumMeshes); @@ -169,48 +164,55 @@ void BlenderModifier_Mirror :: DoIt(aiNode& out, ConversionData& conv_data, co // take all input meshes and clone them for (unsigned int i = 0; i < out.mNumMeshes; ++i) { - aiMesh* mesh; - SceneCombiner::Copy(&mesh,conv_data.meshes[out.mMeshes[i]]); + aiMesh *mesh; + SceneCombiner::Copy(&mesh, conv_data.meshes[out.mMeshes[i]]); const float xs = mir.flag & MirrorModifierData::Flags_AXIS_X ? -1.f : 1.f; const float ys = mir.flag & MirrorModifierData::Flags_AXIS_Y ? -1.f : 1.f; const float zs = mir.flag & MirrorModifierData::Flags_AXIS_Z ? -1.f : 1.f; if (mir.mirror_ob) { - const aiVector3D center( mir.mirror_ob->obmat[3][0],mir.mirror_ob->obmat[3][1],mir.mirror_ob->obmat[3][2] ); - for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { - aiVector3D& v = mesh->mVertices[i]; + const aiVector3D center(mir.mirror_ob->obmat[3][0], mir.mirror_ob->obmat[3][1], mir.mirror_ob->obmat[3][2]); + for (unsigned int j = 0; j < mesh->mNumVertices; ++j) { + aiVector3D &v = mesh->mVertices[j]; - v.x = center.x + xs*(center.x - v.x); - v.y = center.y + ys*(center.y - v.y); - v.z = center.z + zs*(center.z - v.z); + v.x = center.x + xs * (center.x - v.x); + v.y = center.y + ys * (center.y - v.y); + v.z = center.z + zs * (center.z - v.z); } - } - else { - for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { - aiVector3D& v = mesh->mVertices[i]; - v.x *= xs;v.y *= ys;v.z *= zs; + } else { + for (unsigned int j = 0; j < mesh->mNumVertices; ++j) { + aiVector3D &v = mesh->mVertices[j]; + v.x *= xs; + v.y *= ys; + v.z *= zs; } } if (mesh->mNormals) { - for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { - aiVector3D& v = mesh->mNormals[i]; - v.x *= xs;v.y *= ys;v.z *= zs; + for (unsigned int j = 0; j < mesh->mNumVertices; ++j) { + aiVector3D &v = mesh->mNormals[j]; + v.x *= xs; + v.y *= ys; + v.z *= zs; } } if (mesh->mTangents) { - for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { - aiVector3D& v = mesh->mTangents[i]; - v.x *= xs;v.y *= ys;v.z *= zs; + for (unsigned int j = 0; j < mesh->mNumVertices; ++j) { + aiVector3D &v = mesh->mTangents[j]; + v.x *= xs; + v.y *= ys; + v.z *= zs; } } if (mesh->mBitangents) { - for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { - aiVector3D& v = mesh->mBitangents[i]; - v.x *= xs;v.y *= ys;v.z *= zs; + for (unsigned int j = 0; j < mesh->mNumVertices; ++j) { + aiVector3D &v = mesh->mBitangents[j]; + v.x *= xs; + v.y *= ys; + v.z *= zs; } } @@ -218,82 +220,80 @@ void BlenderModifier_Mirror :: DoIt(aiNode& out, ConversionData& conv_data, co const float vs = mir.flag & MirrorModifierData::Flags_MIRROR_V ? -1.f : 1.f; for (unsigned int n = 0; mesh->HasTextureCoords(n); ++n) { - for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { - aiVector3D& v = mesh->mTextureCoords[n][i]; - v.x *= us;v.y *= vs; + for (unsigned int j = 0; j < mesh->mNumVertices; ++j) { + aiVector3D &v = mesh->mTextureCoords[n][j]; + v.x *= us; + v.y *= vs; } } // Only reverse the winding order if an odd number of axes were mirrored. if (xs * ys * zs < 0) { - for( unsigned int i = 0; i < mesh->mNumFaces; i++) { - aiFace& face = mesh->mFaces[i]; - for( unsigned int fi = 0; fi < face.mNumIndices / 2; ++fi) - std::swap( face.mIndices[fi], face.mIndices[face.mNumIndices - 1 - fi]); + for (unsigned int j = 0; j < mesh->mNumFaces; ++j ) { + aiFace &face = mesh->mFaces[j]; + for (unsigned int fi = 0; fi < face.mNumIndices / 2; ++fi) + std::swap(face.mIndices[fi], face.mIndices[face.mNumIndices - 1 - fi]); } } conv_data.meshes->push_back(mesh); } - unsigned int* nind = new unsigned int[out.mNumMeshes*2]; + unsigned int *nind = new unsigned int[out.mNumMeshes * 2]; - std::copy(out.mMeshes,out.mMeshes+out.mNumMeshes,nind); - std::transform(out.mMeshes,out.mMeshes+out.mNumMeshes,nind+out.mNumMeshes, - [&out](unsigned int n) { return out.mNumMeshes + n; }); + std::copy(out.mMeshes, out.mMeshes + out.mNumMeshes, nind); + std::transform(out.mMeshes, out.mMeshes + out.mNumMeshes, nind + out.mNumMeshes, + [&out](unsigned int n) { return out.mNumMeshes + n; }); delete[] out.mMeshes; out.mMeshes = nind; out.mNumMeshes *= 2; ASSIMP_LOG_INFO_F("BlendModifier: Applied the `Mirror` modifier to `", - orig_object.id.name,"`"); + orig_object.id.name, "`"); } // ------------------------------------------------------------------------------------------------ -bool BlenderModifier_Subdivision :: IsActive (const ModifierData& modin) -{ +bool BlenderModifier_Subdivision ::IsActive(const ModifierData &modin) { return modin.type == ModifierData::eModifierType_Subsurf; } // ------------------------------------------------------------------------------------------------ -void BlenderModifier_Subdivision :: DoIt(aiNode& out, ConversionData& conv_data, const ElemBase& orig_modifier, - const Scene& /*in*/, - const Object& orig_object ) -{ +void BlenderModifier_Subdivision ::DoIt(aiNode &out, ConversionData &conv_data, const ElemBase &orig_modifier, + const Scene & /*in*/, + const Object &orig_object) { // hijacking the ABI, see the big note in BlenderModifierShowcase::ApplyModifiers() - const SubsurfModifierData& mir = static_cast(orig_modifier); + const SubsurfModifierData &mir = static_cast(orig_modifier); ai_assert(mir.modifier.type == ModifierData::eModifierType_Subsurf); Subdivider::Algorithm algo; - switch (mir.subdivType) - { - case SubsurfModifierData::TYPE_CatmullClarke: - algo = Subdivider::CATMULL_CLARKE; - break; + switch (mir.subdivType) { + case SubsurfModifierData::TYPE_CatmullClarke: + algo = Subdivider::CATMULL_CLARKE; + break; - case SubsurfModifierData::TYPE_Simple: - ASSIMP_LOG_WARN("BlendModifier: The `SIMPLE` subdivision algorithm is not currently implemented, using Catmull-Clarke"); - algo = Subdivider::CATMULL_CLARKE; - break; + case SubsurfModifierData::TYPE_Simple: + ASSIMP_LOG_WARN("BlendModifier: The `SIMPLE` subdivision algorithm is not currently implemented, using Catmull-Clarke"); + algo = Subdivider::CATMULL_CLARKE; + break; - default: - ASSIMP_LOG_WARN_F("BlendModifier: Unrecognized subdivision algorithm: ",mir.subdivType); - return; + default: + ASSIMP_LOG_WARN_F("BlendModifier: Unrecognized subdivision algorithm: ", mir.subdivType); + return; }; std::unique_ptr subd(Subdivider::Create(algo)); ai_assert(subd); - if ( conv_data.meshes->empty() ) { + if (conv_data.meshes->empty()) { return; } - aiMesh** const meshes = &conv_data.meshes[conv_data.meshes->size() - out.mNumMeshes]; - std::unique_ptr tempmeshes(new aiMesh*[out.mNumMeshes]()); + aiMesh **const meshes = &conv_data.meshes[conv_data.meshes->size() - out.mNumMeshes]; + std::unique_ptr tempmeshes(new aiMesh *[out.mNumMeshes]()); - subd->Subdivide(meshes,out.mNumMeshes,tempmeshes.get(),std::max( mir.renderLevels, mir.levels ),true); - std::copy(tempmeshes.get(),tempmeshes.get()+out.mNumMeshes,meshes); + subd->Subdivide(meshes, out.mNumMeshes, tempmeshes.get(), std::max(mir.renderLevels, mir.levels), true); + std::copy(tempmeshes.get(), tempmeshes.get() + out.mNumMeshes, meshes); ASSIMP_LOG_INFO_F("BlendModifier: Applied the `Subdivision` modifier to `", - orig_object.id.name,"`"); + orig_object.id.name, "`"); } #endif // ASSIMP_BUILD_NO_BLEND_IMPORTER diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 0dff5d9e4..c872e7b20 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -861,15 +861,15 @@ if ((CMAKE_COMPILER_IS_MINGW) AND (CMAKE_BUILD_TYPE MATCHES Debug)) SET_SOURCE_FILES_PROPERTIES(Importer/StepFile/StepFileGen1.cpp PROPERTIES STATIC_LIBRARY_FLAGS -Os ) endif() -ADD_ASSIMP_IMPORTER( STEP - Step/STEPFile.h - Importer/StepFile/StepFileImporter.h - Importer/StepFile/StepFileImporter.cpp - Importer/StepFile/StepFileGen1.cpp - Importer/StepFile/StepFileGen2.cpp - Importer/StepFile/StepFileGen3.cpp - Importer/StepFile/StepReaderGen.h -) +#ADD_ASSIMP_IMPORTER( STEP +# Step/STEPFile.h +# Importer/StepFile/StepFileImporter.h +# Importer/StepFile/StepFileImporter.cpp +# Importer/StepFile/StepFileGen1.cpp +# Importer/StepFile/StepFileGen2.cpp +# Importer/StepFile/StepFileGen3.cpp +# Importer/StepFile/StepReaderGen.h +#) if ((NOT ASSIMP_NO_EXPORT) OR (NOT ASSIMP_EXPORTERS_ENABLED STREQUAL "")) SET( Exporter_SRCS @@ -886,7 +886,7 @@ SET( Extra_SRCS SOURCE_GROUP( Extra FILES ${Extra_SRCS}) # irrXML -IF(HUNTER_ENABLED) +IF(ASSIMP_HUNTER_ENABLED) hunter_add_package(irrXML) find_package(irrXML CONFIG REQUIRED) ELSE() @@ -894,7 +894,7 @@ ELSE() ENDIF() # utf8 -IF(HUNTER_ENABLED) +IF(ASSIMP_HUNTER_ENABLED) hunter_add_package(utf8) find_package(utf8 CONFIG REQUIRED) ELSE() @@ -902,7 +902,7 @@ ELSE() ENDIF() # polyclipping -IF(HUNTER_ENABLED) +IF(ASSIMP_HUNTER_ENABLED) hunter_add_package(polyclipping) find_package(polyclipping CONFIG REQUIRED) ELSE() @@ -914,7 +914,7 @@ ELSE() ENDIF() # poly2tri -IF(HUNTER_ENABLED) +IF(ASSIMP_HUNTER_ENABLED) hunter_add_package(poly2tri) find_package(poly2tri CONFIG REQUIRED) ELSE() @@ -935,7 +935,7 @@ ELSE() ENDIF() # minizip/unzip -IF(HUNTER_ENABLED) +IF(ASSIMP_HUNTER_ENABLED) hunter_add_package(minizip) find_package(minizip CONFIG REQUIRED) ELSE() @@ -950,7 +950,7 @@ ELSE() ENDIF() # zip (https://github.com/kuba--/zip) -IF(HUNTER_ENABLED) +IF(ASSIMP_HUNTER_ENABLED) hunter_add_package(zip) find_package(zip CONFIG REQUIRED) ELSE() @@ -971,7 +971,7 @@ ELSE() ENDIF() # openddlparser -IF(HUNTER_ENABLED) +IF(ASSIMP_HUNTER_ENABLED) hunter_add_package(openddlparser) find_package(openddlparser CONFIG REQUIRED) ELSE() @@ -994,7 +994,7 @@ ELSE() ENDIF() # Open3DGC -IF(HUNTER_ENABLED) +IF(ASSIMP_HUNTER_ENABLED) # Nothing to do, not available in Hunter yet. ELSE() SET ( open3dgc_SRCS @@ -1035,7 +1035,7 @@ ENDIF() # RT-extensions is used in "contrib/Open3DGC/o3dgcTimer.h" for collecting statistics. Pointed file # has implementation for different platforms: WIN32, __MACH__ and other ("else" block). FIND_PACKAGE(RT QUIET) -IF (NOT HUNTER_ENABLED AND (RT_FOUND OR MSVC)) +IF (NOT ASSIMP_HUNTER_ENABLED AND (RT_FOUND OR MSVC)) SET( ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC 1 ) ADD_DEFINITIONS( -DASSIMP_IMPORTER_GLTF_USE_OPEN3DGC=1 ) ELSE () @@ -1045,7 +1045,7 @@ ELSE () ENDIF () # RapidJSON -IF(HUNTER_ENABLED) +IF(ASSIMP_HUNTER_ENABLED) hunter_add_package(RapidJSON) find_package(RapidJSON CONFIG REQUIRED) ELSE() @@ -1068,7 +1068,7 @@ if ( MSVC ) ADD_DEFINITIONS( -D_CRT_SECURE_NO_WARNINGS ) endif () -IF(NOT HUNTER_ENABLED) +IF(NOT ASSIMP_HUNTER_ENABLED) if (UNZIP_FOUND) SET (unzip_compile_SRCS "") else () @@ -1118,7 +1118,7 @@ SET( assimp_src ) ADD_DEFINITIONS( -DOPENDDLPARSER_BUILD ) -IF(NOT HUNTER_ENABLED) +IF(NOT ASSIMP_HUNTER_ENABLED) INCLUDE_DIRECTORIES( ${IRRXML_INCLUDE_DIR} ../contrib/openddlparser/include @@ -1139,7 +1139,7 @@ TARGET_INCLUDE_DIRECTORIES ( assimp PUBLIC $ ) -IF(HUNTER_ENABLED) +IF(ASSIMP_HUNTER_ENABLED) TARGET_LINK_LIBRARIES(assimp PUBLIC polyclipping::polyclipping @@ -1212,7 +1212,7 @@ SET_TARGET_PROPERTIES( assimp PROPERTIES ) if (APPLE) - if (BUILD_FRAMEWORK) + if (ASSIMP_BUILD_FRAMEWORK) SET_TARGET_PROPERTIES( assimp PROPERTIES FRAMEWORK TRUE FRAMEWORK_VERSION C @@ -1232,7 +1232,7 @@ ENDIF() # Build against external unzip, or add ../contrib/unzip so # assimp can #include "unzip.h" -IF(NOT HUNTER_ENABLED) +IF(NOT ASSIMP_HUNTER_ENABLED) if (UNZIP_FOUND) INCLUDE_DIRECTORIES(${UNZIP_INCLUDE_DIRS}) TARGET_LINK_LIBRARIES(assimp ${UNZIP_LIBRARIES}) @@ -1246,7 +1246,7 @@ IF (RT_FOUND AND ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC) TARGET_LINK_LIBRARIES(assimp ${RT_LIBRARY}) ENDIF () -IF(HUNTER_ENABLED) +IF(ASSIMP_HUNTER_ENABLED) INSTALL( TARGETS assimp EXPORT "${TARGETS_EXPORT_NAME}" LIBRARY DESTINATION ${ASSIMP_LIB_INSTALL_DIR} diff --git a/code/COB/COBLoader.cpp b/code/COB/COBLoader.cpp index 8e7c81192..b9ea8aff5 100644 --- a/code/COB/COBLoader.cpp +++ b/code/COB/COBLoader.cpp @@ -1015,8 +1015,8 @@ void COBImporter::ReadPolH_Binary(COB::Scene& out, StreamReaderLE& reader, const // XXX backface culling flag is 0x10 in flags // hole? - bool hole; - if ((hole = (reader.GetI1() & 0x08) != 0)) { + bool hole = (reader.GetI1() & 0x08) != 0; + if ( hole ) { // XXX Basically this should just work fine - then triangulator // should output properly triangulated data even for polygons // with holes. Test data specific to COB is needed to confirm it. diff --git a/code/COB/COBScene.h b/code/COB/COBScene.h index 87f4f4570..ef2f6dc1a 100644 --- a/code/COB/COBScene.h +++ b/code/COB/COBScene.h @@ -75,10 +75,10 @@ struct Face // ------------------ /** COB chunk header information */ +const unsigned int NO_SIZE = UINT_MAX; + struct ChunkInfo { - enum {NO_SIZE=UINT_MAX}; - ChunkInfo () : id (0) , parent_id (0) diff --git a/code/Collada/ColladaExporter.cpp b/code/Collada/ColladaExporter.cpp index 99cdc097b..e27e7aa90 100644 --- a/code/Collada/ColladaExporter.cpp +++ b/code/Collada/ColladaExporter.cpp @@ -1335,32 +1335,34 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex) mOutput << startstr << "" << endstr; PushTag(); - std::string node_idstr; + std::string cur_node_idstr; for (size_t a = 0; a < anim->mNumChannels; ++a) { const aiNodeAnim * nodeAnim = anim->mChannels[a]; // sanity check - if ( nodeAnim->mNumPositionKeys != nodeAnim->mNumScalingKeys || nodeAnim->mNumPositionKeys != nodeAnim->mNumRotationKeys ) continue; + if (nodeAnim->mNumPositionKeys != nodeAnim->mNumScalingKeys || nodeAnim->mNumPositionKeys != nodeAnim->mNumRotationKeys) { + continue; + } { - node_idstr.clear(); - node_idstr += nodeAnim->mNodeName.data; - node_idstr += std::string( "_matrix-input" ); + cur_node_idstr.clear(); + cur_node_idstr += nodeAnim->mNodeName.data; + cur_node_idstr += std::string("_matrix-input"); std::vector frames; for( size_t i = 0; i < nodeAnim->mNumPositionKeys; ++i) { frames.push_back(static_cast(nodeAnim->mPositionKeys[i].mTime)); } - WriteFloatArray( node_idstr , FloatType_Time, (const ai_real*) frames.data(), frames.size()); + WriteFloatArray(cur_node_idstr, FloatType_Time, (const ai_real *)frames.data(), frames.size()); frames.clear(); } { - node_idstr.clear(); + cur_node_idstr.clear(); - node_idstr += nodeAnim->mNodeName.data; - node_idstr += std::string("_matrix-output"); + cur_node_idstr += nodeAnim->mNodeName.data; + cur_node_idstr += std::string("_matrix-output"); std::vector keyframes; keyframes.reserve(nodeAnim->mNumPositionKeys * 16); @@ -1385,7 +1387,7 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex) } } - WriteFloatArray( node_idstr, FloatType_Mat4x4, (const ai_real*) keyframes.data(), keyframes.size() / 16); + WriteFloatArray(cur_node_idstr, FloatType_Mat4x4, (const ai_real *)keyframes.data(), keyframes.size() / 16); } { @@ -1401,16 +1403,16 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex) } } - const std::string node_idstr = nodeAnim->mNodeName.data + std::string("_matrix-interpolation"); - std::string arrayId = XMLIDEncode(node_idstr) + "-array"; + const std::string cur_node_idstr2 = nodeAnim->mNodeName.data + std::string("_matrix-interpolation"); + std::string arrayId = XMLIDEncode(cur_node_idstr2) + "-array"; - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PushTag(); // source array mOutput << startstr << " "; - for( size_t a = 0; a < names.size(); ++a ) { - mOutput << names[a] << " "; + for( size_t aa = 0; aa < names.size(); ++aa ) { + mOutput << names[aa] << " "; } mOutput << "" << endstr; @@ -1672,13 +1674,13 @@ void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode) PushTag(); mOutput << startstr << "mMaterialIndex].name) << "\">" << endstr; PushTag(); - for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a ) + for( size_t aa = 0; aa < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++aa ) { - if( mesh->HasTextureCoords( static_cast(a) ) ) + if( mesh->HasTextureCoords( static_cast(aa) ) ) // semantic as in // input_semantic as in // input_set as in - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; } PopTag(); mOutput << startstr << "" << endstr; diff --git a/code/Collada/ColladaParser.cpp b/code/Collada/ColladaParser.cpp index d0f71d95a..25ee2bc3c 100644 --- a/code/Collada/ColladaParser.cpp +++ b/code/Collada/ColladaParser.cpp @@ -714,8 +714,8 @@ void ColladaParser::ReadAnimation(Collada::Animation* pParent) else if (IsElement("sampler")) { // read the ID to assign the corresponding collada channel afterwards. - int indexID = GetAttribute("id"); - std::string id = mReader->getAttributeValue(indexID); + int indexId = GetAttribute("id"); + std::string id = mReader->getAttributeValue(indexId); ChannelMap::iterator newChannel = channels.insert(std::make_pair(id, AnimationChannel())).first; // have it read into a channel @@ -3339,13 +3339,12 @@ void ColladaParser::TestClosing(const char* pName) { // Returns the index of the named attribute or -1 if not found. Does not throw, therefore useful for optional attributes int ColladaParser::GetAttribute(const char* pAttr) const { int index = TestAttribute(pAttr); - if (index != -1) { - return index; + if (index == -1) { + ThrowException(format() << "Expected attribute \"" << pAttr << "\" for element <" << mReader->getNodeName() << ">."); } // attribute not found -> throw an exception - ThrowException(format() << "Expected attribute \"" << pAttr << "\" for element <" << mReader->getNodeName() << ">."); - return -1; + return index; } // ------------------------------------------------------------------------------------------------ diff --git a/code/Common/BaseImporter.cpp b/code/Common/BaseImporter.cpp index 8d7b029ba..71049a996 100644 --- a/code/Common/BaseImporter.cpp +++ b/code/Common/BaseImporter.cpp @@ -146,7 +146,7 @@ aiScene* BaseImporter::ReadFile(Importer* pImp, const std::string& pFile, IOSyst } // ------------------------------------------------------------------------------------------------ -void BaseImporter::SetupProperties(const Importer* pImp) +void BaseImporter::SetupProperties(const Importer* ) { // the default implementation does nothing } diff --git a/code/Common/DefaultIOStream.cpp b/code/Common/DefaultIOStream.cpp index 205f19e37..63b44d861 100644 --- a/code/Common/DefaultIOStream.cpp +++ b/code/Common/DefaultIOStream.cpp @@ -70,7 +70,7 @@ namespace template<> size_t select_ftell<8>(FILE* file) { - return ::_ftelli64(file); + return (size_t)::_ftelli64(file); } template<> diff --git a/code/Common/DefaultIOSystem.cpp b/code/Common/DefaultIOSystem.cpp index 0343cb289..31e76bdc9 100644 --- a/code/Common/DefaultIOSystem.cpp +++ b/code/Common/DefaultIOSystem.cpp @@ -44,26 +44,25 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include -#include #include -#include +#include #include #include +#include #ifdef __unix__ -#include -#include +# include +# include #endif #ifdef _WIN32 -#include +# include #endif using namespace Assimp; #ifdef _WIN32 -static std::wstring Utf8ToWide(const char* in) -{ +static std::wstring Utf8ToWide(const char *in) { int size = MultiByteToWideChar(CP_UTF8, 0, in, -1, nullptr, 0); // size includes terminating null; std::wstring adds null automatically std::wstring out(static_cast(size) - 1, L'\0'); @@ -71,8 +70,7 @@ static std::wstring Utf8ToWide(const char* in) return out; } -static std::string WideToUtf8(const wchar_t* in) -{ +static std::string WideToUtf8(const wchar_t *in) { int size = WideCharToMultiByte(CP_UTF8, 0, in, -1, nullptr, 0, nullptr, nullptr); // size includes terminating null; std::string adds null automatically std::string out(static_cast(size) - 1, '\0'); @@ -83,52 +81,51 @@ static std::string WideToUtf8(const wchar_t* in) // ------------------------------------------------------------------------------------------------ // Tests for the existence of a file at the given path. -bool DefaultIOSystem::Exists(const char* pFile) const -{ +bool DefaultIOSystem::Exists(const char *pFile) const { #ifdef _WIN32 struct __stat64 filestat; if (_wstat64(Utf8ToWide(pFile).c_str(), &filestat) != 0) { return false; } #else - FILE* file = ::fopen(pFile, "rb"); - if (!file) + FILE *file = ::fopen(pFile, "rb"); + if (!file) { return false; + } ::fclose(file); #endif + return true; } // ------------------------------------------------------------------------------------------------ // Open a new file with a given path. -IOStream* DefaultIOSystem::Open(const char* strFile, const char* strMode) -{ +IOStream *DefaultIOSystem::Open(const char *strFile, const char *strMode) { ai_assert(strFile != nullptr); ai_assert(strMode != nullptr); - FILE* file; + FILE *file; #ifdef _WIN32 file = ::_wfopen(Utf8ToWide(strFile).c_str(), Utf8ToWide(strMode).c_str()); #else file = ::fopen(strFile, strMode); #endif - if (!file) + if (!file) { return nullptr; + } return new DefaultIOStream(file, strFile); } // ------------------------------------------------------------------------------------------------ // Closes the given file and releases all resources associated with it. -void DefaultIOSystem::Close(IOStream* pFile) -{ +void DefaultIOSystem::Close(IOStream *pFile) { delete pFile; } // ------------------------------------------------------------------------------------------------ // Returns the operation specific directory separator -char DefaultIOSystem::getOsSeparator() const -{ +char DefaultIOSystem::getOsSeparator() const { #ifndef _WIN32 return '/'; #else @@ -138,25 +135,23 @@ char DefaultIOSystem::getOsSeparator() const // ------------------------------------------------------------------------------------------------ // IOSystem default implementation (ComparePaths isn't a pure virtual function) -bool IOSystem::ComparePaths(const char* one, const char* second) const -{ +bool IOSystem::ComparePaths(const char *one, const char *second) const { return !ASSIMP_stricmp(one, second); } // ------------------------------------------------------------------------------------------------ // Convert a relative path into an absolute path -inline static std::string MakeAbsolutePath(const char* in) -{ +inline static std::string MakeAbsolutePath(const char *in) { ai_assert(in); std::string out; #ifdef _WIN32 - wchar_t* ret = ::_wfullpath(nullptr, Utf8ToWide(in).c_str(), 0); + wchar_t *ret = ::_wfullpath(nullptr, Utf8ToWide(in).c_str(), 0); if (ret) { out = WideToUtf8(ret); free(ret); } #else - char* ret = realpath(in, nullptr); + char *ret = realpath(in, nullptr); if (ret) { out = ret; free(ret); @@ -173,8 +168,7 @@ inline static std::string MakeAbsolutePath(const char* in) // ------------------------------------------------------------------------------------------------ // DefaultIOSystem's more specialized implementation -bool DefaultIOSystem::ComparePaths(const char* one, const char* second) const -{ +bool DefaultIOSystem::ComparePaths(const char *one, const char *second) const { // chances are quite good both paths are formatted identically, // so we can hopefully return here already if (!ASSIMP_stricmp(one, second)) @@ -187,8 +181,7 @@ bool DefaultIOSystem::ComparePaths(const char* one, const char* second) const } // ------------------------------------------------------------------------------------------------ -std::string DefaultIOSystem::fileName(const std::string& path) -{ +std::string DefaultIOSystem::fileName(const std::string &path) { std::string ret = path; std::size_t last = ret.find_last_of("\\/"); if (last != std::string::npos) ret = ret.substr(last + 1); @@ -196,8 +189,7 @@ std::string DefaultIOSystem::fileName(const std::string& path) } // ------------------------------------------------------------------------------------------------ -std::string DefaultIOSystem::completeBaseName(const std::string& path) -{ +std::string DefaultIOSystem::completeBaseName(const std::string &path) { std::string ret = fileName(path); std::size_t pos = ret.find_last_of('.'); if (pos != std::string::npos) ret = ret.substr(0, pos); @@ -205,8 +197,7 @@ std::string DefaultIOSystem::completeBaseName(const std::string& path) } // ------------------------------------------------------------------------------------------------ -std::string DefaultIOSystem::absolutePath(const std::string& path) -{ +std::string DefaultIOSystem::absolutePath(const std::string &path) { std::string ret = path; std::size_t last = ret.find_last_of("\\/"); if (last != std::string::npos) ret = ret.substr(0, last); diff --git a/code/Common/Exporter.cpp b/code/Common/Exporter.cpp index 9f9a33b58..66bb921d7 100644 --- a/code/Common/Exporter.cpp +++ b/code/Common/Exporter.cpp @@ -5,8 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2020, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -76,6 +74,11 @@ Here we implement only the C++ interface (Assimp::Exporter). namespace Assimp { +#ifdef _WIN32 +# pragma warning( disable : 4800 ) +#endif // _WIN32 + + // PostStepRegistry.cpp void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out); diff --git a/code/Common/ImporterRegistry.cpp b/code/Common/ImporterRegistry.cpp index 41aa21979..ff0e3ae76 100644 --- a/code/Common/ImporterRegistry.cpp +++ b/code/Common/ImporterRegistry.cpp @@ -5,8 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2020, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -200,9 +198,9 @@ corresponding preprocessor flag to selectively disable formats. #ifndef ASSIMP_BUILD_NO_M3D_IMPORTER # include "M3D/M3DImporter.h" #endif -#ifndef ASSIMP_BUILD_NO_STEP_IMPORTER -# include "Importer/StepFile/StepFileImporter.h" -#endif +//#ifndef ASSIMP_BUILD_NO_STEP_IMPORTER +//# include "Importer/StepFile/StepFileImporter.h" +//#endif namespace Assimp { @@ -361,9 +359,9 @@ void GetImporterInstanceList(std::vector< BaseImporter* >& out) #ifndef ASSIMP_BUILD_NO_MMD_IMPORTER out.push_back( new MMDImporter() ); #endif -#ifndef ASSIMP_BUILD_NO_STEP_IMPORTER - out.push_back(new StepFile::StepFileImporter()); -#endif +//#ifndef ASSIMP_BUILD_NO_STEP_IMPORTER +// out.push_back(new StepFile::StepFileImporter()); +//#endif } /** will delete all registered importers. */ diff --git a/code/Common/SpatialSort.cpp b/code/Common/SpatialSort.cpp index 604b086b7..a32ff5f90 100644 --- a/code/Common/SpatialSort.cpp +++ b/code/Common/SpatialSort.cpp @@ -53,6 +53,10 @@ using namespace Assimp; # define CHAR_BIT 8 #endif +#ifdef _WIN32 +# pragma warning(disable : 4127) +#endif // _WIN32 + // ------------------------------------------------------------------------------------------------ // Constructs a spatially sorted representation from the given position array. SpatialSort::SpatialSort( const aiVector3D* pPositions, unsigned int pNumPositions, diff --git a/code/Common/Subdivision.cpp b/code/Common/Subdivision.cpp index 08408f867..2b376695e 100644 --- a/code/Common/Subdivision.cpp +++ b/code/Common/Subdivision.cpp @@ -53,6 +53,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using namespace Assimp; void mydummy() {} +#ifdef _WIN32 +# pragma warning( disable : 4709 ) +#endif // _WIN32 // ------------------------------------------------------------------------------------------------ /** Subdivider stub class to implement the Catmull-Clarke subdivision algorithm. The * implementation is basing on recursive refinement. Directly evaluating the result is also diff --git a/code/Common/Version.cpp b/code/Common/Version.cpp index f04d12233..5698defbf 100644 --- a/code/Common/Version.cpp +++ b/code/Common/Version.cpp @@ -42,51 +42,50 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Actually just a dummy, used by the compiler to build the precompiled header. -#include -#include #include "ScenePrivate.h" +#include +#include #include "revision.h" // -------------------------------------------------------------------------------- // Legal information string - don't remove this. -static const char* LEGAL_INFORMATION = +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" + "Open Asset Import Library (Assimp).\n" + "A free C/C++ library to import various 3D file formats into applications\n\n" -"(c) 2006-2020, assimp team\n" -"License under the terms and conditions of the 3-clause BSD license\n" -"http://assimp.org\n" -; + "(c) 2006-2020, assimp team\n" + "License under the terms and conditions of the 3-clause BSD license\n" + "http://assimp.org\n"; // ------------------------------------------------------------------------------------------------ // Get legal string -ASSIMP_API const char* aiGetLegalString () { +ASSIMP_API const char *aiGetLegalString() { return LEGAL_INFORMATION; } // ------------------------------------------------------------------------------------------------ // Get Assimp patch version ASSIMP_API unsigned int aiGetVersionPatch() { - return VER_PATCH; + return VER_PATCH; } // ------------------------------------------------------------------------------------------------ // Get Assimp minor version -ASSIMP_API unsigned int aiGetVersionMinor () { +ASSIMP_API unsigned int aiGetVersionMinor() { return VER_MINOR; } // ------------------------------------------------------------------------------------------------ // Get Assimp major version -ASSIMP_API unsigned int aiGetVersionMajor () { +ASSIMP_API unsigned int aiGetVersionMajor() { return VER_MAJOR; } // ------------------------------------------------------------------------------------------------ // Get flags used for compilation -ASSIMP_API unsigned int aiGetCompileFlags () { +ASSIMP_API unsigned int aiGetCompileFlags() { unsigned int flags = 0; @@ -119,24 +118,9 @@ ASSIMP_API const char *aiGetBranchName() { } // ------------------------------------------------------------------------------------------------ -ASSIMP_API aiScene::aiScene() -: mFlags(0) -, mRootNode(nullptr) -, mNumMeshes(0) -, mMeshes(nullptr) -, mNumMaterials(0) -, mMaterials(nullptr) -, mNumAnimations(0) -, mAnimations(nullptr) -, mNumTextures(0) -, mTextures(nullptr) -, mNumLights(0) -, mLights(nullptr) -, mNumCameras(0) -, mCameras(nullptr) -, mMetaData(nullptr) -, mPrivate(new Assimp::ScenePrivateData()) { - // empty +ASSIMP_API aiScene::aiScene() : + mFlags(0), mRootNode(nullptr), mNumMeshes(0), mMeshes(nullptr), mNumMaterials(0), mMaterials(nullptr), mNumAnimations(0), mAnimations(nullptr), mNumTextures(0), mTextures(nullptr), mNumLights(0), mLights(nullptr), mNumCameras(0), mCameras(nullptr), mMetaData(nullptr), mPrivate(new Assimp::ScenePrivateData()) { + // empty } // ------------------------------------------------------------------------------------------------ @@ -148,40 +132,39 @@ ASSIMP_API aiScene::~aiScene() { // much better to check whether both mNumXXX and mXXX are // valid instead of relying on just one of them. if (mNumMeshes && mMeshes) - for( unsigned int a = 0; a < mNumMeshes; a++) + for (unsigned int a = 0; a < mNumMeshes; a++) delete mMeshes[a]; - delete [] mMeshes; + delete[] mMeshes; if (mNumMaterials && mMaterials) { - for (unsigned int a = 0; a < mNumMaterials; ++a ) { - delete mMaterials[ a ]; + for (unsigned int a = 0; a < mNumMaterials; ++a) { + delete mMaterials[a]; } } - delete [] mMaterials; + delete[] mMaterials; if (mNumAnimations && mAnimations) - for( unsigned int a = 0; a < mNumAnimations; a++) + for (unsigned int a = 0; a < mNumAnimations; a++) delete mAnimations[a]; - delete [] mAnimations; + delete[] mAnimations; if (mNumTextures && mTextures) - for( unsigned int a = 0; a < mNumTextures; a++) + for (unsigned int a = 0; a < mNumTextures; a++) delete mTextures[a]; - delete [] mTextures; + delete[] mTextures; if (mNumLights && mLights) - for( unsigned int a = 0; a < mNumLights; a++) + for (unsigned int a = 0; a < mNumLights; a++) delete mLights[a]; - delete [] mLights; + delete[] mLights; if (mNumCameras && mCameras) - for( unsigned int a = 0; a < mNumCameras; a++) + for (unsigned int a = 0; a < mNumCameras; a++) delete mCameras[a]; - delete [] mCameras; + delete[] mCameras; aiMetadata::Dealloc(mMetaData); mMetaData = nullptr; - delete static_cast( mPrivate ); + delete static_cast(mPrivate); } - diff --git a/code/Common/ZipArchiveIOSystem.cpp b/code/Common/ZipArchiveIOSystem.cpp index 8d00da912..6ad10e54a 100644 --- a/code/Common/ZipArchiveIOSystem.cpp +++ b/code/Common/ZipArchiveIOSystem.cpp @@ -4,7 +4,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2020, assimp team - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -44,8 +43,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * @brief Zip File I/O implementation for #Importer */ -#include #include +#include #include @@ -53,70 +52,69 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #ifdef ASSIMP_USE_HUNTER -# include +# include #else -# include +# include #endif namespace Assimp { - // ---------------------------------------------------------------- - // Wraps an existing Assimp::IOSystem for unzip - class IOSystem2Unzip { - public: - static voidpf open(voidpf opaque, const char* filename, int mode); - static uLong read(voidpf opaque, voidpf stream, void* buf, uLong size); - static uLong write(voidpf opaque, voidpf stream, const void* buf, uLong size); - static long tell(voidpf opaque, voidpf stream); - static long seek(voidpf opaque, voidpf stream, uLong offset, int origin); - static int close(voidpf opaque, voidpf stream); - static int testerror(voidpf opaque, voidpf stream); - static zlib_filefunc_def get(IOSystem* pIOHandler); - }; - voidpf IOSystem2Unzip::open(voidpf opaque, const char* filename, int mode) { - IOSystem* io_system = reinterpret_cast(opaque); +// ---------------------------------------------------------------- +// Wraps an existing Assimp::IOSystem for unzip +class IOSystem2Unzip { +public: + static voidpf open(voidpf opaque, const char *filename, int mode); + static uLong read(voidpf opaque, voidpf stream, void *buf, uLong size); + static uLong write(voidpf opaque, voidpf stream, const void *buf, uLong size); + static long tell(voidpf opaque, voidpf stream); + static long seek(voidpf opaque, voidpf stream, uLong offset, int origin); + static int close(voidpf opaque, voidpf stream); + static int testerror(voidpf opaque, voidpf stream); + static zlib_filefunc_def get(IOSystem *pIOHandler); +}; - const char* mode_fopen = nullptr; - if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ) { - mode_fopen = "rb"; - } - else { - if (mode & ZLIB_FILEFUNC_MODE_EXISTING) { - mode_fopen = "r+b"; - } - else { - if (mode & ZLIB_FILEFUNC_MODE_CREATE) { - mode_fopen = "wb"; - } +voidpf IOSystem2Unzip::open(voidpf opaque, const char *filename, int mode) { + IOSystem *io_system = reinterpret_cast(opaque); + + const char *mode_fopen = nullptr; + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ) { + mode_fopen = "rb"; + } else { + if (mode & ZLIB_FILEFUNC_MODE_EXISTING) { + mode_fopen = "r+b"; + } else { + if (mode & ZLIB_FILEFUNC_MODE_CREATE) { + mode_fopen = "wb"; } } - - return (voidpf)io_system->Open(filename, mode_fopen); } - uLong IOSystem2Unzip::read(voidpf /*opaque*/, voidpf stream, void* buf, uLong size) { - IOStream* io_stream = (IOStream*)stream; + return (voidpf)io_system->Open(filename, mode_fopen); +} - return static_cast(io_stream->Read(buf, 1, size)); - } +uLong IOSystem2Unzip::read(voidpf /*opaque*/, voidpf stream, void *buf, uLong size) { + IOStream *io_stream = (IOStream *)stream; - uLong IOSystem2Unzip::write(voidpf /*opaque*/, voidpf stream, const void* buf, uLong size) { - IOStream* io_stream = (IOStream*)stream; + return static_cast(io_stream->Read(buf, 1, size)); +} - return static_cast(io_stream->Write(buf, 1, size)); - } +uLong IOSystem2Unzip::write(voidpf /*opaque*/, voidpf stream, const void *buf, uLong size) { + IOStream *io_stream = (IOStream *)stream; - long IOSystem2Unzip::tell(voidpf /*opaque*/, voidpf stream) { - IOStream* io_stream = (IOStream*)stream; + return static_cast(io_stream->Write(buf, 1, size)); +} - return static_cast(io_stream->Tell()); - } +long IOSystem2Unzip::tell(voidpf /*opaque*/, voidpf stream) { + IOStream *io_stream = (IOStream *)stream; - long IOSystem2Unzip::seek(voidpf /*opaque*/, voidpf stream, uLong offset, int origin) { - IOStream* io_stream = (IOStream*)stream; + return static_cast(io_stream->Tell()); +} - aiOrigin assimp_origin; - switch (origin) { +long IOSystem2Unzip::seek(voidpf /*opaque*/, voidpf stream, uLong offset, int origin) { + IOStream *io_stream = (IOStream *)stream; + + aiOrigin assimp_origin; + switch (origin) { default: case ZLIB_FILEFUNC_SEEK_CUR: assimp_origin = aiOrigin_CUR; @@ -127,157 +125,153 @@ namespace Assimp { case ZLIB_FILEFUNC_SEEK_SET: assimp_origin = aiOrigin_SET; break; - } - - return (io_stream->Seek(offset, assimp_origin) == aiReturn_SUCCESS ? 0 : -1); } - int IOSystem2Unzip::close(voidpf opaque, voidpf stream) { - IOSystem* io_system = (IOSystem*)opaque; - IOStream* io_stream = (IOStream*)stream; + return (io_stream->Seek(offset, assimp_origin) == aiReturn_SUCCESS ? 0 : -1); +} - io_system->Close(io_stream); +int IOSystem2Unzip::close(voidpf opaque, voidpf stream) { + IOSystem *io_system = (IOSystem *)opaque; + IOStream *io_stream = (IOStream *)stream; - return 0; - } + io_system->Close(io_stream); - int IOSystem2Unzip::testerror(voidpf /*opaque*/, voidpf /*stream*/) { - return 0; - } + return 0; +} - zlib_filefunc_def IOSystem2Unzip::get(IOSystem* pIOHandler) { - zlib_filefunc_def mapping; +int IOSystem2Unzip::testerror(voidpf /*opaque*/, voidpf /*stream*/) { + return 0; +} + +zlib_filefunc_def IOSystem2Unzip::get(IOSystem *pIOHandler) { + zlib_filefunc_def mapping; #ifdef ASSIMP_USE_HUNTER - mapping.zopen_file = (open_file_func)open; - mapping.zread_file = (read_file_func)read; - mapping.zwrite_file = (write_file_func)write; - mapping.ztell_file = (tell_file_func)tell; - mapping.zseek_file = (seek_file_func)seek; - mapping.zclose_file = (close_file_func)close; - mapping.zerror_file = (error_file_func)testerror; + mapping.zopen_file = (open_file_func)open; + mapping.zread_file = (read_file_func)read; + mapping.zwrite_file = (write_file_func)write; + mapping.ztell_file = (tell_file_func)tell; + mapping.zseek_file = (seek_file_func)seek; + mapping.zclose_file = (close_file_func)close; + mapping.zerror_file = (error_file_func)testerror; #else - mapping.zopen_file = open; - mapping.zread_file = read; - mapping.zwrite_file = write; - mapping.ztell_file = tell; - mapping.zseek_file = seek; - mapping.zclose_file = close; - mapping.zerror_file = testerror; + mapping.zopen_file = open; + mapping.zread_file = read; + mapping.zwrite_file = write; + mapping.ztell_file = tell; + mapping.zseek_file = seek; + mapping.zclose_file = close; + mapping.zerror_file = testerror; #endif - mapping.opaque = reinterpret_cast(pIOHandler); + mapping.opaque = reinterpret_cast(pIOHandler); - return mapping; + return mapping; +} + +// ---------------------------------------------------------------- +// A read-only file inside a ZIP + +class ZipFile : public IOStream { + friend class ZipFileInfo; + explicit ZipFile(size_t size); + +public: + virtual ~ZipFile(); + + // IOStream interface + size_t Read(void *pvBuffer, size_t pSize, size_t pCount) override; + size_t Write(const void * /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) override { return 0; } + size_t FileSize() const override; + aiReturn Seek(size_t pOffset, aiOrigin pOrigin) override; + size_t Tell() const override; + void Flush() override {} + +private: + size_t m_Size = 0; + size_t m_SeekPtr = 0; + std::unique_ptr m_Buffer; +}; + +// ---------------------------------------------------------------- +// Info about a read-only file inside a ZIP +class ZipFileInfo { +public: + explicit ZipFileInfo(unzFile zip_handle, size_t size); + + // Allocate and Extract data from the ZIP + ZipFile *Extract(unzFile zip_handle) const; + +private: + size_t m_Size = 0; + unz_file_pos_s m_ZipFilePos; +}; + +ZipFileInfo::ZipFileInfo(unzFile zip_handle, size_t size) : + m_Size(size) { + ai_assert(m_Size != 0); + // Workaround for MSVC 2013 - C2797 + m_ZipFilePos.num_of_file = 0; + m_ZipFilePos.pos_in_zip_directory = 0; + unzGetFilePos(zip_handle, &(m_ZipFilePos)); +} + +ZipFile *ZipFileInfo::Extract(unzFile zip_handle) const { + // Find in the ZIP. This cannot fail + unz_file_pos_s *filepos = const_cast(&(m_ZipFilePos)); + if (unzGoToFilePos(zip_handle, filepos) != UNZ_OK) + return nullptr; + + if (unzOpenCurrentFile(zip_handle) != UNZ_OK) + return nullptr; + + ZipFile *zip_file = new ZipFile(m_Size); + + if (unzReadCurrentFile(zip_handle, zip_file->m_Buffer.get(), static_cast(m_Size)) != static_cast(m_Size)) { + // Failed, release the memory + delete zip_file; + zip_file = nullptr; } - // ---------------------------------------------------------------- - // A read-only file inside a ZIP + ai_assert(unzCloseCurrentFile(zip_handle) == UNZ_OK); + return zip_file; +} - class ZipFile : public IOStream { - friend class ZipFileInfo; - explicit ZipFile(size_t size); - public: - virtual ~ZipFile(); +ZipFile::ZipFile(size_t size) : + m_Size(size) { + ai_assert(m_Size != 0); + m_Buffer = std::unique_ptr(new uint8_t[m_Size]); +} - // IOStream interface - size_t Read(void* pvBuffer, size_t pSize, size_t pCount) override; - size_t Write(const void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) override { return 0; } - size_t FileSize() const override; - aiReturn Seek(size_t pOffset, aiOrigin pOrigin) override; - size_t Tell() const override; - void Flush() override {} +ZipFile::~ZipFile() { +} - private: - size_t m_Size = 0; - size_t m_SeekPtr = 0; - std::unique_ptr m_Buffer; - }; +size_t ZipFile::Read(void *pvBuffer, size_t pSize, size_t pCount) { + // Should be impossible + ai_assert(m_Buffer != nullptr); + ai_assert(NULL != pvBuffer && 0 != pSize && 0 != pCount); - - // ---------------------------------------------------------------- - // Info about a read-only file inside a ZIP - class ZipFileInfo - { - public: - explicit ZipFileInfo(unzFile zip_handle, size_t size); - - // Allocate and Extract data from the ZIP - ZipFile * Extract(unzFile zip_handle) const; - - private: - size_t m_Size = 0; - unz_file_pos_s m_ZipFilePos; - }; - - ZipFileInfo::ZipFileInfo(unzFile zip_handle, size_t size) - : m_Size(size) { - ai_assert(m_Size != 0); - // Workaround for MSVC 2013 - C2797 - m_ZipFilePos.num_of_file = 0; - m_ZipFilePos.pos_in_zip_directory = 0; - unzGetFilePos(zip_handle, &(m_ZipFilePos)); + // Clip down to file size + size_t byteSize = pSize * pCount; + if ((byteSize + m_SeekPtr) > m_Size) { + pCount = (m_Size - m_SeekPtr) / pSize; + byteSize = pSize * pCount; + if (byteSize == 0) + return 0; } - ZipFile * ZipFileInfo::Extract(unzFile zip_handle) const { - // Find in the ZIP. This cannot fail - unz_file_pos_s *filepos = const_cast(&(m_ZipFilePos)); - if (unzGoToFilePos(zip_handle, filepos) != UNZ_OK) - return nullptr; + std::memcpy(pvBuffer, m_Buffer.get() + m_SeekPtr, byteSize); - if (unzOpenCurrentFile(zip_handle) != UNZ_OK) - return nullptr; + m_SeekPtr += byteSize; - ZipFile *zip_file = new ZipFile(m_Size); + return pCount; +} - if (unzReadCurrentFile(zip_handle, zip_file->m_Buffer.get(), static_cast(m_Size)) != static_cast(m_Size)) - { - // Failed, release the memory - delete zip_file; - zip_file = nullptr; - } +size_t ZipFile::FileSize() const { + return m_Size; +} - ai_assert(unzCloseCurrentFile(zip_handle) == UNZ_OK); - return zip_file; - } - - ZipFile::ZipFile(size_t size) - : m_Size(size) { - ai_assert(m_Size != 0); - m_Buffer = std::unique_ptr(new uint8_t[m_Size]); - } - - ZipFile::~ZipFile() { - } - - size_t ZipFile::Read(void* pvBuffer, size_t pSize, size_t pCount) { - // Should be impossible - ai_assert(m_Buffer != nullptr); - ai_assert(NULL != pvBuffer && 0 != pSize && 0 != pCount); - - // Clip down to file size - size_t byteSize = pSize * pCount; - if ((byteSize + m_SeekPtr) > m_Size) - { - pCount = (m_Size - m_SeekPtr) / pSize; - byteSize = pSize * pCount; - if (byteSize == 0) - return 0; - } - - std::memcpy(pvBuffer, m_Buffer.get() + m_SeekPtr, byteSize); - - m_SeekPtr += byteSize; - - return pCount; - } - - size_t ZipFile::FileSize() const { - return m_Size; - } - - aiReturn ZipFile::Seek(size_t pOffset, aiOrigin pOrigin) { - switch (pOrigin) - { +aiReturn ZipFile::Seek(size_t pOffset, aiOrigin pOrigin) { + switch (pOrigin) { case aiOrigin_SET: { if (pOffset > m_Size) return aiReturn_FAILURE; m_SeekPtr = pOffset; @@ -296,242 +290,237 @@ namespace Assimp { return aiReturn_SUCCESS; } default:; - } - - return aiReturn_FAILURE; - } - - size_t ZipFile::Tell() const { - return m_SeekPtr; - } - - // ---------------------------------------------------------------- - // pImpl of the Zip Archive IO - class ZipArchiveIOSystem::Implement { - public: - static const unsigned int FileNameSize = 256; - - Implement(IOSystem* pIOHandler, const char* pFilename, const char* pMode); - ~Implement(); - - bool isOpen() const; - void getFileList(std::vector& rFileList); - void getFileListExtension(std::vector& rFileList, const std::string& extension); - bool Exists(std::string& filename); - IOStream* OpenFile(std::string& filename); - - static void SimplifyFilename(std::string& filename); - - private: - void MapArchive(); - - private: - typedef std::map ZipFileInfoMap; - - unzFile m_ZipFileHandle = nullptr; - ZipFileInfoMap m_ArchiveMap; - }; - - ZipArchiveIOSystem::Implement::Implement(IOSystem* pIOHandler, const char* pFilename, const char* pMode) { - ai_assert(strcmp(pMode, "r") == 0); - ai_assert(pFilename != nullptr); - if (pFilename[0] == 0) - return; - - zlib_filefunc_def mapping = IOSystem2Unzip::get(pIOHandler); - m_ZipFileHandle = unzOpen2(pFilename, &mapping); - } - - ZipArchiveIOSystem::Implement::~Implement() { - if (m_ZipFileHandle != nullptr) { - unzClose(m_ZipFileHandle); - m_ZipFileHandle = nullptr; - } - } - - void ZipArchiveIOSystem::Implement::MapArchive() { - if (m_ZipFileHandle == nullptr) - return; - - if (!m_ArchiveMap.empty()) - return; - - // At first ensure file is already open - if (unzGoToFirstFile(m_ZipFileHandle) != UNZ_OK) - return; - - // Loop over all files - do { - char filename[FileNameSize]; - unz_file_info fileInfo; - - if (unzGetCurrentFileInfo(m_ZipFileHandle, &fileInfo, filename, FileNameSize, nullptr, 0, nullptr, 0) == UNZ_OK) { - if (fileInfo.uncompressed_size != 0) { - std::string filename_string(filename, fileInfo.size_filename); - SimplifyFilename(filename_string); - m_ArchiveMap.emplace(filename_string, ZipFileInfo(m_ZipFileHandle, fileInfo.uncompressed_size)); - } - } - } while (unzGoToNextFile(m_ZipFileHandle) != UNZ_END_OF_LIST_OF_FILE); - } - - bool ZipArchiveIOSystem::Implement::isOpen() const { - return (m_ZipFileHandle != nullptr); - } - - void ZipArchiveIOSystem::Implement::getFileList(std::vector& rFileList) { - MapArchive(); - rFileList.clear(); - - for (const auto &file : m_ArchiveMap) { - rFileList.push_back(file.first); - } - } - - void ZipArchiveIOSystem::Implement::getFileListExtension(std::vector& rFileList, const std::string& extension) { - MapArchive(); - rFileList.clear(); - - for (const auto &file : m_ArchiveMap) { - if (extension == BaseImporter::GetExtension(file.first)) - rFileList.push_back(file.first); - } - } - - bool ZipArchiveIOSystem::Implement::Exists(std::string& filename) { - MapArchive(); - - ZipFileInfoMap::const_iterator it = m_ArchiveMap.find(filename); - return (it != m_ArchiveMap.end()); - } - - IOStream * ZipArchiveIOSystem::Implement::OpenFile(std::string& filename) { - MapArchive(); - - SimplifyFilename(filename); - - // Find in the map - ZipFileInfoMap::const_iterator zip_it = m_ArchiveMap.find(filename); - if (zip_it == m_ArchiveMap.cend()) - return nullptr; - - const ZipFileInfo &zip_file = (*zip_it).second; - return zip_file.Extract(m_ZipFileHandle); - } - - inline void ReplaceAll(std::string& data, const std::string& before, const std::string& after) { - size_t pos = data.find(before); - while (pos != std::string::npos) - { - data.replace(pos, before.size(), after); - pos = data.find(before, pos + after.size()); - } - } - - inline void ReplaceAllChar(std::string& data, const char before, const char after) { - size_t pos = data.find(before); - while (pos != std::string::npos) - { - data[pos] = after; - pos = data.find(before, pos + 1); - } - } - - void ZipArchiveIOSystem::Implement::SimplifyFilename(std::string& filename) - { - ReplaceAllChar(filename, '\\', '/'); - - // Remove all . and / from the beginning of the path - size_t pos = filename.find_first_not_of("./"); - if (pos != 0) - filename.erase(0, pos); - - // Simplify "my/folder/../file.png" constructions, if any - static const std::string relative("/../"); - const size_t relsize = relative.size() - 1; - pos = filename.find(relative); - while (pos != std::string::npos) - { - // Previous slash - size_t prevpos = filename.rfind('/', pos - 1); - if (prevpos == pos) - filename.erase(0, pos + relative.size()); - else - filename.erase(prevpos, pos + relsize - prevpos); - - pos = filename.find(relative); - } - } - - ZipArchiveIOSystem::ZipArchiveIOSystem(IOSystem* pIOHandler, const char* pFilename, const char* pMode) - : pImpl(new Implement(pIOHandler, pFilename, pMode)) { - } - - // ---------------------------------------------------------------- - // The ZipArchiveIO - ZipArchiveIOSystem::ZipArchiveIOSystem(IOSystem* pIOHandler, const std::string& rFilename, const char* pMode) - : pImpl(new Implement(pIOHandler, rFilename.c_str(), pMode)) - { - } - - ZipArchiveIOSystem::~ZipArchiveIOSystem() { - delete pImpl; - } - - bool ZipArchiveIOSystem::Exists(const char* pFilename) const { - ai_assert(pFilename != nullptr); - - if (pFilename == nullptr) { - return false; - } - - std::string filename(pFilename); - return pImpl->Exists(filename); - } - - // This is always '/' in a ZIP - char ZipArchiveIOSystem::getOsSeparator() const { - return '/'; - } - - // Only supports Reading - IOStream * ZipArchiveIOSystem::Open(const char* pFilename, const char* pMode) { - ai_assert(pFilename != nullptr); - - for (size_t i = 0; pMode[i] != 0; ++i) - { - ai_assert(pMode[i] != 'w'); - if (pMode[i] == 'w') - return nullptr; - } - - std::string filename(pFilename); - return pImpl->OpenFile(filename); - } - - void ZipArchiveIOSystem::Close(IOStream* pFile) { - delete pFile; - } - - bool ZipArchiveIOSystem::isOpen() const { - return (pImpl->isOpen()); - } - - void ZipArchiveIOSystem::getFileList(std::vector& rFileList) const { - return pImpl->getFileList(rFileList); - } - - void ZipArchiveIOSystem::getFileListExtension(std::vector& rFileList, const std::string& extension) const { - return pImpl->getFileListExtension(rFileList, extension); - } - - bool ZipArchiveIOSystem::isZipArchive(IOSystem* pIOHandler, const char* pFilename) { - Implement tmp(pIOHandler, pFilename, "r"); - return tmp.isOpen(); - } - - bool ZipArchiveIOSystem::isZipArchive(IOSystem* pIOHandler, const std::string& rFilename) { - return isZipArchive(pIOHandler, rFilename.c_str()); } + return aiReturn_FAILURE; } + +size_t ZipFile::Tell() const { + return m_SeekPtr; +} + +// ---------------------------------------------------------------- +// pImpl of the Zip Archive IO +class ZipArchiveIOSystem::Implement { +public: + static const unsigned int FileNameSize = 256; + + Implement(IOSystem *pIOHandler, const char *pFilename, const char *pMode); + ~Implement(); + + bool isOpen() const; + void getFileList(std::vector &rFileList); + void getFileListExtension(std::vector &rFileList, const std::string &extension); + bool Exists(std::string &filename); + IOStream *OpenFile(std::string &filename); + + static void SimplifyFilename(std::string &filename); + +private: + void MapArchive(); + +private: + typedef std::map ZipFileInfoMap; + + unzFile m_ZipFileHandle = nullptr; + ZipFileInfoMap m_ArchiveMap; +}; + +ZipArchiveIOSystem::Implement::Implement(IOSystem *pIOHandler, const char *pFilename, const char *pMode) { + ai_assert(strcmp(pMode, "r") == 0); + ai_assert(pFilename != nullptr); + if (pFilename[0] == 0 || nullptr == pMode) { + return; + } + + zlib_filefunc_def mapping = IOSystem2Unzip::get(pIOHandler); + m_ZipFileHandle = unzOpen2(pFilename, &mapping); +} + +ZipArchiveIOSystem::Implement::~Implement() { + if (m_ZipFileHandle != nullptr) { + unzClose(m_ZipFileHandle); + m_ZipFileHandle = nullptr; + } +} + +void ZipArchiveIOSystem::Implement::MapArchive() { + if (m_ZipFileHandle == nullptr) + return; + + if (!m_ArchiveMap.empty()) + return; + + // At first ensure file is already open + if (unzGoToFirstFile(m_ZipFileHandle) != UNZ_OK) + return; + + // Loop over all files + do { + char filename[FileNameSize]; + unz_file_info fileInfo; + + if (unzGetCurrentFileInfo(m_ZipFileHandle, &fileInfo, filename, FileNameSize, nullptr, 0, nullptr, 0) == UNZ_OK) { + if (fileInfo.uncompressed_size != 0) { + std::string filename_string(filename, fileInfo.size_filename); + SimplifyFilename(filename_string); + m_ArchiveMap.emplace(filename_string, ZipFileInfo(m_ZipFileHandle, fileInfo.uncompressed_size)); + } + } + } while (unzGoToNextFile(m_ZipFileHandle) != UNZ_END_OF_LIST_OF_FILE); +} + +bool ZipArchiveIOSystem::Implement::isOpen() const { + return (m_ZipFileHandle != nullptr); +} + +void ZipArchiveIOSystem::Implement::getFileList(std::vector &rFileList) { + MapArchive(); + rFileList.clear(); + + for (const auto &file : m_ArchiveMap) { + rFileList.push_back(file.first); + } +} + +void ZipArchiveIOSystem::Implement::getFileListExtension(std::vector &rFileList, const std::string &extension) { + MapArchive(); + rFileList.clear(); + + for (const auto &file : m_ArchiveMap) { + if (extension == BaseImporter::GetExtension(file.first)) + rFileList.push_back(file.first); + } +} + +bool ZipArchiveIOSystem::Implement::Exists(std::string &filename) { + MapArchive(); + + ZipFileInfoMap::const_iterator it = m_ArchiveMap.find(filename); + return (it != m_ArchiveMap.end()); +} + +IOStream *ZipArchiveIOSystem::Implement::OpenFile(std::string &filename) { + MapArchive(); + + SimplifyFilename(filename); + + // Find in the map + ZipFileInfoMap::const_iterator zip_it = m_ArchiveMap.find(filename); + if (zip_it == m_ArchiveMap.cend()) + return nullptr; + + const ZipFileInfo &zip_file = (*zip_it).second; + return zip_file.Extract(m_ZipFileHandle); +} + +inline void ReplaceAll(std::string &data, const std::string &before, const std::string &after) { + size_t pos = data.find(before); + while (pos != std::string::npos) { + data.replace(pos, before.size(), after); + pos = data.find(before, pos + after.size()); + } +} + +inline void ReplaceAllChar(std::string &data, const char before, const char after) { + size_t pos = data.find(before); + while (pos != std::string::npos) { + data[pos] = after; + pos = data.find(before, pos + 1); + } +} + +void ZipArchiveIOSystem::Implement::SimplifyFilename(std::string &filename) { + ReplaceAllChar(filename, '\\', '/'); + + // Remove all . and / from the beginning of the path + size_t pos = filename.find_first_not_of("./"); + if (pos != 0) + filename.erase(0, pos); + + // Simplify "my/folder/../file.png" constructions, if any + static const std::string relative("/../"); + const size_t relsize = relative.size() - 1; + pos = filename.find(relative); + while (pos != std::string::npos) { + // Previous slash + size_t prevpos = filename.rfind('/', pos - 1); + if (prevpos == pos) + filename.erase(0, pos + relative.size()); + else + filename.erase(prevpos, pos + relsize - prevpos); + + pos = filename.find(relative); + } +} + +ZipArchiveIOSystem::ZipArchiveIOSystem(IOSystem *pIOHandler, const char *pFilename, const char *pMode) : + pImpl(new Implement(pIOHandler, pFilename, pMode)) { +} + +// ---------------------------------------------------------------- +// The ZipArchiveIO +ZipArchiveIOSystem::ZipArchiveIOSystem(IOSystem *pIOHandler, const std::string &rFilename, const char *pMode) : + pImpl(new Implement(pIOHandler, rFilename.c_str(), pMode)) { +} + +ZipArchiveIOSystem::~ZipArchiveIOSystem() { + delete pImpl; +} + +bool ZipArchiveIOSystem::Exists(const char *pFilename) const { + ai_assert(pFilename != nullptr); + + if (pFilename == nullptr) { + return false; + } + + std::string filename(pFilename); + return pImpl->Exists(filename); +} + +// This is always '/' in a ZIP +char ZipArchiveIOSystem::getOsSeparator() const { + return '/'; +} + +// Only supports Reading +IOStream *ZipArchiveIOSystem::Open(const char *pFilename, const char *pMode) { + ai_assert(pFilename != nullptr); + + for (size_t i = 0; pMode[i] != 0; ++i) { + ai_assert(pMode[i] != 'w'); + if (pMode[i] == 'w') + return nullptr; + } + + std::string filename(pFilename); + return pImpl->OpenFile(filename); +} + +void ZipArchiveIOSystem::Close(IOStream *pFile) { + delete pFile; +} + +bool ZipArchiveIOSystem::isOpen() const { + return (pImpl->isOpen()); +} + +void ZipArchiveIOSystem::getFileList(std::vector &rFileList) const { + return pImpl->getFileList(rFileList); +} + +void ZipArchiveIOSystem::getFileListExtension(std::vector &rFileList, const std::string &extension) const { + return pImpl->getFileListExtension(rFileList, extension); +} + +bool ZipArchiveIOSystem::isZipArchive(IOSystem *pIOHandler, const char *pFilename) { + Implement tmp(pIOHandler, pFilename, "r"); + return tmp.isOpen(); +} + +bool ZipArchiveIOSystem::isZipArchive(IOSystem *pIOHandler, const std::string &rFilename) { + return isZipArchive(pIOHandler, rFilename.c_str()); +} + +} // namespace Assimp diff --git a/code/FBX/FBXCommon.h b/code/FBX/FBXCommon.h index 7f70eb784..7d015a134 100644 --- a/code/FBX/FBXCommon.h +++ b/code/FBX/FBXCommon.h @@ -48,40 +48,40 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_FBX_EXPORTER namespace Assimp { -namespace FBX -{ - const std::string NULL_RECORD = { // 25 null bytes in 64-bit and 13 null bytes in 32-bit - '\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0', - '\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0' - }; // who knows why, it looks like two integers 32/64 bit (compressed and uncompressed sizes?) + 1 byte (might be compression type?) - const std::string SEPARATOR = {'\x00', '\x01'}; // for use inside strings - const std::string MAGIC_NODE_TAG = "_$AssimpFbx$"; // from import - const int64_t SECOND = 46186158000; // FBX's kTime unit +namespace FBX { - // rotation order. We'll probably use EulerXYZ for everything - enum RotOrder { - RotOrder_EulerXYZ = 0, - RotOrder_EulerXZY, - RotOrder_EulerYZX, - RotOrder_EulerYXZ, - RotOrder_EulerZXY, - RotOrder_EulerZYX, +const std::string NULL_RECORD = { // 25 null bytes in 64-bit and 13 null bytes in 32-bit + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', + '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0' +}; // who knows why, it looks like two integers 32/64 bit (compressed and uncompressed sizes?) + 1 byte (might be compression type?) +const std::string SEPARATOR = { '\x00', '\x01' }; // for use inside strings +const std::string MAGIC_NODE_TAG = "_$AssimpFbx$"; // from import +const int64_t SECOND = 46186158000; // FBX's kTime unit - RotOrder_SphericXYZ, +// rotation order. We'll probably use EulerXYZ for everything +enum RotOrder { + RotOrder_EulerXYZ = 0, + RotOrder_EulerXZY, + RotOrder_EulerYZX, + RotOrder_EulerYXZ, + RotOrder_EulerZXY, + RotOrder_EulerZYX, - RotOrder_MAX // end-of-enum sentinel - }; + RotOrder_SphericXYZ, - // transformation inheritance method. Most of the time RSrs - enum TransformInheritance { - TransformInheritance_RrSs = 0, - TransformInheritance_RSrs, - TransformInheritance_Rrs, + RotOrder_MAX // end-of-enum sentinel +}; - TransformInheritance_MAX // end-of-enum sentinel - }; -} -} +// transformation inheritance method. Most of the time RSrs +enum TransformInheritance { + TransformInheritance_RrSs = 0, + TransformInheritance_RSrs, + TransformInheritance_Rrs, + + 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/FBX/FBXConverter.cpp b/code/FBX/FBXConverter.cpp index 22616a480..e7ef8fa61 100644 --- a/code/FBX/FBXConverter.cpp +++ b/code/FBX/FBXConverter.cpp @@ -4,7 +4,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2020, assimp team - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -47,2286 +46,2186 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_FBX_IMPORTER #include "FBXConverter.h" -#include "FBXParser.h" -#include "FBXMeshGeometry.h" #include "FBXDocument.h" -#include "FBXUtil.h" -#include "FBXProperties.h" #include "FBXImporter.h" +#include "FBXMeshGeometry.h" +#include "FBXParser.h" +#include "FBXProperties.h" +#include "FBXUtil.h" -#include #include +#include #include #include -#include #include +#include -#include -#include -#include -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include +#include +#include namespace Assimp { - namespace FBX { +namespace FBX { - using namespace Util; +using namespace Util; #define MAGIC_NODE_TAG "_$AssimpFbx$" #define CONVERT_FBX_TIME(time) static_cast(time) / 46186158000LL - FBXConverter::FBXConverter(aiScene* out, const Document& doc, bool removeEmptyBones ) - : defaultMaterialIndex() - , lights() - , cameras() - , textures() - , materials_converted() - , textures_converted() - , meshes_converted() - , node_anim_chain_bits() - , mNodeNames() - , anim_fps() - , out(out) - , doc(doc) { - // animations need to be converted first since this will - // populate the node_anim_chain_bits map, which is needed - // to determine which nodes need to be generated. - ConvertAnimations(); - // Embedded textures in FBX could be connected to nothing but to itself, - // for instance Texture -> Video connection only but not to the main graph, - // The idea here is to traverse all objects to find these Textures and convert them, - // so later during material conversion it will find converted texture in the textures_converted array. - if (doc.Settings().readTextures) - { - ConvertOrphantEmbeddedTextures(); - } - ConvertRootNode(); +FBXConverter::FBXConverter(aiScene *out, const Document &doc, bool removeEmptyBones) : + defaultMaterialIndex(), + mMeshes(), + lights(), + cameras(), + textures(), + materials_converted(), + textures_converted(), + meshes_converted(), + node_anim_chain_bits(), + mNodeNames(), + anim_fps(), + mSceneOut(out), + doc(doc), + mRemoveEmptyBones(removeEmptyBones) { + // animations need to be converted first since this will + // populate the node_anim_chain_bits map, which is needed + // to determine which nodes need to be generated. + ConvertAnimations(); + // Embedded textures in FBX could be connected to nothing but to itself, + // for instance Texture -> Video connection only but not to the main graph, + // The idea here is to traverse all objects to find these Textures and convert them, + // so later during material conversion it will find converted texture in the textures_converted array. + if (doc.Settings().readTextures) { + ConvertOrphantEmbeddedTextures(); + } + ConvertRootNode(); - if (doc.Settings().readAllMaterials) { - // unfortunately this means we have to evaluate all objects - for (const ObjectMap::value_type& v : doc.Objects()) { + if (doc.Settings().readAllMaterials) { + // unfortunately this means we have to evaluate all objects + for (const ObjectMap::value_type &v : doc.Objects()) { - const Object* ob = v.second->Get(); - if (!ob) { - continue; - } - - const Material* mat = dynamic_cast(ob); - if (mat) { - - if (materials_converted.find(mat) == materials_converted.end()) { - ConvertMaterial(*mat, 0); - } - } - } + const Object *ob = v.second->Get(); + if (!ob) { + continue; } - ConvertGlobalSettings(); - TransferDataToScene(); + const Material *mat = dynamic_cast(ob); + if (mat) { - // if we didn't read any meshes set the AI_SCENE_FLAGS_INCOMPLETE - // to make sure the scene passes assimp's validation. FBX files - // need not contain geometry (i.e. camera animations, raw armatures). - if (out->mNumMeshes == 0) { - out->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; - } - } - - - FBXConverter::~FBXConverter() { - std::for_each(meshes.begin(), meshes.end(), Util::delete_fun()); - std::for_each(materials.begin(), materials.end(), Util::delete_fun()); - std::for_each(animations.begin(), animations.end(), Util::delete_fun()); - std::for_each(lights.begin(), lights.end(), Util::delete_fun()); - std::for_each(cameras.begin(), cameras.end(), Util::delete_fun()); - std::for_each(textures.begin(), textures.end(), Util::delete_fun()); - } - - void FBXConverter::ConvertRootNode() { - out->mRootNode = new aiNode(); - std::string unique_name; - GetUniqueName("RootNode", unique_name); - out->mRootNode->mName.Set(unique_name); - - // root has ID 0 - ConvertNodes(0L, out->mRootNode, out->mRootNode); - } - - static std::string getAncestorBaseName(const aiNode* node) - { - const char* nodeName = nullptr; - size_t length = 0; - while (node && (!nodeName || length == 0)) - { - nodeName = node->mName.C_Str(); - length = node->mName.length; - node = node->mParent; - } - - if (!nodeName || length == 0) - { - return {}; - } - // could be std::string_view if c++17 available - return std::string(nodeName, length); - } - - // Make unique name - std::string FBXConverter::MakeUniqueNodeName(const Model* const model, const aiNode& parent) - { - std::string original_name = FixNodeName(model->Name()); - if (original_name.empty()) - { - original_name = getAncestorBaseName(&parent); - } - std::string unique_name; - GetUniqueName(original_name, unique_name); - return unique_name; - } - /// todo: pre-build node hierarchy - /// todo: get bone from stack - /// todo: make map of aiBone* to aiNode* - /// then update convert clusters to the new format - void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node) { - const std::vector& conns = doc.GetConnectionsByDestinationSequenced(id, "Model"); - - std::vector nodes; - nodes.reserve(conns.size()); - - std::vector nodes_chain; - std::vector post_nodes_chain; - - try { - for (const Connection* con : conns) { - // ignore object-property links - if (con->PropertyName().length()) { - // really important we document why this is ignored. - FBXImporter::LogInfo("ignoring property link - no docs on why this is ignored"); - continue; //? - } - - // convert connection source object into Object base class - const Object* const object = con->SourceObject(); - if (nullptr == object) { - FBXImporter::LogError("failed to convert source object for Model link"); - continue; - } - - // FBX Model::Cube, Model::Bone001, etc elements - // This detects if we can cast the object into this model structure. - const Model* const model = dynamic_cast(object); - - if (nullptr != model) { - nodes_chain.clear(); - post_nodes_chain.clear(); - - aiMatrix4x4 new_abs_transform = parent->mTransformation; - std::string node_name = FixNodeName(model->Name()); - // even though there is only a single input node, the design of - // assimp (or rather: the complicated transformation chain that - // is employed by fbx) means that we may need multiple aiNode's - // to represent a fbx node's transformation. - - - // generate node transforms - this includes pivot data - // if need_additional_node is true then you t - const bool need_additional_node = GenerateTransformationNodeChain(*model, node_name, nodes_chain, post_nodes_chain); - - // assert that for the current node we must have at least a single transform - ai_assert(nodes_chain.size()); - - if (need_additional_node) { - nodes_chain.push_back(new aiNode(node_name)); - } - - //setup metadata on newest node - SetupNodeMetadata(*model, *nodes_chain.back()); - - // link all nodes in a row - aiNode* last_parent = parent; - for (aiNode* child : nodes_chain) { - ai_assert(child); - - if (last_parent != parent) { - last_parent->mNumChildren = 1; - last_parent->mChildren = new aiNode*[1]; - last_parent->mChildren[0] = child; - } - - child->mParent = last_parent; - last_parent = child; - - new_abs_transform *= child->mTransformation; - } - - // attach geometry - ConvertModel(*model, nodes_chain.back(), root_node, new_abs_transform); - - // check if there will be any child nodes - const std::vector& child_conns - = doc.GetConnectionsByDestinationSequenced(model->ID(), "Model"); - - // if so, link the geometric transform inverse nodes - // before we attach any child nodes - if (child_conns.size()) { - for (aiNode* postnode : post_nodes_chain) { - ai_assert(postnode); - - if (last_parent != parent) { - last_parent->mNumChildren = 1; - last_parent->mChildren = new aiNode*[1]; - last_parent->mChildren[0] = postnode; - } - - postnode->mParent = last_parent; - last_parent = postnode; - - new_abs_transform *= postnode->mTransformation; - } - } - else { - // free the nodes we allocated as we don't need them - Util::delete_fun deleter; - std::for_each( - post_nodes_chain.begin(), - post_nodes_chain.end(), - deleter - ); - } - - // recursion call - child nodes - ConvertNodes(model->ID(), last_parent, root_node); - - if (doc.Settings().readLights) { - ConvertLights(*model, node_name); - } - - if (doc.Settings().readCameras) { - ConvertCameras(*model, node_name); - } - - nodes.push_back(nodes_chain.front()); - nodes_chain.clear(); - } - } - - if (nodes.size()) { - parent->mChildren = new aiNode*[nodes.size()](); - parent->mNumChildren = static_cast(nodes.size()); - - std::swap_ranges(nodes.begin(), nodes.end(), parent->mChildren); - } - else - { - parent->mNumChildren = 0; - parent->mChildren = nullptr; - } - - } - catch (std::exception&) { - Util::delete_fun deleter; - std::for_each(nodes.begin(), nodes.end(), deleter); - std::for_each(nodes_chain.begin(), nodes_chain.end(), deleter); - std::for_each(post_nodes_chain.begin(), post_nodes_chain.end(), deleter); - } - } - - - void FBXConverter::ConvertLights(const Model& model, const std::string &orig_name) { - const std::vector& node_attrs = model.GetAttributes(); - for (const NodeAttribute* attr : node_attrs) { - const Light* const light = dynamic_cast(attr); - if (light) { - ConvertLight(*light, orig_name); + if (materials_converted.find(mat) == materials_converted.end()) { + ConvertMaterial(*mat, 0); } } } + } - void FBXConverter::ConvertCameras(const Model& model, const std::string &orig_name) { - const std::vector& node_attrs = model.GetAttributes(); - for (const NodeAttribute* attr : node_attrs) { - const Camera* const cam = dynamic_cast(attr); - if (cam) { - ConvertCamera(*cam, orig_name); - } - } - } + ConvertGlobalSettings(); + TransferDataToScene(); - void FBXConverter::ConvertLight(const Light& light, const std::string &orig_name) { - lights.push_back(new aiLight()); - aiLight* const out_light = lights.back(); - - out_light->mName.Set(orig_name); - - const float intensity = light.Intensity() / 100.0f; - const aiVector3D& col = light.Color(); - - out_light->mColorDiffuse = aiColor3D(col.x, col.y, col.z); - out_light->mColorDiffuse.r *= intensity; - out_light->mColorDiffuse.g *= intensity; - out_light->mColorDiffuse.b *= intensity; - - out_light->mColorSpecular = out_light->mColorDiffuse; - - //lights are defined along negative y direction - out_light->mPosition = aiVector3D(0.0f); - out_light->mDirection = aiVector3D(0.0f, -1.0f, 0.0f); - out_light->mUp = aiVector3D(0.0f, 0.0f, -1.0f); - - switch (light.LightType()) - { - case Light::Type_Point: - out_light->mType = aiLightSource_POINT; - break; - - case Light::Type_Directional: - out_light->mType = aiLightSource_DIRECTIONAL; - break; - - case Light::Type_Spot: - out_light->mType = aiLightSource_SPOT; - out_light->mAngleOuterCone = AI_DEG_TO_RAD(light.OuterAngle()); - out_light->mAngleInnerCone = AI_DEG_TO_RAD(light.InnerAngle()); - break; - - case Light::Type_Area: - FBXImporter::LogWarn("cannot represent area light, set to UNDEFINED"); - out_light->mType = aiLightSource_UNDEFINED; - break; - - case Light::Type_Volume: - FBXImporter::LogWarn("cannot represent volume light, set to UNDEFINED"); - out_light->mType = aiLightSource_UNDEFINED; - break; - default: - ai_assert(false); - } - - float decay = light.DecayStart(); - switch (light.DecayType()) - { - case Light::Decay_None: - out_light->mAttenuationConstant = decay; - out_light->mAttenuationLinear = 0.0f; - out_light->mAttenuationQuadratic = 0.0f; - break; - case Light::Decay_Linear: - out_light->mAttenuationConstant = 0.0f; - out_light->mAttenuationLinear = 2.0f / decay; - out_light->mAttenuationQuadratic = 0.0f; - break; - case Light::Decay_Quadratic: - out_light->mAttenuationConstant = 0.0f; - out_light->mAttenuationLinear = 0.0f; - out_light->mAttenuationQuadratic = 2.0f / (decay * decay); - break; - case Light::Decay_Cubic: - FBXImporter::LogWarn("cannot represent cubic attenuation, set to Quadratic"); - out_light->mAttenuationQuadratic = 1.0f; - break; - default: - ai_assert(false); - break; - } - } - - void FBXConverter::ConvertCamera(const Camera& cam, const std::string &orig_name) - { - cameras.push_back(new aiCamera()); - aiCamera* const out_camera = cameras.back(); - - out_camera->mName.Set(orig_name); - - out_camera->mAspect = cam.AspectWidth() / cam.AspectHeight(); - - out_camera->mPosition = aiVector3D(0.0f); - out_camera->mLookAt = aiVector3D(1.0f, 0.0f, 0.0f); - out_camera->mUp = aiVector3D(0.0f, 1.0f, 0.0f); - - out_camera->mHorizontalFOV = AI_DEG_TO_RAD(cam.FieldOfView()); - - out_camera->mClipPlaneNear = cam.NearPlane(); - out_camera->mClipPlaneFar = cam.FarPlane(); - - out_camera->mHorizontalFOV = AI_DEG_TO_RAD(cam.FieldOfView()); - out_camera->mClipPlaneNear = cam.NearPlane(); - out_camera->mClipPlaneFar = cam.FarPlane(); - } - - void FBXConverter::GetUniqueName(const std::string &name, std::string &uniqueName) - { - uniqueName = name; - auto it_pair = mNodeNames.insert({ name, 0 }); // duplicate node name instance count - unsigned int& i = it_pair.first->second; - while (!it_pair.second) - { - i++; - std::ostringstream ext; - ext << name << std::setfill('0') << std::setw(3) << i; - uniqueName = ext.str(); - it_pair = mNodeNames.insert({ uniqueName, 0 }); - } - } - - const char* FBXConverter::NameTransformationComp(TransformationComp comp) { - switch (comp) { - case TransformationComp_Translation: - return "Translation"; - case TransformationComp_RotationOffset: - return "RotationOffset"; - case TransformationComp_RotationPivot: - return "RotationPivot"; - case TransformationComp_PreRotation: - return "PreRotation"; - case TransformationComp_Rotation: - return "Rotation"; - case TransformationComp_PostRotation: - return "PostRotation"; - case TransformationComp_RotationPivotInverse: - return "RotationPivotInverse"; - case TransformationComp_ScalingOffset: - return "ScalingOffset"; - case TransformationComp_ScalingPivot: - return "ScalingPivot"; - case TransformationComp_Scaling: - return "Scaling"; - case TransformationComp_ScalingPivotInverse: - return "ScalingPivotInverse"; - case TransformationComp_GeometricScaling: - return "GeometricScaling"; - case TransformationComp_GeometricRotation: - return "GeometricRotation"; - case TransformationComp_GeometricTranslation: - return "GeometricTranslation"; - case TransformationComp_GeometricScalingInverse: - return "GeometricScalingInverse"; - case TransformationComp_GeometricRotationInverse: - return "GeometricRotationInverse"; - case TransformationComp_GeometricTranslationInverse: - return "GeometricTranslationInverse"; - case TransformationComp_MAXIMUM: // this is to silence compiler warnings - default: - break; - } - - ai_assert(false); - - return nullptr; - } - - const char* FBXConverter::NameTransformationCompProperty(TransformationComp comp) { - switch (comp) { - case TransformationComp_Translation: - return "Lcl Translation"; - case TransformationComp_RotationOffset: - return "RotationOffset"; - case TransformationComp_RotationPivot: - return "RotationPivot"; - case TransformationComp_PreRotation: - return "PreRotation"; - case TransformationComp_Rotation: - return "Lcl Rotation"; - case TransformationComp_PostRotation: - return "PostRotation"; - case TransformationComp_RotationPivotInverse: - return "RotationPivotInverse"; - case TransformationComp_ScalingOffset: - return "ScalingOffset"; - case TransformationComp_ScalingPivot: - return "ScalingPivot"; - case TransformationComp_Scaling: - return "Lcl Scaling"; - case TransformationComp_ScalingPivotInverse: - return "ScalingPivotInverse"; - case TransformationComp_GeometricScaling: - return "GeometricScaling"; - case TransformationComp_GeometricRotation: - return "GeometricRotation"; - case TransformationComp_GeometricTranslation: - return "GeometricTranslation"; - case TransformationComp_GeometricScalingInverse: - return "GeometricScalingInverse"; - case TransformationComp_GeometricRotationInverse: - return "GeometricRotationInverse"; - case TransformationComp_GeometricTranslationInverse: - return "GeometricTranslationInverse"; - case TransformationComp_MAXIMUM: // this is to silence compiler warnings - break; - } - - ai_assert(false); - - return nullptr; - } - - aiVector3D FBXConverter::TransformationCompDefaultValue(TransformationComp comp) - { - // XXX a neat way to solve the never-ending special cases for scaling - // would be to do everything in log space! - return comp == TransformationComp_Scaling ? aiVector3D(1.f, 1.f, 1.f) : aiVector3D(); - } - - void FBXConverter::GetRotationMatrix(Model::RotOrder mode, const aiVector3D& rotation, aiMatrix4x4& out) - { - if (mode == Model::RotOrder_SphericXYZ) { - FBXImporter::LogError("Unsupported RotationMode: SphericXYZ"); - out = aiMatrix4x4(); - return; - } - - const float angle_epsilon = Math::getEpsilon(); - - out = aiMatrix4x4(); - - bool is_id[3] = { true, true, true }; - - aiMatrix4x4 temp[3]; - if (std::fabs(rotation.z) > angle_epsilon) { - aiMatrix4x4::RotationZ(AI_DEG_TO_RAD(rotation.z), temp[2]); - is_id[2] = false; - } - if (std::fabs(rotation.y) > angle_epsilon) { - aiMatrix4x4::RotationY(AI_DEG_TO_RAD(rotation.y), temp[1]); - is_id[1] = false; - } - if (std::fabs(rotation.x) > angle_epsilon) { - aiMatrix4x4::RotationX(AI_DEG_TO_RAD(rotation.x), temp[0]); - is_id[0] = false; - } - - int order[3] = { -1, -1, -1 }; - - // note: rotation order is inverted since we're left multiplying as is usual in assimp - switch (mode) - { - case Model::RotOrder_EulerXYZ: - order[0] = 2; - order[1] = 1; - order[2] = 0; - break; - - case Model::RotOrder_EulerXZY: - order[0] = 1; - order[1] = 2; - order[2] = 0; - break; - - case Model::RotOrder_EulerYZX: - order[0] = 0; - order[1] = 2; - order[2] = 1; - break; - - case Model::RotOrder_EulerYXZ: - order[0] = 2; - order[1] = 0; - order[2] = 1; - break; - - case Model::RotOrder_EulerZXY: - order[0] = 1; - order[1] = 0; - order[2] = 2; - break; - - case Model::RotOrder_EulerZYX: - order[0] = 0; - order[1] = 1; - order[2] = 2; - break; - - default: - ai_assert(false); - break; - } - - ai_assert(order[0] >= 0); - ai_assert(order[0] <= 2); - ai_assert(order[1] >= 0); - ai_assert(order[1] <= 2); - ai_assert(order[2] >= 0); - ai_assert(order[2] <= 2); - - if (!is_id[order[0]]) { - out = temp[order[0]]; - } - - if (!is_id[order[1]]) { - out = out * temp[order[1]]; - } - - if (!is_id[order[2]]) { - out = out * temp[order[2]]; - } - } - - bool FBXConverter::NeedsComplexTransformationChain(const Model& model) - { - const PropertyTable& props = model.Props(); - bool ok; - - const float zero_epsilon = 1e-6f; - 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); - - if (comp == TransformationComp_Rotation || comp == TransformationComp_Scaling || comp == TransformationComp_Translation) { - continue; - } - - bool scale_compare = (comp == TransformationComp_GeometricScaling || comp == TransformationComp_Scaling); - - const aiVector3D& v = PropertyGet(props, NameTransformationCompProperty(comp), ok); - if (ok && scale_compare) { - if ((v - all_ones).SquareLength() > zero_epsilon) { - return true; - } - } else if (ok) { - if (v.SquareLength() > zero_epsilon) { - return true; - } - } - } - - return false; - } - - std::string FBXConverter::NameTransformationChainNode(const std::string& name, TransformationComp comp) - { - return name + std::string(MAGIC_NODE_TAG) + "_" + NameTransformationComp(comp); - } - - bool FBXConverter::GenerateTransformationNodeChain(const Model& model, const std::string& name, std::vector& output_nodes, - std::vector& post_output_nodes) { - const PropertyTable& props = model.Props(); - const Model::RotOrder rot = model.RotationOrder(); - - bool ok; - - aiMatrix4x4 chain[TransformationComp_MAXIMUM]; - - ai_assert(TransformationComp_MAXIMUM < 32); - std::uint32_t chainBits = 0; - // A node won't need a node chain if it only has these. - const std::uint32_t chainMaskSimple = (1 << TransformationComp_Translation) + (1 << TransformationComp_Scaling) + (1 << TransformationComp_Rotation); - // A node will need a node chain if it has any of these. - const std::uint32_t chainMaskComplex = ((1 << (TransformationComp_MAXIMUM)) - 1) - chainMaskSimple; - - std::fill_n(chain, static_cast(TransformationComp_MAXIMUM), aiMatrix4x4()); - - // generate transformation matrices for all the different transformation components - const float zero_epsilon = Math::getEpsilon(); - const aiVector3D all_ones(1.0f, 1.0f, 1.0f); - - const aiVector3D& PreRotation = PropertyGet(props, "PreRotation", ok); - if (ok && PreRotation.SquareLength() > zero_epsilon) { - chainBits = chainBits | (1 << TransformationComp_PreRotation); - - GetRotationMatrix(Model::RotOrder::RotOrder_EulerXYZ, PreRotation, chain[TransformationComp_PreRotation]); - } - - const aiVector3D& PostRotation = PropertyGet(props, "PostRotation", ok); - if (ok && PostRotation.SquareLength() > zero_epsilon) { - chainBits = chainBits | (1 << TransformationComp_PostRotation); - - GetRotationMatrix(Model::RotOrder::RotOrder_EulerXYZ, PostRotation, chain[TransformationComp_PostRotation]); - } - - const aiVector3D& RotationPivot = PropertyGet(props, "RotationPivot", ok); - if (ok && RotationPivot.SquareLength() > zero_epsilon) { - chainBits = chainBits | (1 << TransformationComp_RotationPivot) | (1 << TransformationComp_RotationPivotInverse); - - aiMatrix4x4::Translation(RotationPivot, chain[TransformationComp_RotationPivot]); - aiMatrix4x4::Translation(-RotationPivot, chain[TransformationComp_RotationPivotInverse]); - } - - const aiVector3D& RotationOffset = PropertyGet(props, "RotationOffset", ok); - if (ok && RotationOffset.SquareLength() > zero_epsilon) { - chainBits = chainBits | (1 << TransformationComp_RotationOffset); - - aiMatrix4x4::Translation(RotationOffset, chain[TransformationComp_RotationOffset]); - } - - const aiVector3D& ScalingOffset = PropertyGet(props, "ScalingOffset", ok); - if (ok && ScalingOffset.SquareLength() > zero_epsilon) { - chainBits = chainBits | (1 << TransformationComp_ScalingOffset); - - aiMatrix4x4::Translation(ScalingOffset, chain[TransformationComp_ScalingOffset]); - } - - const aiVector3D& ScalingPivot = PropertyGet(props, "ScalingPivot", ok); - if (ok && ScalingPivot.SquareLength() > zero_epsilon) { - chainBits = chainBits | (1 << TransformationComp_ScalingPivot) | (1 << TransformationComp_ScalingPivotInverse); - - aiMatrix4x4::Translation(ScalingPivot, chain[TransformationComp_ScalingPivot]); - aiMatrix4x4::Translation(-ScalingPivot, chain[TransformationComp_ScalingPivotInverse]); - } - - const aiVector3D& Translation = PropertyGet(props, "Lcl Translation", ok); - if (ok && Translation.SquareLength() > zero_epsilon) { - chainBits = chainBits | (1 << TransformationComp_Translation); - - aiMatrix4x4::Translation(Translation, chain[TransformationComp_Translation]); - } - - const aiVector3D& Scaling = PropertyGet(props, "Lcl Scaling", ok); - if (ok && (Scaling - all_ones).SquareLength() > zero_epsilon) { - chainBits = chainBits | (1 << TransformationComp_Scaling); - - aiMatrix4x4::Scaling(Scaling, chain[TransformationComp_Scaling]); - } - - const aiVector3D& Rotation = PropertyGet(props, "Lcl Rotation", ok); - if (ok && Rotation.SquareLength() > zero_epsilon) { - chainBits = chainBits | (1 << TransformationComp_Rotation); - - GetRotationMatrix(rot, Rotation, chain[TransformationComp_Rotation]); - } - - const aiVector3D& GeometricScaling = PropertyGet(props, "GeometricScaling", ok); - if (ok && (GeometricScaling - all_ones).SquareLength() > zero_epsilon) { - chainBits = chainBits | (1 << TransformationComp_GeometricScaling); - aiMatrix4x4::Scaling(GeometricScaling, chain[TransformationComp_GeometricScaling]); - aiVector3D GeometricScalingInverse = GeometricScaling; - bool canscale = true; - for (unsigned int i = 0; i < 3; ++i) { - if (std::fabs(GeometricScalingInverse[i]) > zero_epsilon) { - GeometricScalingInverse[i] = 1.0f / GeometricScaling[i]; - } - else { - FBXImporter::LogError("cannot invert geometric scaling matrix with a 0.0 scale component"); - canscale = false; - break; - } - } - if (canscale) { - chainBits = chainBits | (1 << TransformationComp_GeometricScalingInverse); - aiMatrix4x4::Scaling(GeometricScalingInverse, chain[TransformationComp_GeometricScalingInverse]); - } - } - - const aiVector3D& GeometricRotation = PropertyGet(props, "GeometricRotation", ok); - if (ok && GeometricRotation.SquareLength() > zero_epsilon) { - chainBits = chainBits | (1 << TransformationComp_GeometricRotation) | (1 << TransformationComp_GeometricRotationInverse); - GetRotationMatrix(rot, GeometricRotation, chain[TransformationComp_GeometricRotation]); - GetRotationMatrix(rot, GeometricRotation, chain[TransformationComp_GeometricRotationInverse]); - chain[TransformationComp_GeometricRotationInverse].Inverse(); - } - - const aiVector3D& GeometricTranslation = PropertyGet(props, "GeometricTranslation", ok); - if (ok && GeometricTranslation.SquareLength() > zero_epsilon) { - chainBits = chainBits | (1 << TransformationComp_GeometricTranslation) | (1 << TransformationComp_GeometricTranslationInverse); - aiMatrix4x4::Translation(GeometricTranslation, chain[TransformationComp_GeometricTranslation]); - aiMatrix4x4::Translation(-GeometricTranslation, chain[TransformationComp_GeometricTranslationInverse]); - } - - // is_complex needs to be consistent with NeedsComplexTransformationChain() - // or the interplay between this code and the animation converter would - // not be guaranteed. - //ai_assert(NeedsComplexTransformationChain(model) == ((chainBits & chainMaskComplex) != 0)); - - // now, if we have more than just Translation, Scaling and Rotation, - // we need to generate a full node chain to accommodate for assimp's - // lack to express pivots and offsets. - if ((chainBits & chainMaskComplex) && doc.Settings().preservePivots) { - FBXImporter::LogInfo("generating full transformation chain for node: " + name); - - // query the anim_chain_bits dictionary to find out which chain elements - // have associated node animation channels. These can not be dropped - // even if they have identity transform in bind pose. - NodeAnimBitMap::const_iterator it = node_anim_chain_bits.find(name); - const unsigned int anim_chain_bitmask = (it == node_anim_chain_bits.end() ? 0 : (*it).second); - - unsigned int bit = 0x1; - for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i, bit <<= 1) { - const TransformationComp comp = static_cast(i); - - if ((chainBits & bit) == 0 && (anim_chain_bitmask & bit) == 0) { - continue; - } - - if (comp == TransformationComp_PostRotation) { - chain[i] = chain[i].Inverse(); - } - - aiNode* nd = new aiNode(); - nd->mName.Set(NameTransformationChainNode(name, comp)); - nd->mTransformation = chain[i]; - - // geometric inverses go in a post-node chain - if (comp == TransformationComp_GeometricScalingInverse || - comp == TransformationComp_GeometricRotationInverse || - comp == TransformationComp_GeometricTranslationInverse - ) { - post_output_nodes.push_back(nd); - } - else { - output_nodes.push_back(nd); - } - } - - ai_assert(output_nodes.size()); - return true; - } - - // else, we can just multiply the matrices together - aiNode* nd = new aiNode(); - output_nodes.push_back(nd); - - // name passed to the method is already unique - nd->mName.Set(name); - - for (const auto &transform : chain) { - nd->mTransformation = nd->mTransformation * transform; - } - return false; - } - - void FBXConverter::SetupNodeMetadata(const Model& model, aiNode& nd) - { - const PropertyTable& props = model.Props(); - DirectPropertyMap unparsedProperties = props.GetUnparsedProperties(); - - // create metadata on node - const std::size_t numStaticMetaData = 2; - aiMetadata* data = aiMetadata::Alloc(static_cast(unparsedProperties.size() + numStaticMetaData)); - nd.mMetaData = data; - int index = 0; - - // find user defined properties (3ds Max) - data->Set(index++, "UserProperties", aiString(PropertyGet(props, "UDP3DSMAX", ""))); - // preserve the info that a node was marked as Null node in the original file. - data->Set(index++, "IsNull", model.IsNull() ? true : false); - - // add unparsed properties to the node's metadata - for (const DirectPropertyMap::value_type& prop : unparsedProperties) { - // Interpret the property as a concrete type - if (const TypedProperty* interpreted = prop.second->As >()) { - data->Set(index++, prop.first, interpreted->Value()); - } - else if (const TypedProperty* interpreted = prop.second->As >()) { - data->Set(index++, prop.first, interpreted->Value()); - } - else if (const TypedProperty* interpreted = prop.second->As >()) { - data->Set(index++, prop.first, interpreted->Value()); - } - else if (const TypedProperty* interpreted = prop.second->As >()) { - data->Set(index++, prop.first, interpreted->Value()); - } - else if (const TypedProperty* interpreted = prop.second->As >()) { - data->Set(index++, prop.first, aiString(interpreted->Value())); - } - else if (const TypedProperty* interpreted = prop.second->As >()) { - data->Set(index++, prop.first, interpreted->Value()); - } - else { - ai_assert(false); - } - } - } - - void FBXConverter::ConvertModel(const Model &model, aiNode *parent, aiNode *root_node, - const aiMatrix4x4 &absolute_transform) - { - const std::vector& geos = model.GetGeometry(); - - std::vector meshes; - meshes.reserve(geos.size()); - - for (const Geometry* geo : geos) { - - const MeshGeometry* const mesh = dynamic_cast(geo); - const LineGeometry* const line = dynamic_cast(geo); - if (mesh) { - const std::vector& indices = ConvertMesh(*mesh, model, parent, root_node, - absolute_transform); - std::copy(indices.begin(), indices.end(), std::back_inserter(meshes)); - } - else if (line) { - const std::vector& indices = ConvertLine(*line, model, parent, root_node); - std::copy(indices.begin(), indices.end(), std::back_inserter(meshes)); - } - else { - FBXImporter::LogWarn("ignoring unrecognized geometry: " + geo->Name()); - } - } - - if (meshes.size()) { - parent->mMeshes = new unsigned int[meshes.size()](); - parent->mNumMeshes = static_cast(meshes.size()); - - std::swap_ranges(meshes.begin(), meshes.end(), parent->mMeshes); - } - } - - std::vector - FBXConverter::ConvertMesh(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node, - const aiMatrix4x4 &absolute_transform) - { - std::vector temp; - - MeshMap::const_iterator it = meshes_converted.find(&mesh); - if (it != meshes_converted.end()) { - std::copy((*it).second.begin(), (*it).second.end(), std::back_inserter(temp)); - return temp; - } - - const std::vector& vertices = mesh.GetVertices(); - const std::vector& faces = mesh.GetFaceIndexCounts(); - if (vertices.empty() || faces.empty()) { - FBXImporter::LogWarn("ignoring empty geometry: " + mesh.Name()); - return temp; - } - - // one material per mesh maps easily to aiMesh. Multiple material - // meshes need to be split. - const MatIndexArray& mindices = mesh.GetMaterialIndices(); - if (doc.Settings().readMaterials && !mindices.empty()) { - const MatIndexArray::value_type base = mindices[0]; - for (MatIndexArray::value_type index : mindices) { - if (index != base) { - return ConvertMeshMultiMaterial(mesh, model, parent, root_node, absolute_transform); - } - } - } - - // faster code-path, just copy the data - temp.push_back(ConvertMeshSingleMaterial(mesh, model, absolute_transform, parent, root_node)); - return temp; - } - - std::vector FBXConverter::ConvertLine(const LineGeometry& line, const Model& model, - aiNode *parent, aiNode *root_node) - { - std::vector temp; - - const std::vector& vertices = line.GetVertices(); - const std::vector& indices = line.GetIndices(); - if (vertices.empty() || indices.empty()) { - FBXImporter::LogWarn("ignoring empty line: " + line.Name()); - return temp; - } - - aiMesh* const out_mesh = SetupEmptyMesh(line, root_node); - out_mesh->mPrimitiveTypes |= aiPrimitiveType_LINE; - - // copy vertices - out_mesh->mNumVertices = static_cast(vertices.size()); - out_mesh->mVertices = new aiVector3D[out_mesh->mNumVertices]; - std::copy(vertices.begin(), vertices.end(), out_mesh->mVertices); - - //Number of line segments (faces) is "Number of Points - Number of Endpoints" - //N.B.: Endpoints in FbxLine are denoted by negative indices. - //If such an Index is encountered, add 1 and multiply by -1 to get the real index. - unsigned int epcount = 0; - for (unsigned i = 0; i < indices.size(); i++) - { - if (indices[i] < 0) { - epcount++; - } - } - unsigned int pcount = static_cast( indices.size() ); - unsigned int scount = out_mesh->mNumFaces = pcount - epcount; - - aiFace* fac = out_mesh->mFaces = new aiFace[scount](); - for (unsigned int i = 0; i < pcount; ++i) { - if (indices[i] < 0) continue; - aiFace& f = *fac++; - f.mNumIndices = 2; //2 == aiPrimitiveType_LINE - f.mIndices = new unsigned int[2]; - f.mIndices[0] = indices[i]; - int segid = indices[(i + 1 == pcount ? 0 : i + 1)]; //If we have reached he last point, wrap around - f.mIndices[1] = (segid < 0 ? (segid + 1)*-1 : segid); //Convert EndPoint Index to normal Index - } - temp.push_back(static_cast(meshes.size() - 1)); - return temp; - } - - aiMesh* FBXConverter::SetupEmptyMesh(const Geometry& mesh, aiNode *parent) - { - aiMesh* const out_mesh = new aiMesh(); - meshes.push_back(out_mesh); - meshes_converted[&mesh].push_back(static_cast(meshes.size() - 1)); - - // set name - std::string name = mesh.Name(); - if (name.substr(0, 10) == "Geometry::") { - name = name.substr(10); - } - - if (name.length()) { - out_mesh->mName.Set(name); - } - else - { - out_mesh->mName = parent->mName; - } - - return out_mesh; - } - - unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry &mesh, const Model &model, - const aiMatrix4x4 &absolute_transform, aiNode *parent, - aiNode *root_node) - { - const MatIndexArray& mindices = mesh.GetMaterialIndices(); - aiMesh* const out_mesh = SetupEmptyMesh(mesh, parent); - - const std::vector& vertices = mesh.GetVertices(); - const std::vector& faces = mesh.GetFaceIndexCounts(); - - // copy vertices - out_mesh->mNumVertices = static_cast(vertices.size()); - out_mesh->mVertices = new aiVector3D[vertices.size()]; - - std::copy(vertices.begin(), vertices.end(), out_mesh->mVertices); - - // generate dummy faces - out_mesh->mNumFaces = static_cast(faces.size()); - aiFace* fac = out_mesh->mFaces = new aiFace[faces.size()](); - - unsigned int cursor = 0; - for (unsigned int pcount : faces) { - aiFace& f = *fac++; - f.mNumIndices = pcount; - f.mIndices = new unsigned int[pcount]; - switch (pcount) - { - case 1: - out_mesh->mPrimitiveTypes |= aiPrimitiveType_POINT; - break; - case 2: - out_mesh->mPrimitiveTypes |= aiPrimitiveType_LINE; - break; - case 3: - out_mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; - break; - default: - out_mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON; - break; - } - for (unsigned int i = 0; i < pcount; ++i) { - f.mIndices[i] = cursor++; - } - } - - // copy normals - const std::vector& normals = mesh.GetNormals(); - if (normals.size()) { - ai_assert(normals.size() == vertices.size()); - - out_mesh->mNormals = new aiVector3D[vertices.size()]; - std::copy(normals.begin(), normals.end(), out_mesh->mNormals); - } - - // copy tangents - assimp requires both tangents and bitangents (binormals) - // to be present, or neither of them. Compute binormals from normals - // and tangents if needed. - const std::vector& tangents = mesh.GetTangents(); - const std::vector* binormals = &mesh.GetBinormals(); - - if (tangents.size()) { - std::vector tempBinormals; - if (!binormals->size()) { - if (normals.size()) { - tempBinormals.resize(normals.size()); - for (unsigned int i = 0; i < tangents.size(); ++i) { - tempBinormals[i] = normals[i] ^ tangents[i]; - } - - binormals = &tempBinormals; - } - else { - binormals = nullptr; - } - } - - if (binormals) { - ai_assert(tangents.size() == vertices.size()); - ai_assert(binormals->size() == vertices.size()); - - out_mesh->mTangents = new aiVector3D[vertices.size()]; - std::copy(tangents.begin(), tangents.end(), out_mesh->mTangents); - - out_mesh->mBitangents = new aiVector3D[vertices.size()]; - std::copy(binormals->begin(), binormals->end(), out_mesh->mBitangents); - } - } - - // copy texture coords - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { - const std::vector& uvs = mesh.GetTextureCoords(i); - if (uvs.empty()) { - break; - } - - aiVector3D* out_uv = out_mesh->mTextureCoords[i] = new aiVector3D[vertices.size()]; - for (const aiVector2D& v : uvs) { - *out_uv++ = aiVector3D(v.x, v.y, 0.0f); - } - - out_mesh->mNumUVComponents[i] = 2; - } - - // copy vertex colors - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i) { - const std::vector& colors = mesh.GetVertexColors(i); - if (colors.empty()) { - break; - } - - out_mesh->mColors[i] = new aiColor4D[vertices.size()]; - std::copy(colors.begin(), colors.end(), out_mesh->mColors[i]); - } - - if (!doc.Settings().readMaterials || mindices.empty()) { - FBXImporter::LogError("no material assigned to mesh, setting default material"); - out_mesh->mMaterialIndex = GetDefaultMaterial(); - } - else { - ConvertMaterialForMesh(out_mesh, model, mesh, mindices[0]); - } - - if (doc.Settings().readWeights && mesh.DeformerSkin() != nullptr) { - ConvertWeights(out_mesh, model, mesh, absolute_transform, parent, root_node, NO_MATERIAL_SEPARATION, - nullptr); - } - - std::vector animMeshes; - for (const BlendShape* blendShape : mesh.GetBlendShapes()) { - for (const BlendShapeChannel* blendShapeChannel : blendShape->BlendShapeChannels()) { - const std::vector& shapeGeometries = blendShapeChannel->GetShapeGeometries(); - for (size_t i = 0; i < shapeGeometries.size(); i++) { - aiAnimMesh *animMesh = aiCreateAnimMesh(out_mesh); - const ShapeGeometry* shapeGeometry = shapeGeometries.at(i); - const std::vector& vertices = shapeGeometry->GetVertices(); - const std::vector& normals = shapeGeometry->GetNormals(); - const std::vector& indices = shapeGeometry->GetIndices(); - animMesh->mName.Set(FixAnimMeshName(shapeGeometry->Name())); - for (size_t j = 0; j < indices.size(); j++) { - unsigned int index = indices.at(j); - aiVector3D vertex = vertices.at(j); - aiVector3D normal = normals.at(j); - unsigned int count = 0; - const unsigned int* outIndices = mesh.ToOutputVertexIndex(index, count); - for (unsigned int k = 0; k < count; k++) { - unsigned int index = outIndices[k]; - animMesh->mVertices[index] += vertex; - if (animMesh->mNormals != nullptr) { - animMesh->mNormals[index] += normal; - animMesh->mNormals[index].NormalizeSafe(); - } - } - } - animMesh->mWeight = shapeGeometries.size() > 1 ? blendShapeChannel->DeformPercent() / 100.0f : 1.0f; - animMeshes.push_back(animMesh); - } - } - } - const size_t numAnimMeshes = animMeshes.size(); - if (numAnimMeshes > 0) { - out_mesh->mNumAnimMeshes = static_cast(numAnimMeshes); - out_mesh->mAnimMeshes = new aiAnimMesh*[numAnimMeshes]; - for (size_t i = 0; i < numAnimMeshes; i++) { - out_mesh->mAnimMeshes[i] = animMeshes.at(i); - } - } - return static_cast(meshes.size() - 1); - } - - std::vector - FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, aiNode *parent, - aiNode *root_node, - const aiMatrix4x4 &absolute_transform) - { - const MatIndexArray& mindices = mesh.GetMaterialIndices(); - ai_assert(mindices.size()); - - std::set had; - std::vector indices; - - for (MatIndexArray::value_type index : mindices) { - if (had.find(index) == had.end()) { - - indices.push_back(ConvertMeshMultiMaterial(mesh, model, index, parent, root_node, absolute_transform)); - had.insert(index); - } - } - - return indices; - } - - unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, - MatIndexArray::value_type index, - aiNode *parent, aiNode *root_node, - const aiMatrix4x4 &absolute_transform) - { - aiMesh* const out_mesh = SetupEmptyMesh(mesh, parent); - - const MatIndexArray& mindices = mesh.GetMaterialIndices(); - const std::vector& vertices = mesh.GetVertices(); - const std::vector& faces = mesh.GetFaceIndexCounts(); - - const bool process_weights = doc.Settings().readWeights && mesh.DeformerSkin() != nullptr; - - unsigned int count_faces = 0; - unsigned int count_vertices = 0; - - // count faces - std::vector::const_iterator itf = faces.begin(); - for (MatIndexArray::const_iterator it = mindices.begin(), - end = mindices.end(); it != end; ++it, ++itf) - { - if ((*it) != index) { - continue; - } - ++count_faces; - count_vertices += *itf; - } - - ai_assert(count_faces); - ai_assert(count_vertices); - - // mapping from output indices to DOM indexing, needed to resolve weights or blendshapes - std::vector reverseMapping; - std::map translateIndexMap; - if (process_weights || mesh.GetBlendShapes().size() > 0) { - reverseMapping.resize(count_vertices); - } - - // allocate output data arrays, but don't fill them yet - out_mesh->mNumVertices = count_vertices; - out_mesh->mVertices = new aiVector3D[count_vertices]; - - out_mesh->mNumFaces = count_faces; - aiFace* fac = out_mesh->mFaces = new aiFace[count_faces](); - - - // allocate normals - const std::vector& normals = mesh.GetNormals(); - if (normals.size()) { - ai_assert(normals.size() == vertices.size()); - out_mesh->mNormals = new aiVector3D[vertices.size()]; - } - - // allocate tangents, binormals. - const std::vector& tangents = mesh.GetTangents(); - const std::vector* binormals = &mesh.GetBinormals(); - std::vector tempBinormals; - - if (tangents.size()) { - if (!binormals->size()) { - if (normals.size()) { - // XXX this computes the binormals for the entire mesh, not only - // the part for which we need them. - tempBinormals.resize(normals.size()); - for (unsigned int i = 0; i < tangents.size(); ++i) { - tempBinormals[i] = normals[i] ^ tangents[i]; - } - - binormals = &tempBinormals; - } - else { - binormals = nullptr; - } - } - - if (binormals) { - ai_assert(tangents.size() == vertices.size() && binormals->size() == vertices.size()); - - out_mesh->mTangents = new aiVector3D[vertices.size()]; - out_mesh->mBitangents = new aiVector3D[vertices.size()]; - } - } - - // allocate texture coords - unsigned int num_uvs = 0; - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i, ++num_uvs) { - const std::vector& uvs = mesh.GetTextureCoords(i); - if (uvs.empty()) { - break; - } - - out_mesh->mTextureCoords[i] = new aiVector3D[vertices.size()]; - out_mesh->mNumUVComponents[i] = 2; - } - - // allocate vertex colors - unsigned int num_vcs = 0; - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i, ++num_vcs) { - const std::vector& colors = mesh.GetVertexColors(i); - if (colors.empty()) { - break; - } - - out_mesh->mColors[i] = new aiColor4D[vertices.size()]; - } - - unsigned int cursor = 0, in_cursor = 0; - - itf = faces.begin(); - for (MatIndexArray::const_iterator it = mindices.begin(), end = mindices.end(); it != end; ++it, ++itf) - { - const unsigned int pcount = *itf; - if ((*it) != index) { - in_cursor += pcount; - continue; - } - - aiFace& f = *fac++; - - f.mNumIndices = pcount; - f.mIndices = new unsigned int[pcount]; - switch (pcount) - { - case 1: - out_mesh->mPrimitiveTypes |= aiPrimitiveType_POINT; - break; - case 2: - out_mesh->mPrimitiveTypes |= aiPrimitiveType_LINE; - break; - case 3: - out_mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; - break; - default: - out_mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON; - break; - } - for (unsigned int i = 0; i < pcount; ++i, ++cursor, ++in_cursor) { - f.mIndices[i] = cursor; - - if (reverseMapping.size()) { - reverseMapping[cursor] = in_cursor; - translateIndexMap[in_cursor] = cursor; - } - - out_mesh->mVertices[cursor] = vertices[in_cursor]; - - if (out_mesh->mNormals) { - out_mesh->mNormals[cursor] = normals[in_cursor]; - } - - if (out_mesh->mTangents) { - out_mesh->mTangents[cursor] = tangents[in_cursor]; - out_mesh->mBitangents[cursor] = (*binormals)[in_cursor]; - } - - for (unsigned int j = 0; j < num_uvs; ++j) { - const std::vector& uvs = mesh.GetTextureCoords(j); - out_mesh->mTextureCoords[j][cursor] = aiVector3D(uvs[in_cursor].x, uvs[in_cursor].y, 0.0f); - } - - for (unsigned int j = 0; j < num_vcs; ++j) { - const std::vector& cols = mesh.GetVertexColors(j); - out_mesh->mColors[j][cursor] = cols[in_cursor]; - } - } - } - - ConvertMaterialForMesh(out_mesh, model, mesh, index); - - if (process_weights) { - ConvertWeights(out_mesh, model, mesh, absolute_transform, parent, root_node, index, &reverseMapping); - } - - std::vector animMeshes; - for (const BlendShape* blendShape : mesh.GetBlendShapes()) { - for (const BlendShapeChannel* blendShapeChannel : blendShape->BlendShapeChannels()) { - const std::vector& shapeGeometries = blendShapeChannel->GetShapeGeometries(); - for (size_t i = 0; i < shapeGeometries.size(); i++) { - aiAnimMesh* animMesh = aiCreateAnimMesh(out_mesh); - const ShapeGeometry* shapeGeometry = shapeGeometries.at(i); - const std::vector& vertices = shapeGeometry->GetVertices(); - const std::vector& normals = shapeGeometry->GetNormals(); - const std::vector& indices = shapeGeometry->GetIndices(); - animMesh->mName.Set(FixAnimMeshName(shapeGeometry->Name())); - for (size_t j = 0; j < indices.size(); j++) { - unsigned int index = indices.at(j); - aiVector3D vertex = vertices.at(j); - aiVector3D normal = normals.at(j); - unsigned int count = 0; - const unsigned int* outIndices = mesh.ToOutputVertexIndex(index, count); - for (unsigned int k = 0; k < count; k++) { - unsigned int outIndex = outIndices[k]; - if (translateIndexMap.find(outIndex) == translateIndexMap.end()) - continue; - unsigned int index = translateIndexMap[outIndex]; - animMesh->mVertices[index] += vertex; - if (animMesh->mNormals != nullptr) { - animMesh->mNormals[index] += normal; - animMesh->mNormals[index].NormalizeSafe(); - } - } - } - animMesh->mWeight = shapeGeometries.size() > 1 ? blendShapeChannel->DeformPercent() / 100.0f : 1.0f; - animMeshes.push_back(animMesh); - } - } - } - - const size_t numAnimMeshes = animMeshes.size(); - if (numAnimMeshes > 0) { - out_mesh->mNumAnimMeshes = static_cast(numAnimMeshes); - out_mesh->mAnimMeshes = new aiAnimMesh*[numAnimMeshes]; - for (size_t i = 0; i < numAnimMeshes; i++) { - out_mesh->mAnimMeshes[i] = animMeshes.at(i); - } - } - - return static_cast(meshes.size() - 1); - } - - void FBXConverter::ConvertWeights(aiMesh *out, const Model &model, const MeshGeometry &geo, - const aiMatrix4x4 &absolute_transform, - aiNode *parent, aiNode *root_node, unsigned int materialIndex, - std::vector *outputVertStartIndices) - { - ai_assert(geo.DeformerSkin()); - - std::vector out_indices; - std::vector index_out_indices; - std::vector count_out_indices; - - const Skin& sk = *geo.DeformerSkin(); - - std::vector bones; - - const bool no_mat_check = materialIndex == NO_MATERIAL_SEPARATION; - ai_assert(no_mat_check || outputVertStartIndices); - - try { - // iterate over the sub deformers - for (const Cluster* cluster : sk.Clusters()) { - ai_assert(cluster); - - const WeightIndexArray& indices = cluster->GetIndices(); - - const MatIndexArray& mats = geo.GetMaterialIndices(); - - const size_t no_index_sentinel = std::numeric_limits::max(); - - count_out_indices.clear(); - index_out_indices.clear(); - out_indices.clear(); - - - // now check if *any* of these weights is contained in the output mesh, - // taking notes so we don't need to do it twice. - for (WeightIndexArray::value_type index : indices) { - - unsigned int count = 0; - const unsigned int* const out_idx = geo.ToOutputVertexIndex(index, count); - // ToOutputVertexIndex only returns nullptr if index is out of bounds - // which should never happen - ai_assert(out_idx != nullptr); - - index_out_indices.push_back(no_index_sentinel); - count_out_indices.push_back(0); - - for (unsigned int i = 0; i < count; ++i) { - if (no_mat_check || static_cast(mats[geo.FaceForVertexIndex(out_idx[i])]) == materialIndex) { - - if (index_out_indices.back() == no_index_sentinel) { - index_out_indices.back() = out_indices.size(); - } - - if (no_mat_check) { - out_indices.push_back(out_idx[i]); - } else { - // this extra lookup is in O(logn), so the entire algorithm becomes O(nlogn) - const std::vector::iterator it = std::lower_bound( - outputVertStartIndices->begin(), - outputVertStartIndices->end(), - out_idx[i] - ); - - out_indices.push_back(std::distance(outputVertStartIndices->begin(), it)); - } - - ++count_out_indices.back(); - } - } - } - - // if we found at least one, generate the output bones - // XXX this could be heavily simplified by collecting the bone - // data in a single step. - ConvertCluster(bones, cluster, out_indices, index_out_indices, - count_out_indices, absolute_transform, parent, root_node); - } - - bone_map.clear(); - } - catch (std::exception&) { - std::for_each(bones.begin(), bones.end(), Util::delete_fun()); - throw; - } - - if (bones.empty()) { - out->mBones = nullptr; - out->mNumBones = 0; - return; - } else { - out->mBones = new aiBone *[bones.size()](); - out->mNumBones = static_cast(bones.size()); - - std::swap_ranges(bones.begin(), bones.end(), out->mBones); - } - } - - const aiNode* FBXConverter::GetNodeByName( const aiString& name, aiNode *current_node ) - { - aiNode * iter = current_node; - //printf("Child count: %d", iter->mNumChildren); - return iter; - } - - void FBXConverter::ConvertCluster(std::vector &local_mesh_bones, const Cluster *cl, - std::vector &out_indices, std::vector &index_out_indices, - std::vector &count_out_indices, const aiMatrix4x4 &absolute_transform, - aiNode *parent, aiNode *root_node) { - ai_assert(cl); // make sure cluster valid - std::string deformer_name = cl->TargetNode()->Name(); - aiString bone_name = aiString(FixNodeName(deformer_name)); - - aiBone *bone = nullptr; - - if (bone_map.count(deformer_name)) { - ASSIMP_LOG_DEBUG_F("retrieved bone from lookup ", bone_name.C_Str(), ". Deformer:", deformer_name); - bone = bone_map[deformer_name]; - } else { - ASSIMP_LOG_DEBUG_F("created new bone ", bone_name.C_Str(), ". Deformer: ", deformer_name); - bone = new aiBone(); - bone->mName = bone_name; - - // store local transform link for post processing - bone->mOffsetMatrix = cl->TransformLink(); - bone->mOffsetMatrix.Inverse(); - - aiMatrix4x4 matrix = (aiMatrix4x4)absolute_transform; - - bone->mOffsetMatrix = bone->mOffsetMatrix * matrix; // * mesh_offset - - - // - // Now calculate the aiVertexWeights - // - - aiVertexWeight *cursor = nullptr; - - bone->mNumWeights = static_cast(out_indices.size()); - cursor = bone->mWeights = new aiVertexWeight[out_indices.size()]; - - const size_t no_index_sentinel = std::numeric_limits::max(); - const WeightArray& weights = cl->GetWeights(); - - const size_t c = index_out_indices.size(); - for (size_t i = 0; i < c; ++i) { - const size_t index_index = index_out_indices[i]; - - if (index_index == no_index_sentinel) { - continue; - } - - const size_t cc = count_out_indices[i]; - for (size_t j = 0; j < cc; ++j) { - // cursor runs from first element relative to the start - // or relative to the start of the next indexes. - aiVertexWeight& out_weight = *cursor++; - - out_weight.mVertexId = static_cast(out_indices[index_index + j]); - out_weight.mWeight = weights[i]; - } - } - - bone_map.insert(std::pair(deformer_name, bone)); - } - - ASSIMP_LOG_DEBUG_F("bone research: Indicies size: ", out_indices.size()); - - // lookup must be populated in case something goes wrong - // this also allocates bones to mesh instance outside - local_mesh_bones.push_back(bone); - } - - void FBXConverter::ConvertMaterialForMesh(aiMesh* out, const Model& model, const MeshGeometry& geo, - MatIndexArray::value_type materialIndex) - { - // locate source materials for this mesh - const std::vector& mats = model.GetMaterials(); - if (static_cast(materialIndex) >= mats.size() || materialIndex < 0) { - FBXImporter::LogError("material index out of bounds, setting default material"); - out->mMaterialIndex = GetDefaultMaterial(); - return; - } - - const Material* const mat = mats[materialIndex]; - MaterialMap::const_iterator it = materials_converted.find(mat); - if (it != materials_converted.end()) { - out->mMaterialIndex = (*it).second; - return; - } - - out->mMaterialIndex = ConvertMaterial(*mat, &geo); - materials_converted[mat] = out->mMaterialIndex; - } - - unsigned int FBXConverter::GetDefaultMaterial() - { - if (defaultMaterialIndex) { - return defaultMaterialIndex - 1; - } - - aiMaterial* out_mat = new aiMaterial(); - materials.push_back(out_mat); - - const aiColor3D diffuse = aiColor3D(0.8f, 0.8f, 0.8f); - out_mat->AddProperty(&diffuse, 1, AI_MATKEY_COLOR_DIFFUSE); - - aiString s; - s.Set(AI_DEFAULT_MATERIAL_NAME); - - out_mat->AddProperty(&s, AI_MATKEY_NAME); - - defaultMaterialIndex = static_cast(materials.size()); - return defaultMaterialIndex - 1; - } - - - unsigned int FBXConverter::ConvertMaterial(const Material& material, const MeshGeometry* const mesh) - { - const PropertyTable& props = material.Props(); - - // generate empty output material - aiMaterial* out_mat = new aiMaterial(); - materials_converted[&material] = static_cast(materials.size()); - - materials.push_back(out_mat); - - aiString str; - - // strip Material:: prefix - std::string name = material.Name(); - if (name.substr(0, 10) == "Material::") { - name = name.substr(10); - } - - // set material name if not empty - this could happen - // and there should be no key for it in this case. - if (name.length()) { - str.Set(name); - out_mat->AddProperty(&str, AI_MATKEY_NAME); - } - - // Set the shading mode as best we can: The FBX specification only mentions Lambert and Phong, and only Phong is mentioned in Assimp's aiShadingMode enum. - if (material.GetShadingModel() == "phong") - { - aiShadingMode shadingMode = aiShadingMode_Phong; - out_mat->AddProperty(&shadingMode, 1, AI_MATKEY_SHADING_MODEL); - } - - // shading stuff and colors - SetShadingPropertiesCommon(out_mat, props); - SetShadingPropertiesRaw( out_mat, props, material.Textures(), mesh ); - - // texture assignments - SetTextureProperties(out_mat, material.Textures(), mesh); - SetTextureProperties(out_mat, material.LayeredTextures(), mesh); - - return static_cast(materials.size() - 1); - } - - unsigned int FBXConverter::ConvertVideo(const Video& video) - { - // generate empty output texture - aiTexture* out_tex = new aiTexture(); - textures.push_back(out_tex); - - // assuming the texture is compressed - out_tex->mWidth = static_cast(video.ContentLength()); // total data size - out_tex->mHeight = 0; // fixed to 0 - - // steal the data from the Video to avoid an additional copy - out_tex->pcData = reinterpret_cast(const_cast(video).RelinquishContent()); - - // try to extract a hint from the file extension - const std::string& filename = video.RelativeFilename().empty() ? video.FileName() : video.RelativeFilename(); - std::string ext = BaseImporter::GetExtension(filename); - - if (ext == "jpeg") { - ext = "jpg"; - } - - if (ext.size() <= 3) { - memcpy(out_tex->achFormatHint, ext.c_str(), ext.size()); - } - - out_tex->mFilename.Set(filename.c_str()); - - return static_cast(textures.size() - 1); - } - - aiString FBXConverter::GetTexturePath(const Texture* tex) - { - aiString path; - path.Set(tex->RelativeFilename()); - - const Video* media = tex->Media(); - if (media != nullptr) { - bool textureReady = false; //tells if our texture is ready (if it was loaded or if it was found) - unsigned int index; - - VideoMap::const_iterator it = textures_converted.find(*media); - if (it != textures_converted.end()) { - index = (*it).second; - textureReady = true; - } - else { - if (media->ContentLength() > 0) { - index = ConvertVideo(*media); - textures_converted[*media] = index; - textureReady = true; - } - } - - // setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture), if the texture is ready - if (doc.Settings().useLegacyEmbeddedTextureNaming) { - if (textureReady) { - // TODO: check the possibility of using the flag "AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING" - // In FBX files textures are now stored internally by Assimp with their filename included - // Now Assimp can lookup through the loaded textures after all data is processed - // We need to load all textures before referencing them, as FBX file format order may reference a texture before loading it - // This may occur on this case too, it has to be studied - path.data[0] = '*'; - path.length = 1 + ASSIMP_itoa10(path.data + 1, MAXLEN - 1, index); - } - } - } - - return path; - } - - void FBXConverter::TrySetTextureProperties(aiMaterial* out_mat, const TextureMap& textures, - const std::string& propName, - aiTextureType target, const MeshGeometry* const mesh) { - TextureMap::const_iterator it = textures.find(propName); - if (it == textures.end()) { - return; - } - - const Texture* const tex = (*it).second; - if (tex != 0) - { - aiString path = GetTexturePath(tex); - out_mat->AddProperty(&path, _AI_MATKEY_TEXTURE_BASE, target, 0); - - aiUVTransform uvTrafo; - // XXX handle all kinds of UV transformations - uvTrafo.mScaling = tex->UVScaling(); - uvTrafo.mTranslation = tex->UVTranslation(); - out_mat->AddProperty(&uvTrafo, 1, _AI_MATKEY_UVTRANSFORM_BASE, target, 0); - - const PropertyTable& props = tex->Props(); - - int uvIndex = 0; - - bool ok; - const std::string& uvSet = PropertyGet(props, "UVSet", ok); - if (ok) { - // "default" is the name which usually appears in the FbxFileTexture template - if (uvSet != "default" && uvSet.length()) { - // this is a bit awkward - we need to find a mesh that uses this - // material and scan its UV channels for the given UV name because - // assimp references UV channels by index, not by name. - - // XXX: the case that UV channels may appear in different orders - // in meshes is unhandled. A possible solution would be to sort - // the UV channels alphabetically, but this would have the side - // effect that the primary (first) UV channel would sometimes - // be moved, causing trouble when users read only the first - // UV channel and ignore UV channel assignments altogether. - - const unsigned int matIndex = static_cast(std::distance(materials.begin(), - std::find(materials.begin(), materials.end(), out_mat) - )); - - - uvIndex = -1; - if (!mesh) - { - for (const MeshMap::value_type& v : meshes_converted) { - const MeshGeometry* const meshGeom = dynamic_cast (v.first); - if (!meshGeom) { - continue; - } - - const MatIndexArray& mats = meshGeom->GetMaterialIndices(); - if (std::find(mats.begin(), mats.end(), matIndex) == mats.end()) { - continue; - } - - int index = -1; - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { - if (meshGeom->GetTextureCoords(i).empty()) { - break; - } - const std::string& name = meshGeom->GetTextureCoordChannelName(i); - if (name == uvSet) { - index = static_cast(i); - break; - } - } - if (index == -1) { - FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material"); - continue; - } - - if (uvIndex == -1) { - uvIndex = index; - } - else { - FBXImporter::LogWarn("the UV channel named " + uvSet + - " appears at different positions in meshes, results will be wrong"); - } - } - } - else - { - int index = -1; - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { - if (mesh->GetTextureCoords(i).empty()) { - break; - } - const std::string& name = mesh->GetTextureCoordChannelName(i); - if (name == uvSet) { - index = static_cast(i); - break; - } - } - if (index == -1) { - FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material"); - } - - if (uvIndex == -1) { - uvIndex = index; - } - } - - if (uvIndex == -1) { - FBXImporter::LogWarn("failed to resolve UV channel " + uvSet + ", using first UV channel"); - uvIndex = 0; - } - } - } - - out_mat->AddProperty(&uvIndex, 1, _AI_MATKEY_UVWSRC_BASE, target, 0); - } - } - - void FBXConverter::TrySetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, - const std::string& propName, - aiTextureType target, const MeshGeometry* const mesh) { - LayeredTextureMap::const_iterator it = layeredTextures.find(propName); - if (it == layeredTextures.end()) { - return; - } - - int texCount = (*it).second->textureCount(); - - // Set the blend mode for layered textures - int blendmode = (*it).second->GetBlendMode(); - out_mat->AddProperty(&blendmode, 1, _AI_MATKEY_TEXOP_BASE, target, 0); - - for (int texIndex = 0; texIndex < texCount; texIndex++) { - - const Texture* const tex = (*it).second->getTexture(texIndex); - - aiString path = GetTexturePath(tex); - out_mat->AddProperty(&path, _AI_MATKEY_TEXTURE_BASE, target, texIndex); - - aiUVTransform uvTrafo; - // XXX handle all kinds of UV transformations - uvTrafo.mScaling = tex->UVScaling(); - uvTrafo.mTranslation = tex->UVTranslation(); - out_mat->AddProperty(&uvTrafo, 1, _AI_MATKEY_UVTRANSFORM_BASE, target, texIndex); - - const PropertyTable& props = tex->Props(); - - int uvIndex = 0; - - bool ok; - const std::string& uvSet = PropertyGet(props, "UVSet", ok); - if (ok) { - // "default" is the name which usually appears in the FbxFileTexture template - if (uvSet != "default" && uvSet.length()) { - // this is a bit awkward - we need to find a mesh that uses this - // material and scan its UV channels for the given UV name because - // assimp references UV channels by index, not by name. - - // XXX: the case that UV channels may appear in different orders - // in meshes is unhandled. A possible solution would be to sort - // the UV channels alphabetically, but this would have the side - // effect that the primary (first) UV channel would sometimes - // be moved, causing trouble when users read only the first - // UV channel and ignore UV channel assignments altogether. - - const unsigned int matIndex = static_cast(std::distance(materials.begin(), - std::find(materials.begin(), materials.end(), out_mat) - )); - - uvIndex = -1; - if (!mesh) - { - for (const MeshMap::value_type& v : meshes_converted) { - const MeshGeometry* const meshGeom = dynamic_cast (v.first); - if (!meshGeom) { - continue; - } - - const MatIndexArray& mats = meshGeom->GetMaterialIndices(); - if (std::find(mats.begin(), mats.end(), matIndex) == mats.end()) { - continue; - } - - int index = -1; - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { - if (meshGeom->GetTextureCoords(i).empty()) { - break; - } - const std::string& name = meshGeom->GetTextureCoordChannelName(i); - if (name == uvSet) { - index = static_cast(i); - break; - } - } - if (index == -1) { - FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material"); - continue; - } - - if (uvIndex == -1) { - uvIndex = index; - } - else { - FBXImporter::LogWarn("the UV channel named " + uvSet + - " appears at different positions in meshes, results will be wrong"); - } - } - } - else - { - int index = -1; - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { - if (mesh->GetTextureCoords(i).empty()) { - break; - } - const std::string& name = mesh->GetTextureCoordChannelName(i); - if (name == uvSet) { - index = static_cast(i); - break; - } - } - if (index == -1) { - FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material"); - } - - if (uvIndex == -1) { - uvIndex = index; - } - } - - if (uvIndex == -1) { - FBXImporter::LogWarn("failed to resolve UV channel " + uvSet + ", using first UV channel"); - uvIndex = 0; - } - } - } - - out_mat->AddProperty(&uvIndex, 1, _AI_MATKEY_UVWSRC_BASE, target, texIndex); - } - } - - void FBXConverter::SetTextureProperties(aiMaterial* out_mat, const TextureMap& textures, const MeshGeometry* const mesh) - { - TrySetTextureProperties(out_mat, textures, "DiffuseColor", aiTextureType_DIFFUSE, mesh); - TrySetTextureProperties(out_mat, textures, "AmbientColor", aiTextureType_AMBIENT, mesh); - TrySetTextureProperties(out_mat, textures, "EmissiveColor", aiTextureType_EMISSIVE, mesh); - TrySetTextureProperties(out_mat, textures, "SpecularColor", aiTextureType_SPECULAR, mesh); - TrySetTextureProperties(out_mat, textures, "SpecularFactor", aiTextureType_SPECULAR, mesh); - TrySetTextureProperties(out_mat, textures, "TransparentColor", aiTextureType_OPACITY, mesh); - TrySetTextureProperties(out_mat, textures, "ReflectionColor", aiTextureType_REFLECTION, mesh); - TrySetTextureProperties(out_mat, textures, "DisplacementColor", aiTextureType_DISPLACEMENT, mesh); - TrySetTextureProperties(out_mat, textures, "NormalMap", aiTextureType_NORMALS, mesh); - TrySetTextureProperties(out_mat, textures, "Bump", aiTextureType_HEIGHT, mesh); - TrySetTextureProperties(out_mat, textures, "ShininessExponent", aiTextureType_SHININESS, mesh); - TrySetTextureProperties( out_mat, textures, "TransparencyFactor", aiTextureType_OPACITY, mesh ); - TrySetTextureProperties( out_mat, textures, "EmissiveFactor", aiTextureType_EMISSIVE, mesh ); - //Maya counterparts - TrySetTextureProperties(out_mat, textures, "Maya|DiffuseTexture", aiTextureType_DIFFUSE, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|NormalTexture", aiTextureType_NORMALS, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|SpecularTexture", aiTextureType_SPECULAR, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|FalloffTexture", aiTextureType_OPACITY, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|ReflectionMapTexture", aiTextureType_REFLECTION, mesh); - - // Maya PBR - TrySetTextureProperties(out_mat, textures, "Maya|baseColor|file", aiTextureType_BASE_COLOR, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|normalCamera|file", aiTextureType_NORMAL_CAMERA, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|emissionColor|file", aiTextureType_EMISSION_COLOR, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|metalness|file", aiTextureType_METALNESS, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|diffuseRoughness|file", aiTextureType_DIFFUSE_ROUGHNESS, mesh); - - // Maya stingray - TrySetTextureProperties(out_mat, textures, "Maya|TEX_color_map|file", aiTextureType_BASE_COLOR, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|TEX_normal_map|file", aiTextureType_NORMAL_CAMERA, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|TEX_emissive_map|file", aiTextureType_EMISSION_COLOR, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|TEX_metallic_map|file", aiTextureType_METALNESS, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|TEX_roughness_map|file", aiTextureType_DIFFUSE_ROUGHNESS, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|TEX_ao_map|file", aiTextureType_AMBIENT_OCCLUSION, mesh); - - // 3DSMax PBR - TrySetTextureProperties(out_mat, textures, "3dsMax|Parameters|base_color_map", aiTextureType_BASE_COLOR, mesh); - TrySetTextureProperties(out_mat, textures, "3dsMax|Parameters|bump_map", aiTextureType_NORMAL_CAMERA, mesh); - TrySetTextureProperties(out_mat, textures, "3dsMax|Parameters|emission_map", aiTextureType_EMISSION_COLOR, mesh); - TrySetTextureProperties(out_mat, textures, "3dsMax|Parameters|metalness_map", aiTextureType_METALNESS, mesh); - TrySetTextureProperties(out_mat, textures, "3dsMax|Parameters|roughness_map", aiTextureType_DIFFUSE_ROUGHNESS, mesh); - } - - void FBXConverter::SetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, const MeshGeometry* const mesh) - { - TrySetTextureProperties(out_mat, layeredTextures, "DiffuseColor", aiTextureType_DIFFUSE, mesh); - TrySetTextureProperties(out_mat, layeredTextures, "AmbientColor", aiTextureType_AMBIENT, mesh); - TrySetTextureProperties(out_mat, layeredTextures, "EmissiveColor", aiTextureType_EMISSIVE, mesh); - TrySetTextureProperties(out_mat, layeredTextures, "SpecularColor", aiTextureType_SPECULAR, mesh); - TrySetTextureProperties(out_mat, layeredTextures, "SpecularFactor", aiTextureType_SPECULAR, mesh); - TrySetTextureProperties(out_mat, layeredTextures, "TransparentColor", aiTextureType_OPACITY, mesh); - TrySetTextureProperties(out_mat, layeredTextures, "ReflectionColor", aiTextureType_REFLECTION, mesh); - TrySetTextureProperties(out_mat, layeredTextures, "DisplacementColor", aiTextureType_DISPLACEMENT, mesh); - TrySetTextureProperties(out_mat, layeredTextures, "NormalMap", aiTextureType_NORMALS, mesh); - TrySetTextureProperties(out_mat, layeredTextures, "Bump", aiTextureType_HEIGHT, mesh); - TrySetTextureProperties(out_mat, layeredTextures, "ShininessExponent", aiTextureType_SHININESS, mesh); - TrySetTextureProperties( out_mat, layeredTextures, "EmissiveFactor", aiTextureType_EMISSIVE, mesh ); - TrySetTextureProperties( out_mat, layeredTextures, "TransparencyFactor", aiTextureType_OPACITY, mesh ); - } - - aiColor3D FBXConverter::GetColorPropertyFactored(const PropertyTable& props, const std::string& colorName, - const std::string& factorName, bool& result, bool useTemplate) - { - result = true; - - bool ok; - aiVector3D BaseColor = PropertyGet(props, colorName, ok, useTemplate); - if (!ok) { - result = false; - return aiColor3D(0.0f, 0.0f, 0.0f); - } - - // if no factor name, return the colour as is - if (factorName.empty()) { - return aiColor3D(BaseColor.x, BaseColor.y, BaseColor.z); - } - - // otherwise it should be multiplied by the factor, if found. - float factor = PropertyGet(props, factorName, ok, useTemplate); - if (ok) { - BaseColor *= factor; - } - return aiColor3D(BaseColor.x, BaseColor.y, BaseColor.z); - } - - aiColor3D FBXConverter::GetColorPropertyFromMaterial(const PropertyTable& props, const std::string& baseName, - bool& result) - { - return GetColorPropertyFactored(props, baseName + "Color", baseName + "Factor", result, true); - } - - aiColor3D FBXConverter::GetColorProperty(const PropertyTable& props, const std::string& colorName, - bool& result, bool useTemplate) - { - result = true; - bool ok; - const aiVector3D& ColorVec = PropertyGet(props, colorName, ok, useTemplate); - if (!ok) { - result = false; - return aiColor3D(0.0f, 0.0f, 0.0f); - } - return aiColor3D(ColorVec.x, ColorVec.y, ColorVec.z); - } - - void FBXConverter::SetShadingPropertiesCommon(aiMaterial* out_mat, const PropertyTable& props) - { - // Set shading properties. - // Modern FBX Files have two separate systems for defining these, - // with only the more comprehensive one described in the property template. - // Likely the other values are a legacy system, - // which is still always exported by the official FBX SDK. - // - // Blender's FBX import and export mostly ignore this legacy system, - // and as we only support recent versions of FBX anyway, we can do the same. - bool ok; - - const aiColor3D& Diffuse = GetColorPropertyFromMaterial(props, "Diffuse", ok); - if (ok) { - out_mat->AddProperty(&Diffuse, 1, AI_MATKEY_COLOR_DIFFUSE); - } - - const aiColor3D& Emissive = GetColorPropertyFromMaterial(props, "Emissive", ok); - if (ok) { - out_mat->AddProperty(&Emissive, 1, AI_MATKEY_COLOR_EMISSIVE); - } - - const aiColor3D& Ambient = GetColorPropertyFromMaterial(props, "Ambient", ok); - if (ok) { - out_mat->AddProperty(&Ambient, 1, AI_MATKEY_COLOR_AMBIENT); - } - - // we store specular factor as SHININESS_STRENGTH, so just get the color - const aiColor3D& Specular = GetColorProperty(props, "SpecularColor", ok, true); - if (ok) { - out_mat->AddProperty(&Specular, 1, AI_MATKEY_COLOR_SPECULAR); - } - - // and also try to get SHININESS_STRENGTH - const float SpecularFactor = PropertyGet(props, "SpecularFactor", ok, true); - if (ok) { - out_mat->AddProperty(&SpecularFactor, 1, AI_MATKEY_SHININESS_STRENGTH); - } - - // and the specular exponent - const float ShininessExponent = PropertyGet(props, "ShininessExponent", ok); - if (ok) { - out_mat->AddProperty(&ShininessExponent, 1, AI_MATKEY_SHININESS); - } - - // TransparentColor / TransparencyFactor... gee thanks FBX :rolleyes: - const aiColor3D& Transparent = GetColorPropertyFactored(props, "TransparentColor", "TransparencyFactor", ok); - float CalculatedOpacity = 1.0f; - if (ok) { - out_mat->AddProperty(&Transparent, 1, AI_MATKEY_COLOR_TRANSPARENT); - // as calculated by FBX SDK 2017: - CalculatedOpacity = 1.0f - ((Transparent.r + Transparent.g + Transparent.b) / 3.0f); - } - - // try to get the transparency factor - const float TransparencyFactor = PropertyGet(props, "TransparencyFactor", ok); - if (ok) { - out_mat->AddProperty(&TransparencyFactor, 1, AI_MATKEY_TRANSPARENCYFACTOR); - } - - // use of TransparencyFactor is inconsistent. - // Maya always stores it as 1.0, - // so we can't use it to set AI_MATKEY_OPACITY. - // Blender is more sensible and stores it as the alpha value. - // However both the FBX SDK and Blender always write an additional - // legacy "Opacity" field, so we can try to use that. - // - // If we can't find it, - // we can fall back to the value which the FBX SDK calculates - // from transparency colour (RGB) and factor (F) as - // 1.0 - F*((R+G+B)/3). - // - // There's no consistent way to interpret this opacity value, - // so it's up to clients to do the correct thing. - const float Opacity = PropertyGet(props, "Opacity", ok); - if (ok) { - out_mat->AddProperty(&Opacity, 1, AI_MATKEY_OPACITY); - } - else if (CalculatedOpacity != 1.0) { - out_mat->AddProperty(&CalculatedOpacity, 1, AI_MATKEY_OPACITY); - } - - // reflection color and factor are stored separately - const aiColor3D& Reflection = GetColorProperty(props, "ReflectionColor", ok, true); - if (ok) { - out_mat->AddProperty(&Reflection, 1, AI_MATKEY_COLOR_REFLECTIVE); - } - - float ReflectionFactor = PropertyGet(props, "ReflectionFactor", ok, true); - if (ok) { - out_mat->AddProperty(&ReflectionFactor, 1, AI_MATKEY_REFLECTIVITY); - } - - const float BumpFactor = PropertyGet(props, "BumpFactor", ok); - if (ok) { - out_mat->AddProperty(&BumpFactor, 1, AI_MATKEY_BUMPSCALING); - } - - const float DispFactor = PropertyGet(props, "DisplacementFactor", ok); - if (ok) { - out_mat->AddProperty(&DispFactor, 1, "$mat.displacementscaling", 0, 0); + // if we didn't read any meshes set the AI_SCENE_FLAGS_INCOMPLETE + // to make sure the scene passes assimp's validation. FBX files + // need not contain geometry (i.e. camera animations, raw armatures). + if (out->mNumMeshes == 0) { + out->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; } } +FBXConverter::~FBXConverter() { + std::for_each(mMeshes.begin(), mMeshes.end(), Util::delete_fun()); + std::for_each(materials.begin(), materials.end(), Util::delete_fun()); + std::for_each(animations.begin(), animations.end(), Util::delete_fun()); + std::for_each(lights.begin(), lights.end(), Util::delete_fun()); + std::for_each(cameras.begin(), cameras.end(), Util::delete_fun()); + std::for_each(textures.begin(), textures.end(), Util::delete_fun()); +} -void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTable& props, const TextureMap& textures, const MeshGeometry* const mesh) -{ +void FBXConverter::ConvertRootNode() { + mSceneOut->mRootNode = new aiNode(); + std::string unique_name; + GetUniqueName("RootNode", unique_name); + mSceneOut->mRootNode->mName.Set(unique_name); + + // root has ID 0 + ConvertNodes(0L, mSceneOut->mRootNode, mSceneOut->mRootNode); +} + +static std::string getAncestorBaseName(const aiNode *node) { + const char *nodeName = nullptr; + size_t length = 0; + while (node && (!nodeName || length == 0)) { + nodeName = node->mName.C_Str(); + length = node->mName.length; + node = node->mParent; + } + + if (!nodeName || length == 0) { + return {}; + } + // could be std::string_view if c++17 available + return std::string(nodeName, length); +} + +// Make unique name +std::string FBXConverter::MakeUniqueNodeName(const Model *const model, const aiNode &parent) { + std::string original_name = FixNodeName(model->Name()); + if (original_name.empty()) { + original_name = getAncestorBaseName(&parent); + } + std::string unique_name; + GetUniqueName(original_name, unique_name); + return unique_name; +} + +/// todo: pre-build node hierarchy +/// todo: get bone from stack +/// todo: make map of aiBone* to aiNode* +/// then update convert clusters to the new format +void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node) { + const std::vector &conns = doc.GetConnectionsByDestinationSequenced(id, "Model"); + + std::vector nodes; + nodes.reserve(conns.size()); + + std::vector nodes_chain; + std::vector post_nodes_chain; + + try { + for (const Connection *con : conns) { + // ignore object-property links + if (con->PropertyName().length()) { + // really important we document why this is ignored. + FBXImporter::LogInfo("ignoring property link - no docs on why this is ignored"); + continue; //? + } + + // convert connection source object into Object base class + const Object *const object = con->SourceObject(); + if (nullptr == object) { + FBXImporter::LogError("failed to convert source object for Model link"); + continue; + } + + // FBX Model::Cube, Model::Bone001, etc elements + // This detects if we can cast the object into this model structure. + const Model *const model = dynamic_cast(object); + + if (nullptr != model) { + nodes_chain.clear(); + post_nodes_chain.clear(); + + aiMatrix4x4 new_abs_transform = parent->mTransformation; + std::string node_name = FixNodeName(model->Name()); + // even though there is only a single input node, the design of + // assimp (or rather: the complicated transformation chain that + // is employed by fbx) means that we may need multiple aiNode's + // to represent a fbx node's transformation. + + // generate node transforms - this includes pivot data + // if need_additional_node is true then you t + const bool need_additional_node = GenerateTransformationNodeChain(*model, node_name, nodes_chain, post_nodes_chain); + + // assert that for the current node we must have at least a single transform + ai_assert(nodes_chain.size()); + + if (need_additional_node) { + nodes_chain.push_back(new aiNode(node_name)); + } + + //setup metadata on newest node + SetupNodeMetadata(*model, *nodes_chain.back()); + + // link all nodes in a row + aiNode *last_parent = parent; + for (aiNode *child : nodes_chain) { + ai_assert(child); + + if (last_parent != parent) { + last_parent->mNumChildren = 1; + last_parent->mChildren = new aiNode *[1]; + last_parent->mChildren[0] = child; + } + + child->mParent = last_parent; + last_parent = child; + + new_abs_transform *= child->mTransformation; + } + + // attach geometry + ConvertModel(*model, nodes_chain.back(), root_node, new_abs_transform); + + // check if there will be any child nodes + const std::vector &child_conns = doc.GetConnectionsByDestinationSequenced(model->ID(), "Model"); + + // if so, link the geometric transform inverse nodes + // before we attach any child nodes + if (child_conns.size()) { + for (aiNode *postnode : post_nodes_chain) { + ai_assert(postnode); + + if (last_parent != parent) { + last_parent->mNumChildren = 1; + last_parent->mChildren = new aiNode *[1]; + last_parent->mChildren[0] = postnode; + } + + postnode->mParent = last_parent; + last_parent = postnode; + + new_abs_transform *= postnode->mTransformation; + } + } else { + // free the nodes we allocated as we don't need them + Util::delete_fun deleter; + std::for_each( + post_nodes_chain.begin(), + post_nodes_chain.end(), + deleter); + } + + // recursion call - child nodes + ConvertNodes(model->ID(), last_parent, root_node); + + if (doc.Settings().readLights) { + ConvertLights(*model, node_name); + } + + if (doc.Settings().readCameras) { + ConvertCameras(*model, node_name); + } + + nodes.push_back(nodes_chain.front()); + nodes_chain.clear(); + } + } + + if (nodes.size()) { + parent->mChildren = new aiNode *[nodes.size()](); + parent->mNumChildren = static_cast(nodes.size()); + + std::swap_ranges(nodes.begin(), nodes.end(), parent->mChildren); + } else { + parent->mNumChildren = 0; + parent->mChildren = nullptr; + } + + } catch (std::exception &) { + Util::delete_fun deleter; + std::for_each(nodes.begin(), nodes.end(), deleter); + std::for_each(nodes_chain.begin(), nodes_chain.end(), deleter); + std::for_each(post_nodes_chain.begin(), post_nodes_chain.end(), deleter); + } +} + +void FBXConverter::ConvertLights(const Model &model, const std::string &orig_name) { + const std::vector &node_attrs = model.GetAttributes(); + for (const NodeAttribute *attr : node_attrs) { + const Light *const light = dynamic_cast(attr); + if (light) { + ConvertLight(*light, orig_name); + } + } +} + +void FBXConverter::ConvertCameras(const Model &model, const std::string &orig_name) { + const std::vector &node_attrs = model.GetAttributes(); + for (const NodeAttribute *attr : node_attrs) { + const Camera *const cam = dynamic_cast(attr); + if (cam) { + ConvertCamera(*cam, orig_name); + } + } +} + +void FBXConverter::ConvertLight(const Light &light, const std::string &orig_name) { + lights.push_back(new aiLight()); + aiLight *const out_light = lights.back(); + + out_light->mName.Set(orig_name); + + const float intensity = light.Intensity() / 100.0f; + const aiVector3D &col = light.Color(); + + out_light->mColorDiffuse = aiColor3D(col.x, col.y, col.z); + out_light->mColorDiffuse.r *= intensity; + out_light->mColorDiffuse.g *= intensity; + out_light->mColorDiffuse.b *= intensity; + + out_light->mColorSpecular = out_light->mColorDiffuse; + + //lights are defined along negative y direction + out_light->mPosition = aiVector3D(0.0f); + out_light->mDirection = aiVector3D(0.0f, -1.0f, 0.0f); + out_light->mUp = aiVector3D(0.0f, 0.0f, -1.0f); + + switch (light.LightType()) { + case Light::Type_Point: + out_light->mType = aiLightSource_POINT; + break; + + case Light::Type_Directional: + out_light->mType = aiLightSource_DIRECTIONAL; + break; + + case Light::Type_Spot: + out_light->mType = aiLightSource_SPOT; + out_light->mAngleOuterCone = AI_DEG_TO_RAD(light.OuterAngle()); + out_light->mAngleInnerCone = AI_DEG_TO_RAD(light.InnerAngle()); + break; + + case Light::Type_Area: + FBXImporter::LogWarn("cannot represent area light, set to UNDEFINED"); + out_light->mType = aiLightSource_UNDEFINED; + break; + + case Light::Type_Volume: + FBXImporter::LogWarn("cannot represent volume light, set to UNDEFINED"); + out_light->mType = aiLightSource_UNDEFINED; + break; + default: + ai_assert(false); + } + + float decay = light.DecayStart(); + switch (light.DecayType()) { + case Light::Decay_None: + out_light->mAttenuationConstant = decay; + out_light->mAttenuationLinear = 0.0f; + out_light->mAttenuationQuadratic = 0.0f; + break; + case Light::Decay_Linear: + out_light->mAttenuationConstant = 0.0f; + out_light->mAttenuationLinear = 2.0f / decay; + out_light->mAttenuationQuadratic = 0.0f; + break; + case Light::Decay_Quadratic: + out_light->mAttenuationConstant = 0.0f; + out_light->mAttenuationLinear = 0.0f; + out_light->mAttenuationQuadratic = 2.0f / (decay * decay); + break; + case Light::Decay_Cubic: + FBXImporter::LogWarn("cannot represent cubic attenuation, set to Quadratic"); + out_light->mAttenuationQuadratic = 1.0f; + break; + default: + ai_assert(false); + break; + } +} + +void FBXConverter::ConvertCamera(const Camera &cam, const std::string &orig_name) { + cameras.push_back(new aiCamera()); + aiCamera *const out_camera = cameras.back(); + + out_camera->mName.Set(orig_name); + + out_camera->mAspect = cam.AspectWidth() / cam.AspectHeight(); + + out_camera->mPosition = aiVector3D(0.0f); + out_camera->mLookAt = aiVector3D(1.0f, 0.0f, 0.0f); + out_camera->mUp = aiVector3D(0.0f, 1.0f, 0.0f); + + out_camera->mHorizontalFOV = AI_DEG_TO_RAD(cam.FieldOfView()); + + out_camera->mClipPlaneNear = cam.NearPlane(); + out_camera->mClipPlaneFar = cam.FarPlane(); + + out_camera->mHorizontalFOV = AI_DEG_TO_RAD(cam.FieldOfView()); + out_camera->mClipPlaneNear = cam.NearPlane(); + out_camera->mClipPlaneFar = cam.FarPlane(); +} + +void FBXConverter::GetUniqueName(const std::string &name, std::string &uniqueName) { + uniqueName = name; + auto it_pair = mNodeNames.insert({ name, 0 }); // duplicate node name instance count + unsigned int &i = it_pair.first->second; + while (!it_pair.second) { + i++; + std::ostringstream ext; + ext << name << std::setfill('0') << std::setw(3) << i; + uniqueName = ext.str(); + it_pair = mNodeNames.insert({ uniqueName, 0 }); + } +} + +const char *FBXConverter::NameTransformationComp(TransformationComp comp) { + switch (comp) { + case TransformationComp_Translation: + return "Translation"; + case TransformationComp_RotationOffset: + return "RotationOffset"; + case TransformationComp_RotationPivot: + return "RotationPivot"; + case TransformationComp_PreRotation: + return "PreRotation"; + case TransformationComp_Rotation: + return "Rotation"; + case TransformationComp_PostRotation: + return "PostRotation"; + case TransformationComp_RotationPivotInverse: + return "RotationPivotInverse"; + case TransformationComp_ScalingOffset: + return "ScalingOffset"; + case TransformationComp_ScalingPivot: + return "ScalingPivot"; + case TransformationComp_Scaling: + return "Scaling"; + case TransformationComp_ScalingPivotInverse: + return "ScalingPivotInverse"; + case TransformationComp_GeometricScaling: + return "GeometricScaling"; + case TransformationComp_GeometricRotation: + return "GeometricRotation"; + case TransformationComp_GeometricTranslation: + return "GeometricTranslation"; + case TransformationComp_GeometricScalingInverse: + return "GeometricScalingInverse"; + case TransformationComp_GeometricRotationInverse: + return "GeometricRotationInverse"; + case TransformationComp_GeometricTranslationInverse: + return "GeometricTranslationInverse"; + case TransformationComp_MAXIMUM: // this is to silence compiler warnings + default: + break; + } + + ai_assert(false); + + return nullptr; +} + +const char *FBXConverter::NameTransformationCompProperty(TransformationComp comp) { + switch (comp) { + case TransformationComp_Translation: + return "Lcl Translation"; + case TransformationComp_RotationOffset: + return "RotationOffset"; + case TransformationComp_RotationPivot: + return "RotationPivot"; + case TransformationComp_PreRotation: + return "PreRotation"; + case TransformationComp_Rotation: + return "Lcl Rotation"; + case TransformationComp_PostRotation: + return "PostRotation"; + case TransformationComp_RotationPivotInverse: + return "RotationPivotInverse"; + case TransformationComp_ScalingOffset: + return "ScalingOffset"; + case TransformationComp_ScalingPivot: + return "ScalingPivot"; + case TransformationComp_Scaling: + return "Lcl Scaling"; + case TransformationComp_ScalingPivotInverse: + return "ScalingPivotInverse"; + case TransformationComp_GeometricScaling: + return "GeometricScaling"; + case TransformationComp_GeometricRotation: + return "GeometricRotation"; + case TransformationComp_GeometricTranslation: + return "GeometricTranslation"; + case TransformationComp_GeometricScalingInverse: + return "GeometricScalingInverse"; + case TransformationComp_GeometricRotationInverse: + return "GeometricRotationInverse"; + case TransformationComp_GeometricTranslationInverse: + return "GeometricTranslationInverse"; + case TransformationComp_MAXIMUM: // this is to silence compiler warnings + break; + } + + ai_assert(false); + + return nullptr; +} + +aiVector3D FBXConverter::TransformationCompDefaultValue(TransformationComp comp) { + // XXX a neat way to solve the never-ending special cases for scaling + // would be to do everything in log space! + return comp == TransformationComp_Scaling ? aiVector3D(1.f, 1.f, 1.f) : aiVector3D(); +} + +void FBXConverter::GetRotationMatrix(Model::RotOrder mode, const aiVector3D &rotation, aiMatrix4x4 &out) { + if (mode == Model::RotOrder_SphericXYZ) { + FBXImporter::LogError("Unsupported RotationMode: SphericXYZ"); + out = aiMatrix4x4(); + return; + } + + const float angle_epsilon = Math::getEpsilon(); + + out = aiMatrix4x4(); + + bool is_id[3] = { true, true, true }; + + aiMatrix4x4 temp[3]; + if (std::fabs(rotation.z) > angle_epsilon) { + aiMatrix4x4::RotationZ(AI_DEG_TO_RAD(rotation.z), temp[2]); + is_id[2] = false; + } + if (std::fabs(rotation.y) > angle_epsilon) { + aiMatrix4x4::RotationY(AI_DEG_TO_RAD(rotation.y), temp[1]); + is_id[1] = false; + } + if (std::fabs(rotation.x) > angle_epsilon) { + aiMatrix4x4::RotationX(AI_DEG_TO_RAD(rotation.x), temp[0]); + is_id[0] = false; + } + + int order[3] = { -1, -1, -1 }; + + // note: rotation order is inverted since we're left multiplying as is usual in assimp + switch (mode) { + case Model::RotOrder_EulerXYZ: + order[0] = 2; + order[1] = 1; + order[2] = 0; + break; + + case Model::RotOrder_EulerXZY: + order[0] = 1; + order[1] = 2; + order[2] = 0; + break; + + case Model::RotOrder_EulerYZX: + order[0] = 0; + order[1] = 2; + order[2] = 1; + break; + + case Model::RotOrder_EulerYXZ: + order[0] = 2; + order[1] = 0; + order[2] = 1; + break; + + case Model::RotOrder_EulerZXY: + order[0] = 1; + order[1] = 0; + order[2] = 2; + break; + + case Model::RotOrder_EulerZYX: + order[0] = 0; + order[1] = 1; + order[2] = 2; + break; + + default: + ai_assert(false); + break; + } + + ai_assert(order[0] >= 0); + ai_assert(order[0] <= 2); + ai_assert(order[1] >= 0); + ai_assert(order[1] <= 2); + ai_assert(order[2] >= 0); + ai_assert(order[2] <= 2); + + if (!is_id[order[0]]) { + out = temp[order[0]]; + } + + if (!is_id[order[1]]) { + out = out * temp[order[1]]; + } + + if (!is_id[order[2]]) { + out = out * temp[order[2]]; + } +} + +bool FBXConverter::NeedsComplexTransformationChain(const Model &model) { + const PropertyTable &props = model.Props(); + bool ok; + + const float zero_epsilon = 1e-6f; + 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); + + if (comp == TransformationComp_Rotation || comp == TransformationComp_Scaling || comp == TransformationComp_Translation) { + continue; + } + + bool scale_compare = (comp == TransformationComp_GeometricScaling || comp == TransformationComp_Scaling); + + const aiVector3D &v = PropertyGet(props, NameTransformationCompProperty(comp), ok); + if (ok && scale_compare) { + if ((v - all_ones).SquareLength() > zero_epsilon) { + return true; + } + } else if (ok) { + if (v.SquareLength() > zero_epsilon) { + return true; + } + } + } + + return false; +} + +std::string FBXConverter::NameTransformationChainNode(const std::string &name, TransformationComp comp) { + return name + std::string(MAGIC_NODE_TAG) + "_" + NameTransformationComp(comp); +} + +bool FBXConverter::GenerateTransformationNodeChain(const Model &model, const std::string &name, std::vector &output_nodes, + std::vector &post_output_nodes) { + const PropertyTable &props = model.Props(); + const Model::RotOrder rot = model.RotationOrder(); + + bool ok; + + aiMatrix4x4 chain[TransformationComp_MAXIMUM]; + + ai_assert(TransformationComp_MAXIMUM < 32); + std::uint32_t chainBits = 0; + // A node won't need a node chain if it only has these. + const std::uint32_t chainMaskSimple = (1 << TransformationComp_Translation) + (1 << TransformationComp_Scaling) + (1 << TransformationComp_Rotation); + // A node will need a node chain if it has any of these. + const std::uint32_t chainMaskComplex = ((1 << (TransformationComp_MAXIMUM)) - 1) - chainMaskSimple; + + std::fill_n(chain, static_cast(TransformationComp_MAXIMUM), aiMatrix4x4()); + + // generate transformation matrices for all the different transformation components + const float zero_epsilon = Math::getEpsilon(); + const aiVector3D all_ones(1.0f, 1.0f, 1.0f); + + const aiVector3D &PreRotation = PropertyGet(props, "PreRotation", ok); + if (ok && PreRotation.SquareLength() > zero_epsilon) { + chainBits = chainBits | (1 << TransformationComp_PreRotation); + + GetRotationMatrix(Model::RotOrder::RotOrder_EulerXYZ, PreRotation, chain[TransformationComp_PreRotation]); + } + + const aiVector3D &PostRotation = PropertyGet(props, "PostRotation", ok); + if (ok && PostRotation.SquareLength() > zero_epsilon) { + chainBits = chainBits | (1 << TransformationComp_PostRotation); + + GetRotationMatrix(Model::RotOrder::RotOrder_EulerXYZ, PostRotation, chain[TransformationComp_PostRotation]); + } + + const aiVector3D &RotationPivot = PropertyGet(props, "RotationPivot", ok); + if (ok && RotationPivot.SquareLength() > zero_epsilon) { + chainBits = chainBits | (1 << TransformationComp_RotationPivot) | (1 << TransformationComp_RotationPivotInverse); + + aiMatrix4x4::Translation(RotationPivot, chain[TransformationComp_RotationPivot]); + aiMatrix4x4::Translation(-RotationPivot, chain[TransformationComp_RotationPivotInverse]); + } + + const aiVector3D &RotationOffset = PropertyGet(props, "RotationOffset", ok); + if (ok && RotationOffset.SquareLength() > zero_epsilon) { + chainBits = chainBits | (1 << TransformationComp_RotationOffset); + + aiMatrix4x4::Translation(RotationOffset, chain[TransformationComp_RotationOffset]); + } + + const aiVector3D &ScalingOffset = PropertyGet(props, "ScalingOffset", ok); + if (ok && ScalingOffset.SquareLength() > zero_epsilon) { + chainBits = chainBits | (1 << TransformationComp_ScalingOffset); + + aiMatrix4x4::Translation(ScalingOffset, chain[TransformationComp_ScalingOffset]); + } + + const aiVector3D &ScalingPivot = PropertyGet(props, "ScalingPivot", ok); + if (ok && ScalingPivot.SquareLength() > zero_epsilon) { + chainBits = chainBits | (1 << TransformationComp_ScalingPivot) | (1 << TransformationComp_ScalingPivotInverse); + + aiMatrix4x4::Translation(ScalingPivot, chain[TransformationComp_ScalingPivot]); + aiMatrix4x4::Translation(-ScalingPivot, chain[TransformationComp_ScalingPivotInverse]); + } + + const aiVector3D &Translation = PropertyGet(props, "Lcl Translation", ok); + if (ok && Translation.SquareLength() > zero_epsilon) { + chainBits = chainBits | (1 << TransformationComp_Translation); + + aiMatrix4x4::Translation(Translation, chain[TransformationComp_Translation]); + } + + const aiVector3D &Scaling = PropertyGet(props, "Lcl Scaling", ok); + if (ok && (Scaling - all_ones).SquareLength() > zero_epsilon) { + chainBits = chainBits | (1 << TransformationComp_Scaling); + + aiMatrix4x4::Scaling(Scaling, chain[TransformationComp_Scaling]); + } + + const aiVector3D &Rotation = PropertyGet(props, "Lcl Rotation", ok); + if (ok && Rotation.SquareLength() > zero_epsilon) { + chainBits = chainBits | (1 << TransformationComp_Rotation); + + GetRotationMatrix(rot, Rotation, chain[TransformationComp_Rotation]); + } + + const aiVector3D &GeometricScaling = PropertyGet(props, "GeometricScaling", ok); + if (ok && (GeometricScaling - all_ones).SquareLength() > zero_epsilon) { + chainBits = chainBits | (1 << TransformationComp_GeometricScaling); + aiMatrix4x4::Scaling(GeometricScaling, chain[TransformationComp_GeometricScaling]); + aiVector3D GeometricScalingInverse = GeometricScaling; + bool canscale = true; + for (unsigned int i = 0; i < 3; ++i) { + if (std::fabs(GeometricScalingInverse[i]) > zero_epsilon) { + GeometricScalingInverse[i] = 1.0f / GeometricScaling[i]; + } else { + FBXImporter::LogError("cannot invert geometric scaling matrix with a 0.0 scale component"); + canscale = false; + break; + } + } + if (canscale) { + chainBits = chainBits | (1 << TransformationComp_GeometricScalingInverse); + aiMatrix4x4::Scaling(GeometricScalingInverse, chain[TransformationComp_GeometricScalingInverse]); + } + } + + const aiVector3D &GeometricRotation = PropertyGet(props, "GeometricRotation", ok); + if (ok && GeometricRotation.SquareLength() > zero_epsilon) { + chainBits = chainBits | (1 << TransformationComp_GeometricRotation) | (1 << TransformationComp_GeometricRotationInverse); + GetRotationMatrix(rot, GeometricRotation, chain[TransformationComp_GeometricRotation]); + GetRotationMatrix(rot, GeometricRotation, chain[TransformationComp_GeometricRotationInverse]); + chain[TransformationComp_GeometricRotationInverse].Inverse(); + } + + const aiVector3D &GeometricTranslation = PropertyGet(props, "GeometricTranslation", ok); + if (ok && GeometricTranslation.SquareLength() > zero_epsilon) { + chainBits = chainBits | (1 << TransformationComp_GeometricTranslation) | (1 << TransformationComp_GeometricTranslationInverse); + aiMatrix4x4::Translation(GeometricTranslation, chain[TransformationComp_GeometricTranslation]); + aiMatrix4x4::Translation(-GeometricTranslation, chain[TransformationComp_GeometricTranslationInverse]); + } + + // is_complex needs to be consistent with NeedsComplexTransformationChain() + // or the interplay between this code and the animation converter would + // not be guaranteed. + //ai_assert(NeedsComplexTransformationChain(model) == ((chainBits & chainMaskComplex) != 0)); + + // now, if we have more than just Translation, Scaling and Rotation, + // we need to generate a full node chain to accommodate for assimp's + // lack to express pivots and offsets. + if ((chainBits & chainMaskComplex) && doc.Settings().preservePivots) { + FBXImporter::LogInfo("generating full transformation chain for node: " + name); + + // query the anim_chain_bits dictionary to find out which chain elements + // have associated node animation channels. These can not be dropped + // even if they have identity transform in bind pose. + NodeAnimBitMap::const_iterator it = node_anim_chain_bits.find(name); + const unsigned int anim_chain_bitmask = (it == node_anim_chain_bits.end() ? 0 : (*it).second); + + unsigned int bit = 0x1; + for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i, bit <<= 1) { + const TransformationComp comp = static_cast(i); + + if ((chainBits & bit) == 0 && (anim_chain_bitmask & bit) == 0) { + continue; + } + + if (comp == TransformationComp_PostRotation) { + chain[i] = chain[i].Inverse(); + } + + aiNode *nd = new aiNode(); + nd->mName.Set(NameTransformationChainNode(name, comp)); + nd->mTransformation = chain[i]; + + // geometric inverses go in a post-node chain + if (comp == TransformationComp_GeometricScalingInverse || + comp == TransformationComp_GeometricRotationInverse || + comp == TransformationComp_GeometricTranslationInverse) { + post_output_nodes.push_back(nd); + } else { + output_nodes.push_back(nd); + } + } + + ai_assert(output_nodes.size()); + return true; + } + + // else, we can just multiply the matrices together + aiNode *nd = new aiNode(); + output_nodes.push_back(nd); + + // name passed to the method is already unique + nd->mName.Set(name); + // for (const auto &transform : chain) { + // skip inverse chain for no preservePivots + for (unsigned int i = TransformationComp_Translation; i < TransformationComp_MAXIMUM; i++) { + nd->mTransformation = nd->mTransformation * chain[i]; + } + return false; +} + +void FBXConverter::SetupNodeMetadata(const Model &model, aiNode &nd) { + const PropertyTable &props = model.Props(); + DirectPropertyMap unparsedProperties = props.GetUnparsedProperties(); + + // create metadata on node + const std::size_t numStaticMetaData = 2; + aiMetadata *data = aiMetadata::Alloc(static_cast(unparsedProperties.size() + numStaticMetaData)); + nd.mMetaData = data; + int index = 0; + + // find user defined properties (3ds Max) + data->Set(index++, "UserProperties", aiString(PropertyGet(props, "UDP3DSMAX", ""))); + // preserve the info that a node was marked as Null node in the original file. + data->Set(index++, "IsNull", model.IsNull() ? true : false); + + // add unparsed properties to the node's metadata + for (const DirectPropertyMap::value_type &prop : unparsedProperties) { + // Interpret the property as a concrete type + if (const TypedProperty *interpretedBool = prop.second->As>()) { + data->Set(index++, prop.first, interpretedBool->Value()); + } else if (const TypedProperty *interpretedInt = prop.second->As>()) { + data->Set(index++, prop.first, interpretedInt->Value()); + } else if (const TypedProperty *interpretedUint64 = prop.second->As>()) { + data->Set(index++, prop.first, interpretedUint64->Value()); + } else if (const TypedProperty *interpretedFloat = prop.second->As>()) { + data->Set(index++, prop.first, interpretedFloat->Value()); + } else if (const TypedProperty *interpretedString = prop.second->As>()) { + data->Set(index++, prop.first, aiString(interpretedString->Value())); + } else if (const TypedProperty *interpretedVec3 = prop.second->As>()) { + data->Set(index++, prop.first, interpretedVec3->Value()); + } else { + ai_assert(false); + } + } +} + +void FBXConverter::ConvertModel(const Model &model, aiNode *parent, aiNode *root_node, + const aiMatrix4x4 &absolute_transform) { + const std::vector &geos = model.GetGeometry(); + + std::vector meshes; + meshes.reserve(geos.size()); + + for (const Geometry *geo : geos) { + + const MeshGeometry *const mesh = dynamic_cast(geo); + const LineGeometry *const line = dynamic_cast(geo); + if (mesh) { + const std::vector &indices = ConvertMesh(*mesh, model, parent, root_node, + absolute_transform); + std::copy(indices.begin(), indices.end(), std::back_inserter(meshes)); + } else if (line) { + const std::vector &indices = ConvertLine(*line, root_node); + std::copy(indices.begin(), indices.end(), std::back_inserter(meshes)); + } else { + FBXImporter::LogWarn("ignoring unrecognized geometry: " + geo->Name()); + } + } + + if (meshes.size()) { + parent->mMeshes = new unsigned int[meshes.size()](); + parent->mNumMeshes = static_cast(meshes.size()); + + std::swap_ranges(meshes.begin(), meshes.end(), parent->mMeshes); + } +} + +std::vector +FBXConverter::ConvertMesh(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node, + const aiMatrix4x4 &absolute_transform) { + std::vector temp; + + MeshMap::const_iterator it = meshes_converted.find(&mesh); + if (it != meshes_converted.end()) { + std::copy((*it).second.begin(), (*it).second.end(), std::back_inserter(temp)); + return temp; + } + + const std::vector &vertices = mesh.GetVertices(); + const std::vector &faces = mesh.GetFaceIndexCounts(); + if (vertices.empty() || faces.empty()) { + FBXImporter::LogWarn("ignoring empty geometry: " + mesh.Name()); + return temp; + } + + // one material per mesh maps easily to aiMesh. Multiple material + // meshes need to be split. + const MatIndexArray &mindices = mesh.GetMaterialIndices(); + if (doc.Settings().readMaterials && !mindices.empty()) { + const MatIndexArray::value_type base = mindices[0]; + for (MatIndexArray::value_type index : mindices) { + if (index != base) { + return ConvertMeshMultiMaterial(mesh, model, parent, root_node, absolute_transform); + } + } + } + + // faster code-path, just copy the data + temp.push_back(ConvertMeshSingleMaterial(mesh, model, absolute_transform, parent, root_node)); + return temp; +} + +std::vector FBXConverter::ConvertLine(const LineGeometry &line, aiNode *root_node) { + std::vector temp; + + const std::vector &vertices = line.GetVertices(); + const std::vector &indices = line.GetIndices(); + if (vertices.empty() || indices.empty()) { + FBXImporter::LogWarn("ignoring empty line: " + line.Name()); + return temp; + } + + aiMesh *const out_mesh = SetupEmptyMesh(line, root_node); + out_mesh->mPrimitiveTypes |= aiPrimitiveType_LINE; + + // copy vertices + out_mesh->mNumVertices = static_cast(vertices.size()); + out_mesh->mVertices = new aiVector3D[out_mesh->mNumVertices]; + std::copy(vertices.begin(), vertices.end(), out_mesh->mVertices); + + //Number of line segments (faces) is "Number of Points - Number of Endpoints" + //N.B.: Endpoints in FbxLine are denoted by negative indices. + //If such an Index is encountered, add 1 and multiply by -1 to get the real index. + unsigned int epcount = 0; + for (unsigned i = 0; i < indices.size(); i++) { + if (indices[i] < 0) { + epcount++; + } + } + unsigned int pcount = static_cast(indices.size()); + unsigned int scount = out_mesh->mNumFaces = pcount - epcount; + + aiFace *fac = out_mesh->mFaces = new aiFace[scount](); + for (unsigned int i = 0; i < pcount; ++i) { + if (indices[i] < 0) continue; + aiFace &f = *fac++; + f.mNumIndices = 2; //2 == aiPrimitiveType_LINE + f.mIndices = new unsigned int[2]; + f.mIndices[0] = indices[i]; + int segid = indices[(i + 1 == pcount ? 0 : i + 1)]; //If we have reached he last point, wrap around + f.mIndices[1] = (segid < 0 ? (segid + 1) * -1 : segid); //Convert EndPoint Index to normal Index + } + temp.push_back(static_cast(mMeshes.size() - 1)); + return temp; +} + +aiMesh *FBXConverter::SetupEmptyMesh(const Geometry &mesh, aiNode *parent) { + aiMesh *const out_mesh = new aiMesh(); + mMeshes.push_back(out_mesh); + meshes_converted[&mesh].push_back(static_cast(mMeshes.size() - 1)); + + // set name + std::string name = mesh.Name(); + if (name.substr(0, 10) == "Geometry::") { + name = name.substr(10); + } + + if (name.length()) { + out_mesh->mName.Set(name); + } else { + out_mesh->mName = parent->mName; + } + + return out_mesh; +} + +unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry &mesh, const Model &model, + const aiMatrix4x4 &absolute_transform, aiNode *parent, + aiNode *) { + const MatIndexArray &mindices = mesh.GetMaterialIndices(); + aiMesh *const out_mesh = SetupEmptyMesh(mesh, parent); + + const std::vector &vertices = mesh.GetVertices(); + const std::vector &faces = mesh.GetFaceIndexCounts(); + + // copy vertices + out_mesh->mNumVertices = static_cast(vertices.size()); + out_mesh->mVertices = new aiVector3D[vertices.size()]; + + std::copy(vertices.begin(), vertices.end(), out_mesh->mVertices); + + // generate dummy faces + out_mesh->mNumFaces = static_cast(faces.size()); + aiFace *fac = out_mesh->mFaces = new aiFace[faces.size()](); + + unsigned int cursor = 0; + for (unsigned int pcount : faces) { + aiFace &f = *fac++; + f.mNumIndices = pcount; + f.mIndices = new unsigned int[pcount]; + switch (pcount) { + case 1: + out_mesh->mPrimitiveTypes |= aiPrimitiveType_POINT; + break; + case 2: + out_mesh->mPrimitiveTypes |= aiPrimitiveType_LINE; + break; + case 3: + out_mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; + break; + default: + out_mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON; + break; + } + for (unsigned int i = 0; i < pcount; ++i) { + f.mIndices[i] = cursor++; + } + } + + // copy normals + const std::vector &normals = mesh.GetNormals(); + if (normals.size()) { + ai_assert(normals.size() == vertices.size()); + + out_mesh->mNormals = new aiVector3D[vertices.size()]; + std::copy(normals.begin(), normals.end(), out_mesh->mNormals); + } + + // copy tangents - assimp requires both tangents and bitangents (binormals) + // to be present, or neither of them. Compute binormals from normals + // and tangents if needed. + const std::vector &tangents = mesh.GetTangents(); + const std::vector *binormals = &mesh.GetBinormals(); + + if (tangents.size()) { + std::vector tempBinormals; + if (!binormals->size()) { + if (normals.size()) { + tempBinormals.resize(normals.size()); + for (unsigned int i = 0; i < tangents.size(); ++i) { + tempBinormals[i] = normals[i] ^ tangents[i]; + } + + binormals = &tempBinormals; + } else { + binormals = nullptr; + } + } + + if (binormals) { + ai_assert(tangents.size() == vertices.size()); + ai_assert(binormals->size() == vertices.size()); + + out_mesh->mTangents = new aiVector3D[vertices.size()]; + std::copy(tangents.begin(), tangents.end(), out_mesh->mTangents); + + out_mesh->mBitangents = new aiVector3D[vertices.size()]; + std::copy(binormals->begin(), binormals->end(), out_mesh->mBitangents); + } + } + + // copy texture coords + for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { + const std::vector &uvs = mesh.GetTextureCoords(i); + if (uvs.empty()) { + break; + } + + aiVector3D *out_uv = out_mesh->mTextureCoords[i] = new aiVector3D[vertices.size()]; + for (const aiVector2D &v : uvs) { + *out_uv++ = aiVector3D(v.x, v.y, 0.0f); + } + + out_mesh->mNumUVComponents[i] = 2; + } + + // copy vertex colors + for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i) { + const std::vector &colors = mesh.GetVertexColors(i); + if (colors.empty()) { + break; + } + + out_mesh->mColors[i] = new aiColor4D[vertices.size()]; + std::copy(colors.begin(), colors.end(), out_mesh->mColors[i]); + } + + if (!doc.Settings().readMaterials || mindices.empty()) { + FBXImporter::LogError("no material assigned to mesh, setting default material"); + out_mesh->mMaterialIndex = GetDefaultMaterial(); + } else { + ConvertMaterialForMesh(out_mesh, model, mesh, mindices[0]); + } + + if (doc.Settings().readWeights && mesh.DeformerSkin() != nullptr) { + ConvertWeights(out_mesh, mesh, absolute_transform, parent, NO_MATERIAL_SEPARATION, nullptr); + } + + std::vector animMeshes; + for (const BlendShape *blendShape : mesh.GetBlendShapes()) { + for (const BlendShapeChannel *blendShapeChannel : blendShape->BlendShapeChannels()) { + const std::vector &shapeGeometries = blendShapeChannel->GetShapeGeometries(); + for (size_t i = 0; i < shapeGeometries.size(); i++) { + aiAnimMesh *animMesh = aiCreateAnimMesh(out_mesh); + const ShapeGeometry *shapeGeometry = shapeGeometries.at(i); + const std::vector &curVertices = shapeGeometry->GetVertices(); + const std::vector &curNormals = shapeGeometry->GetNormals(); + const std::vector &curIndices = shapeGeometry->GetIndices(); + animMesh->mName.Set(FixAnimMeshName(shapeGeometry->Name())); + for (size_t j = 0; j < curIndices.size(); j++) { + const unsigned int curIndex = curIndices.at(j); + aiVector3D vertex = curVertices.at(j); + aiVector3D normal = curNormals.at(j); + unsigned int count = 0; + const unsigned int *outIndices = mesh.ToOutputVertexIndex(curIndex, count); + for (unsigned int k = 0; k < count; k++) { + unsigned int index = outIndices[k]; + animMesh->mVertices[index] += vertex; + if (animMesh->mNormals != nullptr) { + animMesh->mNormals[index] += normal; + animMesh->mNormals[index].NormalizeSafe(); + } + } + } + animMesh->mWeight = shapeGeometries.size() > 1 ? blendShapeChannel->DeformPercent() / 100.0f : 1.0f; + animMeshes.push_back(animMesh); + } + } + } + const size_t numAnimMeshes = animMeshes.size(); + if (numAnimMeshes > 0) { + out_mesh->mNumAnimMeshes = static_cast(numAnimMeshes); + out_mesh->mAnimMeshes = new aiAnimMesh *[numAnimMeshes]; + for (size_t i = 0; i < numAnimMeshes; i++) { + out_mesh->mAnimMeshes[i] = animMeshes.at(i); + } + } + return static_cast(mMeshes.size() - 1); +} + +std::vector +FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, aiNode *parent, + aiNode *root_node, + const aiMatrix4x4 &absolute_transform) { + const MatIndexArray &mindices = mesh.GetMaterialIndices(); + ai_assert(mindices.size()); + + std::set had; + std::vector indices; + + for (MatIndexArray::value_type index : mindices) { + if (had.find(index) == had.end()) { + + indices.push_back(ConvertMeshMultiMaterial(mesh, model, index, parent, root_node, absolute_transform)); + had.insert(index); + } + } + + return indices; +} + +unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, + MatIndexArray::value_type index, + aiNode *parent, aiNode *, + const aiMatrix4x4 &absolute_transform) { + aiMesh *const out_mesh = SetupEmptyMesh(mesh, parent); + + const MatIndexArray &mindices = mesh.GetMaterialIndices(); + const std::vector &vertices = mesh.GetVertices(); + const std::vector &faces = mesh.GetFaceIndexCounts(); + + const bool process_weights = doc.Settings().readWeights && mesh.DeformerSkin() != nullptr; + + unsigned int count_faces = 0; + unsigned int count_vertices = 0; + + // count faces + std::vector::const_iterator itf = faces.begin(); + for (MatIndexArray::const_iterator it = mindices.begin(), + end = mindices.end(); + it != end; ++it, ++itf) { + if ((*it) != index) { + continue; + } + ++count_faces; + count_vertices += *itf; + } + + ai_assert(count_faces); + ai_assert(count_vertices); + + // mapping from output indices to DOM indexing, needed to resolve weights or blendshapes + std::vector reverseMapping; + std::map translateIndexMap; + if (process_weights || mesh.GetBlendShapes().size() > 0) { + reverseMapping.resize(count_vertices); + } + + // allocate output data arrays, but don't fill them yet + out_mesh->mNumVertices = count_vertices; + out_mesh->mVertices = new aiVector3D[count_vertices]; + + out_mesh->mNumFaces = count_faces; + aiFace *fac = out_mesh->mFaces = new aiFace[count_faces](); + + // allocate normals + const std::vector &normals = mesh.GetNormals(); + if (normals.size()) { + ai_assert(normals.size() == vertices.size()); + out_mesh->mNormals = new aiVector3D[vertices.size()]; + } + + // allocate tangents, binormals. + const std::vector &tangents = mesh.GetTangents(); + const std::vector *binormals = &mesh.GetBinormals(); + std::vector tempBinormals; + + if (tangents.size()) { + if (!binormals->size()) { + if (normals.size()) { + // XXX this computes the binormals for the entire mesh, not only + // the part for which we need them. + tempBinormals.resize(normals.size()); + for (unsigned int i = 0; i < tangents.size(); ++i) { + tempBinormals[i] = normals[i] ^ tangents[i]; + } + + binormals = &tempBinormals; + } else { + binormals = nullptr; + } + } + + if (binormals) { + ai_assert(tangents.size() == vertices.size() && binormals->size() == vertices.size()); + + out_mesh->mTangents = new aiVector3D[vertices.size()]; + out_mesh->mBitangents = new aiVector3D[vertices.size()]; + } + } + + // allocate texture coords + unsigned int num_uvs = 0; + for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i, ++num_uvs) { + const std::vector &uvs = mesh.GetTextureCoords(i); + if (uvs.empty()) { + break; + } + + out_mesh->mTextureCoords[i] = new aiVector3D[vertices.size()]; + out_mesh->mNumUVComponents[i] = 2; + } + + // allocate vertex colors + unsigned int num_vcs = 0; + for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i, ++num_vcs) { + const std::vector &colors = mesh.GetVertexColors(i); + if (colors.empty()) { + break; + } + + out_mesh->mColors[i] = new aiColor4D[vertices.size()]; + } + + unsigned int cursor = 0, in_cursor = 0; + + itf = faces.begin(); + for (MatIndexArray::const_iterator it = mindices.begin(), end = mindices.end(); it != end; ++it, ++itf) { + const unsigned int pcount = *itf; + if ((*it) != index) { + in_cursor += pcount; + continue; + } + + aiFace &f = *fac++; + + f.mNumIndices = pcount; + f.mIndices = new unsigned int[pcount]; + switch (pcount) { + case 1: + out_mesh->mPrimitiveTypes |= aiPrimitiveType_POINT; + break; + case 2: + out_mesh->mPrimitiveTypes |= aiPrimitiveType_LINE; + break; + case 3: + out_mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; + break; + default: + out_mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON; + break; + } + for (unsigned int i = 0; i < pcount; ++i, ++cursor, ++in_cursor) { + f.mIndices[i] = cursor; + + if (reverseMapping.size()) { + reverseMapping[cursor] = in_cursor; + translateIndexMap[in_cursor] = cursor; + } + + out_mesh->mVertices[cursor] = vertices[in_cursor]; + + if (out_mesh->mNormals) { + out_mesh->mNormals[cursor] = normals[in_cursor]; + } + + if (out_mesh->mTangents) { + out_mesh->mTangents[cursor] = tangents[in_cursor]; + out_mesh->mBitangents[cursor] = (*binormals)[in_cursor]; + } + + for (unsigned int j = 0; j < num_uvs; ++j) { + const std::vector &uvs = mesh.GetTextureCoords(j); + out_mesh->mTextureCoords[j][cursor] = aiVector3D(uvs[in_cursor].x, uvs[in_cursor].y, 0.0f); + } + + for (unsigned int j = 0; j < num_vcs; ++j) { + const std::vector &cols = mesh.GetVertexColors(j); + out_mesh->mColors[j][cursor] = cols[in_cursor]; + } + } + } + + ConvertMaterialForMesh(out_mesh, model, mesh, index); + + if (process_weights) { + ConvertWeights(out_mesh, mesh, absolute_transform, parent, index, &reverseMapping); + } + + std::vector animMeshes; + for (const BlendShape *blendShape : mesh.GetBlendShapes()) { + for (const BlendShapeChannel *blendShapeChannel : blendShape->BlendShapeChannels()) { + const std::vector &shapeGeometries = blendShapeChannel->GetShapeGeometries(); + for (size_t i = 0; i < shapeGeometries.size(); i++) { + aiAnimMesh *animMesh = aiCreateAnimMesh(out_mesh); + const ShapeGeometry *shapeGeometry = shapeGeometries.at(i); + const std::vector &curVertices = shapeGeometry->GetVertices(); + const std::vector &curNormals = shapeGeometry->GetNormals(); + const std::vector &curIndices = shapeGeometry->GetIndices(); + animMesh->mName.Set(FixAnimMeshName(shapeGeometry->Name())); + for (size_t j = 0; j < curIndices.size(); j++) { + unsigned int curIndex = curIndices.at(j); + aiVector3D vertex = curVertices.at(j); + aiVector3D normal = curNormals.at(j); + unsigned int count = 0; + const unsigned int *outIndices = mesh.ToOutputVertexIndex(curIndex, count); + for (unsigned int k = 0; k < count; k++) { + unsigned int outIndex = outIndices[k]; + if (translateIndexMap.find(outIndex) == translateIndexMap.end()) + continue; + unsigned int transIndex = translateIndexMap[outIndex]; + animMesh->mVertices[transIndex] += vertex; + if (animMesh->mNormals != nullptr) { + animMesh->mNormals[transIndex] += normal; + animMesh->mNormals[transIndex].NormalizeSafe(); + } + } + } + animMesh->mWeight = shapeGeometries.size() > 1 ? blendShapeChannel->DeformPercent() / 100.0f : 1.0f; + animMeshes.push_back(animMesh); + } + } + } + + const size_t numAnimMeshes = animMeshes.size(); + if (numAnimMeshes > 0) { + out_mesh->mNumAnimMeshes = static_cast(numAnimMeshes); + out_mesh->mAnimMeshes = new aiAnimMesh *[numAnimMeshes]; + for (size_t i = 0; i < numAnimMeshes; i++) { + out_mesh->mAnimMeshes[i] = animMeshes.at(i); + } + } + + return static_cast(mMeshes.size() - 1); +} + +void FBXConverter::ConvertWeights(aiMesh *out, const MeshGeometry &geo, + const aiMatrix4x4 &absolute_transform, + aiNode *parent, unsigned int materialIndex, + std::vector *outputVertStartIndices) { + ai_assert(geo.DeformerSkin()); + + std::vector out_indices; + std::vector index_out_indices; + std::vector count_out_indices; + + const Skin &sk = *geo.DeformerSkin(); + + std::vector bones; + + const bool no_mat_check = materialIndex == NO_MATERIAL_SEPARATION; + ai_assert(no_mat_check || outputVertStartIndices); + + try { + // iterate over the sub deformers + for (const Cluster *cluster : sk.Clusters()) { + ai_assert(cluster); + + const WeightIndexArray &indices = cluster->GetIndices(); + + const MatIndexArray &mats = geo.GetMaterialIndices(); + + const size_t no_index_sentinel = std::numeric_limits::max(); + + count_out_indices.clear(); + index_out_indices.clear(); + out_indices.clear(); + + // now check if *any* of these weights is contained in the output mesh, + // taking notes so we don't need to do it twice. + for (WeightIndexArray::value_type index : indices) { + + unsigned int count = 0; + const unsigned int *const out_idx = geo.ToOutputVertexIndex(index, count); + // ToOutputVertexIndex only returns nullptr if index is out of bounds + // which should never happen + ai_assert(out_idx != nullptr); + + index_out_indices.push_back(no_index_sentinel); + count_out_indices.push_back(0); + + for (unsigned int i = 0; i < count; ++i) { + if (no_mat_check || static_cast(mats[geo.FaceForVertexIndex(out_idx[i])]) == materialIndex) { + + if (index_out_indices.back() == no_index_sentinel) { + index_out_indices.back() = out_indices.size(); + } + + if (no_mat_check) { + out_indices.push_back(out_idx[i]); + } else { + // this extra lookup is in O(logn), so the entire algorithm becomes O(nlogn) + const std::vector::iterator it = std::lower_bound( + outputVertStartIndices->begin(), + outputVertStartIndices->end(), + out_idx[i]); + + out_indices.push_back(std::distance(outputVertStartIndices->begin(), it)); + } + + ++count_out_indices.back(); + } + } + } + + // if we found at least one, generate the output bones + // XXX this could be heavily simplified by collecting the bone + // data in a single step. + ConvertCluster(bones, cluster, out_indices, index_out_indices, + count_out_indices, absolute_transform, parent); + } + + bone_map.clear(); + } catch (std::exception &) { + std::for_each(bones.begin(), bones.end(), Util::delete_fun()); + throw; + } + + if (bones.empty()) { + out->mBones = nullptr; + out->mNumBones = 0; + return; + } else { + out->mBones = new aiBone *[bones.size()](); + out->mNumBones = static_cast(bones.size()); + + std::swap_ranges(bones.begin(), bones.end(), out->mBones); + } +} + +const aiNode *GetNodeByName(aiNode *current_node) { + aiNode *iter = current_node; + //printf("Child count: %d", iter->mNumChildren); + return iter; +} + +void FBXConverter::ConvertCluster(std::vector &local_mesh_bones, const Cluster *cl, + std::vector &out_indices, std::vector &index_out_indices, + std::vector &count_out_indices, const aiMatrix4x4 &absolute_transform, + aiNode *) { + ai_assert(cl); // make sure cluster valid + std::string deformer_name = cl->TargetNode()->Name(); + aiString bone_name = aiString(FixNodeName(deformer_name)); + + aiBone *bone = nullptr; + + if (bone_map.count(deformer_name)) { + ASSIMP_LOG_DEBUG_F("retrieved bone from lookup ", bone_name.C_Str(), ". Deformer:", deformer_name); + bone = bone_map[deformer_name]; + } else { + ASSIMP_LOG_DEBUG_F("created new bone ", bone_name.C_Str(), ". Deformer: ", deformer_name); + bone = new aiBone(); + bone->mName = bone_name; + + // store local transform link for post processing + bone->mOffsetMatrix = cl->TransformLink(); + bone->mOffsetMatrix.Inverse(); + + aiMatrix4x4 matrix = (aiMatrix4x4)absolute_transform; + + bone->mOffsetMatrix = bone->mOffsetMatrix * matrix; // * mesh_offset + + // + // Now calculate the aiVertexWeights + // + + aiVertexWeight *cursor = nullptr; + + bone->mNumWeights = static_cast(out_indices.size()); + cursor = bone->mWeights = new aiVertexWeight[out_indices.size()]; + + const size_t no_index_sentinel = std::numeric_limits::max(); + const WeightArray &weights = cl->GetWeights(); + + const size_t c = index_out_indices.size(); + for (size_t i = 0; i < c; ++i) { + const size_t index_index = index_out_indices[i]; + + if (index_index == no_index_sentinel) { + continue; + } + + const size_t cc = count_out_indices[i]; + for (size_t j = 0; j < cc; ++j) { + // cursor runs from first element relative to the start + // or relative to the start of the next indexes. + aiVertexWeight &out_weight = *cursor++; + + out_weight.mVertexId = static_cast(out_indices[index_index + j]); + out_weight.mWeight = weights[i]; + } + } + + bone_map.insert(std::pair(deformer_name, bone)); + } + + ASSIMP_LOG_DEBUG_F("bone research: Indicies size: ", out_indices.size()); + + // lookup must be populated in case something goes wrong + // this also allocates bones to mesh instance outside + local_mesh_bones.push_back(bone); +} + +void FBXConverter::ConvertMaterialForMesh(aiMesh *out, const Model &model, const MeshGeometry &geo, + MatIndexArray::value_type materialIndex) { + // locate source materials for this mesh + const std::vector &mats = model.GetMaterials(); + if (static_cast(materialIndex) >= mats.size() || materialIndex < 0) { + FBXImporter::LogError("material index out of bounds, setting default material"); + out->mMaterialIndex = GetDefaultMaterial(); + return; + } + + const Material *const mat = mats[materialIndex]; + MaterialMap::const_iterator it = materials_converted.find(mat); + if (it != materials_converted.end()) { + out->mMaterialIndex = (*it).second; + return; + } + + out->mMaterialIndex = ConvertMaterial(*mat, &geo); + materials_converted[mat] = out->mMaterialIndex; +} + +unsigned int FBXConverter::GetDefaultMaterial() { + if (defaultMaterialIndex) { + return defaultMaterialIndex - 1; + } + + aiMaterial *out_mat = new aiMaterial(); + materials.push_back(out_mat); + + const aiColor3D diffuse = aiColor3D(0.8f, 0.8f, 0.8f); + out_mat->AddProperty(&diffuse, 1, AI_MATKEY_COLOR_DIFFUSE); + + aiString s; + s.Set(AI_DEFAULT_MATERIAL_NAME); + + out_mat->AddProperty(&s, AI_MATKEY_NAME); + + defaultMaterialIndex = static_cast(materials.size()); + return defaultMaterialIndex - 1; +} + +unsigned int FBXConverter::ConvertMaterial(const Material &material, const MeshGeometry *const mesh) { + const PropertyTable &props = material.Props(); + + // generate empty output material + aiMaterial *out_mat = new aiMaterial(); + materials_converted[&material] = static_cast(materials.size()); + + materials.push_back(out_mat); + + aiString str; + + // strip Material:: prefix + std::string name = material.Name(); + if (name.substr(0, 10) == "Material::") { + name = name.substr(10); + } + + // set material name if not empty - this could happen + // and there should be no key for it in this case. + if (name.length()) { + str.Set(name); + out_mat->AddProperty(&str, AI_MATKEY_NAME); + } + + // Set the shading mode as best we can: The FBX specification only mentions Lambert and Phong, and only Phong is mentioned in Assimp's aiShadingMode enum. + if (material.GetShadingModel() == "phong") { + aiShadingMode shadingMode = aiShadingMode_Phong; + out_mat->AddProperty(&shadingMode, 1, AI_MATKEY_SHADING_MODEL); + } + + // shading stuff and colors + SetShadingPropertiesCommon(out_mat, props); + SetShadingPropertiesRaw(out_mat, props, material.Textures(), mesh); + + // texture assignments + SetTextureProperties(out_mat, material.Textures(), mesh); + SetTextureProperties(out_mat, material.LayeredTextures(), mesh); + + return static_cast(materials.size() - 1); +} + +unsigned int FBXConverter::ConvertVideo(const Video &video) { + // generate empty output texture + aiTexture *out_tex = new aiTexture(); + textures.push_back(out_tex); + + // assuming the texture is compressed + out_tex->mWidth = static_cast(video.ContentLength()); // total data size + out_tex->mHeight = 0; // fixed to 0 + + // steal the data from the Video to avoid an additional copy + out_tex->pcData = reinterpret_cast(const_cast