diff --git a/code/AssetLib/glTF2/glTF2Asset.h b/code/AssetLib/glTF2/glTF2Asset.h index bfd4e4342..99bcaf072 100644 --- a/code/AssetLib/glTF2/glTF2Asset.h +++ b/code/AssetLib/glTF2/glTF2Asset.h @@ -175,19 +175,19 @@ enum ComponentType { inline unsigned int ComponentTypeSize(ComponentType t) { switch (t) { - case ComponentType_SHORT: - case ComponentType_UNSIGNED_SHORT: - return 2; + case ComponentType_SHORT: + case ComponentType_UNSIGNED_SHORT: + return 2; - case ComponentType_UNSIGNED_INT: - case ComponentType_FLOAT: - return 4; + 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)); + case ComponentType_BYTE: + case ComponentType_UNSIGNED_BYTE: + return 1; + default: + throw DeadlyImportError("GLTF: Unsupported Component Type " + to_string(t)); } } @@ -318,9 +318,11 @@ class Ref { public: Ref() : - vector(0), index(0) {} + vector(0), + index(0) {} Ref(std::vector &vec, unsigned int idx) : - vector(&vec), index(idx) {} + vector(&vec), + index(idx) {} inline unsigned int GetIndex() const { return index; } @@ -340,7 +342,8 @@ struct Nullable { Nullable() : isPresent(false) {} Nullable(T &val) : - value(val), isPresent(true) {} + value(val), + isPresent(true) {} }; //! Base class for all glTF top-level objects @@ -363,49 +366,28 @@ struct Object { // Classes for each glTF top-level object type // -//! Base class for types that access binary data from a BufferView, such as accessors -//! or sparse accessors' indices. -//! N.B. not a virtual class. All owned pointers to BufferViewClient instances should -//! be to their most derived types (which may of course be just BufferViewClient). -struct BufferViewClient : 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) - - inline uint8_t *GetPointer(); - - void Read(Value &obj, Asset &r); -}; - -//! BufferViewClient with component type information. -//! N.B. not a virtual class. All owned pointers to ComponentTypedBufferViewClient -//! instances should be to their most derived types (which may of course be just -//! ComponentTypedBufferViewClient). -struct ComponentTypedBufferViewClient : public BufferViewClient { - ComponentType componentType; //!< The datatype of components in the attribute. (required) - - unsigned int GetBytesPerComponent(); - - void Read(Value &obj, Asset &r); -}; - //! 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 ComponentTypedBufferViewClient { +struct Accessor : public Object { struct Sparse; + 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. - std::unique_ptr sparse; //!< Sparse accessor information + std::unique_ptr sparse; unsigned int GetNumComponents(); + unsigned int GetBytesPerComponent(); unsigned int GetElementSize(); inline uint8_t *GetPointer(); - template + template void ExtractData(T *&outData); void WriteData(size_t count, const void *src_buffer, size_t src_stride); @@ -414,8 +396,8 @@ struct Accessor : public ComponentTypedBufferViewClient { class Indexer { friend struct Accessor; - // This field is reported as not used, making it protectd is the easiest way to work around it without going to the bottom of what the problem is: - // ../code/glTF2/glTF2Asset.h:392:19: error: private field 'accessor' is not used [-Werror,-Wunused-private-field] + // This field is reported as not used, making it protectd is the easiest way to work around it without going to the bottom of what the problem is: + // ../code/glTF2/glTF2Asset.h:392:19: error: private field 'accessor' is not used [-Werror,-Wunused-private-field] protected: Accessor &accessor; @@ -424,8 +406,7 @@ struct Accessor : public ComponentTypedBufferViewClient { size_t elemSize, stride; Indexer(Accessor &acc); - - + public: //! Accesses the i-th value as defined by the accessor template @@ -441,62 +422,27 @@ struct Accessor : public ComponentTypedBufferViewClient { } }; - //! Sparse accessor information - struct Sparse { - size_t count; - ComponentTypedBufferViewClient indices; - BufferViewClient values; - - std::vector data; //!< Actual data, which may be defaulted to an array of zeros or the original data, with the sparse buffer view applied on top of it. - - inline void PopulateData(size_t numBytes, uint8_t *bytes) { - if (bytes) { - data.assign(bytes, bytes + numBytes); - } else { - data.resize(numBytes, 0x00); - } - } - - inline void PatchData(unsigned int elementSize) - { - uint8_t *pIndices = indices.GetPointer(); - const unsigned int indexSize = indices.GetBytesPerComponent(); - uint8_t *indicesEnd = pIndices + count * indexSize; - - uint8_t *pValues = values.GetPointer(); - while (pIndices != indicesEnd) { - size_t offset; - switch (indices.componentType) { - case ComponentType_UNSIGNED_BYTE: - offset = *pIndices; - break; - case ComponentType_UNSIGNED_SHORT: - offset = *reinterpret_cast(pIndices); - break; - case ComponentType_UNSIGNED_INT: - offset = *reinterpret_cast(pIndices); - break; - default: - // have fun with float and negative values from signed types as indices. - throw DeadlyImportError("Unsupported component type in index."); - } - - offset *= elementSize; - std::memcpy(data.data() + offset, pValues, elementSize); - - pValues += elementSize; - pIndices += indexSize; - } - } - }; - inline Indexer GetIndexer() { return Indexer(*this); } Accessor() {} - void Read(Value &obj, Asset &r); + + //sparse + struct Sparse { + size_t count; + ComponentType indicesType; + Ref indices; + size_t indicesByteOffset; + Ref values; + size_t valuesByteOffset; + + std::vector data; //!< Actual data, which may be defaulted to an array of zeros or the original data, with the sparse buffer view applied on top of it. + + void PopulateData(size_t numBytes, uint8_t *bytes); + void PatchData(unsigned int elementSize); + }; }; //! A buffer points to binary geometry, animation, or skins. @@ -525,7 +471,11 @@ public: /// \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) {} + Offset(pOffset), + EncodedData_Length(pEncodedData_Length), + DecodedData(pDecodedData), + DecodedData_Length(pDecodedData_Length), + ID(pID) {} /// \fn ~SEncodedRegion() /// Destructor. @@ -629,6 +579,7 @@ struct BufferView : public Object { BufferViewTarget target; //! The target that the WebGL buffer should be bound to. void Read(Value &obj, Asset &r); + uint8_t *GetPointer(size_t accOffset); }; struct Camera : public Object { @@ -656,7 +607,8 @@ struct Camera : public Object { } cameraProperties; Camera() : - type(Perspective), cameraProperties() { + type(Perspective), + cameraProperties() { // empty } void Read(Value &obj, Asset &r); @@ -961,7 +913,7 @@ class LazyDict : public LazyDictBase { Value *mDict; //! JSON dictionary object Asset &mAsset; //! The asset instance - std::gltf_unordered_set mRecursiveReferenceCheck; //! Used by Retrieve to prevent recursive lookups + std::gltf_unordered_set mRecursiveReferenceCheck; //! Used by Retrieve to prevent recursive lookups void AttachToDocument(Document &doc); void DetachFromDocument(); @@ -1075,7 +1027,22 @@ public: 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") { + 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)); } diff --git a/code/AssetLib/glTF2/glTF2Asset.inl b/code/AssetLib/glTF2/glTF2Asset.inl index 9015847e3..80207a4be 100644 --- a/code/AssetLib/glTF2/glTF2Asset.inl +++ b/code/AssetLib/glTF2/glTF2Asset.inl @@ -180,7 +180,10 @@ inline Value *FindObject(Value &val, const char *id) { template inline LazyDict::LazyDict(Asset &asset, const char *dictId, const char *extId) : - mDictId(dictId), mExtId(extId), mDict(0), mAsset(asset) { + mDictId(dictId), + mExtId(extId), + mDict(0), + mAsset(asset) { asset.mDicts.push_back(this); // register to the list of dictionaries } @@ -342,7 +345,10 @@ Ref LazyDict::Create(const char *id) { // inline Buffer::Buffer() : - byteLength(0), type(Type_arraybuffer), EncodedRegion_Current(nullptr), mIsSpecial(false) {} + byteLength(0), + type(Type_arraybuffer), + EncodedRegion_Current(nullptr), + mIsSpecial(false) {} inline Buffer::~Buffer() { for (SEncodedRegion *reg : EncodedRegion_List) @@ -517,7 +523,7 @@ inline void Buffer::Grow(size_t amount) { if (amount <= 0) { return; } - + // Capacity is big enough if (capacity >= byteLength + amount) { byteLength += amount; @@ -550,11 +556,130 @@ inline void BufferView::Read(Value &obj, Asset &r) { byteStride = MemberOrDefault(obj, "byteStride", 0u); } -// -// struct BufferViewClient -// +inline uint8_t *BufferView::GetPointer(size_t accOffset) { + if (!buffer) return 0; + uint8_t *basePtr = buffer->GetPointer(); + if (!basePtr) return 0; + + size_t offset = accOffset + byteOffset; + if (buffer->EncodedRegion_Current != nullptr) { + const size_t begin = buffer->EncodedRegion_Current->Offset; + const size_t end = begin + buffer->EncodedRegion_Current->DecodedData_Length; + if ((offset >= begin) && (offset < end)) + return &buffer->EncodedRegion_Current->DecodedData[offset - begin]; + } + + return basePtr + offset; +} + +// +// struct Accessor +// +inline void Accessor::Sparse::PopulateData(size_t numBytes, uint8_t *bytes) { + if (bytes) { + data.assign(bytes, bytes + numBytes); + } else { + data.resize(numBytes, 0x00); + } +} + +inline void Accessor::Sparse::PatchData(unsigned int elementSize) { + uint8_t *pIndices = indices->GetPointer(indicesByteOffset); + const unsigned int indexSize = int(ComponentTypeSize(indicesType)); + uint8_t *indicesEnd = pIndices + count * indexSize; + + uint8_t *pValues = values->GetPointer(valuesByteOffset); + while (pIndices != indicesEnd) { + size_t offset; + switch (indicesType) { + case ComponentType_UNSIGNED_BYTE: + offset = *pIndices; + break; + case ComponentType_UNSIGNED_SHORT: + offset = *reinterpret_cast(pIndices); + break; + case ComponentType_UNSIGNED_INT: + offset = *reinterpret_cast(pIndices); + break; + default: + // have fun with float and negative values from signed types as indices. + throw DeadlyImportError("Unsupported component type in index."); + } + + offset *= elementSize; + std::memcpy(data.data() + offset, pValues, elementSize); + + pValues += elementSize; + pIndices += indexSize; + } +} + +inline void Accessor::Read(Value &obj, Asset &r) { + + if (Value *bufferViewVal = FindUInt(obj, "bufferView")) { + bufferView = r.bufferViews.Retrieve(bufferViewVal->GetUint()); + } + + byteOffset = MemberOrDefault(obj, "byteOffset", size_t(0)); + componentType = MemberOrDefault(obj, "componentType", ComponentType_BYTE); + count = MemberOrDefault(obj, "count", size_t(0)); + + const char *typestr; + type = ReadMember(obj, "type", typestr) ? AttribType::FromString(typestr) : AttribType::SCALAR; + + if (Value *sparseValue = FindObject(obj, "sparse")) { + sparse.reset(new Sparse); + // count + ReadMember(*sparseValue, "count", sparse->count); + + // indices + if (Value *indicesValue = FindObject(*sparseValue, "indices")) { + //indices bufferView + Value *indiceViewID = FindUInt(*indicesValue, "bufferView"); + sparse->indices = r.bufferViews.Retrieve(indiceViewID->GetUint()); + //indices byteOffset + sparse->indicesByteOffset = MemberOrDefault(*indicesValue, "byteOffset", size_t(0)); + //indices componentType + sparse->indicesType = MemberOrDefault(*indicesValue, "componentType", ComponentType_BYTE); + //sparse->indices->Read(*indicesValue, r); + } + + // value + if (Value *valuesValue = FindObject(*sparseValue, "values")) { + //value bufferView + Value *valueViewID = FindUInt(*valuesValue, "bufferView"); + sparse->values = r.bufferViews.Retrieve(valueViewID->GetUint()); + //value byteOffset + sparse->valuesByteOffset = MemberOrDefault(*valuesValue, "byteOffset", size_t(0)); + //sparse->values->Read(*valuesValue, r); + } + + // indicesType + sparse->indicesType = MemberOrDefault(*sparseValue, "componentType", ComponentType_UNSIGNED_SHORT); + + const unsigned int elementSize = GetElementSize(); + const size_t dataSize = count * elementSize; + sparse->PopulateData(dataSize, bufferView ? bufferView->GetPointer(byteOffset) : 0); + sparse->PatchData(elementSize); + } +} + +inline unsigned int Accessor::GetNumComponents() { + return AttribType::GetNumComponents(type); +} + +inline unsigned int Accessor::GetBytesPerComponent() { + return int(ComponentTypeSize(componentType)); +} + +inline unsigned int Accessor::GetElementSize() { + return GetNumComponents() * GetBytesPerComponent(); +} + +inline uint8_t *Accessor::GetPointer() { + if (sparse) + return sparse->data.data(); -inline uint8_t *BufferViewClient::GetPointer() { if (!bufferView || !bufferView->buffer) return 0; uint8_t *basePtr = bufferView->buffer->GetPointer(); if (!basePtr) return 0; @@ -573,76 +698,6 @@ inline uint8_t *BufferViewClient::GetPointer() { return basePtr + offset; } -inline void BufferViewClient::Read(Value &obj, Asset &r) { - - if (Value *bufferViewVal = FindUInt(obj, "bufferView")) { - bufferView = r.bufferViews.Retrieve(bufferViewVal->GetUint()); - } - - byteOffset = MemberOrDefault(obj, "byteOffset", size_t(0)); -} - -// -// struct ComponentTypedBufferViewClient -// - -inline unsigned int ComponentTypedBufferViewClient::GetBytesPerComponent() { - return int(ComponentTypeSize(componentType)); -} - -inline void ComponentTypedBufferViewClient::Read(Value &obj, Asset &r) { - - BufferViewClient::Read(obj, r); - - componentType = MemberOrDefault(obj, "componentType", ComponentType_BYTE); -} - -// -// struct Accessor -// - -inline uint8_t *Accessor::GetPointer() { - if (!sparse) return BufferViewClient::GetPointer(); - - return sparse->data.data(); -} - -inline void Accessor::Read(Value &obj, Asset &r) { - - ComponentTypedBufferViewClient::Read(obj, r); - - count = MemberOrDefault(obj, "count", size_t(0)); - - const char *typestr; - type = ReadMember(obj, "type", typestr) ? AttribType::FromString(typestr) : AttribType::SCALAR; - - if (Value *sparseValue = FindObject(obj, "sparse")) { - sparse.reset(new Sparse); - ReadMember(*sparseValue, "count", sparse->count); - - if (Value *indicesValue = FindObject(*sparseValue, "indices")) { - sparse->indices.Read(*indicesValue, r); - } - - if (Value *valuesValue = FindObject(*sparseValue, "values")) { - sparse->values.Read(*valuesValue, r); - } - - const unsigned int elementSize = GetElementSize(); - const size_t dataSize = count * elementSize; - sparse->PopulateData(dataSize, BufferViewClient::GetPointer()); - sparse->PatchData(elementSize); - } -} - -inline unsigned int Accessor::GetNumComponents() { - return AttribType::GetNumComponents(type); -} - -inline unsigned int Accessor::GetElementSize() { - return GetNumComponents() * GetBytesPerComponent(); -} - namespace { inline void CopyData(size_t count, const uint8_t *src, size_t src_stride, @@ -663,10 +718,9 @@ inline void CopyData(size_t count, } } // namespace -template -void Accessor::ExtractData(T *&outData) -{ - uint8_t* data = GetPointer(); +template +void Accessor::ExtractData(T *&outData) { + uint8_t *data = GetPointer(); if (!data) { throw DeadlyImportError("GLTF: data is NULL"); } @@ -678,7 +732,6 @@ void Accessor::ExtractData(T *&outData) const size_t targetElemSize = sizeof(T); ai_assert(elemSize <= targetElemSize); - ai_assert(count * stride <= (bufferView ? bufferView->byteLength : sparse->data.size())); outData = new T[count]; @@ -705,7 +758,10 @@ inline void Accessor::WriteData(size_t _count, const void *src_buffer, size_t sr } inline Accessor::Indexer::Indexer(Accessor &acc) : - accessor(acc), data(acc.GetPointer()), elemSize(acc.GetElementSize()), stride(acc.bufferView && acc.bufferView->byteStride ? acc.bufferView->byteStride : elemSize) { + accessor(acc), + data(acc.GetPointer()), + elemSize(acc.GetElementSize()), + stride(acc.bufferView && acc.bufferView->byteStride ? acc.bufferView->byteStride : elemSize) { } //! Accesses the i-th value as defined by the accessor @@ -720,7 +776,9 @@ T Accessor::Indexer::GetValue(int i) { } inline Image::Image() : - width(0), height(0), mDataLength(0) { + width(0), + height(0), + mDataLength(0) { } inline void Image::Read(Value &obj, Asset &r) { @@ -958,8 +1016,8 @@ inline int Compare(const char *attr, const char (&str)[N]) { } #ifdef _WIN32 -# pragma warning(push) -# pragma warning(disable : 4706) +#pragma warning(push) +#pragma warning(disable : 4706) #endif // _WIN32 inline bool GetAttribVector(Mesh::Primitive &p, const char *attr, Mesh::AccessorList *&v, int &pos) { @@ -1079,11 +1137,11 @@ inline void Mesh::Read(Value &pJSON_Object, Asset &pAsset_Root) { } Value *extras = FindObject(pJSON_Object, "extras"); - if (nullptr != extras ) { - if (Value* curTargetNames = FindArray(*extras, "targetNames")) { + if (nullptr != extras) { + if (Value *curTargetNames = FindArray(*extras, "targetNames")) { this->targetNames.resize(curTargetNames->Size()); for (unsigned int i = 0; i < curTargetNames->Size(); ++i) { - Value& targetNameValue = (*curTargetNames)[i]; + Value &targetNameValue = (*curTargetNames)[i]; if (targetNameValue.IsString()) { this->targetNames[i] = targetNameValue.GetString(); } @@ -1188,8 +1246,6 @@ inline void Node::Read(Value &obj, Asset &r) { } } - // Do not retrieve a skin here, just take a reference, to avoid infinite recursion - // Skins will be properly loaded later Value *curSkin = FindUInt(obj, "skin"); if (nullptr != curSkin) { this->skin = r.skins.Get(curSkin->GetUint()); @@ -1597,7 +1653,7 @@ inline std::string Asset::FindUniqueID(const std::string &str, const char *suffi } #ifdef _WIN32 -# pragma warning(pop) +#pragma warning(pop) #endif // _WIN32 } // namespace glTF2