static bool ParseDracoExtension(Primitive *primitive, Model *model,
                                std::string *err,
                                const Value &dracoExtensionValue) {
  (void)err;
  auto bufferViewValue = dracoExtensionValue.Get("bufferView");
  if (!bufferViewValue.IsInt()) return false;
  auto attributesValue = dracoExtensionValue.Get("attributes");
  if (!attributesValue.IsObject()) return false;

  auto attributesObject = attributesValue.Get<Value::Object>();
  int bufferView = bufferViewValue.Get<int>();

  BufferView &view = model->bufferViews[bufferView];
  Buffer &buffer = model->buffers[view.buffer];
  // BufferView has already been decoded
  if (view.dracoDecoded) return true;
  view.dracoDecoded = true;

  const char *bufferViewData =
      reinterpret_cast<const char *>(buffer.data.data() + view.byteOffset);
  size_t bufferViewSize = view.byteLength;

  // decode draco
  draco::DecoderBuffer decoderBuffer;
  decoderBuffer.Init(bufferViewData, bufferViewSize);
  draco::Decoder decoder;
  auto decodeResult = decoder.DecodeMeshFromBuffer(&decoderBuffer);
  if (!decodeResult.ok()) {
    return false;
  }
  const std::unique_ptr<draco::Mesh> &mesh = decodeResult.value();

  // create new bufferView for indices
  if (primitive->indices >= 0) {
    int32_t componentSize = GetComponentSizeInBytes(
        model->accessors[primitive->indices].componentType);
    Buffer decodedIndexBuffer;
    decodedIndexBuffer.data.resize(mesh->num_faces() * 3 * componentSize);

    DecodeIndexBuffer(mesh.get(), componentSize, decodedIndexBuffer.data);

    model->buffers.emplace_back(std::move(decodedIndexBuffer));

    BufferView decodedIndexBufferView;
    decodedIndexBufferView.buffer = int(model->buffers.size() - 1);
    decodedIndexBufferView.byteLength =
        int(mesh->num_faces() * 3 * componentSize);
    decodedIndexBufferView.byteOffset = 0;
    decodedIndexBufferView.byteStride = 0;
    decodedIndexBufferView.target = TINYGLTF_TARGET_ARRAY_BUFFER;
    model->bufferViews.emplace_back(std::move(decodedIndexBufferView));

    model->accessors[primitive->indices].bufferView =
        int(model->bufferViews.size() - 1);
    model->accessors[primitive->indices].count = int(mesh->num_faces() * 3);
  }

  for (const auto &attribute : attributesObject) {
    if (!attribute.second.IsInt()) return false;
    auto primitiveAttribute = primitive->attributes.find(attribute.first);
    if (primitiveAttribute == primitive->attributes.end()) return false;

    int dracoAttributeIndex = attribute.second.Get<int>();
    const auto pAttribute = mesh->GetAttributeByUniqueId(dracoAttributeIndex);
    const auto componentType =
        model->accessors[primitiveAttribute->second].componentType;

    // Create a new buffer for this decoded buffer
    Buffer decodedBuffer;
    size_t bufferSize = mesh->num_points() * pAttribute->num_components() *
                        GetComponentSizeInBytes(componentType);
    decodedBuffer.data.resize(bufferSize);

    if (!GetAttributeForAllPoints(componentType, mesh.get(), pAttribute,
                                  decodedBuffer.data))
      return false;

    model->buffers.emplace_back(std::move(decodedBuffer));

    BufferView decodedBufferView;
    decodedBufferView.buffer = int(model->buffers.size() - 1);
    decodedBufferView.byteLength = bufferSize;
    decodedBufferView.byteOffset = pAttribute->byte_offset();
    decodedBufferView.byteStride = pAttribute->byte_stride();
    decodedBufferView.target = primitive->indices >= 0
                                   ? TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER
                                   : TINYGLTF_TARGET_ARRAY_BUFFER;
    model->bufferViews.emplace_back(std::move(decodedBufferView));

    model->accessors[primitiveAttribute->second].bufferView =
        int(model->bufferViews.size() - 1);
    model->accessors[primitiveAttribute->second].count =
        int(mesh->num_points());
  }

  return true;
}
static bool ParseDracoExtension(Primitive *primitive, Model *model,
                                std::string *err,
                                const Value &dracoExtensionValue) {
  (void)err;
  auto bufferViewValue = dracoExtensionValue.Get("bufferView");
  if (!bufferViewValue.IsInt()) return false;
  auto attributesValue = dracoExtensionValue.Get("attributes");
  if (!attributesValue.IsObject()) return false;

  auto attributesObject = attributesValue.Get<Value::Object>();
  int bufferView = bufferViewValue.Get<int>();

  BufferView &view = model->bufferViews[bufferView];
  Buffer &buffer = model->buffers[view.buffer];
   
  if (view.dracoDecoded) return true;
  view.dracoDecoded = true;

  const char *bufferViewData =
      reinterpret_cast<const char *>(buffer.data.data() + view.byteOffset);
  size_t bufferViewSize = view.byteLength;

   
  draco::DecoderBuffer decoderBuffer;
  decoderBuffer.Init(bufferViewData, bufferViewSize);
  draco::Decoder decoder;
  auto decodeResult = decoder.DecodeMeshFromBuffer(&decoderBuffer);
  if (!decodeResult.ok()) {
    return false;
  }
  const std::unique_ptr<draco::Mesh> &mesh = decodeResult.value();

   
  if (primitive->indices >= 0) {
    int32_t componentSize = GetComponentSizeInBytes(
        model->accessors[primitive->indices].componentType);
    Buffer decodedIndexBuffer;
    decodedIndexBuffer.data.resize(mesh->num_faces() * 3 * componentSize);

    DecodeIndexBuffer(mesh.get(), componentSize, decodedIndexBuffer.data);

    model->buffers.emplace_back(std::move(decodedIndexBuffer));

    BufferView decodedIndexBufferView;
    decodedIndexBufferView.buffer = int(model->buffers.size() - 1);
    decodedIndexBufferView.byteLength =
        int(mesh->num_faces() * 3 * componentSize);
    decodedIndexBufferView.byteOffset = 0;
    decodedIndexBufferView.byteStride = 0;
    decodedIndexBufferView.target = TINYGLTF_TARGET_ARRAY_BUFFER;
    model->bufferViews.emplace_back(std::move(decodedIndexBufferView));

    model->accessors[primitive->indices].bufferView =
        int(model->bufferViews.size() - 1);
    model->accessors[primitive->indices].count = int(mesh->num_faces() * 3);
  }

  for (const auto &attribute : attributesObject) {
    if (!attribute.second.IsInt()) return false;
    auto primitiveAttribute = primitive->attributes.find(attribute.first);
    if (primitiveAttribute == primitive->attributes.end()) return false;

    int dracoAttributeIndex = attribute.second.Get<int>();
    const auto pAttribute = mesh->GetAttributeByUniqueId(dracoAttributeIndex);
    const auto componentType =
        model->accessors[primitiveAttribute->second].componentType;

     
    Buffer decodedBuffer;
    size_t bufferSize = mesh->num_points() * pAttribute->num_components() *
                        GetComponentSizeInBytes(componentType);
    decodedBuffer.data.resize(bufferSize);

    if (!GetAttributeForAllPoints(componentType, mesh.get(), pAttribute,
                                  decodedBuffer.data))
      return false;

    model->buffers.emplace_back(std::move(decodedBuffer));

    BufferView decodedBufferView;
    decodedBufferView.buffer = int(model->buffers.size() - 1);
    decodedBufferView.byteLength = bufferSize;
    decodedBufferView.byteOffset = pAttribute->byte_offset();
    decodedBufferView.byteStride = pAttribute->byte_stride();
    decodedBufferView.target = primitive->indices >= 0
                                   ? TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER
                                   : TINYGLTF_TARGET_ARRAY_BUFFER;
    model->bufferViews.emplace_back(std::move(decodedBufferView));

    model->accessors[primitiveAttribute->second].bufferView =
        int(model->bufferViews.size() - 1);
    model->accessors[primitiveAttribute->second].count =
        int(mesh->num_points());
  }

  return true;
}