Browse Source

Merge pull request #3223 from assimp/zyndor-master

Zyndor master
Kim Kulling 5 years ago
parent
commit
22607de237
2 changed files with 148 additions and 30 deletions
  1. 79 5
      code/AssetLib/glTF2/glTF2Asset.h
  2. 69 25
      code/AssetLib/glTF2/glTF2Asset.inl

+ 79 - 5
code/AssetLib/glTF2/glTF2Asset.h

@@ -363,20 +363,44 @@ struct Object {
 // 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 {
+//! 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> 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 Sparse;
+
     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<double> max; //!< Maximum value of each component in this attribute.
     std::vector<double> min; //!< Minimum value of each component in this attribute.
+    std::unique_ptr<Sparse> sparse; //!< Sparse accessor information
 
     unsigned int GetNumComponents();
-    unsigned int GetBytesPerComponent();
     unsigned int GetElementSize();
 
     inline uint8_t *GetPointer();
@@ -417,11 +441,61 @@ struct Accessor : public Object {
         }
     };
 
+    //! Sparse accessor information
+    struct Sparse {
+        size_t count;
+        ComponentTypedBufferViewClient indices;
+        BufferViewClient values;
+
+        std::vector<uint8_t> 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<uint16_t *>(pIndices);
+                    break;
+                case ComponentType_UNSIGNED_INT:
+                    offset = *reinterpret_cast<uint32_t *>(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);
 };
 

+ 69 - 25
code/AssetLib/glTF2/glTF2Asset.inl

@@ -551,52 +551,96 @@ inline void BufferView::Read(Value &obj, Asset &r) {
 }
 
 //
-// struct Accessor
+// struct BufferViewClient
 //
 
-inline void Accessor::Read(Value &obj, Asset &r) {
+inline uint8_t *BufferViewClient::GetPointer() {
+    if (!bufferView || !bufferView->buffer) return 0;
+    uint8_t *basePtr = bufferView->buffer->GetPointer();
+    if (!basePtr) return 0;
+
+    size_t offset = byteOffset + bufferView->byteOffset;
+
+    // Check if region is encoded.
+    if (bufferView->buffer->EncodedRegion_Current != nullptr) {
+        const size_t begin = bufferView->buffer->EncodedRegion_Current->Offset;
+        const size_t end = begin + bufferView->buffer->EncodedRegion_Current->DecodedData_Length;
+
+        if ((offset >= begin) && (offset < end))
+            return &bufferView->buffer->EncodedRegion_Current->DecodedData[offset - begin];
+    }
+
+    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));
-    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;
 }
 
-inline unsigned int Accessor::GetNumComponents() {
-    return AttribType::GetNumComponents(type);
-}
+//
+// struct ComponentTypedBufferViewClient
+//
 
-inline unsigned int Accessor::GetBytesPerComponent() {
+inline unsigned int ComponentTypedBufferViewClient::GetBytesPerComponent() {
     return int(ComponentTypeSize(componentType));
 }
 
-inline unsigned int Accessor::GetElementSize() {
-    return GetNumComponents() * GetBytesPerComponent();
+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 (!bufferView || !bufferView->buffer) return 0;
-    uint8_t *basePtr = bufferView->buffer->GetPointer();
-    if (!basePtr) return 0;
+    if (!sparse) return BufferViewClient::GetPointer();
 
-    size_t offset = byteOffset + bufferView->byteOffset;
+    return sparse->data.data();
+}
 
-    // Check if region is encoded.
-    if (bufferView->buffer->EncodedRegion_Current != nullptr) {
-        const size_t begin = bufferView->buffer->EncodedRegion_Current->Offset;
-        const size_t end = begin + bufferView->buffer->EncodedRegion_Current->DecodedData_Length;
+inline void Accessor::Read(Value &obj, Asset &r) {
 
-        if ((offset >= begin) && (offset < end))
-            return &bufferView->buffer->EncodedRegion_Current->DecodedData[offset - begin];
+    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);
     }
+}
 
-    return basePtr + offset;
+inline unsigned int Accessor::GetNumComponents() {
+    return AttribType::GetNumComponents(type);
+}
+
+inline unsigned int Accessor::GetElementSize() {
+    return GetNumComponents() * GetBytesPerComponent();
 }
 
 namespace {
@@ -635,7 +679,7 @@ void Accessor::ExtractData(T *&outData)
     const size_t targetElemSize = sizeof(T);
     ai_assert(elemSize <= targetElemSize);
 
-    ai_assert(count * stride <= bufferView->byteLength);
+    ai_assert(count * stride <= (bufferView ? bufferView->byteLength : sparse->data.size()));
 
     outData = new T[count];
     if (stride == elemSize && targetElemSize == elemSize) {