Browse Source

Merge pull request #3219 from thomasbiang/gltf2_sparseAccessor_import

Gltf2 Support Importing sparse accessor
Kim Kulling 5 years ago
parent
commit
1427e67b54
2 changed files with 189 additions and 166 deletions
  1. 69 102
      code/AssetLib/glTF2/glTF2Asset.h
  2. 120 64
      code/AssetLib/glTF2/glTF2Asset.inl

+ 69 - 102
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_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_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));
     }
 }
 
@@ -318,9 +318,11 @@ class Ref {
 
 public:
     Ref() :
-            vector(0), index(0) {}
+            vector(0),
+            index(0) {}
     Ref(std::vector<T *> &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> 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> 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<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
+    std::unique_ptr<Sparse> sparse;
 
     unsigned int GetNumComponents();
+    unsigned int GetBytesPerComponent();
     unsigned int GetElementSize();
 
     inline uint8_t *GetPointer();
 
-    template<class T>
+    template <class T>
     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 <class T>
@@ -441,62 +422,27 @@ struct Accessor : public ComponentTypedBufferViewClient {
         }
     };
 
-    //! 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);
+
+    //sparse
+    struct Sparse {
+        size_t count;
+        ComponentType indicesType;
+        Ref<BufferView> indices;
+        size_t indicesByteOffset;
+        Ref<BufferView> values;
+        size_t valuesByteOffset;
+
+        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.
+
+        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<unsigned int> mRecursiveReferenceCheck;  //! Used by Retrieve to prevent recursive lookups
+    std::gltf_unordered_set<unsigned int> 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));
     }

+ 120 - 64
code/AssetLib/glTF2/glTF2Asset.inl

@@ -180,7 +180,10 @@ inline Value *FindObject(Value &val, const char *id) {
 
 template <class T>
 inline LazyDict<T>::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<T> LazyDict<T>::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,67 +556,72 @@ inline void BufferView::Read(Value &obj, Asset &r) {
     byteStride = MemberOrDefault(obj, "byteStride", 0u);
 }
 
-//
-// struct BufferViewClient
-//
-
-inline uint8_t *BufferViewClient::GetPointer() {
-    if (!bufferView || !bufferView->buffer) return 0;
-    uint8_t *basePtr = bufferView->buffer->GetPointer();
+inline uint8_t *BufferView::GetPointer(size_t accOffset) {
+    if (!buffer) return 0;
+    uint8_t *basePtr = 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;
-
+    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 &bufferView->buffer->EncodedRegion_Current->DecodedData[offset - begin];
+            return &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));
-}
-
-//
-// 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 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<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.");
+        }
 
-inline uint8_t *Accessor::GetPointer() {
-    if (!sparse) return BufferViewClient::GetPointer();
+        offset *= elementSize;
+        std::memcpy(data.data() + offset, pValues, elementSize);
 
-    return sparse->data.data();
+        pValues += elementSize;
+        pIndices += indexSize;
+    }
 }
 
 inline void Accessor::Read(Value &obj, Asset &r) {
 
-    ComponentTypedBufferViewClient::Read(obj, 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;
@@ -618,19 +629,37 @@ inline void Accessor::Read(Value &obj, Asset &r) {
 
     if (Value *sparseValue = FindObject(obj, "sparse")) {
         sparse.reset(new Sparse);
+        // count
         ReadMember(*sparseValue, "count", sparse->count);
 
+        // indices
         if (Value *indicesValue = FindObject(*sparseValue, "indices")) {
-            sparse->indices.Read(*indicesValue, r);
+            //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")) {
-            sparse->values.Read(*valuesValue, r);
+            //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, BufferViewClient::GetPointer());
+        sparse->PopulateData(dataSize, bufferView ? bufferView->GetPointer(byteOffset) : 0);
         sparse->PatchData(elementSize);
     }
 }
@@ -639,10 +668,36 @@ 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();
+
+    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;
+}
+
 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<class T>
-void Accessor::ExtractData(T *&outData)
-{
-    uint8_t* data = GetPointer();
+template <class T>
+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