From 0fef0e11016e4cc3f59eee45f1522ccd2525c584 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Tue, 14 Sep 2021 20:45:36 +0200 Subject: [PATCH] Move duplicate code to glFT common header. --- code/AssetLib/glTF/glTFAsset.h | 1745 ++++++++++++------------- code/AssetLib/glTF/glTFAsset.inl | 119 -- code/AssetLib/glTF/glTFCommon.h | 314 ++++- code/AssetLib/glTF/glTFExporter.h | 115 +- code/AssetLib/glTF/glTFImporter.h | 2 +- code/AssetLib/glTF2/glTF2Asset.h | 90 +- code/AssetLib/glTF2/glTF2Asset.inl | 253 +--- code/AssetLib/glTF2/glTF2Exporter.cpp | 2 +- code/AssetLib/glTF2/glTF2Exporter.h | 152 +-- code/AssetLib/glTF2/glTF2Importer.cpp | 8 +- code/AssetLib/glTF2/glTF2Importer.h | 3 +- 11 files changed, 1319 insertions(+), 1484 deletions(-) diff --git a/code/AssetLib/glTF/glTFAsset.h b/code/AssetLib/glTF/glTFAsset.h index b62ebe135..5f5945271 100644 --- a/code/AssetLib/glTF/glTFAsset.h +++ b/code/AssetLib/glTF/glTFAsset.h @@ -51,14 +51,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #if !defined(ASSIMP_BUILD_NO_GLTF_IMPORTER) && !defined(ASSIMP_BUILD_NO_GLTF1_IMPORTER) +#include "glTFCommon.h" #include - -#include -#include -#include -#include #include +#include +#include #include +#include +#include + +// clang-format off #if (__GNUC__ == 8 && __GNUC_MINOR__ >= 0) #pragma GCC diagnostic push @@ -99,198 +101,205 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # endif #endif +// clang-format on + #include "AssetLib/glTF/glTFCommon.h" namespace glTF { - using glTFCommon::shared_ptr; - using glTFCommon::IOSystem; - using glTFCommon::IOStream; - using rapidjson::Value; - using rapidjson::Document; +using glTFCommon::IOStream; +using glTFCommon::IOSystem; +using glTFCommon::Nullable; +using glTFCommon::Ref; +using glTFCommon::shared_ptr; - class Asset; - class AssetWriter; +using rapidjson::Document; +using rapidjson::Value; - struct BufferView; // here due to cross-reference - struct Texture; - struct Light; - struct Skin; +class Asset; +class AssetWriter; - using glTFCommon::vec3; - using glTFCommon::vec4; - using glTFCommon::mat4; +struct BufferView; // here due to cross-reference +struct Texture; +struct Light; +struct Skin; - //! Magic number for GLB files - #define AI_GLB_MAGIC_NUMBER "glTF" +using glTFCommon::mat4; +using glTFCommon::vec3; +using glTFCommon::vec4; - #ifdef ASSIMP_API - #include - #endif +//! Magic number for GLB files +#define AI_GLB_MAGIC_NUMBER "glTF" - //! For the KHR_binary_glTF extension (binary .glb file) - //! 20-byte header (+ the JSON + a "body" data section) - struct GLB_Header { - uint8_t magic[4]; //!< Magic number: "glTF" - uint32_t version; //!< Version number (always 1 as of the last update) - uint32_t length; //!< Total length of the Binary glTF, including header, scene, and body, in bytes - uint32_t sceneLength; //!< Length, in bytes, of the glTF scene - uint32_t sceneFormat; //!< Specifies the format of the glTF scene (see the SceneFormat enum) - } PACK_STRUCT; +// clang-format off +#ifdef ASSIMP_API +# include +#endif +// clang-format on - #ifdef ASSIMP_API - #include - #endif +//! For the KHR_binary_glTF extension (binary .glb file) +//! 20-byte header (+ the JSON + a "body" data section) +struct GLB_Header { + uint8_t magic[4]; //!< Magic number: "glTF" + uint32_t version; //!< Version number (always 1 as of the last update) + uint32_t length; //!< Total length of the Binary glTF, including header, scene, and body, in bytes + uint32_t sceneLength; //!< Length, in bytes, of the glTF scene + uint32_t sceneFormat; //!< Specifies the format of the glTF scene (see the SceneFormat enum) +} PACK_STRUCT; +// clang-format off +#ifdef ASSIMP_API +# include +#endif +// clang-format on - //! Values for the GLB_Header::sceneFormat field - enum SceneFormat { - SceneFormat_JSON = 0 +//! Values for the GLB_Header::sceneFormat field +enum SceneFormat { + SceneFormat_JSON = 0 +}; + +//! Values for the mesh primitive modes +enum PrimitiveMode { + PrimitiveMode_POINTS = 0, + PrimitiveMode_LINES = 1, + PrimitiveMode_LINE_LOOP = 2, + PrimitiveMode_LINE_STRIP = 3, + PrimitiveMode_TRIANGLES = 4, + PrimitiveMode_TRIANGLE_STRIP = 5, + PrimitiveMode_TRIANGLE_FAN = 6 +}; + +//! Values for the Accessor::componentType field +enum ComponentType { + ComponentType_BYTE = 5120, + ComponentType_UNSIGNED_BYTE = 5121, + ComponentType_SHORT = 5122, + ComponentType_UNSIGNED_SHORT = 5123, + ComponentType_UNSIGNED_INT = 5125, + ComponentType_FLOAT = 5126 +}; + +inline unsigned int ComponentTypeSize(ComponentType t) { + switch (t) { + case ComponentType_SHORT: + case ComponentType_UNSIGNED_SHORT: + return 2; + + case ComponentType_UNSIGNED_INT: + case ComponentType_FLOAT: + return 4; + + case ComponentType_BYTE: + case ComponentType_UNSIGNED_BYTE: + return 1; + default: + std::string err = "GLTF: Unsupported Component Type "; + err += std::to_string(t); + throw DeadlyImportError(err); + } +} + +//! Values for the BufferView::target field +enum BufferViewTarget { + BufferViewTarget_NONE = 0, + BufferViewTarget_ARRAY_BUFFER = 34962, + BufferViewTarget_ELEMENT_ARRAY_BUFFER = 34963 +}; + +//! Values for the Sampler::magFilter field +enum SamplerMagFilter { + SamplerMagFilter_Nearest = 9728, + SamplerMagFilter_Linear = 9729 +}; + +//! Values for the Sampler::minFilter field +enum SamplerMinFilter { + SamplerMinFilter_Nearest = 9728, + SamplerMinFilter_Linear = 9729, + SamplerMinFilter_Nearest_Mipmap_Nearest = 9984, + SamplerMinFilter_Linear_Mipmap_Nearest = 9985, + SamplerMinFilter_Nearest_Mipmap_Linear = 9986, + SamplerMinFilter_Linear_Mipmap_Linear = 9987 +}; + +//! Values for the Sampler::wrapS and Sampler::wrapT field +enum SamplerWrap { + SamplerWrap_Clamp_To_Edge = 33071, + SamplerWrap_Mirrored_Repeat = 33648, + SamplerWrap_Repeat = 10497 +}; + +//! Values for the Texture::format and Texture::internalFormat fields +enum TextureFormat { + TextureFormat_ALPHA = 6406, + TextureFormat_RGB = 6407, + TextureFormat_RGBA = 6408, + TextureFormat_LUMINANCE = 6409, + TextureFormat_LUMINANCE_ALPHA = 6410 +}; + +//! Values for the Texture::target field +enum TextureTarget { + TextureTarget_TEXTURE_2D = 3553 +}; + +//! Values for the Texture::type field +enum TextureType { + TextureType_UNSIGNED_BYTE = 5121, + TextureType_UNSIGNED_SHORT_5_6_5 = 33635, + TextureType_UNSIGNED_SHORT_4_4_4_4 = 32819, + TextureType_UNSIGNED_SHORT_5_5_5_1 = 32820 +}; + +//! Values for the Accessor::type field (helper class) +class AttribType { +public: + enum Value { SCALAR, + VEC2, + VEC3, + VEC4, + MAT2, + MAT3, + MAT4 }; + +private: + static const size_t NUM_VALUES = static_cast(MAT4) + 1; + + struct Info { + const char *name; + unsigned int numComponents; }; - //! Values for the mesh primitive modes - enum PrimitiveMode { - PrimitiveMode_POINTS = 0, - PrimitiveMode_LINES = 1, - PrimitiveMode_LINE_LOOP = 2, - PrimitiveMode_LINE_STRIP = 3, - PrimitiveMode_TRIANGLES = 4, - PrimitiveMode_TRIANGLE_STRIP = 5, - PrimitiveMode_TRIANGLE_FAN = 6 - }; + template + struct data { static const Info infos[NUM_VALUES]; }; - //! Values for the Accessor::componentType field - enum ComponentType { - ComponentType_BYTE = 5120, - ComponentType_UNSIGNED_BYTE = 5121, - ComponentType_SHORT = 5122, - ComponentType_UNSIGNED_SHORT = 5123, - ComponentType_UNSIGNED_INT = 5125, - ComponentType_FLOAT = 5126 - }; - - inline unsigned int ComponentTypeSize(ComponentType t) { - switch (t) { - case ComponentType_SHORT: - case ComponentType_UNSIGNED_SHORT: - return 2; - - case ComponentType_UNSIGNED_INT: - case ComponentType_FLOAT: - return 4; - - case ComponentType_BYTE: - case ComponentType_UNSIGNED_BYTE: - return 1; - default: - std::string err = "GLTF: Unsupported Component Type "; - err += std::to_string( t ); - throw DeadlyImportError(err); +public: + inline static Value FromString(const char *str) { + for (size_t i = 0; i < NUM_VALUES; ++i) { + if (strcmp(data<0>::infos[i].name, str) == 0) { + return static_cast(i); + } } + return SCALAR; } - //! Values for the BufferView::target field - enum BufferViewTarget { - BufferViewTarget_NONE = 0, - BufferViewTarget_ARRAY_BUFFER = 34962, - BufferViewTarget_ELEMENT_ARRAY_BUFFER = 34963 - }; - - //! Values for the Sampler::magFilter field - enum SamplerMagFilter { - SamplerMagFilter_Nearest = 9728, - SamplerMagFilter_Linear = 9729 - }; - - //! Values for the Sampler::minFilter field - enum SamplerMinFilter { - SamplerMinFilter_Nearest = 9728, - SamplerMinFilter_Linear = 9729, - SamplerMinFilter_Nearest_Mipmap_Nearest = 9984, - SamplerMinFilter_Linear_Mipmap_Nearest = 9985, - SamplerMinFilter_Nearest_Mipmap_Linear = 9986, - SamplerMinFilter_Linear_Mipmap_Linear = 9987 - }; - - //! Values for the Sampler::wrapS and Sampler::wrapT field - enum SamplerWrap { - SamplerWrap_Clamp_To_Edge = 33071, - SamplerWrap_Mirrored_Repeat = 33648, - SamplerWrap_Repeat = 10497 - }; - - //! Values for the Texture::format and Texture::internalFormat fields - enum TextureFormat - { - TextureFormat_ALPHA = 6406, - TextureFormat_RGB = 6407, - TextureFormat_RGBA = 6408, - TextureFormat_LUMINANCE = 6409, - TextureFormat_LUMINANCE_ALPHA = 6410 - }; - - //! Values for the Texture::target field - enum TextureTarget - { - TextureTarget_TEXTURE_2D = 3553 - }; - - //! Values for the Texture::type field - enum TextureType - { - TextureType_UNSIGNED_BYTE = 5121, - TextureType_UNSIGNED_SHORT_5_6_5 = 33635, - TextureType_UNSIGNED_SHORT_4_4_4_4 = 32819, - TextureType_UNSIGNED_SHORT_5_5_5_1 = 32820 - }; - - - //! Values for the Accessor::type field (helper class) - class AttribType - { - public: - enum Value - { SCALAR, VEC2, VEC3, VEC4, MAT2, MAT3, MAT4 }; - - private: - static const size_t NUM_VALUES = static_cast(MAT4)+1; - - struct Info - { const char* name; unsigned int numComponents; }; - - template struct data - { static const Info infos[NUM_VALUES]; }; - - public: - inline static Value FromString(const char* str) - { - for (size_t i = 0; i < NUM_VALUES; ++i) { - if (strcmp(data<0>::infos[i].name, str) == 0) { - return static_cast(i); - } - } - return SCALAR; - } - - inline static const char* ToString(Value type) - { - return data<0>::infos[static_cast(type)].name; - } - - inline static unsigned int GetNumComponents(Value type) - { - return data<0>::infos[static_cast(type)].numComponents; - } - }; - - // must match the order of the AttribTypeTraits::Value enum! - template const AttribType::Info - AttribType::data::infos[AttribType::NUM_VALUES] = { - { "SCALAR", 1 }, { "VEC2", 2 }, { "VEC3", 3 }, { "VEC4", 4 }, { "MAT2", 4 }, { "MAT3", 9 }, { "MAT4", 16 } - }; + inline static const char *ToString(Value type) { + return data<0>::infos[static_cast(type)].name; + } + inline static unsigned int GetNumComponents(Value type) { + return data<0>::infos[static_cast(type)].numComponents; + } +}; +// must match the order of the AttribTypeTraits::Value enum! +template +const AttribType::Info + AttribType::data::infos[AttribType::NUM_VALUES] = { + { "SCALAR", 1 }, { "VEC2", 2 }, { "VEC3", 3 }, { "VEC4", 4 }, { "MAT2", 4 }, { "MAT3", 9 }, { "MAT4", 16 } + }; +/* //! A reference to one top-level object, which is valid //! until the Asset instance is destroyed template @@ -314,834 +323,742 @@ namespace glTF { T& operator*() { return *((*vector)[index]); } - }; + };*/ - //! Helper struct to represent values that might not be present - template - struct Nullable - { - T value; - bool isPresent; +//! Base class for all glTF top-level objects +struct Object { + std::string id; //!< The globally unique ID used to reference this object + std::string name; //!< The user-defined name of this object - Nullable() : isPresent(false) {} - Nullable(T& val) : value(val), isPresent(true) {} - }; + //! Objects marked as special are not exported (used to emulate the binary body buffer) + virtual bool IsSpecial() const { return false; } + virtual ~Object() {} - //! Base class for all glTF top-level objects - struct Object - { - std::string id; //!< The globally unique ID used to reference this object - std::string name; //!< The user-defined name of this object + //! Maps special IDs to another ID, where needed. Subclasses may override it (statically) + static const char *TranslateId(Asset & /*r*/, const char *id) { return id; } +}; - //! Objects marked as special are not exported (used to emulate the binary body buffer) - virtual bool IsSpecial() const - { return false; } +// +// Classes for each glTF top-level object type +// - virtual ~Object() {} +//! A typed view into a BufferView. A BufferView contains raw binary data. +//! An accessor provides a typed view into a BufferView or a subset of a BufferView +//! similar to how WebGL's vertexAttribPointer() defines an attribute in a buffer. +struct Accessor : public Object { + Ref bufferView; //!< The ID of the bufferView. (required) + unsigned int byteOffset; //!< The offset relative to the start of the bufferView in bytes. (required) + unsigned int byteStride; //!< The stride, in bytes, between attributes referenced by this accessor. (default: 0) + ComponentType componentType; //!< The datatype of components in the attribute. (required) + unsigned int count; //!< The number of attributes referenced by this accessor. (required) + AttribType::Value type; //!< Specifies if the attribute is a scalar, vector, or matrix. (required) + std::vector max; //!< Maximum value of each component in this attribute. + std::vector min; //!< Minimum value of each component in this attribute. - //! Maps special IDs to another ID, where needed. Subclasses may override it (statically) - static const char* TranslateId(Asset& /*r*/, const char* id) - { return id; } - }; + unsigned int GetNumComponents(); + unsigned int GetBytesPerComponent(); + unsigned int GetElementSize(); - // - // Classes for each glTF top-level object type - // + inline uint8_t *GetPointer(); - //! A typed view into a BufferView. A BufferView contains raw binary data. - //! An accessor provides a typed view into a BufferView or a subset of a BufferView - //! similar to how WebGL's vertexAttribPointer() defines an attribute in a buffer. - struct Accessor : public Object - { - Ref bufferView; //!< The ID of the bufferView. (required) - unsigned int byteOffset; //!< The offset relative to the start of the bufferView in bytes. (required) - unsigned int byteStride; //!< The stride, in bytes, between attributes referenced by this accessor. (default: 0) - ComponentType componentType; //!< The datatype of components in the attribute. (required) - unsigned int count; //!< The number of attributes referenced by this accessor. (required) - AttribType::Value type; //!< Specifies if the attribute is a scalar, vector, or matrix. (required) - std::vector max; //!< Maximum value of each component in this attribute. - std::vector min; //!< Minimum value of each component in this attribute. + template + bool ExtractData(T *&outData); - unsigned int GetNumComponents(); - unsigned int GetBytesPerComponent(); - unsigned int GetElementSize(); + void WriteData(size_t count, const void *src_buffer, size_t src_stride); - inline uint8_t* GetPointer(); - - template - bool ExtractData(T*& outData); - - void WriteData(size_t count, const void* src_buffer, size_t src_stride); - - //! Helper class to iterate the data - class Indexer - { - friend struct Accessor; + //! Helper class to iterate the data + class Indexer { + friend struct Accessor; // This field is reported as not used, making it protectd is the easiest way to work around it without going to the bottom of what the problem is: // ../code/glTF2/glTF2Asset.h:392:19: error: private field 'accessor' is not used [-Werror,-Wunused-private-field] - protected: - Accessor &accessor; - - private: - uint8_t* data; - size_t elemSize, stride; - - Indexer(Accessor& acc); - - public: - - //! Accesses the i-th value as defined by the accessor - template - T GetValue(int i); - - //! Accesses the i-th value as defined by the accessor - inline unsigned int GetUInt(int i) - { - return GetValue(i); - } - - inline bool IsValid() const - { - return data != 0; - } - }; - - inline Indexer GetIndexer() - { - return Indexer(*this); - } - - Accessor() {} - void Read(Value& obj, Asset& r); - }; - - //! A buffer points to binary geometry, animation, or skins. - struct Buffer : public Object - { - /********************* Types *********************/ - public: - - enum Type - { - Type_arraybuffer, - Type_text - }; - - /// \struct SEncodedRegion - /// Descriptor of encoded region in "bufferView". - struct SEncodedRegion - { - const size_t Offset;///< Offset from begin of "bufferView" to encoded region, in bytes. - const size_t EncodedData_Length;///< Size of encoded region, in bytes. - uint8_t* const DecodedData;///< Cached encoded data. - const size_t DecodedData_Length;///< Size of decoded region, in bytes. - const std::string ID;///< ID of the region. - - /// \fn SEncodedRegion(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string pID) - /// Constructor. - /// \param [in] pOffset - offset from begin of "bufferView" to encoded region, in bytes. - /// \param [in] pEncodedData_Length - size of encoded region, in bytes. - /// \param [in] pDecodedData - pointer to decoded data array. - /// \param [in] pDecodedData_Length - size of encoded region, in bytes. - /// \param [in] pID - ID of the region. - SEncodedRegion(const size_t pOffset, const size_t pEncodedData_Length, uint8_t *pDecodedData, const size_t pDecodedData_Length, const std::string &pID) : - Offset(pOffset), EncodedData_Length(pEncodedData_Length), DecodedData(pDecodedData), DecodedData_Length(pDecodedData_Length), ID(pID) {} - - /// \fn ~SEncodedRegion() - /// Destructor. - ~SEncodedRegion() { delete [] DecodedData; } - }; - - /******************* Variables *******************/ - - //std::string uri; //!< The uri of the buffer. Can be a filepath, a data uri, etc. (required) - size_t byteLength; //!< The length of the buffer in bytes. (default: 0) - //std::string type; //!< XMLHttpRequest responseType (default: "arraybuffer") - - Type type; - - /// \var EncodedRegion_Current - /// Pointer to currently active encoded region. - /// Why not decoding all regions at once and not to set one buffer with decoded data? - /// Yes, why not? Even "accessor" point to decoded data. I mean that fields "byteOffset", "byteStride" and "count" has values which describes decoded - /// data array. But only in range of mesh while is active parameters from "compressedData". For another mesh accessors point to decoded data too. But - /// offset is counted for another regions is encoded. - /// Example. You have two meshes. For every of it you have 4 bytes of data. That data compressed to 2 bytes. So, you have buffer with encoded data: - /// M1_E0, M1_E1, M2_E0, M2_E1. - /// After decoding you'll get: - /// M1_D0, M1_D1, M1_D2, M1_D3, M2_D0, M2_D1, M2_D2, M2_D3. - /// "accessors" must to use values that point to decoded data - obviously. So, you'll expect "accessors" like - /// "accessor_0" : { byteOffset: 0, byteLength: 4}, "accessor_1" : { byteOffset: 4, byteLength: 4} - /// but in real life you'll get: - /// "accessor_0" : { byteOffset: 0, byteLength: 4}, "accessor_1" : { byteOffset: 2, byteLength: 4} - /// Yes, accessor of next mesh has offset and length which mean: current mesh data is decoded, all other data is encoded. - /// And when before you start to read data of current mesh (with encoded data ofcourse) you must decode region of "bufferView", after read finished - /// delete encoding mark. And after that you can repeat process: decode data of mesh, read, delete decoded data. - /// - /// Remark. Encoding all data at once is good in world with computers which do not has RAM limitation. So, you must use step by step encoding in - /// exporter and importer. And, thanks to such way, there is no need to load whole file into memory. - SEncodedRegion* EncodedRegion_Current; - - private: - - shared_ptr mData; //!< Pointer to the data - bool mIsSpecial; //!< Set to true for special cases (e.g. the body buffer) - size_t capacity = 0; //!< The capacity of the buffer in bytes. (default: 0) - /// \var EncodedRegion_List - /// List of encoded regions. - std::list EncodedRegion_List; - - /******************* Functions *******************/ - - public: - - Buffer(); - ~Buffer(); - - void Read(Value& obj, Asset& r); - - bool LoadFromStream(IOStream& stream, size_t length = 0, size_t baseOffset = 0); - - /// \fn void EncodedRegion_Mark(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string& pID) - /// Mark region of "bufferView" as encoded. When data is request from such region then "bufferView" use decoded data. - /// \param [in] pOffset - offset from begin of "bufferView" to encoded region, in bytes. - /// \param [in] pEncodedData_Length - size of encoded region, in bytes. - /// \param [in] pDecodedData - pointer to decoded data array. - /// \param [in] pDecodedData_Length - size of encoded region, in bytes. - /// \param [in] pID - ID of the region. - void EncodedRegion_Mark(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string& pID); - - /// \fn void EncodedRegion_SetCurrent(const std::string& pID) - /// Select current encoded region by ID. \sa EncodedRegion_Current. - /// \param [in] pID - ID of the region. - void EncodedRegion_SetCurrent(const std::string& pID); - - /// \fn bool ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t* pReplace_Data, const size_t pReplace_Count) - /// Replace part of buffer data. Pay attention that function work with original array of data (\ref mData) not with encoded regions. - /// \param [in] pBufferData_Offset - index of first element in buffer from which new data will be placed. - /// \param [in] pBufferData_Count - count of bytes in buffer which will be replaced. - /// \param [in] pReplace_Data - pointer to array with new data for buffer. - /// \param [in] pReplace_Count - count of bytes in new data. - /// \return true - if successfully replaced, false if input arguments is out of range. - bool ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t* pReplace_Data, const size_t pReplace_Count); - - size_t AppendData(uint8_t* data, size_t length); - void Grow(size_t amount); - - uint8_t* GetPointer() - { return mData.get(); } - - void MarkAsSpecial() - { mIsSpecial = true; } - - bool IsSpecial() const - { return mIsSpecial; } - - std::string GetURI() - { return std::string(this->id) + ".bin"; } - - static const char* TranslateId(Asset& r, const char* id); - }; - - //! A view into a buffer generally representing a subset of the buffer. - struct BufferView : public Object - { - Ref buffer; //! The ID of the buffer. (required) - size_t byteOffset; //! The offset into the buffer in bytes. (required) - size_t byteLength; //! The length of the bufferView in bytes. (default: 0) - - BufferViewTarget target; //! The target that the WebGL buffer should be bound to. - - void Read(Value& obj, Asset& r); - }; - - struct Camera : public Object - { - enum Type - { - Perspective, - Orthographic - }; - - Type type; - - union - { - struct { - float aspectRatio; //! bufferView; - - std::string mimeType; - - int width, height; + protected: + Accessor &accessor; private: - std::unique_ptr mData; - size_t mDataLength; + uint8_t *data; + size_t elemSize, stride; + + Indexer(Accessor &acc); public: + //! Accesses the i-th value as defined by the accessor + template + T GetValue(int i); - Image(); - void Read(Value& obj, Asset& r); + //! Accesses the i-th value as defined by the accessor + inline unsigned int GetUInt(int i) { + return GetValue(i); + } - inline bool HasData() const - { return mDataLength > 0; } - - inline size_t GetDataLength() const - { return mDataLength; } - - inline const uint8_t* GetData() const - { return mData.get(); } - - inline uint8_t* StealData(); - - inline void SetData(uint8_t* data, size_t length, Asset& r); + inline bool IsValid() const { + return data != 0; + } }; - //! Holds a material property that can be a texture or a color - struct TexProperty - { - Ref texture; - vec4 color; + inline Indexer GetIndexer() { + return Indexer(*this); + } + + Accessor() {} + void Read(Value &obj, Asset &r); +}; + +//! A buffer points to binary geometry, animation, or skins. +struct Buffer : public Object { + /********************* Types *********************/ +public: + enum Type { + Type_arraybuffer, + Type_text }; - //! The material appearance of a primitive. - struct Material : public Object - { - //Ref source; //!< The ID of the technique. - //std::gltf_unordered_map values; //!< A dictionary object of parameter values. + /// \struct SEncodedRegion + /// Descriptor of encoded region in "bufferView". + struct SEncodedRegion { + const size_t Offset; ///< Offset from begin of "bufferView" to encoded region, in bytes. + const size_t EncodedData_Length; ///< Size of encoded region, in bytes. + uint8_t *const DecodedData; ///< Cached encoded data. + const size_t DecodedData_Length; ///< Size of decoded region, in bytes. + const std::string ID; ///< ID of the region. - //! Techniques defined by KHR_materials_common - enum Technique - { - Technique_undefined = 0, - Technique_BLINN, - Technique_PHONG, - Technique_LAMBERT, - Technique_CONSTANT - }; + /// \fn SEncodedRegion(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string pID) + /// Constructor. + /// \param [in] pOffset - offset from begin of "bufferView" to encoded region, in bytes. + /// \param [in] pEncodedData_Length - size of encoded region, in bytes. + /// \param [in] pDecodedData - pointer to decoded data array. + /// \param [in] pDecodedData_Length - size of encoded region, in bytes. + /// \param [in] pID - ID of the region. + SEncodedRegion(const size_t pOffset, const size_t pEncodedData_Length, uint8_t *pDecodedData, const size_t pDecodedData_Length, const std::string &pID) : + Offset(pOffset), EncodedData_Length(pEncodedData_Length), DecodedData(pDecodedData), DecodedData_Length(pDecodedData_Length), ID(pID) {} - TexProperty ambient; - TexProperty diffuse; - TexProperty specular; - TexProperty emission; - - bool doubleSided; - bool transparent; - float transparency; - float shininess; - - Technique technique; - - Material() { SetDefaults(); } - void Read(Value& obj, Asset& r); - void SetDefaults(); + /// \fn ~SEncodedRegion() + /// Destructor. + ~SEncodedRegion() { delete[] DecodedData; } }; - //! A set of primitives to be rendered. A node can contain one or more meshes. A node's transform places the mesh in the scene. - struct Mesh : public Object - { - typedef std::vector< Ref > AccessorList; + /******************* Variables *******************/ - struct Primitive - { - PrimitiveMode mode; + //std::string uri; //!< The uri of the buffer. Can be a filepath, a data uri, etc. (required) + size_t byteLength; //!< The length of the buffer in bytes. (default: 0) + //std::string type; //!< XMLHttpRequest responseType (default: "arraybuffer") - struct Attributes { - AccessorList position, normal, texcoord, color, joint, jointmatrix, weight; - } attributes; + Type type; - Ref indices; + /// \var EncodedRegion_Current + /// Pointer to currently active encoded region. + /// Why not decoding all regions at once and not to set one buffer with decoded data? + /// Yes, why not? Even "accessor" point to decoded data. I mean that fields "byteOffset", "byteStride" and "count" has values which describes decoded + /// data array. But only in range of mesh while is active parameters from "compressedData". For another mesh accessors point to decoded data too. But + /// offset is counted for another regions is encoded. + /// Example. You have two meshes. For every of it you have 4 bytes of data. That data compressed to 2 bytes. So, you have buffer with encoded data: + /// M1_E0, M1_E1, M2_E0, M2_E1. + /// After decoding you'll get: + /// M1_D0, M1_D1, M1_D2, M1_D3, M2_D0, M2_D1, M2_D2, M2_D3. + /// "accessors" must to use values that point to decoded data - obviously. So, you'll expect "accessors" like + /// "accessor_0" : { byteOffset: 0, byteLength: 4}, "accessor_1" : { byteOffset: 4, byteLength: 4} + /// but in real life you'll get: + /// "accessor_0" : { byteOffset: 0, byteLength: 4}, "accessor_1" : { byteOffset: 2, byteLength: 4} + /// Yes, accessor of next mesh has offset and length which mean: current mesh data is decoded, all other data is encoded. + /// And when before you start to read data of current mesh (with encoded data ofcourse) you must decode region of "bufferView", after read finished + /// delete encoding mark. And after that you can repeat process: decode data of mesh, read, delete decoded data. + /// + /// Remark. Encoding all data at once is good in world with computers which do not has RAM limitation. So, you must use step by step encoding in + /// exporter and importer. And, thanks to such way, there is no need to load whole file into memory. + SEncodedRegion *EncodedRegion_Current; - Ref material; - }; +private: + shared_ptr mData; //!< Pointer to the data + bool mIsSpecial; //!< Set to true for special cases (e.g. the body buffer) + size_t capacity = 0; //!< The capacity of the buffer in bytes. (default: 0) + /// \var EncodedRegion_List + /// List of encoded regions. + std::list EncodedRegion_List; - /// \struct SExtension - /// Extension used for mesh. - struct SExtension - { - /// \enum EType - /// Type of extension. - enum EType - { - #ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC - Compression_Open3DGC,///< Compression of mesh data using Open3DGC algorithm. - #endif + /******************* Functions *******************/ - Unknown - }; +public: + Buffer(); + ~Buffer(); - EType Type;///< Type of extension. + void Read(Value &obj, Asset &r); - /// \fn SExtension - /// Constructor. - /// \param [in] pType - type of extension. - SExtension(const EType pType) - : Type(pType) - {} + bool LoadFromStream(IOStream &stream, size_t length = 0, size_t baseOffset = 0); - virtual ~SExtension() { - // empty - } - }; + /// \fn void EncodedRegion_Mark(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string& pID) + /// Mark region of "bufferView" as encoded. When data is request from such region then "bufferView" use decoded data. + /// \param [in] pOffset - offset from begin of "bufferView" to encoded region, in bytes. + /// \param [in] pEncodedData_Length - size of encoded region, in bytes. + /// \param [in] pDecodedData - pointer to decoded data array. + /// \param [in] pDecodedData_Length - size of encoded region, in bytes. + /// \param [in] pID - ID of the region. + void EncodedRegion_Mark(const size_t pOffset, const size_t pEncodedData_Length, uint8_t *pDecodedData, const size_t pDecodedData_Length, const std::string &pID); - #ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC - /// \struct SCompression_Open3DGC - /// Compression of mesh data using Open3DGC algorithm. - struct SCompression_Open3DGC : public SExtension - { - using SExtension::Type; + /// \fn void EncodedRegion_SetCurrent(const std::string& pID) + /// Select current encoded region by ID. \sa EncodedRegion_Current. + /// \param [in] pID - ID of the region. + void EncodedRegion_SetCurrent(const std::string &pID); - std::string Buffer;///< ID of "buffer" used for storing compressed data. - size_t Offset;///< Offset in "bufferView" where compressed data are stored. - size_t Count;///< Count of elements in compressed data. Is always equivalent to size in bytes: look comments for "Type" and "Component_Type". - bool Binary;///< If true then "binary" mode is used for coding, if false - "ascii" mode. - size_t IndicesCount;///< Count of indices in mesh. - size_t VerticesCount;///< Count of vertices in mesh. - // AttribType::Value Type;///< Is always "SCALAR". - // ComponentType Component_Type;///< Is always "ComponentType_UNSIGNED_BYTE" (5121). + /// \fn bool ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t* pReplace_Data, const size_t pReplace_Count) + /// Replace part of buffer data. Pay attention that function work with original array of data (\ref mData) not with encoded regions. + /// \param [in] pBufferData_Offset - index of first element in buffer from which new data will be placed. + /// \param [in] pBufferData_Count - count of bytes in buffer which will be replaced. + /// \param [in] pReplace_Data - pointer to array with new data for buffer. + /// \param [in] pReplace_Count - count of bytes in new data. + /// \return true - if successfully replaced, false if input arguments is out of range. + bool ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t *pReplace_Data, const size_t pReplace_Count); - /// \fn SCompression_Open3DGC - /// Constructor. - SCompression_Open3DGC() - : SExtension(Compression_Open3DGC) { - // empty - } + size_t AppendData(uint8_t *data, size_t length); + void Grow(size_t amount); - virtual ~SCompression_Open3DGC() { - // empty - } - }; - #endif + uint8_t *GetPointer() { return mData.get(); } - std::vector primitives; - std::list Extension;///< List of extensions used in mesh. + void MarkAsSpecial() { mIsSpecial = true; } - Mesh() {} + bool IsSpecial() const { return mIsSpecial; } - /// \fn ~Mesh() - /// Destructor. - ~Mesh() { for(std::list::iterator it = Extension.begin(), it_end = Extension.end(); it != it_end; it++) { delete *it; }; } + std::string GetURI() { return std::string(this->id) + ".bin"; } - /// \fn void Read(Value& pJSON_Object, Asset& pAsset_Root) - /// Get mesh data from JSON-object and place them to root asset. - /// \param [in] pJSON_Object - reference to pJSON-object from which data are read. - /// \param [out] pAsset_Root - reference to root asset where data will be stored. - void Read(Value& pJSON_Object, Asset& pAsset_Root); + static const char *TranslateId(Asset &r, const char *id); +}; - #ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC - /// \fn void Decode_O3DGC(const SCompression_Open3DGC& pCompression_Open3DGC, Asset& pAsset_Root) - /// Decode part of "buffer" which encoded with Open3DGC algorithm. - /// \param [in] pCompression_Open3DGC - reference to structure which describe encoded region. - /// \param [out] pAsset_Root - reference to root assed where data will be stored. - void Decode_O3DGC(const SCompression_Open3DGC& pCompression_Open3DGC, Asset& pAsset_Root); - #endif +//! A view into a buffer generally representing a subset of the buffer. +struct BufferView : public Object { + Ref buffer; //! The ID of the buffer. (required) + size_t byteOffset; //! The offset into the buffer in bytes. (required) + size_t byteLength; //! The length of the bufferView in bytes. (default: 0) + + BufferViewTarget target; //! The target that the WebGL buffer should be bound to. + + void Read(Value &obj, Asset &r); +}; + +struct Camera : public Object { + enum Type { + Perspective, + Orthographic }; - struct Node : public Object - { - std::vector< Ref > children; - std::vector< Ref > meshes; + Type type; - Nullable matrix; - Nullable translation; - Nullable rotation; - Nullable scale; - - Ref camera; - Ref light; - - std::vector< Ref > skeletons; //!< The ID of skeleton nodes. Each of which is the root of a node hierarchy. - Ref skin; //!< The ID of the skin referenced by this node. - std::string jointName; //!< Name used when this node is a joint in a skin. - - Ref parent; //!< This is not part of the glTF specification. Used as a helper. - - Node() {} - void Read(Value& obj, Asset& r); - }; - - struct Program : public Object - { - Program() {} - void Read(Value& obj, Asset& r); - }; - - - struct Sampler : public Object - { - SamplerMagFilter magFilter; //!< The texture magnification filter. (required) - SamplerMinFilter minFilter; //!< The texture minification filter. (required) - SamplerWrap wrapS; //!< The texture wrapping in the S direction. (required) - SamplerWrap wrapT; //!< The texture wrapping in the T direction. (required) - - Sampler() {} - void Read(Value& obj, Asset& r); - void SetDefaults(); - }; - - struct Scene : public Object - { - std::vector< Ref > nodes; - - Scene() {} - void Read(Value& obj, Asset& r); - }; - - struct Shader : public Object - { - Shader() {} - void Read(Value& obj, Asset& r); - }; - - struct Skin : public Object - { - Nullable bindShapeMatrix; //!< Floating-point 4x4 transformation matrix stored in column-major order. - Ref inverseBindMatrices; //!< The ID of the accessor containing the floating-point 4x4 inverse-bind matrices. - std::vector> jointNames; //!< Joint names of the joints (nodes with a jointName property) in this skin. - std::string name; //!< The user-defined name of this object. - - Skin() {} - void Read(Value& obj, Asset& r); - }; - - struct Technique : public Object - { - struct Parameters - { - - }; - - struct States - { - - }; - - struct Functions - { - - }; - - Technique() {} - void Read(Value& obj, Asset& r); - }; - - //! A texture and its sampler. - struct Texture : public Object - { - Ref sampler; //!< The ID of the sampler used by this texture. (required) - Ref source; //!< The ID of the image used by this texture. (required) - - //TextureFormat format; //!< The texture's format. (default: TextureFormat_RGBA) - //TextureFormat internalFormat; //!< The texture's internal format. (default: TextureFormat_RGBA) - - //TextureTarget target; //!< The target that the WebGL texture should be bound to. (default: TextureTarget_TEXTURE_2D) - //TextureType type; //!< Texel datatype. (default: TextureType_UNSIGNED_BYTE) - - Texture() {} - void Read(Value& obj, Asset& r); - }; - - - //! A light (from KHR_materials_common extension) - struct Light : public Object - { - enum Type - { - Type_undefined, - Type_ambient, - Type_directional, - Type_point, - Type_spot - }; - - Type type; - - vec4 color; - float distance; - float constantAttenuation; - float linearAttenuation; - float quadraticAttenuation; - float falloffAngle; - float falloffExponent; - - Light() {} - void Read(Value& obj, Asset& r); - - void SetDefaults(); - }; - - struct Animation : public Object - { - struct AnimSampler { - std::string id; //!< The ID of this sampler. - std::string input; //!< The ID of a parameter in this animation to use as key-frame input. - std::string interpolation; //!< Type of interpolation algorithm to use between key-frames. - std::string output; //!< The ID of a parameter in this animation to use as key-frame output. - }; - - struct AnimChannel { - std::string sampler; //!< The ID of one sampler present in the containing animation's samplers property. - - struct AnimTarget { - Ref id; //!< The ID of the node to animate. - std::string path; //!< The name of property of the node to animate ("translation", "rotation", or "scale"). - } target; - }; - - struct AnimParameters { - Ref TIME; //!< Accessor reference to a buffer storing a array of floating point scalar values. - Ref rotation; //!< Accessor reference to a buffer storing a array of four-component floating-point vectors. - Ref scale; //!< Accessor reference to a buffer storing a array of three-component floating-point vectors. - Ref translation; //!< Accessor reference to a buffer storing a array of three-component floating-point vectors. - }; - - // AnimChannel Channels[3]; //!< Connect the output values of the key-frame animation to a specific node in the hierarchy. - // AnimParameters Parameters; //!< The samplers that interpolate between the key-frames. - // AnimSampler Samplers[3]; //!< The parameterized inputs representing the key-frame data. - - std::vector Channels; //!< Connect the output values of the key-frame animation to a specific node in the hierarchy. - AnimParameters Parameters; //!< The samplers that interpolate between the key-frames. - std::vector Samplers; //!< The parameterized inputs representing the key-frame data. - - Animation() {} - void Read(Value& obj, Asset& r); - }; - - - //! Base class for LazyDict that acts as an interface - class LazyDictBase - { - public: - virtual ~LazyDictBase() {} - - virtual void AttachToDocument(Document& doc) = 0; - virtual void DetachFromDocument() = 0; - -#if !defined(ASSIMP_BUILD_NO_EXPORT) - virtual void WriteObjects(AssetWriter& writer) = 0; -#endif - }; - - - template - class LazyDict; - - //! (Implemented in glTFAssetWriter.h) - template - void WriteLazyDict(LazyDict& d, AssetWriter& w); - - - //! Manages lazy loading of the glTF top-level objects, and keeps a reference to them by ID - //! It is the owner the loaded objects, so when it is destroyed it also deletes them - template - class LazyDict : public LazyDictBase - { - friend class Asset; - friend class AssetWriter; - - typedef typename std::gltf_unordered_map< std::string, unsigned int > Dict; - - std::vector mObjs; //! The read objects - Dict mObjsById; //! The read objects accessible by id - const char* mDictId; //! ID of the dictionary object - const char* mExtId; //! ID of the extension defining the dictionary - Value* mDict; //! JSON dictionary object - Asset& mAsset; //! The asset instance - - void AttachToDocument(Document& doc); - void DetachFromDocument(); - -#if !defined(ASSIMP_BUILD_NO_EXPORT) - void WriteObjects(AssetWriter& writer) - { WriteLazyDict(*this, writer); } -#endif - - Ref Add(T* obj); - - public: - LazyDict(Asset& asset, const char* dictId, const char* extId = 0); - ~LazyDict(); - - Ref Get(const char* id); - Ref Get(unsigned int i); - Ref Get(const std::string& pID) { return Get(pID.c_str()); } - - Ref Create(const char* id); - Ref Create(const std::string& id) - { return Create(id.c_str()); } - - inline unsigned int Size() const - { return unsigned(mObjs.size()); } - - inline T& operator[](size_t i) - { return *mObjs[i]; } - - }; - - - struct AssetMetadata - { - std::string copyright; //!< A copyright message suitable for display to credit the content creator. - std::string generator; //!< Tool that generated this glTF model.Useful for debugging. - bool premultipliedAlpha; //!< Specifies if the shaders were generated with premultiplied alpha. (default: false) + union { + struct { + float aspectRatio; //! bufferView; + + std::string mimeType; + + int width, height; + +private: + std::unique_ptr mData; + size_t mDataLength; + +public: + Image(); + void Read(Value &obj, Asset &r); + + inline bool HasData() const { return mDataLength > 0; } + + inline size_t GetDataLength() const { return mDataLength; } + + inline const uint8_t *GetData() const { return mData.get(); } + + inline uint8_t *StealData(); + + inline void SetData(uint8_t *data, size_t length, Asset &r); +}; + +//! Holds a material property that can be a texture or a color +struct TexProperty { + Ref texture; + vec4 color; +}; + +//! The material appearance of a primitive. +struct Material : public Object { + //Ref source; //!< The ID of the technique. + //std::gltf_unordered_map values; //!< A dictionary object of parameter values. + + //! Techniques defined by KHR_materials_common + enum Technique { + Technique_undefined = 0, + Technique_BLINN, + Technique_PHONG, + Technique_LAMBERT, + Technique_CONSTANT + }; + + TexProperty ambient; + TexProperty diffuse; + TexProperty specular; + TexProperty emission; + + bool doubleSided; + bool transparent; + float transparency; + float shininess; + + Technique technique; + + Material() { SetDefaults(); } + void Read(Value &obj, Asset &r); + void SetDefaults(); +}; + +//! A set of primitives to be rendered. A node can contain one or more meshes. A node's transform places the mesh in the scene. +struct Mesh : public Object { + typedef std::vector> AccessorList; + + struct Primitive { + PrimitiveMode mode; + + struct Attributes { + AccessorList position, normal, texcoord, color, joint, jointmatrix, weight; + } attributes; + + Ref indices; + + Ref material; + }; + + /// \struct SExtension + /// Extension used for mesh. + struct SExtension { + /// \enum EType + /// Type of extension. + enum EType { +#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC + Compression_Open3DGC, ///< Compression of mesh data using Open3DGC algorithm. +#endif + + Unknown + }; + + EType Type; ///< Type of extension. + + /// \fn SExtension + /// Constructor. + /// \param [in] pType - type of extension. + SExtension(const EType pType) : + Type(pType) {} + + virtual ~SExtension() { + // empty } }; - // - // glTF Asset class - // +#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC + /// \struct SCompression_Open3DGC + /// Compression of mesh data using Open3DGC algorithm. + struct SCompression_Open3DGC : public SExtension { + using SExtension::Type; - //! Root object for a glTF asset - class Asset - { - typedef std::gltf_unordered_map IdMap; + std::string Buffer; ///< ID of "buffer" used for storing compressed data. + size_t Offset; ///< Offset in "bufferView" where compressed data are stored. + size_t Count; ///< Count of elements in compressed data. Is always equivalent to size in bytes: look comments for "Type" and "Component_Type". + bool Binary; ///< If true then "binary" mode is used for coding, if false - "ascii" mode. + size_t IndicesCount; ///< Count of indices in mesh. + size_t VerticesCount; ///< Count of vertices in mesh. + // AttribType::Value Type;///< Is always "SCALAR". + // ComponentType Component_Type;///< Is always "ComponentType_UNSIGNED_BYTE" (5121). - template - friend class LazyDict; + /// \fn SCompression_Open3DGC + /// Constructor. + SCompression_Open3DGC() : + SExtension(Compression_Open3DGC) { + // empty + } - friend struct Buffer; // To access OpenFile + virtual ~SCompression_Open3DGC() { + // empty + } + }; +#endif - friend class AssetWriter; + std::vector primitives; + std::list Extension; ///< List of extensions used in mesh. - private: - IOSystem* mIOSystem; + Mesh() {} - std::string mCurrentAssetDir; + /// \fn ~Mesh() + /// Destructor. + ~Mesh() { + for (std::list::iterator it = Extension.begin(), it_end = Extension.end(); it != it_end; it++) { + delete *it; + }; + } - size_t mSceneLength; - size_t mBodyOffset, mBodyLength; + /// \fn void Read(Value& pJSON_Object, Asset& pAsset_Root) + /// Get mesh data from JSON-object and place them to root asset. + /// \param [in] pJSON_Object - reference to pJSON-object from which data are read. + /// \param [out] pAsset_Root - reference to root asset where data will be stored. + void Read(Value &pJSON_Object, Asset &pAsset_Root); - std::vector mDicts; +#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC + /// \fn void Decode_O3DGC(const SCompression_Open3DGC& pCompression_Open3DGC, Asset& pAsset_Root) + /// Decode part of "buffer" which encoded with Open3DGC algorithm. + /// \param [in] pCompression_Open3DGC - reference to structure which describe encoded region. + /// \param [out] pAsset_Root - reference to root assed where data will be stored. + void Decode_O3DGC(const SCompression_Open3DGC &pCompression_Open3DGC, Asset &pAsset_Root); +#endif +}; - IdMap mUsedIds; +struct Node : public Object { + std::vector> children; + std::vector> meshes; - Ref mBodyBuffer; + Nullable matrix; + Nullable translation; + Nullable rotation; + Nullable scale; - Asset(Asset&); - Asset& operator=(const Asset&); + Ref camera; + Ref light; - public: + std::vector> skeletons; //!< The ID of skeleton nodes. Each of which is the root of a node hierarchy. + Ref skin; //!< The ID of the skin referenced by this node. + std::string jointName; //!< Name used when this node is a joint in a skin. - //! Keeps info about the enabled extensions - struct Extensions - { - bool KHR_binary_glTF; - bool KHR_materials_common; + Ref parent; //!< This is not part of the glTF specification. Used as a helper. - } extensionsUsed; + Node() {} + void Read(Value &obj, Asset &r); +}; - AssetMetadata asset; +struct Program : public Object { + Program() {} + void Read(Value &obj, Asset &r); +}; +struct Sampler : public Object { + SamplerMagFilter magFilter; //!< The texture magnification filter. (required) + SamplerMinFilter minFilter; //!< The texture minification filter. (required) + SamplerWrap wrapS; //!< The texture wrapping in the S direction. (required) + SamplerWrap wrapT; //!< The texture wrapping in the T direction. (required) - // Dictionaries for each type of object + Sampler() {} + void Read(Value &obj, Asset &r); + void SetDefaults(); +}; - LazyDict accessors; - LazyDict animations; - LazyDict buffers; - LazyDict bufferViews; - LazyDict cameras; - LazyDict images; - LazyDict materials; - LazyDict meshes; - LazyDict nodes; - //LazyDict programs; - LazyDict samplers; - LazyDict scenes; - //LazyDict shaders; - LazyDict skins; - //LazyDict techniques; - LazyDict textures; +struct Scene : public Object { + std::vector> nodes; - LazyDict lights; // KHR_materials_common ext + Scene() {} + void Read(Value &obj, Asset &r); +}; - Ref scene; +struct Shader : public Object { + Shader() {} + void Read(Value &obj, Asset &r); +}; - public: - Asset(IOSystem* io = 0) - : mIOSystem(io) - , asset() - , accessors (*this, "accessors") - , animations (*this, "animations") - , buffers (*this, "buffers") - , bufferViews (*this, "bufferViews") - , cameras (*this, "cameras") - , images (*this, "images") - , materials (*this, "materials") - , meshes (*this, "meshes") - , nodes (*this, "nodes") +struct Skin : public Object { + Nullable bindShapeMatrix; //!< Floating-point 4x4 transformation matrix stored in column-major order. + Ref inverseBindMatrices; //!< The ID of the accessor containing the floating-point 4x4 inverse-bind matrices. + std::vector> jointNames; //!< Joint names of the joints (nodes with a jointName property) in this skin. + std::string name; //!< The user-defined name of this object. + + Skin() {} + void Read(Value &obj, Asset &r); +}; + +struct Technique : public Object { + struct Parameters { + }; + + struct States { + }; + + struct Functions { + }; + + Technique() {} + void Read(Value &obj, Asset &r); +}; + +//! A texture and its sampler. +struct Texture : public Object { + Ref sampler; //!< The ID of the sampler used by this texture. (required) + Ref source; //!< The ID of the image used by this texture. (required) + + //TextureFormat format; //!< The texture's format. (default: TextureFormat_RGBA) + //TextureFormat internalFormat; //!< The texture's internal format. (default: TextureFormat_RGBA) + + //TextureTarget target; //!< The target that the WebGL texture should be bound to. (default: TextureTarget_TEXTURE_2D) + //TextureType type; //!< Texel datatype. (default: TextureType_UNSIGNED_BYTE) + + Texture() {} + void Read(Value &obj, Asset &r); +}; + +//! A light (from KHR_materials_common extension) +struct Light : public Object { + enum Type { + Type_undefined, + Type_ambient, + Type_directional, + Type_point, + Type_spot + }; + + Type type; + + vec4 color; + float distance; + float constantAttenuation; + float linearAttenuation; + float quadraticAttenuation; + float falloffAngle; + float falloffExponent; + + Light() {} + void Read(Value &obj, Asset &r); + + void SetDefaults(); +}; + +struct Animation : public Object { + struct AnimSampler { + std::string id; //!< The ID of this sampler. + std::string input; //!< The ID of a parameter in this animation to use as key-frame input. + std::string interpolation; //!< Type of interpolation algorithm to use between key-frames. + std::string output; //!< The ID of a parameter in this animation to use as key-frame output. + }; + + struct AnimChannel { + std::string sampler; //!< The ID of one sampler present in the containing animation's samplers property. + + struct AnimTarget { + Ref id; //!< The ID of the node to animate. + std::string path; //!< The name of property of the node to animate ("translation", "rotation", or "scale"). + } target; + }; + + struct AnimParameters { + Ref TIME; //!< Accessor reference to a buffer storing a array of floating point scalar values. + Ref rotation; //!< Accessor reference to a buffer storing a array of four-component floating-point vectors. + Ref scale; //!< Accessor reference to a buffer storing a array of three-component floating-point vectors. + Ref translation; //!< Accessor reference to a buffer storing a array of three-component floating-point vectors. + }; + + // AnimChannel Channels[3]; //!< Connect the output values of the key-frame animation to a specific node in the hierarchy. + // AnimParameters Parameters; //!< The samplers that interpolate between the key-frames. + // AnimSampler Samplers[3]; //!< The parameterized inputs representing the key-frame data. + + std::vector Channels; //!< Connect the output values of the key-frame animation to a specific node in the hierarchy. + AnimParameters Parameters; //!< The samplers that interpolate between the key-frames. + std::vector Samplers; //!< The parameterized inputs representing the key-frame data. + + Animation() {} + void Read(Value &obj, Asset &r); +}; + +//! Base class for LazyDict that acts as an interface +class LazyDictBase { +public: + virtual ~LazyDictBase() {} + + virtual void AttachToDocument(Document &doc) = 0; + virtual void DetachFromDocument() = 0; + +#if !defined(ASSIMP_BUILD_NO_EXPORT) + virtual void WriteObjects(AssetWriter &writer) = 0; +#endif +}; + +template +class LazyDict; + +//! (Implemented in glTFAssetWriter.h) +template +void WriteLazyDict(LazyDict &d, AssetWriter &w); + +//! Manages lazy loading of the glTF top-level objects, and keeps a reference to them by ID +//! It is the owner the loaded objects, so when it is destroyed it also deletes them +template +class LazyDict : public LazyDictBase { + friend class Asset; + friend class AssetWriter; + + typedef typename std::gltf_unordered_map Dict; + + std::vector mObjs; //! The read objects + Dict mObjsById; //! The read objects accessible by id + const char *mDictId; //! ID of the dictionary object + const char *mExtId; //! ID of the extension defining the dictionary + Value *mDict; //! JSON dictionary object + Asset &mAsset; //! The asset instance + + void AttachToDocument(Document &doc); + void DetachFromDocument(); + +#if !defined(ASSIMP_BUILD_NO_EXPORT) + void WriteObjects(AssetWriter &writer) { WriteLazyDict(*this, writer); } +#endif + + Ref Add(T *obj); + +public: + LazyDict(Asset &asset, const char *dictId, const char *extId = 0); + ~LazyDict(); + + Ref Get(const char *id); + Ref Get(unsigned int i); + Ref Get(const std::string &pID) { return Get(pID.c_str()); } + + Ref Create(const char *id); + Ref Create(const std::string &id) { return Create(id.c_str()); } + + inline unsigned int Size() const { return unsigned(mObjs.size()); } + + inline T &operator[](size_t i) { return *mObjs[i]; } +}; + +struct AssetMetadata { + std::string copyright; //!< A copyright message suitable for display to credit the content creator. + std::string generator; //!< Tool that generated this glTF model.Useful for debugging. + bool premultipliedAlpha; //!< Specifies if the shaders were generated with premultiplied alpha. (default: false) + + struct { + std::string api; //!< Specifies the target rendering API (default: "WebGL") + std::string version; //!< Specifies the target rendering API (default: "1.0.3") + } profile; //!< Specifies the target rendering API and version, e.g., WebGL 1.0.3. (default: {}) + + std::string version; //!< The glTF format version (should be 1.0) + + void Read(Document &doc); + + AssetMetadata() : + premultipliedAlpha(false), version() { + } +}; + +// +// glTF Asset class +// + +//! Root object for a glTF asset +class Asset { + typedef std::gltf_unordered_map IdMap; + + template + friend class LazyDict; + + friend struct Buffer; // To access OpenFile + + friend class AssetWriter; + +private: + IOSystem *mIOSystem; + + std::string mCurrentAssetDir; + + size_t mSceneLength; + size_t mBodyOffset, mBodyLength; + + std::vector mDicts; + + IdMap mUsedIds; + + Ref mBodyBuffer; + + Asset(Asset &); + Asset &operator=(const Asset &); + +public: + //! Keeps info about the enabled extensions + struct Extensions { + bool KHR_binary_glTF; + bool KHR_materials_common; + + } extensionsUsed; + + AssetMetadata asset; + + // Dictionaries for each type of object + + LazyDict accessors; + LazyDict animations; + LazyDict buffers; + LazyDict bufferViews; + LazyDict cameras; + LazyDict images; + LazyDict materials; + LazyDict meshes; + LazyDict nodes; + //LazyDict programs; + LazyDict samplers; + LazyDict scenes; + //LazyDict shaders; + LazyDict skins; + //LazyDict techniques; + LazyDict textures; + + LazyDict lights; // KHR_materials_common ext + + Ref scene; + +public: + Asset(IOSystem *io = 0) : + mIOSystem(io), asset(), accessors(*this, "accessors"), animations(*this, "animations"), buffers(*this, "buffers"), bufferViews(*this, "bufferViews"), cameras(*this, "cameras"), images(*this, "images"), materials(*this, "materials"), meshes(*this, "meshes"), nodes(*this, "nodes") //, programs (*this, "programs") - , samplers (*this, "samplers") - , scenes (*this, "scenes") + , + samplers(*this, "samplers"), + scenes(*this, "scenes") //, shaders (*this, "shaders") - , skins (*this, "skins") + , + skins(*this, "skins") //, techniques (*this, "techniques") - , textures (*this, "textures") - , lights (*this, "lights", "KHR_materials_common") - { - memset(&extensionsUsed, 0, sizeof(extensionsUsed)); - } + , + textures(*this, "textures"), + lights(*this, "lights", "KHR_materials_common") { + memset(&extensionsUsed, 0, sizeof(extensionsUsed)); + } - //! Main function - void Load(const std::string& file, bool isBinary = false); + //! Main function + void Load(const std::string &file, bool isBinary = false); - //! Enables the "KHR_binary_glTF" extension on the asset - void SetAsBinary(); + //! Enables the "KHR_binary_glTF" extension on the asset + void SetAsBinary(); - //! Search for an available name, starting from the given strings - std::string FindUniqueID(const std::string& str, const char* suffix); + //! Search for an available name, starting from the given strings + std::string FindUniqueID(const std::string &str, const char *suffix); - Ref GetBodyBuffer() - { return mBodyBuffer; } + Ref GetBodyBuffer() { return mBodyBuffer; } - private: - void ReadBinaryHeader(IOStream& stream); +private: + void ReadBinaryHeader(IOStream &stream); - void ReadExtensionsUsed(Document& doc); + void ReadExtensionsUsed(Document &doc); - IOStream *OpenFile(const std::string &path, const char *mode, bool absolute = false); - }; + IOStream *OpenFile(const std::string &path, const char *mode, bool absolute = false); +}; -} +} // namespace glTF // Include the implementation of the methods #include "glTFAsset.inl" diff --git a/code/AssetLib/glTF/glTFAsset.inl b/code/AssetLib/glTF/glTFAsset.inl index e915a3aee..387fd27df 100644 --- a/code/AssetLib/glTF/glTFAsset.inl +++ b/code/AssetLib/glTF/glTFAsset.inl @@ -56,130 +56,11 @@ using namespace glTFCommon; namespace glTF { -namespace { - #if _MSC_VER # pragma warning(push) # pragma warning(disable : 4706) #endif // _MSC_VER -// -// JSON Value reading helpers -// - -template -struct ReadHelper { - static bool Read(Value &val, T &out) { - return val.IsInt() ? out = static_cast(val.GetInt()), true : false; - } -}; - -template <> -struct ReadHelper { - static bool Read(Value &val, bool &out) { - return val.IsBool() ? out = val.GetBool(), true : false; - } -}; - -template <> -struct ReadHelper { - static bool Read(Value &val, float &out) { - return val.IsNumber() ? out = static_cast(val.GetDouble()), true : false; - } -}; - -template -struct ReadHelper { - static bool Read(Value &val, float (&out)[N]) { - if (!val.IsArray() || val.Size() != N) return false; - for (unsigned int i = 0; i < N; ++i) { - if (val[i].IsNumber()) - out[i] = static_cast(val[i].GetDouble()); - } - return true; - } -}; - -template <> -struct ReadHelper { - static bool Read(Value &val, const char *&out) { - return val.IsString() ? (out = val.GetString(), true) : false; - } -}; - -template <> -struct ReadHelper { - static bool Read(Value &val, std::string &out) { - return val.IsString() ? (out = std::string(val.GetString(), val.GetStringLength()), true) : false; - } -}; - -template -struct ReadHelper> { - static bool Read(Value &val, Nullable &out) { - return out.isPresent = ReadHelper::Read(val, out.value); - } -}; - -template <> -struct ReadHelper { - static bool Read(Value &val, uint64_t &out) { - return val.IsUint64() ? out = val.GetUint64(), true : false; - } -}; - -template <> -struct ReadHelper { - static bool Read(Value &val, int64_t &out) { - return val.IsInt64() ? out = val.GetInt64(), true : false; - } -}; - -template -inline static bool ReadValue(Value &val, T &out) { - return ReadHelper::Read(val, out); -} - -template -inline static bool ReadMember(Value &obj, const char *id, T &out) { - Value::MemberIterator it = obj.FindMember(id); - if (it != obj.MemberEnd()) { - return ReadHelper::Read(it->value, out); - } - return false; -} - -template -inline static T MemberOrDefault(Value &obj, const char *id, T defaultValue) { - T out; - return ReadMember(obj, id, out) ? out : defaultValue; -} - -inline Value *FindMember(Value &val, const char *id) { - Value::MemberIterator it = val.FindMember(id); - return (it != val.MemberEnd()) ? &it->value : 0; -} - -inline Value *FindString(Value &val, const char *id) { - Value::MemberIterator it = val.FindMember(id); - return (it != val.MemberEnd() && it->value.IsString()) ? &it->value : 0; -} - -inline Value *FindNumber(Value &val, const char *id) { - Value::MemberIterator it = val.FindMember(id); - return (it != val.MemberEnd() && it->value.IsNumber()) ? &it->value : 0; -} - -inline Value *FindArray(Value &val, const char *id) { - Value::MemberIterator it = val.FindMember(id); - return (it != val.MemberEnd() && it->value.IsArray()) ? &it->value : 0; -} - -inline Value *FindObject(Value &val, const char *id) { - Value::MemberIterator it = val.FindMember(id); - return (it != val.MemberEnd() && it->value.IsObject()) ? &it->value : 0; -} -} // namespace // // LazyDict methods diff --git a/code/AssetLib/glTF/glTFCommon.h b/code/AssetLib/glTF/glTFCommon.h index 6f35e7881..78d40ce2c 100644 --- a/code/AssetLib/glTF/glTFCommon.h +++ b/code/AssetLib/glTF/glTFCommon.h @@ -56,33 +56,40 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +// clang-format off + #ifdef ASSIMP_API -#include -#include -#include +# include +# include +# include #else -#include -#define AI_SWAP4(p) -#define ai_assert +# include +# define AI_SWAP4(p) +# define ai_assert #endif #if _MSC_VER > 1500 || (defined __GNUC___) -#define ASSIMP_GLTF_USE_UNORDERED_MULTIMAP +# define ASSIMP_GLTF_USE_UNORDERED_MULTIMAP #else -#define gltf_unordered_map map +# define gltf_unordered_map map #endif #ifdef ASSIMP_GLTF_USE_UNORDERED_MULTIMAP -#include -#if defined(_MSC_VER) && _MSC_VER <= 1600 -#define gltf_unordered_map tr1::unordered_map -#else -#define gltf_unordered_map unordered_map -#endif +# include +# if defined(_MSC_VER) && _MSC_VER <= 1600 +# define gltf_unordered_map tr1::unordered_map +# else +# define gltf_unordered_map unordered_map +# endif #endif +// clang-format on + namespace glTFCommon { +using rapidjson::Document; +using rapidjson::Value; + #ifdef ASSIMP_API using Assimp::IOStream; using Assimp::IOSystem; @@ -193,7 +200,6 @@ inline void CopyValue(const glTFCommon::mat4 &v, aiMatrix4x4 &o) { #endif // _MSC_VER inline std::string getCurrentAssetDir(const std::string &pFile) { - std::string path = pFile; int pos = std::max(int(pFile.rfind('/')), int(pFile.rfind('\\'))); if (pos == int(std::string::npos)) { return std::string(); @@ -262,6 +268,284 @@ void EncodeBase64(const uint8_t *in, size_t inLength, std::string &out); #define CHECK_EXT(EXT) \ if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true; + + +//! Helper struct to represent values that might not be present +template +struct Nullable { + T value; + bool isPresent; + + Nullable() : + isPresent(false) {} + Nullable(T &val) : + value(val), + isPresent(true) {} +}; + +//! A reference to one top-level object, which is valid +//! until the Asset instance is destroyed +template +class Ref { + std::vector *vector; + unsigned int index; + +public: + Ref() : + vector(0), + index(0) {} + Ref(std::vector &vec, unsigned int idx) : + vector(&vec), + index(idx) {} + + inline unsigned int GetIndex() const { return index; } + + operator bool() const { return vector != 0; } + + T *operator->() { return (*vector)[index]; } + + T &operator*() { return *((*vector)[index]); } +}; + +// +// JSON Value reading helpers +// + +template +struct ReadHelper { + static bool Read(Value &val, T &out) { + return val.IsInt() ? out = static_cast(val.GetInt()), true : false; + } +}; + +template <> +struct ReadHelper { + static bool Read(Value &val, bool &out) { + return val.IsBool() ? out = val.GetBool(), true : false; + } +}; + +template <> +struct ReadHelper { + static bool Read(Value &val, float &out) { + return val.IsNumber() ? out = static_cast(val.GetDouble()), true : false; + } +}; + +template +struct ReadHelper { + static bool Read(Value &val, float (&out)[N]) { + if (!val.IsArray() || val.Size() != N) return false; + for (unsigned int i = 0; i < N; ++i) { + if (val[i].IsNumber()) + out[i] = static_cast(val[i].GetDouble()); + } + return true; + } +}; + +template <> +struct ReadHelper { + static bool Read(Value &val, const char *&out) { + return val.IsString() ? (out = val.GetString(), true) : false; + } +}; + +template <> +struct ReadHelper { + static bool Read(Value &val, std::string &out) { + return val.IsString() ? (out = std::string(val.GetString(), val.GetStringLength()), true) : false; + } +}; + +template +struct ReadHelper> { + static bool Read(Value &val, Nullable &out) { + return out.isPresent = ReadHelper::Read(val, out.value); + } +}; + +template <> +struct ReadHelper { + static bool Read(Value &val, uint64_t &out) { + return val.IsUint64() ? out = val.GetUint64(), true : false; + } +}; + +template <> +struct ReadHelper { + static bool Read(Value &val, int64_t &out) { + return val.IsInt64() ? out = val.GetInt64(), true : false; + } +}; + +template +inline static bool ReadValue(Value &val, T &out) { + return ReadHelper::Read(val, out); +} + +template +inline static bool ReadMember(Value &obj, const char *id, T &out) { + if (!obj.IsObject()) { + return false; + } + Value::MemberIterator it = obj.FindMember(id); + if (it != obj.MemberEnd()) { + return ReadHelper::Read(it->value, out); + } + return false; +} + +template +inline static T MemberOrDefault(Value &obj, const char *id, T defaultValue) { + T out; + return ReadMember(obj, id, out) ? out : defaultValue; +} + +inline Value *FindMember(Value &val, const char *id) { + if (!val.IsObject()) { + return nullptr; + } + Value::MemberIterator it = val.FindMember(id); + return (it != val.MemberEnd()) ? &it->value : nullptr; +} + +template +inline void throwUnexpectedTypeError(const char (&expectedTypeName)[N], const char *memberId, const char *context, const char *extraContext) { + std::string fullContext = context; + if (extraContext && (strlen(extraContext) > 0)) { + fullContext = fullContext + " (" + extraContext + ")"; + } + throw DeadlyImportError("Member \"", memberId, "\" was not of type \"", expectedTypeName, "\" when reading ", fullContext); +} + +// Look-up functions with type checks. Context and extra context help the user identify the problem if there's an error. + +inline Value *FindStringInContext(Value &val, const char *memberId, const char *context, const char *extraContext = nullptr) { + if (!val.IsObject()) { + return nullptr; + } + Value::MemberIterator it = val.FindMember(memberId); + if (it == val.MemberEnd()) { + return nullptr; + } + if (!it->value.IsString()) { + throwUnexpectedTypeError("string", memberId, context, extraContext); + } + return &it->value; +} + +inline Value *FindNumberInContext(Value &val, const char *memberId, const char *context, const char *extraContext = nullptr) { + if (!val.IsObject()) { + return nullptr; + } + Value::MemberIterator it = val.FindMember(memberId); + if (it == val.MemberEnd()) { + return nullptr; + } + if (!it->value.IsNumber()) { + throwUnexpectedTypeError("number", memberId, context, extraContext); + } + return &it->value; +} + +inline Value *FindUIntInContext(Value &val, const char *memberId, const char *context, const char *extraContext = nullptr) { + if (!val.IsObject()) { + return nullptr; + } + Value::MemberIterator it = val.FindMember(memberId); + if (it == val.MemberEnd()) { + return nullptr; + } + if (!it->value.IsUint()) { + throwUnexpectedTypeError("uint", memberId, context, extraContext); + } + return &it->value; +} + +inline Value *FindArrayInContext(Value &val, const char *memberId, const char *context, const char *extraContext = nullptr) { + if (!val.IsObject()) { + return nullptr; + } + Value::MemberIterator it = val.FindMember(memberId); + if (it == val.MemberEnd()) { + return nullptr; + } + if (!it->value.IsArray()) { + throwUnexpectedTypeError("array", memberId, context, extraContext); + } + return &it->value; +} + +inline Value *FindObjectInContext(Value &val, const char *memberId, const char *context, const char *extraContext = nullptr) { + if (!val.IsObject()) { + return nullptr; + } + Value::MemberIterator it = val.FindMember(memberId); + if (it == val.MemberEnd()) { + return nullptr; + } + if (!it->value.IsObject()) { + throwUnexpectedTypeError("object", memberId, context, extraContext); + } + return &it->value; +} + +inline Value *FindExtensionInContext(Value &val, const char *extensionId, const char *context, const char *extraContext = nullptr) { + if (Value *extensionList = FindObjectInContext(val, "extensions", context, extraContext)) { + if (Value *extension = FindObjectInContext(*extensionList, extensionId, context, extraContext)) { + return extension; + } + } + return nullptr; +} + +// Overloads when the value is the document. + +inline Value *FindString(Document &doc, const char *memberId) { + return FindStringInContext(doc, memberId, "the document"); +} + +inline Value *FindNumber(Document &doc, const char *memberId) { + return FindNumberInContext(doc, memberId, "the document"); +} + +inline Value *FindUInt(Document &doc, const char *memberId) { + return FindUIntInContext(doc, memberId, "the document"); +} + +inline Value *FindArray(Document &val, const char *memberId) { + return FindArrayInContext(val, memberId, "the document"); +} + +inline Value *FindObject(Document &doc, const char *memberId) { + return FindObjectInContext(doc, memberId, "the document"); +} + +inline Value *FindExtension(Value &val, const char *extensionId) { + return FindExtensionInContext(val, extensionId, "the document"); +} + +inline Value *FindString(Value &val, const char *id) { + Value::MemberIterator it = val.FindMember(id); + return (it != val.MemberEnd() && it->value.IsString()) ? &it->value : 0; +} + +inline Value *FindObject(Value &val, const char *id) { + Value::MemberIterator it = val.FindMember(id); + return (it != val.MemberEnd() && it->value.IsObject()) ? &it->value : 0; +} + +inline Value *FindArray(Value &val, const char *id) { + Value::MemberIterator it = val.FindMember(id); + return (it != val.MemberEnd() && it->value.IsArray()) ? &it->value : 0; +} + +inline Value *FindNumber(Value &val, const char *id) { + Value::MemberIterator it = val.FindMember(id); + return (it != val.MemberEnd() && it->value.IsNumber()) ? &it->value : 0; +} + } // namespace glTFCommon #endif // ASSIMP_BUILD_NO_GLTF_IMPORTER diff --git a/code/AssetLib/glTF/glTFExporter.h b/code/AssetLib/glTF/glTFExporter.h index 1ed3c73ea..bb9d5f05d 100644 --- a/code/AssetLib/glTF/glTFExporter.h +++ b/code/AssetLib/glTF/glTFExporter.h @@ -4,7 +4,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2021, assimp team - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -41,79 +40,79 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @file GltfExporter.h -* Declares the exporter class to write a scene to a gltf/glb file -*/ + * Declares the exporter class to write a scene to a gltf/glb file + */ +#pragma once #ifndef AI_GLTFEXPORTER_H_INC #define AI_GLTFEXPORTER_H_INC #if !defined(ASSIMP_BUILD_NO_GLTF_EXPORTER) && !defined(ASSIMP_BUILD_NO_GLTF1_EXPORTER) -#include #include +#include -#include -#include #include #include +#include +#include struct aiScene; struct aiNode; -struct aiMaterial; -namespace glTF -{ - template - class Ref; - - class Asset; - struct TexProperty; - struct Node; -} - -namespace Assimp -{ - class IOSystem; - class IOStream; - class ExportProperties; - - // ------------------------------------------------------------------------------------------------ - /** Helper class to export a given scene to an glTF file. */ - // ------------------------------------------------------------------------------------------------ - class glTFExporter - { - public: - /// Constructor for a specific scene to export - glTFExporter(const char* filename, IOSystem* pIOSystem, const aiScene* pScene, - const ExportProperties* pProperties, bool binary); - - private: - - const char* mFilename; - IOSystem* mIOSystem; - std::shared_ptr mScene; - const ExportProperties* mProperties; - - std::map mTexturesByPath; - - std::shared_ptr mAsset; - - std::vector mBodyData; - - void WriteBinaryData(IOStream* outfile, std::size_t sceneLength); - - void GetTexSampler(const aiMaterial* mat, glTF::TexProperty& prop); - void GetMatColorOrTex(const aiMaterial* mat, glTF::TexProperty& prop, const char* propName, int type, int idx, aiTextureType tt); - void ExportMetadata(); - void ExportMaterials(); - void ExportMeshes(); - unsigned int ExportNodeHierarchy(const aiNode* n); - unsigned int ExportNode(const aiNode* node, glTF::Ref& parent); - void ExportScene(); - void ExportAnimations(); - }; +namespace glTFCommon { +template +class Ref; } +namespace glTF { +class Asset; +struct TexProperty; +struct Node; + +} // namespace glTF + +namespace Assimp { +class IOSystem; +class IOStream; +class ExportProperties; + +// ------------------------------------------------------------------------------------------------ +/** Helper class to export a given scene to an glTF file. */ +// ------------------------------------------------------------------------------------------------ +class glTFExporter { +public: + /// Constructor for a specific scene to export + glTFExporter(const char *filename, IOSystem *pIOSystem, const aiScene *pScene, + const ExportProperties *pProperties, bool binary); + +private: + const char *mFilename; + IOSystem *mIOSystem; + std::shared_ptr mScene; + const ExportProperties *mProperties; + + std::map mTexturesByPath; + + std::shared_ptr mAsset; + + std::vector mBodyData; + + void WriteBinaryData(IOStream *outfile, std::size_t sceneLength); + + void GetTexSampler(const aiMaterial *mat, glTF::TexProperty &prop); + void GetMatColorOrTex(const aiMaterial *mat, glTF::TexProperty &prop, const char *propName, int type, int idx, aiTextureType tt); + void ExportMetadata(); + void ExportMaterials(); + void ExportMeshes(); + unsigned int ExportNodeHierarchy(const aiNode *n); + unsigned int ExportNode(const aiNode *node, glTFCommon::Ref & parent); + void ExportScene(); + void ExportAnimations(); +}; + +} // namespace Assimp + #endif // ASSIMP_BUILD_NO_GLTF_EXPORTER #endif // AI_GLTFEXPORTER_H_INC diff --git a/code/AssetLib/glTF/glTFImporter.h b/code/AssetLib/glTF/glTFImporter.h index eda386cd2..2df60a463 100644 --- a/code/AssetLib/glTF/glTFImporter.h +++ b/code/AssetLib/glTF/glTFImporter.h @@ -49,7 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. struct aiNode; namespace glTF { -class Asset; + class Asset; } diff --git a/code/AssetLib/glTF2/glTF2Asset.h b/code/AssetLib/glTF2/glTF2Asset.h index cd6c1c89d..9a50ede99 100644 --- a/code/AssetLib/glTF2/glTF2Asset.h +++ b/code/AssetLib/glTF2/glTF2Asset.h @@ -65,6 +65,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +// clang-format off #if (__GNUC__ == 8 && __GNUC_MINOR__ >= 0) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wclass-memaccess" @@ -75,37 +76,38 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #if (__GNUC__ == 8 && __GNUC_MINOR__ >= 0) -#pragma GCC diagnostic pop +# pragma GCC diagnostic pop #endif #ifdef ASSIMP_API -#include -#include -#include +# include +# include +# include #else -#include -#define AI_SWAP4(p) -#define ai_assert +# include +# define AI_SWAP4(p) +# define ai_assert #endif #if _MSC_VER > 1500 || (defined __GNUC___) -#define ASSIMP_GLTF_USE_UNORDERED_MULTIMAP +# define ASSIMP_GLTF_USE_UNORDERED_MULTIMAP #else -#define gltf_unordered_map map -#define gltf_unordered_set set +# define gltf_unordered_map map +# define gltf_unordered_set set #endif #ifdef ASSIMP_GLTF_USE_UNORDERED_MULTIMAP -#include -#include -#if defined(_MSC_VER) && _MSC_VER <= 1600 -#define gltf_unordered_map tr1::unordered_map -#define gltf_unordered_set tr1::unordered_set -#else -#define gltf_unordered_map unordered_map -#define gltf_unordered_set unordered_set -#endif +# include +# include +# if defined(_MSC_VER) && _MSC_VER <= 1600 +# define gltf_unordered_map tr1::unordered_map +# define gltf_unordered_set tr1::unordered_set +# else +# define gltf_unordered_map unordered_map +# define gltf_unordered_set unordered_set +# endif #endif +// clang-format on #include @@ -113,6 +115,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace glTF2 { +using glTFCommon::Nullable; +using glTFCommon::Ref; using glTFCommon::IOStream; using glTFCommon::IOSystem; using glTFCommon::shared_ptr; @@ -319,44 +323,9 @@ const AttribType::Info { "SCALAR", 1 }, { "VEC2", 2 }, { "VEC3", 3 }, { "VEC4", 4 }, { "MAT2", 4 }, { "MAT3", 9 }, { "MAT4", 16 } }; -//! A reference to one top-level object, which is valid -//! until the Asset instance is destroyed -template -class Ref { - std::vector *vector; - unsigned int index; - -public: - Ref() : - vector(0), - index(0) {} - Ref(std::vector &vec, unsigned int idx) : - vector(&vec), - index(idx) {} - - inline unsigned int GetIndex() const { return index; } - - operator bool() const { return vector != 0; } - - T *operator->() { return (*vector)[index]; } - - T &operator*() { return *((*vector)[index]); } -}; - -//! Helper struct to represent values that might not be present -template -struct Nullable { - T value; - bool isPresent; - - Nullable() : - isPresent(false) {} - Nullable(T &val) : - value(val), - isPresent(true) {} -}; struct CustomExtension { + // // A struct containing custom extension data added to a glTF2 file // Has to contain Object, Array, String, Double, Uint64, and Int64 at a minimum @@ -553,7 +522,7 @@ public: void MarkAsSpecial() { mIsSpecial = true; } - bool IsSpecial() const { return mIsSpecial; } + bool IsSpecial() const override { return mIsSpecial; } std::string GetURI() { return std::string(this->id) + ".bin"; } @@ -849,7 +818,7 @@ struct Material : public Object { //! A set of primitives to be rendered. A node can contain one or more meshes. A node's transform places the mesh in the scene. struct Mesh : public Object { - typedef std::vector> AccessorList; + using AccessorList = std::vector>; struct Primitive { PrimitiveMode mode; @@ -880,7 +849,6 @@ struct Mesh : public Object { Mesh() {} - /// \fn void Read(Value& pJSON_Object, Asset& pAsset_Root) /// Get mesh data from JSON-object and place them to root asset. /// \param [in] pJSON_Object - reference to pJSON-object from which data are read. /// \param [out] pAsset_Root - reference to root asset where data will be stored. @@ -1023,8 +991,8 @@ class LazyDict : public LazyDictBase { friend class Asset; friend class AssetWriter; - typedef typename std::gltf_unordered_map Dict; - typedef typename std::gltf_unordered_map IdDict; + using Dict = typename std::gltf_unordered_map; + using IdDict = typename std::gltf_unordered_map; std::vector mObjs; //! The read objects Dict mObjsByOIndex; //! The read objects accessible by original index @@ -1087,7 +1055,7 @@ struct AssetMetadata { //! Root object for a glTF asset class Asset { - typedef std::gltf_unordered_map IdMap; + using IdMap = std::gltf_unordered_map; template friend class LazyDict; diff --git a/code/AssetLib/glTF2/glTF2Asset.inl b/code/AssetLib/glTF2/glTF2Asset.inl index 9f793d7c0..4832995cc 100644 --- a/code/AssetLib/glTF2/glTF2Asset.inl +++ b/code/AssetLib/glTF2/glTF2Asset.inl @@ -45,40 +45,43 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +// clang-format off #ifdef ASSIMP_ENABLE_DRACO // Google draco library headers spew many warnings. Bad Google, no cookie -#if _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4018) // Signed/unsigned mismatch -#pragma warning(disable : 4804) // Unsafe use of type 'bool' -#elif defined(__clang__) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wsign-compare" -#elif defined(__GNUC__) -#pragma GCC diagnostic push -#if (__GNUC__ > 4) -#pragma GCC diagnostic ignored "-Wbool-compare" -#endif -#pragma GCC diagnostic ignored "-Wsign-compare" +# if _MSC_VER +# pragma warning(push) +# pragma warning(disable : 4018) // Signed/unsigned mismatch +# pragma warning(disable : 4804) // Unsafe use of type 'bool' +# elif defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wsign-compare" +# elif defined(__GNUC__) +# pragma GCC diagnostic push +# if (__GNUC__ > 4) +# pragma GCC diagnostic ignored "-Wbool-compare" +# endif +# pragma GCC diagnostic ignored "-Wsign-compare" #endif #include "draco/compression/decode.h" #include "draco/core/decoder_buffer.h" #if _MSC_VER -#pragma warning(pop) +# pragma warning(pop) #elif defined(__clang__) -#pragma clang diagnostic pop +# pragma clang diagnostic pop #elif defined(__GNUC__) -#pragma GCC diagnostic pop +# pragma GCC diagnostic pop #endif #ifndef DRACO_MESH_COMPRESSION_SUPPORTED -#error glTF: KHR_draco_mesh_compression: draco library must have DRACO_MESH_COMPRESSION_SUPPORTED +# error glTF: KHR_draco_mesh_compression: draco library must have DRACO_MESH_COMPRESSION_SUPPORTED #endif #endif +// clang-format on using namespace Assimp; +using namespace glTFCommon; namespace glTF2 { @@ -88,222 +91,6 @@ namespace { // JSON Value reading helpers // -template -struct ReadHelper { - static bool Read(Value &val, T &out) { - return val.IsInt() ? out = static_cast(val.GetInt()), true : false; - } -}; - -template <> -struct ReadHelper { - static bool Read(Value &val, bool &out) { - return val.IsBool() ? out = val.GetBool(), true : false; - } -}; - -template <> -struct ReadHelper { - static bool Read(Value &val, float &out) { - return val.IsNumber() ? out = static_cast(val.GetDouble()), true : false; - } -}; - -template -struct ReadHelper { - static bool Read(Value &val, float (&out)[N]) { - if (!val.IsArray() || val.Size() != N) return false; - for (unsigned int i = 0; i < N; ++i) { - if (val[i].IsNumber()) - out[i] = static_cast(val[i].GetDouble()); - } - return true; - } -}; - -template <> -struct ReadHelper { - static bool Read(Value &val, const char *&out) { - return val.IsString() ? (out = val.GetString(), true) : false; - } -}; - -template <> -struct ReadHelper { - static bool Read(Value &val, std::string &out) { - return val.IsString() ? (out = std::string(val.GetString(), val.GetStringLength()), true) : false; - } -}; - -template <> -struct ReadHelper { - static bool Read(Value &val, uint64_t &out) { - return val.IsUint64() ? out = val.GetUint64(), true : false; - } -}; - -template <> -struct ReadHelper { - static bool Read(Value &val, int64_t &out) { - return val.IsInt64() ? out = val.GetInt64(), true : false; - } -}; - -template -struct ReadHelper> { - static bool Read(Value &val, Nullable &out) { - return out.isPresent = ReadHelper::Read(val, out.value); - } -}; - -template -inline static bool ReadValue(Value &val, T &out) { - return ReadHelper::Read(val, out); -} - -template -inline static bool ReadMember(Value &obj, const char *id, T &out) { - if (!obj.IsObject()) { - return false; - } - Value::MemberIterator it = obj.FindMember(id); - if (it != obj.MemberEnd()) { - return ReadHelper::Read(it->value, out); - } - return false; -} - -template -inline static T MemberOrDefault(Value &obj, const char *id, T defaultValue) { - T out; - return ReadMember(obj, id, out) ? out : defaultValue; -} - -inline Value *FindMember(Value &val, const char *id) { - if (!val.IsObject()) { - return nullptr; - } - Value::MemberIterator it = val.FindMember(id); - return (it != val.MemberEnd()) ? &it->value : nullptr; -} - -template -inline void throwUnexpectedTypeError(const char (&expectedTypeName)[N], const char* memberId, const char* context, const char* extraContext) { - std::string fullContext = context; - if (extraContext && (strlen(extraContext) > 0)) - { - fullContext = fullContext + " (" + extraContext + ")"; - } - throw DeadlyImportError("Member \"", memberId, "\" was not of type \"", expectedTypeName, "\" when reading ", fullContext); -} - -// Look-up functions with type checks. Context and extra context help the user identify the problem if there's an error. - -inline Value *FindStringInContext(Value &val, const char *memberId, const char* context, const char* extraContext = nullptr) { - if (!val.IsObject()) { - return nullptr; - } - Value::MemberIterator it = val.FindMember(memberId); - if (it == val.MemberEnd()) { - return nullptr; - } - if (!it->value.IsString()) { - throwUnexpectedTypeError("string", memberId, context, extraContext); - } - return &it->value; -} - -inline Value *FindNumberInContext(Value &val, const char *memberId, const char* context, const char* extraContext = nullptr) { - if (!val.IsObject()) { - return nullptr; - } - Value::MemberIterator it = val.FindMember(memberId); - if (it == val.MemberEnd()) { - return nullptr; - } - if (!it->value.IsNumber()) { - throwUnexpectedTypeError("number", memberId, context, extraContext); - } - return &it->value; -} - -inline Value *FindUIntInContext(Value &val, const char *memberId, const char* context, const char* extraContext = nullptr) { - if (!val.IsObject()) { - return nullptr; - } - Value::MemberIterator it = val.FindMember(memberId); - if (it == val.MemberEnd()) { - return nullptr; - } - if (!it->value.IsUint()) { - throwUnexpectedTypeError("uint", memberId, context, extraContext); - } - return &it->value; -} - -inline Value *FindArrayInContext(Value &val, const char *memberId, const char* context, const char* extraContext = nullptr) { - if (!val.IsObject()) { - return nullptr; - } - Value::MemberIterator it = val.FindMember(memberId); - if (it == val.MemberEnd()) { - return nullptr; - } - if (!it->value.IsArray()) { - throwUnexpectedTypeError("array", memberId, context, extraContext); - } - return &it->value; -} - -inline Value *FindObjectInContext(Value &val, const char *memberId, const char* context, const char* extraContext = nullptr) { - if (!val.IsObject()) { - return nullptr; - } - Value::MemberIterator it = val.FindMember(memberId); - if (it == val.MemberEnd()) { - return nullptr; - } - if (!it->value.IsObject()) { - throwUnexpectedTypeError("object", memberId, context, extraContext); - } - return &it->value; -} - -inline Value *FindExtensionInContext(Value &val, const char *extensionId, const char* context, const char* extraContext = nullptr) { - if (Value *extensionList = FindObjectInContext(val, "extensions", context, extraContext)) { - if (Value *extension = FindObjectInContext(*extensionList, extensionId, context, extraContext)) { - return extension; - } - } - return nullptr; -} - -// Overloads when the value is the document. - -inline Value *FindString(Document &doc, const char *memberId) { - return FindStringInContext(doc, memberId, "the document"); -} - -inline Value *FindNumber(Document &doc, const char *memberId) { - return FindNumberInContext(doc, memberId, "the document"); -} - -inline Value *FindUInt(Document &doc, const char *memberId) { - return FindUIntInContext(doc, memberId, "the document"); -} - -inline Value *FindArray(Document &val, const char *memberId) { - return FindArrayInContext(val, memberId, "the document"); -} - -inline Value *FindObject(Document &doc, const char *memberId) { - return FindObjectInContext(doc, memberId, "the document"); -} - -inline Value *FindExtension(Value &val, const char *extensionId) { - return FindExtensionInContext(val, extensionId, "the document"); -} - inline CustomExtension ReadExtensions(const char *name, Value &obj) { CustomExtension ret; ret.name = name; diff --git a/code/AssetLib/glTF2/glTF2Exporter.cpp b/code/AssetLib/glTF2/glTF2Exporter.cpp index bd8cd224a..22db4b26d 100644 --- a/code/AssetLib/glTF2/glTF2Exporter.cpp +++ b/code/AssetLib/glTF2/glTF2Exporter.cpp @@ -57,7 +57,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include // Header files, standard library. -#include +#include #include #include diff --git a/code/AssetLib/glTF2/glTF2Exporter.h b/code/AssetLib/glTF2/glTF2Exporter.h index f5238297f..842d29815 100644 --- a/code/AssetLib/glTF2/glTF2Exporter.h +++ b/code/AssetLib/glTF2/glTF2Exporter.h @@ -4,7 +4,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2021, assimp team - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -48,93 +47,94 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #if !defined(ASSIMP_BUILD_NO_GLTF_IMPORTER) && !defined(ASSIMP_BUILD_NO_GLTF2_IMPORTER) -#include #include +#include -#include -#include #include #include +#include +#include struct aiScene; struct aiNode; struct aiMaterial; -namespace glTF2 -{ - template - class Ref; - - class Asset; - struct TexProperty; - struct TextureInfo; - struct NormalTextureInfo; - struct OcclusionTextureInfo; - struct Node; - struct Texture; - struct PbrSpecularGlossiness; - struct MaterialSheen; - struct MaterialClearcoat; - struct MaterialTransmission; - - // Vec/matrix types, as raw float arrays - typedef float (vec2)[2]; - typedef float (vec3)[3]; - typedef float (vec4)[4]; -} - -namespace Assimp -{ - class IOSystem; - class IOStream; - class ExportProperties; - - // ------------------------------------------------------------------------------------------------ - /** Helper class to export a given scene to an glTF file. */ - // ------------------------------------------------------------------------------------------------ - class glTF2Exporter { - public: - /// Constructor for a specific scene to export - glTF2Exporter(const char* filename, IOSystem* pIOSystem, const aiScene* pScene, - const ExportProperties* pProperties, bool binary); - ~glTF2Exporter(); - - protected: - void WriteBinaryData(IOStream* outfile, std::size_t sceneLength); - void GetTexSampler(const aiMaterial& mat, glTF2::Ref texture, aiTextureType tt, unsigned int slot); - void GetMatTexProp(const aiMaterial& mat, unsigned int& prop, const char* propName, aiTextureType tt, unsigned int idx); - void GetMatTexProp(const aiMaterial& mat, float& prop, const char* propName, aiTextureType tt, unsigned int idx); - void GetMatTex(const aiMaterial& mat, glTF2::Ref& texture, unsigned int &texCoord, aiTextureType tt, unsigned int slot); - void GetMatTex(const aiMaterial& mat, glTF2::TextureInfo& prop, aiTextureType tt, unsigned int slot); - void GetMatTex(const aiMaterial& mat, glTF2::NormalTextureInfo& prop, aiTextureType tt, unsigned int slot); - void GetMatTex(const aiMaterial& mat, glTF2::OcclusionTextureInfo& prop, aiTextureType tt, unsigned int slot); - aiReturn GetMatColor(const aiMaterial& mat, glTF2::vec4& prop, const char* propName, int type, int idx) const; - aiReturn GetMatColor(const aiMaterial& mat, glTF2::vec3& prop, const char* propName, int type, int idx) const; - bool GetMatSpecGloss(const aiMaterial& mat, glTF2::PbrSpecularGlossiness& pbrSG); - bool GetMatSheen(const aiMaterial& mat, glTF2::MaterialSheen& sheen); - bool GetMatClearcoat(const aiMaterial& mat, glTF2::MaterialClearcoat& clearcoat); - bool GetMatTransmission(const aiMaterial& mat, glTF2::MaterialTransmission& transmission); - void ExportMetadata(); - void ExportMaterials(); - void ExportMeshes(); - void MergeMeshes(); - unsigned int ExportNodeHierarchy(const aiNode* n); - unsigned int ExportNode(const aiNode* node, glTF2::Ref& parent); - void ExportScene(); - void ExportAnimations(); - - private: - const char* mFilename; - IOSystem* mIOSystem; - const aiScene* mScene; - const ExportProperties* mProperties; - std::map mTexturesByPath; - std::shared_ptr mAsset; - std::vector mBodyData; - }; +namespace glTFCommon { +template +class Ref; } +namespace glTF2 { +class Asset; +struct TexProperty; +struct TextureInfo; +struct NormalTextureInfo; +struct OcclusionTextureInfo; +struct Node; +struct Texture; +struct PbrSpecularGlossiness; +struct MaterialSheen; +struct MaterialClearcoat; +struct MaterialTransmission; + +// Vec/matrix types, as raw float arrays +typedef float(vec2)[2]; +typedef float(vec3)[3]; +typedef float(vec4)[4]; +} // namespace glTF2 + +namespace Assimp { +class IOSystem; +class IOStream; +class ExportProperties; + +// ------------------------------------------------------------------------------------------------ +/** Helper class to export a given scene to an glTF file. */ +// ------------------------------------------------------------------------------------------------ +class glTF2Exporter { +public: + /// Constructor for a specific scene to export + glTF2Exporter(const char *filename, IOSystem *pIOSystem, const aiScene *pScene, + const ExportProperties *pProperties, bool binary); + ~glTF2Exporter(); + +protected: + void WriteBinaryData(IOStream *outfile, std::size_t sceneLength); + void GetTexSampler(const aiMaterial &mat, glTFCommon::Ref texture, aiTextureType tt, unsigned int slot); + void GetMatTexProp(const aiMaterial &mat, unsigned int &prop, const char *propName, aiTextureType tt, unsigned int idx); + void GetMatTexProp(const aiMaterial &mat, float &prop, const char *propName, aiTextureType tt, unsigned int idx); + void GetMatTex(const aiMaterial &mat, glTFCommon::Ref &texture, unsigned int &texCoord, aiTextureType tt, unsigned int slot); + void GetMatTex(const aiMaterial &mat, glTF2::TextureInfo &prop, aiTextureType tt, unsigned int slot); + void GetMatTex(const aiMaterial &mat, glTF2::NormalTextureInfo &prop, aiTextureType tt, unsigned int slot); + void GetMatTex(const aiMaterial &mat, glTF2::OcclusionTextureInfo &prop, aiTextureType tt, unsigned int slot); + aiReturn GetMatColor(const aiMaterial &mat, glTF2::vec4 &prop, const char *propName, int type, int idx) const; + aiReturn GetMatColor(const aiMaterial &mat, glTF2::vec3 &prop, const char *propName, int type, int idx) const; + bool GetMatSpecGloss(const aiMaterial &mat, glTF2::PbrSpecularGlossiness &pbrSG); + bool GetMatSheen(const aiMaterial &mat, glTF2::MaterialSheen &sheen); + bool GetMatClearcoat(const aiMaterial &mat, glTF2::MaterialClearcoat &clearcoat); + bool GetMatTransmission(const aiMaterial &mat, glTF2::MaterialTransmission &transmission); + void ExportMetadata(); + void ExportMaterials(); + void ExportMeshes(); + void MergeMeshes(); + unsigned int ExportNodeHierarchy(const aiNode *n); + unsigned int ExportNode(const aiNode *node, glTFCommon::Ref &parent); + void ExportScene(); + void ExportAnimations(); + +private: + const char *mFilename; + IOSystem *mIOSystem; + const aiScene *mScene; + const ExportProperties *mProperties; + std::map mTexturesByPath; + std::shared_ptr mAsset; + std::vector mBodyData; +}; + +} // namespace Assimp + #endif // ASSIMP_BUILD_NO_GLTF_IMPORTER #endif // AI_GLTF2EXPORTER_H_INC diff --git a/code/AssetLib/glTF2/glTF2Importer.cpp b/code/AssetLib/glTF2/glTF2Importer.cpp index da6023851..6c92bdc87 100644 --- a/code/AssetLib/glTF2/glTF2Importer.cpp +++ b/code/AssetLib/glTF2/glTF2Importer.cpp @@ -44,6 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "AssetLib/glTF2/glTF2Importer.h" #include "PostProcessing/MakeVerboseFormat.h" #include "AssetLib/glTF2/glTF2Asset.h" + #if !defined(ASSIMP_BUILD_NO_EXPORT) #include "AssetLib/glTF2/glTF2AssetWriter.h" #endif @@ -57,6 +58,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include #include @@ -1536,11 +1538,9 @@ void glTF2Importer::ImportEmbeddedTextures(glTF2::Asset &r) { if (ext) { if (strcmp(ext, "jpeg") == 0) { ext = "jpg"; - } - else if(strcmp(ext, "ktx2") == 0) { //basisu: ktx remains + } else if(strcmp(ext, "ktx2") == 0) { //basisu: ktx remains ext = "kx2"; - } - else if(strcmp(ext, "basis") == 0) { //basisu + } else if(strcmp(ext, "basis") == 0) { //basisu ext = "bu"; } diff --git a/code/AssetLib/glTF2/glTF2Importer.h b/code/AssetLib/glTF2/glTF2Importer.h index 5df375d55..e586dc6cc 100644 --- a/code/AssetLib/glTF2/glTF2Importer.h +++ b/code/AssetLib/glTF2/glTF2Importer.h @@ -43,12 +43,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define AI_GLTF2IMPORTER_H_INC #include -#include struct aiNode; namespace glTF2 { -class Asset; + class Asset; } namespace Assimp {