From 1ccb4ff5802561fad3942df7f1e5e0f896018bb9 Mon Sep 17 00:00:00 2001 From: "Arthur Brainville (Ybalrid)" Date: Wed, 6 Mar 2019 11:30:00 +0100 Subject: [PATCH 1/6] added sparse structure to accessors --- tiny_gltf.h | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/tiny_gltf.h b/tiny_gltf.h index ed9e497..90b73c9 100644 --- a/tiny_gltf.h +++ b/tiny_gltf.h @@ -575,7 +575,19 @@ struct Accessor { std::vector minValues; // optional std::vector maxValues; // optional - // TODO(syoyo): "sparse" + struct { + int count; + bool isSparse; + struct { + int byteOffset; + int bufferView; + int component_type; // a TINYGLTF_COMPONENT_TYPE_ value + } indices; + struct { + int bufferView; + int byteOffset; + } values; + } sparse; /// /// Utility function to compute byteStride for a given bufferView object. @@ -614,7 +626,7 @@ struct Accessor { return 0; } - Accessor() { bufferView = -1; } + Accessor() { bufferView = -1; sparse.isSparse = false } bool operator==(const tinygltf::Accessor &) const; }; From 9d86405d3d551d5c0fdc5977e28988b8838ad0d1 Mon Sep 17 00:00:00 2001 From: "Arthur Brainville (Ybalrid)" Date: Wed, 6 Mar 2019 11:33:30 +0000 Subject: [PATCH 2/6] Fix accessor ctor --- tiny_gltf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tiny_gltf.h b/tiny_gltf.h index 90b73c9..13110ff 100644 --- a/tiny_gltf.h +++ b/tiny_gltf.h @@ -626,7 +626,7 @@ struct Accessor { return 0; } - Accessor() { bufferView = -1; sparse.isSparse = false } + Accessor() { bufferView = -1; sparse.isSparse = false; } bool operator==(const tinygltf::Accessor &) const; }; From 7e9f734d736aa9822df08705afe7ff92a479f271 Mon Sep 17 00:00:00 2001 From: "Arthur Brainville (Ybalrid)" Date: Wed, 6 Mar 2019 12:27:23 +0000 Subject: [PATCH 3/6] Parse sparse accessors --- tiny_gltf.h | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/tiny_gltf.h b/tiny_gltf.h index 13110ff..3f5fcd4 100644 --- a/tiny_gltf.h +++ b/tiny_gltf.h @@ -581,7 +581,7 @@ struct Accessor { struct { int byteOffset; int bufferView; - int component_type; // a TINYGLTF_COMPONENT_TYPE_ value + int componentType; // a TINYGLTF_COMPONENT_TYPE_ value } indices; struct { int bufferView; @@ -2816,10 +2816,55 @@ static bool ParseBufferView(BufferView *bufferView, std::string *err, bufferView->byteOffset = static_cast(byteOffset); bufferView->byteLength = static_cast(byteLength); bufferView->byteStride = static_cast(byteStride); - return true; } +static bool ParseSparseAccessor(Accessor* accessor, std::string* err, const json &o) +{ + accessor->sparse.isSparse = true; + + double count = 0.0; + ParseNumberProperty(&count, err, o, "count", true); + + const auto indices_iterator = o.find("indices"); + const auto values_iterator = o.find("values"); + if(indices_iterator == o.end()) + { + (*err) = "the sparse object of this accessor doesn't have indices"; + return false; + } + + if(values_iterator == o.end()) + { + (*err) = "the sparse object ob ths accessor doesn't have values"; + return false; + } + + + const json& indices_obj = *indices_iterator; + const json& values_obj = *values_iterator; + + double indices_buffer_view = 0.0, indices_byte_offset = 0.0, component_type = 0.0; + ParseNumberProperty(&indices_buffer_view, err, indices_obj, "bufferView", true); + ParseNumberProperty(&indices_byte_offset, err, indices_obj, "byteOffset", true); + ParseNumberProperty(&component_type, err, indices_obj, "componentType", true); + + double values_buffer_view = 0.0, values_byte_offset = 0.0; + ParseNumberProperty(&values_buffer_view, err, values_obj, "bufferView", true); + ParseNumberProperty(&values_byte_offset, err, values_obj, "byteOffset", true); + + accessor->sparse.count = static_cast(count); + accessor->sparse.indices.bufferView = static_cast(indices_buffer_view); + accessor->sparse.indices.byteOffset = static_cast(indices_byte_offset); + accessor->sparse.indices.componentType = static_cast(component_type); + accessor->sparse.values.bufferView = static_cast(values_buffer_view); + accessor->sparse.values.byteOffset = static_cast(values_byte_offset); + + //todo check theses values + + return true; +} + static bool ParseAccessor(Accessor *accessor, std::string *err, const json &o) { double bufferView = -1.0; ParseNumberProperty(&bufferView, err, o, "bufferView", false, "Accessor"); @@ -2901,6 +2946,14 @@ static bool ParseAccessor(Accessor *accessor, std::string *err, const json &o) { ParseExtrasProperty(&(accessor->extras), o); + //check if accessor has a "sparse" object: + const auto iterator = o.find("sparse"); + if(iterator != o.end()) + { + //here this accessor has a "sparse" subobject + return ParseSparseAccessor(accessor, err, *iterator); + } + return true; } From 9b321a8515261edef46994c345c37eb76eb5036e Mon Sep 17 00:00:00 2001 From: "Arthur Brainville (Ybalrid)" Date: Wed, 6 Mar 2019 12:39:39 +0000 Subject: [PATCH 4/6] clang-format + added sparse accessor in loader_example --- loader_example.cc | 54 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/loader_example.cc b/loader_example.cc index 7f8a426..c0eec95 100644 --- a/loader_example.cc +++ b/loader_example.cc @@ -228,7 +228,8 @@ static std::string PrintParameterMap(const tinygltf::ParameterMap &pmap) { #endif static std::string PrintValue(const std::string &name, - const tinygltf::Value &value, const int indent, const bool tag = true) { + const tinygltf::Value &value, const int indent, + const bool tag = true) { std::stringstream ss; if (value.IsObject()) { @@ -265,11 +266,10 @@ static std::string PrintValue(const std::string &name, } else if (value.IsArray()) { ss << Indent(indent) << name << " [ "; for (size_t i = 0; i < value.Size(); i++) { - ss << PrintValue("", value.Get(int(i)), indent + 1, /* tag */false); - if (i != (value.ArrayLen()-1)) { + ss << PrintValue("", value.Get(int(i)), indent + 1, /* tag */ false); + if (i != (value.ArrayLen() - 1)) { ss << ", "; } - } ss << Indent(indent) << "] "; } @@ -330,13 +330,13 @@ static void DumpPrimitive(const tinygltf::Primitive &primitive, int indent) { << PrintValue("extras", primitive.extras, indent + 1) << std::endl; } -static void DumpExtensions(const tinygltf::ExtensionMap &extension, const int indent) -{ +static void DumpExtensions(const tinygltf::ExtensionMap &extension, + const int indent) { // TODO(syoyo): pritty print Value for (auto &e : extension) { std::cout << Indent(indent) << e.first << std::endl; - std::cout << PrintValue("extensions", e.second, indent+1) << std::endl; - } + std::cout << PrintValue("extensions", e.second, indent + 1) << std::endl; + } } static void Dump(const tinygltf::Model &model) { @@ -409,6 +409,30 @@ static void Dump(const tinygltf::Model &model) { } std::cout << "]" << std::endl; } + + if (accessor.sparse.isSparse) { + std::cout << Indent(2) << "sparse:" << std::endl; + std::cout << Indent(3) << "count : " << accessor.sparse.count + << std::endl; + std::cout << Indent(3) << "indices: " << std::endl; + std::cout << Indent(4) + << "bufferView : " << accessor.sparse.indices.bufferView + << std::endl; + std::cout << Indent(4) + << "byteOffset : " << accessor.sparse.indices.byteOffset + << std::endl; + std::cout << Indent(4) << "componentType: " + << PrintComponentType(accessor.sparse.indices.componentType) + << "(" << accessor.sparse.indices.componentType << ")" + << std::endl; + std::cout << Indent(3) << "values : " << std::endl; + std::cout << Indent(4) + << "bufferView : " << accessor.sparse.values.bufferView + << std::endl; + std::cout << Indent(4) + << "byteOffset : " << accessor.sparse.values.byteOffset + << std::endl; + } } } @@ -585,10 +609,11 @@ static void Dump(const tinygltf::Model &model) { } } } - + // toplevel extensions { - std::cout << "extensions(items=" << model.extensions.size() << ")" << std::endl; + std::cout << "extensions(items=" << model.extensions.size() << ")" + << std::endl; DumpExtensions(model.extensions, 1); } } @@ -602,7 +627,7 @@ int main(int argc, char **argv) { tinygltf::Model model; tinygltf::TinyGLTF gltf_ctx; std::string err; - std::string warn; + std::string warn; std::string input_filename(argv[1]); std::string ext = GetFilePathExtension(input_filename); @@ -610,18 +635,19 @@ int main(int argc, char **argv) { if (ext.compare("glb") == 0) { std::cout << "Reading binary glTF" << std::endl; // assume binary glTF. - ret = gltf_ctx.LoadBinaryFromFile(&model, &err, &warn, input_filename.c_str()); + ret = gltf_ctx.LoadBinaryFromFile(&model, &err, &warn, + input_filename.c_str()); } else { std::cout << "Reading ASCII glTF" << std::endl; // assume ascii glTF. - ret = gltf_ctx.LoadASCIIFromFile(&model, &err, &warn, input_filename.c_str()); + ret = + gltf_ctx.LoadASCIIFromFile(&model, &err, &warn, input_filename.c_str()); } if (!warn.empty()) { printf("Warn: %s\n", warn.c_str()); } - if (!err.empty()) { printf("Err: %s\n", err.c_str()); } From 9223d3133a7cb70cbbe7b292c190319e2bdeb6aa Mon Sep 17 00:00:00 2001 From: "Arthur Brainville (Ybalrid)" Date: Wed, 6 Mar 2019 14:00:56 +0000 Subject: [PATCH 5/6] Ran clang-format on tiny_gltf.h --- tiny_gltf.h | 489 ++++++++++++++++++++++++++++------------------------ 1 file changed, 263 insertions(+), 226 deletions(-) diff --git a/tiny_gltf.h b/tiny_gltf.h index 3f5fcd4..e8d5a60 100644 --- a/tiny_gltf.h +++ b/tiny_gltf.h @@ -149,7 +149,7 @@ namespace tinygltf { #ifdef __ANDROID__ #ifdef TINYGLTF_ANDROID_LOAD_FROM_ASSETS - AAssetManager* asset_manager = nullptr; +AAssetManager *asset_manager = nullptr; #endif #endif @@ -380,15 +380,15 @@ struct Parameter { return -1; } - /// Return the index of a texture coordinate set if this Parameter is a texture map. - /// Returned value is only valid if the parameter represent a texture from a - /// material + /// Return the index of a texture coordinate set if this Parameter is a + /// texture map. Returned value is only valid if the parameter represent a + /// texture from a material int TextureTexCoord() const { - const auto it = json_double_value.find("texCoord"); - if (it != std::end(json_double_value)) { - return int(it->second); - } - return 0; + const auto it = json_double_value.find("texCoord"); + if (it != std::end(json_double_value)) { + return int(it->second); + } + return 0; } /// Material factor, like the roughness or metalness of a material @@ -483,7 +483,7 @@ struct Sampler { magFilter(TINYGLTF_TEXTURE_FILTER_LINEAR), wrapS(TINYGLTF_TEXTURE_WRAP_REPEAT), wrapT(TINYGLTF_TEXTURE_WRAP_REPEAT), - wrapR(TINYGLTF_TEXTURE_WRAP_REPEAT){} + wrapR(TINYGLTF_TEXTURE_WRAP_REPEAT) {} bool operator==(const Sampler &) const; }; @@ -492,8 +492,9 @@ struct Image { int width; int height; int component; - int bits; // bit depth per channel. 8(byte), 16 or 32. - int pixel_type; // pixel type(TINYGLTF_COMPONENT_TYPE_***). usually UBYTE(bits = 8) or USHORT(bits = 16) + int bits; // bit depth per channel. 8(byte), 16 or 32. + int pixel_type; // pixel type(TINYGLTF_COMPONENT_TYPE_***). usually + // UBYTE(bits = 8) or USHORT(bits = 16) std::vector image; int bufferView; // (required if no uri) std::string mimeType; // (required if no uri) ["image/jpeg", "image/png", @@ -576,17 +577,17 @@ struct Accessor { std::vector maxValues; // optional struct { - int count; - bool isSparse; - struct { - int byteOffset; - int bufferView; - int componentType; // a TINYGLTF_COMPONENT_TYPE_ value - } indices; - struct { - int bufferView; - int byteOffset; - } values; + int count; + bool isSparse; + struct { + int byteOffset; + int bufferView; + int componentType; // a TINYGLTF_COMPONENT_TYPE_ value + } indices; + struct { + int bufferView; + int byteOffset; + } values; } sparse; /// @@ -626,7 +627,10 @@ struct Accessor { return 0; } - Accessor() { bufferView = -1; sparse.isSparse = false; } + Accessor() { + bufferView = -1; + sparse.isSparse = false; + } bool operator==(const tinygltf::Accessor &) const; }; @@ -832,9 +836,9 @@ enum SectionCheck { /// /// LoadImageDataFunction type. Signature for custom image loading callbacks. /// -typedef bool (*LoadImageDataFunction)(Image *, const int, std::string *, std::string *, - int, int, const unsigned char *, int, - void *); +typedef bool (*LoadImageDataFunction)(Image *, const int, std::string *, + std::string *, int, int, + const unsigned char *, int, void *); /// /// WriteImageDataFunction type. Signature for custom image writing callbacks. @@ -844,9 +848,9 @@ typedef bool (*WriteImageDataFunction)(const std::string *, const std::string *, #ifndef TINYGLTF_NO_STB_IMAGE // Declaration of default image loader callback -bool LoadImageData(Image *image, const int image_idx, std::string *err, std::string *warn, - int req_width, int req_height, const unsigned char *bytes, - int size, void *); +bool LoadImageData(Image *image, const int image_idx, std::string *err, + std::string *warn, int req_width, int req_height, + const unsigned char *bytes, int size, void *); #endif #ifndef TINYGLTF_NO_STB_IMAGE_WRITE @@ -966,10 +970,8 @@ class TinyGLTF { /// Write glTF to file. /// bool WriteGltfSceneToFile(Model *model, const std::string &filename, - bool embedImages, - bool embedBuffers, - bool prettyPrint, - bool writeBinary); + bool embedImages, bool embedBuffers, + bool prettyPrint, bool writeBinary); /// /// Set callback to use for loading image data @@ -1096,8 +1098,8 @@ class TinyGLTF { #endif #ifdef TINYGLTF_ENABLE_DRACO -#include "draco/core/decoder_buffer.h" #include "draco/compression/decode.h" +#include "draco/core/decoder_buffer.h" #endif #ifndef TINYGLTF_NO_STB_IMAGE @@ -1130,7 +1132,7 @@ class TinyGLTF { #define WIN32_LEAN_AND_MEAN #define TINYGLTF_INTERNAL_WIN32_LEAN_AND_MEAN #endif -#include // include API for expanding a file path +#include // include API for expanding a file path #ifdef TINYGLTF_INTERNAL_WIN32_LEAN_AND_MEAN #undef WIN32_LEAN_AND_MEAN @@ -1836,16 +1838,17 @@ void TinyGLTF::SetFsCallbacks(FsCallbacks callbacks) { fs = callbacks; } bool FileExists(const std::string &abs_filename, void *) { bool ret; #ifdef TINYGLTF_ANDROID_LOAD_FROM_ASSETS - if (asset_manager) { - AAsset* asset = AAssetManager_open(asset_manager, abs_filename.c_str(), AASSET_MODE_STREAMING); - if (!asset) { - return false; - } - AAsset_close(asset); - ret = true; - } else { + if (asset_manager) { + AAsset *asset = AAssetManager_open(asset_manager, abs_filename.c_str(), + AASSET_MODE_STREAMING); + if (!asset) { return false; } + AAsset_close(asset); + ret = true; + } else { + return false; + } #else #ifdef _WIN32 FILE *fp; @@ -1918,7 +1921,8 @@ bool ReadWholeFile(std::vector *out, std::string *err, const std::string &filepath, void *) { #ifdef TINYGLTF_ANDROID_LOAD_FROM_ASSETS if (asset_manager) { - AAsset* asset = AAssetManager_open(asset_manager, filepath.c_str(), AASSET_MODE_STREAMING); + AAsset *asset = AAssetManager_open(asset_manager, filepath.c_str(), + AASSET_MODE_STREAMING); if (!asset) { if (err) { (*err) += "File open error : " + filepath + "\n"; @@ -2495,12 +2499,13 @@ static bool ParseExtensionsProperty(ExtensionMap *ret, std::string *err, json::const_iterator extIt = it.value().begin(); for (; extIt != it.value().end(); extIt++) { if (!extIt.value().is_object()) continue; - if (!ParseJsonAsValue(&extensions[extIt.key()], extIt.value())) { + if (!ParseJsonAsValue(&extensions[extIt.key()], extIt.value())) { if (!extIt.key().empty()) { - // create empty object so that an extension object is still of type object - extensions[extIt.key()] = Value{ Value::Object{} }; + // create empty object so that an extension object is still of type + // object + extensions[extIt.key()] = Value{Value::Object{}}; } - } + } } if (ret) { (*ret) = extensions; @@ -2521,9 +2526,9 @@ static bool ParseAsset(Asset *asset, std::string *err, const json &o) { return true; } -static bool ParseImage(Image *image, const int image_idx, std::string *err, std::string *warn, - const json &o, const std::string &basedir, - FsCallbacks *fs, +static bool ParseImage(Image *image, const int image_idx, std::string *err, + std::string *warn, const json &o, + const std::string &basedir, FsCallbacks *fs, LoadImageDataFunction *LoadImageData = nullptr, void *load_image_user_data = nullptr) { // A glTF image must either reference a bufferView or an image uri @@ -2540,14 +2545,17 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err, std: if (err) { (*err) += "Only one of `bufferView` or `uri` should be defined, but both are " - "defined for image[" + std::to_string(image_idx) + "] name = \"" + image->name + "\"\n"; + "defined for image[" + + std::to_string(image_idx) + "] name = \"" + image->name + "\"\n"; } return false; } if (!hasBufferView && !hasURI) { if (err) { - (*err) += "Neither required `bufferView` nor `uri` defined for image[" + std::to_string(image_idx) + "] name = \"" + image->name + "\"\n"; + (*err) += "Neither required `bufferView` nor `uri` defined for image[" + + std::to_string(image_idx) + "] name = \"" + image->name + + "\"\n"; } return false; } @@ -2559,7 +2567,9 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err, std: double bufferView = -1; if (!ParseNumberProperty(&bufferView, err, o, "bufferView", true)) { if (err) { - (*err) += "Failed to parse `bufferView` for image[" + std::to_string(image_idx) + "] name = \"" + image->name + "\"\n"; + (*err) += "Failed to parse `bufferView` for image[" + + std::to_string(image_idx) + "] name = \"" + image->name + + "\"\n"; } return false; } @@ -2589,7 +2599,8 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err, std: std::string tmp_err; if (!ParseStringProperty(&uri, &tmp_err, o, "uri", true)) { if (err) { - (*err) += "Failed to parse `uri` for image[" + std::to_string(image_idx) + "] name = \"" + image->name + "\".\n"; + (*err) += "Failed to parse `uri` for image[" + std::to_string(image_idx) + + "] name = \"" + image->name + "\".\n"; } return false; } @@ -2599,7 +2610,9 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err, std: if (IsDataURI(uri)) { if (!DecodeDataURI(&img, image->mimeType, uri, 0, false)) { if (err) { - (*err) += "Failed to decode 'uri' for image[" + std::to_string(image_idx) + "] name = [" + image->name + "]\n"; + (*err) += "Failed to decode 'uri' for image[" + + std::to_string(image_idx) + "] name = [" + image->name + + "]\n"; } return false; } @@ -2612,7 +2625,9 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err, std: #endif if (!LoadExternalFile(&img, err, warn, uri, basedir, false, 0, false, fs)) { if (warn) { - (*warn) += "Failed to load external 'uri' for image[" + std::to_string(image_idx) + "] name = [" + image->name + "]\n"; + (*warn) += "Failed to load external 'uri' for image[" + + std::to_string(image_idx) + "] name = [" + image->name + + "]\n"; } // If the image cannot be loaded, keep uri as image->uri. return true; @@ -2620,7 +2635,9 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err, std: if (img.empty()) { if (warn) { - (*warn) += "Image data is empty for image[" + std::to_string(image_idx) + "] name = [" + image->name + "] \n"; + (*warn) += "Image data is empty for image[" + + std::to_string(image_idx) + "] name = [" + image->name + + "] \n"; } return false; } @@ -2819,50 +2836,50 @@ static bool ParseBufferView(BufferView *bufferView, std::string *err, return true; } -static bool ParseSparseAccessor(Accessor* accessor, std::string* err, const json &o) -{ - accessor->sparse.isSparse = true; +static bool ParseSparseAccessor(Accessor *accessor, std::string *err, + const json &o) { + accessor->sparse.isSparse = true; - double count = 0.0; - ParseNumberProperty(&count, err, o, "count", true); + double count = 0.0; + ParseNumberProperty(&count, err, o, "count", true); - const auto indices_iterator = o.find("indices"); - const auto values_iterator = o.find("values"); - if(indices_iterator == o.end()) - { - (*err) = "the sparse object of this accessor doesn't have indices"; - return false; - } + const auto indices_iterator = o.find("indices"); + const auto values_iterator = o.find("values"); + if (indices_iterator == o.end()) { + (*err) = "the sparse object of this accessor doesn't have indices"; + return false; + } - if(values_iterator == o.end()) - { - (*err) = "the sparse object ob ths accessor doesn't have values"; - return false; - } - + if (values_iterator == o.end()) { + (*err) = "the sparse object ob ths accessor doesn't have values"; + return false; + } - const json& indices_obj = *indices_iterator; - const json& values_obj = *values_iterator; + const json &indices_obj = *indices_iterator; + const json &values_obj = *values_iterator; - double indices_buffer_view = 0.0, indices_byte_offset = 0.0, component_type = 0.0; - ParseNumberProperty(&indices_buffer_view, err, indices_obj, "bufferView", true); - ParseNumberProperty(&indices_byte_offset, err, indices_obj, "byteOffset", true); - ParseNumberProperty(&component_type, err, indices_obj, "componentType", true); + double indices_buffer_view = 0.0, indices_byte_offset = 0.0, + component_type = 0.0; + ParseNumberProperty(&indices_buffer_view, err, indices_obj, "bufferView", + true); + ParseNumberProperty(&indices_byte_offset, err, indices_obj, "byteOffset", + true); + ParseNumberProperty(&component_type, err, indices_obj, "componentType", true); - double values_buffer_view = 0.0, values_byte_offset = 0.0; - ParseNumberProperty(&values_buffer_view, err, values_obj, "bufferView", true); - ParseNumberProperty(&values_byte_offset, err, values_obj, "byteOffset", true); + double values_buffer_view = 0.0, values_byte_offset = 0.0; + ParseNumberProperty(&values_buffer_view, err, values_obj, "bufferView", true); + ParseNumberProperty(&values_byte_offset, err, values_obj, "byteOffset", true); - accessor->sparse.count = static_cast(count); - accessor->sparse.indices.bufferView = static_cast(indices_buffer_view); - accessor->sparse.indices.byteOffset = static_cast(indices_byte_offset); - accessor->sparse.indices.componentType = static_cast(component_type); - accessor->sparse.values.bufferView = static_cast(values_buffer_view); - accessor->sparse.values.byteOffset = static_cast(values_byte_offset); + accessor->sparse.count = static_cast(count); + accessor->sparse.indices.bufferView = static_cast(indices_buffer_view); + accessor->sparse.indices.byteOffset = static_cast(indices_byte_offset); + accessor->sparse.indices.componentType = static_cast(component_type); + accessor->sparse.values.bufferView = static_cast(values_buffer_view); + accessor->sparse.values.byteOffset = static_cast(values_byte_offset); - //todo check theses values + // todo check theses values - return true; + return true; } static bool ParseAccessor(Accessor *accessor, std::string *err, const json &o) { @@ -2946,12 +2963,11 @@ static bool ParseAccessor(Accessor *accessor, std::string *err, const json &o) { ParseExtrasProperty(&(accessor->extras), o); - //check if accessor has a "sparse" object: + // check if accessor has a "sparse" object: const auto iterator = o.find("sparse"); - if(iterator != o.end()) - { - //here this accessor has a "sparse" subobject - return ParseSparseAccessor(accessor, err, *iterator); + if (iterator != o.end()) { + // here this accessor has a "sparse" subobject + return ParseSparseAccessor(accessor, err, *iterator); } return true; @@ -2959,107 +2975,116 @@ static bool ParseAccessor(Accessor *accessor, std::string *err, const json &o) { #ifdef TINYGLTF_ENABLE_DRACO -static void DecodeIndexBuffer(draco::Mesh* mesh, size_t componentSize, std::vector& outBuffer) -{ - if (componentSize == 4) - { +static void DecodeIndexBuffer(draco::Mesh *mesh, size_t componentSize, + std::vector &outBuffer) { + if (componentSize == 4) { assert(sizeof(mesh->face(draco::FaceIndex(0))[0]) == componentSize); - memcpy(outBuffer.data(), &mesh->face(draco::FaceIndex(0))[0], outBuffer.size()); - } - else - { + memcpy(outBuffer.data(), &mesh->face(draco::FaceIndex(0))[0], + outBuffer.size()); + } else { size_t faceStride = componentSize * 3; - for (draco::FaceIndex f(0); f < mesh->num_faces(); ++f) - { - const draco::Mesh::Face& face = mesh->face(f); - if (componentSize == 2) - { - uint16_t indices[3] = { (uint16_t)face[0].value(), (uint16_t)face[1].value(), (uint16_t)face[2].value() }; - memcpy(outBuffer.data() + f.value() * faceStride, &indices[0], faceStride); - } - else - { - uint8_t indices[3] = { (uint8_t)face[0].value(), (uint8_t)face[1].value(), (uint8_t)face[2].value() }; - memcpy(outBuffer.data() + f.value() * faceStride, &indices[0], faceStride); + for (draco::FaceIndex f(0); f < mesh->num_faces(); ++f) { + const draco::Mesh::Face &face = mesh->face(f); + if (componentSize == 2) { + uint16_t indices[3] = {(uint16_t)face[0].value(), + (uint16_t)face[1].value(), + (uint16_t)face[2].value()}; + memcpy(outBuffer.data() + f.value() * faceStride, &indices[0], + faceStride); + } else { + uint8_t indices[3] = {(uint8_t)face[0].value(), + (uint8_t)face[1].value(), + (uint8_t)face[2].value()}; + memcpy(outBuffer.data() + f.value() * faceStride, &indices[0], + faceStride); } } } } -template -static bool GetAttributeForAllPoints(draco::Mesh* mesh, const draco::PointAttribute* pAttribute, std::vector& outBuffer) -{ +template +static bool GetAttributeForAllPoints(draco::Mesh *mesh, + const draco::PointAttribute *pAttribute, + std::vector &outBuffer) { size_t byteOffset = 0; - T values[4] = { 0, 0, 0, 0 }; - for (draco::PointIndex i(0); i < mesh->num_points(); ++i) - { + T values[4] = {0, 0, 0, 0}; + for (draco::PointIndex i(0); i < mesh->num_points(); ++i) { const draco::AttributeValueIndex val_index = pAttribute->mapped_index(i); - if (!pAttribute->ConvertValue(val_index, pAttribute->num_components(), values)) + if (!pAttribute->ConvertValue(val_index, pAttribute->num_components(), + values)) return false; - memcpy(outBuffer.data() + byteOffset, &values[0], sizeof(T) * pAttribute->num_components()); + memcpy(outBuffer.data() + byteOffset, &values[0], + sizeof(T) * pAttribute->num_components()); byteOffset += sizeof(T) * pAttribute->num_components(); } return true; } -static bool GetAttributeForAllPoints(uint32_t componentType, draco::Mesh* mesh, const draco::PointAttribute* pAttribute, std::vector& outBuffer) -{ +static bool GetAttributeForAllPoints(uint32_t componentType, draco::Mesh *mesh, + const draco::PointAttribute *pAttribute, + std::vector &outBuffer) { bool decodeResult = false; - switch (componentType) - { - case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE: - decodeResult = GetAttributeForAllPoints(mesh, pAttribute, outBuffer); - break; - case TINYGLTF_COMPONENT_TYPE_BYTE: - decodeResult = GetAttributeForAllPoints(mesh, pAttribute, outBuffer); - break; - case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT: - decodeResult = GetAttributeForAllPoints(mesh, pAttribute, outBuffer); - break; - case TINYGLTF_COMPONENT_TYPE_SHORT: - decodeResult = GetAttributeForAllPoints(mesh, pAttribute, outBuffer); - break; - case TINYGLTF_COMPONENT_TYPE_INT: - decodeResult = GetAttributeForAllPoints(mesh, pAttribute, outBuffer); - break; - case TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT: - decodeResult = GetAttributeForAllPoints(mesh, pAttribute, outBuffer); - break; - case TINYGLTF_COMPONENT_TYPE_FLOAT: - decodeResult = GetAttributeForAllPoints(mesh, pAttribute, outBuffer); - break; - case TINYGLTF_COMPONENT_TYPE_DOUBLE: - decodeResult = GetAttributeForAllPoints(mesh, pAttribute, outBuffer); - break; - default: - return false; + switch (componentType) { + case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE: + decodeResult = + GetAttributeForAllPoints(mesh, pAttribute, outBuffer); + break; + case TINYGLTF_COMPONENT_TYPE_BYTE: + decodeResult = + GetAttributeForAllPoints(mesh, pAttribute, outBuffer); + break; + case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT: + decodeResult = + GetAttributeForAllPoints(mesh, pAttribute, outBuffer); + break; + case TINYGLTF_COMPONENT_TYPE_SHORT: + decodeResult = + GetAttributeForAllPoints(mesh, pAttribute, outBuffer); + break; + case TINYGLTF_COMPONENT_TYPE_INT: + decodeResult = + GetAttributeForAllPoints(mesh, pAttribute, outBuffer); + break; + case TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT: + decodeResult = + GetAttributeForAllPoints(mesh, pAttribute, outBuffer); + break; + case TINYGLTF_COMPONENT_TYPE_FLOAT: + decodeResult = + GetAttributeForAllPoints(mesh, pAttribute, outBuffer); + break; + case TINYGLTF_COMPONENT_TYPE_DOUBLE: + decodeResult = + GetAttributeForAllPoints(mesh, pAttribute, outBuffer); + break; + default: + return false; } return decodeResult; } -static bool ParseDracoExtension(Primitive *primitive, Model *model, std::string *err, const Value &dracoExtensionValue) -{ +static bool ParseDracoExtension(Primitive *primitive, Model *model, + std::string *err, + const Value &dracoExtensionValue) { auto bufferViewValue = dracoExtensionValue.Get("bufferView"); - if (!bufferViewValue.IsInt()) - return false; + if (!bufferViewValue.IsInt()) return false; auto attributesValue = dracoExtensionValue.Get("attributes"); - if (!attributesValue.IsObject()) - return false; + if (!attributesValue.IsObject()) return false; auto attributesObject = attributesValue.Get(); int bufferView = bufferViewValue.Get(); - BufferView& view = model->bufferViews[bufferView]; - Buffer& buffer = model->buffers[view.buffer]; + BufferView &view = model->bufferViews[bufferView]; + Buffer &buffer = model->buffers[view.buffer]; // BufferView has already been decoded - if (view.dracoDecoded) - return true; + if (view.dracoDecoded) return true; view.dracoDecoded = true; - const char* bufferViewData = reinterpret_cast(buffer.data.data() + view.byteOffset); + const char *bufferViewData = + reinterpret_cast(buffer.data.data() + view.byteOffset); size_t bufferViewSize = view.byteLength; // decode draco @@ -3070,12 +3095,12 @@ static bool ParseDracoExtension(Primitive *primitive, Model *model, std::string if (!decodeResult.ok()) { return false; } - const std::unique_ptr& mesh = decodeResult.value(); + const std::unique_ptr &mesh = decodeResult.value(); // create new bufferView for indices - if (primitive->indices >= 0) - { - int32_t componentSize = GetComponentSizeInBytes(model->accessors[primitive->indices].componentType); + if (primitive->indices >= 0) { + int32_t componentSize = GetComponentSizeInBytes( + model->accessors[primitive->indices].componentType); Buffer decodedIndexBuffer; decodedIndexBuffer.data.resize(mesh->num_faces() * 3 * componentSize); @@ -3085,35 +3110,37 @@ static bool ParseDracoExtension(Primitive *primitive, Model *model, std::string BufferView decodedIndexBufferView; decodedIndexBufferView.buffer = int(model->buffers.size() - 1); - decodedIndexBufferView.byteLength = int(mesh->num_faces() * 3 * componentSize); + 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].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; + 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; + if (primitiveAttribute == primitive->attributes.end()) return false; int dracoAttributeIndex = attribute.second.Get(); const auto pAttribute = mesh->GetAttributeByUniqueId(dracoAttributeIndex); const auto pBuffer = pAttribute->buffer(); - const auto componentType = model->accessors[primitiveAttribute->second].componentType; + 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); + size_t bufferSize = mesh->num_points() * pAttribute->num_components() * + GetComponentSizeInBytes(componentType); decodedBuffer.data.resize(bufferSize); - if (!GetAttributeForAllPoints(componentType, mesh.get(), pAttribute, decodedBuffer.data)) + if (!GetAttributeForAllPoints(componentType, mesh.get(), pAttribute, + decodedBuffer.data)) return false; model->buffers.emplace_back(std::move(decodedBuffer)); @@ -3123,11 +3150,15 @@ static bool ParseDracoExtension(Primitive *primitive, Model *model, std::string 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; + 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()); + model->accessors[primitiveAttribute->second].bufferView = + int(model->bufferViews.size() - 1); + model->accessors[primitiveAttribute->second].count = + int(mesh->num_points()); } return true; @@ -3177,17 +3208,18 @@ static bool ParsePrimitive(Primitive *primitive, Model *model, std::string *err, ParseExtensionsProperty(&primitive->extensions, err, o); #ifdef TINYGLTF_ENABLE_DRACO - auto dracoExtension = primitive->extensions.find("KHR_draco_mesh_compression"); - if (dracoExtension != primitive->extensions.end()) - { - ParseDracoExtension(primitive, model, err, dracoExtension->second); + auto dracoExtension = + primitive->extensions.find("KHR_draco_mesh_compression"); + if (dracoExtension != primitive->extensions.end()) { + ParseDracoExtension(primitive, model, err, dracoExtension->second); } #endif return true; } -static bool ParseMesh(Mesh *mesh, Model *model, std::string *err, const json &o) { +static bool ParseMesh(Mesh *mesh, Model *model, std::string *err, + const json &o) { ParseStringProperty(&mesh->name, err, o, "name", false); mesh->primitives.clear(); @@ -3862,22 +3894,22 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, // Assign missing bufferView target types // - Look for missing Mesh indices // - Look for missing bufferView targets - for (auto &mesh : model->meshes) - { - for (auto &primitive : mesh.primitives) - { - if (primitive.indices > -1) // has indices from parsing step, must be Element Array Buffer + for (auto &mesh : model->meshes) { + for (auto &primitive : mesh.primitives) { + if (primitive.indices > + -1) // has indices from parsing step, must be Element Array Buffer { model->bufferViews[model->accessors[primitive.indices].bufferView] .target = TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER; - // we could optionally check if acessors' bufferView type is Scalar, as it should be + // we could optionally check if acessors' bufferView type is Scalar, as + // it should be } } } - // find any missing targets, must be an array buffer type if not fulfilled from previous check - for (auto &bufferView : model->bufferViews) - { - if (bufferView.target == 0) // missing target type + // find any missing targets, must be an array buffer type if not fulfilled + // from previous check + for (auto &bufferView : model->bufferViews) { + if (bufferView.target == 0) // missing target type { bufferView.target = TINYGLTF_TARGET_ARRAY_BUFFER; } @@ -3996,7 +4028,8 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, for (; it != itEnd; it++, idx++) { if (!it.value().is_object()) { if (err) { - (*err) += "image[" + std::to_string(idx) + "] is not a JSON object."; + (*err) += + "image[" + std::to_string(idx) + "] is not a JSON object."; } return false; } @@ -4028,10 +4061,10 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, } return false; } - bool ret = LoadImageData(&image, idx, err, warn, image.width, image.height, - &buffer.data[bufferView.byteOffset], - static_cast(bufferView.byteLength), - load_image_user_data_); + bool ret = LoadImageData( + &image, idx, err, warn, image.width, image.height, + &buffer.data[bufferView.byteOffset], + static_cast(bufferView.byteLength), load_image_user_data_); if (!ret) { return false; } @@ -4485,7 +4518,7 @@ static void SerializeGltfBufferData(const std::vector &data, static bool SerializeGltfBufferData(const std::vector &data, const std::string &binFilename) { std::ofstream output(binFilename.c_str(), std::ofstream::binary); - if(!output.is_open()) return false; + if (!output.is_open()) return false; output.write(reinterpret_cast(&data[0]), std::streamsize(data.size())); output.close(); @@ -4534,9 +4567,10 @@ static void SerializeExtensionMap(ExtensionMap &extensions, json &o) { if (ValueToJson(extIt->second, &ret)) { extMap[extIt->first] = ret; } - if(ret.is_null()) { - if (!(extIt->first.empty())) { // name should not be empty, but for sure - // create empty object so that an extension name is still included in json. + if (ret.is_null()) { + if (!(extIt->first.empty())) { // name should not be empty, but for sure + // create empty object so that an extension name is still included in + // json. extMap[extIt->first] = json({}); } } @@ -4667,7 +4701,7 @@ static void SerializeGltfBuffer(Buffer &buffer, json &o) { static bool SerializeGltfBuffer(Buffer &buffer, json &o, const std::string &binFilename, const std::string &binBaseFilename) { - if(!SerializeGltfBufferData(buffer.data, binFilename)) return false; + if (!SerializeGltfBufferData(buffer.data, binFilename)) return false; SerializeNumberProperty("byteLength", buffer.data.size(), o); SerializeStringProperty("uri", binBaseFilename, o); @@ -4955,9 +4989,10 @@ static void WriteBinaryGltfFile(const std::string &output, const int version = 2; const int padding_size = content.size() % 4; - // 12 bytes for header, JSON content length, 8 bytes for JSON chunk info, padding + // 12 bytes for header, JSON content length, 8 bytes for JSON chunk info, + // padding const int length = 12 + 8 + int(content.size()) + padding_size; - + gltfFile.write(header.c_str(), header.size()); gltfFile.write(reinterpret_cast(&version), sizeof(version)); gltfFile.write(reinterpret_cast(&length), sizeof(length)); @@ -4965,8 +5000,10 @@ static void WriteBinaryGltfFile(const std::string &output, // JSON chunk info, then JSON data const int model_length = int(content.size()) + padding_size; const int model_format = 0x4E4F534A; - gltfFile.write(reinterpret_cast(&model_length), sizeof(model_length)); - gltfFile.write(reinterpret_cast(&model_format), sizeof(model_format)); + gltfFile.write(reinterpret_cast(&model_length), + sizeof(model_length)); + gltfFile.write(reinterpret_cast(&model_format), + sizeof(model_format)); gltfFile.write(content.c_str(), content.size()); // Chunk must be multiplies of 4, so pad with spaces @@ -5012,7 +5049,8 @@ bool TinyGLTF::WriteGltfSceneToFile(Model *model, const std::string &filename, std::string defaultBinFilename = GetBaseFilename(filename); std::string defaultBinFileExt = ".bin"; - std::string::size_type pos = defaultBinFilename.rfind('.', defaultBinFilename.length()); + std::string::size_type pos = + defaultBinFilename.rfind('.', defaultBinFilename.length()); if (pos != std::string::npos) { defaultBinFilename = defaultBinFilename.substr(0, pos); @@ -5032,28 +5070,27 @@ bool TinyGLTF::WriteGltfSceneToFile(Model *model, const std::string &filename, } else { std::string binSavePath; std::string binUri; - if (!model->buffers[i].uri.empty() - && !IsDataURI(model->buffers[i].uri)) { + if (!model->buffers[i].uri.empty() && !IsDataURI(model->buffers[i].uri)) { binUri = model->buffers[i].uri; - } - else { + } else { binUri = defaultBinFilename + defaultBinFileExt; bool inUse = true; int numUsed = 0; - while(inUse) { + while (inUse) { inUse = false; - for (const std::string& usedName : usedUris) { + for (const std::string &usedName : usedUris) { if (binUri.compare(usedName) != 0) continue; inUse = true; - binUri = defaultBinFilename + std::to_string(numUsed++) + defaultBinFileExt; + binUri = defaultBinFilename + std::to_string(numUsed++) + + defaultBinFileExt; break; } } } usedUris.push_back(binUri); - binSavePath = JoinPath(baseDir, binUri); - if(!SerializeGltfBuffer(model->buffers[i], buffer, binSavePath, - binUri)) { + binSavePath = JoinPath(baseDir, binUri); + if (!SerializeGltfBuffer(model->buffers[i], buffer, binSavePath, + binUri)) { return false; } } From 14d259f361b4a4dac50cfa2d552d2ee6423a66d0 Mon Sep 17 00:00:00 2001 From: "Arthur Brainville (Ybalrid)" Date: Wed, 6 Mar 2019 14:48:44 +0000 Subject: [PATCH 6/6] glview can now load static geometry modified by sparse accessor --- examples/glview/glview.cc | 558 +++++++++++++++++++++++--------------- 1 file changed, 342 insertions(+), 216 deletions(-) diff --git a/examples/glview/glview.cc b/examples/glview/glview.cc index b2a3d70..375b556 100644 --- a/examples/glview/glview.cc +++ b/examples/glview/glview.cc @@ -28,7 +28,6 @@ #include "tiny_gltf.h" #endif - #define BUFFER_OFFSET(i) ((char *)NULL + (i)) #define CheckGLErrors(desc) \ @@ -55,7 +54,9 @@ float eye[3], lookat[3], up[3]; GLFWwindow *window; -typedef struct { GLuint vb; } GLBufferState; +typedef struct { + GLuint vb; +} GLBufferState; typedef struct { std::vector diffuseTex; // for each primitive in mesh @@ -254,6 +255,26 @@ void motionFunc(GLFWwindow *window, double mouse_x, double mouse_y) { prevMouseY = mouse_y; } +static size_t ComponentTypeByteSize(int type) { + switch (type) { + case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE: + case TINYGLTF_COMPONENT_TYPE_BYTE: + return sizeof(char); + case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT: + case TINYGLTF_COMPONENT_TYPE_SHORT: + return sizeof(short); + case TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT: + case TINYGLTF_COMPONENT_TYPE_INT: + return sizeof(int); + case TINYGLTF_COMPONENT_TYPE_FLOAT: + return sizeof(float); + case TINYGLTF_COMPONENT_TYPE_DOUBLE: + return sizeof(double); + default: + return 0; + } +} + static void SetupMeshState(tinygltf::Model &model, GLuint progId) { // Buffer { @@ -264,14 +285,117 @@ static void SetupMeshState(tinygltf::Model &model, GLuint progId) { continue; // Unsupported bufferView. } + int sparse_accessor = -1; + for (size_t a_i = 0; a_i < model.accessors.size(); ++a_i) { + const auto &accessor = model.accessors[a_i]; + if (accessor.bufferView == i) { + std::cout << i << " is used by accessor " << a_i << std::endl; + if (accessor.sparse.isSparse) { + std::cout + << "WARN: this bufferView has at least one sparse accessor to " + "it. We are going to load the data as patched by this " + "sparse accessor, not the original data" + << std::endl; + sparse_accessor = a_i; + break; + } + } + } + const tinygltf::Buffer &buffer = model.buffers[bufferView.buffer]; GLBufferState state; glGenBuffers(1, &state.vb); glBindBuffer(bufferView.target, state.vb); std::cout << "buffer.size= " << buffer.data.size() << ", byteOffset = " << bufferView.byteOffset << std::endl; - glBufferData(bufferView.target, bufferView.byteLength, - &buffer.data.at(0) + bufferView.byteOffset, GL_STATIC_DRAW); + + if (sparse_accessor < 0) + glBufferData(bufferView.target, bufferView.byteLength, + &buffer.data.at(0) + bufferView.byteOffset, + GL_STATIC_DRAW); + else { + const auto accessor = model.accessors[sparse_accessor]; + // copy the buffer to a temporary one for sparse patching + unsigned char *tmp_buffer = new unsigned char[bufferView.byteLength]; + memcpy(tmp_buffer, buffer.data.data() + bufferView.byteOffset, + bufferView.byteLength); + + const size_t size_of_object_in_buffer = + ComponentTypeByteSize(accessor.componentType); + const size_t size_of_sparse_indices = + ComponentTypeByteSize(accessor.sparse.indices.componentType); + + const auto &indices_buffer_view = + model.bufferViews[accessor.sparse.indices.bufferView]; + const auto &indices_buffer = model.buffers[indices_buffer_view.buffer]; + + const auto &values_buffer_view = + model.bufferViews[accessor.sparse.values.bufferView]; + const auto &values_buffer = model.buffers[values_buffer_view.buffer]; + + for (size_t sparse_index = 0; sparse_index < accessor.sparse.count; + ++sparse_index) { + int index = 0; + // std::cout << "accessor.sparse.indices.componentType = " << + // accessor.sparse.indices.componentType << std::endl; + switch (accessor.sparse.indices.componentType) { + case TINYGLTF_COMPONENT_TYPE_BYTE: + case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE: + index = (int)*( + unsigned char *)(indices_buffer.data.data() + + indices_buffer_view.byteOffset + + accessor.sparse.indices.byteOffset + + (sparse_index * size_of_sparse_indices)); + break; + case TINYGLTF_COMPONENT_TYPE_SHORT: + case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT: + index = (int)*( + unsigned short *)(indices_buffer.data.data() + + indices_buffer_view.byteOffset + + accessor.sparse.indices.byteOffset + + (sparse_index * size_of_sparse_indices)); + break; + case TINYGLTF_COMPONENT_TYPE_INT: + case TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT: + index = (int)*( + unsigned int *)(indices_buffer.data.data() + + indices_buffer_view.byteOffset + + accessor.sparse.indices.byteOffset + + (sparse_index * size_of_sparse_indices)); + break; + } + std::cout << "updating sparse data at index : " << index + << std::endl; + // index is now the target of the sparse index to patch in + const unsigned char *read_from = + values_buffer.data.data() + + (values_buffer_view.byteOffset + + accessor.sparse.values.byteOffset) + + (sparse_index * (size_of_object_in_buffer * accessor.type)); + + /* + std::cout << ((float*)read_from)[0] << "\n"; + std::cout << ((float*)read_from)[1] << "\n"; + std::cout << ((float*)read_from)[2] << "\n"; + */ + + unsigned char *write_to = + tmp_buffer + index * (size_of_object_in_buffer * accessor.type); + + memcpy(write_to, read_from, size_of_object_in_buffer * accessor.type); + } + + // debug: + /*for(size_t p = 0; p < bufferView.byteLength/sizeof(float); p++) + { + float* b = (float*)tmp_buffer; + std::cout << "modified_buffer [" << p << "] = " << b[p] << '\n'; + }*/ + + glBufferData(bufferView.target, bufferView.byteLength, tmp_buffer, + GL_STATIC_DRAW); + delete[] tmp_buffer; + } glBindBuffer(bufferView.target, 0); gBufferState[i] = state; @@ -279,55 +403,55 @@ static void SetupMeshState(tinygltf::Model &model, GLuint progId) { } #if 0 // TODO(syoyo): Implement - // Texture - { - for (size_t i = 0; i < model.meshes.size(); i++) { - const tinygltf::Mesh &mesh = model.meshes[i]; + // Texture + { + for (size_t i = 0; i < model.meshes.size(); i++) { + const tinygltf::Mesh &mesh = model.meshes[i]; - gMeshState[mesh.name].diffuseTex.resize(mesh.primitives.size()); - for (size_t primId = 0; primId < mesh.primitives.size(); primId++) { - const tinygltf::Primitive &primitive = mesh.primitives[primId]; + gMeshState[mesh.name].diffuseTex.resize(mesh.primitives.size()); + for (size_t primId = 0; primId < mesh.primitives.size(); primId++) { + const tinygltf::Primitive &primitive = mesh.primitives[primId]; - gMeshState[mesh.name].diffuseTex[primId] = 0; + gMeshState[mesh.name].diffuseTex[primId] = 0; - if (primitive.material < 0) { - continue; - } - tinygltf::Material &mat = model.materials[primitive.material]; - // printf("material.name = %s\n", mat.name.c_str()); - if (mat.values.find("diffuse") != mat.values.end()) { - std::string diffuseTexName = mat.values["diffuse"].string_value; - if (model.textures.find(diffuseTexName) != model.textures.end()) { - tinygltf::Texture &tex = model.textures[diffuseTexName]; - if (scene.images.find(tex.source) != model.images.end()) { - tinygltf::Image &image = model.images[tex.source]; - GLuint texId; - glGenTextures(1, &texId); - glBindTexture(tex.target, texId); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glTexParameterf(tex.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(tex.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + if (primitive.material < 0) { + continue; + } + tinygltf::Material &mat = model.materials[primitive.material]; + // printf("material.name = %s\n", mat.name.c_str()); + if (mat.values.find("diffuse") != mat.values.end()) { + std::string diffuseTexName = mat.values["diffuse"].string_value; + if (model.textures.find(diffuseTexName) != model.textures.end()) { + tinygltf::Texture &tex = model.textures[diffuseTexName]; + if (scene.images.find(tex.source) != model.images.end()) { + tinygltf::Image &image = model.images[tex.source]; + GLuint texId; + glGenTextures(1, &texId); + glBindTexture(tex.target, texId); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glTexParameterf(tex.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(tex.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - // Ignore Texture.fomat. - GLenum format = GL_RGBA; - if (image.component == 3) { - format = GL_RGB; - } - glTexImage2D(tex.target, 0, tex.internalFormat, image.width, - image.height, 0, format, tex.type, - &image.image.at(0)); + // Ignore Texture.fomat. + GLenum format = GL_RGBA; + if (image.component == 3) { + format = GL_RGB; + } + glTexImage2D(tex.target, 0, tex.internalFormat, image.width, + image.height, 0, format, tex.type, + &image.image.at(0)); - CheckErrors("texImage2D"); - glBindTexture(tex.target, 0); + CheckErrors("texImage2D"); + glBindTexture(tex.target, 0); - printf("TexId = %d\n", texId); - gMeshState[mesh.name].diffuseTex[primId] = texId; - } - } - } - } - } - } + printf("TexId = %d\n", texId); + gMeshState[mesh.name].diffuseTex[primId] = texId; + } + } + } + } + } + } #endif glUseProgram(progId); @@ -348,164 +472,164 @@ static void SetupMeshState(tinygltf::Model &model, GLuint progId) { #if 0 // TODO(syoyo): Implement // Setup curves geometry extension static void SetupCurvesState(tinygltf::Scene &scene, GLuint progId) { - // Find curves primitive. - { - std::map::const_iterator it( - scene.meshes.begin()); - std::map::const_iterator itEnd( - scene.meshes.end()); + // Find curves primitive. + { + std::map::const_iterator it( + scene.meshes.begin()); + std::map::const_iterator itEnd( + scene.meshes.end()); - for (; it != itEnd; it++) { - const tinygltf::Mesh &mesh = it->second; + for (; it != itEnd; it++) { + const tinygltf::Mesh &mesh = it->second; - // Currently we only support one primitive per mesh. - if (mesh.primitives.size() > 1) { - continue; - } + // Currently we only support one primitive per mesh. + if (mesh.primitives.size() > 1) { + continue; + } - for (size_t primId = 0; primId < mesh.primitives.size(); primId++) { - const tinygltf::Primitive &primitive = mesh.primitives[primId]; + for (size_t primId = 0; primId < mesh.primitives.size(); primId++) { + const tinygltf::Primitive &primitive = mesh.primitives[primId]; - gMeshState[mesh.name].diffuseTex[primId] = 0; + gMeshState[mesh.name].diffuseTex[primId] = 0; - if (primitive.material.empty()) { - continue; - } + if (primitive.material.empty()) { + continue; + } - bool has_curves = false; - if (primitive.extras.IsObject()) { - if (primitive.extras.Has("ext_mode")) { - const tinygltf::Value::Object &o = - primitive.extras.Get(); - const tinygltf::Value &ext_mode = o.find("ext_mode")->second; + bool has_curves = false; + if (primitive.extras.IsObject()) { + if (primitive.extras.Has("ext_mode")) { + const tinygltf::Value::Object &o = + primitive.extras.Get(); + const tinygltf::Value &ext_mode = o.find("ext_mode")->second; - if (ext_mode.IsString()) { - const std::string &str = ext_mode.Get(); - if (str.compare("curves") == 0) { - has_curves = true; - } - } - } - } + if (ext_mode.IsString()) { + const std::string &str = ext_mode.Get(); + if (str.compare("curves") == 0) { + has_curves = true; + } + } + } + } - if (!has_curves) { - continue; - } + if (!has_curves) { + continue; + } - // Construct curves buffer - const tinygltf::Accessor &vtx_accessor = - scene.accessors[primitive.attributes.find("POSITION")->second]; - const tinygltf::Accessor &nverts_accessor = - scene.accessors[primitive.attributes.find("NVERTS")->second]; - const tinygltf::BufferView &vtx_bufferView = - scene.bufferViews[vtx_accessor.bufferView]; - const tinygltf::BufferView &nverts_bufferView = - scene.bufferViews[nverts_accessor.bufferView]; - const tinygltf::Buffer &vtx_buffer = - scene.buffers[vtx_bufferView.buffer]; - const tinygltf::Buffer &nverts_buffer = - scene.buffers[nverts_bufferView.buffer]; + // Construct curves buffer + const tinygltf::Accessor &vtx_accessor = + scene.accessors[primitive.attributes.find("POSITION")->second]; + const tinygltf::Accessor &nverts_accessor = + scene.accessors[primitive.attributes.find("NVERTS")->second]; + const tinygltf::BufferView &vtx_bufferView = + scene.bufferViews[vtx_accessor.bufferView]; + const tinygltf::BufferView &nverts_bufferView = + scene.bufferViews[nverts_accessor.bufferView]; + const tinygltf::Buffer &vtx_buffer = + scene.buffers[vtx_bufferView.buffer]; + const tinygltf::Buffer &nverts_buffer = + scene.buffers[nverts_bufferView.buffer]; - // std::cout << "vtx_bufferView = " << vtx_accessor.bufferView << - // std::endl; - // std::cout << "nverts_bufferView = " << nverts_accessor.bufferView << - // std::endl; - // std::cout << "vtx_buffer.size = " << vtx_buffer.data.size() << - // std::endl; - // std::cout << "nverts_buffer.size = " << nverts_buffer.data.size() << - // std::endl; + // std::cout << "vtx_bufferView = " << vtx_accessor.bufferView << + // std::endl; + // std::cout << "nverts_bufferView = " << nverts_accessor.bufferView << + // std::endl; + // std::cout << "vtx_buffer.size = " << vtx_buffer.data.size() << + // std::endl; + // std::cout << "nverts_buffer.size = " << nverts_buffer.data.size() << + // std::endl; - const int *nverts = - reinterpret_cast(nverts_buffer.data.data()); - const float *vtx = - reinterpret_cast(vtx_buffer.data.data()); + const int *nverts = + reinterpret_cast(nverts_buffer.data.data()); + const float *vtx = + reinterpret_cast(vtx_buffer.data.data()); - // Convert to GL_LINES data. - std::vector line_pts; - size_t vtx_offset = 0; - for (int k = 0; k < static_cast(nverts_accessor.count); k++) { - for (int n = 0; n < nverts[k] - 1; n++) { + // Convert to GL_LINES data. + std::vector line_pts; + size_t vtx_offset = 0; + for (int k = 0; k < static_cast(nverts_accessor.count); k++) { + for (int n = 0; n < nverts[k] - 1; n++) { - line_pts.push_back(vtx[3 * (vtx_offset + n) + 0]); - line_pts.push_back(vtx[3 * (vtx_offset + n) + 1]); - line_pts.push_back(vtx[3 * (vtx_offset + n) + 2]); + line_pts.push_back(vtx[3 * (vtx_offset + n) + 0]); + line_pts.push_back(vtx[3 * (vtx_offset + n) + 1]); + line_pts.push_back(vtx[3 * (vtx_offset + n) + 2]); - line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 0]); - line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 1]); - line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 2]); + line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 0]); + line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 1]); + line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 2]); - // std::cout << "p0 " << vtx[3 * (vtx_offset + n) + 0] << ", " - // << vtx[3 * (vtx_offset + n) + 1] << ", " - // << vtx[3 * (vtx_offset + n) + 2] << std::endl; + // std::cout << "p0 " << vtx[3 * (vtx_offset + n) + 0] << ", " + // << vtx[3 * (vtx_offset + n) + 1] << ", " + // << vtx[3 * (vtx_offset + n) + 2] << std::endl; - // std::cout << "p1 " << vtx[3 * (vtx_offset + n+1) + 0] << ", " - // << vtx[3 * (vtx_offset + n+1) + 1] << ", " - // << vtx[3 * (vtx_offset + n+1) + 2] << std::endl; - } + // std::cout << "p1 " << vtx[3 * (vtx_offset + n+1) + 0] << ", " + // << vtx[3 * (vtx_offset + n+1) + 1] << ", " + // << vtx[3 * (vtx_offset + n+1) + 2] << std::endl; + } - vtx_offset += nverts[k]; - } + vtx_offset += nverts[k]; + } - GLCurvesState state; - glGenBuffers(1, &state.vb); - glBindBuffer(GL_ARRAY_BUFFER, state.vb); - glBufferData(GL_ARRAY_BUFFER, line_pts.size() * sizeof(float), - line_pts.data(), GL_STATIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); + GLCurvesState state; + glGenBuffers(1, &state.vb); + glBindBuffer(GL_ARRAY_BUFFER, state.vb); + glBufferData(GL_ARRAY_BUFFER, line_pts.size() * sizeof(float), + line_pts.data(), GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); - state.count = line_pts.size() / 3; - gCurvesMesh[mesh.name] = state; + state.count = line_pts.size() / 3; + gCurvesMesh[mesh.name] = state; - // Material - tinygltf::Material &mat = scene.materials[primitive.material]; - // printf("material.name = %s\n", mat.name.c_str()); - if (mat.values.find("diffuse") != mat.values.end()) { - std::string diffuseTexName = mat.values["diffuse"].string_value; - if (scene.textures.find(diffuseTexName) != scene.textures.end()) { - tinygltf::Texture &tex = scene.textures[diffuseTexName]; - if (scene.images.find(tex.source) != scene.images.end()) { - tinygltf::Image &image = scene.images[tex.source]; - GLuint texId; - glGenTextures(1, &texId); - glBindTexture(tex.target, texId); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glTexParameterf(tex.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(tex.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + // Material + tinygltf::Material &mat = scene.materials[primitive.material]; + // printf("material.name = %s\n", mat.name.c_str()); + if (mat.values.find("diffuse") != mat.values.end()) { + std::string diffuseTexName = mat.values["diffuse"].string_value; + if (scene.textures.find(diffuseTexName) != scene.textures.end()) { + tinygltf::Texture &tex = scene.textures[diffuseTexName]; + if (scene.images.find(tex.source) != scene.images.end()) { + tinygltf::Image &image = scene.images[tex.source]; + GLuint texId; + glGenTextures(1, &texId); + glBindTexture(tex.target, texId); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glTexParameterf(tex.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(tex.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - // Ignore Texture.fomat. - GLenum format = GL_RGBA; - if (image.component == 3) { - format = GL_RGB; - } - glTexImage2D(tex.target, 0, tex.internalFormat, image.width, - image.height, 0, format, tex.type, - &image.image.at(0)); + // Ignore Texture.fomat. + GLenum format = GL_RGBA; + if (image.component == 3) { + format = GL_RGB; + } + glTexImage2D(tex.target, 0, tex.internalFormat, image.width, + image.height, 0, format, tex.type, + &image.image.at(0)); - CheckErrors("texImage2D"); - glBindTexture(tex.target, 0); + CheckErrors("texImage2D"); + glBindTexture(tex.target, 0); - printf("TexId = %d\n", texId); - gMeshState[mesh.name].diffuseTex[primId] = texId; - } - } - } - } - } - } + printf("TexId = %d\n", texId); + gMeshState[mesh.name].diffuseTex[primId] = texId; + } + } + } + } + } + } - glUseProgram(progId); - GLint vtloc = glGetAttribLocation(progId, "in_vertex"); - GLint nrmloc = glGetAttribLocation(progId, "in_normal"); - GLint uvloc = glGetAttribLocation(progId, "in_texcoord"); + glUseProgram(progId); + GLint vtloc = glGetAttribLocation(progId, "in_vertex"); + GLint nrmloc = glGetAttribLocation(progId, "in_normal"); + GLint uvloc = glGetAttribLocation(progId, "in_texcoord"); - GLint diffuseTexLoc = glGetUniformLocation(progId, "diffuseTex"); - GLint isCurvesLoc = glGetUniformLocation(progId, "uIsCurves"); + GLint diffuseTexLoc = glGetUniformLocation(progId, "diffuseTex"); + GLint isCurvesLoc = glGetUniformLocation(progId, "uIsCurves"); - gGLProgramState.attribs["POSITION"] = vtloc; - gGLProgramState.attribs["NORMAL"] = nrmloc; - gGLProgramState.attribs["TEXCOORD_0"] = uvloc; - gGLProgramState.uniforms["diffuseTex"] = diffuseTexLoc; - gGLProgramState.uniforms["uIsCurves"] = isCurvesLoc; + gGLProgramState.attribs["POSITION"] = vtloc; + gGLProgramState.attribs["NORMAL"] = nrmloc; + gGLProgramState.attribs["TEXCOORD_0"] = uvloc; + gGLProgramState.uniforms["diffuseTex"] = diffuseTexLoc; + gGLProgramState.uniforms["uIsCurves"] = isCurvesLoc; }; #endif @@ -558,12 +682,13 @@ static void DrawMesh(tinygltf::Model &model, const tinygltf::Mesh &mesh) { (it->first.compare("TEXCOORD_0") == 0)) { if (gGLProgramState.attribs[it->first] >= 0) { // Compute byteStride from Accessor + BufferView combination. - int byteStride = accessor.ByteStride(model.bufferViews[accessor.bufferView]); + int byteStride = + accessor.ByteStride(model.bufferViews[accessor.bufferView]); assert(byteStride != -1); glVertexAttribPointer(gGLProgramState.attribs[it->first], size, - accessor.componentType, accessor.normalized ? GL_TRUE : GL_FALSE, - byteStride, - BUFFER_OFFSET(accessor.byteOffset)); + accessor.componentType, + accessor.normalized ? GL_TRUE : GL_FALSE, + byteStride, BUFFER_OFFSET(accessor.byteOffset)); CheckErrors("vertex attrib pointer"); glEnableVertexAttribArray(gGLProgramState.attribs[it->first]); CheckErrors("enable vertex attrib array"); @@ -617,32 +742,32 @@ static void DrawMesh(tinygltf::Model &model, const tinygltf::Mesh &mesh) { #if 0 // TODO(syoyo): Implement static void DrawCurves(tinygltf::Scene &scene, const tinygltf::Mesh &mesh) { - (void)scene; + (void)scene; - if (gCurvesMesh.find(mesh.name) == gCurvesMesh.end()) { - return; - } + if (gCurvesMesh.find(mesh.name) == gCurvesMesh.end()) { + return; + } - if (gGLProgramState.uniforms["isCurvesLoc"] >= 0) { - glUniform1i(gGLProgramState.uniforms["isCurvesLoc"], 1); - } + if (gGLProgramState.uniforms["isCurvesLoc"] >= 0) { + glUniform1i(gGLProgramState.uniforms["isCurvesLoc"], 1); + } - GLCurvesState &state = gCurvesMesh[mesh.name]; + GLCurvesState &state = gCurvesMesh[mesh.name]; - if (gGLProgramState.attribs["POSITION"] >= 0) { - glBindBuffer(GL_ARRAY_BUFFER, state.vb); - glVertexAttribPointer(gGLProgramState.attribs["POSITION"], 3, GL_FLOAT, - GL_FALSE, /* stride */ 0, BUFFER_OFFSET(0)); - CheckErrors("curve: vertex attrib pointer"); - glEnableVertexAttribArray(gGLProgramState.attribs["POSITION"]); - CheckErrors("curve: enable vertex attrib array"); - } + if (gGLProgramState.attribs["POSITION"] >= 0) { + glBindBuffer(GL_ARRAY_BUFFER, state.vb); + glVertexAttribPointer(gGLProgramState.attribs["POSITION"], 3, GL_FLOAT, + GL_FALSE, /* stride */ 0, BUFFER_OFFSET(0)); + CheckErrors("curve: vertex attrib pointer"); + glEnableVertexAttribArray(gGLProgramState.attribs["POSITION"]); + CheckErrors("curve: enable vertex attrib array"); + } - glDrawArrays(GL_LINES, 0, state.count); + glDrawArrays(GL_LINES, 0, state.count); - if (gGLProgramState.attribs["POSITION"] >= 0) { - glDisableVertexAttribArray(gGLProgramState.attribs["POSITION"]); - } + if (gGLProgramState.attribs["POSITION"] >= 0) { + glDisableVertexAttribArray(gGLProgramState.attribs["POSITION"]); + } } #endif @@ -693,16 +818,16 @@ static void DrawNode(tinygltf::Model &model, const tinygltf::Node &node) { static void DrawModel(tinygltf::Model &model) { #if 0 - std::map::const_iterator it(scene.meshes.begin()); - std::map::const_iterator itEnd(scene.meshes.end()); + std::map::const_iterator it(scene.meshes.begin()); + std::map::const_iterator itEnd(scene.meshes.end()); - for (; it != itEnd; it++) { - DrawMesh(scene, it->second); - DrawCurves(scene, it->second); - } + for (; it != itEnd; it++) { + DrawMesh(scene, it->second); + DrawCurves(scene, it->second); + } #else - //If the glTF asset has at least one scene, and doesn't define a default one - //just show the first one we can find + // If the glTF asset has at least one scene, and doesn't define a default one + // just show the first one we can find assert(model.scenes.size() > 0); int scene_to_display = model.defaultScene > -1 ? model.defaultScene : 0; const tinygltf::Scene &scene = model.scenes[scene_to_display]; @@ -752,7 +877,8 @@ int main(int argc, char **argv) { #ifdef _WIN32 #ifdef _DEBUG - std::string input_filename(argv[1] ? argv[1] : "../../../models/Cube/Cube.gltf"); + std::string input_filename(argv[1] ? argv[1] + : "../../../models/Cube/Cube.gltf"); #endif #else std::string input_filename(argv[1] ? argv[1] : "../../models/Cube/Cube.gltf"); @@ -763,7 +889,8 @@ int main(int argc, char **argv) { bool ret = false; if (ext.compare("glb") == 0) { // assume binary glTF. - ret = loader.LoadBinaryFromFile(&model, &err, &warn, input_filename.c_str()); + ret = + loader.LoadBinaryFromFile(&model, &err, &warn, input_filename.c_str()); } else { // assume ascii glTF. ret = loader.LoadASCIIFromFile(&model, &err, &warn, input_filename.c_str()); @@ -825,15 +952,14 @@ int main(int argc, char **argv) { #ifdef _WIN32 #ifdef _DEBUG - const char *shader_frag_filename = "../shader.frag"; - const char *shader_vert_filename = "../shader.vert"; + const char *shader_frag_filename = "../shader.frag"; + const char *shader_vert_filename = "../shader.vert"; #endif #else const char *shader_frag_filename = "shader.frag"; const char *shader_vert_filename = "shader.vert"; #endif - if (false == LoadShader(GL_VERTEX_SHADER, vertId, shader_vert_filename)) { return -1; }