From 0357333c8185ef7a4446502cebc9ef239564c67a Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Sun, 15 Mar 2020 10:17:54 +0100 Subject: [PATCH] fix all unittests. --- code/Assbin/AssbinExporter.cpp | 16 +- code/Assbin/AssbinFileWriter.cpp | 597 +++++----- code/Assbin/AssbinLoader.cpp | 6 +- code/glTF/glTFAsset.inl | 16 +- code/glTF/glTFCommon.cpp | 26 +- code/glTF/glTFCommon.h | 344 +++--- code/glTF2/glTF2Asset.h | 1808 ++++++++++++++---------------- code/glTF2/glTF2Asset.inl | 17 +- code/glTF2/glTF2Importer.cpp | 5 +- 9 files changed, 1360 insertions(+), 1475 deletions(-) diff --git a/code/Assbin/AssbinExporter.cpp b/code/Assbin/AssbinExporter.cpp index 496b39d49..0b99afbda 100644 --- a/code/Assbin/AssbinExporter.cpp +++ b/code/Assbin/AssbinExporter.cpp @@ -49,19 +49,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "AssbinFileWriter.h" #include -#include #include +#include namespace Assimp { -void ExportSceneAssbin(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/) { +void ExportSceneAssbin(const char *pFile, IOSystem *pIOSystem, const aiScene *pScene, const ExportProperties * /*pProperties*/) { DumpSceneToAssbin( - pFile, - "\0", // no command(s). - pIOSystem, - pScene, - false, // shortened? - false); // compressed? + pFile, + "\0", // no command(s). + pIOSystem, + pScene, + false, // shortened? + false); // compressed? } } // end of namespace Assimp diff --git a/code/Assbin/AssbinFileWriter.cpp b/code/Assbin/AssbinFileWriter.cpp index b756adfa0..8f302b919 100644 --- a/code/Assbin/AssbinFileWriter.cpp +++ b/code/Assbin/AssbinFileWriter.cpp @@ -48,15 +48,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "Common/assbin_chunks.h" #include "PostProcessing/ProcessHelper.h" -#include -#include -#include #include +#include +#include +#include #ifdef ASSIMP_BUILD_NO_OWN_ZLIB -# include +#include #else -# include "../contrib/zlib/zlib.h" +#include "../contrib/zlib/zlib.h" #endif #include @@ -67,34 +67,32 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace Assimp { template -size_t Write(IOStream * stream, const T& v) { - return stream->Write( &v, sizeof(T), 1 ); +size_t Write(IOStream *stream, const T &v) { + return stream->Write(&v, sizeof(T), 1); } // ----------------------------------------------------------------------------------- // Serialize an aiString template <> -inline -size_t Write(IOStream * stream, const aiString& s) { +inline size_t Write(IOStream *stream, const aiString &s) { const size_t s2 = (uint32_t)s.length; - stream->Write(&s,4,1); - stream->Write(s.data,s2,1); + stream->Write(&s, 4, 1); + stream->Write(s.data, s2, 1); - return s2+4; + return s2 + 4; } // ----------------------------------------------------------------------------------- // Serialize an unsigned int as uint32_t template <> -inline -size_t Write(IOStream * stream, const unsigned int& w) { +inline size_t Write(IOStream *stream, const unsigned int &w) { const uint32_t t = (uint32_t)w; if (w > t) { // this shouldn't happen, integers in Assimp data structures never exceed 2^32 throw DeadlyExportError("loss of data due to 64 -> 32 bit integer conversion"); } - stream->Write(&t,4,1); + stream->Write(&t, 4, 1); return 4; } @@ -102,10 +100,9 @@ size_t Write(IOStream * stream, const unsigned int& w) { // ----------------------------------------------------------------------------------- // Serialize an unsigned int as uint16_t template <> -inline -size_t Write(IOStream * stream, const uint16_t& w) { - static_assert(sizeof(uint16_t)==2, "sizeof(uint16_t)==2"); - stream->Write(&w,2,1); +inline size_t Write(IOStream *stream, const uint16_t &w) { + static_assert(sizeof(uint16_t) == 2, "sizeof(uint16_t)==2"); + stream->Write(&w, 2, 1); return 2; } @@ -113,10 +110,9 @@ size_t Write(IOStream * stream, const uint16_t& w) { // ----------------------------------------------------------------------------------- // Serialize a float template <> -inline -size_t Write(IOStream * stream, const float& f) { - static_assert(sizeof(float)==4, "sizeof(float)==4"); - stream->Write(&f,4,1); +inline size_t Write(IOStream *stream, const float &f) { + static_assert(sizeof(float) == 4, "sizeof(float)==4"); + stream->Write(&f, 4, 1); return 4; } @@ -124,10 +120,9 @@ size_t Write(IOStream * stream, const float& f) { // ----------------------------------------------------------------------------------- // Serialize a double template <> -inline -size_t Write(IOStream * stream, const double& f) { - static_assert(sizeof(double)==8, "sizeof(double)==8"); - stream->Write(&f,8,1); +inline size_t Write(IOStream *stream, const double &f) { + static_assert(sizeof(double) == 8, "sizeof(double)==8"); + stream->Write(&f, 8, 1); return 8; } @@ -135,11 +130,10 @@ size_t Write(IOStream * stream, const double& f) { // ----------------------------------------------------------------------------------- // Serialize a vec3 template <> -inline -size_t Write(IOStream * stream, const aiVector3D& v) { - size_t t = Write(stream,v.x); - t += Write(stream,v.y); - t += Write(stream,v.z); +inline size_t Write(IOStream *stream, const aiVector3D &v) { + size_t t = Write(stream, v.x); + t += Write(stream, v.y); + t += Write(stream, v.z); return t; } @@ -147,11 +141,10 @@ size_t Write(IOStream * stream, const aiVector3D& v) { // ----------------------------------------------------------------------------------- // Serialize a color value template <> -inline -size_t Write(IOStream * stream, const aiColor3D& v) { - size_t t = Write(stream,v.r); - t += Write(stream,v.g); - t += Write(stream,v.b); +inline size_t Write(IOStream *stream, const aiColor3D &v) { + size_t t = Write(stream, v.r); + t += Write(stream, v.g); + t += Write(stream, v.b); return t; } @@ -159,12 +152,11 @@ size_t Write(IOStream * stream, const aiColor3D& v) { // ----------------------------------------------------------------------------------- // Serialize a color value template <> -inline -size_t Write(IOStream * stream, const aiColor4D& v) { - size_t t = Write(stream,v.r); - t += Write(stream,v.g); - t += Write(stream,v.b); - t += Write(stream,v.a); +inline size_t Write(IOStream *stream, const aiColor4D &v) { + size_t t = Write(stream, v.r); + t += Write(stream, v.g); + t += Write(stream, v.b); + t += Write(stream, v.a); return t; } @@ -172,12 +164,11 @@ size_t Write(IOStream * stream, const aiColor4D& v) { // ----------------------------------------------------------------------------------- // Serialize a quaternion template <> -inline -size_t Write(IOStream * stream, const aiQuaternion& v) { - size_t t = Write(stream,v.w); - t += Write(stream,v.x); - t += Write(stream,v.y); - t += Write(stream,v.z); +inline size_t Write(IOStream *stream, const aiQuaternion &v) { + size_t t = Write(stream, v.w); + t += Write(stream, v.x); + t += Write(stream, v.y); + t += Write(stream, v.z); ai_assert(t == 16); return 16; @@ -186,21 +177,19 @@ size_t Write(IOStream * stream, const aiQuaternion& v) { // ----------------------------------------------------------------------------------- // Serialize a vertex weight template <> -inline -size_t Write(IOStream * stream, const aiVertexWeight& v) { - size_t t = Write(stream,v.mVertexId); +inline size_t Write(IOStream *stream, const aiVertexWeight &v) { + size_t t = Write(stream, v.mVertexId); - return t+Write(stream,v.mWeight); + return t + Write(stream, v.mWeight); } // ----------------------------------------------------------------------------------- // Serialize a mat4x4 template <> -inline -size_t Write(IOStream * stream, const aiMatrix4x4& m) { - for (unsigned int i = 0; i < 4;++i) { - for (unsigned int i2 = 0; i2 < 4;++i2) { - Write(stream,m[i][i2]); +inline size_t Write(IOStream *stream, const aiMatrix4x4 &m) { + for (unsigned int i = 0; i < 4; ++i) { + for (unsigned int i2 = 0; i2 < 4; ++i2) { + Write(stream, m[i][i2]); } } @@ -210,38 +199,35 @@ size_t Write(IOStream * stream, const aiMatrix4x4& m) { // ----------------------------------------------------------------------------------- // Serialize an aiVectorKey template <> -inline -size_t Write(IOStream * stream, const aiVectorKey& v) { - const size_t t = Write(stream,v.mTime); - return t + Write(stream,v.mValue); +inline size_t Write(IOStream *stream, const aiVectorKey &v) { + const size_t t = Write(stream, v.mTime); + return t + Write(stream, v.mValue); } // ----------------------------------------------------------------------------------- // Serialize an aiQuatKey template <> -inline -size_t Write(IOStream * stream, const aiQuatKey& v) { - const size_t t = Write(stream,v.mTime); - return t + Write(stream,v.mValue); +inline size_t Write(IOStream *stream, const aiQuatKey &v) { + const size_t t = Write(stream, v.mTime); + return t + Write(stream, v.mValue); } template -inline -size_t WriteBounds(IOStream * stream, const T* in, unsigned int size) { +inline size_t WriteBounds(IOStream *stream, const T *in, unsigned int size) { T minc, maxc; - ArrayBounds(in,size,minc,maxc); + ArrayBounds(in, size, minc, maxc); - const size_t t = Write(stream,minc); - return t + Write(stream,maxc); + const size_t t = Write(stream, minc); + return t + Write(stream, maxc); } // We use this to write out non-byte arrays so that we write using the specializations. // This way we avoid writing out extra bytes that potentially come from struct alignment. template -inline -size_t WriteArray(IOStream * stream, const T* in, unsigned int size) { +inline size_t WriteArray(IOStream *stream, const T *in, unsigned int size) { size_t n = 0; - for (unsigned int i=0; i(stream,in[i]); + for (unsigned int i = 0; i < size; i++) + n += Write(stream, in[i]); return n; } @@ -256,26 +242,23 @@ size_t WriteArray(IOStream * stream, const T* in, unsigned int size) { * and the chunk contents to the container stream. This allows relatively easy chunk * chunk construction, even recursively. */ -class AssbinChunkWriter : public IOStream -{ +class AssbinChunkWriter : public IOStream { private: - - uint8_t* buffer; + uint8_t *buffer; uint32_t magic; - IOStream * container; + IOStream *container; size_t cur_size, cursor, initial; private: // ------------------------------------------------------------------- - void Grow(size_t need = 0) - { - size_t new_size = std::max(initial, std::max( need, cur_size+(cur_size>>1) )); + void Grow(size_t need = 0) { + size_t new_size = std::max(initial, std::max(need, cur_size + (cur_size >> 1))); - const uint8_t* const old = buffer; + const uint8_t *const old = buffer; buffer = new uint8_t[new_size]; if (old) { - memcpy(buffer,old,cur_size); + memcpy(buffer, old, cur_size); delete[] old; } @@ -283,26 +266,29 @@ private: } public: - - AssbinChunkWriter( IOStream * container, uint32_t magic, size_t initial = 4096) - : buffer(NULL), magic(magic), container(container), cur_size(0), cursor(0), initial(initial) - { + AssbinChunkWriter(IOStream *container, uint32_t magic, size_t initial = 4096) : + buffer(NULL), + magic(magic), + container(container), + cur_size(0), + cursor(0), + initial(initial) { + // empty } - virtual ~AssbinChunkWriter() - { + virtual ~AssbinChunkWriter() { if (container) { - container->Write( &magic, sizeof(uint32_t), 1 ); - container->Write( &cursor, sizeof(uint32_t), 1 ); - container->Write( buffer, 1, cursor ); + container->Write(&magic, sizeof(uint32_t), 1); + container->Write(&cursor, sizeof(uint32_t), 1); + container->Write(buffer, 1, cursor); } if (buffer) delete[] buffer; } - void * GetBufferPointer() { return buffer; } + void *GetBufferPointer() { return buffer; } // ------------------------------------------------------------------- - virtual size_t Read(void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) { + virtual size_t Read(void * /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) { return 0; } virtual aiReturn Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/) { @@ -320,18 +306,17 @@ public: } // ------------------------------------------------------------------- - virtual size_t Write(const void* pvBuffer, size_t pSize, size_t pCount) { + virtual size_t Write(const void *pvBuffer, size_t pSize, size_t pCount) { pSize *= pCount; if (cursor + pSize > cur_size) { Grow(cursor + pSize); } - memcpy(buffer+cursor, pvBuffer, pSize); + memcpy(buffer + cursor, pvBuffer, pSize); cursor += pSize; return pCount; } - }; // ---------------------------------------------------------------------------------- @@ -340,63 +325,61 @@ public: * * This class writes an .assbin file, and is responsible for the file layout. */ -class AssbinFileWriter -{ +class AssbinFileWriter { private: bool shortened; bool compressed; protected: // ----------------------------------------------------------------------------------- - void WriteBinaryNode( IOStream * container, const aiNode* node) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AINODE ); + void WriteBinaryNode(IOStream *container, const aiNode *node) { + AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AINODE); unsigned int nb_metadata = (node->mMetaData != NULL ? node->mMetaData->mNumProperties : 0); - Write(&chunk,node->mName); - Write(&chunk,node->mTransformation); - Write(&chunk,node->mNumChildren); - Write(&chunk,node->mNumMeshes); - Write(&chunk,nb_metadata); + Write(&chunk, node->mName); + Write(&chunk, node->mTransformation); + Write(&chunk, node->mNumChildren); + Write(&chunk, node->mNumMeshes); + Write(&chunk, nb_metadata); - for (unsigned int i = 0; i < node->mNumMeshes;++i) { - Write(&chunk,node->mMeshes[i]); + for (unsigned int i = 0; i < node->mNumMeshes; ++i) { + Write(&chunk, node->mMeshes[i]); } - for (unsigned int i = 0; i < node->mNumChildren;++i) { - WriteBinaryNode( &chunk, node->mChildren[i] ); + for (unsigned int i = 0; i < node->mNumChildren; ++i) { + WriteBinaryNode(&chunk, node->mChildren[i]); } for (unsigned int i = 0; i < nb_metadata; ++i) { - const aiString& key = node->mMetaData->mKeys[i]; + const aiString &key = node->mMetaData->mKeys[i]; aiMetadataType type = node->mMetaData->mValues[i].mType; - void* value = node->mMetaData->mValues[i].mData; + void *value = node->mMetaData->mValues[i].mData; Write(&chunk, key); - Write(&chunk, (uint16_t) type); + Write(&chunk, (uint16_t)type); switch (type) { case AI_BOOL: - Write(&chunk, *((bool*) value)); + Write(&chunk, *((bool *)value)); break; case AI_INT32: - Write(&chunk, *((int32_t*) value)); + Write(&chunk, *((int32_t *)value)); break; case AI_UINT64: - Write(&chunk, *((uint64_t*) value)); + Write(&chunk, *((uint64_t *)value)); break; case AI_FLOAT: - Write(&chunk, *((float*) value)); + Write(&chunk, *((float *)value)); break; case AI_DOUBLE: - Write(&chunk, *((double*) value)); + Write(&chunk, *((double *)value)); break; case AI_AISTRING: - Write(&chunk, *((aiString*) value)); + Write(&chunk, *((aiString *)value)); break; case AI_AIVECTOR3D: - Write(&chunk, *((aiVector3D*) value)); + Write(&chunk, *((aiVector3D *)value)); break; #ifdef SWIG case FORCE_32BIT: @@ -408,53 +391,49 @@ protected: } // ----------------------------------------------------------------------------------- - void WriteBinaryTexture(IOStream * container, const aiTexture* tex) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AITEXTURE ); + void WriteBinaryTexture(IOStream *container, const aiTexture *tex) { + AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AITEXTURE); - Write(&chunk,tex->mWidth); - Write(&chunk,tex->mHeight); + Write(&chunk, tex->mWidth); + Write(&chunk, tex->mHeight); // Write the texture format, but don't include the null terminator. - chunk.Write( tex->achFormatHint, sizeof(char), HINTMAXTEXTURELEN - 1 ); + chunk.Write(tex->achFormatHint, sizeof(char), HINTMAXTEXTURELEN - 1); - if(!shortened) { + if (!shortened) { if (!tex->mHeight) { - chunk.Write(tex->pcData,1,tex->mWidth); - } - else { - chunk.Write(tex->pcData,1,tex->mWidth*tex->mHeight*4); + chunk.Write(tex->pcData, 1, tex->mWidth); + } else { + chunk.Write(tex->pcData, 1, tex->mWidth * tex->mHeight * 4); } } - } // ----------------------------------------------------------------------------------- - void WriteBinaryBone(IOStream * container, const aiBone* b) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIBONE ); + void WriteBinaryBone(IOStream *container, const aiBone *b) { + AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AIBONE); - Write(&chunk,b->mName); - Write(&chunk,b->mNumWeights); - Write(&chunk,b->mOffsetMatrix); + Write(&chunk, b->mName); + Write(&chunk, b->mNumWeights); + Write(&chunk, b->mOffsetMatrix); // for the moment we write dumb min/max values for the bones, too. // maybe I'll add a better, hash-like solution later if (shortened) { - WriteBounds(&chunk,b->mWeights,b->mNumWeights); + WriteBounds(&chunk, b->mWeights, b->mNumWeights); } // else write as usual - else WriteArray(&chunk,b->mWeights,b->mNumWeights); + else + WriteArray(&chunk, b->mWeights, b->mNumWeights); } // ----------------------------------------------------------------------------------- - void WriteBinaryMesh(IOStream * container, const aiMesh* mesh) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMESH ); + void WriteBinaryMesh(IOStream *container, const aiMesh *mesh) { + AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AIMESH); - Write(&chunk,mesh->mPrimitiveTypes); - Write(&chunk,mesh->mNumVertices); - Write(&chunk,mesh->mNumFaces); - Write(&chunk,mesh->mNumBones); - Write(&chunk,mesh->mMaterialIndex); + Write(&chunk, mesh->mPrimitiveTypes); + Write(&chunk, mesh->mNumVertices); + Write(&chunk, mesh->mNumFaces); + Write(&chunk, mesh->mNumBones); + Write(&chunk, mesh->mMaterialIndex); // first of all, write bits for all existent vertex components unsigned int c = 0; @@ -467,63 +446,67 @@ protected: if (mesh->mTangents && mesh->mBitangents) { c |= ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS; } - for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) { + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++n) { if (!mesh->mTextureCoords[n]) { break; } c |= ASSBIN_MESH_HAS_TEXCOORD(n); } - for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) { + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS; ++n) { if (!mesh->mColors[n]) { break; } c |= ASSBIN_MESH_HAS_COLOR(n); } - Write(&chunk,c); + Write(&chunk, c); aiVector3D minVec, maxVec; if (mesh->mVertices) { if (shortened) { - WriteBounds(&chunk,mesh->mVertices,mesh->mNumVertices); + WriteBounds(&chunk, mesh->mVertices, mesh->mNumVertices); } // else write as usual - else WriteArray(&chunk,mesh->mVertices,mesh->mNumVertices); + else + WriteArray(&chunk, mesh->mVertices, mesh->mNumVertices); } if (mesh->mNormals) { if (shortened) { - WriteBounds(&chunk,mesh->mNormals,mesh->mNumVertices); + WriteBounds(&chunk, mesh->mNormals, mesh->mNumVertices); } // else write as usual - else WriteArray(&chunk,mesh->mNormals,mesh->mNumVertices); + else + WriteArray(&chunk, mesh->mNormals, mesh->mNumVertices); } if (mesh->mTangents && mesh->mBitangents) { if (shortened) { - WriteBounds(&chunk,mesh->mTangents,mesh->mNumVertices); - WriteBounds(&chunk,mesh->mBitangents,mesh->mNumVertices); + WriteBounds(&chunk, mesh->mTangents, mesh->mNumVertices); + WriteBounds(&chunk, mesh->mBitangents, mesh->mNumVertices); } // else write as usual else { - WriteArray(&chunk,mesh->mTangents,mesh->mNumVertices); - WriteArray(&chunk,mesh->mBitangents,mesh->mNumVertices); + WriteArray(&chunk, mesh->mTangents, mesh->mNumVertices); + WriteArray(&chunk, mesh->mBitangents, mesh->mNumVertices); } } - for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) { + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS; ++n) { if (!mesh->mColors[n]) break; if (shortened) { - WriteBounds(&chunk,mesh->mColors[n],mesh->mNumVertices); + WriteBounds(&chunk, mesh->mColors[n], mesh->mNumVertices); } // else write as usual - else WriteArray(&chunk,mesh->mColors[n],mesh->mNumVertices); + else + WriteArray(&chunk, mesh->mColors[n], mesh->mNumVertices); } - for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) { + for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++n) { if (!mesh->mTextureCoords[n]) break; // write number of UV components - Write(&chunk,mesh->mNumUVComponents[n]); + Write(&chunk, mesh->mNumUVComponents[n]); if (shortened) { - WriteBounds(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices); + WriteBounds(&chunk, mesh->mTextureCoords[n], mesh->mNumVertices); } // else write as usual - else WriteArray(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices); + else + WriteArray(&chunk, mesh->mTextureCoords[n], mesh->mNumVertices); } // write faces. There are no floating-point calculations involved @@ -532,234 +515,223 @@ protected: // using Assimp's standard hashing function. if (shortened) { unsigned int processed = 0; - for (unsigned int job;(job = std::min(mesh->mNumFaces-processed,512u));processed += job) { + for (unsigned int job; (job = std::min(mesh->mNumFaces - processed, 512u)); processed += job) { uint32_t hash = 0; - for (unsigned int a = 0; a < job;++a) { + for (unsigned int a = 0; a < job; ++a) { - const aiFace& f = mesh->mFaces[processed+a]; + const aiFace &f = mesh->mFaces[processed + a]; uint32_t tmp = f.mNumIndices; - hash = SuperFastHash(reinterpret_cast(&tmp),sizeof tmp,hash); + hash = SuperFastHash(reinterpret_cast(&tmp), sizeof tmp, hash); for (unsigned int i = 0; i < f.mNumIndices; ++i) { static_assert(AI_MAX_VERTICES <= 0xffffffff, "AI_MAX_VERTICES <= 0xffffffff"); - tmp = static_cast( f.mIndices[i] ); - hash = SuperFastHash(reinterpret_cast(&tmp),sizeof tmp,hash); + tmp = static_cast(f.mIndices[i]); + hash = SuperFastHash(reinterpret_cast(&tmp), sizeof tmp, hash); } } - Write(&chunk,hash); + Write(&chunk, hash); } - } - else // else write as usual + } else // else write as usual { // if there are less than 2^16 vertices, we can simply use 16 bit integers ... - for (unsigned int i = 0; i < mesh->mNumFaces;++i) { - const aiFace& f = mesh->mFaces[i]; + for (unsigned int i = 0; i < mesh->mNumFaces; ++i) { + const aiFace &f = mesh->mFaces[i]; static_assert(AI_MAX_FACE_INDICES <= 0xffff, "AI_MAX_FACE_INDICES <= 0xffff"); - Write(&chunk,f.mNumIndices); + Write(&chunk, static_cast(f.mNumIndices)); - for (unsigned int a = 0; a < f.mNumIndices;++a) { - if (mesh->mNumVertices < (1u<<16)) { - Write(&chunk,f.mIndices[a]); - } else { - Write(&chunk, f.mIndices[a]); - } + for (unsigned int a = 0; a < f.mNumIndices; ++a) { + if (mesh->mNumVertices < (1u << 16)) { + Write(&chunk, static_cast(f.mIndices[a])); + } else { + Write(&chunk, f.mIndices[a]); + } } } } // write bones if (mesh->mNumBones) { - for (unsigned int a = 0; a < mesh->mNumBones;++a) { - const aiBone* b = mesh->mBones[a]; - WriteBinaryBone(&chunk,b); + for (unsigned int a = 0; a < mesh->mNumBones; ++a) { + const aiBone *b = mesh->mBones[a]; + WriteBinaryBone(&chunk, b); } } } // ----------------------------------------------------------------------------------- - void WriteBinaryMaterialProperty(IOStream * container, const aiMaterialProperty* prop) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMATERIALPROPERTY ); + void WriteBinaryMaterialProperty(IOStream *container, const aiMaterialProperty *prop) { + AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AIMATERIALPROPERTY); - Write(&chunk,prop->mKey); - Write(&chunk,prop->mSemantic); - Write(&chunk,prop->mIndex); + Write(&chunk, prop->mKey); + Write(&chunk, prop->mSemantic); + Write(&chunk, prop->mIndex); - Write(&chunk,prop->mDataLength); - Write(&chunk,(unsigned int)prop->mType); - chunk.Write(prop->mData,1,prop->mDataLength); + Write(&chunk, prop->mDataLength); + Write(&chunk, (unsigned int)prop->mType); + chunk.Write(prop->mData, 1, prop->mDataLength); } // ----------------------------------------------------------------------------------- - void WriteBinaryMaterial(IOStream * container, const aiMaterial* mat) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMATERIAL); + void WriteBinaryMaterial(IOStream *container, const aiMaterial *mat) { + AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AIMATERIAL); - Write(&chunk,mat->mNumProperties); - for (unsigned int i = 0; i < mat->mNumProperties;++i) { - WriteBinaryMaterialProperty( &chunk, mat->mProperties[i]); + Write(&chunk, mat->mNumProperties); + for (unsigned int i = 0; i < mat->mNumProperties; ++i) { + WriteBinaryMaterialProperty(&chunk, mat->mProperties[i]); } } // ----------------------------------------------------------------------------------- - void WriteBinaryNodeAnim(IOStream * container, const aiNodeAnim* nd) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AINODEANIM ); + void WriteBinaryNodeAnim(IOStream *container, const aiNodeAnim *nd) { + AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AINODEANIM); - Write(&chunk,nd->mNodeName); - Write(&chunk,nd->mNumPositionKeys); - Write(&chunk,nd->mNumRotationKeys); - Write(&chunk,nd->mNumScalingKeys); - Write(&chunk,nd->mPreState); - Write(&chunk,nd->mPostState); + Write(&chunk, nd->mNodeName); + Write(&chunk, nd->mNumPositionKeys); + Write(&chunk, nd->mNumRotationKeys); + Write(&chunk, nd->mNumScalingKeys); + Write(&chunk, nd->mPreState); + Write(&chunk, nd->mPostState); if (nd->mPositionKeys) { if (shortened) { - WriteBounds(&chunk,nd->mPositionKeys,nd->mNumPositionKeys); + WriteBounds(&chunk, nd->mPositionKeys, nd->mNumPositionKeys); } // else write as usual - else WriteArray(&chunk,nd->mPositionKeys,nd->mNumPositionKeys); + else + WriteArray(&chunk, nd->mPositionKeys, nd->mNumPositionKeys); } if (nd->mRotationKeys) { if (shortened) { - WriteBounds(&chunk,nd->mRotationKeys,nd->mNumRotationKeys); + WriteBounds(&chunk, nd->mRotationKeys, nd->mNumRotationKeys); } // else write as usual - else WriteArray(&chunk,nd->mRotationKeys,nd->mNumRotationKeys); + else + WriteArray(&chunk, nd->mRotationKeys, nd->mNumRotationKeys); } if (nd->mScalingKeys) { if (shortened) { - WriteBounds(&chunk,nd->mScalingKeys,nd->mNumScalingKeys); + WriteBounds(&chunk, nd->mScalingKeys, nd->mNumScalingKeys); } // else write as usual - else WriteArray(&chunk,nd->mScalingKeys,nd->mNumScalingKeys); - } - } - - - // ----------------------------------------------------------------------------------- - void WriteBinaryAnim( IOStream * container, const aiAnimation* anim ) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIANIMATION ); - - Write(&chunk,anim->mName); - Write(&chunk,anim->mDuration); - Write(&chunk,anim->mTicksPerSecond); - Write(&chunk,anim->mNumChannels); - - for (unsigned int a = 0; a < anim->mNumChannels;++a) { - const aiNodeAnim* nd = anim->mChannels[a]; - WriteBinaryNodeAnim(&chunk,nd); + else + WriteArray(&chunk, nd->mScalingKeys, nd->mNumScalingKeys); } } // ----------------------------------------------------------------------------------- - void WriteBinaryLight( IOStream * container, const aiLight* l ) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AILIGHT ); + void WriteBinaryAnim(IOStream *container, const aiAnimation *anim) { + AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AIANIMATION); - Write(&chunk,l->mName); - Write(&chunk,l->mType); + Write(&chunk, anim->mName); + Write(&chunk, anim->mDuration); + Write(&chunk, anim->mTicksPerSecond); + Write(&chunk, anim->mNumChannels); + + for (unsigned int a = 0; a < anim->mNumChannels; ++a) { + const aiNodeAnim *nd = anim->mChannels[a]; + WriteBinaryNodeAnim(&chunk, nd); + } + } + + // ----------------------------------------------------------------------------------- + void WriteBinaryLight(IOStream *container, const aiLight *l) { + AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AILIGHT); + + Write(&chunk, l->mName); + Write(&chunk, l->mType); if (l->mType != aiLightSource_DIRECTIONAL) { - Write(&chunk,l->mAttenuationConstant); - Write(&chunk,l->mAttenuationLinear); - Write(&chunk,l->mAttenuationQuadratic); + Write(&chunk, l->mAttenuationConstant); + Write(&chunk, l->mAttenuationLinear); + Write(&chunk, l->mAttenuationQuadratic); } - Write(&chunk,l->mColorDiffuse); - Write(&chunk,l->mColorSpecular); - Write(&chunk,l->mColorAmbient); + Write(&chunk, l->mColorDiffuse); + Write(&chunk, l->mColorSpecular); + Write(&chunk, l->mColorAmbient); if (l->mType == aiLightSource_SPOT) { - Write(&chunk,l->mAngleInnerCone); - Write(&chunk,l->mAngleOuterCone); + Write(&chunk, l->mAngleInnerCone); + Write(&chunk, l->mAngleOuterCone); } - } // ----------------------------------------------------------------------------------- - void WriteBinaryCamera( IOStream * container, const aiCamera* cam ) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AICAMERA ); + void WriteBinaryCamera(IOStream *container, const aiCamera *cam) { + AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AICAMERA); - Write(&chunk,cam->mName); - Write(&chunk,cam->mPosition); - Write(&chunk,cam->mLookAt); - Write(&chunk,cam->mUp); - Write(&chunk,cam->mHorizontalFOV); - Write(&chunk,cam->mClipPlaneNear); - Write(&chunk,cam->mClipPlaneFar); - Write(&chunk,cam->mAspect); + Write(&chunk, cam->mName); + Write(&chunk, cam->mPosition); + Write(&chunk, cam->mLookAt); + Write(&chunk, cam->mUp); + Write(&chunk, cam->mHorizontalFOV); + Write(&chunk, cam->mClipPlaneNear); + Write(&chunk, cam->mClipPlaneFar); + Write(&chunk, cam->mAspect); } // ----------------------------------------------------------------------------------- - void WriteBinaryScene( IOStream * container, const aiScene* scene) - { - AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AISCENE ); + void WriteBinaryScene(IOStream *container, const aiScene *scene) { + AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AISCENE); // basic scene information - Write(&chunk,scene->mFlags); - Write(&chunk,scene->mNumMeshes); - Write(&chunk,scene->mNumMaterials); - Write(&chunk,scene->mNumAnimations); - Write(&chunk,scene->mNumTextures); - Write(&chunk,scene->mNumLights); - Write(&chunk,scene->mNumCameras); + Write(&chunk, scene->mFlags); + Write(&chunk, scene->mNumMeshes); + Write(&chunk, scene->mNumMaterials); + Write(&chunk, scene->mNumAnimations); + Write(&chunk, scene->mNumTextures); + Write(&chunk, scene->mNumLights); + Write(&chunk, scene->mNumCameras); // write node graph - WriteBinaryNode( &chunk, scene->mRootNode ); + WriteBinaryNode(&chunk, scene->mRootNode); // write all meshes - for (unsigned int i = 0; i < scene->mNumMeshes;++i) { - const aiMesh* mesh = scene->mMeshes[i]; - WriteBinaryMesh( &chunk,mesh); + for (unsigned int i = 0; i < scene->mNumMeshes; ++i) { + const aiMesh *mesh = scene->mMeshes[i]; + WriteBinaryMesh(&chunk, mesh); } // write materials - for (unsigned int i = 0; i< scene->mNumMaterials; ++i) { - const aiMaterial* mat = scene->mMaterials[i]; - WriteBinaryMaterial(&chunk,mat); + for (unsigned int i = 0; i < scene->mNumMaterials; ++i) { + const aiMaterial *mat = scene->mMaterials[i]; + WriteBinaryMaterial(&chunk, mat); } // write all animations - for (unsigned int i = 0; i < scene->mNumAnimations;++i) { - const aiAnimation* anim = scene->mAnimations[i]; - WriteBinaryAnim(&chunk,anim); + for (unsigned int i = 0; i < scene->mNumAnimations; ++i) { + const aiAnimation *anim = scene->mAnimations[i]; + WriteBinaryAnim(&chunk, anim); } - // write all textures - for (unsigned int i = 0; i < scene->mNumTextures;++i) { - const aiTexture* mesh = scene->mTextures[i]; - WriteBinaryTexture(&chunk,mesh); + for (unsigned int i = 0; i < scene->mNumTextures; ++i) { + const aiTexture *mesh = scene->mTextures[i]; + WriteBinaryTexture(&chunk, mesh); } // write lights - for (unsigned int i = 0; i < scene->mNumLights;++i) { - const aiLight* l = scene->mLights[i]; - WriteBinaryLight(&chunk,l); + for (unsigned int i = 0; i < scene->mNumLights; ++i) { + const aiLight *l = scene->mLights[i]; + WriteBinaryLight(&chunk, l); } // write cameras - for (unsigned int i = 0; i < scene->mNumCameras;++i) { - const aiCamera* cam = scene->mCameras[i]; - WriteBinaryCamera(&chunk,cam); + for (unsigned int i = 0; i < scene->mNumCameras; ++i) { + const aiCamera *cam = scene->mCameras[i]; + WriteBinaryCamera(&chunk, cam); } - } public: - AssbinFileWriter(bool shortened, bool compressed) - : shortened(shortened), compressed(compressed) - { + AssbinFileWriter(bool shortened, bool compressed) : + shortened(shortened), compressed(compressed) { } // ----------------------------------------------------------------------------------- // Write a binary model dump - void WriteBinaryDump(const char* pFile, const char* cmd, IOSystem* pIOSystem, const aiScene* pScene) - { - IOStream * out = pIOSystem->Open( pFile, "wb" ); + void WriteBinaryDump(const char *pFile, const char *cmd, IOSystem *pIOSystem, const aiScene *pScene) { + IOStream *out = pIOSystem->Open(pFile, "wb"); if (!out) throw std::runtime_error("Unable to open output file " + std::string(pFile) + '\n'); @@ -773,10 +745,10 @@ public: try { time_t tt = time(NULL); #if _WIN32 - tm* p = gmtime(&tt); + tm *p = gmtime(&tt); #else struct tm now; - tm* p = gmtime_r(&tt, &now); + tm *p = gmtime_r(&tt, &now); #endif // header @@ -798,14 +770,14 @@ public: Write(out, compressed); // == 20 bytes - char buff[256] = {0}; + char buff[256] = { 0 }; ai_snprintf(buff, 256, "%s", pFile); out->Write(buff, sizeof(char), 256); memset(buff, 0, sizeof(buff)); ai_snprintf(buff, 128, "%s", cmd); out->Write(buff, sizeof(char), 128); - + // leave 64 bytes free for future extensions memset(buff, 0xcd, 64); out->Write(buff, sizeof(char), 64); @@ -816,18 +788,16 @@ public: // Up to here the data is uncompressed. For compressed files, the rest // is compressed using standard DEFLATE from zlib. - if (compressed) - { + if (compressed) { AssbinChunkWriter uncompressedStream(NULL, 0); WriteBinaryScene(&uncompressedStream, pScene); uLongf uncompressedSize = static_cast(uncompressedStream.Tell()); uLongf compressedSize = (uLongf)compressBound(uncompressedSize); - uint8_t* compressedBuffer = new uint8_t[compressedSize]; + uint8_t *compressedBuffer = new uint8_t[compressedSize]; - int res = compress2(compressedBuffer, &compressedSize, (const Bytef*)uncompressedStream.GetBufferPointer(), uncompressedSize, 9); - if (res != Z_OK) - { + int res = compress2(compressedBuffer, &compressedSize, (const Bytef *)uncompressedStream.GetBufferPointer(), uncompressedSize, 9); + if (res != Z_OK) { delete[] compressedBuffer; throw DeadlyExportError("Compression failed."); } @@ -836,15 +806,12 @@ public: out->Write(compressedBuffer, sizeof(char), compressedSize); delete[] compressedBuffer; - } - else - { + } else { WriteBinaryScene(out, pScene); } CloseIOStream(); - } - catch (...) { + } catch (...) { CloseIOStream(); throw; } @@ -852,8 +819,8 @@ public: }; void DumpSceneToAssbin( - const char* pFile, const char* cmd, IOSystem* pIOSystem, - const aiScene* pScene, bool shortened, bool compressed) { + const char *pFile, const char *cmd, IOSystem *pIOSystem, + const aiScene *pScene, bool shortened, bool compressed) { AssbinFileWriter fileWriter(shortened, compressed); fileWriter.WriteBinaryDump(pFile, cmd, pIOSystem, pScene); } diff --git a/code/Assbin/AssbinLoader.cpp b/code/Assbin/AssbinLoader.cpp index 3ca3b247c..4293cae29 100644 --- a/code/Assbin/AssbinLoader.cpp +++ b/code/Assbin/AssbinLoader.cpp @@ -5,8 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2020, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -105,8 +103,9 @@ template T Read(IOStream *stream) { T t; size_t res = stream->Read(&t, sizeof(T), 1); - if (res != 1) + if (res != 1) { throw DeadlyImportError("Unexpected EOF"); + } return t; } @@ -313,6 +312,7 @@ void AssbinImporter::ReadBinaryBone(IOStream *stream, aiBone *b) { static bool fitsIntoUI16(unsigned int mNumVertices) { return (mNumVertices < (1u << 16)); } + // ----------------------------------------------------------------------------------- void AssbinImporter::ReadBinaryMesh(IOStream *stream, aiMesh *mesh) { if (Read(stream) != ASSBIN_CHUNK_AIMESH) diff --git a/code/glTF/glTFAsset.inl b/code/glTF/glTFAsset.inl index b28e07981..0a4b4b24c 100644 --- a/code/glTF/glTFAsset.inl +++ b/code/glTF/glTFAsset.inl @@ -618,7 +618,7 @@ inline void Image::Read(Value &obj, Asset &r) { if (!mDataLength) { Value *curUri = FindString(obj, "uri"); - if (nullptr != curUri ) { + if (nullptr != curUri) { const char *uristr = curUri->GetString(); glTFCommon::Util::DataURI dataURI; @@ -1272,13 +1272,9 @@ inline void Asset::ReadBinaryHeader(IOStream &stream) { inline void Asset::Load(const std::string &pFile, bool isBinary) { mCurrentAssetDir.clear(); - int pos = std::max(int(pFile.rfind('/')), int(pFile.rfind('\\'))); - if (pos != int(std::string::npos)) mCurrentAssetDir = pFile.substr(0, pos + 1); - -/* std::string::size_type pos = std::max(pFile.rfind('/'), pFile.rfind('\\')); - if (pos != std::string::npos) { - mCurrentAssetDir = pFile.substr(0, pos + 1); - }*/ + /*int pos = std::max(int(pFile.rfind('/')), int(pFile.rfind('\\'))); + if (pos != int(std::string::npos)) mCurrentAssetDir = pFile.substr(0, pos + 1);*/ + mCurrentAssetDir = getCurrentAssetDir(pFile); shared_ptr stream(OpenFile(pFile.c_str(), "rb", true)); if (!stream) { @@ -1373,9 +1369,9 @@ inline void Asset::ReadExtensionsUsed(Document &doc) { #undef CHECK_EXT } -inline IOStream *Asset::OpenFile(std::string path, const char *mode, bool absolute ) { +inline IOStream *Asset::OpenFile(std::string path, const char *mode, bool absolute) { #ifdef ASSIMP_API - (void) absolute; + (void)absolute; return mIOSystem->Open(path, mode); #else if (path.size() < 2) return 0; diff --git a/code/glTF/glTFCommon.cpp b/code/glTF/glTFCommon.cpp index 9fac8de2d..1c662a16a 100644 --- a/code/glTF/glTFCommon.cpp +++ b/code/glTF/glTFCommon.cpp @@ -46,7 +46,7 @@ using namespace glTFCommon::Util; namespace Util { -size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out) { +size_t DecodeBase64(const char *in, size_t inLength, uint8_t *&out) { ai_assert(inLength % 4 == 0); if (inLength < 4) { @@ -55,7 +55,7 @@ size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out) { } int nEquals = int(in[inLength - 1] == '=') + - int(in[inLength - 2] == '='); + int(in[inLength - 2] == '='); size_t outLength = (inLength * 3) / 4 - nEquals; out = new uint8_t[outLength]; @@ -88,7 +88,7 @@ size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out) { return outLength; } -void EncodeBase64(const uint8_t* in, size_t inLength, std::string& out) { +void EncodeBase64(const uint8_t *in, size_t inLength, std::string &out) { size_t outLength = ((inLength + 2) / 3) * 4; size_t j = out.size(); @@ -110,13 +110,11 @@ void EncodeBase64(const uint8_t* in, size_t inLength, std::string& out) { b = in[i + 2] & 0x3F; out[j++] = EncodeCharBase64(b); - } - else { + } else { out[j++] = EncodeCharBase64(b); out[j++] = '='; } - } - else { + } else { out[j++] = EncodeCharBase64(b); out[j++] = '='; out[j++] = '='; @@ -124,7 +122,7 @@ void EncodeBase64(const uint8_t* in, size_t inLength, std::string& out) { } } -bool ParseDataURI(const char* const_uri, size_t uriLen, DataURI& out) { +bool ParseDataURI(const char *const_uri, size_t uriLen, DataURI &out) { if (nullptr == const_uri) { return false; } @@ -139,7 +137,7 @@ bool ParseDataURI(const char* const_uri, size_t uriLen, DataURI& out) { out.charset = "US-ASCII"; out.base64 = false; - char* uri = const_cast(const_uri); + char *uri = const_cast(const_uri); if (uri[0] != 0x10) { uri[0] = 0x10; uri[1] = uri[2] = uri[3] = uri[4] = 0; @@ -159,16 +157,14 @@ bool ParseDataURI(const char* const_uri, size_t uriLen, DataURI& out) { if (strncmp(uri + j, "charset=", 8) == 0) { uri[2] = char(j + 8); - } - else if (strncmp(uri + j, "base64", 6) == 0) { + } else if (strncmp(uri + j, "base64", 6) == 0) { uri[3] = char(j); } } if (i < uriLen) { uri[i++] = '\0'; uri[4] = char(i); - } - else { + } else { uri[1] = uri[2] = uri[3] = 0; uri[4] = 5; } @@ -189,5 +185,5 @@ bool ParseDataURI(const char* const_uri, size_t uriLen, DataURI& out) { return true; } -} -} +} // namespace Util +} // namespace glTFCommon diff --git a/code/glTF/glTFCommon.h b/code/glTF/glTFCommon.h index d942b4ba8..5d04822a2 100644 --- a/code/glTF/glTFCommon.h +++ b/code/glTF/glTFCommon.h @@ -45,201 +45,219 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include -#include -#include -#include -#include #include +#include +#include #include +#include +#include #define RAPIDJSON_HAS_STDSTRING 1 -#include #include #include +#include #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 -# else -# define gltf_unordered_map map +#define ASSIMP_GLTF_USE_UNORDERED_MULTIMAP +#else +#define gltf_unordered_map map #endif #ifdef ASSIMP_GLTF_USE_UNORDERED_MULTIMAP -# include -# if _MSC_VER > 1600 -# define gltf_unordered_map unordered_map -# else -# define gltf_unordered_map tr1::unordered_map -# endif +#include +#if _MSC_VER > 1600 +#define gltf_unordered_map unordered_map +#else +#define gltf_unordered_map tr1::unordered_map +#endif #endif namespace glTFCommon { #ifdef ASSIMP_API - using Assimp::IOStream; - using Assimp::IOSystem; - using std::shared_ptr; +using Assimp::IOStream; +using Assimp::IOSystem; +using std::shared_ptr; #else - using std::shared_ptr; +using std::shared_ptr; - typedef std::runtime_error DeadlyImportError; - typedef std::runtime_error DeadlyExportError; +typedef std::runtime_error DeadlyImportError; +typedef std::runtime_error DeadlyExportError; - enum aiOrigin { - aiOrigin_SET = 0, - aiOrigin_CUR = 1, - aiOrigin_END = 2 - }; +enum aiOrigin { + aiOrigin_SET = 0, + aiOrigin_CUR = 1, + aiOrigin_END = 2 +}; - class IOSystem; +class IOSystem; - class IOStream { - public: - IOStream(FILE* file) : f(file) {} - ~IOStream() { fclose(f); f = 0; } +class IOStream { +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 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)); - } + size_t FileSize() { + long p = Tell(), len = (Seek(0, aiOrigin_END), Tell()); + return size_t((Seek(p, aiOrigin_SET), len)); + } - private: - FILE* f; - }; +private: + FILE *f; +}; #endif - // Vec/matrix types, as raw float arrays - typedef float(vec3)[3]; - typedef float(vec4)[4]; - typedef float(mat4)[16]; - - inline - void CopyValue(const glTFCommon::vec3& v, aiColor4D& out) { - out.r = v[0]; - out.g = v[1]; - out.b = v[2]; - out.a = 1.0; - } - - inline - void CopyValue(const glTFCommon::vec4& v, aiColor4D& out) { - out.r = v[0]; - out.g = v[1]; - out.b = v[2]; - out.a = v[3]; - } - - inline - void CopyValue(const glTFCommon::vec4& v, aiColor3D& out) { - out.r = v[0]; - out.g = v[1]; - out.b = v[2]; - } - - inline - void CopyValue(const glTFCommon::vec3& v, aiColor3D& out) { - out.r = v[0]; - out.g = v[1]; - out.b = v[2]; - } - - inline - void CopyValue(const glTFCommon::vec3& v, aiVector3D& out) { - out.x = v[0]; - out.y = v[1]; - out.z = v[2]; - } - - inline - void CopyValue(const glTFCommon::vec4& v, aiQuaternion& out) { - out.x = v[0]; - out.y = v[1]; - out.z = v[2]; - out.w = v[3]; - } - - inline - void CopyValue(const glTFCommon::mat4& v, aiMatrix4x4& o) { - o.a1 = v[0]; o.b1 = v[1]; o.c1 = v[2]; o.d1 = v[3]; - o.a2 = v[4]; o.b2 = v[5]; o.c2 = v[6]; o.d2 = v[7]; - o.a3 = v[8]; o.b3 = v[9]; o.c3 = v[10]; o.d3 = v[11]; - o.a4 = v[12]; o.b4 = v[13]; o.c4 = v[14]; o.d4 = v[15]; - } - - 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 - bool ParseDataURI(const char* const_uri, size_t uriLen, DataURI& out); - - template - struct DATA { - static const uint8_t tableDecodeBase64[128]; - }; - - template - const uint8_t DATA::tableDecodeBase64[128] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 64, 0, 0, - 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, - 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, 0 - }; - - inline - char EncodeCharBase64(uint8_t b) { - return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="[size_t(b)]; - } - - inline - uint8_t DecodeCharBase64(char c) { - return DATA::tableDecodeBase64[size_t(c)]; // TODO faster with lookup table or ifs? - } - - size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out); - - void EncodeBase64(const uint8_t* in, size_t inLength, std::string& out); - } // namespace Util - -#define CHECK_EXT(EXT) \ - if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true; +// Vec/matrix types, as raw float arrays +typedef float(vec3)[3]; +typedef float(vec4)[4]; +typedef float(mat4)[16]; +inline void CopyValue(const glTFCommon::vec3 &v, aiColor4D &out) { + out.r = v[0]; + out.g = v[1]; + out.b = v[2]; + out.a = 1.0; } -#endif // ASSIMP_BUILD_NO_GLTF_IMPORTER +inline void CopyValue(const glTFCommon::vec4 &v, aiColor4D &out) { + out.r = v[0]; + out.g = v[1]; + out.b = v[2]; + out.a = v[3]; +} + +inline void CopyValue(const glTFCommon::vec4 &v, aiColor3D &out) { + out.r = v[0]; + out.g = v[1]; + out.b = v[2]; +} + +inline void CopyValue(const glTFCommon::vec3 &v, aiColor3D &out) { + out.r = v[0]; + out.g = v[1]; + out.b = v[2]; +} + +inline void CopyValue(const glTFCommon::vec3 &v, aiVector3D &out) { + out.x = v[0]; + out.y = v[1]; + out.z = v[2]; +} + +inline void CopyValue(const glTFCommon::vec4 &v, aiQuaternion &out) { + out.x = v[0]; + out.y = v[1]; + out.z = v[2]; + out.w = v[3]; +} + +inline void CopyValue(const glTFCommon::mat4 &v, aiMatrix4x4 &o) { + o.a1 = v[0]; + o.b1 = v[1]; + o.c1 = v[2]; + o.d1 = v[3]; + o.a2 = v[4]; + o.b2 = v[5]; + o.c2 = v[6]; + o.d2 = v[7]; + o.a3 = v[8]; + o.b3 = v[9]; + o.c3 = v[10]; + o.d3 = v[11]; + o.a4 = v[12]; + o.b4 = v[13]; + o.c4 = v[14]; + o.d4 = v[15]; +} + +#pragma warning(push) +#pragma warning(disable : 4310) +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)) { + path = pFile.substr(0, pos + 1); + } + + return path; +} +#pragma warning(pop) + +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 +bool ParseDataURI(const char *const_uri, size_t uriLen, DataURI &out); + +template +struct DATA { + static const uint8_t tableDecodeBase64[128]; +}; + +template +const uint8_t DATA::tableDecodeBase64[128] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 64, 0, 0, + 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, + 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, 0 +}; + +inline char EncodeCharBase64(uint8_t b) { + return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="[size_t(b)]; +} + +inline uint8_t DecodeCharBase64(char c) { + return DATA::tableDecodeBase64[size_t(c)]; // TODO faster with lookup table or ifs? +} + +size_t DecodeBase64(const char *in, size_t inLength, uint8_t *&out); + +void EncodeBase64(const uint8_t *in, size_t inLength, std::string &out); +} // namespace Util + +#define CHECK_EXT(EXT) \ + if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true; + +} // namespace glTFCommon + +#endif // ASSIMP_BUILD_NO_GLTF_IMPORTER #endif // AI_GLFTCOMMON_H_INC diff --git a/code/glTF2/glTF2Asset.h b/code/glTF2/glTF2Asset.h index d3c1654d0..c27522df3 100644 --- a/code/glTF2/glTF2Asset.h +++ b/code/glTF2/glTF2Asset.h @@ -55,1059 +55,963 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include -#include -#include -#include -#include #include +#include +#include #include +#include +#include #define RAPIDJSON_HAS_STDSTRING 1 -#include #include #include +#include #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 -# else -# define gltf_unordered_map map +#define ASSIMP_GLTF_USE_UNORDERED_MULTIMAP +#else +#define gltf_unordered_map map #endif #ifdef ASSIMP_GLTF_USE_UNORDERED_MULTIMAP -# include -# if _MSC_VER > 1600 -# define gltf_unordered_map unordered_map -# else -# define gltf_unordered_map tr1::unordered_map -# endif +#include +#if _MSC_VER > 1600 +#define gltf_unordered_map unordered_map +#else +#define gltf_unordered_map tr1::unordered_map +#endif #endif #include #include "glTF/glTFCommon.h" -namespace glTF2 -{ - using glTFCommon::shared_ptr; - using glTFCommon::IOSystem; - using glTFCommon::IOStream; +namespace glTF2 { +using glTFCommon::IOStream; +using glTFCommon::IOSystem; +using glTFCommon::shared_ptr; - using rapidjson::Value; - using rapidjson::Document; +using rapidjson::Document; +using rapidjson::Value; - class Asset; - class AssetWriter; +class Asset; +class AssetWriter; - struct BufferView; // here due to cross-reference - struct Texture; - struct Skin; +struct BufferView; // here due to cross-reference +struct Texture; +struct Skin; - using glTFCommon::vec3; - using glTFCommon::vec4; - using glTFCommon::mat4; +using glTFCommon::mat4; +using glTFCommon::vec3; +using glTFCommon::vec4; - //! Magic number for GLB files - #define AI_GLB_MAGIC_NUMBER "glTF" - #include +//! Magic number for GLB files +#define AI_GLB_MAGIC_NUMBER "glTF" +#include - #ifdef ASSIMP_API - #include - #endif +#ifdef ASSIMP_API +#include +#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; +//! 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; +struct GLB_Chunk { + uint32_t chunkLength; + uint32_t chunkType; +} PACK_STRUCT; - #ifdef ASSIMP_API - #include - #endif +#ifdef ASSIMP_API +#include +#endif +//! Values for the GLB_Chunk::chunkType field +enum ChunkType { + ChunkType_JSON = 0x4E4F534A, + ChunkType_BIN = 0x004E4942 +}; - //! 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_NONE = 0, + 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 Animation::Target::path field +enum AnimationPath { + AnimationPath_TRANSLATION, + AnimationPath_ROTATION, + AnimationPath_SCALE, + AnimationPath_WEIGHTS, +}; + +//! Values for the Animation::Sampler::interpolation field +enum Interpolation { + Interpolation_LINEAR, + Interpolation_STEP, + Interpolation_CUBICSPLINE, +}; + +//! 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: - throw DeadlyImportError("GLTF: Unsupported Component Type " + to_string(t)); +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 - }; + inline static const char *ToString(Value type) { + return data<0>::infos[static_cast(type)].name; + } - //! Values for the Sampler::magFilter field - enum class SamplerMagFilter : unsigned int - { - UNSET = 0, - SamplerMagFilter_Nearest = 9728, - SamplerMagFilter_Linear = 9729 - }; + inline static unsigned int GetNumComponents(Value type) { + return data<0>::infos[static_cast(type)].numComponents; + } +}; - //! 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 - }; +// 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 } + }; - //! 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 - }; +//! 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; - //! 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 - }; +public: + Ref() : + vector(0), index(0) {} + Ref(std::vector &vec, unsigned int idx) : + vector(&vec), index(idx) {} - //! Values for the Texture::target field - enum TextureTarget - { - TextureTarget_TEXTURE_2D = 3553 - }; + inline unsigned int GetIndex() const { return index; } - //! 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 - }; + operator bool() const { return vector != 0; } - //! Values for the Animation::Target::path field - enum AnimationPath { - AnimationPath_TRANSLATION, - AnimationPath_ROTATION, - AnimationPath_SCALE, - AnimationPath_WEIGHTS, - }; + T *operator->() { return (*vector)[index]; } - //! Values for the Animation::Sampler::interpolation field - enum Interpolation { - Interpolation_LINEAR, - Interpolation_STEP, - Interpolation_CUBICSPLINE, - }; + T &operator*() { return *((*vector)[index]); } +}; - //! Values for the Accessor::type field (helper class) - class AttribType - { - public: - enum Value - { SCALAR, VEC2, VEC3, VEC4, MAT2, MAT3, MAT4 }; +//! Helper struct to represent values that might not be present +template +struct Nullable { + T value; + bool isPresent; - private: - static const size_t NUM_VALUES = static_cast(MAT4)+1; + Nullable() : + isPresent(false) {} + Nullable(T &val) : + value(val), isPresent(true) {} +}; - struct Info - { const char* name; unsigned int numComponents; }; +//! Base class 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 - template struct data - { static const Info infos[NUM_VALUES]; }; + //! 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; //!< The ID of the bufferView. (required) + size_t byteOffset; //!< The offset relative to the start of the bufferView in bytes. (required) + ComponentType componentType; //!< The datatype of components in the attribute. (required) + size_t 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. + + unsigned int GetNumComponents(); + unsigned int GetBytesPerComponent(); + unsigned int GetElementSize(); + + 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; + + Accessor &accessor; + uint8_t *data; + size_t elemSize, stride; + + Indexer(Accessor &acc); 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; + //! 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 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; + inline bool IsValid() const { + return data != 0; } }; - // 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 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) {} - //! 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]); } + /// \fn ~SEncodedRegion() + /// Destructor. + ~SEncodedRegion() { delete[] DecodedData; } }; - //! Helper struct to represent values that might not be present - template - struct Nullable - { - T value; - bool isPresent; + /******************* Variables *******************/ - Nullable() : isPresent(false) {} - Nullable(T& val) : value(val), isPresent(true) {} + //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") + size_t capacity = 0; //!< The capacity of the buffer in bytes. (default: 0) + + 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 of course) 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) + + /// \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); + bool ReplaceData_joint(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) + 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 }; - - //! Base class 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; //!< The ID of the bufferView. (required) - size_t byteOffset; //!< The offset relative to the start of the bufferView in bytes. (required) - ComponentType componentType; //!< The datatype of components in the attribute. (required) - size_t 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. - - unsigned int GetNumComponents(); - unsigned int GetBytesPerComponent(); - unsigned int GetElementSize(); - - 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; - - Accessor& accessor; - 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") - size_t capacity = 0; //!< The capacity of the buffer in bytes. (default: 0) - - 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 of course) 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) - - /// \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); - bool ReplaceData_joint(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) - 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; //! range; - - float innerConeAngle; - float outerConeAngle; - - Light() {} - void Read(Value& obj, Asset& r); - }; - - //! Image data used to create a texture. - struct Image : public Object - { - std::string uri; //! The uri of the image, that can be a file path, a data URI, etc.. (required) - - Ref bufferView; - - std::string mimeType; - - int width, height; - - private: - std::unique_ptr mData; - size_t mDataLength; - - public: - - Image(); - void Read(Value& obj, Asset& r); - - inline bool HasData() const - { return mDataLength > 0; } - - inline size_t GetDataLength() const - { return mDataLength; } - - inline const uint8_t* GetData() const - { return mData.get(); } - - inline uint8_t* StealData(); - - inline void SetData(uint8_t* data, size_t length, Asset& r); - }; - - 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; - unsigned int index; - unsigned int texCoord = 0; - - bool textureTransformSupported = false; - struct TextureTransformExt { - float offset[2]; - float rotation; - float scale[2]; - } TextureTransformExt_t; - }; - - 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; - - //extension: KHR_materials_unlit - bool unlit; - - 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 > AccessorList; - - struct Primitive - { - PrimitiveMode mode; - - struct Attributes { - AccessorList position, normal, tangent, texcoord, color, joint, jointmatrix, weight; - } attributes; - - Ref indices; - - Ref material; - - struct Target { - AccessorList position, normal, tangent; - }; - std::vector targets; - }; - - std::vector primitives; - - std::vector weights; - - 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. - void Read(Value& pJSON_Object, Asset& pAsset_Root); - }; - - struct Node : public Object - { - std::vector< Ref > children; - std::vector< Ref > meshes; - - 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. - 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 > 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); - }; - - //! 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); - }; - - struct Animation : public Object - { - struct Sampler { - Sampler() : interpolation(Interpolation_LINEAR) {} - - Ref input; //!< Accessor reference to the buffer storing the key-frame times. - Ref output; //!< Accessor reference to the buffer storing the key-frame values. - Interpolation interpolation; //!< Type of interpolation algorithm to use between key-frames. - }; - - struct Target { - Target() : path(AnimationPath_TRANSLATION) {} - - Ref node; //!< The node to animate. - AnimationPath path; //!< The property of the node to animate. - }; - - struct Channel { - Channel() : sampler(-1) {} - - int sampler; //!< The sampler index containing the animation data. - Target target; //!< The node and property to animate. - }; - - std::vector samplers; //!< All the key-frame data for this animation. - std::vector channels; //!< Data to connect nodes to key-frames. - - 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; - - virtual void WriteObjects(AssetWriter& writer) = 0; - }; - - - 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< unsigned int, unsigned int > Dict; - typedef typename std::gltf_unordered_map< std::string, unsigned int > IdDict; - - std::vector 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(*this, writer); } - - Ref Add(T* obj); - - public: - LazyDict(Asset& asset, const char* dictId, const char* extId = 0); - ~LazyDict(); - - Ref Retrieve(unsigned int i); - - Ref Get(unsigned int i); - Ref Get(const char* id); - - Ref Create(const char* id); - Ref 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. + Type type; + + union { + struct { + float aspectRatio; //! IdMap; + vec3 color; + float intensity; + Nullable range; - template - friend class LazyDict; + float innerConeAngle; + float outerConeAngle; - friend struct Buffer; // To access OpenFile + Light() {} + void Read(Value &obj, Asset &r); +}; - friend class AssetWriter; +//! 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) - private: - IOSystem* mIOSystem; + Ref bufferView; - std::string mCurrentAssetDir; + std::string mimeType; - size_t mSceneLength; - size_t mBodyOffset, mBodyLength; + int width, height; - std::vector mDicts; +private: + std::unique_ptr mData; + size_t mDataLength; - IdMap mUsedIds; +public: + Image(); + void Read(Value &obj, Asset &r); - Ref mBodyBuffer; + inline bool HasData() const { return mDataLength > 0; } - Asset(Asset&); - Asset& operator=(const Asset&); + inline size_t GetDataLength() const { return mDataLength; } - public: + inline const uint8_t *GetData() const { return mData.get(); } - //! Keeps info about the enabled extensions - struct Extensions - { - bool KHR_materials_pbrSpecularGlossiness; - bool KHR_materials_unlit; - bool KHR_lights_punctual; - bool KHR_texture_transform; - } extensionsUsed; + inline uint8_t *StealData(); - //! Keeps info about the required extensions - struct RequiredExtensions - { - bool KHR_draco_mesh_compression; - } extensionsRequired; + inline void SetData(uint8_t *data, size_t length, Asset &r); +}; - AssetMetadata asset; +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; + unsigned int index; + unsigned int texCoord = 0; - // Dictionaries for each type of object + bool textureTransformSupported = false; + struct TextureTransformExt { + float offset[2]; + float rotation; + float scale[2]; + } TextureTransformExt_t; +}; - LazyDict accessors; - LazyDict animations; - LazyDict buffers; - LazyDict bufferViews; - LazyDict cameras; - LazyDict lights; - LazyDict images; - LazyDict materials; - LazyDict meshes; - LazyDict nodes; - LazyDict samplers; - LazyDict scenes; - LazyDict skins; - LazyDict textures; +struct NormalTextureInfo : TextureInfo { + float scale = 1; +}; - Ref scene; +struct OcclusionTextureInfo : TextureInfo { + float strength = 1; +}; - public: - Asset(IOSystem* io = 0) - : mIOSystem(io) - , asset() - , accessors (*this, "accessors") - , animations (*this, "animations") - , buffers (*this, "buffers") - , bufferViews (*this, "bufferViews") - , cameras (*this, "cameras") - , lights (*this, "lights", "KHR_lights_punctual") - , 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)); - memset(&extensionsRequired, 0, sizeof(extensionsRequired)); - } +struct PbrMetallicRoughness { + vec4 baseColorFactor; + TextureInfo baseColorTexture; + TextureInfo metallicRoughnessTexture; + float metallicFactor; + float roughnessFactor; +}; - //! Main function - void Load(const std::string& file, bool isBinary = false); +struct PbrSpecularGlossiness { + vec4 diffuseFactor; + vec3 specularFactor; + float glossinessFactor; + TextureInfo diffuseTexture; + TextureInfo specularGlossinessTexture; - //! Enables binary encoding on the asset - void SetAsBinary(); + PbrSpecularGlossiness() { SetDefaults(); } + void SetDefaults(); +}; - //! Search for an available name, starting from the given strings - std::string FindUniqueID(const std::string& str, const char* suffix); +//! The material appearance of a primitive. +struct Material : public Object { + //PBR metallic roughness properties + PbrMetallicRoughness pbrMetallicRoughness; - Ref GetBodyBuffer() - { return mBodyBuffer; } + //other basic material properties + NormalTextureInfo normalTexture; + OcclusionTextureInfo occlusionTexture; + TextureInfo emissiveTexture; + vec3 emissiveFactor; + std::string alphaMode; + float alphaCutoff; + bool doubleSided; - private: - void ReadBinaryHeader(IOStream& stream, std::vector& sceneData); + //extension: KHR_materials_pbrSpecularGlossiness + Nullable pbrSpecularGlossiness; - void ReadExtensionsUsed(Document& doc); - void ReadExtensionsRequired(Document& doc); + //extension: KHR_materials_unlit + bool unlit; - IOStream* OpenFile(std::string path, const char* mode, bool absolute = false); + 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, tangent, texcoord, color, joint, jointmatrix, weight; + } attributes; + + Ref indices; + + Ref material; + + struct Target { + AccessorList position, normal, tangent; + }; + std::vector targets; }; -} + std::vector primitives; + + std::vector weights; + + 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. + void Read(Value &pJSON_Object, Asset &pAsset_Root); +}; + +struct Node : public Object { + std::vector> children; + std::vector> meshes; + + Nullable matrix; + Nullable translation; + Nullable rotation; + Nullable scale; + + Ref camera; + Ref light; + + 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. + + 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. + 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> 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); +}; + +//! 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); +}; + +struct Animation : public Object { + struct Sampler { + Sampler() : + interpolation(Interpolation_LINEAR) {} + + Ref input; //!< Accessor reference to the buffer storing the key-frame times. + Ref output; //!< Accessor reference to the buffer storing the key-frame values. + Interpolation interpolation; //!< Type of interpolation algorithm to use between key-frames. + }; + + struct Target { + Target() : + path(AnimationPath_TRANSLATION) {} + + Ref node; //!< The node to animate. + AnimationPath path; //!< The property of the node to animate. + }; + + struct Channel { + Channel() : + sampler(-1) {} + + int sampler; //!< The sampler index containing the animation data. + Target target; //!< The node and property to animate. + }; + + std::vector samplers; //!< All the key-frame data for this animation. + std::vector channels; //!< Data to connect nodes to key-frames. + + 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; + + virtual void WriteObjects(AssetWriter &writer) = 0; +}; + +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; + typedef typename std::gltf_unordered_map IdDict; + + std::vector 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(*this, writer); } + + Ref Add(T *obj); + +public: + LazyDict(Asset &asset, const char *dictId, const char *extId = 0); + ~LazyDict(); + + Ref Retrieve(unsigned int i); + + Ref Get(unsigned int i); + Ref Get(const char *id); + + Ref Create(const char *id); + Ref 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 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_materials_pbrSpecularGlossiness; + bool KHR_materials_unlit; + bool KHR_lights_punctual; + bool KHR_texture_transform; + } extensionsUsed; + + //! Keeps info about the required extensions + struct RequiredExtensions { + bool KHR_draco_mesh_compression; + } extensionsRequired; + + AssetMetadata asset; + + // Dictionaries for each type of object + + LazyDict accessors; + LazyDict animations; + LazyDict buffers; + LazyDict bufferViews; + LazyDict cameras; + LazyDict lights; + LazyDict images; + LazyDict materials; + LazyDict meshes; + LazyDict nodes; + LazyDict samplers; + LazyDict scenes; + LazyDict skins; + LazyDict textures; + + 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"), lights(*this, "lights", "KHR_lights_punctual"), 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)); + memset(&extensionsRequired, 0, sizeof(extensionsRequired)); + } + + //! 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 GetBodyBuffer() { return mBodyBuffer; } + +private: + void ReadBinaryHeader(IOStream &stream, std::vector &sceneData); + + void ReadExtensionsUsed(Document &doc); + void ReadExtensionsRequired(Document &doc); + + IOStream *OpenFile(std::string path, const char *mode, bool absolute = false); +}; + +} // namespace glTF2 // Include the implementation of the methods #include "glTF2Asset.inl" diff --git a/code/glTF2/glTF2Asset.inl b/code/glTF2/glTF2Asset.inl index 9bf767e29..97aa12e34 100644 --- a/code/glTF2/glTF2Asset.inl +++ b/code/glTF2/glTF2Asset.inl @@ -40,6 +40,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ +#include "glTF/glTFCommon.h" #include // Header files, Assimp @@ -901,7 +902,7 @@ inline int Compare(const char *attr, const char (&str)[N]) { } #pragma warning(push) -#pragma warning(disable: 4706 ) +#pragma warning(disable : 4706) inline bool GetAttribVector(Mesh::Primitive &p, const char *attr, Mesh::AccessorList *&v, int &pos) { if ((pos = Compare(attr, "POSITION"))) { v = &(p.attributes.position); @@ -1106,7 +1107,7 @@ inline void Node::Read(Value &obj, Asset &r) { } Value *curMesh = FindUInt(obj, "mesh"); - if (nullptr != curMesh ) { + if (nullptr != curMesh) { unsigned int numMeshes = 1; this->meshes.reserve(numMeshes); Ref meshRef = r.meshes.Retrieve((*curMesh).GetUint()); @@ -1116,12 +1117,12 @@ inline void Node::Read(Value &obj, Asset &r) { } Value *curSkin = FindUInt(obj, "skin"); - if (nullptr != curSkin ) { + if (nullptr != curSkin) { this->skin = r.skins.Retrieve(curSkin->GetUint()); } Value *curCamera = FindUInt(obj, "camera"); - if (nullptr != curCamera ) { + if (nullptr != curCamera) { this->camera = r.cameras.Retrieve(curCamera->GetUint()); if (this->camera) { this->camera->id = this->id; @@ -1328,8 +1329,10 @@ inline void Asset::ReadBinaryHeader(IOStream &stream, std::vector &sceneDa inline void Asset::Load(const std::string &pFile, bool isBinary) { mCurrentAssetDir.clear(); - int pos = std::max(int(pFile.rfind('/')), int(pFile.rfind('\\'))); - if (pos != int(std::string::npos)) mCurrentAssetDir = pFile.substr(0, pos + 1); + /*int pos = std::max(int(pFile.rfind('/')), int(pFile.rfind('\\'))); + if (pos != int(std::string::npos)) */ + + mCurrentAssetDir = glTFCommon::getCurrentAssetDir(pFile); shared_ptr stream(OpenFile(pFile.c_str(), "rb", true)); if (!stream) { @@ -1516,6 +1519,6 @@ inline std::string Asset::FindUniqueID(const std::string &str, const char *suffi return id; } -#pragma warning( pop ) +#pragma warning(pop) } // namespace glTF2 diff --git a/code/glTF2/glTF2Importer.cpp b/code/glTF2/glTF2Importer.cpp index b0d05f7a9..ee6a420d7 100644 --- a/code/glTF2/glTF2Importer.cpp +++ b/code/glTF2/glTF2Importer.cpp @@ -110,8 +110,9 @@ const aiImporterDesc *glTF2Importer::GetInfo() const { bool glTF2Importer::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /* checkSig */) const { const std::string &extension = GetExtension(pFile); - if (extension != "gltf" && extension != "glb") - return false; + if (extension != "gltf" && extension != "glb") { + return false; + } if (pIOHandler) { glTF2::Asset asset(pIOHandler);