diff --git a/.gitignore b/.gitignore index f8dda3e8b..d383f3ec8 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,8 @@ build bin/ lib/ +# QtCreator +CMakeLists.txt.user # Generated assimp.pc @@ -19,6 +21,7 @@ revision.h contrib/zlib/zconf.h contrib/zlib/zlib.pc include/assimp/config.h +unit.vcxproj.user # CMake CMakeCache.txt @@ -85,3 +88,9 @@ lib64/assimp-vc120-mt.exp xcuserdata cmake-build-debug +install_manifest.txt +tools/assimp_qt_viewer/moc_glview.cpp +tools/assimp_qt_viewer/moc_glview.cpp_parameters +tools/assimp_qt_viewer/moc_mainwindow.cpp +tools/assimp_qt_viewer/moc_mainwindow.cpp_parameters +tools/assimp_qt_viewer/ui_mainwindow.h diff --git a/Build.md b/Build.md new file mode 100644 index 000000000..b548c1794 --- /dev/null +++ b/Build.md @@ -0,0 +1,7 @@ +# Build instructions + +> cmake CMakeLists.txt +make -j4 + +##UWP +See https://stackoverflow.com/questions/40803170/cmake-uwp-using-cmake-to-build-universal-windows-app diff --git a/CMakeLists.txt b/CMakeLists.txt index cb407c4b1..f1482fdfa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,10 +39,12 @@ CMAKE_MINIMUM_REQUIRED( VERSION 2.8 ) PROJECT( Assimp ) # All supported options ############################################### + OPTION( BUILD_SHARED_LIBS "Build package with shared libraries." ON ) + OPTION( BUILD_FRAMEWORK "Build package as Mac OS X Framework bundle." OFF @@ -103,6 +105,16 @@ OPTION ( BUILD_DOCS "Build documentation using Doxygen." OFF ) +OPTION( INJECT_DEBUG_POSTFIX + "Inject debug postfix in .a/.so lib names" + ON +) + +IF (IOS) + IF (NOT CMAKE_BUILD_TYPE) + SET(CMAKE_BUILD_TYPE "Release") + ENDIF (NOT CMAKE_BUILD_TYPE) +ENDIF (IOS) # Use subset of Windows.h if (WIN32) @@ -152,7 +164,7 @@ EXECUTE_PROCESS( # Get the latest abbreviated commit hash of the working branch EXECUTE_PROCESS( - COMMAND git log -1 --format=%h + COMMAND git log -1 --format=%h --no-show-signature WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} OUTPUT_VARIABLE GIT_COMMIT_HASH OUTPUT_STRIP_TRAILING_WHITESPACE @@ -198,13 +210,13 @@ ENDIF( UNIX ) # Grouped compiler settings IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT CMAKE_COMPILER_IS_MINGW) # hide all not-exported symbols - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fvisibility=hidden -fPIC -Wall -std=c++0x") - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") + SET(CMAKE_CXX_FLAGS "-g -fvisibility=hidden -fPIC -fno-strict-aliasing -Wall -std=c++0x ${CMAKE_CXX_FLAGS}") + SET(CMAKE_C_FLAGS "-fPIC -fno-strict-aliasing ${CMAKE_C_FLAGS}") SET(LIBSTDC++_LIBRARIES -lstdc++) ELSEIF(MSVC) # enable multi-core compilation with MSVC ADD_COMPILE_OPTIONS(/MP) - IF("${CMAKE_GENERATOR}" MATCHES "(Win64|IA64)") + if(CMAKE_SIZEOF_VOID_P EQUAL 8) ADD_COMPILE_OPTIONS( /bigobj ) ENDIF() # disable "elements of array '' will be default initialized" warning on MSVC2013 @@ -212,19 +224,26 @@ ELSEIF(MSVC) ADD_COMPILE_OPTIONS(/wd4351) ENDIF() ELSEIF ( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" ) - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fvisibility=hidden -fPIC -Wall -Wno-long-long -std=c++11" ) - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") + SET(CMAKE_CXX_FLAGS "-g -fvisibility=hidden -fPIC -fno-strict-aliasing -Wall -Wno-long-long -std=c++11 ${CMAKE_CXX_FLAGS}" ) + SET(CMAKE_C_FLAGS "-fPIC -fno-strict-aliasing ${CMAKE_C_FLAGS}") ELSEIF( CMAKE_COMPILER_IS_MINGW ) - SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -Wall -Wno-long-long -std=c++11" ) - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") + SET( CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall -Wno-long-long -std=c++11 -Wa,-mbig-obj ${CMAKE_CXX_FLAGS}" ) + SET(CMAKE_C_FLAGS "-fPIC -fno-strict-aliasing ${CMAKE_C_FLAGS} ") ADD_DEFINITIONS( -U__STRICT_ANSI__ ) ENDIF() -IF (IOS) - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fembed-bitcode -O3") +IF ( IOS ) + +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") +ELSE() + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fembed-bitcode -O3") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fembed-bitcode -O3") ENDIF() +ENDIF( IOS ) + IF (ASSIMP_COVERALLS) MESSAGE(STATUS "Coveralls enabled") INCLUDE(Coveralls) @@ -320,6 +339,8 @@ IF( NOT ZLIB_FOUND ) SET(ZLIB_FOUND 1) SET(ZLIB_LIBRARIES zlibstatic) SET(ZLIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/contrib/zlib ${CMAKE_CURRENT_BINARY_DIR}/contrib/zlib) + # need to ensure we don't link with system zlib or minizip as well. + SET(ASSIMP_BUILD_MINIZIP 1) ELSE(NOT ZLIB_FOUND) ADD_DEFINITIONS(-DASSIMP_BUILD_NO_OWN_ZLIB) SET(ZLIB_LIBRARIES_LINKED -lz) @@ -327,7 +348,17 @@ ENDIF(NOT ZLIB_FOUND) INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR}) # Search for unzip -use_pkgconfig(UNZIP minizip) +IF ( NOT IOS ) + IF( NOT ASSIMP_BUILD_MINIZIP ) + use_pkgconfig(UNZIP minizip) + ENDIF( NOT ASSIMP_BUILD_MINIZIP ) +ELSE ( NOT IOS ) + IF(NOT BUILD_SHARED_LIBS) + IF( NOT ASSIMP_BUILD_MINIZIP ) + use_pkgconfig(UNZIP minizip) + ENDIF( NOT ASSIMP_BUILD_MINIZIP ) + ENDIF (NOT BUILD_SHARED_LIBS) +ENDIF ( NOT IOS ) IF ( ASSIMP_NO_EXPORT ) ADD_DEFINITIONS( -DASSIMP_BUILD_NO_EXPORT) @@ -412,32 +443,9 @@ IF ( ASSIMP_BUILD_ASSIMP_TOOLS ) ENDIF ( WIN32 AND DirectX_D3DX9_LIBRARY ) ADD_SUBDIRECTORY( tools/assimp_cmd/ ) - - # Check dependencies for assimp_qt_viewer. - # Why here? Maybe user do not want Qt viewer and have no Qt. - # Why assimp_qt_viewer/CMakeLists.txt still contain similar check? - # Because viewer can be build independently of Assimp. - FIND_PACKAGE(Qt5Widgets QUIET) - FIND_PACKAGE(DevIL QUIET) - FIND_PACKAGE(OpenGL QUIET) - IF ( Qt5Widgets_FOUND AND IL_FOUND AND OPENGL_FOUND) - ADD_SUBDIRECTORY( tools/assimp_qt_viewer/ ) - ELSE() - SET ( ASSIMP_QT_VIEWER_DEPENDENCIES "") - IF (NOT Qt5_FOUND) - SET ( ASSIMP_QT_VIEWER_DEPENDENCIES "${ASSIMP_QT_VIEWER_DEPENDENCIES} Qt5") - ENDIF (NOT Qt5_FOUND) - - IF (NOT IL_FOUND) - SET ( ASSIMP_QT_VIEWER_DEPENDENCIES "${ASSIMP_QT_VIEWER_DEPENDENCIES} DevIL") - ENDIF (NOT IL_FOUND) - - IF (NOT OPENGL_FOUND) - SET ( ASSIMP_QT_VIEWER_DEPENDENCIES "${ASSIMP_QT_VIEWER_DEPENDENCIES} OpengGL") - ENDIF (NOT OPENGL_FOUND) - - MESSAGE (WARNING "Build of assimp_qt_viewer is disabled. Unsatisfied dendencies: ${ASSIMP_QT_VIEWER_DEPENDENCIES}") - ENDIF ( Qt5Widgets_FOUND AND IL_FOUND AND OPENGL_FOUND) +IF (NOT IOS) + ADD_SUBDIRECTORY( tools/assimp_qt_viewer/ ) +ENDIF (NOT IOS) ENDIF ( ASSIMP_BUILD_ASSIMP_TOOLS ) IF ( ASSIMP_BUILD_SAMPLES) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6aebbbd01..82ef07a65 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,11 +1,10 @@ -#How to contribute +# How to contribute -If you want to contribute you can follow these setps: -- Fist create your own clone of assimp -- When you want to fix a bug or add a new feature create a branch on your own fork ( just follow https://help.github.com/articles/creating-a-pull-request-from-a-fork/ ) -- Push it to the repo and open a pull request -- A pull request will start our CI-service, which checks if the build works for linux and windows. - It will check for memory leaks, compiler warnings and memory alignment issues. If any of these tests fails: fix it and the tests will be reastarted automatically - - At the end we will perform a code review and merge your branch to the master branch. - - +If you want to contribute, follow these steps: + +- First, create your own clone of assimp. +- When you want to fix a bug or add a new feature, create a branch on your own fork following [these instructions](https://help.github.com/articles/creating-a-pull-request-from-a-fork/). +- Push it to your fork of the repository and open a pull request. +- A pull request will start our continuous integration service, which checks if the build works for Linux and Windows. + It will check for memory leaks, compiler warnings and memory alignment issues. If any of these tests fail, fix it and the tests will be restarted automatically. + - At the end, we will perform a code review and merge your branch to the master branch. diff --git a/INSTALL b/INSTALL index 3baaddc4a..357918d6b 100644 --- a/INSTALL +++ b/INSTALL @@ -42,3 +42,6 @@ For Windows: 1. Open a command prompt 2. cmake CMakeLists.txt 2. Open your default IDE and build it + +For iOS: +Just check the following project, which deploys a compiler toolchain for different iOS-versions: https://github.com/assimp/assimp/tree/master/port/iOS diff --git a/Readme.md b/Readme.md index 449efc547..ac71a29db 100644 --- a/Readme.md +++ b/Readme.md @@ -30,6 +30,8 @@ One-off donations via PayPal: Please check our Wiki as well: https://github.com/assimp/assimp/wiki +If you want to check our Model-Database, use the following repo: https://github.com/assimp/assimp-mdb + #### Supported file formats #### __Importers__: diff --git a/appveyor.yml b/appveyor.yml index 1b87286f6..2b5f212f9 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -32,6 +32,9 @@ install: - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" set CMAKE_GENERATOR_NAME=Visual Studio 15 2017 - if "%platform%"=="x64" set CMAKE_GENERATOR_NAME=%CMAKE_GENERATOR_NAME% Win64 - cmake %CMAKE_DEFINES% -G "%CMAKE_GENERATOR_NAME%" + - set PATH=%PATH%;"C:\\Program Files (x86)\\Inno Setup 5" + - ps: Invoke-WebRequest -Uri https://download.microsoft.com/download/5/7/b/57b2947c-7221-4f33-b35e-2fc78cb10df4/vc_redist.x64.exe -OutFile .\packaging\windows-innosetup\vc_redist.x64.exe + - ps: Invoke-WebRequest -Uri https://download.microsoft.com/download/1/d/8/1d8137db-b5bb-4925-8c5d-927424a2e4de/vc_redist.x86.exe -OutFile .\packaging\windows-innosetup\vc_redist.x86.exe cache: - code\assimp.dir\%CONFIGURATION% @@ -50,6 +53,7 @@ build: project: Assimp.sln after_build: + - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" iscc packaging\windows-innosetup\script.iss - 7z a assimp.7z bin\%CONFIGURATION%\* lib\%CONFIGURATION%\* test_script: diff --git a/code/3DSConverter.cpp b/code/3DSConverter.cpp index e07ca4c2d..7ec79ba64 100644 --- a/code/3DSConverter.cpp +++ b/code/3DSConverter.cpp @@ -204,8 +204,9 @@ void CopyTexture(aiMaterial& mat, D3DS::Texture& texture, aiTextureType type) mat.AddProperty( &texture.mTextureBlend, 1, AI_MATKEY_TEXBLEND(type,0)); // Setup the texture mapping mode - mat.AddProperty((int*)&texture.mMapMode,1,AI_MATKEY_MAPPINGMODE_U(type,0)); - mat.AddProperty((int*)&texture.mMapMode,1,AI_MATKEY_MAPPINGMODE_V(type,0)); + int mapMode = static_cast(texture.mMapMode); + mat.AddProperty(&mapMode,1,AI_MATKEY_MAPPINGMODE_U(type,0)); + mat.AddProperty(&mapMode,1,AI_MATKEY_MAPPINGMODE_V(type,0)); // Mirroring - double the scaling values // FIXME: this is not really correct ... @@ -313,7 +314,8 @@ void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat, case D3DS::Discreet3DS::Blinn : eShading = aiShadingMode_Blinn; break; } - mat.AddProperty( (int*)&eShading,1,AI_MATKEY_SHADING_MODEL); + int eShading_ = static_cast(eShading); + mat.AddProperty(&eShading_, 1, AI_MATKEY_SHADING_MODEL); // DIFFUSE texture if( oldMat.sTexDiffuse.mMapName.length() > 0) diff --git a/code/3DSHelper.h b/code/3DSHelper.h index 7476438bd..a904abb20 100644 --- a/code/3DSHelper.h +++ b/code/3DSHelper.h @@ -66,7 +66,7 @@ namespace D3DS { */ class Discreet3DS { private: - Discreet3DS() { + Discreet3DS() AI_NO_EXCEPT { // empty } @@ -328,19 +328,17 @@ struct Face : public FaceWithSmoothingGroup // --------------------------------------------------------------------------- /** Helper structure representing a texture */ -struct Texture -{ +struct Texture { //! Default constructor - Texture() - : mOffsetU (0.0) - , mOffsetV (0.0) - , mScaleU (1.0) - , mScaleV (1.0) - , mRotation (0.0) - , mMapMode (aiTextureMapMode_Wrap) - , bPrivate() - , iUVSrc (0) - { + 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 = get_qnan(); } @@ -394,7 +392,7 @@ struct Material //! Move constructor. This is explicitly written because MSVC doesn't support defaulting it - Material(Material &&other) + Material(Material &&other) AI_NO_EXCEPT : mName(std::move(other.mName)) , mDiffuse(std::move(other.mDiffuse)) , mSpecularExponent(std::move(other.mSpecularExponent)) @@ -418,7 +416,7 @@ struct Material } - Material &operator=(Material &&other) { + Material &operator=(Material &&other) AI_NO_EXCEPT { if (this == &other) { return *this; } @@ -447,7 +445,7 @@ struct Material } - ~Material() {} + virtual ~Material() {} //! Name of the material diff --git a/code/3DSLoader.cpp b/code/3DSLoader.cpp index 3c95d8193..cd79b0a6d 100644 --- a/code/3DSLoader.cpp +++ b/code/3DSLoader.cpp @@ -71,7 +71,7 @@ static const aiImporterDesc desc = { 0, 0, 0, - "3ds prj 3DS PRJ" + "3ds prj" }; @@ -127,7 +127,7 @@ Discreet3DSImporter::~Discreet3DSImporter() { // Returns whether the class can handle the format of the given file. bool Discreet3DSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { std::string extension = GetExtension(pFile); - if(extension == "3ds" || extension == "3DS" || extension == "prj"|| extension == "PRJ" ) { + if(extension == "3ds" || extension == "prj") { return true; } diff --git a/code/AMFImporter.hpp b/code/AMFImporter.hpp index 3c60caeab..b7e58362c 100644 --- a/code/AMFImporter.hpp +++ b/code/AMFImporter.hpp @@ -63,8 +63,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Header files, stdlib. #include -namespace Assimp -{ +namespace Assimp { + /// \class AMFImporter /// Class that holding scene graph which include: geometry, metadata, materials etc. /// @@ -99,100 +99,49 @@ namespace Assimp /// new - and children , , , , , /// old - and children , , , , , /// -class AMFImporter : public BaseImporter -{ - /***********************************************/ - /******************** Types ********************/ - /***********************************************/ - +class AMFImporter : public BaseImporter { private: + struct SPP_Material;// forward declaration - struct SPP_Material;// forward declaration + /// \struct SPP_Composite + /// Data type for post-processing step. More suitable container for part of material's composition. + struct SPP_Composite { + SPP_Material* Material;///< Pointer to material - part of composition. + std::string Formula;///< Formula for calculating ratio of \ref Material. + }; - /// \struct SPP_Composite - /// Data type for postprocessing step. More suitable container for part of material's composition. - struct SPP_Composite - { - SPP_Material* Material;///< Pointer to material - part of composition. - std::string Formula;///< Formula for calculating ratio of \ref Material. - }; + /// \struct SPP_Material + /// Data type for post-processing step. More suitable container for material. + struct SPP_Material { + std::string ID;///< Material ID. + std::list Metadata;///< Metadata of material. + CAMFImporter_NodeElement_Color* Color;///< Color of material. + std::list Composition;///< List of child materials if current material is composition of few another. - /// \struct SPP_Material - /// Data type for postprocessing step. More suitable container for material. - struct SPP_Material - { - std::string ID;///< Material ID. - std::list Metadata;///< Metadata of material. - CAMFImporter_NodeElement_Color* Color;///< Color of material. - std::list Composition;///< List of child materials if current material is composition of few another. + /// Return color calculated for specified coordinate. + /// \param [in] pX - "x" coordinate. + /// \param [in] pY - "y" coordinate. + /// \param [in] pZ - "z" coordinate. + /// \return calculated color. + aiColor4D GetColor(const float pX, const float pY, const float pZ) const; + }; - /// \fn aiColor4D GetColor(const float pX, const float pY, const float pZ) const - /// Return color calculated for specified coordinate. - /// \param [in] pX - "x" coordinate. - /// \param [in] pY - "y" coordinate. - /// \param [in] pZ - "z" coordinate. - /// \return calculated color. - aiColor4D GetColor(const float pX, const float pY, const float pZ) const; - }; + /// Data type for post-processing step. More suitable container for texture. + struct SPP_Texture { + std::string ID; + size_t Width, Height, Depth; + bool Tiled; + char FormatHint[9];// 8 for string + 1 for terminator. + uint8_t *Data; + }; - /// \struct SPP_Texture - /// Data type for post-processing step. More suitable container for texture. - struct SPP_Texture - { - std::string ID; - size_t Width, Height, Depth; - bool Tiled; - char FormatHint[ 9 ];// 8 for string + 1 for terminator. - uint8_t *Data; - }; + /// Data type for post-processing step. Contain face data. + struct SComplexFace { + aiFace Face;///< Face vertices. + const CAMFImporter_NodeElement_Color* Color;///< Face color. Equal to nullptr if color is not set for the face. + const CAMFImporter_NodeElement_TexMap* TexMap;///< Face texture mapping data. Equal to nullptr if texture mapping is not set for the face. + }; - /// \struct SComplexFace - /// Data type for post-processing step. Contain face data. - struct SComplexFace - { - aiFace Face;///< Face vertices. - const CAMFImporter_NodeElement_Color* Color;///< Face color. Equal to nullptr if color is not set for the face. - const CAMFImporter_NodeElement_TexMap* TexMap;///< Face texture mapping data. Equal to nullptr if texture mapping is not set for the face. - }; - - - - /***********************************************/ - /****************** Constants ******************/ - /***********************************************/ - -private: - - static const aiImporterDesc Description; - - /***********************************************/ - /****************** Variables ******************/ - /***********************************************/ - -private: - - CAMFImporter_NodeElement* mNodeElement_Cur;///< Current element. - std::list mNodeElement_List;///< All elements of scene graph. - irr::io::IrrXMLReader* mReader;///< Pointer to XML-reader object - std::string mUnit; - std::list mMaterial_Converted;///< List of converted materials for postprocessing step. - std::list mTexture_Converted;///< List of converted textures for postprocessing step. - - /***********************************************/ - /****************** Functions ******************/ - /***********************************************/ - -private: - - /// \fn AMFImporter(const AMFImporter& pScene) - /// Disabled copy constructor. - AMFImporter(const AMFImporter& pScene); - - /// \fn AMFImporter& operator=(const AMFImporter& pScene) - /// Disabled assign operator. - AMFImporter& operator=(const AMFImporter& pScene); - - /// \fn void Clear() /// Clear all temporary data. void Clear(); @@ -200,7 +149,6 @@ private: /************* Functions: find set *************/ /***********************************************/ - /// \fn bool Find_NodeElement(const std::string& pID, const CAMFImporter_NodeElement::EType pType, aiNode** pNode) const /// Find specified node element in node elements list ( \ref mNodeElement_List). /// \param [in] pID - ID(name) of requested node element. /// \param [in] pType - type of node element. @@ -208,7 +156,6 @@ private: /// \return true - if the node element is found, else - false. bool Find_NodeElement(const std::string& pID, const CAMFImporter_NodeElement::EType pType, CAMFImporter_NodeElement** pNodeElement) const; - /// \fn bool Find_ConvertedNode(const std::string& pID, std::list& pNodeList, aiNode** pNode) const /// Find requested aiNode in node list. /// \param [in] pID - ID(name) of requested node. /// \param [in] pNodeList - list of nodes where to find the node. @@ -216,15 +163,13 @@ private: /// \return true - if the node is found, else - false. bool Find_ConvertedNode(const std::string& pID, std::list& pNodeList, aiNode** pNode) const; - /// \fn bool Find_ConvertedMaterial(const std::string& pID, const SPP_Material** pConvertedMaterial) const /// Find material in list for converted materials. Use at postprocessing step. /// \param [in] pID - material ID. /// \param [out] pConvertedMaterial - pointer to found converted material (\ref SPP_Material). /// \return true - if the material is found, else - false. bool Find_ConvertedMaterial(const std::string& pID, const SPP_Material** pConvertedMaterial) const; - /// \fn bool Find_ConvertedTexture(const std::string& pID_R, const std::string& pID_G, const std::string& pID_B, const std::string& pID_A, uint32_t* pConvertedTextureIndex = nullptr) const - /// Find texture in list of converted textures. Use at postprocessing step, + /// Find texture in list of converted textures. Use at postprocessing step, /// \param [in] pID_R - ID of source "red" texture. /// \param [in] pID_G - ID of source "green" texture. /// \param [in] pID_B - ID of source "blue" texture. @@ -235,11 +180,7 @@ private: bool Find_ConvertedTexture(const std::string& pID_R, const std::string& pID_G, const std::string& pID_B, const std::string& pID_A, uint32_t* pConvertedTextureIndex = nullptr) const; - /***********************************************/ - /********* Functions: postprocess set **********/ - /***********************************************/ - /// \fn void PostprocessHelper_CreateMeshDataArray(const CAMFImporter_NodeElement_Mesh& pNodeElement, std::vector& pVertexCoordinateArray, std::vector& pVertexColorArray) const /// Get data stored in and place it to arrays. /// \param [in] pNodeElement - reference to node element which kept data. /// \param [in] pVertexCoordinateArray - reference to vertices coordinates kept in . @@ -248,7 +189,6 @@ private: void PostprocessHelper_CreateMeshDataArray(const CAMFImporter_NodeElement_Mesh& pNodeElement, std::vector& pVertexCoordinateArray, std::vector& pVertexColorArray) const; - /// \fn size_t PostprocessHelper_GetTextureID_Or_Create(const std::string& pID_R, const std::string& pID_G, const std::string& pID_B, const std::string& pID_A) /// Return converted texture ID which related to specified source textures ID's. If converted texture does not exist then it will be created and ID on new /// converted texture will be returned. Conversion: set of textures from \ref CAMFImporter_NodeElement_Texture to one \ref SPP_Texture and place it /// to converted textures list. @@ -260,27 +200,23 @@ private: /// \return index of the texture in array of the converted textures. size_t PostprocessHelper_GetTextureID_Or_Create(const std::string& pID_R, const std::string& pID_G, const std::string& pID_B, const std::string& pID_A); - /// \fn void PostprocessHelper_SplitFacesByTextureID(std::list& pInputList, std::list > pOutputList_Separated) /// Separate input list by texture IDs. This step is needed because aiMesh can contain mesh which is use only one texture (or set: diffuse, bump etc). /// \param [in] pInputList - input list with faces. Some of them can contain color or texture mapping, or both of them, or nothing. Will be cleared after /// processing. /// \param [out] pOutputList_Separated - output list of the faces lists. Separated faces list by used texture IDs. Will be cleared before processing. void PostprocessHelper_SplitFacesByTextureID(std::list& pInputList, std::list >& pOutputList_Separated); - /// \fn void Postprocess_AddMetadata(const std::list& pMetadataList, aiNode& pSceneNode) const /// Check if child elements of node element is metadata and add it to scene node. /// \param [in] pMetadataList - reference to list with collected metadata. /// \param [out] pSceneNode - scene node in which metadata will be added. void Postprocess_AddMetadata(const std::list& pMetadataList, aiNode& pSceneNode) const; - /// \fn void Postprocess_BuildNodeAndObject(const CAMFImporter_NodeElement_Object& pNodeElement, std::list& pMeshList, aiNode** pSceneNode) /// To create aiMesh and aiNode for it from . /// \param [in] pNodeElement - reference to node element which kept data. /// \param [out] pMeshList - reference to a list with all aiMesh of the scene. /// \param [out] pSceneNode - pointer to place where new aiNode will be created. void Postprocess_BuildNodeAndObject(const CAMFImporter_NodeElement_Object& pNodeElement, std::list& pMeshList, aiNode** pSceneNode); - /// \fn void Postprocess_BuildMeshSet(const CAMFImporter_NodeElement_Mesh& pNodeElement, const std::vector& pVertexCoordinateArray, const std::vector& pVertexColorArray, const CAMFImporter_NodeElement_Color* pObjectColor, std::list& pMeshList, aiNode& pSceneNode) /// Create mesh for every in . /// \param [in] pNodeElement - reference to node element which kept data. /// \param [in] pVertexCoordinateArray - reference to vertices coordinates for all 's. @@ -294,27 +230,20 @@ private: const std::vector& pVertexColorArray, const CAMFImporter_NodeElement_Color* pObjectColor, std::list& pMeshList, aiNode& pSceneNode); - /// \fn void Postprocess_BuildMaterial(const CAMFImporter_NodeElement_Material& pMaterial) /// Convert material from \ref CAMFImporter_NodeElement_Material to \ref SPP_Material. /// \param [in] pMaterial - source CAMFImporter_NodeElement_Material. void Postprocess_BuildMaterial(const CAMFImporter_NodeElement_Material& pMaterial); - /// \fn void Postprocess_BuildConstellation(CAMFImporter_NodeElement_Constellation& pConstellation, std::list& pNodeList) const /// Create and add to aiNode's list new part of scene graph defined by . /// \param [in] pConstellation - reference to node. /// \param [out] pNodeList - reference to aiNode's list. void Postprocess_BuildConstellation(CAMFImporter_NodeElement_Constellation& pConstellation, std::list& pNodeList) const; - /// \fn void Postprocess_BuildScene() /// Build Assimp scene graph in aiScene from collected data. /// \param [out] pScene - pointer to aiScene where tree will be built. void Postprocess_BuildScene(aiScene* pScene); - /***********************************************/ - /************* Functions: throw set ************/ - /***********************************************/ - /// \fn void Throw_CloseNotFound(const std::string& pNode) /// Call that function when close tag of node not found and exception must be raised. /// E.g.: /// @@ -324,19 +253,16 @@ private: /// \param [in] pNode - node name in which exception happened. void Throw_CloseNotFound(const std::string& pNode); - /// \fn void Throw_IncorrectAttr(const std::string& pAttrName) /// Call that function when attribute name is incorrect and exception must be raised. /// \param [in] pAttrName - attribute name. /// \throw DeadlyImportError. void Throw_IncorrectAttr(const std::string& pAttrName); - /// \fn void Throw_IncorrectAttrValue(const std::string& pAttrName) /// Call that function when attribute value is incorrect and exception must be raised. /// \param [in] pAttrName - attribute name. /// \throw DeadlyImportError. void Throw_IncorrectAttrValue(const std::string& pAttrName); - /// \fn void Throw_MoreThanOnceDefined(const std::string& pNode, const std::string& pDescription) /// Call that function when some type of nodes are defined twice or more when must be used only once and exception must be raised. /// E.g.: /// @@ -348,204 +274,158 @@ private: /// \param [in] pDescription - message about error. E.g. what the node defined while exception raised. void Throw_MoreThanOnceDefined(const std::string& pNodeType, const std::string& pDescription); - /// \fn void Throw_ID_NotFound(const std::string& pID) const /// Call that function when referenced element ID are not found in graph and exception must be raised. /// \param [in] pID - ID of of element which not found. /// \throw DeadlyImportError. void Throw_ID_NotFound(const std::string& pID) const; - /***********************************************/ - /************** Functions: LOG set *************/ - /***********************************************/ - - /***********************************************/ - /************** Functions: XML set *************/ - /***********************************************/ - - /// \fn void XML_CheckNode_MustHaveChildren() /// Check if current node have children: .... If not then exception will throwed. void XML_CheckNode_MustHaveChildren(); - /// \fn bool XML_CheckNode_NameEqual(const std::string& pNodeName) /// Check if current node name is equal to pNodeName. /// \param [in] pNodeName - name for checking. /// return true if current node name is equal to pNodeName, else - false. bool XML_CheckNode_NameEqual(const std::string& pNodeName) { return mReader->getNodeName() == pNodeName; } - /// \fn void XML_CheckNode_SkipUnsupported(const std::string& pParentNodeName) /// Skip unsupported node and report about that. Depend on node name can be skipped begin tag of node all whole node. /// \param [in] pParentNodeName - parent node name. Used for reporting. void XML_CheckNode_SkipUnsupported(const std::string& pParentNodeName); - /// \fn bool XML_SearchNode(const std::string& pNodeName) /// Search for specified node in file. XML file read pointer(mReader) will point to found node or file end after search is end. /// \param [in] pNodeName - requested node name. /// return true - if node is found, else - false. bool XML_SearchNode(const std::string& pNodeName); - /// \fn bool XML_ReadNode_GetAttrVal_AsBool(const int pAttrIdx) /// Read attribute value. /// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set). /// \return read data. bool XML_ReadNode_GetAttrVal_AsBool(const int pAttrIdx); - /// \fn float XML_ReadNode_GetAttrVal_AsFloat(const int pAttrIdx) /// Read attribute value. /// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set). /// \return read data. float XML_ReadNode_GetAttrVal_AsFloat(const int pAttrIdx); - /// \fn uint32_t XML_ReadNode_GetAttrVal_AsU32(const int pAttrIdx) /// Read attribute value. /// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set). /// \return read data. uint32_t XML_ReadNode_GetAttrVal_AsU32(const int pAttrIdx); - /// \fn float XML_ReadNode_GetVal_AsFloat() /// Read node value. /// \return read data. float XML_ReadNode_GetVal_AsFloat(); - /// \fn uint32_t XML_ReadNode_GetVal_AsU32() /// Read node value. /// \return read data. uint32_t XML_ReadNode_GetVal_AsU32(); - /// \fn void XML_ReadNode_GetVal_AsString(std::string& pValue) /// Read node value. /// \return read data. void XML_ReadNode_GetVal_AsString(std::string& pValue); - /***********************************************/ - /******** Functions: parse set private *********/ - /***********************************************/ - - /// \fn void ParseHelper_Node_Enter(CAMFImporter_NodeElement* pNode) /// Make pNode as current and enter deeper for parsing child nodes. At end \ref ParseHelper_Node_Exit must be called. /// \param [in] pNode - new current node. void ParseHelper_Node_Enter(CAMFImporter_NodeElement* pNode); - /// \fn void ParseHelper_Group_End() /// This function must be called when exiting from grouping node. \ref ParseHelper_Group_Begin. void ParseHelper_Node_Exit(); - /// \fn void ParseHelper_FixTruncatedFloatString(const char* pInStr, std::string& pOutString) /// Attribute values of floating point types can take form ".x"(without leading zero). irrXMLReader can not read this form of values and it /// must be converted to right form - "0.xxx". /// \param [in] pInStr - pointer to input string which can contain incorrect form of values. /// \param [out[ pOutString - output string with right form of values. void ParseHelper_FixTruncatedFloatString(const char* pInStr, std::string& pOutString); - /// \fn void ParseHelper_Decode_Base64(const std::string& pInputBase64, std::vector& pOutputData) const /// Decode Base64-encoded data. /// \param [in] pInputBase64 - reference to input Base64-encoded string. /// \param [out] pOutputData - reference to output array for decoded data. void ParseHelper_Decode_Base64(const std::string& pInputBase64, std::vector& pOutputData) const; - /// \fn void ParseNode_Root() /// Parse node of the file. void ParseNode_Root(); - /******** Functions: top nodes *********/ - - /// \fn void ParseNode_Constellation() /// Parse node of the file. void ParseNode_Constellation(); - /// \fn void ParseNode_Constellation() /// Parse node of the file. void ParseNode_Instance(); - /// \fn void ParseNode_Material() /// Parse node of the file. void ParseNode_Material(); - /// \fn void ParseNode_Metadata() /// Parse node. void ParseNode_Metadata(); - /// \fn void ParseNode_Object() /// Parse node of the file. void ParseNode_Object(); - /// \fn void ParseNode_Texture() /// Parse node of the file. void ParseNode_Texture(); - /******** Functions: geometry nodes *********/ - - /// \fn void ParseNode_Coordinates() /// Parse node of the file. void ParseNode_Coordinates(); - /// \fn void ParseNode_Edge() /// Parse node of the file. void ParseNode_Edge(); - /// \fn void ParseNode_Mesh() /// Parse node of the file. void ParseNode_Mesh(); - /// \fn void ParseNode_Triangle() /// Parse node of the file. void ParseNode_Triangle(); - /// \fn void ParseNode_Vertex() /// Parse node of the file. void ParseNode_Vertex(); - /// \fn void ParseNode_Vertices() /// Parse node of the file. void ParseNode_Vertices(); - /// \fn void ParseNode_Volume() /// Parse node of the file. void ParseNode_Volume(); - /******** Functions: material nodes *********/ - - /// \fn void ParseNode_Color() /// Parse node of the file. void ParseNode_Color(); - /// \fn void ParseNode_TexMap(const bool pUseOldName = false) /// Parse of node of the file. /// \param [in] pUseOldName - if true then use old name of node(and children) - , instead of new name - . void ParseNode_TexMap(const bool pUseOldName = false); public: - - /// \fn AMFImporter() /// Default constructor. - AMFImporter() - : mNodeElement_Cur(nullptr), mReader(nullptr) - {} + AMFImporter() AI_NO_EXCEPT + : mNodeElement_Cur(nullptr) + , mReader(nullptr) { + // empty + } - /// \fn ~AMFImporter() /// Default destructor. ~AMFImporter(); - /***********************************************/ - /******** Functions: parse set, public *********/ - /***********************************************/ - - /// \fn void ParseFile(const std::string& pFile, IOSystem* pIOHandler) /// Parse AMF file and fill scene graph. The function has no return value. Result can be found by analyzing the generated graph. - /// Also exception can be throwed if trouble will found. + /// Also exception can be thrown if trouble will found. /// \param [in] pFile - name of file to be parsed. /// \param [in] pIOHandler - pointer to IO helper object. void ParseFile(const std::string& pFile, IOSystem* pIOHandler); - /***********************************************/ - /********* Functions: BaseImporter set *********/ - /***********************************************/ - bool CanRead(const std::string& pFile, IOSystem* pIOHandler, bool pCheckSig) const; void GetExtensionList(std::set& pExtensionList); void InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler); const aiImporterDesc* GetInfo ()const; -};// class AMFImporter + AMFImporter(const AMFImporter& pScene) = delete; + AMFImporter& operator=(const AMFImporter& pScene) = delete; + +private: + static const aiImporterDesc Description; + + CAMFImporter_NodeElement* mNodeElement_Cur;///< Current element. + std::list mNodeElement_List;///< All elements of scene graph. + irr::io::IrrXMLReader* mReader;///< Pointer to XML-reader object + std::string mUnit; + std::list mMaterial_Converted;///< List of converted materials for postprocessing step. + std::list mTexture_Converted;///< List of converted textures for postprocessing step. + +}; }// namespace Assimp diff --git a/code/AMFImporter_Material.cpp b/code/AMFImporter_Material.cpp index 2f65ad833..c9190bb92 100644 --- a/code/AMFImporter_Material.cpp +++ b/code/AMFImporter_Material.cpp @@ -68,10 +68,9 @@ namespace Assimp // Multi elements - No. // Red, Greed, Blue and Alpha (transparency) component of a color in sRGB space, values ranging from 0 to 1. The // values can be specified as constants, or as a formula depending on the coordinates. -void AMFImporter::ParseNode_Color() -{ -std::string profile; -CAMFImporter_NodeElement* ne; +void AMFImporter::ParseNode_Color() { + std::string profile; + CAMFImporter_NodeElement* ne; // Read attributes for node . MACRO_ATTRREAD_LOOPBEG; @@ -98,15 +97,19 @@ CAMFImporter_NodeElement* ne; MACRO_NODECHECK_LOOPEND("color"); ParseHelper_Node_Exit(); // check that all components was defined - if(!(read_flag[0] && read_flag[1] && read_flag[2])) throw DeadlyImportError("Not all color components are defined."); - // check if is absent. Then manually add "a == 1". - if(!read_flag[3]) als.Color.a = 1; + if (!(read_flag[0] && read_flag[1] && read_flag[2])) { + throw DeadlyImportError("Not all color components are defined."); + } - }// if(!mReader->isEmptyElement()) + // check if is absent. Then manually add "a == 1". + if (!read_flag[3]) { + als.Color.a = 1; + } + } else { mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element - }// if(!mReader->isEmptyElement()) else + } als.Composed = false; mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph. @@ -119,10 +122,9 @@ CAMFImporter_NodeElement* ne; // An available material. // Multi elements - Yes. // Parent element - . -void AMFImporter::ParseNode_Material() -{ -std::string id; -CAMFImporter_NodeElement* ne; +void AMFImporter::ParseNode_Material() { + std::string id; + CAMFImporter_NodeElement* ne; // Read attributes for node . MACRO_ATTRREAD_LOOPBEG; @@ -131,9 +133,11 @@ CAMFImporter_NodeElement* ne; // create new object. ne = new CAMFImporter_NodeElement_Material(mNodeElement_Cur); - // and assign read data + + // and assign read data ((CAMFImporter_NodeElement_Material*)ne)->ID = id; - // Check for child nodes + + // Check for child nodes if(!mReader->isEmptyElement()) { bool col_read = false; @@ -154,11 +158,11 @@ CAMFImporter_NodeElement* ne; if(XML_CheckNode_NameEqual("metadata")) { ParseNode_Metadata(); continue; } MACRO_NODECHECK_LOOPEND("material"); ParseHelper_Node_Exit(); - }// if(!mReader->isEmptyElement()) + } else { mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element - }// if(!mReader->isEmptyElement()) else + } mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph. } @@ -181,14 +185,13 @@ CAMFImporter_NodeElement* ne; // Parent element - . void AMFImporter::ParseNode_Texture() { -std::string id; -uint32_t width = 0; -uint32_t height = 0; -uint32_t depth = 1; -std::string type; -bool tiled = false; -std::string enc64_data; -CAMFImporter_NodeElement* ne; + std::string id; + uint32_t width = 0; + uint32_t height = 0; + uint32_t depth = 1; + std::string type; + bool tiled = false; + std::string enc64_data; // Read attributes for node . MACRO_ATTRREAD_LOOPBEG; @@ -201,20 +204,34 @@ CAMFImporter_NodeElement* ne; MACRO_ATTRREAD_LOOPEND; // create new texture object. - ne = new CAMFImporter_NodeElement_Texture(mNodeElement_Cur); + CAMFImporter_NodeElement *ne = new CAMFImporter_NodeElement_Texture(mNodeElement_Cur); CAMFImporter_NodeElement_Texture& als = *((CAMFImporter_NodeElement_Texture*)ne);// alias for convenience // Check for child nodes - if(!mReader->isEmptyElement()) XML_ReadNode_GetVal_AsString(enc64_data); + if (!mReader->isEmptyElement()) { + XML_ReadNode_GetVal_AsString(enc64_data); + } // check that all components was defined - if(id.empty()) throw DeadlyImportError("ID for texture must be defined."); - if(width < 1) Throw_IncorrectAttrValue("width"); - if(height < 1) Throw_IncorrectAttrValue("height"); - if(depth < 1) Throw_IncorrectAttrValue("depth"); - if(type != "grayscale") Throw_IncorrectAttrValue("type"); - if(enc64_data.empty()) throw DeadlyImportError("Texture data not defined."); + if (id.empty()) { + throw DeadlyImportError("ID for texture must be defined."); + } + if (width < 1) { + Throw_IncorrectAttrValue("width"); + } + if (height < 1) { + Throw_IncorrectAttrValue("height"); + } + if (depth < 1) { + Throw_IncorrectAttrValue("depth"); + } + if (type != "grayscale") { + Throw_IncorrectAttrValue("type"); + } + if (enc64_data.empty()) { + throw DeadlyImportError("Texture data not defined."); + } // copy data als.ID = id; als.Width = width; @@ -222,8 +239,11 @@ CAMFImporter_NodeElement* ne; als.Depth = depth; als.Tiled = tiled; ParseHelper_Decode_Base64(enc64_data, als.Data); - // check data size - if((width * height * depth) != als.Data.size()) throw DeadlyImportError("Texture has incorrect data size."); + + // check data size + if ((width * height * depth) != als.Data.size()) { + throw DeadlyImportError("Texture has incorrect data size."); + } mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph. @@ -243,10 +263,8 @@ CAMFImporter_NodeElement* ne; // , , , , , . Old name: , , , , , . // Multi elements - No. // Texture coordinates for every vertex of triangle. -void AMFImporter::ParseNode_TexMap(const bool pUseOldName) -{ -std::string rtexid, gtexid, btexid, atexid; -CAMFImporter_NodeElement* ne; +void AMFImporter::ParseNode_TexMap(const bool pUseOldName) { + std::string rtexid, gtexid, btexid, atexid; // Read attributes for node . MACRO_ATTRREAD_LOOPBEG; @@ -257,7 +275,7 @@ CAMFImporter_NodeElement* ne; MACRO_ATTRREAD_LOOPEND; // create new texture coordinates object. - ne = new CAMFImporter_NodeElement_TexMap(mNodeElement_Cur); + CAMFImporter_NodeElement *ne = new CAMFImporter_NodeElement_TexMap(mNodeElement_Cur); CAMFImporter_NodeElement_TexMap& als = *((CAMFImporter_NodeElement_TexMap*)ne);// alias for convenience // check data diff --git a/code/AMFImporter_Node.hpp b/code/AMFImporter_Node.hpp index cdbedf2c7..22b8f58cb 100644 --- a/code/AMFImporter_Node.hpp +++ b/code/AMFImporter_Node.hpp @@ -62,7 +62,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /// \class CAMFImporter_NodeElement /// Base class for elements of nodes. class CAMFImporter_NodeElement { - public: /// Define what data type contain node element. enum EType { @@ -96,15 +95,11 @@ public: /// Destructor, virtual.. // empty } -private: - /// Disabled copy constructor. - CAMFImporter_NodeElement(const CAMFImporter_NodeElement& pNodeElement); - - /// Disabled assign operator. - CAMFImporter_NodeElement& operator=(const CAMFImporter_NodeElement& pNodeElement); - - /// Disabled default constructor. - CAMFImporter_NodeElement(); + /// Disabled copy constructor and co. + CAMFImporter_NodeElement(const CAMFImporter_NodeElement& pNodeElement) = delete; + CAMFImporter_NodeElement(CAMFImporter_NodeElement&&) = delete; + CAMFImporter_NodeElement& operator=(const CAMFImporter_NodeElement& pNodeElement) = delete; + CAMFImporter_NodeElement() = delete; protected: /// In constructor inheritor must set element type. @@ -121,9 +116,7 @@ protected: /// \struct CAMFImporter_NodeElement_Constellation /// A collection of objects or constellations with specific relative locations. -struct CAMFImporter_NodeElement_Constellation : public CAMFImporter_NodeElement -{ - /// \fn CAMFImporter_NodeElement_Constellation(CAMFImporter_NodeElement* pParent) +struct CAMFImporter_NodeElement_Constellation : public CAMFImporter_NodeElement { /// Constructor. /// \param [in] pParent - pointer to parent node. CAMFImporter_NodeElement_Constellation(CAMFImporter_NodeElement* pParent) @@ -134,9 +127,7 @@ struct CAMFImporter_NodeElement_Constellation : public CAMFImporter_NodeElement /// \struct CAMFImporter_NodeElement_Instance /// Part of constellation. -struct CAMFImporter_NodeElement_Instance : public CAMFImporter_NodeElement -{ - /****************** Variables ******************/ +struct CAMFImporter_NodeElement_Instance : public CAMFImporter_NodeElement { std::string ObjectID;///< ID of object for instantiation. /// \var Delta - The distance of translation in the x, y, or z direction, respectively, in the referenced object's coordinate system, to @@ -147,237 +138,185 @@ struct CAMFImporter_NodeElement_Instance : public CAMFImporter_NodeElement /// instance of the object in the current constellation. Rotations shall be executed in order of x first, then y, then z. aiVector3D Rotation; - /****************** Functions ******************/ - - /// \fn CAMFImporter_NodeElement_Instance(CAMFImporter_NodeElement* pParent) /// Constructor. /// \param [in] pParent - pointer to parent node. CAMFImporter_NodeElement_Instance(CAMFImporter_NodeElement* pParent) : CAMFImporter_NodeElement(ENET_Instance, pParent) {} - -};// struct CAMFImporter_NodeElement_Instance +}; /// \struct CAMFImporter_NodeElement_Metadata /// Structure that define metadata node. -struct CAMFImporter_NodeElement_Metadata : public CAMFImporter_NodeElement -{ - /****************** Variables ******************/ +struct CAMFImporter_NodeElement_Metadata : public CAMFImporter_NodeElement { - std::string Type;///< Type of "Value". + std::string Type;///< Type of "Value". std::string Value;///< Value. - /****************** Functions ******************/ - - /// \fn CAMFImporter_NodeElement_Metadata(CAMFImporter_NodeElement* pParent) /// Constructor. /// \param [in] pParent - pointer to parent node. CAMFImporter_NodeElement_Metadata(CAMFImporter_NodeElement* pParent) : CAMFImporter_NodeElement(ENET_Metadata, pParent) {} - -};// struct CAMFImporter_NodeElement_Metadata +}; /// \struct CAMFImporter_NodeElement_Root /// Structure that define root node. -struct CAMFImporter_NodeElement_Root : public CAMFImporter_NodeElement -{ - /****************** Variables ******************/ +struct CAMFImporter_NodeElement_Root : public CAMFImporter_NodeElement { std::string Unit;///< The units to be used. May be "inch", "millimeter", "meter", "feet", or "micron". std::string Version;///< Version of format. - /****************** Functions ******************/ - - /// \fn CAMFImporter_NodeElement_Root(CAMFImporter_NodeElement* pParent) /// Constructor. /// \param [in] pParent - pointer to parent node. CAMFImporter_NodeElement_Root(CAMFImporter_NodeElement* pParent) : CAMFImporter_NodeElement(ENET_Root, pParent) {} - -};// struct CAMFImporter_NodeElement_Root +}; /// \struct CAMFImporter_NodeElement_Color /// Structure that define object node. -struct CAMFImporter_NodeElement_Color : public CAMFImporter_NodeElement -{ - /****************** Variables ******************/ +struct CAMFImporter_NodeElement_Color : public CAMFImporter_NodeElement { + bool Composed; ///< Type of color stored: if true then look for formula in \ref Color_Composed[4], else - in \ref Color. + std::string Color_Composed[4]; ///< By components formulas of composed color. [0..3] - RGBA. + aiColor4D Color; ///< Constant color. + std::string Profile; ///< The ICC color space used to interpret the three color channels r, g and b.. - bool Composed;///< Type of color stored: if true then look for formula in \ref Color_Composed[4], else - in \ref Color. - std::string Color_Composed[4];///< By components formulas of composed color. [0..3] => RGBA. - aiColor4D Color;///< Constant color. - std::string Profile;///< The ICC color space used to interpret the three color channels , and .. - - /****************** Functions ******************/ - - /// \fn CAMFImporter_NodeElement_Color(CAMFImporter_NodeElement* pParent) - /// Constructor. - /// \param [in] pParent - pointer to parent node. + /// @brief Constructor. + /// @param [in] pParent - pointer to parent node. CAMFImporter_NodeElement_Color(CAMFImporter_NodeElement* pParent) - : CAMFImporter_NodeElement(ENET_Color, pParent) - {} - -};// struct CAMFImporter_NodeElement_Color + : CAMFImporter_NodeElement(ENET_Color, pParent) + , Composed( false ) + , Color() + , Profile() { + // empty + } +}; /// \struct CAMFImporter_NodeElement_Material /// Structure that define material node. -struct CAMFImporter_NodeElement_Material : public CAMFImporter_NodeElement -{ - /// \fn CAMFImporter_NodeElement_Material(CAMFImporter_NodeElement* pParent) +struct CAMFImporter_NodeElement_Material : public CAMFImporter_NodeElement { + /// Constructor. /// \param [in] pParent - pointer to parent node. CAMFImporter_NodeElement_Material(CAMFImporter_NodeElement* pParent) : CAMFImporter_NodeElement(ENET_Material, pParent) {} -};// struct CAMFImporter_NodeElement_Material +}; /// \struct CAMFImporter_NodeElement_Object /// Structure that define object node. -struct CAMFImporter_NodeElement_Object : public CAMFImporter_NodeElement -{ - /// \fn CAMFImporter_NodeElement_Object(CAMFImporter_NodeElement* pParent) - /// Constructor. +struct CAMFImporter_NodeElement_Object : public CAMFImporter_NodeElement { + + /// Constructor. /// \param [in] pParent - pointer to parent node. CAMFImporter_NodeElement_Object(CAMFImporter_NodeElement* pParent) : CAMFImporter_NodeElement(ENET_Object, pParent) {} - -};// struct CAMFImporter_NodeElement_Object +}; /// \struct CAMFImporter_NodeElement_Mesh /// Structure that define mesh node. -struct CAMFImporter_NodeElement_Mesh : public CAMFImporter_NodeElement -{ - /// \fn CAMFImporter_NodeElement_Mesh(CAMFImporter_NodeElement* pParent) +struct CAMFImporter_NodeElement_Mesh : public CAMFImporter_NodeElement { /// Constructor. /// \param [in] pParent - pointer to parent node. CAMFImporter_NodeElement_Mesh(CAMFImporter_NodeElement* pParent) : CAMFImporter_NodeElement(ENET_Mesh, pParent) {} - -};// struct CAMFImporter_NodeElement_Mesh +}; /// \struct CAMFImporter_NodeElement_Vertex /// Structure that define vertex node. -struct CAMFImporter_NodeElement_Vertex : public CAMFImporter_NodeElement -{ - /// \fn CAMFImporter_NodeElement_Vertex(CAMFImporter_NodeElement* pParent) +struct CAMFImporter_NodeElement_Vertex : public CAMFImporter_NodeElement { /// Constructor. /// \param [in] pParent - pointer to parent node. CAMFImporter_NodeElement_Vertex(CAMFImporter_NodeElement* pParent) : CAMFImporter_NodeElement(ENET_Vertex, pParent) {} - -};// struct CAMFImporter_NodeElement_Vertex +}; /// \struct CAMFImporter_NodeElement_Edge /// Structure that define edge node. -struct CAMFImporter_NodeElement_Edge : public CAMFImporter_NodeElement -{ - /// \fn CAMFImporter_NodeElement_Edge(CAMFImporter_NodeElement* pParent) +struct CAMFImporter_NodeElement_Edge : public CAMFImporter_NodeElement { /// Constructor. /// \param [in] pParent - pointer to parent node. CAMFImporter_NodeElement_Edge(CAMFImporter_NodeElement* pParent) : CAMFImporter_NodeElement(ENET_Edge, pParent) {} -};// struct CAMFImporter_NodeElement_Vertex +}; /// \struct CAMFImporter_NodeElement_Vertices /// Structure that define vertices node. -struct CAMFImporter_NodeElement_Vertices : public CAMFImporter_NodeElement -{ - /// \fn CAMFImporter_NodeElement_Vertices(CAMFImporter_NodeElement* pParent) +struct CAMFImporter_NodeElement_Vertices : public CAMFImporter_NodeElement { /// Constructor. /// \param [in] pParent - pointer to parent node. CAMFImporter_NodeElement_Vertices(CAMFImporter_NodeElement* pParent) : CAMFImporter_NodeElement(ENET_Vertices, pParent) {} - -};// struct CAMFImporter_NodeElement_Vertices +}; /// \struct CAMFImporter_NodeElement_Volume /// Structure that define volume node. -struct CAMFImporter_NodeElement_Volume : public CAMFImporter_NodeElement -{ - /****************** Variables ******************/ - +struct CAMFImporter_NodeElement_Volume : public CAMFImporter_NodeElement { std::string MaterialID;///< Which material to use. std::string Type;///< What this volume describes can be “region” or “support”. If none specified, “object” is assumed. - /****************** Functions ******************/ - - /// \fn CAMFImporter_NodeElement_Volume(CAMFImporter_NodeElement* pParent) /// Constructor. /// \param [in] pParent - pointer to parent node. CAMFImporter_NodeElement_Volume(CAMFImporter_NodeElement* pParent) : CAMFImporter_NodeElement(ENET_Volume, pParent) {} - -};// struct CAMFImporter_NodeElement_Volume +}; /// \struct CAMFImporter_NodeElement_Coordinates /// Structure that define coordinates node. struct CAMFImporter_NodeElement_Coordinates : public CAMFImporter_NodeElement { - /****************** Variables ******************/ - aiVector3D Coordinate;///< Coordinate. - /****************** Functions ******************/ - - /// \fn CAMFImporter_NodeElement_Coordinates(CAMFImporter_NodeElement* pParent) /// Constructor. /// \param [in] pParent - pointer to parent node. CAMFImporter_NodeElement_Coordinates(CAMFImporter_NodeElement* pParent) : CAMFImporter_NodeElement(ENET_Coordinates, pParent) {} -};// struct CAMFImporter_NodeElement_Coordinates +}; /// \struct CAMFImporter_NodeElement_TexMap /// Structure that define texture coordinates node. -struct CAMFImporter_NodeElement_TexMap : public CAMFImporter_NodeElement -{ - /****************** Variables ******************/ - +struct CAMFImporter_NodeElement_TexMap : public CAMFImporter_NodeElement { aiVector3D TextureCoordinate[3];///< Texture coordinates. std::string TextureID_R;///< Texture ID for red color component. std::string TextureID_G;///< Texture ID for green color component. std::string TextureID_B;///< Texture ID for blue color component. std::string TextureID_A;///< Texture ID for alpha color component. - /****************** Functions ******************/ - - /// \fn CAMFImporter_NodeElement_TexMap(CAMFImporter_NodeElement* pParent) /// Constructor. /// \param [in] pParent - pointer to parent node. CAMFImporter_NodeElement_TexMap(CAMFImporter_NodeElement* pParent) - : CAMFImporter_NodeElement(ENET_TexMap, pParent) - {} - -};// struct CAMFImporter_NodeElement_TexMap + : CAMFImporter_NodeElement(ENET_TexMap, pParent) + , TextureCoordinate{} + , TextureID_R() + , TextureID_G() + , TextureID_B() + , TextureID_A() { + // empty + } +}; /// \struct CAMFImporter_NodeElement_Triangle /// Structure that define triangle node. -struct CAMFImporter_NodeElement_Triangle : public CAMFImporter_NodeElement -{ - /****************** Variables ******************/ - +struct CAMFImporter_NodeElement_Triangle : public CAMFImporter_NodeElement { size_t V[3];///< Triangle vertices. - /****************** Functions ******************/ - - /// \fn CAMFImporter_NodeElement_Triangle(CAMFImporter_NodeElement* pParent) /// Constructor. /// \param [in] pParent - pointer to parent node. CAMFImporter_NodeElement_Triangle(CAMFImporter_NodeElement* pParent) - : CAMFImporter_NodeElement(ENET_Triangle, pParent) - {} - -};// struct CAMFImporter_NodeElement_Triangle + : CAMFImporter_NodeElement(ENET_Triangle, pParent) { + // empty + } +}; /// Structure that define texture node. struct CAMFImporter_NodeElement_Texture : public CAMFImporter_NodeElement { @@ -396,6 +335,6 @@ struct CAMFImporter_NodeElement_Texture : public CAMFImporter_NodeElement { , Tiled( false ){ // empty } -};// struct CAMFImporter_NodeElement_Texture +}; #endif // INCLUDED_AI_AMF_IMPORTER_NODE_H diff --git a/code/ASEParser.h b/code/ASEParser.h index 70eb3de66..305a3f3d6 100644 --- a/code/ASEParser.h +++ b/code/ASEParser.h @@ -71,21 +71,20 @@ struct Material : public D3DS::Material //! Default constructor has been deleted Material() = delete; - //! Constructor with explicit name explicit Material(const std::string &name) : D3DS::Material(name) , pcInstance(NULL) - , bNeed (false) - {} - + , bNeed (false) { + // empty + } 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) + Material(Material &&other) AI_NO_EXCEPT : D3DS::Material(std::move(other)) , avSubMaterials(std::move(other.avSubMaterials)) , pcInstance(std::move(other.pcInstance)) @@ -95,7 +94,7 @@ struct Material : public D3DS::Material } - Material &operator=(Material &&other) { + Material &operator=(Material &&other) AI_NO_EXCEPT { if (this == &other) { return *this; } @@ -127,19 +126,12 @@ struct Material : public D3DS::Material // --------------------------------------------------------------------------- /** Helper structure to represent an ASE file face */ -struct Face : public FaceWithSmoothingGroup -{ +struct Face : public FaceWithSmoothingGroup { //! Default constructor. Initializes everything with 0 - Face() - { - mColorIndices[0] = mColorIndices[1] = mColorIndices[2] = 0; - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i) - { - amUVIndices[i][0] = amUVIndices[i][1] = amUVIndices[i][2] = 0; - } - - iMaterial = DEFAULT_MATINDEX; - iFace = 0; + Face() AI_NO_EXCEPT + : iMaterial(DEFAULT_MATINDEX) + , iFace(0) { + // empty } //! special value to indicate that no material index has @@ -147,8 +139,6 @@ struct Face : public FaceWithSmoothingGroup //! will replace this value later. static const unsigned int DEFAULT_MATINDEX = 0xFFFFFFFF; - - //! Indices into each list of texture coordinates unsigned int amUVIndices[AI_MAX_NUMBER_OF_TEXTURECOORDS][3]; @@ -166,15 +156,15 @@ struct Face : public FaceWithSmoothingGroup // --------------------------------------------------------------------------- /** Helper structure to represent an ASE file bone */ -struct Bone -{ +struct Bone { //! Constructor Bone() = delete; //! Construction from an existing name explicit Bone( const std::string& name) - : mName (name) - {} + : mName(name) { + // empty + } //! Name of the bone std::string mName; @@ -182,29 +172,22 @@ struct Bone // --------------------------------------------------------------------------- /** Helper structure to represent an ASE file bone vertex */ -struct BoneVertex -{ +struct BoneVertex { //! Bone and corresponding vertex weight. //! -1 for unrequired bones .... std::vector > mBoneWeights; - - //! Position of the bone vertex. - //! MUST be identical to the vertex position - //aiVector3D mPosition; }; // --------------------------------------------------------------------------- /** Helper structure to represent an ASE file animation */ -struct Animation -{ - enum Type - { +struct Animation { + enum Type { TRACK = 0x0, BEZIER = 0x1, TCB = 0x2 } mRotationType, mScalingType, mPositionType; - Animation() + Animation() AI_NO_EXCEPT : mRotationType (TRACK) , mScalingType (TRACK) , mPositionType (TRACK) @@ -218,19 +201,16 @@ struct Animation //! List of track scaling keyframes std::vector< aiVectorKey > akeyScaling; - }; // --------------------------------------------------------------------------- /** Helper structure to represent the inheritance information of an ASE node */ -struct InheritanceInfo -{ +struct InheritanceInfo { //! Default constructor - InheritanceInfo() - { - // set the inheritance flag for all axes by default to true - for (unsigned int i = 0; i < 3;++i) + InheritanceInfo() AI_NO_EXCEPT { + for ( size_t i=0; i<3; ++i ) { abInheritPosition[i] = abInheritRotation[i] = abInheritScaling[i] = true; + } } //! Inherit the parent's position?, axis order is x,y,z @@ -245,17 +225,19 @@ struct InheritanceInfo // --------------------------------------------------------------------------- /** Represents an ASE file node. Base class for mesh, light and cameras */ -struct BaseNode -{ - enum Type {Light, Camera, Mesh, Dummy} mType; - +struct BaseNode { + enum Type { + Light, + Camera, + Mesh, + Dummy + } mType; //! Construction from an existing name BaseNode(Type _mType, const std::string &name) : mType (_mType) , mName (name) - , mProcessed (false) - { + , mProcessed (false) { // Set mTargetPosition to qnan const ai_real qnan = get_qnan(); mTargetPosition.x = qnan; @@ -291,24 +273,23 @@ struct BaseNode // --------------------------------------------------------------------------- /** Helper structure to represent an ASE file mesh */ -struct Mesh : public MeshWithSmoothingGroups, public BaseNode -{ +struct Mesh : public MeshWithSmoothingGroups, public BaseNode { //! Default constructor has been deleted Mesh() = delete; - //! Construction from an existing name explicit Mesh(const std::string &name) - : BaseNode (BaseNode::Mesh, name) + : BaseNode( BaseNode::Mesh, name ) + , mVertexColors() + , mBoneVertices() + , mBones() , iMaterialIndex(Face::DEFAULT_MATINDEX) - , bSkip (false) - { - // use 2 texture vertex components by default - for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) + , bSkip (false) { + for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) { this->mNumUVComponents[c] = 2; + } } - //! List of all texture coordinate sets std::vector amTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS]; @@ -396,12 +377,11 @@ struct Camera : public BaseNode // --------------------------------------------------------------------------- /** Helper structure to represent an ASE helper object (dummy) */ -struct Dummy : public BaseNode -{ +struct Dummy : public BaseNode { //! Constructor - Dummy() - : BaseNode (BaseNode::Dummy, "DUMMY") - { + Dummy() AI_NO_EXCEPT + : BaseNode (BaseNode::Dummy, "DUMMY") { + // empty } }; @@ -416,12 +396,11 @@ struct Dummy : public BaseNode // ------------------------------------------------------------------------------- /** \brief Class to parse ASE files */ -class Parser -{ - +class Parser { private: - - Parser() {} + Parser() AI_NO_EXCEPT { + // empty + } public: diff --git a/code/AssbinExporter.cpp b/code/AssbinExporter.cpp index cc404396b..d64b5c1de 100644 --- a/code/AssbinExporter.cpp +++ b/code/AssbinExporter.cpp @@ -62,33 +62,30 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include -using namespace Assimp; - -namespace Assimp { +namespace Assimp { template -size_t Write(IOStream * stream, const T& v) -{ +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); + 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 @@ -96,114 +93,123 @@ inline size_t Write(IOStream * stream, const unsigned int& w) } stream->Write(&t,4,1); + return 4; } // ----------------------------------------------------------------------------------- // Serialize an unsigned int as uint16_t template <> -inline size_t Write(IOStream * stream, const uint16_t& w) -{ +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; } // ----------------------------------------------------------------------------------- // Serialize a float template <> -inline size_t Write(IOStream * stream, const float& f) -{ +inline +size_t Write(IOStream * stream, const float& f) { static_assert(sizeof(float)==4, "sizeof(float)==4"); stream->Write(&f,4,1); + return 4; } // ----------------------------------------------------------------------------------- // Serialize a double template <> -inline size_t Write(IOStream * stream, const double& f) -{ +inline +size_t Write(IOStream * stream, const double& f) { static_assert(sizeof(double)==8, "sizeof(double)==8"); stream->Write(&f,8,1); + return 8; } // ----------------------------------------------------------------------------------- // Serialize a vec3 template <> -inline size_t Write(IOStream * stream, const aiVector3D& v) -{ +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; } // ----------------------------------------------------------------------------------- // Serialize a color value template <> -inline size_t Write(IOStream * stream, const aiColor3D& v) -{ +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; } // ----------------------------------------------------------------------------------- // Serialize a color value template <> -inline size_t Write(IOStream * stream, const aiColor4D& v) -{ +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; } // ----------------------------------------------------------------------------------- // Serialize a quaternion template <> -inline size_t Write(IOStream * stream, const aiQuaternion& v) -{ +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; } - // ----------------------------------------------------------------------------------- // Serialize a vertex weight template <> -inline size_t Write(IOStream * stream, const aiVertexWeight& v) -{ +inline +size_t Write(IOStream * stream, const aiVertexWeight& v) { size_t t = Write(stream,v.mVertexId); + return t+Write(stream,v.mWeight); } // ----------------------------------------------------------------------------------- // Serialize a mat4x4 template <> -inline size_t Write(IOStream * stream, const aiMatrix4x4& m) -{ +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]); } } + return 64; } // ----------------------------------------------------------------------------------- // Serialize an aiVectorKey template <> -inline size_t Write(IOStream * stream, const aiVectorKey& v) -{ +inline +size_t Write(IOStream * stream, const aiVectorKey& v) { const size_t t = Write(stream,v.mTime); return t + Write(stream,v.mValue); } @@ -211,16 +217,16 @@ inline size_t Write(IOStream * stream, const aiVectorKey& v) // ----------------------------------------------------------------------------------- // Serialize an aiQuatKey template <> -inline size_t Write(IOStream * stream, const aiQuatKey& v) -{ +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) -{ - T minc,maxc; +inline +size_t WriteBounds(IOStream * stream, const T* in, unsigned int size) { + T minc, maxc; ArrayBounds(in,size,minc,maxc); const size_t t = Write(stream,minc); @@ -230,590 +236,595 @@ inline size_t WriteBounds(IOStream * stream, const T* in, unsigned int size) // 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]); + return n; } - // ---------------------------------------------------------------------------------- - /** @class AssbinChunkWriter - * @brief Chunk writer mechanism for the .assbin file structure - * - * This is a standard in-memory IOStream (most of the code is based on BlobIOStream), - * the difference being that this takes another IOStream as a "container" in the - * constructor, and when it is destroyed, it appends the magic number, the chunk size, - * and the chunk contents to the container stream. This allows relatively easy chunk - * chunk construction, even recursively. - */ - class AssbinChunkWriter : public IOStream - { - private: - - uint8_t* buffer; - uint32_t magic; - 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) )); - - const uint8_t* const old = buffer; - buffer = new uint8_t[new_size]; - - if (old) { - memcpy(buffer,old,cur_size); - delete[] old; - } - - cur_size = new_size; - } - - public: - - AssbinChunkWriter( IOStream * container, uint32_t magic, size_t initial = 4096) - : buffer(NULL), magic(magic), container(container), cur_size(0), cursor(0), initial(initial) - { - } - - virtual ~AssbinChunkWriter() - { - if (container) { - 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; } - - // ------------------------------------------------------------------- - virtual size_t Read(void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) { return 0; } - virtual aiReturn Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/) { return aiReturn_FAILURE; } - virtual size_t Tell() const { return cursor; } - virtual void Flush() { } - - virtual size_t FileSize() const - { - return cursor; - } - - // ------------------------------------------------------------------- - 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); - cursor += pSize; - - return pCount; - } - - }; - - // ---------------------------------------------------------------------------------- - /** @class AssbinExport - * @brief Assbin exporter class - * - * This class performs the .assbin exporting, and is responsible for the file layout. - */ - class AssbinExport - { - private: - bool shortened; - bool compressed; - - protected: - - // ----------------------------------------------------------------------------------- - 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); - - 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 < nb_metadata; ++i) { - const aiString& key = node->mMetaData->mKeys[i]; - aiMetadataType type = node->mMetaData->mValues[i].mType; - void* value = node->mMetaData->mValues[i].mData; - - Write(&chunk, key); - Write(&chunk, type); - - switch (type) { - case AI_BOOL: - Write(&chunk, *((bool*) value)); - break; - case AI_INT32: - Write(&chunk, *((int32_t*) value)); - break; - case AI_UINT64: - Write(&chunk, *((uint64_t*) value)); - break; - case AI_FLOAT: - Write(&chunk, *((float*) value)); - break; - case AI_DOUBLE: - Write(&chunk, *((double*) value)); - break; - case AI_AISTRING: - Write(&chunk, *((aiString*) value)); - break; - case AI_AIVECTOR3D: - Write(&chunk, *((aiVector3D*) value)); - break; -#ifdef SWIG - case FORCE_32BIT: -#endif // SWIG - default: - break; - } - } - } - - // ----------------------------------------------------------------------------------- - void WriteBinaryTexture(IOStream * container, const aiTexture* tex) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AITEXTURE ); - - Write(&chunk,tex->mWidth); - Write(&chunk,tex->mHeight); - chunk.Write( tex->achFormatHint, sizeof(char), 4 ); - - if(!shortened) { - if (!tex->mHeight) { - 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 ); - - 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); - } // else write as usual - else WriteArray(&chunk,b->mWeights,b->mNumWeights); - } - - // ----------------------------------------------------------------------------------- - 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); - - // first of all, write bits for all existent vertex components - unsigned int c = 0; - if (mesh->mVertices) { - c |= ASSBIN_MESH_HAS_POSITIONS; - } - if (mesh->mNormals) { - c |= ASSBIN_MESH_HAS_NORMALS; - } - if (mesh->mTangents && mesh->mBitangents) { - c |= ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS; - } - 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) { - if (!mesh->mColors[n]) { - break; - } - c |= ASSBIN_MESH_HAS_COLOR(n); - } - Write(&chunk,c); - - aiVector3D minVec, maxVec; - if (mesh->mVertices) { - if (shortened) { - WriteBounds(&chunk,mesh->mVertices,mesh->mNumVertices); - } // else write as usual - else WriteArray(&chunk,mesh->mVertices,mesh->mNumVertices); - } - if (mesh->mNormals) { - if (shortened) { - WriteBounds(&chunk,mesh->mNormals,mesh->mNumVertices); - } // else write as usual - 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); - } // else write as usual - else { - 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) { - if (!mesh->mColors[n]) - break; - - if (shortened) { - WriteBounds(&chunk,mesh->mColors[n],mesh->mNumVertices); - } // else write as usual - else WriteArray(&chunk,mesh->mColors[n],mesh->mNumVertices); - } - 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]); - - if (shortened) { - WriteBounds(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices); - } // else write as usual - else WriteArray(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices); - } - - // write faces. There are no floating-point calculations involved - // in these, so we can write a simple hash over the face data - // to the dump file. We generate a single 32 Bit hash for 512 faces - // 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) { - - uint32_t hash = 0; - for (unsigned int a = 0; a < job;++a) { - - const aiFace& f = mesh->mFaces[processed+a]; - uint32_t tmp = f.mNumIndices; - 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); - } - } - Write(&chunk,hash); - } - } - 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]; - - static_assert(AI_MAX_FACE_INDICES <= 0xffff, "AI_MAX_FACE_INDICES <= 0xffff"); - Write(&chunk,f.mNumIndices); - - for (unsigned int a = 0; a < f.mNumIndices;++a) { - if (mesh->mNumVertices < (1u<<16)) { - 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); - } - } - } - - // ----------------------------------------------------------------------------------- - 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->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); - - 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 ); - - 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); - - } // else write as usual - else WriteArray(&chunk,nd->mPositionKeys,nd->mNumPositionKeys); - } - if (nd->mRotationKeys) { - if (shortened) { - WriteBounds(&chunk,nd->mRotationKeys,nd->mNumRotationKeys); - - } // else write as usual - else WriteArray(&chunk,nd->mRotationKeys,nd->mNumRotationKeys); - } - if (nd->mScalingKeys) { - if (shortened) { - 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); - } - } - - // ----------------------------------------------------------------------------------- - 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->mColorDiffuse); - Write(&chunk,l->mColorSpecular); - Write(&chunk,l->mColorAmbient); - - if (l->mType == aiLightSource_SPOT) { - Write(&chunk,l->mAngleInnerCone); - Write(&chunk,l->mAngleOuterCone); - } - - } - - // ----------------------------------------------------------------------------------- - 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); - } - - // ----------------------------------------------------------------------------------- - 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 node graph - 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); - } - - // write materials - 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); - } - - - // write all textures - 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); - } - - // write cameras - for (unsigned int i = 0; i < scene->mNumCameras;++i) { - const aiCamera* cam = scene->mCameras[i]; - WriteBinaryCamera(&chunk,cam); - } - - } - - public: - AssbinExport() - : shortened(false), compressed(false) // temporary settings until properties are introduced for exporters - { - } - - // ----------------------------------------------------------------------------------- - // Write a binary model dump - void WriteBinaryDump(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene) - { - IOStream * out = pIOSystem->Open( pFile, "wb" ); - if (!out) return; - - time_t tt = time(NULL); - tm* p = gmtime(&tt); - - // header - char s[64]; - memset( s, 0, 64 ); -#if _MSC_VER >= 1400 - sprintf_s(s,"ASSIMP.binary-dump.%s",asctime(p)); -#else - ai_snprintf(s,64,"ASSIMP.binary-dump.%s",asctime(p)); -#endif - out->Write( s, 44, 1 ); - // == 44 bytes - - Write( out, ASSBIN_VERSION_MAJOR ); - Write( out, ASSBIN_VERSION_MINOR ); - Write( out, aiGetVersionRevision() ); - Write( out, aiGetCompileFlags() ); - Write( out, shortened ); - Write( out, compressed ); - // == 20 bytes - - char buff[256]; - strncpy(buff,pFile,256); - out->Write(buff,sizeof(char),256); - - char cmd[] = "\0"; - strncpy(buff,cmd,128); - out->Write(buff,sizeof(char),128); - - // leave 64 bytes free for future extensions - memset(buff,0xcd,64); - out->Write(buff,sizeof(char),64); - // == 435 bytes - - // ==== total header size: 512 bytes - ai_assert( out->Tell() == ASSBIN_HEADER_LENGTH ); - - // Up to here the data is uncompressed. For compressed files, the rest - // is compressed using standard DEFLATE from zlib. - if (compressed) - { - AssbinChunkWriter uncompressedStream( NULL, 0 ); - WriteBinaryScene( &uncompressedStream, pScene ); - - uLongf uncompressedSize = static_cast(uncompressedStream.Tell()); - uLongf compressedSize = (uLongf)(uncompressedStream.Tell() * 1.001 + 12.); - uint8_t* compressedBuffer = new uint8_t[ compressedSize ]; - - compress2( compressedBuffer, &compressedSize, (const Bytef*)uncompressedStream.GetBufferPointer(), uncompressedSize, 9 ); - - out->Write( &uncompressedSize, sizeof(uint32_t), 1 ); - out->Write( compressedBuffer, sizeof(char), compressedSize ); - - delete[] compressedBuffer; - } - else - { - WriteBinaryScene( out, pScene ); - } - - pIOSystem->Close( out ); - } - }; - -void ExportSceneAssbin(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/) +// ---------------------------------------------------------------------------------- +/** @class AssbinChunkWriter + * @brief Chunk writer mechanism for the .assbin file structure + * + * This is a standard in-memory IOStream (most of the code is based on BlobIOStream), + * the difference being that this takes another IOStream as a "container" in the + * constructor, and when it is destroyed, it appends the magic number, the chunk size, + * and the chunk contents to the container stream. This allows relatively easy chunk + * chunk construction, even recursively. + */ +class AssbinChunkWriter : public IOStream { +private: + + uint8_t* buffer; + uint32_t magic; + 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) )); + + const uint8_t* const old = buffer; + buffer = new uint8_t[new_size]; + + if (old) { + memcpy(buffer,old,cur_size); + delete[] old; + } + + cur_size = new_size; + } + +public: + + AssbinChunkWriter( IOStream * container, uint32_t magic, size_t initial = 4096) + : buffer(NULL), magic(magic), container(container), cur_size(0), cursor(0), initial(initial) + { + } + + virtual ~AssbinChunkWriter() + { + if (container) { + 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; } + + // ------------------------------------------------------------------- + virtual size_t Read(void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) { + return 0; + } + virtual aiReturn Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/) { + return aiReturn_FAILURE; + } + virtual size_t Tell() const { + return cursor; + } + virtual void Flush() { + // not implemented + } + + virtual size_t FileSize() const { + return cursor; + } + + // ------------------------------------------------------------------- + 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); + cursor += pSize; + + return pCount; + } + +}; + +// ---------------------------------------------------------------------------------- +/** @class AssbinExport + * @brief Assbin exporter class + * + * This class performs the .assbin exporting, and is responsible for the file layout. + */ +class AssbinExport +{ +private: + bool shortened; + bool compressed; + +protected: + // ----------------------------------------------------------------------------------- + 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); + + 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 < nb_metadata; ++i) { + const aiString& key = node->mMetaData->mKeys[i]; + aiMetadataType type = node->mMetaData->mValues[i].mType; + void* value = node->mMetaData->mValues[i].mData; + + Write(&chunk, key); + Write(&chunk, type); + + switch (type) { + case AI_BOOL: + Write(&chunk, *((bool*) value)); + break; + case AI_INT32: + Write(&chunk, *((int32_t*) value)); + break; + case AI_UINT64: + Write(&chunk, *((uint64_t*) value)); + break; + case AI_FLOAT: + Write(&chunk, *((float*) value)); + break; + case AI_DOUBLE: + Write(&chunk, *((double*) value)); + break; + case AI_AISTRING: + Write(&chunk, *((aiString*) value)); + break; + case AI_AIVECTOR3D: + Write(&chunk, *((aiVector3D*) value)); + break; +#ifdef SWIG + case FORCE_32BIT: +#endif // SWIG + default: + break; + } + } + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryTexture(IOStream * container, const aiTexture* tex) + { + AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AITEXTURE ); + + Write(&chunk,tex->mWidth); + Write(&chunk,tex->mHeight); + chunk.Write( tex->achFormatHint, sizeof(char), 4 ); + + if(!shortened) { + if (!tex->mHeight) { + 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 ); + + 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); + } // else write as usual + else WriteArray(&chunk,b->mWeights,b->mNumWeights); + } + + // ----------------------------------------------------------------------------------- + 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); + + // first of all, write bits for all existent vertex components + unsigned int c = 0; + if (mesh->mVertices) { + c |= ASSBIN_MESH_HAS_POSITIONS; + } + if (mesh->mNormals) { + c |= ASSBIN_MESH_HAS_NORMALS; + } + if (mesh->mTangents && mesh->mBitangents) { + c |= ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS; + } + 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) { + if (!mesh->mColors[n]) { + break; + } + c |= ASSBIN_MESH_HAS_COLOR(n); + } + Write(&chunk,c); + + aiVector3D minVec, maxVec; + if (mesh->mVertices) { + if (shortened) { + WriteBounds(&chunk,mesh->mVertices,mesh->mNumVertices); + } // else write as usual + else WriteArray(&chunk,mesh->mVertices,mesh->mNumVertices); + } + if (mesh->mNormals) { + if (shortened) { + WriteBounds(&chunk,mesh->mNormals,mesh->mNumVertices); + } // else write as usual + 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); + } // else write as usual + else { + 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) { + if (!mesh->mColors[n]) + break; + + if (shortened) { + WriteBounds(&chunk,mesh->mColors[n],mesh->mNumVertices); + } // else write as usual + else WriteArray(&chunk,mesh->mColors[n],mesh->mNumVertices); + } + 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]); + + if (shortened) { + WriteBounds(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices); + } // else write as usual + else WriteArray(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices); + } + + // write faces. There are no floating-point calculations involved + // in these, so we can write a simple hash over the face data + // to the dump file. We generate a single 32 Bit hash for 512 faces + // 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) { + + uint32_t hash = 0; + for (unsigned int a = 0; a < job;++a) { + + const aiFace& f = mesh->mFaces[processed+a]; + uint32_t tmp = f.mNumIndices; + 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); + } + } + Write(&chunk,hash); + } + } + 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]; + + static_assert(AI_MAX_FACE_INDICES <= 0xffff, "AI_MAX_FACE_INDICES <= 0xffff"); + Write(&chunk,f.mNumIndices); + + for (unsigned int a = 0; a < f.mNumIndices;++a) { + if (mesh->mNumVertices < (1u<<16)) { + 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); + } + } + } + + // ----------------------------------------------------------------------------------- + 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->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); + + 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 ); + + 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); + + } // else write as usual + else WriteArray(&chunk,nd->mPositionKeys,nd->mNumPositionKeys); + } + if (nd->mRotationKeys) { + if (shortened) { + WriteBounds(&chunk,nd->mRotationKeys,nd->mNumRotationKeys); + + } // else write as usual + else WriteArray(&chunk,nd->mRotationKeys,nd->mNumRotationKeys); + } + if (nd->mScalingKeys) { + if (shortened) { + 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); + } + } + + // ----------------------------------------------------------------------------------- + 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->mColorDiffuse); + Write(&chunk,l->mColorSpecular); + Write(&chunk,l->mColorAmbient); + + if (l->mType == aiLightSource_SPOT) { + Write(&chunk,l->mAngleInnerCone); + Write(&chunk,l->mAngleOuterCone); + } + + } + + // ----------------------------------------------------------------------------------- + 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); + } + + // ----------------------------------------------------------------------------------- + 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 node graph + 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); + } + + // write materials + 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); + } + + + // write all textures + 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); + } + + // write cameras + for (unsigned int i = 0; i < scene->mNumCameras;++i) { + const aiCamera* cam = scene->mCameras[i]; + WriteBinaryCamera(&chunk,cam); + } + + } + +public: + AssbinExport() + : shortened(false), compressed(false) // temporary settings until properties are introduced for exporters + { + } + + // ----------------------------------------------------------------------------------- + // Write a binary model dump + void WriteBinaryDump(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene) + { + IOStream * out = pIOSystem->Open( pFile, "wb" ); + if (!out) return; + + time_t tt = time(NULL); + tm* p = gmtime(&tt); + + // header + char s[64]; + memset( s, 0, 64 ); +#if _MSC_VER >= 1400 + sprintf_s(s,"ASSIMP.binary-dump.%s",asctime(p)); +#else + ai_snprintf(s,64,"ASSIMP.binary-dump.%s",asctime(p)); +#endif + out->Write( s, 44, 1 ); + // == 44 bytes + + Write( out, ASSBIN_VERSION_MAJOR ); + Write( out, ASSBIN_VERSION_MINOR ); + Write( out, aiGetVersionRevision() ); + Write( out, aiGetCompileFlags() ); + Write( out, shortened ); + Write( out, compressed ); + // == 20 bytes + + char buff[256]; + strncpy(buff,pFile,256); + out->Write(buff,sizeof(char),256); + + char cmd[] = "\0"; + strncpy(buff,cmd,128); + out->Write(buff,sizeof(char),128); + + // leave 64 bytes free for future extensions + memset(buff,0xcd,64); + out->Write(buff,sizeof(char),64); + // == 435 bytes + + // ==== total header size: 512 bytes + ai_assert( out->Tell() == ASSBIN_HEADER_LENGTH ); + + // Up to here the data is uncompressed. For compressed files, the rest + // is compressed using standard DEFLATE from zlib. + if (compressed) + { + AssbinChunkWriter uncompressedStream( NULL, 0 ); + WriteBinaryScene( &uncompressedStream, pScene ); + + uLongf uncompressedSize = static_cast(uncompressedStream.Tell()); + uLongf compressedSize = (uLongf)(uncompressedStream.Tell() * 1.001 + 12.); + uint8_t* compressedBuffer = new uint8_t[ compressedSize ]; + + compress2( compressedBuffer, &compressedSize, (const Bytef*)uncompressedStream.GetBufferPointer(), uncompressedSize, 9 ); + + out->Write( &uncompressedSize, sizeof(uint32_t), 1 ); + out->Write( compressedBuffer, sizeof(char), compressedSize ); + + delete[] compressedBuffer; + } + else + { + WriteBinaryScene( out, pScene ); + } + + pIOSystem->Close( out ); + } +}; + +void ExportSceneAssbin(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/) { AssbinExport exporter; exporter.WriteBinaryDump( pFile, pIOSystem, pScene ); } diff --git a/code/AssbinExporter.h b/code/AssbinExporter.h index 2539984c3..ee70d78b6 100644 --- a/code/AssbinExporter.h +++ b/code/AssbinExporter.h @@ -46,6 +46,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_ASSBINEXPORTER_H_INC #define AI_ASSBINEXPORTER_H_INC -// nothing really needed here - reserved for future use like properties +#include -#endif +// nothing really needed here - reserved for future use like properties +namespace Assimp { + +void ASSIMP_API ExportSceneAssbin(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/); + +} + +#endif // AI_ASSBINEXPORTER_H_INC diff --git a/code/AssbinLoader.cpp b/code/AssbinLoader.cpp index 65b29b737..81c77f3fa 100644 --- a/code/AssbinLoader.cpp +++ b/code/AssbinLoader.cpp @@ -79,16 +79,17 @@ static const aiImporterDesc desc = { "assbin" }; -const aiImporterDesc* AssbinImporter::GetInfo() const -{ +// ----------------------------------------------------------------------------------- +const aiImporterDesc* AssbinImporter::GetInfo() const { return &desc; } -bool AssbinImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool /*checkSig*/ ) const -{ +// ----------------------------------------------------------------------------------- +bool AssbinImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool /*checkSig*/ ) const { IOStream * in = pIOHandler->Open(pFile); - if (!in) + if (nullptr == in) { return false; + } char s[32]; in->Read( s, sizeof(char), 32 ); @@ -98,17 +99,17 @@ bool AssbinImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bo return strncmp( s, "ASSIMP.binary-dump.", 19 ) == 0; } +// ----------------------------------------------------------------------------------- template -T Read(IOStream * stream) -{ +T Read(IOStream * stream) { T t; stream->Read( &t, sizeof(T), 1 ); return t; } +// ----------------------------------------------------------------------------------- template <> -aiVector3D Read(IOStream * stream) -{ +aiVector3D Read(IOStream * stream) { aiVector3D v; v.x = Read(stream); v.y = Read(stream); @@ -116,9 +117,9 @@ aiVector3D Read(IOStream * stream) return v; } +// ----------------------------------------------------------------------------------- template <> -aiColor4D Read(IOStream * stream) -{ +aiColor4D Read(IOStream * stream) { aiColor4D c; c.r = Read(stream); c.g = Read(stream); @@ -127,9 +128,9 @@ aiColor4D Read(IOStream * stream) return c; } +// ----------------------------------------------------------------------------------- template <> -aiQuaternion Read(IOStream * stream) -{ +aiQuaternion Read(IOStream * stream) { aiQuaternion v; v.w = Read(stream); v.x = Read(stream); @@ -138,9 +139,9 @@ aiQuaternion Read(IOStream * stream) return v; } +// ----------------------------------------------------------------------------------- template <> -aiString Read(IOStream * stream) -{ +aiString Read(IOStream * stream) { aiString s; stream->Read(&s.length,4,1); stream->Read(s.data,s.length,1); @@ -148,18 +149,18 @@ aiString Read(IOStream * stream) return s; } +// ----------------------------------------------------------------------------------- template <> -aiVertexWeight Read(IOStream * stream) -{ +aiVertexWeight Read(IOStream * stream) { aiVertexWeight w; w.mVertexId = 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) { @@ -169,36 +170,43 @@ aiMatrix4x4 Read(IOStream * stream) return m; } +// ----------------------------------------------------------------------------------- template <> -aiVectorKey Read(IOStream * stream) -{ +aiVectorKey Read(IOStream * stream) { aiVectorKey v; v.mTime = Read(stream); v.mValue = Read(stream); return v; } +// ----------------------------------------------------------------------------------- template <> -aiQuatKey Read(IOStream * stream) -{ +aiQuatKey Read(IOStream * stream) { aiQuatKey v; v.mTime = Read(stream); v.mValue = Read(stream); return v; } +// ----------------------------------------------------------------------------------- template -void ReadArray(IOStream * stream, T * out, unsigned int size) -{ - for (unsigned int i=0; i(stream); +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 ) -{ +// ----------------------------------------------------------------------------------- +template +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 ); } +// ----------------------------------------------------------------------------------- void AssbinImporter::ReadBinaryNode( IOStream * stream, aiNode** node, aiNode* parent ) { uint32_t chunkID = Read(stream); (void)(chunkID); @@ -273,8 +281,7 @@ void AssbinImporter::ReadBinaryNode( IOStream * stream, aiNode** node, aiNode* p } // ----------------------------------------------------------------------------------- -void AssbinImporter::ReadBinaryBone( IOStream * stream, aiBone* b ) -{ +void AssbinImporter::ReadBinaryBone( IOStream * stream, aiBone* b ) { uint32_t chunkID = Read(stream); (void)(chunkID); ai_assert(chunkID == ASSBIN_CHUNK_AIBONE); @@ -286,20 +293,22 @@ 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) - { + if (shortened) { ReadBounds(stream,b->mWeights,b->mNumWeights); - } // else write as usual - else - { + } else { + // else write as usual b->mWeights = new aiVertexWeight[b->mNumWeights]; ReadArray(stream,b->mWeights,b->mNumWeights); } } +// ----------------------------------------------------------------------------------- +static bool fitsIntoUI16(unsigned int mNumVertices) { + return ( mNumVertices < (1u<<16) ); +} -void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh ) -{ +// ----------------------------------------------------------------------------------- +void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh ) { uint32_t chunkID = Read(stream); (void)(chunkID); ai_assert(chunkID == ASSBIN_CHUNK_AIMESH); @@ -314,70 +323,61 @@ void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh ) // first of all, write bits for all existent vertex components unsigned int c = Read(stream); - if (c & ASSBIN_MESH_HAS_POSITIONS) - { + if (c & ASSBIN_MESH_HAS_POSITIONS) { if (shortened) { ReadBounds(stream,mesh->mVertices,mesh->mNumVertices); - } // else write as usual - else - { + } else { + // else write as usual mesh->mVertices = new aiVector3D[mesh->mNumVertices]; ReadArray(stream,mesh->mVertices,mesh->mNumVertices); } } - if (c & ASSBIN_MESH_HAS_NORMALS) - { + if (c & ASSBIN_MESH_HAS_NORMALS) { if (shortened) { ReadBounds(stream,mesh->mNormals,mesh->mNumVertices); - } // else write as usual - else - { + } else { + // else write as usual mesh->mNormals = new aiVector3D[mesh->mNumVertices]; ReadArray(stream,mesh->mNormals,mesh->mNumVertices); } } - if (c & ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS) - { + if (c & ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS) { if (shortened) { ReadBounds(stream,mesh->mTangents,mesh->mNumVertices); ReadBounds(stream,mesh->mBitangents,mesh->mNumVertices); - } // else write as usual - else - { + } else { + // else write as usual mesh->mTangents = new aiVector3D[mesh->mNumVertices]; ReadArray(stream,mesh->mTangents,mesh->mNumVertices); mesh->mBitangents = new aiVector3D[mesh->mNumVertices]; ReadArray(stream,mesh->mBitangents,mesh->mNumVertices); } } - for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) - { - if (!(c & ASSBIN_MESH_HAS_COLOR(n))) + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) { + if (!(c & ASSBIN_MESH_HAS_COLOR(n))) { break; + } - if (shortened) - { + if (shortened) { ReadBounds(stream,mesh->mColors[n],mesh->mNumVertices); - } // else write as usual - else - { + } else { + // else write as usual mesh->mColors[n] = new aiColor4D[mesh->mNumVertices]; ReadArray(stream,mesh->mColors[n],mesh->mNumVertices); } } - for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) - { - if (!(c & ASSBIN_MESH_HAS_TEXCOORD(n))) + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) { + if (!(c & ASSBIN_MESH_HAS_TEXCOORD(n))) { break; + } // write number of UV components mesh->mNumUVComponents[n] = Read(stream); if (shortened) { ReadBounds(stream,mesh->mTextureCoords[n],mesh->mNumVertices); - } // else write as usual - else - { + } else { + // else write as usual mesh->mTextureCoords[n] = new aiVector3D[mesh->mNumVertices]; ReadArray(stream,mesh->mTextureCoords[n],mesh->mNumVertices); } @@ -389,9 +389,8 @@ void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh ) // using Assimp's standard hashing function. if (shortened) { Read(stream); - } - 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 ... mesh->mFaces = new aiFace[mesh->mNumFaces]; for (unsigned int i = 0; i < mesh->mNumFaces;++i) { @@ -402,12 +401,10 @@ void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh ) f.mIndices = new unsigned int[f.mNumIndices]; for (unsigned int a = 0; a < f.mNumIndices;++a) { - if (mesh->mNumVertices < (1u<<16)) - { + // Check if unsigned short ( 16 bit ) are big enought for the indices + if ( fitsIntoUI16( mesh->mNumVertices ) ) { f.mIndices[a] = Read(stream); - } - else - { + } else { f.mIndices[a] = Read(stream); } } @@ -424,8 +421,8 @@ void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh ) } } -void AssbinImporter::ReadBinaryMaterialProperty(IOStream * stream, aiMaterialProperty* prop) -{ +// ----------------------------------------------------------------------------------- +void AssbinImporter::ReadBinaryMaterialProperty(IOStream * stream, aiMaterialProperty* prop) { uint32_t chunkID = Read(stream); (void)(chunkID); ai_assert(chunkID == ASSBIN_CHUNK_AIMATERIALPROPERTY); @@ -442,8 +439,7 @@ void AssbinImporter::ReadBinaryMaterialProperty(IOStream * stream, aiMaterialPro } // ----------------------------------------------------------------------------------- -void AssbinImporter::ReadBinaryMaterial(IOStream * stream, aiMaterial* mat) -{ +void AssbinImporter::ReadBinaryMaterial(IOStream * stream, aiMaterial* mat) { uint32_t chunkID = Read(stream); (void)(chunkID); ai_assert(chunkID == ASSBIN_CHUNK_AIMATERIAL); @@ -465,8 +461,7 @@ void AssbinImporter::ReadBinaryMaterial(IOStream * stream, aiMaterial* mat) } // ----------------------------------------------------------------------------------- -void AssbinImporter::ReadBinaryNodeAnim(IOStream * stream, aiNodeAnim* nd) -{ +void AssbinImporter::ReadBinaryNodeAnim(IOStream * stream, aiNodeAnim* nd) { uint32_t chunkID = Read(stream); (void)(chunkID); ai_assert(chunkID == ASSBIN_CHUNK_AINODEANIM); @@ -493,9 +488,8 @@ void AssbinImporter::ReadBinaryNodeAnim(IOStream * stream, aiNodeAnim* nd) if (shortened) { ReadBounds(stream,nd->mRotationKeys,nd->mNumRotationKeys); - } // else write as usual - else - { + } else { + // else write as usual nd->mRotationKeys = new aiQuatKey[nd->mNumRotationKeys]; ReadArray(stream,nd->mRotationKeys,nd->mNumRotationKeys); } @@ -504,19 +498,16 @@ void AssbinImporter::ReadBinaryNodeAnim(IOStream * stream, aiNodeAnim* nd) if (shortened) { ReadBounds(stream,nd->mScalingKeys,nd->mNumScalingKeys); - } // else write as usual - else - { + } else { + // else write as usual nd->mScalingKeys = new aiVectorKey[nd->mNumScalingKeys]; ReadArray(stream,nd->mScalingKeys,nd->mNumScalingKeys); } } } - // ----------------------------------------------------------------------------------- -void AssbinImporter::ReadBinaryAnim( IOStream * stream, aiAnimation* anim ) -{ +void AssbinImporter::ReadBinaryAnim( IOStream * stream, aiAnimation* anim ) { uint32_t chunkID = Read(stream); (void)(chunkID); ai_assert(chunkID == ASSBIN_CHUNK_AIANIMATION); @@ -527,8 +518,7 @@ void AssbinImporter::ReadBinaryAnim( IOStream * stream, aiAnimation* anim ) anim->mTicksPerSecond = Read (stream); anim->mNumChannels = Read(stream); - if (anim->mNumChannels) - { + if (anim->mNumChannels) { anim->mChannels = new aiNodeAnim*[ anim->mNumChannels ]; for (unsigned int a = 0; a < anim->mNumChannels;++a) { anim->mChannels[a] = new aiNodeAnim(); @@ -537,8 +527,8 @@ void AssbinImporter::ReadBinaryAnim( IOStream * stream, aiAnimation* anim ) } } -void AssbinImporter::ReadBinaryTexture(IOStream * stream, aiTexture* tex) -{ +// ----------------------------------------------------------------------------------- +void AssbinImporter::ReadBinaryTexture(IOStream * stream, aiTexture* tex) { uint32_t chunkID = Read(stream); (void)(chunkID); ai_assert(chunkID == ASSBIN_CHUNK_AITEXTURE); @@ -552,18 +542,15 @@ void AssbinImporter::ReadBinaryTexture(IOStream * stream, aiTexture* tex) if (!tex->mHeight) { tex->pcData = new aiTexel[ tex->mWidth ]; stream->Read(tex->pcData,1,tex->mWidth); - } - else { + } else { 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 ) -{ +void AssbinImporter::ReadBinaryLight( IOStream * stream, aiLight* l ) { uint32_t chunkID = Read(stream); (void)(chunkID); ai_assert(chunkID == ASSBIN_CHUNK_AILIGHT); @@ -586,12 +573,10 @@ void AssbinImporter::ReadBinaryLight( IOStream * stream, aiLight* l ) l->mAngleInnerCone = Read(stream); l->mAngleOuterCone = Read(stream); } - } // ----------------------------------------------------------------------------------- -void AssbinImporter::ReadBinaryCamera( IOStream * stream, aiCamera* cam ) -{ +void AssbinImporter::ReadBinaryCamera( IOStream * stream, aiCamera* cam ) { uint32_t chunkID = Read(stream); (void)(chunkID); ai_assert(chunkID == ASSBIN_CHUNK_AICAMERA); @@ -607,8 +592,8 @@ void AssbinImporter::ReadBinaryCamera( IOStream * stream, aiCamera* cam ) cam->mAspect = Read(stream); } -void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene ) -{ +// ----------------------------------------------------------------------------------- +void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene ) { uint32_t chunkID = Read(stream); (void)(chunkID); ai_assert(chunkID == ASSBIN_CHUNK_AISCENE); @@ -623,12 +608,11 @@ void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene ) scene->mNumCameras = Read(stream); // Read node graph - scene->mRootNode = new aiNode[1]; + //scene->mRootNode = new aiNode[1]; ReadBinaryNode( stream, &scene->mRootNode, (aiNode*)NULL ); // Read all meshes - if (scene->mNumMeshes) - { + if (scene->mNumMeshes) { scene->mMeshes = new aiMesh*[scene->mNumMeshes]; for (unsigned int i = 0; i < scene->mNumMeshes;++i) { scene->mMeshes[i] = new aiMesh(); @@ -637,8 +621,7 @@ void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene ) } // Read materials - if (scene->mNumMaterials) - { + if (scene->mNumMaterials) { scene->mMaterials = new aiMaterial*[scene->mNumMaterials]; for (unsigned int i = 0; i< scene->mNumMaterials; ++i) { scene->mMaterials[i] = new aiMaterial(); @@ -647,8 +630,7 @@ void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene ) } // Read all animations - if (scene->mNumAnimations) - { + if (scene->mNumAnimations) { scene->mAnimations = new aiAnimation*[scene->mNumAnimations]; for (unsigned int i = 0; i < scene->mNumAnimations;++i) { scene->mAnimations[i] = new aiAnimation(); @@ -657,8 +639,7 @@ void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene ) } // Read all textures - if (scene->mNumTextures) - { + if (scene->mNumTextures) { scene->mTextures = new aiTexture*[scene->mNumTextures]; for (unsigned int i = 0; i < scene->mNumTextures;++i) { scene->mTextures[i] = new aiTexture(); @@ -667,8 +648,7 @@ void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene ) } // Read lights - if (scene->mNumLights) - { + if (scene->mNumLights) { scene->mLights = new aiLight*[scene->mNumLights]; for (unsigned int i = 0; i < scene->mNumLights;++i) { scene->mLights[i] = new aiLight(); @@ -677,8 +657,7 @@ void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene ) } // Read cameras - if (scene->mNumCameras) - { + if (scene->mNumCameras) { scene->mCameras = new aiCamera*[scene->mNumCameras]; for (unsigned int i = 0; i < scene->mNumCameras;++i) { scene->mCameras[i] = new aiCamera(); @@ -688,16 +667,22 @@ void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene ) } -void AssbinImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler ) -{ +// ----------------------------------------------------------------------------------- +void AssbinImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler ) { IOStream * stream = pIOHandler->Open(pFile,"rb"); - if (!stream) + if (nullptr == stream) { return; + } - stream->Seek( 44, aiOrigin_CUR ); // signature + // signature + 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!" ); + } - /*unsigned int versionMajor =*/ Read(stream); - /*unsigned int versionMinor =*/ Read(stream); /*unsigned int versionRevision =*/ Read(stream); /*unsigned int compileFlags =*/ Read(stream); @@ -711,8 +696,7 @@ void AssbinImporter::InternReadFile( const std::string& pFile, aiScene* pScene, stream->Seek( 128, aiOrigin_CUR ); // options stream->Seek( 64, aiOrigin_CUR ); // padding - if (compressed) - { + if (compressed) { uLongf uncompressedSize = Read(stream); uLongf compressedSize = static_cast(stream->FileSize() - stream->Tell()); @@ -729,9 +713,7 @@ void AssbinImporter::InternReadFile( const std::string& pFile, aiScene* pScene, delete[] uncompressedData; delete[] compressedData; - } - else - { + } else { ReadBinaryScene(stream,pScene); } diff --git a/code/AssbinLoader.h b/code/AssbinLoader.h index 9ffd84a16..37799a2c8 100644 --- a/code/AssbinLoader.h +++ b/code/AssbinLoader.h @@ -70,32 +70,33 @@ namespace Assimp { class AssbinImporter : public BaseImporter { private: - bool shortened; - bool compressed; + bool shortened; + bool compressed; public: - virtual bool CanRead( - const std::string& pFile, - IOSystem* pIOHandler, - bool checkSig + virtual bool CanRead( + const std::string& pFile, + IOSystem* pIOHandler, + bool checkSig ) const; - virtual const aiImporterDesc* GetInfo() const; - virtual void InternReadFile( + virtual const aiImporterDesc* GetInfo() const; + virtual void InternReadFile( const std::string& pFile, - aiScene* pScene, - IOSystem* pIOHandler + aiScene* pScene, + IOSystem* pIOHandler ); - void ReadBinaryScene( IOStream * stream, aiScene* pScene ); - void ReadBinaryNode( IOStream * stream, aiNode** mRootNode, aiNode* parent ); - void ReadBinaryMesh( IOStream * stream, aiMesh* mesh ); - void ReadBinaryBone( IOStream * stream, aiBone* bone ); - void ReadBinaryMaterial(IOStream * stream, aiMaterial* mat); - void ReadBinaryMaterialProperty(IOStream * stream, aiMaterialProperty* prop); - void ReadBinaryNodeAnim(IOStream * stream, aiNodeAnim* nd); - void ReadBinaryAnim( IOStream * stream, aiAnimation* anim ); - void ReadBinaryTexture(IOStream * stream, aiTexture* tex); - void ReadBinaryLight( IOStream * stream, aiLight* l ); - void ReadBinaryCamera( IOStream * stream, aiCamera* cam ); + void ReadHeader(); + void ReadBinaryScene( IOStream * stream, aiScene* pScene ); + void ReadBinaryNode( IOStream * stream, aiNode** mRootNode, aiNode* parent ); + void ReadBinaryMesh( IOStream * stream, aiMesh* mesh ); + void ReadBinaryBone( IOStream * stream, aiBone* bone ); + void ReadBinaryMaterial(IOStream * stream, aiMaterial* mat); + void ReadBinaryMaterialProperty(IOStream * stream, aiMaterialProperty* prop); + void ReadBinaryNodeAnim(IOStream * stream, aiNodeAnim* nd); + void ReadBinaryAnim( IOStream * stream, aiAnimation* anim ); + void ReadBinaryTexture(IOStream * stream, aiTexture* tex); + void ReadBinaryLight( IOStream * stream, aiLight* l ); + void ReadBinaryCamera( IOStream * stream, aiCamera* cam ); }; } // end of namespace Assimp diff --git a/code/BVHLoader.cpp b/code/BVHLoader.cpp index 0b2a818ae..cba58d056 100644 --- a/code/BVHLoader.cpp +++ b/code/BVHLoader.cpp @@ -54,6 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include using namespace Assimp; using namespace Assimp::Formatter; @@ -461,6 +462,13 @@ void BVHLoader::CreateAnimation( aiScene* pScene) aiNodeAnim* nodeAnim = new aiNodeAnim; anim->mChannels[a] = nodeAnim; nodeAnim->mNodeName.Set( nodeName); + std::map channelMap; + + //Build map of channels + for (unsigned int channel = 0; channel < node.mChannels.size(); ++channel) + { + channelMap[node.mChannels[channel]] = channel; + } // translational part, if given if( node.mChannels.size() == 6) @@ -472,16 +480,32 @@ void BVHLoader::CreateAnimation( aiScene* pScene) { poskey->mTime = double( fr); - // Now compute all translations in the right order - for( unsigned int channel = 0; channel < 3; ++channel) + // Now compute all translations + for(BVHLoader::ChannelType channel = Channel_PositionX; channel <= Channel_PositionZ; channel = (BVHLoader::ChannelType)(channel +1)) { - switch( node.mChannels[channel]) - { - case Channel_PositionX: poskey->mValue.x = node.mChannelValues[fr * node.mChannels.size() + channel]; break; - case Channel_PositionY: poskey->mValue.y = node.mChannelValues[fr * node.mChannels.size() + channel]; break; - case Channel_PositionZ: poskey->mValue.z = node.mChannelValues[fr * node.mChannels.size() + channel]; break; - default: throw DeadlyImportError( "Unexpected animation channel setup at node " + nodeName ); - } + //Find channel in node + std::map::iterator mapIter = channelMap.find(channel); + + if (mapIter == channelMap.end()) + throw DeadlyImportError("Missing position channel in node " + nodeName); + else { + int channelIdx = mapIter->second; + switch (channel) { + case Channel_PositionX: + poskey->mValue.x = node.mChannelValues[fr * node.mChannels.size() + channelIdx]; + break; + case Channel_PositionY: + poskey->mValue.y = node.mChannelValues[fr * node.mChannels.size() + channelIdx]; + break; + case Channel_PositionZ: + poskey->mValue.z = node.mChannelValues[fr * node.mChannels.size() + channelIdx]; + break; + + default: + break; + } + + } } ++poskey; } @@ -497,12 +521,6 @@ void BVHLoader::CreateAnimation( aiScene* pScene) // rotation part. Always present. First find value offsets { - unsigned int rotOffset = 0; - if( node.mChannels.size() == 6) - { - // Offset all further calculations - rotOffset = 3; - } // Then create the number of rotation keys nodeAnim->mNumRotationKeys = mAnimNumFrames; @@ -512,20 +530,33 @@ void BVHLoader::CreateAnimation( aiScene* pScene) { aiMatrix4x4 temp; aiMatrix3x3 rotMatrix; + for (BVHLoader::ChannelType channel = Channel_RotationX; channel <= Channel_RotationZ; channel = (BVHLoader::ChannelType)(channel + 1)) + { + //Find channel in node + std::map::iterator mapIter = channelMap.find(channel); - for( unsigned int channel = 0; channel < 3; ++channel) - { - // translate ZXY euler angels into a quaternion - const float angle = node.mChannelValues[fr * node.mChannels.size() + rotOffset + channel] * float( AI_MATH_PI) / 180.0f; + if (mapIter == channelMap.end()) + throw DeadlyImportError("Missing rotation channel in node " + nodeName); + else { + int channelIdx = mapIter->second; + // translate ZXY euler angels into a quaternion + const float angle = node.mChannelValues[fr * node.mChannels.size() + channelIdx] * float(AI_MATH_PI) / 180.0f; - // Compute rotation transformations in the right order - switch (node.mChannels[rotOffset+channel]) - { - case Channel_RotationX: aiMatrix4x4::RotationX( angle, temp); rotMatrix *= aiMatrix3x3( temp); break; - case Channel_RotationY: aiMatrix4x4::RotationY( angle, temp); rotMatrix *= aiMatrix3x3( temp); break; - case Channel_RotationZ: aiMatrix4x4::RotationZ( angle, temp); rotMatrix *= aiMatrix3x3( temp); break; - default: throw DeadlyImportError( "Unexpected animation channel setup at node " + nodeName ); - } + // Compute rotation transformations in the right order + switch (channel) + { + case Channel_RotationX: + aiMatrix4x4::RotationX(angle, temp); rotMatrix *= aiMatrix3x3(temp); + break; + case Channel_RotationY: + aiMatrix4x4::RotationY(angle, temp); rotMatrix *= aiMatrix3x3(temp); + break; + case Channel_RotationZ: aiMatrix4x4::RotationZ(angle, temp); rotMatrix *= aiMatrix3x3(temp); + break; + default: + break; + } + } } rotkey->mTime = double( fr); diff --git a/code/BaseImporter.cpp b/code/BaseImporter.cpp index 78979d078..f03db189f 100644 --- a/code/BaseImporter.cpp +++ b/code/BaseImporter.cpp @@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include +#include #include "FileSystemFilter.h" #include "Importer.h" #include @@ -53,6 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include + #include #include #include @@ -63,7 +65,7 @@ using namespace Assimp; // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer -BaseImporter::BaseImporter() +BaseImporter::BaseImporter() AI_NO_EXCEPT : m_progress() { // nothing to do here } @@ -143,7 +145,8 @@ void BaseImporter::GetExtensionList(std::set& extensions) { const char** tokens, unsigned int numTokens, unsigned int searchBytes /* = 200 */, - bool tokensSol /* false */) + bool tokensSol /* false */, + bool noAlphaBeforeTokens /* false */) { ai_assert( nullptr != tokens ); ai_assert( 0 != numTokens ); @@ -157,15 +160,14 @@ void BaseImporter::GetExtensionList(std::set& extensions) { if (pStream.get() ) { // read 200 characters from the file std::unique_ptr _buffer (new char[searchBytes+1 /* for the '\0' */]); - char* buffer = _buffer.get(); - - const size_t read = pStream->Read(buffer,1,searchBytes); - if( !read ) { + char *buffer( _buffer.get() ); + const size_t read( pStream->Read(buffer,1,searchBytes) ); + if( 0 == read ) { return false; } for( size_t i = 0; i < read; ++i ) { - buffer[ i ] = ::tolower( buffer[ i ] ); + buffer[ i ] = static_cast( ::tolower( buffer[ i ] ) ); } // It is not a proper handling of unicode files here ... @@ -186,13 +188,18 @@ void BaseImporter::GetExtensionList(std::set& extensions) { token.clear(); const char *ptr( tokens[ i ] ); for ( size_t tokIdx = 0; tokIdx < len; ++tokIdx ) { - token.push_back( tolower( *ptr ) ); + token.push_back( static_cast( tolower( *ptr ) ) ); ++ptr; } const char* r = strstr( buffer, token.c_str() ); if( !r ) { continue; } + // We need to make sure that we didn't accidentially identify the end of another token as our token, + // e.g. in a previous version the "gltf " present in some gltf files was detected as "f " + if (noAlphaBeforeTokens && (r != buffer && isalpha(r[-1]))) { + continue; + } // We got a match, either we don't care where it is, or it happens to // be in the beginning of the file / line if (!tokensSol || r == buffer || r[-1] == '\r' || r[-1] == '\n') { @@ -234,16 +241,19 @@ void BaseImporter::GetExtensionList(std::set& extensions) { // ------------------------------------------------------------------------------------------------ // Get file extension from path -/*static*/ std::string BaseImporter::GetExtension (const std::string& pFile) -{ - std::string::size_type pos = pFile.find_last_of('.'); +std::string BaseImporter::GetExtension( const std::string& file ) { + std::string::size_type pos = file.find_last_of('.'); // no file extension at all - if( pos == std::string::npos) + if (pos == std::string::npos) { return ""; + } + + + // thanks to Andy Maloney for the hint + std::string ret = file.substr( pos + 1 ); + std::transform( ret.begin(), ret.end(), ret.begin(), ToLower); - std::string ret = pFile.substr(pos+1); - std::transform(ret.begin(),ret.end(),ret.begin(),::tolower); // thanks to Andy Maloney for the hint return ret; } diff --git a/code/BaseProcess.cpp b/code/BaseProcess.cpp index ba968a819..154b586d2 100644 --- a/code/BaseProcess.cpp +++ b/code/BaseProcess.cpp @@ -53,7 +53,7 @@ using namespace Assimp; // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer -BaseProcess::BaseProcess() +BaseProcess::BaseProcess() AI_NO_EXCEPT : shared() , progress() { diff --git a/code/BaseProcess.h b/code/BaseProcess.h index d9323fbef..b09fc732e 100644 --- a/code/BaseProcess.h +++ b/code/BaseProcess.h @@ -211,20 +211,16 @@ private: * should be executed. If the function returns true, the class' Execute() * function is called subsequently. */ -class ASSIMP_API_WINONLY BaseProcess -{ +class ASSIMP_API_WINONLY BaseProcess { friend class Importer; public: - /** Constructor to be privately used by Importer */ - BaseProcess(); + BaseProcess() AI_NO_EXCEPT; /** Destructor, private as well */ virtual ~BaseProcess(); -public: - // ------------------------------------------------------------------- /** Returns whether the processing step is present in the given flag. * @param pFlags The processing flags the importer was called with. A diff --git a/code/BlenderCustomData.cpp b/code/BlenderCustomData.cpp new file mode 100644 index 000000000..682186618 --- /dev/null +++ b/code/BlenderCustomData.cpp @@ -0,0 +1,185 @@ +#include "BlenderCustomData.h" +#include "BlenderDNA.h" +#include +#include + +namespace Assimp { + namespace Blender { + /** + * @brief read/convert of Structure array to memory + */ + template + bool read(const Structure &s, T *p, const size_t cnt, const FileDatabase &db) { + for (size_t i = 0; i < cnt; ++i) { + T read; + s.Convert(read, db); + *p = read; + p++; + } + return true; + } + + /** + * @brief pointer to function read memory for n CustomData types + */ + typedef bool (*PRead)(ElemBase *pOut, const size_t cnt, const FileDatabase &db); + typedef ElemBase * (*PCreate)(const size_t cnt); + typedef void(*PDestroy)(ElemBase *); + +#define IMPL_STRUCT_READ(ty) \ + bool read##ty(ElemBase *v, const size_t cnt, const FileDatabase &db) { \ + return read(db.dna[#ty], dynamic_cast(v), cnt, db); \ + } + +#define IMPL_STRUCT_CREATE(ty) \ + ElemBase *create##ty(const size_t cnt) { \ + return new ty[cnt]; \ + } + +#define IMPL_STRUCT_DESTROY(ty) \ + void destroy##ty(ElemBase *pE) { \ + ty *p = dynamic_cast(pE); \ + delete[]p; \ + } + + /** + * @brief helper macro to define Structure functions + */ +#define IMPL_STRUCT(ty) \ + IMPL_STRUCT_READ(ty) \ + IMPL_STRUCT_CREATE(ty) \ + IMPL_STRUCT_DESTROY(ty) + + // supported structures for CustomData + IMPL_STRUCT(MVert) + IMPL_STRUCT(MEdge) + IMPL_STRUCT(MFace) + IMPL_STRUCT(MTFace) + IMPL_STRUCT(MTexPoly) + IMPL_STRUCT(MLoopUV) + IMPL_STRUCT(MLoopCol) + IMPL_STRUCT(MPoly) + IMPL_STRUCT(MLoop) + + /** + * @brief describes the size of data and the read function to be used for single CustomerData.type + */ + struct CustomDataTypeDescription { + PRead Read; ///< function to read one CustomData type element + PCreate Create; ///< function to allocate n type elements + PDestroy Destroy; + + CustomDataTypeDescription(PRead read, PCreate create, PDestroy destroy) + : Read(read) + , Create(create) + , Destroy(destroy) + {} + }; + + + /** + * @brief helper macro to define Structure type specific CustomDataTypeDescription + * @note IMPL_STRUCT_READ for same ty must be used earlier to implement the typespecific read function + */ +#define DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(ty) \ + CustomDataTypeDescription{&read##ty, &create##ty, &destroy##ty} + + /** + * @brief helper macro to define CustomDataTypeDescription for UNSUPPORTED type + */ +#define DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION \ + CustomDataTypeDescription{nullptr, nullptr, nullptr} + + /** + * @brief descriptors for data pointed to from CustomDataLayer.data + * @note some of the CustomData uses already well defined Structures + * other (like CD_ORCO, ...) uses arrays of rawtypes or even arrays of Structures + * use a special readfunction for that cases + */ + std::array customDataTypeDescriptions = { { + DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MVert), + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MEdge), + DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MFace), + DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MTFace), + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MTexPoly), + DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MLoopUV), + DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MLoopCol), + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MPoly), + DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MLoop), + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION, + DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION + }}; + + + bool isValidCustomDataType(const int cdtype) { + return cdtype >= 0 && cdtype < CD_NUMTYPES; + } + + bool readCustomData(std::shared_ptr &out, const int cdtype, const size_t cnt, const FileDatabase &db) { + if (!isValidCustomDataType(cdtype)) { + throw Error((Formatter::format(), "CustomData.type ", cdtype, " out of index")); + } + + const CustomDataTypeDescription cdtd = customDataTypeDescriptions[cdtype]; + if (cdtd.Read && cdtd.Create && cdtd.Destroy && cnt > 0) { + // allocate cnt elements and parse them from file + out.reset(cdtd.Create(cnt), cdtd.Destroy); + return cdtd.Read(out.get(), cnt, db); + } + return false; + } + + std::shared_ptr getCustomDataLayer(const CustomData &customdata, const CustomDataType cdtype, const std::string &name) { + for (auto it = customdata.layers.begin(); it != customdata.layers.end(); ++it) { + if (it->get()->type == cdtype && name == it->get()->name) { + return *it; + } + } + return nullptr; + } + + const ElemBase * getCustomDataLayerData(const CustomData &customdata, const CustomDataType cdtype, const std::string &name) + { + const std::shared_ptr pLayer = getCustomDataLayer(customdata, cdtype, name); + if (pLayer && pLayer->data) { + return pLayer->data.get(); + } + return nullptr; + } + } +} diff --git a/code/BlenderCustomData.h b/code/BlenderCustomData.h new file mode 100644 index 000000000..f61d79a26 --- /dev/null +++ b/code/BlenderCustomData.h @@ -0,0 +1,89 @@ +#pragma once + +#include "BlenderDNA.h" +#include "BlenderScene.h" +#include + +namespace Assimp { + namespace Blender { + /* CustomData.type from Blender (2.79b) */ + enum CustomDataType { + CD_AUTO_FROM_NAME = -1, + CD_MVERT = 0, +#ifdef DNA_DEPRECATED + CD_MSTICKY = 1, /* DEPRECATED */ +#endif + CD_MDEFORMVERT = 2, + CD_MEDGE = 3, + CD_MFACE = 4, + CD_MTFACE = 5, + CD_MCOL = 6, + CD_ORIGINDEX = 7, + CD_NORMAL = 8, + /* CD_POLYINDEX = 9, */ + CD_PROP_FLT = 10, + CD_PROP_INT = 11, + CD_PROP_STR = 12, + CD_ORIGSPACE = 13, /* for modifier stack face location mapping */ + CD_ORCO = 14, + CD_MTEXPOLY = 15, + CD_MLOOPUV = 16, + CD_MLOOPCOL = 17, + CD_TANGENT = 18, + CD_MDISPS = 19, + CD_PREVIEW_MCOL = 20, /* for displaying weightpaint colors */ + /* CD_ID_MCOL = 21, */ + CD_TEXTURE_MLOOPCOL = 22, + CD_CLOTH_ORCO = 23, + CD_RECAST = 24, + + /* BMESH ONLY START */ + CD_MPOLY = 25, + CD_MLOOP = 26, + CD_SHAPE_KEYINDEX = 27, + CD_SHAPEKEY = 28, + CD_BWEIGHT = 29, + CD_CREASE = 30, + CD_ORIGSPACE_MLOOP = 31, + CD_PREVIEW_MLOOPCOL = 32, + CD_BM_ELEM_PYPTR = 33, + /* BMESH ONLY END */ + + CD_PAINT_MASK = 34, + CD_GRID_PAINT_MASK = 35, + CD_MVERT_SKIN = 36, + CD_FREESTYLE_EDGE = 37, + CD_FREESTYLE_FACE = 38, + CD_MLOOPTANGENT = 39, + CD_TESSLOOPNORMAL = 40, + CD_CUSTOMLOOPNORMAL = 41, + + CD_NUMTYPES = 42 + }; + + /** + * @brief check if given cdtype is valid (ie >= 0 and < CD_NUMTYPES) + * @param[in] cdtype to check + * @return true when valid + */ + bool isValidCustomDataType(const int cdtype); + + /** + * @brief returns CustomDataLayer ptr for given cdtype and name + * @param[in] customdata CustomData to search for wanted layer + * @param[in] cdtype to search for + * @param[in] name to search for + * @return CustomDataLayer * or nullptr if not found + */ + std::shared_ptr getCustomDataLayer(const CustomData &customdata, CustomDataType cdtype, const std::string &name); + + /** + * @brief returns CustomDataLayer data ptr for given cdtype and name + * @param[in] customdata CustomData to search for wanted layer + * @param[in] cdtype to search for + * @param[in] name to search for + * @return * to struct data or nullptr if not found + */ + const ElemBase * getCustomDataLayerData(const CustomData &customdata, CustomDataType cdtype, const std::string &name); + } +} diff --git a/code/BlenderDNA.h b/code/BlenderDNA.h index 6a18fe9fa..ecf606a3b 100644 --- a/code/BlenderDNA.h +++ b/code/BlenderDNA.h @@ -309,6 +309,28 @@ public: void ReadField(T& out, const char* name, const FileDatabase& db) const; + // -------------------------------------------------------- + /** + * @brief field parsing for dynamic vectors + * @param[in] out vector of struct to be filled + * @param[in] name of field + * @param[in] db to access the file, dna, ... + * @return true when read was successful + */ + template class TOUT, typename T> + bool ReadFieldPtrVector(vector>&out, const char* name, const FileDatabase& db) const; + + /** + * @brief parses raw customdata + * @param[in] out shared_ptr to be filled + * @param[in] cdtype customdata type to read + * @param[in] name of field ptr + * @param[in] db to access the file, dna, ... + * @return true when read was successful + */ + template + bool ReadCustomDataPtr(std::shared_ptr&out, int cdtype, const char* name, const FileDatabase& db) const; + private: // -------------------------------------------------------- @@ -803,6 +825,17 @@ private: FileDatabase& db; }; +/** +* @brief read CustomData's data to ptr to mem +* @param[out] out memory ptr to set +* @param[in] cdtype to read +* @param[in] cnt cnt of elements to read +* @param[in] db to read elements from +* @return true when ok +*/ +bool readCustomData(std::shared_ptr &out, int cdtype, size_t cnt, const FileDatabase &db); + + } // end Blend } // end Assimp diff --git a/code/BlenderDNA.inl b/code/BlenderDNA.inl index e43d15d38..5065aa118 100644 --- a/code/BlenderDNA.inl +++ b/code/BlenderDNA.inl @@ -307,6 +307,108 @@ void Structure :: ReadField(T& out, const char* name, const FileDatabase& db) co } +//-------------------------------------------------------------------------------- +// field parsing for raw untyped data (like CustomDataLayer.data) +template +bool Structure::ReadCustomDataPtr(std::shared_ptr&out, int cdtype, const char* name, const FileDatabase& db) const { + + const StreamReaderAny::pos old = db.reader->GetCurrentPos(); + + Pointer ptrval; + const Field* f; + try { + f = &(*this)[name]; + + // sanity check, should never happen if the genblenddna script is right + if (!(f->flags & FieldFlag_Pointer)) { + throw Error((Formatter::format(), "Field `", name, "` of structure `", + this->name, "` ought to be a pointer")); + } + + db.reader->IncPtr(f->offset); + Convert(ptrval, db); + // actually it is meaningless on which Structure the Convert is called + // because the `Pointer` argument triggers a special implementation. + } + catch (const Error& e) { + _defaultInitializer()(out, e.what()); + out.reset(); + } + + bool readOk = true; + if (ptrval.val) { + // get block for ptr + const FileBlockHead* block = LocateFileBlockForAddress(ptrval, db); + db.reader->SetCurrentPos(block->start + static_cast((ptrval.val - block->address.val))); + // read block->num instances of given type to out + readOk = readCustomData(out, cdtype, block->num, db); + } + + // and recover the previous stream position + db.reader->SetCurrentPos(old); + +#ifndef ASSIMP_BUILD_BLENDER_NO_STATS + ++db.stats().fields_read; +#endif + + return readOk; +} + +//-------------------------------------------------------------------------------- +template class TOUT, typename T> +bool Structure::ReadFieldPtrVector(vector>&out, const char* name, const FileDatabase& db) const { + out.clear(); + + const StreamReaderAny::pos old = db.reader->GetCurrentPos(); + + Pointer ptrval; + const Field* f; + try { + f = &(*this)[name]; + + // sanity check, should never happen if the genblenddna script is right + if (!(f->flags & FieldFlag_Pointer)) { + throw Error((Formatter::format(), "Field `", name, "` of structure `", + this->name, "` ought to be a pointer")); + } + + db.reader->IncPtr(f->offset); + Convert(ptrval, db); + // actually it is meaningless on which Structure the Convert is called + // because the `Pointer` argument triggers a special implementation. + } + catch (const Error& e) { + _defaultInitializer()(out, e.what()); + out.clear(); + return false; + } + + + if (ptrval.val) { + // find the file block the pointer is pointing to + const FileBlockHead* block = LocateFileBlockForAddress(ptrval, db); + db.reader->SetCurrentPos(block->start + static_cast((ptrval.val - block->address.val))); + // FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems. + // I really ought to improve StreamReader to work with 64 bit indices exclusively. + + const Structure& s = db.dna[f->type]; + for (size_t i = 0; i < block->num; ++i) { + TOUT p(new T); + s.Convert(*p, db); + out.push_back(p); + } + } + + db.reader->SetCurrentPos(old); + +#ifndef ASSIMP_BUILD_BLENDER_NO_STATS + ++db.stats().fields_read; +#endif + + return false; +} + + //-------------------------------------------------------------------------------- template