| /* |
| Open Asset Import Library (assimp) |
| ---------------------------------------------------------------------- |
| |
| Copyright (c) 2006-2017, assimp team |
| |
| All rights reserved. |
| |
| Redistribution and use of this software in source and binary forms, |
| with or without modification, are permitted provided that the |
| following conditions are met: |
| |
| * Redistributions of source code must retain the above |
| copyright notice, this list of conditions and the |
| following disclaimer. |
| |
| * Redistributions in binary form must reproduce the above |
| copyright notice, this list of conditions and the |
| following disclaimer in the documentation and/or other |
| materials provided with the distribution. |
| |
| * Neither the name of the assimp team, nor the names of its |
| contributors may be used to endorse or promote products |
| derived from this software without specific prior |
| written permission of the assimp team. |
| |
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| ---------------------------------------------------------------------- |
| */ |
| |
| /** @file glTFAsset.h |
| * Declares a glTF class to handle gltf/glb files |
| * |
| * glTF Extensions Support: |
| * KHR_materials_pbrSpecularGlossiness full |
| */ |
| #ifndef GLTF2ASSET_H_INC |
| #define GLTF2ASSET_H_INC |
| |
| #ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER |
| |
| #include <map> |
| #include <string> |
| #include <list> |
| #include <vector> |
| #include <algorithm> |
| #include <stdexcept> |
| |
| #define RAPIDJSON_HAS_STDSTRING 1 |
| #include <rapidjson/rapidjson.h> |
| #include <rapidjson/document.h> |
| #include <rapidjson/error/en.h> |
| |
| #ifdef ASSIMP_API |
| # include <memory> |
| # include <assimp/DefaultIOSystem.h> |
| # include "ByteSwapper.h" |
| #else |
| # include <memory> |
| # define AI_SWAP4(p) |
| # define ai_assert |
| #endif |
| |
| |
| #if _MSC_VER > 1500 || (defined __GNUC___) |
| # define ASSIMP_GLTF_USE_UNORDERED_MULTIMAP |
| # else |
| # define gltf_unordered_map map |
| #endif |
| |
| #ifdef ASSIMP_GLTF_USE_UNORDERED_MULTIMAP |
| # include <unordered_map> |
| # if _MSC_VER > 1600 |
| # define gltf_unordered_map unordered_map |
| # else |
| # define gltf_unordered_map tr1::unordered_map |
| # endif |
| #endif |
| |
| #include "StringUtils.h" |
| |
| namespace glTF2 |
| { |
| #ifdef ASSIMP_API |
| using Assimp::IOStream; |
| using Assimp::IOSystem; |
| using std::shared_ptr; |
| #else |
| using std::shared_ptr; |
| |
| typedef std::runtime_error DeadlyImportError; |
| typedef std::runtime_error DeadlyExportError; |
| |
| enum aiOrigin { aiOrigin_SET = 0, aiOrigin_CUR = 1, aiOrigin_END = 2 }; |
| class IOSystem; |
| class IOStream |
| { |
| FILE* f; |
| public: |
| IOStream(FILE* file) : f(file) {} |
| ~IOStream() { fclose(f); f = 0; } |
| |
| size_t Read(void* b, size_t sz, size_t n) { return fread(b, sz, n, f); } |
| size_t Write(const void* b, size_t sz, size_t n) { return fwrite(b, sz, n, f); } |
| int Seek(size_t off, aiOrigin orig) { return fseek(f, off, int(orig)); } |
| size_t Tell() const { return ftell(f); } |
| |
| size_t FileSize() { |
| long p = Tell(), len = (Seek(0, aiOrigin_END), Tell()); |
| return size_t((Seek(p, aiOrigin_SET), len)); |
| } |
| }; |
| #endif |
| |
| using rapidjson::Value; |
| using rapidjson::Document; |
| |
| class Asset; |
| class AssetWriter; |
| |
| struct BufferView; // here due to cross-reference |
| struct Texture; |
| struct Skin; |
| |
| // Vec/matrix types, as raw float arrays |
| typedef float (vec3)[3]; |
| typedef float (vec4)[4]; |
| typedef float (mat4)[16]; |
| |
| namespace Util |
| { |
| void EncodeBase64(const uint8_t* in, size_t inLength, std::string& out); |
| |
| size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out); |
| |
| inline size_t DecodeBase64(const char* in, uint8_t*& out) |
| { |
| return DecodeBase64(in, strlen(in), out); |
| } |
| |
| struct DataURI |
| { |
| const char* mediaType; |
| const char* charset; |
| bool base64; |
| const char* data; |
| size_t dataLength; |
| }; |
| |
| //! Check if a uri is a data URI |
| inline bool ParseDataURI(const char* uri, size_t uriLen, DataURI& out); |
| } |
| |
| |
| //! Magic number for GLB files |
| #define AI_GLB_MAGIC_NUMBER "glTF" |
| |
| #define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_FACTOR "$mat.gltf.pbrMetallicRoughness.baseColorFactor", 0, 0 |
| #define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR "$mat.gltf.pbrMetallicRoughness.metallicFactor", 0, 0 |
| #define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR "$mat.gltf.pbrMetallicRoughness.roughnessFactor", 0, 0 |
| #define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_TEXTURE aiTextureType_DIFFUSE, 1 |
| #define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE aiTextureType_UNKNOWN, 0 |
| #define AI_MATKEY_GLTF_ALPHAMODE "$mat.gltf.alphaMode", 0, 0 |
| #define AI_MATKEY_GLTF_ALPHACUTOFF "$mat.gltf.alphaCutoff", 0, 0 |
| #define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS "$mat.gltf.pbrSpecularGlossiness", 0, 0 |
| #define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_GLOSSINESS_FACTOR "$mat.gltf.pbrMetallicRoughness.glossinessFactor", 0, 0 |
| |
| #define _AI_MATKEY_GLTF_TEXTURE_TEXCOORD_BASE "$tex.file.texCoord" |
| #define _AI_MATKEY_GLTF_MAPPINGNAME_BASE "$tex.mappingname" |
| #define _AI_MATKEY_GLTF_MAPPINGID_BASE "$tex.mappingid" |
| #define _AI_MATKEY_GLTF_MAPPINGFILTER_MAG_BASE "$tex.mappingfiltermag" |
| #define _AI_MATKEY_GLTF_MAPPINGFILTER_MIN_BASE "$tex.mappingfiltermin" |
| |
| #define AI_MATKEY_GLTF_TEXTURE_TEXCOORD _AI_MATKEY_GLTF_TEXTURE_TEXCOORD_BASE, type, N |
| #define AI_MATKEY_GLTF_MAPPINGNAME(type, N) _AI_MATKEY_GLTF_MAPPINGNAME_BASE, type, N |
| #define AI_MATKEY_GLTF_MAPPINGID(type, N) _AI_MATKEY_GLTF_MAPPINGID_BASE, type, N |
| #define AI_MATKEY_GLTF_MAPPINGFILTER_MAG(type, N) _AI_MATKEY_GLTF_MAPPINGFILTER_MAG_BASE, type, N |
| #define AI_MATKEY_GLTF_MAPPINGFILTER_MIN(type, N) _AI_MATKEY_GLTF_MAPPINGFILTER_MIN_BASE, type, N |
| |
| #ifdef ASSIMP_API |
| #include "./../include/assimp/Compiler/pushpack1.h" |
| #endif |
| |
| //! For binary .glb files |
| //! 12-byte header (+ the JSON + a "body" data section) |
| struct GLB_Header |
| { |
| uint8_t magic[4]; //!< Magic number: "glTF" |
| uint32_t version; //!< Version number (always 2 as of the last update) |
| uint32_t length; //!< Total length of the Binary glTF, including header, scene, and body, in bytes |
| } PACK_STRUCT; |
| |
| struct GLB_Chunk |
| { |
| uint32_t chunkLength; |
| uint32_t chunkType; |
| } PACK_STRUCT; |
| |
| #ifdef ASSIMP_API |
| #include "./../include/assimp/Compiler/poppack1.h" |
| #endif |
| |
| |
| //! Values for the GLB_Chunk::chunkType field |
| enum ChunkType |
| { |
| ChunkType_JSON = 0x4E4F534A, |
| ChunkType_BIN = 0x004E4942 |
| }; |
| |
| //! 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: |
| throw DeadlyImportError("GLTF: Unsupported Component Type " + to_string(t)); |
| } |
| } |
| |
| //! Values for the BufferView::target field |
| enum BufferViewTarget |
| { |
| BufferViewTarget_ARRAY_BUFFER = 34962, |
| BufferViewTarget_ELEMENT_ARRAY_BUFFER = 34963 |
| }; |
| |
| //! Values for the Sampler::magFilter field |
| enum class SamplerMagFilter: unsigned int |
| { |
| UNSET = 0, |
| SamplerMagFilter_Nearest = 9728, |
| SamplerMagFilter_Linear = 9729 |
| }; |
| |
| //! Values for the Sampler::minFilter field |
| enum class SamplerMinFilter: unsigned int |
| { |
| UNSET = 0, |
| 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 class SamplerWrap: unsigned int |
| { |
| UNSET = 0, |
| Clamp_To_Edge = 33071, |
| Mirrored_Repeat = 33648, |
| 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<size_t>(MAT4)+1; |
| |
| struct Info |
| { const char* name; unsigned int numComponents; }; |
| |
| template<int N> struct data |
| { static const Info infos[NUM_VALUES]; }; |
| |
| public: |
| inline static Value FromString(const char* str) |
| { |
| for (size_t i = 0; i < NUM_VALUES; ++i) { |
| if (strcmp(data<0>::infos[i].name, str) == 0) { |
| return static_cast<Value>(i); |
| } |
| } |
| return SCALAR; |
| } |
| |
| inline static const char* ToString(Value type) |
| { |
| return data<0>::infos[static_cast<size_t>(type)].name; |
| } |
| |
| inline static unsigned int GetNumComponents(Value type) |
| { |
| return data<0>::infos[static_cast<size_t>(type)].numComponents; |
| } |
| }; |
| |
| // must match the order of the AttribTypeTraits::Value enum! |
| template<int N> const AttribType::Info |
| AttribType::data<N>::infos[AttribType::NUM_VALUES] = { |
| { "SCALAR", 1 }, { "VEC2", 2 }, { "VEC3", 3 }, { "VEC4", 4 }, { "MAT2", 4 }, { "MAT3", 9 }, { "MAT4", 16 } |
| }; |
| |
| |
| |
| //! A reference to one top-level object, which is valid |
| //! until the Asset instance is destroyed |
| template<class T> |
| class Ref |
| { |
| std::vector<T*>* vector; |
| unsigned int index; |
| |
| public: |
| Ref() : vector(0), index(0) {} |
| Ref(std::vector<T*>& vec, unsigned int idx) : vector(&vec), index(idx) {} |
| |
| inline unsigned int GetIndex() const |
| { return index; } |
| |
| operator bool() const |
| { return vector != 0; } |
| |
| T* operator->() |
| { return (*vector)[index]; } |
| |
| T& operator*() |
| { return *((*vector)[index]); } |
| }; |
| |
| //! Helper struct to represent values that might not be present |
| template<class T> |
| struct Nullable |
| { |
| T value; |
| bool isPresent; |
| |
| Nullable() : isPresent(false) {} |
| Nullable(T& val) : value(val), isPresent(true) {} |
| }; |
| |
| |
| //! Base classe for all glTF top-level objects |
| struct Object |
| { |
| int index; //!< The index of this object within its property container |
| int oIndex; //!< The original index of this object defined in the JSON |
| std::string id; //!< The globally unique ID used to reference this object |
| std::string name; //!< The user-defined name of this object |
| |
| //! Objects marked as special are not exported (used to emulate the binary body buffer) |
| virtual bool IsSpecial() const |
| { return false; } |
| |
| virtual ~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; } |
| }; |
| |
| // |
| // Classes for each glTF top-level object type |
| // |
| |
| //! 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> bufferView; //!< The ID of the bufferView. (required) |
| unsigned int byteOffset; //!< The offset relative to the start of the bufferView in bytes. (required) |
| 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<float> max; //!< Maximum value of each component in this attribute. |
| std::vector<float> min; //!< Minimum value of each component in this attribute. |
| |
| unsigned int GetNumComponents(); |
| unsigned int GetBytesPerComponent(); |
| unsigned int GetElementSize(); |
| |
| inline uint8_t* GetPointer(); |
| |
| template<class T> |
| 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; |
| |
| Accessor& accessor; |
| uint8_t* data; |
| size_t elemSize, stride; |
| |
| Indexer(Accessor& acc); |
| |
| public: |
| |
| //! Accesses the i-th value as defined by the accessor |
| template<class T> |
| T GetValue(int i); |
| |
| //! Accesses the i-th value as defined by the accessor |
| inline unsigned int GetUInt(int i) |
| { |
| return GetValue<unsigned int>(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<uint8_t> mData; //!< Pointer to the data |
| bool mIsSpecial; //!< Set to true for special cases (e.g. the body buffer) |
| |
| /// \var EncodedRegion_List |
| /// List of encoded regions. |
| std::list<SEncodedRegion*> 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> 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) |
| unsigned int byteStride; //!< The stride, in bytes, between attributes referenced by this accessor. (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; //!<The floating - point aspect ratio of the field of view. (0 = undefined = use the canvas one) |
| float yfov; //!<The floating - point vertical field of view in radians. (required) |
| float zfar; //!<The floating - point distance to the far clipping plane. (required) |
| float znear; //!< The floating - point distance to the near clipping plane. (required) |
| } perspective; |
| |
| struct { |
| float xmag; //! The floating-point horizontal magnification of the view. (required) |
| float ymag; //! The floating-point vertical magnification of the view. (required) |
| float zfar; //! The floating-point distance to the far clipping plane. (required) |
| float znear; //! The floating-point distance to the near clipping plane. (required) |
| } ortographic; |
| } cameraProperties; |
| |
| Camera() {} |
| void Read(Value& obj, Asset& r); |
| }; |
| |
| |
| //! Image data used to create a texture. |
| struct Image : public Object |
| { |
| std::string uri; //! The uri of the image, that can be a file path, a data URI, etc.. (required) |
| |
| Ref<BufferView> bufferView; |
| |
| std::string mimeType; |
| |
| int width, height; |
| |
| private: |
| uint8_t* 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; } |
| |
| inline uint8_t* StealData(); |
| |
| inline void SetData(uint8_t* data, size_t length, Asset& r); |
| }; |
| |
| const vec4 defaultBaseColor = {1, 1, 1, 1}; |
| const vec3 defaultEmissiveFactor = {0, 0, 0}; |
| const vec4 defaultDiffuseFactor = {1, 1, 1, 1}; |
| const vec3 defaultSpecularFactor = {1, 1, 1}; |
| |
| struct TextureInfo |
| { |
| Ref<Texture> texture; |
| unsigned int index; |
| unsigned int texCoord = 0; |
| }; |
| |
| struct NormalTextureInfo : TextureInfo |
| { |
| float scale = 1; |
| }; |
| |
| struct OcclusionTextureInfo : TextureInfo |
| { |
| float strength = 1; |
| }; |
| |
| struct PbrMetallicRoughness |
| { |
| vec4 baseColorFactor; |
| TextureInfo baseColorTexture; |
| TextureInfo metallicRoughnessTexture; |
| float metallicFactor; |
| float roughnessFactor; |
| }; |
| |
| struct PbrSpecularGlossiness |
| { |
| vec4 diffuseFactor; |
| vec3 specularFactor; |
| float glossinessFactor; |
| TextureInfo diffuseTexture; |
| TextureInfo specularGlossinessTexture; |
| |
| PbrSpecularGlossiness() { SetDefaults(); } |
| void SetDefaults(); |
| }; |
| |
| //! The material appearance of a primitive. |
| struct Material : public Object |
| { |
| //PBR metallic roughness properties |
| PbrMetallicRoughness pbrMetallicRoughness; |
| |
| //other basic material properties |
| NormalTextureInfo normalTexture; |
| OcclusionTextureInfo occlusionTexture; |
| TextureInfo emissiveTexture; |
| vec3 emissiveFactor; |
| std::string alphaMode; |
| float alphaCutoff; |
| bool doubleSided; |
| |
| //extension: KHR_materials_pbrSpecularGlossiness |
| Nullable<PbrSpecularGlossiness> pbrSpecularGlossiness; |
| |
| 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< Ref<Accessor> > AccessorList; |
| |
| struct Primitive |
| { |
| PrimitiveMode mode; |
| |
| struct Attributes { |
| AccessorList position, normal, tangent, texcoord, color, joint, jointmatrix, weight; |
| } attributes; |
| |
| Ref<Accessor> indices; |
| |
| Ref<Material> material; |
| }; |
| |
| std::vector<Primitive> primitives; |
| |
| 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 assed where data will be stored. |
| void Read(Value& pJSON_Object, Asset& pAsset_Root); |
| }; |
| |
| struct Node : public Object |
| { |
| std::vector< Ref<Node> > children; |
| std::vector< Ref<Mesh> > meshes; |
| |
| Nullable<mat4> matrix; |
| Nullable<vec3> translation; |
| Nullable<vec4> rotation; |
| Nullable<vec3> scale; |
| |
| Ref<Camera> camera; |
| |
| std::vector< Ref<Node> > skeletons; //!< The ID of skeleton nodes. Each of which is the root of a node hierarchy. |
| Ref<Skin> 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<Node> 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. |
| SamplerMinFilter minFilter; //!< The texture minification filter. |
| SamplerWrap wrapS; //!< The texture wrapping in the S direction. |
| SamplerWrap wrapT; //!< The texture wrapping in the T direction. |
| |
| Sampler() { SetDefaults(); } |
| void Read(Value& obj, Asset& r); |
| void SetDefaults(); |
| }; |
| |
| struct Scene : public Object |
| { |
| std::vector< Ref<Node> > nodes; |
| |
| Scene() {} |
| void Read(Value& obj, Asset& r); |
| }; |
| |
| struct Shader : public Object |
| { |
| Shader() {} |
| void Read(Value& obj, Asset& r); |
| }; |
| |
| struct Skin : public Object |
| { |
| Nullable<mat4> bindShapeMatrix; //!< Floating-point 4x4 transformation matrix stored in column-major order. |
| Ref<Accessor> inverseBindMatrices; //!< The ID of the accessor containing the floating-point 4x4 inverse-bind matrices. |
| std::vector<Ref<Node>> jointNames; //!< Joint names of the joints (nodes with a jointName property) in this skin. |
| std::string name; //!< The user-defined name of this object. |
| |
| Skin() {} |
| void Read(Value& obj, Asset& r); |
| }; |
| |
| //! A texture and its sampler. |
| struct Texture : public Object |
| { |
| Ref<Sampler> sampler; //!< The ID of the sampler used by this texture. (required) |
| Ref<Image> source; //!< The ID of the image used by this texture. (required) |
| |
| //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); |
| }; |
| |
| 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 { |
| int sampler; //!< The index of a sampler in the containing animation's samplers property. |
| |
| struct AnimTarget { |
| Ref<Node> node; //!< The node to animate. |
| std::string path; //!< The name of property of the node to animate ("translation", "rotation", or "scale"). |
| } target; |
| }; |
| |
| struct AnimParameters { |
| Ref<Accessor> TIME; //!< Accessor reference to a buffer storing a array of floating point scalar values. |
| Ref<Accessor> rotation; //!< Accessor reference to a buffer storing a array of four-component floating-point vectors. |
| Ref<Accessor> scale; //!< Accessor reference to a buffer storing a array of three-component floating-point vectors. |
| Ref<Accessor> translation; //!< Accessor reference to a buffer storing a array of three-component floating-point vectors. |
| }; |
| |
| // AnimChannel Channels[3]; //!< Connect the output values of the key-frame animation to a specific node in the hierarchy. |
| // AnimParameters Parameters; //!< The samplers that interpolate between the key-frames. |
| // AnimSampler Samplers[3]; //!< The parameterized inputs representing the key-frame data. |
| |
| std::vector<AnimChannel> Channels; //!< Connect the output values of the key-frame animation to a specific node in the hierarchy. |
| AnimParameters Parameters; //!< The samplers that interpolate between the key-frames. |
| std::vector<AnimSampler> Samplers; //!< The parameterized inputs representing the key-frame data. |
| |
| Animation() {} |
| void Read(Value& obj, Asset& r); |
| |
| //! Get accessor given an animation parameter name. |
| Ref<Accessor> GetAccessor(std::string name) { |
| if (name == "TIME") { |
| return Parameters.TIME; |
| } else if (name == "rotation") { |
| return Parameters.rotation; |
| } else if (name == "scale") { |
| return Parameters.scale; |
| } else if (name == "translation") { |
| return Parameters.translation; |
| } |
| return Ref<Accessor>(); |
| } |
| }; |
| |
| |
| //! Base class for LazyDict that acts as an interface |
| class LazyDictBase |
| { |
| public: |
| virtual ~LazyDictBase() {} |
| |
| virtual void AttachToDocument(Document& doc) = 0; |
| virtual void DetachFromDocument() = 0; |
| |
| virtual void WriteObjects(AssetWriter& writer) = 0; |
| }; |
| |
| |
| template<class T> |
| class LazyDict; |
| |
| //! (Implemented in glTFAssetWriter.h) |
| template<class T> |
| void WriteLazyDict(LazyDict<T>& 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 T> |
| class LazyDict : public LazyDictBase |
| { |
| friend class Asset; |
| friend class AssetWriter; |
| |
| typedef typename std::gltf_unordered_map< unsigned int, unsigned int > Dict; |
| typedef typename std::gltf_unordered_map< std::string, unsigned int > IdDict; |
| |
| std::vector<T*> mObjs; //! The read objects |
| Dict mObjsByOIndex; //! The read objects accessible by original index |
| IdDict 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(); |
| |
| void WriteObjects(AssetWriter& writer) |
| { WriteLazyDict<T>(*this, writer); } |
| |
| Ref<T> Add(T* obj); |
| |
| public: |
| LazyDict(Asset& asset, const char* dictId, const char* extId = 0); |
| ~LazyDict(); |
| |
| Ref<T> Retrieve(unsigned int i); |
| |
| Ref<T> Get(unsigned int i); |
| Ref<T> Get(const char* id); |
| |
| Ref<T> Create(const char* id); |
| Ref<T> Create(const std::string& id) |
| { return Create(id.c_str()); } |
| |
| unsigned int Remove(const char* id); |
| |
| 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. |
| |
| 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 |
| |
| void Read(Document& doc); |
| |
| AssetMetadata() : version("") {} |
| }; |
| |
| // |
| // glTF Asset class |
| // |
| |
| //! Root object for a glTF asset |
| class Asset |
| { |
| typedef std::gltf_unordered_map<std::string, int> IdMap; |
| |
| template<class T> |
| 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<LazyDictBase*> mDicts; |
| |
| IdMap mUsedIds; |
| |
| Ref<Buffer> mBodyBuffer; |
| |
| Asset(Asset&); |
| Asset& operator=(const Asset&); |
| |
| public: |
| |
| //! Keeps info about the enabled extensions |
| struct Extensions |
| { |
| bool KHR_materials_pbrSpecularGlossiness; |
| |
| } extensionsUsed; |
| |
| AssetMetadata asset; |
| |
| |
| // Dictionaries for each type of object |
| |
| LazyDict<Accessor> accessors; |
| LazyDict<Animation> animations; |
| LazyDict<Buffer> buffers; |
| LazyDict<BufferView> bufferViews; |
| LazyDict<Camera> cameras; |
| LazyDict<Image> images; |
| LazyDict<Material> materials; |
| LazyDict<Mesh> meshes; |
| LazyDict<Node> nodes; |
| LazyDict<Sampler> samplers; |
| LazyDict<Scene> scenes; |
| LazyDict<Skin> skins; |
| LazyDict<Texture> textures; |
| |
| Ref<Scene> 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") |
| , samplers (*this, "samplers") |
| , scenes (*this, "scenes") |
| , skins (*this, "skins") |
| , textures (*this, "textures") |
| { |
| memset(&extensionsUsed, 0, sizeof(extensionsUsed)); |
| } |
| |
| //! Main function |
| void Load(const std::string& file, bool isBinary = false); |
| |
| //! Enables binary encoding 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); |
| |
| Ref<Buffer> GetBodyBuffer() |
| { return mBodyBuffer; } |
| |
| private: |
| void ReadBinaryHeader(IOStream& stream, std::vector<char>& sceneData); |
| |
| void ReadExtensionsUsed(Document& doc); |
| |
| IOStream* OpenFile(std::string path, const char* mode, bool absolute = false); |
| }; |
| |
| } |
| |
| // Include the implementation of the methods |
| #include "glTF2Asset.inl" |
| |
| #endif // ASSIMP_BUILD_NO_GLTF_IMPORTER |
| |
| #endif // GLTF2ASSET_H_INC |