From f4f4ae4d89acd41eafb41f9622bff24baaa4fc65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Chatelain?= Date: Wed, 24 May 2017 12:54:17 +0000 Subject: [PATCH 01/10] Removes Technique/Shader/Program support (glTF 2.0) --- tiny_gltf_loader.h | 359 +-------------------------------------------- 1 file changed, 2 insertions(+), 357 deletions(-) diff --git a/tiny_gltf_loader.h b/tiny_gltf_loader.h index 430fbd9..4f36b77 100644 --- a/tiny_gltf_loader.h +++ b/tiny_gltf_loader.h @@ -428,44 +428,6 @@ typedef struct { Value extras; } Buffer; -typedef struct { - std::string name; - int type; - int pad0; - std::vector source; - - Value extras; -} Shader; - -typedef struct { - std::string name; - std::string vertexShader; - std::string fragmentShader; - std::vector attributes; - - Value extras; -} Program; - -typedef struct { - int count; - int pad0; - std::string node; - std::string semantic; - int type; - int pad1; - Parameter value; -} TechniqueParameter; - -typedef struct { - std::string name; - std::string program; - std::map parameters; - std::map attributes; - std::map uniforms; - - Value extras; -} Technique; - typedef struct { std::string generator; std::string version; @@ -490,9 +452,6 @@ class Scene { std::map nodes; std::map textures; std::map images; - std::map shaders; - std::map programs; - std::map techniques; std::map samplers; std::map > scenes; // list of nodes @@ -1178,93 +1137,6 @@ static bool ParseStringProperty( return true; } -static bool ParseStringArrayProperty(std::vector *ret, - std::string *err, - const picojson::object &o, - const std::string &property, - bool required) { - picojson::object::const_iterator it = o.find(property); - if (it == o.end()) { - if (required) { - if (err) { - (*err) += "'" + property + "' property is missing.\n"; - } - } - return false; - } - - if (!it->second.is()) { - if (required) { - if (err) { - (*err) += "'" + property + "' property is not an array.\n"; - } - } - return false; - } - - ret->clear(); - const picojson::array &arr = it->second.get(); - for (size_t i = 0; i < arr.size(); i++) { - if (!arr[i].is()) { - if (required) { - if (err) { - (*err) += "'" + property + "' property is not a string.\n"; - } - } - return false; - } - ret->push_back(arr[i].get()); - } - - return true; -} - -static bool ParseStringMapProperty(std::map *ret, - std::string *err, const picojson::object &o, - const std::string &property, bool required) { - picojson::object::const_iterator it = o.find(property); - if (it == o.end()) { - if (required) { - if (err) { - (*err) += "'" + property + "' property is missing.\n"; - } - } - return false; - } - - // Make sure we are dealing with an object / dictionary. - if (!it->second.is()) { - if (required) { - if (err) { - (*err) += "'" + property + "' property is not an object.\n"; - } - } - return false; - } - - ret->clear(); - const picojson::object &dict = it->second.get(); - - picojson::object::const_iterator dictIt(dict.begin()); - picojson::object::const_iterator dictItEnd(dict.end()); - - for (; dictIt != dictItEnd; ++dictIt) { - // Check that the value is a string. - if (!dictIt->second.is()) { - if (required) { - if (err) { - (*err) += "'" + property + "' value is not a string.\n"; - } - } - return false; - } - - // Insert into the list. - (*ret)[dictIt->first] = dictIt->second.get(); - } - return true; -} - static bool ParseKHRBinaryExtension(const picojson::object &o, std::string *err, std::string *buffer_view, std::string *mime_type, int *image_width, @@ -1829,183 +1701,6 @@ static bool ParseMaterial(Material *material, std::string *err, return true; } -static bool ParseShader(Shader *shader, std::string *err, - const picojson::object &o, const std::string &basedir, - bool is_binary = false, - const unsigned char *bin_data = NULL, - size_t bin_size = 0) { - std::string uri; - if (!ParseStringProperty(&uri, err, o, "uri", true)) { - return false; - } - - if (is_binary) { - // Still binary glTF accepts external dataURI. First try external resources. - bool loaded = false; - if (IsDataURI(uri)) { - loaded = DecodeDataURI(&shader->source, uri, 0, false); - } else { - // Assume external .bin file. - loaded = LoadExternalFile(&shader->source, err, uri, basedir, 0, false); - } - - if (!loaded) { - // load data from (embedded) binary data - - if ((bin_size == 0) || (bin_data == NULL)) { - if (err) { - (*err) += "Invalid binary data.\n"; - } - return false; - } - - // There should be "extensions" property. - // "extensions":{"KHR_binary_glTF":{"bufferView": "id", ... - - std::string buffer_view; - std::string mime_type; - int image_width; - int image_height; - bool ret = ParseKHRBinaryExtension(o, err, &buffer_view, &mime_type, - &image_width, &image_height); - if (!ret) { - return false; - } - - if (uri.compare("data:,") == 0) { - // ok - } else { - if (err) { - (*err) += "Invalid URI for binary data.\n"; - } - return false; - } - } - } else { - // Load shader source from data uri - // TODO(syoyo): Support ascii or utf-8 data uris. - if (IsDataURI(uri)) { - if (!DecodeDataURI(&shader->source, uri, 0, false)) { - if (err) { - (*err) += "Failed to decode 'uri' for shader parameter.\n"; - } - return false; - } - } else { - // Assume external file - if (!LoadExternalFile(&shader->source, err, uri, basedir, 0, false)) { - if (err) { - (*err) += "Failed to load external 'uri' for shader parameter.\n"; - } - return false; - } - if (shader->source.empty()) { - if (err) { - (*err) += "shader is empty.\n"; // This may be OK? - } - return false; - } - } - } - - double type; - if (!ParseNumberProperty(&type, err, o, "type", true)) { - return false; - } - - shader->type = static_cast(type); - - ParseExtrasProperty(&(shader->extras), o); - - return true; -} - -static bool ParseProgram(Program *program, std::string *err, - const picojson::object &o) { - ParseStringProperty(&program->name, err, o, "name", false); - - if (!ParseStringProperty(&program->vertexShader, err, o, "vertexShader", - true)) { - return false; - } - if (!ParseStringProperty(&program->fragmentShader, err, o, "fragmentShader", - true)) { - return false; - } - - // I suppose the list of attributes isn't needed, but a technique doesn't - // really make sense without it. - ParseStringArrayProperty(&program->attributes, err, o, "attributes", false); - - ParseExtrasProperty(&(program->extras), o); - - return true; -} - -static bool ParseTechniqueParameter(TechniqueParameter *param, std::string *err, - const picojson::object &o) { - double count = 1; - ParseNumberProperty(&count, err, o, "count", false); - - double type; - if (!ParseNumberProperty(&type, err, o, "type", true)) { - return false; - } - - ParseStringProperty(¶m->node, err, o, "node", false); - ParseStringProperty(¶m->semantic, err, o, "semantic", false); - - ParseParameterProperty(¶m->value, err, o, "value", false); - - param->count = static_cast(count); - param->type = static_cast(type); - - return true; -} - -static bool ParseTechnique(Technique *technique, std::string *err, - const picojson::object &o) { - ParseStringProperty(&technique->name, err, o, "name", false); - - if (!ParseStringProperty(&technique->program, err, o, "program", true)) { - return false; - } - - ParseStringMapProperty(&technique->attributes, err, o, "attributes", false); - ParseStringMapProperty(&technique->uniforms, err, o, "uniforms", false); - - technique->parameters.clear(); - picojson::object::const_iterator paramsIt = o.find("parameters"); - - // Verify parameters is an object - if ((paramsIt != o.end()) && (paramsIt->second).is()) { - // For each parameter in params_object. - const picojson::object ¶ms_object = - (paramsIt->second).get(); - - picojson::object::const_iterator it(params_object.begin()); - picojson::object::const_iterator itEnd(params_object.end()); - - for (; it != itEnd; it++) { - TechniqueParameter param; - - // Skip non-objects - if (!it->second.is()) continue; - - // Parse the technique parameter - const picojson::object ¶m_obj = it->second.get(); - if (ParseTechniqueParameter(¶m, err, param_obj)) { - // Add if successful - technique->parameters[it->first] = param; - } - } - } - - ParseExtrasProperty(&(technique->extras), o); - - return true; -} - static bool ParseAnimationChannel(AnimationChannel *channel, std::string *err, const picojson::object &o) { if (!ParseStringProperty(&channel->sampler, err, o, "sampler", true)) { @@ -2421,57 +2116,7 @@ bool TinyGLTFLoader::LoadFromString(Scene *scene, std::string *err, } } - // 11. Parse Shader - if (v.contains("shaders") && v.get("shaders").is()) { - const picojson::object &root = v.get("shaders").get(); - - picojson::object::const_iterator it(root.begin()); - picojson::object::const_iterator itEnd(root.end()); - for (; it != itEnd; ++it) { - Shader shader; - if (!ParseShader(&shader, err, (it->second).get(), - base_dir, is_binary_, bin_data_, bin_size_)) { - return false; - } - - scene->shaders[it->first] = shader; - } - } - - // 12. Parse Program - if (v.contains("programs") && v.get("programs").is()) { - const picojson::object &root = v.get("programs").get(); - - picojson::object::const_iterator it(root.begin()); - picojson::object::const_iterator itEnd(root.end()); - for (; it != itEnd; ++it) { - Program program; - if (!ParseProgram(&program, err, (it->second).get())) { - return false; - } - - scene->programs[it->first] = program; - } - } - - // 13. Parse Technique - if (v.contains("techniques") && v.get("techniques").is()) { - const picojson::object &root = v.get("techniques").get(); - - picojson::object::const_iterator it(root.begin()); - picojson::object::const_iterator itEnd(root.end()); - for (; it != itEnd; ++it) { - Technique technique; - if (!ParseTechnique(&technique, err, - (it->second).get())) { - return false; - } - - scene->techniques[it->first] = technique; - } - } - - // 14. Parse Animation + // 11. Parse Animation if (v.contains("animations") && v.get("animations").is()) { const picojson::object &root = v.get("animations").get(); @@ -2488,7 +2133,7 @@ bool TinyGLTFLoader::LoadFromString(Scene *scene, std::string *err, } } - // 15. Parse Sampler + // 12. Parse Sampler if (v.contains("samplers") && v.get("samplers").is()) { const picojson::object &root = v.get("samplers").get(); From ee4693e3a15eb6d4ba0122dc0986f9ff879676cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Chatelain?= Date: Wed, 24 May 2017 12:33:36 +0000 Subject: [PATCH 02/10] Supports glTF 2.0 schema - Renaming 'Scene' to 'Model' to avoid confusion - glTF top objects are now arrays, and objects are referenced by index instead of id - added a few comments (required) - default values --- tiny_gltf_loader.h | 685 ++++++++++++++++++++++++++------------------- 1 file changed, 394 insertions(+), 291 deletions(-) diff --git a/tiny_gltf_loader.h b/tiny_gltf_loader.h index 4f36b77..b4dcaf2 100644 --- a/tiny_gltf_loader.h +++ b/tiny_gltf_loader.h @@ -278,63 +278,84 @@ typedef struct { typedef std::map ParameterMap; -typedef struct { - std::string sampler; - std::string target_id; - std::string target_path; +struct AnimationChannel { + int sampler; // required + int target_node; // required (index of the node to target) + std::string target_path; // required in ["translation", "rotation", "scale", "weights"] Value extras; -} AnimationChannel; -typedef struct { - std::string input; - std::string interpolation; - std::string output; - Value extras; -} AnimationSampler; + AnimationChannel() + { + sampler = -1; + target_node = -1; + } +}; + +struct AnimationSampler { + int input; // required + std::string interpolation; // in ["LINEAR", "STEP", "CATMULLROMSPLINE", "CUBICSPLINE"], default "LINEAR" + int output; // required + + AnimationSampler() + { + input = -1; + output = -1; + } +}; typedef struct { std::string name; std::vector channels; - std::map samplers; - ParameterMap parameters; + std::vector samplers; Value extras; } Animation; -typedef struct { +struct Sampler { std::string name; - int minFilter; - int magFilter; - int wrapS; - int wrapT; + int minFilter; // ["NEAREST", "LINEAR", "NEAREST_MIPMAP_LINEAR", "LINEAR_MIPMAP_NEAREST", "NEAREST_MIPMAP_LINEAR", "LINEAR_MIPMAP_LINEAR"] + int magFilter; // ["NEAREST", "LINEAR"] + int wrapS; // ["CLAMP_TO_EDGE", "MIRRORED_REPEAT", "REPEAT"], default "REPEAT" + int wrapT; // ["CLAMP_TO_EDGE", "MIRRORED_REPEAT", "REPEAT"], default "REPEAT" int wrapR; // TinyGLTF extension int pad0; Value extras; -} Sampler; -typedef struct { + Sampler() + { + wrapS = TINYGLTF_TEXTURE_WRAP_RPEAT; + wrapT = TINYGLTF_TEXTURE_WRAP_RPEAT; + } +}; + +struct Image{ std::string name; int width; int height; int component; int pad0; std::vector image; - - std::string bufferView; // KHR_binary_glTF extenstion. - std::string mimeType; // KHR_binary_glTF extenstion. - + int bufferView; // (required if no uri) + std::string mimeType; // (required if no uri) ["image/jpeg", "image/png"] + std::string uri; // (reqiored if no mimeType) Value extras; -} Image; -typedef struct { - int format; - int internalFormat; - std::string sampler; // Required - std::string source; // Required - int target; - int type; - std::string name; + Image() + { + bufferView = -1; + } +}; + +struct Texture { + int sampler; + int source; // Required (not specified in the spec ?) Value extras; -} Texture; + + Texture() + { + sampler = -1; + source =-1; + } +}; typedef struct { std::string name; @@ -344,30 +365,35 @@ typedef struct { Value extras; } Material; -typedef struct { +struct BufferView{ std::string name; - std::string buffer; // Required - size_t byteOffset; // Required - size_t byteLength; // default: 0 - int target; + int buffer; // Required + size_t byteOffset; // minimum 0, default 0 + size_t byteLength; // required, minimum 1 + size_t byteStride; // minimum 4, maximum 252 (multiple of 4) + int target; // ["ARRAY_BUFFER", "ELEMENT_ARRAY_BUFFER"] int pad0; Value extras; -} BufferView; +}; -typedef struct { - std::string bufferView; +struct Accessor { + int bufferView; // optional in spec but required here since sparse accessor are not supported std::string name; size_t byteOffset; size_t byteStride; - int componentType; // One of TINYGLTF_COMPONENT_TYPE_*** - int pad0; - size_t count; - int type; // One of TINYGLTF_TYPE_*** - int pad1; - std::vector minValues; // Optional - std::vector maxValues; // Optional + int componentType; // (required) One of TINYGLTF_COMPONENT_TYPE_*** + size_t count; // required + int type; // (required) One of TINYGLTF_TYPE_*** .. Value extras; -} Accessor; + + std::vector minValues; // required + std::vector maxValues; // required + + Accessor() + { + bufferView = -1; + } +}; class Camera { public: @@ -384,35 +410,45 @@ class Camera { float zNear; }; -typedef struct { - std::map attributes; // A dictionary object of - // strings, where each string - // is the ID of the accessor - // containing an attribute. - std::string material; // The ID of the material to apply to this primitive - // when rendering. - std::string indices; // The ID of the accessor that contains the indices. - int mode; // one of TINYGLTF_MODE_*** - int pad0; +struct Primitive { + std::map attributes; // (required) A dictionary object of + // integer, where each integer + // is the index of the accessor + // containing an attribute. + int material; // The index of the material to apply to this primitive + // when rendering. + int indices; // The index of the accessor that contains the indices. + int mode; // one of TINYGLTF_MODE_*** + Value extras; - Value extras; // "extra" property -} Primitive; + Primitive() + { + material = -1; + indices = -1; + } +}; typedef struct { std::string name; std::vector primitives; + ParameterMap extensions; Value extras; } Mesh; class Node { public: - Node() {} + Node() + { + mesh = -1; + } + ~Node() {} - std::string camera; // camera object referenced by this node. + int camera; // the index of the camera referenced by this node std::string name; - std::vector children; + int mesh; + std::vector children; std::vector rotation; // length must be 0 or 4 std::vector scale; // length must be 0 or 3 std::vector translation; // length must be 0 or 3 @@ -425,6 +461,7 @@ class Node { typedef struct { std::string name; std::vector data; + std::string uri; // considered as required here but not in the spec (need to clarify) Value extras; } Buffer; @@ -438,24 +475,33 @@ typedef struct { Value extras; } Asset; -class Scene { +struct Scene { + std::string name; + std::vector nodes; + + ParameterMap extensions; + ParameterMap extras; +}; + +class Model { public: - Scene() {} - ~Scene() {} + Model() {} + ~Model() {} - std::map accessors; - std::map animations; - std::map buffers; - std::map bufferViews; - std::map materials; - std::map meshes; - std::map nodes; - std::map textures; - std::map images; - std::map samplers; - std::map > scenes; // list of nodes + std::vector accessors; + std::vector animations; + std::vector buffers; + std::vector bufferViews; + std::vector materials; + std::vector meshes; + std::vector nodes; + std::vector textures; + std::vector images; + std::vector samplers; + std::vector scenes; - std::string defaultScene; + int defaultScene; + std::vector extensionsUsed; Asset asset; @@ -482,28 +528,28 @@ class TinyGLTFLoader { /// Loads glTF ASCII asset from a file. /// Returns false and set error string to `err` if there's an error. - bool LoadASCIIFromFile(Scene *scene, std::string *err, + bool LoadASCIIFromFile(Model *model, std::string *err, const std::string &filename, unsigned int check_sections = REQUIRE_ALL); /// Loads glTF ASCII asset from string(memory). /// `length` = strlen(str); /// Returns false and set error string to `err` if there's an error. - bool LoadASCIIFromString(Scene *scene, std::string *err, const char *str, + bool LoadASCIIFromString(Model *model, std::string *err, const char *str, const unsigned int length, const std::string &base_dir, unsigned int check_sections = REQUIRE_ALL); /// Loads glTF binary asset from a file. /// Returns false and set error string to `err` if there's an error. - bool LoadBinaryFromFile(Scene *scene, std::string *err, + bool LoadBinaryFromFile(Model *model, std::string *err, const std::string &filename, unsigned int check_sections = REQUIRE_ALL); /// Loads glTF binary asset from memory. /// `length` = strlen(str); /// Returns false and set error string to `err` if there's an error. - bool LoadBinaryFromMemory(Scene *scene, std::string *err, + bool LoadBinaryFromMemory(Model *model, std::string *err, const unsigned char *bytes, const unsigned int length, const std::string &base_dir = "", @@ -513,7 +559,7 @@ class TinyGLTFLoader { /// Loads glTF asset from string(memory). /// `length` = strlen(str); /// Returns false and set error string to `err` if there's an error. - bool LoadFromString(Scene *scene, std::string *err, const char *str, + bool LoadFromString(Model *model, std::string *err, const char *str, const unsigned int length, const std::string &base_dir, unsigned int check_sections); @@ -1137,8 +1183,53 @@ static bool ParseStringProperty( return true; } +static bool ParseStringIntProperty(std::map *ret, + std::string *err, const picojson::object &o, + const std::string &property, bool required) { + picojson::object::const_iterator it = o.find(property); + if (it == o.end()) { + if (required) { + if (err) { + (*err) += "'" + property + "' property is missing.\n"; + } + } + return false; + } + + // Make sure we are dealing with an object / dictionary. + if (!it->second.is()) { + if (required) { + if (err) { + (*err) += "'" + property + "' property is not an object.\n"; + } + } + return false; + } + + ret->clear(); + const picojson::object &dict = it->second.get(); + + picojson::object::const_iterator dictIt(dict.begin()); + picojson::object::const_iterator dictItEnd(dict.end()); + + for (; dictIt != dictItEnd; ++dictIt) { + if (!dictIt->second.is()) { + if (required) { + if (err) { + (*err) += "'" + property + "' value is not an int.\n"; + } + } + return false; + } + + // Insert into the list. + (*ret)[dictIt->first] = static_cast(dictIt->second.get()); + } + return true; +} + static bool ParseKHRBinaryExtension(const picojson::object &o, std::string *err, - std::string *buffer_view, + double *buffer_view, std::string *mime_type, int *image_width, int *image_height) { picojson::object j = o; @@ -1176,7 +1267,7 @@ static bool ParseKHRBinaryExtension(const picojson::object &o, std::string *err, picojson::object k = ext["KHR_binary_glTF"].get(); - if (!ParseStringProperty(buffer_view, err, k, "bufferView", true)) { + if (!ParseNumberProperty(buffer_view, err, k, "bufferView", true)) { return false; } @@ -1227,8 +1318,16 @@ static bool ParseImage(Image *image, std::string *err, const picojson::object &o, const std::string &basedir, bool is_binary, const unsigned char *bin_data, size_t bin_size) { + // A glTF image must either reference a bufferView or an image uri + double bufferView = -1; + bool isEmbedded = ParseNumberProperty(&bufferView, err, o, "bufferView", true); + isEmbedded = isEmbedded && static_cast(bufferView) != -1; + std::string uri; - if (!ParseStringProperty(&uri, err, o, "uri", true)) { + if (!ParseStringProperty(&uri, err, o, "uri", true) && !isEmbedded) { + if (err) { + (*err) += "Invalid image data (required data is missing).\n"; + } return false; } @@ -1259,7 +1358,7 @@ static bool ParseImage(Image *image, std::string *err, // There should be "extensions" property. // "extensions":{"KHR_binary_glTF":{"bufferView": "id", ... - std::string buffer_view; + double buffer_view = -1.0; std::string mime_type; int image_width; int image_height; @@ -1280,7 +1379,7 @@ static bool ParseImage(Image *image, std::string *err, // Just only save some information here. Loading actual image data from // bufferView is done in other place. - image->bufferView = buffer_view; + image->bufferView = static_cast(buffer_view); image->mimeType = mime_type; image->width = image_width; image->height = image_height; @@ -1320,33 +1419,16 @@ static bool ParseTexture(Texture *texture, std::string *err, const picojson::object &o, const std::string &basedir) { (void)basedir; + double sampler = -1.0; + double source = -1.0; + ParseNumberProperty(&sampler, err, o, "sampler", false); - if (!ParseStringProperty(&texture->sampler, err, o, "sampler", true)) { + if (!ParseNumberProperty(&source, err, o, "source", true)) { return false; } - if (!ParseStringProperty(&texture->source, err, o, "source", true)) { - return false; - } - - ParseStringProperty(&texture->name, err, o, "name", false); - - double format = TINYGLTF_TEXTURE_FORMAT_RGBA; - ParseNumberProperty(&format, err, o, "format", false); - - double internalFormat = TINYGLTF_TEXTURE_FORMAT_RGBA; - ParseNumberProperty(&internalFormat, err, o, "internalFormat", false); - - double target = TINYGLTF_TEXTURE_TARGET_TEXTURE2D; - ParseNumberProperty(&target, err, o, "target", false); - - double type = TINYGLTF_TEXTURE_TYPE_UNSIGNED_BYTE; - ParseNumberProperty(&type, err, o, "type", false); - - texture->format = static_cast(format); - texture->internalFormat = static_cast(internalFormat); - texture->target = static_cast(target); - texture->type = static_cast(type); + texture->sampler = static_cast(sampler); + texture->source = static_cast(source); return true; } @@ -1445,8 +1527,8 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, static bool ParseBufferView(BufferView *bufferView, std::string *err, const picojson::object &o) { - std::string buffer; - if (!ParseStringProperty(&buffer, err, o, "buffer", true)) { + double buffer = -1.0; + if (!ParseNumberProperty(&buffer, err, o, "buffer", true)) { return false; } @@ -1455,8 +1537,13 @@ static bool ParseBufferView(BufferView *bufferView, std::string *err, return false; } - double byteLength = 0.0; - ParseNumberProperty(&byteLength, err, o, "byteLength", false); + double byteLength = 1.0; + if(!ParseNumberProperty(&byteLength, err, o, "byteLength", true)) { + return false; + } + + double byteStride = 4.0; + ParseNumberProperty(&byteLength, err, o, "byteStride", false); double target = 0.0; ParseNumberProperty(&target, err, o, "target", false); @@ -1471,26 +1558,27 @@ static bool ParseBufferView(BufferView *bufferView, std::string *err, ParseStringProperty(&bufferView->name, err, o, "name", false); - bufferView->buffer = buffer; + bufferView->buffer = static_cast(buffer); bufferView->byteOffset = static_cast(byteOffset); bufferView->byteLength = static_cast(byteLength); + bufferView->byteStride = static_cast(byteStride); return true; } static bool ParseAccessor(Accessor *accessor, std::string *err, const picojson::object &o) { - std::string bufferView; - if (!ParseStringProperty(&bufferView, err, o, "bufferView", true)) { + double bufferView = -1.0; + if (!ParseNumberProperty(&bufferView, err, o, "bufferView", true)) { return false; } - double byteOffset; + double byteOffset = 0.0; if (!ParseNumberProperty(&byteOffset, err, o, "byteOffset", true)) { return false; } - double componentType; + double componentType = 0.0; if (!ParseNumberProperty(&componentType, err, o, "componentType", true)) { return false; } @@ -1535,11 +1623,16 @@ static bool ParseAccessor(Accessor *accessor, std::string *err, accessor->minValues.clear(); accessor->maxValues.clear(); - ParseNumberArrayProperty(&accessor->minValues, err, o, "min", false); - ParseNumberArrayProperty(&accessor->maxValues, err, o, "max", false); + if(!ParseNumberArrayProperty(&accessor->minValues, err, o, "min", true)) { + return false; + } + + if(!ParseNumberArrayProperty(&accessor->maxValues, err, o, "max", true)) { + return false; + } accessor->count = static_cast(count); - accessor->bufferView = bufferView; + accessor->bufferView = static_cast(bufferView); accessor->byteOffset = static_cast(byteOffset); accessor->byteStride = static_cast(byteStride); @@ -1566,21 +1659,23 @@ static bool ParseAccessor(Accessor *accessor, std::string *err, static bool ParsePrimitive(Primitive *primitive, std::string *err, const picojson::object &o) { - if (!ParseStringProperty(&primitive->material, err, o, "material", true, - "mesh.primitive")) { - return false; - } + double material = -1.0; + ParseNumberProperty(&material, err, o, "material", false); + primitive->material = static_cast(material); double mode = static_cast(TINYGLTF_MODE_TRIANGLES); ParseNumberProperty(&mode, err, o, "mode", false); int primMode = static_cast(mode); - primitive->mode = primMode; + primitive->mode = primMode; // Why only triangled were supported ? - primitive->indices = ""; - ParseStringProperty(&primitive->indices, err, o, "indices", false); - - ParseStringMapProperty(&primitive->attributes, err, o, "attributes", false); + double indices = -1.0; + ParseNumberProperty(&indices, err, o, "indices", false); + primitive->indices = static_cast(indices); + if (!ParseStringIntProperty(&primitive->attributes, err, o, "attributes", + true)) { + return false; + } ParseExtrasProperty(&(primitive->extras), o); @@ -1613,11 +1708,21 @@ static bool ParseMesh(Mesh *mesh, std::string *err, const picojson::object &o) { static bool ParseNode(Node *node, std::string *err, const picojson::object &o) { ParseStringProperty(&node->name, err, o, "name", false); - ParseNumberArrayProperty(&node->rotation, err, o, "rotation", false); - ParseNumberArrayProperty(&node->scale, err, o, "scale", false); - ParseNumberArrayProperty(&node->translation, err, o, "translation", false); - ParseNumberArrayProperty(&node->matrix, err, o, "matrix", false); - ParseStringArrayProperty(&node->meshes, err, o, "meshes", false); + // Matrix and T/R/S are exclusive + if(!ParseNumberArrayProperty(&node->matrix, err, o, "matrix", false)) { + + ParseNumberArrayProperty(&node->rotation, err, o, "rotation", false); + ParseNumberArrayProperty(&node->scale, err, o, "scale", false); + ParseNumberArrayProperty(&node->translation, err, o, "translation", false); + } + + double camera = -1.0; + ParseNumberProperty(&camera, err, o, "camera", false); + node->camera = static_cast(camera); + + double mesh = -1.0; + ParseNumberProperty(&mesh, err, o, "mesh", false); + node->mesh = mesh; node->children.clear(); picojson::object::const_iterator childrenObject = o.find("children"); @@ -1626,13 +1731,13 @@ static bool ParseNode(Node *node, std::string *err, const picojson::object &o) { const picojson::array &childrenArray = (childrenObject->second).get(); for (size_t i = 0; i < childrenArray.size(); i++) { - if (!childrenArray[i].is()) { + if (!childrenArray[i].is()) { if (err) { (*err) += "Invalid `children` array.\n"; } return false; } - const std::string &childrenNode = childrenArray[i].get(); + const int &childrenNode = static_cast(childrenArray[i].get()); node->children.push_back(childrenNode); } } @@ -1703,7 +1808,9 @@ static bool ParseMaterial(Material *material, std::string *err, static bool ParseAnimationChannel(AnimationChannel *channel, std::string *err, const picojson::object &o) { - if (!ParseStringProperty(&channel->sampler, err, o, "sampler", true)) { + double samplerIndex = -1.0; + double targetIndex = -1.0; + if (!ParseNumberProperty(&samplerIndex, err, o, "sampler", true)) { if (err) { (*err) += "`sampler` field is missing in animation channels\n"; } @@ -1715,7 +1822,7 @@ static bool ParseAnimationChannel(AnimationChannel *channel, std::string *err, const picojson::object &target_object = (targetIt->second).get(); - if (!ParseStringProperty(&channel->target_id, err, target_object, "id", + if (!ParseNumberProperty(&targetIndex, err, target_object, "node", true)) { if (err) { (*err) += "`id` field is missing in animation.channels.target\n"; @@ -1732,6 +1839,9 @@ static bool ParseAnimationChannel(AnimationChannel *channel, std::string *err, } } + channel->sampler = static_cast(samplerIndex); + channel->target_node = static_cast(targetIndex); + ParseExtrasProperty(&(channel->extras), o); return true; @@ -1757,21 +1867,20 @@ static bool ParseAnimation(Animation *animation, std::string *err, { picojson::object::const_iterator samplerIt = o.find("samplers"); - if ((samplerIt != o.end()) && (samplerIt->second).is()) { - const picojson::object &sampler_object = - (samplerIt->second).get(); + if ((samplerIt != o.end()) && (samplerIt->second).is()) { + const picojson::array &sampler_array = + (samplerIt->second).get(); - picojson::object::const_iterator it = sampler_object.begin(); - picojson::object::const_iterator itEnd = sampler_object.end(); + picojson::array::const_iterator it = sampler_array.begin(); + picojson::array::const_iterator itEnd = sampler_array.end(); for (; it != itEnd; it++) { - // Skip non-objects - if (!it->second.is()) continue; - - const picojson::object &s = it->second.get(); + const picojson::object &s = it->get(); AnimationSampler sampler; - if (!ParseStringProperty(&sampler.input, err, s, "input", true)) { + double inputIndex = -1.0; + double outputIndex = -1.0; + if (!ParseNumberProperty(&inputIndex, err, s, "input", true)) { if (err) { (*err) += "`input` field is missing in animation.sampler\n"; } @@ -1784,35 +1893,19 @@ static bool ParseAnimation(Animation *animation, std::string *err, } return false; } - if (!ParseStringProperty(&sampler.output, err, s, "output", true)) { + if (!ParseNumberProperty(&outputIndex, err, s, "output", true)) { if (err) { (*err) += "`output` field is missing in animation.sampler\n"; } return false; } - - animation->samplers[it->first] = sampler; + sampler.input = static_cast(inputIndex); + sampler.output = static_cast(outputIndex); + animation->samplers.push_back(sampler); } } } - picojson::object::const_iterator parametersIt = o.find("parameters"); - if ((parametersIt != o.end()) && - (parametersIt->second).is()) { - const picojson::object ¶meters_object = - (parametersIt->second).get(); - - picojson::object::const_iterator it(parameters_object.begin()); - picojson::object::const_iterator itEnd(parameters_object.end()); - - for (; it != itEnd; it++) { - Parameter param; - if (ParseParameterProperty(¶m, err, parameters_object, it->first, - false)) { - animation->parameters[it->first] = param; - } - } - } ParseStringProperty(&animation->name, err, o, "name", false); ParseExtrasProperty(&(animation->extras), o); @@ -1844,7 +1937,7 @@ static bool ParseSampler(Sampler *sampler, std::string *err, return true; } -bool TinyGLTFLoader::LoadFromString(Scene *scene, std::string *err, +bool TinyGLTFLoader::LoadFromString(Model *model, std::string *err, const char *str, unsigned int length, const std::string &base_dir, unsigned int check_sections) { @@ -1858,16 +1951,10 @@ bool TinyGLTFLoader::LoadFromString(Scene *scene, std::string *err, return false; } - if (v.contains("scene") && v.get("scene").is()) { - // OK - } else if (check_sections & REQUIRE_SCENE) { - if (err) { - (*err) += "\"scene\" object not found in .gltf\n"; - } - return false; - } + // scene is not mandatory. + //FIXME Maybe a better way to handle it than removing the code - if (v.contains("scenes") && v.get("scenes").is()) { +if (v.contains("scenes") && v.get("scenes").is()) { // OK } else if (check_sections & REQUIRE_SCENES) { if (err) { @@ -1876,7 +1963,7 @@ bool TinyGLTFLoader::LoadFromString(Scene *scene, std::string *err, return false; } - if (v.contains("nodes") && v.get("nodes").is()) { + if (v.contains("nodes") && v.get("nodes").is()) { // OK } else if (check_sections & REQUIRE_NODES) { if (err) { @@ -1885,7 +1972,7 @@ bool TinyGLTFLoader::LoadFromString(Scene *scene, std::string *err, return false; } - if (v.contains("accessors") && v.get("accessors").is()) { + if (v.contains("accessors") && v.get("accessors").is()) { // OK } else if (check_sections & REQUIRE_ACCESSORS) { if (err) { @@ -1894,7 +1981,7 @@ bool TinyGLTFLoader::LoadFromString(Scene *scene, std::string *err, return false; } - if (v.contains("buffers") && v.get("buffers").is()) { + if (v.contains("buffers") && v.get("buffers").is()) { // OK } else if (check_sections & REQUIRE_BUFFERS) { if (err) { @@ -1904,7 +1991,7 @@ bool TinyGLTFLoader::LoadFromString(Scene *scene, std::string *err, } if (v.contains("bufferViews") && - v.get("bufferViews").is()) { + v.get("bufferViews").is()) { // OK } else if (check_sections & REQUIRE_BUFFER_VIEWS) { if (err) { @@ -1913,168 +2000,184 @@ bool TinyGLTFLoader::LoadFromString(Scene *scene, std::string *err, return false; } - scene->buffers.clear(); - scene->bufferViews.clear(); - scene->accessors.clear(); - scene->meshes.clear(); - scene->nodes.clear(); - scene->defaultScene = ""; + model->buffers.clear(); + model->bufferViews.clear(); + model->accessors.clear(); + model->meshes.clear(); + model->nodes.clear(); + model->extensionsUsed.clear(); + model->defaultScene = -1; // 0. Parse Asset if (v.contains("asset") && v.get("asset").is()) { const picojson::object &root = v.get("asset").get(); - ParseAsset(&scene->asset, err, root); + ParseAsset(&model->asset, err, root); + } + + // 0. Parse extensionUsed + if (v.contains("extensionsUsed") && v.get("extensionsUsed").is()) { + const picojson::array &root = v.get("extensionsUsed").get(); + for(unsigned int i=0; i< root.size(); ++i) + { + model->extensionsUsed.push_back(root[i].get()); + } } // 1. Parse Buffer - if (v.contains("buffers") && v.get("buffers").is()) { - const picojson::object &root = v.get("buffers").get(); + if (v.contains("buffers") && v.get("buffers").is()) { + const picojson::array &root = v.get("buffers").get(); - picojson::object::const_iterator it(root.begin()); - picojson::object::const_iterator itEnd(root.end()); + picojson::array::const_iterator it(root.begin()); + picojson::array::const_iterator itEnd(root.end()); for (; it != itEnd; it++) { Buffer buffer; - if (!ParseBuffer(&buffer, err, (it->second).get(), + if (!ParseBuffer(&buffer, err, it->get(), base_dir, is_binary_, bin_data_, bin_size_)) { return false; } - scene->buffers[it->first] = buffer; + model->buffers.push_back(buffer); } } // 2. Parse BufferView if (v.contains("bufferViews") && - v.get("bufferViews").is()) { - const picojson::object &root = v.get("bufferViews").get(); + v.get("bufferViews").is()) { + const picojson::array &root = v.get("bufferViews").get(); - picojson::object::const_iterator it(root.begin()); - picojson::object::const_iterator itEnd(root.end()); + picojson::array::const_iterator it(root.begin()); + picojson::array::const_iterator itEnd(root.end()); for (; it != itEnd; it++) { BufferView bufferView; if (!ParseBufferView(&bufferView, err, - (it->second).get())) { + it->get())) { return false; } - scene->bufferViews[it->first] = bufferView; + model->bufferViews.push_back(bufferView); } } // 3. Parse Accessor - if (v.contains("accessors") && v.get("accessors").is()) { - const picojson::object &root = v.get("accessors").get(); + if (v.contains("accessors") && v.get("accessors").is()) { + const picojson::array &root = v.get("accessors").get(); - picojson::object::const_iterator it(root.begin()); - picojson::object::const_iterator itEnd(root.end()); + picojson::array::const_iterator it(root.begin()); + picojson::array::const_iterator itEnd(root.end()); for (; it != itEnd; it++) { Accessor accessor; if (!ParseAccessor(&accessor, err, - (it->second).get())) { + it->get())) { return false; } - scene->accessors[it->first] = accessor; + model->accessors.push_back(accessor); } } // 4. Parse Mesh - if (v.contains("meshes") && v.get("meshes").is()) { - const picojson::object &root = v.get("meshes").get(); + if (v.contains("meshes") && v.get("meshes").is()) { + const picojson::array &root = v.get("meshes").get(); - picojson::object::const_iterator it(root.begin()); - picojson::object::const_iterator itEnd(root.end()); + picojson::array::const_iterator it(root.begin()); + picojson::array::const_iterator itEnd(root.end()); for (; it != itEnd; it++) { Mesh mesh; - if (!ParseMesh(&mesh, err, (it->second).get())) { + if (!ParseMesh(&mesh, err, it->get())) { return false; } - scene->meshes[it->first] = mesh; + model->meshes.push_back(mesh); } } // 5. Parse Node - if (v.contains("nodes") && v.get("nodes").is()) { - const picojson::object &root = v.get("nodes").get(); + if (v.contains("nodes") && v.get("nodes").is()) { + const picojson::array &root = v.get("nodes").get(); - picojson::object::const_iterator it(root.begin()); - picojson::object::const_iterator itEnd(root.end()); + picojson::array::const_iterator it(root.begin()); + picojson::array::const_iterator itEnd(root.end()); for (; it != itEnd; it++) { Node node; - if (!ParseNode(&node, err, (it->second).get())) { + if (!ParseNode(&node, err, it->get())) { return false; } - scene->nodes[it->first] = node; + model->nodes.push_back(node); } } // 6. Parse scenes. - if (v.contains("scenes") && v.get("scenes").is()) { - const picojson::object &root = v.get("scenes").get(); + if (v.contains("scenes") && v.get("scenes").is()) { + const picojson::array &root = v.get("scenes").get(); - picojson::object::const_iterator it(root.begin()); - picojson::object::const_iterator itEnd(root.end()); + picojson::array::const_iterator it(root.begin()); + picojson::array::const_iterator itEnd(root.end()); for (; it != itEnd; it++) { - if (!((it->second).is())) { + if (!(it->is())) { if (err) { (*err) += "`scenes' does not contain an object."; } return false; } - const picojson::object &o = (it->second).get(); - std::vector nodes; - if (!ParseStringArrayProperty(&nodes, err, o, "nodes", false)) { + const picojson::object &o = it->get(); + std::vector nodes; + if (!ParseNumberArrayProperty(&nodes, err, o, "nodes", false)) { return false; } - scene->scenes[it->first] = nodes; + Scene scene; + ParseStringProperty(&scene.name, err, o, "name", false); + std::vector nodesIds(nodes.begin(), nodes.end()); + scene.nodes = nodesIds; + + model->scenes.push_back(scene); } } // 7. Parse default scenes. - if (v.contains("scene") && v.get("scene").is()) { - const std::string defaultScene = v.get("scene").get(); + if (v.contains("scene") && v.get("scene").is()) { + const int defaultScene = v.get("scene").get(); - scene->defaultScene = defaultScene; + model->defaultScene = static_cast(defaultScene); } // 8. Parse Material - if (v.contains("materials") && v.get("materials").is()) { - const picojson::object &root = v.get("materials").get(); - - picojson::object::const_iterator it(root.begin()); - picojson::object::const_iterator itEnd(root.end()); + if (v.contains("materials") && v.get("materials").is()) { + const picojson::array &root = v.get("materials").get(); + picojson::array::const_iterator it(root.begin()); + picojson::array::const_iterator itEnd(root.end()); for (; it != itEnd; it++) { + picojson::object jsonMaterial = it->get(); + Material material; - if (!ParseMaterial(&material, err, - (it->second).get())) { + ParseStringProperty(&material.name, err, jsonMaterial, "name", false); + + if (!ParseMaterial(&material, err, jsonMaterial)) { return false; } - scene->materials[it->first] = material; + model->materials.push_back(material); } } // 9. Parse Image - if (v.contains("images") && v.get("images").is()) { - const picojson::object &root = v.get("images").get(); + if (v.contains("images") && v.get("images").is()) { + const picojson::array &root = v.get("images").get(); - picojson::object::const_iterator it(root.begin()); - picojson::object::const_iterator itEnd(root.end()); + picojson::array::const_iterator it(root.begin()); + picojson::array::const_iterator itEnd(root.end()); for (; it != itEnd; it++) { Image image; - if (!ParseImage(&image, err, (it->second).get(), + if (!ParseImage(&image, err, it->get(), base_dir, is_binary_, bin_data_, bin_size_)) { return false; } - if (!image.bufferView.empty()) { + if (image.bufferView != -1) { // Load image from the buffer view. - if (scene->bufferViews.find(image.bufferView) == - scene->bufferViews.end()) { + if ((size_t)image.bufferView >= model->bufferViews.size()) { if (err) { std::stringstream ss; ss << "bufferView \"" << image.bufferView @@ -2084,8 +2187,8 @@ bool TinyGLTFLoader::LoadFromString(Scene *scene, std::string *err, return false; } - const BufferView &bufferView = scene->bufferViews[image.bufferView]; - const Buffer &buffer = scene->buffers[bufferView.buffer]; + const BufferView &bufferView = model->bufferViews[image.bufferView]; + const Buffer &buffer = model->buffers[bufferView.buffer]; bool ret = LoadImageData(&image, err, image.width, image.height, &buffer.data[bufferView.byteOffset], @@ -2095,24 +2198,24 @@ bool TinyGLTFLoader::LoadFromString(Scene *scene, std::string *err, } } - scene->images[it->first] = image; + model->images.push_back(image); } } // 10. Parse Texture - if (v.contains("textures") && v.get("textures").is()) { - const picojson::object &root = v.get("textures").get(); + if (v.contains("textures") && v.get("textures").is()) { + const picojson::array &root = v.get("textures").get(); - picojson::object::const_iterator it(root.begin()); - picojson::object::const_iterator itEnd(root.end()); + picojson::array::const_iterator it(root.begin()); + picojson::array::const_iterator itEnd(root.end()); for (; it != itEnd; it++) { Texture texture; - if (!ParseTexture(&texture, err, (it->second).get(), + if (!ParseTexture(&texture, err, it->get(), base_dir)) { return false; } - scene->textures[it->first] = texture; + model->textures.push_back(texture); } } @@ -2120,38 +2223,38 @@ bool TinyGLTFLoader::LoadFromString(Scene *scene, std::string *err, if (v.contains("animations") && v.get("animations").is()) { const picojson::object &root = v.get("animations").get(); - picojson::object::const_iterator it(root.begin()); - picojson::object::const_iterator itEnd(root.end()); + picojson::array::const_iterator it(root.begin()); + picojson::array::const_iterator itEnd(root.end()); for (; it != itEnd; ++it) { Animation animation; if (!ParseAnimation(&animation, err, - (it->second).get())) { + it->get())) { return false; } - scene->animations[it->first] = animation; + model->animations.push_back(animation); } } // 12. Parse Sampler - if (v.contains("samplers") && v.get("samplers").is()) { - const picojson::object &root = v.get("samplers").get(); + if (v.contains("samplers") && v.get("samplers").is()) { + const picojson::array &root = v.get("samplers").get(); - picojson::object::const_iterator it(root.begin()); - picojson::object::const_iterator itEnd(root.end()); + picojson::array::const_iterator it(root.begin()); + picojson::array::const_iterator itEnd(root.end()); for (; it != itEnd; ++it) { Sampler sampler; - if (!ParseSampler(&sampler, err, (it->second).get())) { + if (!ParseSampler(&sampler, err, it->get())) { return false; } - scene->samplers[it->first] = sampler; + model->samplers.push_back(sampler); } } return true; } -bool TinyGLTFLoader::LoadASCIIFromString(Scene *scene, std::string *err, +bool TinyGLTFLoader::LoadASCIIFromString(Model *model, std::string *err, const char *str, unsigned int length, const std::string &base_dir, unsigned int check_sections) { @@ -2159,10 +2262,10 @@ bool TinyGLTFLoader::LoadASCIIFromString(Scene *scene, std::string *err, bin_data_ = NULL; bin_size_ = 0; - return LoadFromString(scene, err, str, length, base_dir, check_sections); + return LoadFromString(model, err, str, length, base_dir, check_sections); } -bool TinyGLTFLoader::LoadASCIIFromFile(Scene *scene, std::string *err, +bool TinyGLTFLoader::LoadASCIIFromFile(Model *model, std::string *err, const std::string &filename, unsigned int check_sections) { std::stringstream ss; @@ -2193,14 +2296,14 @@ bool TinyGLTFLoader::LoadASCIIFromFile(Scene *scene, std::string *err, std::string basedir = GetBaseDir(filename); - bool ret = LoadASCIIFromString(scene, err, &buf.at(0), + bool ret = LoadASCIIFromString(model, err, &buf.at(0), static_cast(buf.size()), basedir, check_sections); return ret; } -bool TinyGLTFLoader::LoadBinaryFromMemory(Scene *scene, std::string *err, +bool TinyGLTFLoader::LoadBinaryFromMemory(Model *model, std::string *err, const unsigned char *bytes, unsigned int size, const std::string &base_dir, @@ -2224,21 +2327,21 @@ bool TinyGLTFLoader::LoadBinaryFromMemory(Scene *scene, std::string *err, unsigned int version; // 4 bytes unsigned int length; // 4 bytes - unsigned int scene_length; // 4 bytes - unsigned int scene_format; // 4 bytes; + unsigned int model_length; // 4 bytes + unsigned int model_format; // 4 bytes; // @todo { Endian swap for big endian machine. } memcpy(&version, bytes + 4, 4); swap4(&version); memcpy(&length, bytes + 8, 4); swap4(&length); - memcpy(&scene_length, bytes + 12, 4); - swap4(&scene_length); - memcpy(&scene_format, bytes + 16, 4); - swap4(&scene_format); + memcpy(&model_length, bytes + 12, 4); + swap4(&model_length); + memcpy(&model_format, bytes + 16, 4); + swap4(&model_format); - if ((20 + scene_length >= size) || (scene_length < 1) || - (scene_format != 0)) { // 0 = JSON format. + if ((20 + model_length >= size) || (model_length < 1) || + (model_format != 0)) { // 0 = JSON format. if (err) { (*err) = "Invalid glTF binary."; } @@ -2247,16 +2350,16 @@ bool TinyGLTFLoader::LoadBinaryFromMemory(Scene *scene, std::string *err, // Extract JSON string. std::string jsonString(reinterpret_cast(&bytes[20]), - scene_length); + model_length); is_binary_ = true; - bin_data_ = bytes + 20 + scene_length; + bin_data_ = bytes + 20 + model_length; bin_size_ = - length - (20 + scene_length); // extract header + JSON scene data. + length - (20 + model_length); // extract header + JSON scene data. bool ret = - LoadFromString(scene, err, reinterpret_cast(&bytes[20]), - scene_length, base_dir, check_sections); + LoadFromString(model, err, reinterpret_cast(&bytes[20]), + model_length, base_dir, check_sections); if (!ret) { return ret; } @@ -2264,7 +2367,7 @@ bool TinyGLTFLoader::LoadBinaryFromMemory(Scene *scene, std::string *err, return true; } -bool TinyGLTFLoader::LoadBinaryFromFile(Scene *scene, std::string *err, +bool TinyGLTFLoader::LoadBinaryFromFile(Model *model, std::string *err, const std::string &filename, unsigned int check_sections) { std::stringstream ss; @@ -2289,7 +2392,7 @@ bool TinyGLTFLoader::LoadBinaryFromFile(Scene *scene, std::string *err, std::string basedir = GetBaseDir(filename); bool ret = LoadBinaryFromMemory( - scene, err, reinterpret_cast(&buf.at(0)), + model, err, reinterpret_cast(&buf.at(0)), static_cast(buf.size()), basedir, check_sections); return ret; From a25e495fd92d1b8da68e0377a15d8e06f2c9a03b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Chatelain?= Date: Wed, 24 May 2017 09:52:28 +0000 Subject: [PATCH 03/10] Updates camera object (glTF 2.0) --- tiny_gltf_loader.h | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/tiny_gltf_loader.h b/tiny_gltf_loader.h index b4dcaf2..aa3ee3f 100644 --- a/tiny_gltf_loader.h +++ b/tiny_gltf_loader.h @@ -403,11 +403,20 @@ class Camera { std::string name; bool isOrthographic; // false = perspective. - // Some common properties. + // Orthographic properties + float xMag; // required + float yMag; // required + float zFar; // required + float zNear; //required + + // Perspective properties float aspectRatio; - float yFov; - float zFar; - float zNear; + float yfov; // required + float zfar; + float znear; // required + + ParameterMap extensions; + Value extras; }; struct Primitive { From ab7b21838579b9dfff1d146aca641cc1ffd9d850 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Chatelain?= Date: Wed, 24 May 2017 09:53:44 +0000 Subject: [PATCH 04/10] Updates materials (glTF 2.0) glTF 2.0 has now PBR materials. Core material is Metallic/Roughness material Specular/glossiness is still in an extension Material properties can be number arrays (colors/factors) or JSON objects (textures) --- tiny_gltf_loader.h | 125 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 106 insertions(+), 19 deletions(-) diff --git a/tiny_gltf_loader.h b/tiny_gltf_loader.h index aa3ee3f..9f647f1 100644 --- a/tiny_gltf_loader.h +++ b/tiny_gltf_loader.h @@ -272,8 +272,10 @@ TINYGLTF_VALUE_GET(Value::Object, object_value_) #undef TINYGLTF_VALUE_GET typedef struct { + bool bool_value; std::string string_value; std::vector number_array; + std::map json_double_value; } Parameter; typedef std::map ParameterMap; @@ -357,13 +359,18 @@ struct Texture { } }; -typedef struct { +// Each extension should be stored in a ParameterMap. +// members not in the values could be included in the ParameterMap +// to keep a single material model +struct Material { std::string name; - std::string technique; - ParameterMap values; + ParameterMap values; // PBR metal/roughness workflow + ParameterMap additionalValues; // normal/occlusion/emissive values + ParameterMap extCommonValues; // KHR_common_material extension + ParameterMap extPBRValues; Value extras; -} Material; +}; struct BufferView{ std::string name; @@ -1301,6 +1308,43 @@ static bool ParseKHRBinaryExtension(const picojson::object &o, std::string *err, return true; } +static bool ParseJSONProperty(std::map *ret, std::string *err, + const picojson::object &o, + const std::string &property, + bool required) +{ + picojson::object::const_iterator it = o.find(property); + if(it == o.end()) + { + if (required) { + if(err) { + (*err) += "'" + property + "' property is missing. \n'"; + } + } + return false; + } + + if(!it->second.is()) { + if (required) { + if (err) { + (*err) += "'" + property + "' property is not a JSON object.\n"; + } + } + return false; + } + + ret->clear(); + const picojson::object &obj = it->second.get(); + picojson::object::const_iterator it2(obj.begin()); + picojson::object::const_iterator itEnd(obj.end()); + for (; it2 != itEnd; it2++) { + if(it2->second.is()) + ret->insert(std::pair(it2->first, it2->second.get())); + } + + return true; +} + static bool ParseAsset(Asset *asset, std::string *err, const picojson::object &o) { ParseStringProperty(&asset->generator, err, o, "generator", false); @@ -1776,6 +1820,10 @@ static bool ParseParameterProperty(Parameter *param, std::string *err, } else if (ParseNumberProperty(&num_val, err, o, prop, false)) { param->number_array.push_back(num_val); return true; + } else if(ParseJSONProperty(¶m->json_double_value, err, o, prop, false)) { + return true; + } else if(ParseBooleanProperty(¶m->bool_value, err, o, prop, false)) { + return true; } else { if (required) { if (err) { @@ -1787,28 +1835,67 @@ static bool ParseParameterProperty(Parameter *param, std::string *err, } static bool ParseMaterial(Material *material, std::string *err, - const picojson::object &o) { - ParseStringProperty(&material->name, err, o, "name", false); - ParseStringProperty(&material->technique, err, o, "technique", false); + const picojson::object &o) { material->values.clear(); - picojson::object::const_iterator valuesIt = o.find("values"); + material->extPBRValues.clear(); + material->additionalValues.clear(); - if ((valuesIt != o.end()) && (valuesIt->second).is()) { - const picojson::object &values_object = - (valuesIt->second).get(); + picojson::object::const_iterator it(o.begin()); + picojson::object::const_iterator itEnd(o.end()); - picojson::object::const_iterator it(values_object.begin()); - picojson::object::const_iterator itEnd(values_object.end()); + for (; it != itEnd; it++) { + if(it->first == "pbrMetallicRoughness") + { + if ((it->second).is()) { + const picojson::object &values_object = + (it->second).get(); - for (; it != itEnd; it++) { - Parameter param; - if (ParseParameterProperty(¶m, err, values_object, it->first, - false)) { - material->values[it->first] = param; + picojson::object::const_iterator itVal(values_object.begin()); + picojson::object::const_iterator itEnd(values_object.end()); + + for (; itVal != itEnd; itVal++) { + Parameter param; + if (ParseParameterProperty(¶m, err, values_object, itVal->first, + false)) { + material->values[itVal->first] = param; + } + } + } + } + else if(it->first == "extensions") + { + if ((it->second).is()) { + const picojson::object &extension = (it->second).get(); + + picojson::object::const_iterator extIt = extension.begin(); + if(!extIt->second.is()) + continue; + + const picojson::object &values_object = + (extIt->second).get(); + + picojson::object::const_iterator itVal(values_object.begin()); + picojson::object::const_iterator itEnd(values_object.end()); + + for (; itVal != itEnd; itVal++) { + Parameter param; + if (ParseParameterProperty(¶m, err, values_object, itVal->first, + false)) { + material->extPBRValues[itVal->first] = param; + } + } + } + } + else + { + Parameter param; + if (ParseParameterProperty(¶m, err, o, it->first, + false)) { + material->additionalValues[it->first] = param; + } } } - } ParseExtrasProperty(&(material->extras), o); From d48bbdcd90779df770cac724bd290d4e2e1d00f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Chatelain?= Date: Wed, 24 May 2017 09:54:18 +0000 Subject: [PATCH 05/10] Updates asset object (glTF 2.0) --- tiny_gltf_loader.h | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/tiny_gltf_loader.h b/tiny_gltf_loader.h index 9f647f1..3ae05c9 100644 --- a/tiny_gltf_loader.h +++ b/tiny_gltf_loader.h @@ -482,12 +482,11 @@ typedef struct { } Buffer; typedef struct { + std::string version; // required std::string generator; - std::string version; - std::string profile_api; - std::string profile_version; - bool premultipliedAlpha; - char pad[7]; + std::string minVersion; + std::string copyright; + ParameterMap extensions; Value extras; } Asset; @@ -1347,22 +1346,12 @@ static bool ParseJSONProperty(std::map *ret, std::string *e static bool ParseAsset(Asset *asset, std::string *err, const picojson::object &o) { + ParseStringProperty(&asset->version, err, o, "version", true); ParseStringProperty(&asset->generator, err, o, "generator", false); - ParseBooleanProperty(&asset->premultipliedAlpha, err, o, "premultipliedAlpha", - false); + ParseStringProperty(&asset->minVersion, err, o, "minVersion", false); - ParseStringProperty(&asset->version, err, o, "version", false); - - picojson::object::const_iterator profile = o.find("profile"); - if (profile != o.end()) { - const picojson::value &v = profile->second; - if (v.contains("api") & v.get("api").is()) { - asset->profile_api = v.get("api").get(); - } - if (v.contains("version") & v.get("version").is()) { - asset->profile_version = v.get("version").get(); - } - } + // Unity exporter version is added as extra here + ParseExtrasProperty(&(asset->extras), o); return true; } From 5cb4346a3270e3d29ef1be9d3787a79145075338 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Chatelain?= Date: Wed, 24 May 2017 09:55:14 +0000 Subject: [PATCH 06/10] Adds workaround for unsupported images --- tiny_gltf_loader.h | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/tiny_gltf_loader.h b/tiny_gltf_loader.h index 3ae05c9..0643d0a 100644 --- a/tiny_gltf_loader.h +++ b/tiny_gltf_loader.h @@ -904,12 +904,16 @@ static bool LoadImageData(Image *image, std::string *err, int req_width, int req_height, const unsigned char *bytes, int size) { int w, h, comp; + // if image cannot be decoded, ignore parsing and keep it by its path + // don't break in this case + //FIXME we should only enter this function if the image is embedded. If image->uri references + // an image file, it should be left as it is. Image loading should not be mandatory (to support other formats) unsigned char *data = stbi_load_from_memory(bytes, size, &w, &h, &comp, 0); if (!data) { if (err) { (*err) += "Unknown image format.\n"; } - return false; + return true; } if (w < 1 || h < 1) { @@ -917,7 +921,7 @@ static bool LoadImageData(Image *image, std::string *err, int req_width, if (err) { (*err) += "Unknown image format.\n"; } - return false; + return true; } if (req_width > 0) { @@ -1438,11 +1442,16 @@ static bool ParseImage(Image *image, std::string *err, } } else { // Assume external file + + // Keep texture path (for textures that cannot be decoded) + image->uri = uri; + if (!LoadExternalFile(&img, err, uri, basedir, 0, false)) { if (err) { (*err) += "Failed to load external 'uri'. for image parameter\n"; } - return false; + // If the image cannot be loaded, keep uri as image->uri. + return true; } if (img.empty()) { if (err) { From 8cb98950ff7e3d5b1a7d6bae5dc239beb2e74552 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Chatelain?= Date: Wed, 24 May 2017 12:55:26 +0000 Subject: [PATCH 07/10] Supports glTF skinning (glTF 2.0) --- tiny_gltf_loader.h | 67 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 4 deletions(-) diff --git a/tiny_gltf_loader.h b/tiny_gltf_loader.h index 0643d0a..7c9bd4e 100644 --- a/tiny_gltf_loader.h +++ b/tiny_gltf_loader.h @@ -312,6 +312,18 @@ typedef struct { Value extras; } Animation; +struct Skin { + std::string name; + int inverseBindMatrices; // required here but not in the spec + int skeleton; // The index of the node used as a skeleton root + std::vector joints; // Indices of skeleton nodes + + Skin() + { + inverseBindMatrices = -1; + } +}; + struct Sampler { std::string name; int minFilter; // ["NEAREST", "LINEAR", "NEAREST_MIPMAP_LINEAR", "LINEAR_MIPMAP_NEAREST", "NEAREST_MIPMAP_LINEAR", "LINEAR_MIPMAP_LINEAR"] @@ -455,7 +467,8 @@ class Node { public: Node() { - mesh = -1; + mesh = -1, + skin = -1; } ~Node() {} @@ -463,6 +476,7 @@ class Node { int camera; // the index of the camera referenced by this node std::string name; + int skin; int mesh; std::vector children; std::vector rotation; // length must be 0 or 4 @@ -512,6 +526,7 @@ class Model { std::vector nodes; std::vector textures; std::vector images; + std::vector skins; std::vector samplers; std::vector scenes; @@ -1759,6 +1774,10 @@ static bool ParseMesh(Mesh *mesh, std::string *err, const picojson::object &o) { static bool ParseNode(Node *node, std::string *err, const picojson::object &o) { ParseStringProperty(&node->name, err, o, "name", false); + double skin = -1.0; + ParseNumberProperty(&skin, err, o, "skin", false); + node->skin = static_cast(skin); + // Matrix and T/R/S are exclusive if(!ParseNumberArrayProperty(&node->matrix, err, o, "matrix", false)) { @@ -2031,6 +2050,29 @@ static bool ParseSampler(Sampler *sampler, std::string *err, return true; } +static bool ParseSkin(Skin *skin, std::string *err, + const picojson::object &o) { + + ParseStringProperty(&skin->name, err, o, "name", false); + + std::vector joints; + if (!ParseNumberArrayProperty(&joints, err, o, "joints", false)) { + return false; + } + + double skeleton; + ParseNumberProperty(&skeleton, err, o, "skeleton", false); + skin->skeleton = static_cast(skeleton); + + skin->joints = std::vector(joints.begin(), joints.end()); + + double invBind = -1.0; + ParseNumberProperty(&invBind, err, o, "inverseBindMatrices", true); + skin->inverseBindMatrices = static_cast(invBind); + + return true; +} + bool TinyGLTFLoader::LoadFromString(Model *model, std::string *err, const char *str, unsigned int length, const std::string &base_dir, @@ -2314,8 +2356,8 @@ if (v.contains("scenes") && v.get("scenes").is()) { } // 11. Parse Animation - if (v.contains("animations") && v.get("animations").is()) { - const picojson::object &root = v.get("animations").get(); + if (v.contains("animations") && v.get("animations").is()) { + const picojson::array &root = v.get("animations").get(); picojson::array::const_iterator it(root.begin()); picojson::array::const_iterator itEnd(root.end()); @@ -2330,7 +2372,24 @@ if (v.contains("scenes") && v.get("scenes").is()) { } } - // 12. Parse Sampler + // 12. Parse Skin + if (v.contains("skins") && v.get("skins").is()) { + const picojson::array &root = v.get("skins").get(); + + picojson::array::const_iterator it(root.begin()); + picojson::array::const_iterator itEnd(root.end()); + for (; it != itEnd; ++it) { + Skin skin; + if (!ParseSkin(&skin, err, + it->get())) { + return false; + } + + model->skins.push_back(skin); + } + } + + // 13. Parse Sampler if (v.contains("samplers") && v.get("samplers").is()) { const picojson::array &root = v.get("samplers").get(); From 38a6a7565c66efec107e139e74bda8f4768a7e3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Chatelain?= Date: Wed, 24 May 2017 09:54:55 +0000 Subject: [PATCH 08/10] Supports glTF morph (glTF 2.0, not tested) --- tiny_gltf_loader.h | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/tiny_gltf_loader.h b/tiny_gltf_loader.h index 7c9bd4e..3c00572 100644 --- a/tiny_gltf_loader.h +++ b/tiny_gltf_loader.h @@ -447,6 +447,9 @@ struct Primitive { // when rendering. int indices; // The index of the accessor that contains the indices. int mode; // one of TINYGLTF_MODE_*** + std::vector > targets; // array of morph targets, + //where each target is a dict with attribues in ["POSITION, "NORMAL", "TANGENT"] pointing + // to their corresponding accessors Value extras; Primitive() @@ -459,6 +462,8 @@ struct Primitive { typedef struct { std::string name; std::vector primitives; + std::vector weights; // weights to be applied to the Morph Targets + std::vector >targets; ParameterMap extensions; Value extras; } Mesh; @@ -483,7 +488,7 @@ class Node { std::vector scale; // length must be 0 or 3 std::vector translation; // length must be 0 or 3 std::vector matrix; // length must be 0 or 16 - std::vector meshes; + std::vector weights; // The weights of the instantiated Morph Target Value extras; }; @@ -1766,6 +1771,28 @@ static bool ParseMesh(Mesh *mesh, std::string *err, const picojson::object &o) { } } + // Look for morph targets + picojson::object::const_iterator targetsObject = o.find("targets"); + if ((targetsObject != o.end()) && (targetsObject->second).is()) { + const picojson::array &targetArray = + (targetsObject->second).get(); + for (size_t i = 0; i < targetArray.size(); i++) { + std::map targetAttribues; + + const picojson::object &dict = targetArray[i].get(); + picojson::object::const_iterator dictIt(dict.begin()); + picojson::object::const_iterator dictItEnd(dict.end()); + + for (; dictIt != dictItEnd; ++dictIt) { + targetAttribues[dictIt->first] = static_cast(dictIt->second.get()); + } + mesh->targets.push_back(targetAttribues); + } + } + + // Should probably check if has targets and if dimensions fit + ParseNumberArrayProperty(&mesh->weights, err, o, "weights", false); + ParseExtrasProperty(&(mesh->extras), o); return true; From f612015ac229b3bd0f15f06719b47bd0a92cfec8 Mon Sep 17 00:00:00 2001 From: Syoyo Fujita Date: Sat, 27 May 2017 23:51:23 +0900 Subject: [PATCH 09/10] Keep up with loader_example.cc Update picojson.h --- box.gltf | 267 ------- loader_example.cc | 409 +++------- picojson.h | 1911 +++++++++++++++++++++++--------------------- tiny_gltf_loader.h | 57 +- 4 files changed, 1150 insertions(+), 1494 deletions(-) delete mode 100644 box.gltf diff --git a/box.gltf b/box.gltf deleted file mode 100644 index 30e81fc..0000000 --- a/box.gltf +++ /dev/null @@ -1,267 +0,0 @@ -{ - "accessors": { - "accessor_21": { - "bufferView": "bufferView_29", - "byteOffset": 0, - "byteStride": 0, - "componentType": 5123, - "count": 36, - "type": "SCALAR" - }, - "accessor_23": { - "bufferView": "bufferView_30", - "byteOffset": 0, - "byteStride": 12, - "componentType": 5126, - "count": 24, - "max": [ - 0.5, - 0.5, - 0.5 - ], - "min": [ - -0.5, - -0.5, - -0.5 - ], - "type": "VEC3" - }, - "accessor_25": { - "bufferView": "bufferView_30", - "byteOffset": 288, - "byteStride": 12, - "componentType": 5126, - "count": 24, - "max": [ - 1, - 1, - 1 - ], - "min": [ - -1, - -1, - -1 - ], - "type": "VEC3" - }, - "accessor_27": { - "bufferView": "bufferView_30", - "byteOffset": 576, - "byteStride": 8, - "componentType": 5126, - "count": 24, - "max": [ - 1, - 1 - ], - "min": [ - 0, - 0 - ], - "type": "VEC2" - } - }, - "animations": {}, - "asset": { - "generator": "collada2gltf@ceec062e3d5793f2f249f53cbd843aee382ad40b", - "premultipliedAlpha": true, - "profile": { - "api": "WebGL", - "version": "1.0.2" - }, - "version": 1 - }, - "bufferViews": { - "bufferView_29": { - "buffer": "box", - "byteLength": 72, - "byteOffset": 0, - "target": 34963 - }, - "bufferView_30": { - "buffer": "box", - "byteLength": 768, - "byteOffset": 72, - "target": 34962 - } - }, - "buffers": { - "box": { - "byteLength": 840, - "type": "arraybuffer", - "uri": "data:application/octet-stream;base64,AAABAAIAAwACAAEABAAFAAYABwAGAAUACAAJAAoACwAKAAkADAANAA4ADwAOAA0AEAARABIAEwASABEAFAAVABYAFwAWABUAAAAAvwAAAL8AAAA/AAAAPwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAL8AAAA/AAAAvwAAAL8AAAA/AAAAPwAAAL8AAAC/AAAAvwAAAL8AAAC/AAAAPwAAAD8AAAA/AAAAPwAAAL8AAAA/AAAAPwAAAD8AAAC/AAAAPwAAAL8AAAC/AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAvwAAAD8AAAC/AAAAPwAAAD8AAAC/AAAAvwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAPwAAAL8AAAC/AAAAPwAAAD8AAAC/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AACAPgAAAAAAAIA+oKqqPgAAAD8AAAAAAAAAP6Cqqj4AAIA+oKqqPgAAAACgqqo+AACAPrCqKj8AAAAAsKoqPwAAAD+gqqo+AACAPqCqqj4AAAA/sKoqPwAAgD6wqio/AABAP6Cqqj4AAAA/oKqqPgAAQD+wqio/AAAAP7CqKj8AAIA/oKqqPgAAQD+gqqo+AACAP7CqKj8AAEA/sKoqPwAAgD4AAIA/AAAAPwAAgD8AAIA+sKoqPwAAAD+wqio/" - } - }, - "materials": { - "Effect-Red": { - "name": "Red", - "technique": "technique0", - "values": { - "diffuse": [ - 0.8, - 0, - 0, - 1 - ], - "shininess": 256, - "specular": [ - 0.2, - 0.2, - 0.2, - 1 - ] - } - } - }, - "meshes": { - "Geometry-mesh002": { - "name": "Mesh", - "primitives": [ - { - "attributes": { - "NORMAL": "accessor_25", - "POSITION": "accessor_23", - "TEXCOORD_0": "accessor_27" - }, - "indices": "accessor_21", - "material": "Effect-Red", - "mode": 4 - } - ] - } - }, - "nodes": { - "Geometry-mesh002Node": { - "children": [], - "matrix": [ - 1, - 0, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 0, - 1 - ], - "meshes": [ - "Geometry-mesh002" - ], - "name": "Mesh" - }, - "node_1": { - "children": [ - "Geometry-mesh002Node" - ], - "matrix": [ - 1, - 0, - 0, - 0, - 0, - 0, - -1, - 0, - 0, - 1, - 0, - 0, - 0, - 0, - 0, - 1 - ], - "name": "Y_UP_Transform" - } - }, - "programs": { - "program_0": { - "attributes": [ - "a_normal", - "a_position" - ], - "fragmentShader": "box0FS", - "vertexShader": "box0VS" - } - }, - "scene": "defaultScene", - "scenes": { - "defaultScene": { - "nodes": [ - "node_1" - ] - } - }, - "shaders": { - "box0FS": { - "type": 35632, - "uri": "data:text/plain;base64,cHJlY2lzaW9uIGhpZ2hwIGZsb2F0Owp2YXJ5aW5nIHZlYzMgdl9ub3JtYWw7CnVuaWZvcm0gdmVjNCB1X2RpZmZ1c2U7CnVuaWZvcm0gdmVjNCB1X3NwZWN1bGFyOwp1bmlmb3JtIGZsb2F0IHVfc2hpbmluZXNzOwp2b2lkIG1haW4odm9pZCkgewp2ZWMzIG5vcm1hbCA9IG5vcm1hbGl6ZSh2X25vcm1hbCk7CnZlYzQgY29sb3IgPSB2ZWM0KDAuLCAwLiwgMC4sIDAuKTsKdmVjNCBkaWZmdXNlID0gdmVjNCgwLiwgMC4sIDAuLCAxLik7CnZlYzQgc3BlY3VsYXI7CmRpZmZ1c2UgPSB1X2RpZmZ1c2U7CnNwZWN1bGFyID0gdV9zcGVjdWxhcjsKZGlmZnVzZS54eXogKj0gbWF4KGRvdChub3JtYWwsdmVjMygwLiwwLiwxLikpLCAwLik7CmNvbG9yLnh5eiArPSBkaWZmdXNlLnh5ejsKY29sb3IgPSB2ZWM0KGNvbG9yLnJnYiAqIGRpZmZ1c2UuYSwgZGlmZnVzZS5hKTsKZ2xfRnJhZ0NvbG9yID0gY29sb3I7Cn0K" - }, - "box0VS": { - "type": 35633, - "uri": "data:text/plain;base64,cHJlY2lzaW9uIGhpZ2hwIGZsb2F0OwphdHRyaWJ1dGUgdmVjMyBhX3Bvc2l0aW9uOwphdHRyaWJ1dGUgdmVjMyBhX25vcm1hbDsKdmFyeWluZyB2ZWMzIHZfbm9ybWFsOwp1bmlmb3JtIG1hdDMgdV9ub3JtYWxNYXRyaXg7CnVuaWZvcm0gbWF0NCB1X21vZGVsVmlld01hdHJpeDsKdW5pZm9ybSBtYXQ0IHVfcHJvamVjdGlvbk1hdHJpeDsKdm9pZCBtYWluKHZvaWQpIHsKdmVjNCBwb3MgPSB1X21vZGVsVmlld01hdHJpeCAqIHZlYzQoYV9wb3NpdGlvbiwxLjApOwp2X25vcm1hbCA9IHVfbm9ybWFsTWF0cml4ICogYV9ub3JtYWw7CmdsX1Bvc2l0aW9uID0gdV9wcm9qZWN0aW9uTWF0cml4ICogcG9zOwp9Cg==" - } - }, - "skins": {}, - "techniques": { - "technique0": { - "attributes": { - "a_normal": "normal", - "a_position": "position" - }, - "parameters": { - "diffuse": { - "type": 35666 - }, - "modelViewMatrix": { - "semantic": "MODELVIEW", - "type": 35676 - }, - "normal": { - "semantic": "NORMAL", - "type": 35665 - }, - "normalMatrix": { - "semantic": "MODELVIEWINVERSETRANSPOSE", - "type": 35675 - }, - "position": { - "semantic": "POSITION", - "type": 35665 - }, - "projectionMatrix": { - "semantic": "PROJECTION", - "type": 35676 - }, - "shininess": { - "type": 5126 - }, - "specular": { - "type": 35666 - } - }, - "program": "program_0", - "states": { - "enable": [ - 2929, - 2884 - ] - }, - "uniforms": { - "u_diffuse": "diffuse", - "u_modelViewMatrix": "modelViewMatrix", - "u_normalMatrix": "normalMatrix", - "u_projectionMatrix": "projectionMatrix", - "u_shininess": "shininess", - "u_specular": "specular" - } - } - } -} \ No newline at end of file diff --git a/loader_example.cc b/loader_example.cc index 64e36be..500fdb7 100644 --- a/loader_example.cc +++ b/loader_example.cc @@ -62,15 +62,6 @@ static std::string PrintType(int ty) { return "**UNKNOWN**"; } -static std::string PrintShaderType(int ty) { - if (ty == TINYGLTF_SHADER_TYPE_VERTEX_SHADER) { - return "VERTEX_SHADER"; - } else if (ty == TINYGLTF_SHADER_TYPE_FRAGMENT_SHADER) { - return "FRAGMENT_SHADER"; - } - return "**UNKNOWN**"; -} - static std::string PrintComponentType(int ty) { if (ty == TINYGLTF_COMPONENT_TYPE_BYTE) { return "BYTE"; @@ -93,6 +84,7 @@ static std::string PrintComponentType(int ty) { return "**UNKNOWN**"; } +#if 0 static std::string PrintParameterType(int ty) { if (ty == TINYGLTF_PARAMETER_TYPE_BYTE) { return "BYTE"; @@ -140,6 +132,7 @@ static std::string PrintParameterType(int ty) { return "**UNKNOWN**"; } +#endif static std::string PrintWrapMode(int mode) { if (mode == TINYGLTF_TEXTURE_WRAP_RPEAT) { @@ -170,7 +163,7 @@ static std::string PrintFilterMode(int mode) { return "**UNKNOWN**"; } -static std::string PrintFloatArray(const std::vector &arr) { +static std::string PrintIntArray(const std::vector &arr) { if (arr.size() == 0) { return ""; } @@ -185,7 +178,7 @@ static std::string PrintFloatArray(const std::vector &arr) { return ss.str(); } -static std::string PrintStringArray(const std::vector &arr) { +static std::string PrintFloatArray(const std::vector &arr) { if (arr.size() == 0) { return ""; } @@ -244,6 +237,7 @@ static std::string PrintValue(const std::string& name, const tinygltf::Value &va static void DumpNode(const tinygltf::Node &node, int indent) { std::cout << Indent(indent) << "name : " << node.name << std::endl; std::cout << Indent(indent) << "camera : " << node.camera << std::endl; + std::cout << Indent(indent) << "mesh : " << node.mesh << std::endl; if (!node.rotation.empty()) { std::cout << Indent(indent) << "rotation : " << PrintFloatArray(node.rotation) @@ -265,16 +259,13 @@ static void DumpNode(const tinygltf::Node &node, int indent) { } std::cout << Indent(indent) - << "meshes : " << PrintStringArray(node.meshes) << std::endl; - - std::cout << Indent(indent) - << "children : " << PrintStringArray(node.children) << std::endl; + << "children : " << PrintIntArray(node.children) << std::endl; } -static void DumpStringMap(const std::map &map, +static void DumpStringIntMap(const std::map &m, int indent) { - std::map::const_iterator it(map.begin()); - std::map::const_iterator itEnd(map.end()); + std::map::const_iterator it(m.begin()); + std::map::const_iterator itEnd(m.end()); for (; it != itEnd; it++) { std::cout << Indent(indent) << it->first << ": " << it->second << std::endl; } @@ -289,110 +280,79 @@ static void DumpPrimitive(const tinygltf::Primitive &primitive, int indent) { std::cout << Indent(indent) << "attributes(items=" << primitive.attributes.size() << ")" << std::endl; - DumpStringMap(primitive.attributes, indent + 1); + DumpStringIntMap(primitive.attributes, indent + 1); std::cout << Indent(indent) << "extras :" << std::endl << PrintValue("extras", primitive.extras, indent+1) << std::endl; } -static void DumpTechniqueParameter(const tinygltf::TechniqueParameter ¶m, - int indent) { - std::cout << Indent(indent) << "count : " << param.count << std::endl; - std::cout << Indent(indent) << "node : " << param.node << std::endl; - std::cout << Indent(indent) << "semantic : " << param.semantic << std::endl; - std::cout << Indent(indent) << "type : " << PrintParameterType(param.type) - << std::endl; - std::cout << Indent(indent) - << "value : " << PrintParameterValue(param.value) << std::endl; -} - -static void Dump(const tinygltf::Scene &scene) { +static void Dump(const tinygltf::Model &model) { std::cout << "=== Dump glTF ===" << std::endl; - std::cout << "asset.generator : " << scene.asset.generator + std::cout << "asset.copyright : " << model.asset.copyright << std::endl; - std::cout << "asset.premultipliedAlpha : " << scene.asset.premultipliedAlpha + std::cout << "asset.generator : " << model.asset.generator << std::endl; - std::cout << "asset.version : " << scene.asset.version + std::cout << "asset.version : " << model.asset.version << std::endl; - std::cout << "asset.profile.api : " << scene.asset.profile_api - << std::endl; - std::cout << "asset.profile.version : " << scene.asset.profile_version + std::cout << "asset.minVersion : " << model.asset.minVersion << std::endl; std::cout << std::endl; + std::cout << "=== Dump scene ===" << std::endl; - std::cout << "defaultScene: " << scene.defaultScene << std::endl; + std::cout << "defaultScene: " << model.defaultScene << std::endl; { - std::map >::const_iterator it( - scene.scenes.begin()); - std::map >::const_iterator itEnd( - scene.scenes.end()); - std::cout << "scenes(items=" << scene.scenes.size() << ")" << std::endl; - for (; it != itEnd; it++) { - std::cout << Indent(1) << "name : " << it->first << std::endl; - std::cout << Indent(2) << "nodes : [ "; - for (size_t i = 0; i < it->second.size(); i++) { - std::cout << it->second[i] - << ((i != (it->second.size() - 1)) ? ", " : ""); - } - std::cout << " ] " << std::endl; + std::cout << "scenes(items=" << model.scenes.size() << ")" << std::endl; + for (size_t i = 0; i < model.scenes.size(); i++) { + std::cout << Indent(1) << "scene[" << i << "] name : " << model.scenes[i].name << std::endl; } } { - std::map::const_iterator it( - scene.meshes.begin()); - std::map::const_iterator itEnd( - scene.meshes.end()); - std::cout << "meshes(item=" << scene.meshes.size() << ")" << std::endl; - for (; it != itEnd; it++) { - std::cout << Indent(1) << "name : " << it->second.name << std::endl; + std::cout << "meshes(item=" << model.meshes.size() << ")" << std::endl; + for (size_t i = 0; i < model.meshes.size(); i++) { + std::cout << Indent(1) << "name : " << model.meshes[i].name << std::endl; std::cout << Indent(1) - << "primitives(items=" << it->second.primitives.size() + << "primitives(items=" << model.meshes[i].primitives.size() << "): " << std::endl; - for (size_t i = 0; i < it->second.primitives.size(); i++) { - DumpPrimitive(it->second.primitives[i], 2); + for (size_t k = 0; k < model.meshes[i].primitives.size(); k++) { + DumpPrimitive(model.meshes[i].primitives[k], 2); } } } { - std::map::const_iterator it( - scene.accessors.begin()); - std::map::const_iterator itEnd( - scene.accessors.end()); - std::cout << "accessors(items=" << scene.accessors.size() << ")" - << std::endl; - for (; it != itEnd; it++) { - std::cout << Indent(1) << "name : " << it->first << std::endl; - std::cout << Indent(2) << "bufferView : " << it->second.bufferView + for (size_t i = 0; i < model.accessors.size(); i++) { + const tinygltf::Accessor &accessor = model.accessors[i]; + std::cout << Indent(1) << "name : " << accessor.name << std::endl; + std::cout << Indent(2) << "bufferView : " << accessor.bufferView << std::endl; - std::cout << Indent(2) << "byteOffset : " << it->second.byteOffset + std::cout << Indent(2) << "byteOffset : " << accessor.byteOffset << std::endl; - std::cout << Indent(2) << "byteStride : " << it->second.byteStride + std::cout << Indent(2) << "byteStride : " << accessor.byteStride << std::endl; std::cout << Indent(2) << "componentType: " - << PrintComponentType(it->second.componentType) << "(" - << it->second.componentType << ")" << std::endl; - std::cout << Indent(2) << "count : " << it->second.count + << PrintComponentType(accessor.componentType) << "(" + << accessor.componentType << ")" << std::endl; + std::cout << Indent(2) << "count : " << accessor.count << std::endl; - std::cout << Indent(2) << "type : " << PrintType(it->second.type) + std::cout << Indent(2) << "type : " << PrintType(accessor.type) << std::endl; - if (!it->second.minValues.empty()) { + if (!accessor.minValues.empty()) { std::cout << Indent(2) << "min : ["; - for (size_t i = 0; i < it->second.minValues.size(); i++) { - std::cout << it->second.minValues[i] - << ((i != it->second.minValues.size() - 1) ? ", " : ""); + for (size_t k = 0; k < accessor.minValues.size(); k++) { + std::cout << accessor.minValues[k] + << ((i != accessor.minValues.size() - 1) ? ", " : ""); } std::cout << "]" << std::endl; } - if (!it->second.maxValues.empty()) { + if (!accessor.maxValues.empty()) { std::cout << Indent(2) << "max : ["; - for (size_t i = 0; i < it->second.maxValues.size(); i++) { - std::cout << it->second.maxValues[i] - << ((i != it->second.maxValues.size() - 1) ? ", " : ""); + for (size_t k = 0; k < accessor.maxValues.size(); k++) { + std::cout << accessor.maxValues[k] + << ((i != accessor.maxValues.size() - 1) ? ", " : ""); } std::cout << "]" << std::endl; } @@ -400,113 +360,82 @@ static void Dump(const tinygltf::Scene &scene) { } { - std::map::const_iterator it( - scene.animations.begin()); - std::map::const_iterator itEnd( - scene.animations.end()); - std::cout << "animations(items=" << scene.animations.size() << ")" + std::cout << "animations(items=" << model.animations.size() << ")" << std::endl; - for (; it != itEnd; it++) { - std::cout << Indent(1) << "name : " << it->first << std::endl; + for (size_t i = 0; i < model.animations.size(); i++) { + const tinygltf::Animation &animation = model.animations[i]; + std::cout << Indent(1) << "name : " << animation.name << std::endl; std::cout << Indent(1) << "channels : [ " << std::endl; - for (size_t i = 0; i < it->second.channels.size(); i++) { + for (size_t j = 0; i < animation.channels.size(); i++) { std::cout << Indent(2) - << "sampler : " << it->second.channels[i].sampler + << "sampler : " << animation.channels[j].sampler << std::endl; std::cout << Indent(2) - << "target.id : " << it->second.channels[i].target_id + << "target.id : " << animation.channels[j].target_node << std::endl; std::cout << Indent(2) - << "target.path : " << it->second.channels[i].target_path + << "target.path : " << animation.channels[j].target_path << std::endl; - std::cout << ((i != (it->second.channels.size() - 1)) ? " , " : ""); + std::cout << ((i != (animation.channels.size() - 1)) ? " , " : ""); } std::cout << " ]" << std::endl; - std::map::const_iterator - samplerIt(it->second.samplers.begin()); - std::map::const_iterator - samplerItEnd(it->second.samplers.end()); - std::cout << Indent(1) << "samplers(items=" << it->second.samplers.size() + std::cout << Indent(1) << "samplers(items=" << animation.samplers.size() << ")" << std::endl; - for (; samplerIt != samplerItEnd; samplerIt++) { - std::cout << Indent(1) << "name : " << samplerIt->first - << std::endl; - std::cout << Indent(2) << "input : " << samplerIt->second.input + for (size_t j = 0; j < animation.samplers.size(); j++) { + const tinygltf::AnimationSampler &sampler = animation.samplers[i]; + std::cout << Indent(2) << "input : " << sampler.input << std::endl; std::cout << Indent(2) - << "interpolation : " << samplerIt->second.interpolation + << "interpolation : " << sampler.interpolation << std::endl; - std::cout << Indent(2) << "output : " << samplerIt->second.output + std::cout << Indent(2) << "output : " << sampler.output << std::endl; } - { - std::cout << Indent(1) - << "parameters(items=" << it->second.parameters.size() << ")" - << std::endl; - tinygltf::ParameterMap::const_iterator p(it->second.parameters.begin()); - tinygltf::ParameterMap::const_iterator pEnd( - it->second.parameters.end()); - for (; p != pEnd; p++) { - std::cout << Indent(2) << p->first << ": " - << PrintParameterValue(p->second) << std::endl; - } - } } } { - std::map::const_iterator it( - scene.bufferViews.begin()); - std::map::const_iterator itEnd( - scene.bufferViews.end()); - std::cout << "bufferViews(items=" << scene.bufferViews.size() << ")" + std::cout << "bufferViews(items=" << model.bufferViews.size() << ")" << std::endl; - for (; it != itEnd; it++) { - std::cout << Indent(1) << "name : " << it->first << std::endl; - std::cout << Indent(2) << "buffer : " << it->second.buffer + for (size_t i = 0; i < model.bufferViews.size(); i++) { + const tinygltf::BufferView &bufferView = model.bufferViews[i]; + std::cout << Indent(1) << "name : " << bufferView.name << std::endl; + std::cout << Indent(2) << "buffer : " << bufferView.buffer << std::endl; - std::cout << Indent(2) << "byteLength : " << it->second.byteLength + std::cout << Indent(2) << "byteLength : " << bufferView.byteLength << std::endl; - std::cout << Indent(2) << "byteOffset : " << it->second.byteOffset + std::cout << Indent(2) << "byteOffset : " << bufferView.byteOffset << std::endl; std::cout << Indent(2) - << "target : " << PrintTarget(it->second.target) + << "target : " << PrintTarget(bufferView.target) << std::endl; } } { - std::map::const_iterator it( - scene.buffers.begin()); - std::map::const_iterator itEnd( - scene.buffers.end()); - std::cout << "buffers(items=" << scene.buffers.size() << ")" << std::endl; - for (; it != itEnd; it++) { - std::cout << Indent(1) << "name : " << it->first << std::endl; - std::cout << Indent(2) << "byteLength : " << it->second.data.size() + std::cout << "buffers(items=" << model.buffers.size() << ")" << std::endl; + for (size_t i = 0; i < model.buffers.size(); i++) { + const tinygltf::Buffer &buffer = model.buffers[i]; + std::cout << Indent(1) << "name : " << buffer.name << std::endl; + std::cout << Indent(2) << "byteLength : " << buffer.data.size() << std::endl; } } { - std::map::const_iterator it( - scene.materials.begin()); - std::map::const_iterator itEnd( - scene.materials.end()); - std::cout << "materials(items=" << scene.materials.size() << ")" + std::cout << "materials(items=" << model.materials.size() << ")" << std::endl; - for (; it != itEnd; it++) { - std::cout << Indent(1) << "name : " << it->first << std::endl; - std::cout << Indent(1) << "technique : " << it->second.technique - << std::endl; - std::cout << Indent(1) << "values(items=" << it->second.values.size() + for (size_t i = 0; i < model.materials.size(); i++) { + const tinygltf::Material &material = model.materials[i]; + std::cout << Indent(1) << "name : " << material.name << std::endl; + std::cout << Indent(1) << "values(items=" << material.values.size() << ")" << std::endl; - tinygltf::ParameterMap::const_iterator p(it->second.values.begin()); - tinygltf::ParameterMap::const_iterator pEnd(it->second.values.end()); + tinygltf::ParameterMap::const_iterator p(material.values.begin()); + tinygltf::ParameterMap::const_iterator pEnd(material.values.end()); for (; p != pEnd; p++) { std::cout << Indent(2) << p->first << ": " << PrintParameterValue(p->second) << std::endl; @@ -515,179 +444,57 @@ static void Dump(const tinygltf::Scene &scene) { } { - std::map::const_iterator it( - scene.nodes.begin()); - std::map::const_iterator itEnd( - scene.nodes.end()); - std::cout << "nodes(items=" << scene.nodes.size() << ")" << std::endl; - for (; it != itEnd; it++) { - std::cout << Indent(1) << "name : " << it->first << std::endl; + std::cout << "nodes(items=" << model.nodes.size() << ")" << std::endl; + for (size_t i = 0; i < model.nodes.size(); i++) { + const tinygltf::Node &node = model.nodes[i]; + std::cout << Indent(1) << "name : " << node.name << std::endl; - DumpNode(it->second, 2); + DumpNode(node, 2); } } { - std::map::const_iterator it( - scene.images.begin()); - std::map::const_iterator itEnd( - scene.images.end()); - std::cout << "images(items=" << scene.images.size() << ")" << std::endl; - for (; it != itEnd; it++) { - std::cout << Indent(1) << "name : " << it->first << std::endl; + std::cout << "images(items=" << model.images.size() << ")" << std::endl; + for (size_t i = 0; i < model.images.size(); i++) { + const tinygltf::Image &image = model.images[i]; + std::cout << Indent(1) << "name : " << image.name << std::endl; - std::cout << Indent(2) << "width : " << it->second.width << std::endl; - std::cout << Indent(2) << "height : " << it->second.height + std::cout << Indent(2) << "width : " << image.width << std::endl; + std::cout << Indent(2) << "height : " << image.height << std::endl; - std::cout << Indent(2) << "component : " << it->second.component - << std::endl; - std::cout << Indent(2) << "name : " << it->second.name << std::endl; - } - } - - { - std::map::const_iterator it( - scene.textures.begin()); - std::map::const_iterator itEnd( - scene.textures.end()); - std::cout << "textures(items=" << scene.textures.size() << ")" << std::endl; - for (; it != itEnd; it++) { - std::cout << Indent(1) << "name : " << it->first << std::endl; - std::cout << Indent(1) << "format : " << it->second.format - << std::endl; - std::cout << Indent(1) << "internalFormat : " << it->second.internalFormat - << std::endl; - std::cout << Indent(1) << "sampler : " << it->second.sampler - << std::endl; - std::cout << Indent(1) << "source : " << it->second.source - << std::endl; - std::cout << Indent(1) << "target : " << it->second.target - << std::endl; - std::cout << Indent(1) << "type : " << it->second.type + std::cout << Indent(2) << "component : " << image.component << std::endl; } } { - std::map::const_iterator it( - scene.shaders.begin()); - std::map::const_iterator itEnd( - scene.shaders.end()); - - std::cout << "shaders(items=" << scene.shaders.size() << ")" << std::endl; - for (; it != itEnd; it++) { - std::cout << Indent(1) << "name (id) : " << it->first << std::endl; - std::cout << Indent(2) - << "type : " << PrintShaderType(it->second.type) + std::cout << "textures(items=" << model.textures.size() << ")" << std::endl; + for (size_t i = 0; i < model.textures.size(); i++) { + const tinygltf::Texture &texture = model.textures[i]; + std::cout << Indent(1) << "sampler : " << texture.sampler << std::endl; - - std::cout << Indent(2) << "name (json) : " << it->second.name - << std::endl; - - // Indent shader source nicely. - std::string shader_source(Indent(3)); - shader_source.resize(shader_source.size() + it->second.source.size()); - - std::vector::const_iterator sourceIt( - it->second.source.begin()); - std::vector::const_iterator sourceItEnd( - it->second.source.end()); - - for (; sourceIt != sourceItEnd; ++sourceIt) { - shader_source += static_cast(*sourceIt); - if (*sourceIt == '\n') { - shader_source += Indent(3); - } - } - std::cout << Indent(2) << "source :\n" - << shader_source << std::endl; - } - } - - { - std::map::const_iterator it( - scene.programs.begin()); - std::map::const_iterator itEnd( - scene.programs.end()); - - std::cout << "programs(items=" << scene.programs.size() << ")" << std::endl; - for (; it != itEnd; it++) { - std::cout << Indent(1) << "name : " << it->first << std::endl; - std::cout << Indent(2) << "vertexShader : " << it->second.vertexShader - << std::endl; - std::cout << Indent(2) << "fragmentShader : " << it->second.fragmentShader - << std::endl; - std::cout << Indent(2) << "attributes : " - << PrintStringArray(it->second.attributes) << std::endl; - std::cout << Indent(2) << "name : " << it->second.name + std::cout << Indent(1) << "source : " << texture.source << std::endl; } } { - std::map::const_iterator it( - scene.techniques.begin()); - std::map::const_iterator itEnd( - scene.techniques.end()); - - std::cout << "techniques(items=" << scene.techniques.size() << ")" - << std::endl; - - for (; it != itEnd; it++) { - std::cout << Indent(1) << "name (id) : " << it->first << std::endl; - std::cout << Indent(2) << "program : " << it->second.program - << std::endl; - - std::cout << Indent(2) << "name (json) : " << it->second.name - << std::endl; + std::cout << "samplers(items=" << model.samplers.size() << ")" << std::endl; + for (size_t i = 0; i < model.samplers.size(); i++) { + const tinygltf::Sampler &sampler = model.samplers[i]; + std::cout << Indent(1) << "name (id) : " << sampler.name << std::endl; std::cout << Indent(2) - << "parameters(items=" << it->second.parameters.size() << ")" - << std::endl; - - std::map::const_iterator - paramIt(it->second.parameters.begin()); - std::map::const_iterator - paramItEnd(it->second.parameters.end()); - - for (; paramIt != paramItEnd; ++paramIt) { - std::cout << Indent(3) << "name : " << paramIt->first << std::endl; - DumpTechniqueParameter(paramIt->second, 4); - } - - std::cout << Indent(2) - << "attributes(items=" << it->second.attributes.size() << ")" - << std::endl; - - DumpStringMap(it->second.attributes, 3); - - std::cout << Indent(2) << "uniforms(items=" << it->second.uniforms.size() - << ")" << std::endl; - DumpStringMap(it->second.uniforms, 3); - } - } - - { - std::map::const_iterator it( - scene.samplers.begin()); - std::map::const_iterator itEnd( - scene.samplers.end()); - - std::cout << "samplers(items=" << scene.samplers.size() << ")" << std::endl; - - for (; it != itEnd; it++) { - std::cout << Indent(1) << "name (id) : " << it->first << std::endl; - std::cout << Indent(2) - << "minFilter : " << PrintFilterMode(it->second.minFilter) + << "minFilter : " << PrintFilterMode(sampler.minFilter) << std::endl; std::cout << Indent(2) - << "magFilter : " << PrintFilterMode(it->second.magFilter) + << "magFilter : " << PrintFilterMode(sampler.magFilter) << std::endl; std::cout << Indent(2) - << "wrapS : " << PrintWrapMode(it->second.wrapS) + << "wrapS : " << PrintWrapMode(sampler.wrapS) << std::endl; std::cout << Indent(2) - << "wrapT : " << PrintWrapMode(it->second.wrapT) + << "wrapT : " << PrintWrapMode(sampler.wrapT) << std::endl; } } @@ -699,7 +506,7 @@ int main(int argc, char **argv) { exit(1); } - tinygltf::Scene scene; + tinygltf::Model model; tinygltf::TinyGLTFLoader loader; std::string err; std::string input_filename(argv[1]); @@ -708,10 +515,10 @@ int main(int argc, char **argv) { bool ret = false; if (ext.compare("glb") == 0) { // assume binary glTF. - ret = loader.LoadBinaryFromFile(&scene, &err, input_filename.c_str()); + ret = loader.LoadBinaryFromFile(&model, &err, input_filename.c_str()); } else { // assume ascii glTF. - ret = loader.LoadASCIIFromFile(&scene, &err, input_filename.c_str()); + ret = loader.LoadASCIIFromFile(&model, &err, input_filename.c_str()); } if (!err.empty()) { @@ -723,7 +530,7 @@ int main(int argc, char **argv) { return -1; } - Dump(scene); + Dump(model); return 0; } diff --git a/picojson.h b/picojson.h index 045dc53..f75c399 100644 --- a/picojson.h +++ b/picojson.h @@ -40,1000 +40,1121 @@ #include #include #include +#include // for isnan/isinf -#if __cplusplus>=201103L -# include +#if __cplusplus >= 201103L +#include #else extern "C" { -# ifdef _MSC_VER -# include -# elif defined(__INTEL_COMPILER) -# include -# else -# include -# endif +#ifdef _MSC_VER +#include +#elif defined(__INTEL_COMPILER) +#include +#else +#include +#endif } #endif #ifndef PICOJSON_USE_RVALUE_REFERENCE -# if (defined(__cpp_rvalue_references) && __cpp_rvalue_references >= 200610) || (defined(_MSC_VER) && _MSC_VER >= 1600) -# define PICOJSON_USE_RVALUE_REFERENCE 1 -# else -# define PICOJSON_USE_RVALUE_REFERENCE 0 -# endif -#endif//PICOJSON_USE_RVALUE_REFERENCE - +#if (defined(__cpp_rvalue_references) && __cpp_rvalue_references >= 200610) || (defined(_MSC_VER) && _MSC_VER >= 1600) +#define PICOJSON_USE_RVALUE_REFERENCE 1 +#else +#define PICOJSON_USE_RVALUE_REFERENCE 0 +#endif +#endif // PICOJSON_USE_RVALUE_REFERENCE // experimental support for int64_t (see README.mkdn for detail) #ifdef PICOJSON_USE_INT64 -# define __STDC_FORMAT_MACROS -# include -# include +#define __STDC_FORMAT_MACROS +#include +#include #endif // to disable the use of localeconv(3), set PICOJSON_USE_LOCALE to 0 #ifndef PICOJSON_USE_LOCALE -# define PICOJSON_USE_LOCALE 1 +#define PICOJSON_USE_LOCALE 1 #endif #if PICOJSON_USE_LOCALE extern "C" { -# include +#include } #endif #ifndef PICOJSON_ASSERT -# define PICOJSON_ASSERT(e) do { if (! (e)) throw std::runtime_error(#e); } while (0) +#define PICOJSON_ASSERT(e) \ + do { \ + if (!(e)) \ + throw std::runtime_error(#e); \ + } while (0) #endif #ifdef _MSC_VER - #define SNPRINTF _snprintf_s - #pragma warning(push) - #pragma warning(disable : 4244) // conversion from int to char - #pragma warning(disable : 4127) // conditional expression is constant - #pragma warning(disable : 4702) // unreachable code +#define SNPRINTF _snprintf_s +#pragma warning(push) +#pragma warning(disable : 4244) // conversion from int to char +#pragma warning(disable : 4127) // conditional expression is constant +#pragma warning(disable : 4702) // unreachable code #else - #define SNPRINTF snprintf +#define SNPRINTF snprintf #endif namespace picojson { - - enum { - null_type, - boolean_type, - number_type, - string_type, - array_type, - object_type + +enum { + null_type, + boolean_type, + number_type, + string_type, + array_type, + object_type #ifdef PICOJSON_USE_INT64 - , int64_type + , + int64_type #endif - }; - - enum { - INDENT_WIDTH = 2 +}; + +enum { INDENT_WIDTH = 2 }; + +struct null {}; + +class value { +public: + typedef std::vector array; + typedef std::map object; + union _storage { + bool boolean_; + double number_; +#ifdef PICOJSON_USE_INT64 + int64_t int64_; +#endif + std::string *string_; + array *array_; + object *object_; }; - struct null {}; - - class value { - public: - typedef std::vector array; - typedef std::map object; - union _storage { - bool boolean_; - double number_; -#ifdef PICOJSON_USE_INT64 - int64_t int64_; -#endif - std::string* string_; - array* array_; - object* object_; - }; - protected: - int type_; - _storage u_; - public: - value(); - value(int type, bool); - explicit value(bool b); -#ifdef PICOJSON_USE_INT64 - explicit value(int64_t i); -#endif - explicit value(double n); - explicit value(const std::string& s); - explicit value(const array& a); - explicit value(const object& o); - explicit value(const char* s); - value(const char* s, size_t len); - ~value(); - value(const value& x); - value& operator=(const value& x); -#if PICOJSON_USE_RVALUE_REFERENCE - value(value&& x)throw(); - value& operator=(value&& x)throw(); -#endif - void swap(value& x)throw(); - template bool is() const; - template const T& get() const; - template T& get(); - bool evaluate_as_boolean() const; - const value& get(size_t idx) const; - const value& get(const std::string& key) const; - value& get(size_t idx); - value& get(const std::string& key); +protected: + int type_; + _storage u_; - bool contains(size_t idx) const; - bool contains(const std::string& key) const; - std::string to_str() const; - template void serialize(Iter os, bool prettify = false) const; - std::string serialize(bool prettify = false) const; - private: - template value(const T*); // intentionally defined to block implicit conversion of pointer to bool - template static void _indent(Iter os, int indent); - template void _serialize(Iter os, int indent) const; - std::string _serialize(int indent) const; - }; - - typedef value::array array; - typedef value::object object; - - inline value::value() : type_(null_type) {} - - inline value::value(int type, bool) : type_(type) { - switch (type) { -#define INIT(p, v) case p##type: u_.p = v; break - INIT(boolean_, false); - INIT(number_, 0.0); +public: + value(); + value(int type, bool); + explicit value(bool b); #ifdef PICOJSON_USE_INT64 - INIT(int64_, 0); + explicit value(int64_t i); #endif - INIT(string_, new std::string()); - INIT(array_, new array()); - INIT(object_, new object()); + explicit value(double n); + explicit value(const std::string &s); + explicit value(const array &a); + explicit value(const object &o); +#if PICOJSON_USE_RVALUE_REFERENCE + explicit value(std::string &&s); + explicit value(array &&a); + explicit value(object &&o); +#endif + explicit value(const char *s); + value(const char *s, size_t len); + ~value(); + value(const value &x); + value &operator=(const value &x); +#if PICOJSON_USE_RVALUE_REFERENCE + value(value &&x) throw(); + value &operator=(value &&x) throw(); +#endif + void swap(value &x) throw(); + template bool is() const; + template const T &get() const; + template T &get(); + template void set(const T &); +#if PICOJSON_USE_RVALUE_REFERENCE + template void set(T &&); +#endif + bool evaluate_as_boolean() const; + const value &get(const size_t idx) const; + const value &get(const std::string &key) const; + value &get(const size_t idx); + value &get(const std::string &key); + + bool contains(const size_t idx) const; + bool contains(const std::string &key) const; + std::string to_str() const; + template void serialize(Iter os, bool prettify = false) const; + std::string serialize(bool prettify = false) const; + +private: + template value(const T *); // intentionally defined to block implicit conversion of pointer to bool + template static void _indent(Iter os, int indent); + template void _serialize(Iter os, int indent) const; + std::string _serialize(int indent) const; + void clear(); +}; + +typedef value::array array; +typedef value::object object; + +inline value::value() : type_(null_type), u_() { +} + +inline value::value(int type, bool) : type_(type), u_() { + switch (type) { +#define INIT(p, v) \ + case p##type: \ + u_.p = v; \ + break + INIT(boolean_, false); + INIT(number_, 0.0); +#ifdef PICOJSON_USE_INT64 + INIT(int64_, 0); +#endif + INIT(string_, new std::string()); + INIT(array_, new array()); + INIT(object_, new object()); #undef INIT - default: break; - } - } - - inline value::value(bool b) : type_(boolean_type) { - u_.boolean_ = b; + default: + break; } +} + +inline value::value(bool b) : type_(boolean_type), u_() { + u_.boolean_ = b; +} #ifdef PICOJSON_USE_INT64 - inline value::value(int64_t i) : type_(int64_type) { - u_.int64_ = i; - } +inline value::value(int64_t i) : type_(int64_type), u_() { + u_.int64_ = i; +} #endif - inline value::value(double n) : type_(number_type) { - if ( +inline value::value(double n) : type_(number_type), u_() { + if ( #ifdef _MSC_VER - ! _finite(n) -#elif __cplusplus>=201103L || !(defined(isnan) && defined(isinf)) - std::isnan(n) || std::isinf(n) + !_finite(n) +#elif __cplusplus >= 201103L || !(defined(isnan) && defined(isinf)) + std::isnan(n) || std::isinf(n) #else - isnan(n) || isinf(n) + isnan(n) || isinf(n) #endif - ) { - throw std::overflow_error(""); - } - u_.number_ = n; - } - - inline value::value(const std::string& s) : type_(string_type) { - u_.string_ = new std::string(s); - } - - inline value::value(const array& a) : type_(array_type) { - u_.array_ = new array(a); - } - - inline value::value(const object& o) : type_(object_type) { - u_.object_ = new object(o); - } - - inline value::value(const char* s) : type_(string_type) { - u_.string_ = new std::string(s); - } - - inline value::value(const char* s, size_t len) : type_(string_type) { - u_.string_ = new std::string(s, len); - } - - inline value::~value() { - switch (type_) { -#define DEINIT(p) case p##type: delete u_.p; break - DEINIT(string_); - DEINIT(array_); - DEINIT(object_); -#undef DEINIT - default: break; - } - } - - inline value::value(const value& x) : type_(x.type_) { - switch (type_) { -#define INIT(p, v) case p##type: u_.p = v; break - INIT(string_, new std::string(*x.u_.string_)); - INIT(array_, new array(*x.u_.array_)); - INIT(object_, new object(*x.u_.object_)); -#undef INIT - default: - u_ = x.u_; - break; - } - } - - inline value& value::operator=(const value& x) { - if (this != &x) { - value t(x); - swap(t); - } - return *this; + ) { + throw std::overflow_error(""); } + u_.number_ = n; +} -#if PICOJSON_USE_RVALUE_REFERENCE - inline value::value(value&& x)throw() : type_(null_type) { - swap(x); - } - inline value& value::operator=(value&& x)throw() { - swap(x); - return *this; - } +inline value::value(const std::string &s) : type_(string_type), u_() { + u_.string_ = new std::string(s); +} + +inline value::value(const array &a) : type_(array_type), u_() { + u_.array_ = new array(a); +} + +inline value::value(const object &o) : type_(object_type), u_() { + u_.object_ = new object(o); +} + +#if PICOJSON_USE_RVALUE_REFERENCE +inline value::value(std::string &&s) : type_(string_type), u_() { + u_.string_ = new std::string(std::move(s)); +} + +inline value::value(array &&a) : type_(array_type), u_() { + u_.array_ = new array(std::move(a)); +} + +inline value::value(object &&o) : type_(object_type), u_() { + u_.object_ = new object(std::move(o)); +} #endif - inline void value::swap(value& x)throw() { - std::swap(type_, x.type_); - std::swap(u_, x.u_); + +inline value::value(const char *s) : type_(string_type), u_() { + u_.string_ = new std::string(s); +} + +inline value::value(const char *s, size_t len) : type_(string_type), u_() { + u_.string_ = new std::string(s, len); +} + +inline void value::clear() { + switch (type_) { +#define DEINIT(p) \ + case p##type: \ + delete u_.p; \ + break + DEINIT(string_); + DEINIT(array_); + DEINIT(object_); +#undef DEINIT + default: + break; } - -#define IS(ctype, jtype) \ - template <> inline bool value::is() const { \ - return type_ == jtype##_type; \ +} + +inline value::~value() { + clear(); +} + +inline value::value(const value &x) : type_(x.type_), u_() { + switch (type_) { +#define INIT(p, v) \ + case p##type: \ + u_.p = v; \ + break + INIT(string_, new std::string(*x.u_.string_)); + INIT(array_, new array(*x.u_.array_)); + INIT(object_, new object(*x.u_.object_)); +#undef INIT + default: + u_ = x.u_; + break; } - IS(null, null) - IS(bool, boolean) +} + +inline value &value::operator=(const value &x) { + if (this != &x) { + value t(x); + swap(t); + } + return *this; +} + +#if PICOJSON_USE_RVALUE_REFERENCE +inline value::value(value &&x) throw() : type_(null_type), u_() { + swap(x); +} +inline value &value::operator=(value &&x) throw() { + swap(x); + return *this; +} +#endif +inline void value::swap(value &x) throw() { + std::swap(type_, x.type_); + std::swap(u_, x.u_); +} + +#define IS(ctype, jtype) \ + template <> inline bool value::is() const { \ + return type_ == jtype##_type; \ + } +IS(null, null) +IS(bool, boolean) #ifdef PICOJSON_USE_INT64 - IS(int64_t, int64) +IS(int64_t, int64) #endif - IS(std::string, string) - IS(array, array) - IS(object, object) +IS(std::string, string) +IS(array, array) +IS(object, object) #undef IS - template <> inline bool value::is() const { - return type_ == number_type +template <> inline bool value::is() const { + return type_ == number_type #ifdef PICOJSON_USE_INT64 - || type_ == int64_type + || type_ == int64_type #endif ; +} + +#define GET(ctype, var) \ + template <> inline const ctype &value::get() const { \ + PICOJSON_ASSERT("type mismatch! call is() before get()" && is()); \ + return var; \ + } \ + template <> inline ctype &value::get() { \ + PICOJSON_ASSERT("type mismatch! call is() before get()" && is()); \ + return var; \ } - -#define GET(ctype, var) \ - template <> inline const ctype& value::get() const { \ - PICOJSON_ASSERT("type mismatch! call is() before get()" \ - && is()); \ - return var; \ - } \ - template <> inline ctype& value::get() { \ - PICOJSON_ASSERT("type mismatch! call is() before get()" \ - && is()); \ - return var; \ - } - GET(bool, u_.boolean_) - GET(std::string, *u_.string_) - GET(array, *u_.array_) - GET(object, *u_.object_) +GET(bool, u_.boolean_) +GET(std::string, *u_.string_) +GET(array, *u_.array_) +GET(object, *u_.object_) #ifdef PICOJSON_USE_INT64 - GET(double, (type_ == int64_type && (const_cast(this)->type_ = number_type, const_cast(this)->u_.number_ = u_.int64_), u_.number_)) - GET(int64_t, u_.int64_) +GET(double, + (type_ == int64_type && (const_cast(this)->type_ = number_type, const_cast(this)->u_.number_ = u_.int64_), + u_.number_)) +GET(int64_t, u_.int64_) #else - GET(double, u_.number_) +GET(double, u_.number_) #endif #undef GET - - inline bool value::evaluate_as_boolean() const { - switch (type_) { - case null_type: - return false; - case boolean_type: - return u_.boolean_; - case number_type: - return u_.number_ != 0; + +#define SET(ctype, jtype, setter) \ + template <> inline void value::set(const ctype &_val) { \ + clear(); \ + type_ = jtype##_type; \ + setter \ + } +SET(bool, boolean, u_.boolean_ = _val;) +SET(std::string, string, u_.string_ = new std::string(_val);) +SET(array, array, u_.array_ = new array(_val);) +SET(object, object, u_.object_ = new object(_val);) +SET(double, number, u_.number_ = _val;) #ifdef PICOJSON_USE_INT64 - case int64_type: - return u_.int64_ != 0; +SET(int64_t, int64, u_.int64_ = _val;) #endif - case string_type: - return ! u_.string_->empty(); - default: - return true; - } - } - - inline const value& value::get(size_t idx) const { - static value s_null; - PICOJSON_ASSERT(is()); - return idx < u_.array_->size() ? (*u_.array_)[idx] : s_null; - } +#undef SET - inline value& value::get(size_t idx) { - static value s_null; - PICOJSON_ASSERT(is()); - return idx < u_.array_->size() ? (*u_.array_)[idx] : s_null; +#if PICOJSON_USE_RVALUE_REFERENCE +#define MOVESET(ctype, jtype, setter) \ + template <> inline void value::set(ctype && _val) { \ + clear(); \ + type_ = jtype##_type; \ + setter \ } +MOVESET(std::string, string, u_.string_ = new std::string(std::move(_val));) +MOVESET(array, array, u_.array_ = new array(std::move(_val));) +MOVESET(object, object, u_.object_ = new object(std::move(_val));) +#undef MOVESET +#endif - inline const value& value::get(const std::string& key) const { - static value s_null; - PICOJSON_ASSERT(is()); - object::const_iterator i = u_.object_->find(key); - return i != u_.object_->end() ? i->second : s_null; - } - - inline value& value::get(const std::string& key) { - static value s_null; - PICOJSON_ASSERT(is()); - object::iterator i = u_.object_->find(key); - return i != u_.object_->end() ? i->second : s_null; - } - - inline bool value::contains(size_t idx) const { - PICOJSON_ASSERT(is()); - return idx < u_.array_->size(); - } - - inline bool value::contains(const std::string& key) const { - PICOJSON_ASSERT(is()); - object::const_iterator i = u_.object_->find(key); - return i != u_.object_->end(); - } - - inline std::string value::to_str() const { - switch (type_) { - case null_type: return "null"; - case boolean_type: return u_.boolean_ ? "true" : "false"; +inline bool value::evaluate_as_boolean() const { + switch (type_) { + case null_type: + return false; + case boolean_type: + return u_.boolean_; + case number_type: + return u_.number_ != 0; #ifdef PICOJSON_USE_INT64 - case int64_type: { - char buf[sizeof("-9223372036854775808")]; - SNPRINTF(buf, sizeof(buf), "%" PRId64, u_.int64_); - return buf; - } + case int64_type: + return u_.int64_ != 0; #endif - case number_type: { - char buf[256]; - double tmp; - SNPRINTF(buf, sizeof(buf), fabs(u_.number_) < (1ULL << 53) && modf(u_.number_, &tmp) == 0 ? "%.f" : "%.17g", u_.number_); -#if PICOJSON_USE_LOCALE - char *decimal_point = localeconv()->decimal_point; - if (strcmp(decimal_point, ".") != 0) { - size_t decimal_point_len = strlen(decimal_point); - for (char *p = buf; *p != '\0'; ++p) { - if (strncmp(p, decimal_point, decimal_point_len) == 0) { - return std::string(buf, p) + "." + (p + decimal_point_len); - } - } - } -#endif - return buf; - } - case string_type: return *u_.string_; - case array_type: return "array"; - case object_type: return "object"; - default: PICOJSON_ASSERT(0); -#ifdef _MSC_VER - __assume(0); -#endif - } - return std::string(); - } - - template void copy(const std::string& s, Iter oi) { - std::copy(s.begin(), s.end(), oi); - } - - template void serialize_str(const std::string& s, Iter oi) { - *oi++ = '"'; - for (std::string::const_iterator i = s.begin(); i != s.end(); ++i) { - switch (*i) { -#define MAP(val, sym) case val: copy(sym, oi); break - MAP('"', "\\\""); - MAP('\\', "\\\\"); - MAP('/', "\\/"); - MAP('\b', "\\b"); - MAP('\f', "\\f"); - MAP('\n', "\\n"); - MAP('\r', "\\r"); - MAP('\t', "\\t"); -#undef MAP - default: - if (static_cast(*i) < 0x20 || *i == 0x7f) { - char buf[7]; - SNPRINTF(buf, sizeof(buf), "\\u%04x", *i & 0xff); - copy(buf, buf + 6, oi); - } else { - *oi++ = *i; - } - break; - } - } - *oi++ = '"'; - } - - template void value::serialize(Iter oi, bool prettify) const { - return _serialize(oi, prettify ? 0 : -1); - } - - inline std::string value::serialize(bool prettify) const { - return _serialize(prettify ? 0 : -1); - } - - template void value::_indent(Iter oi, int indent) { - *oi++ = '\n'; - for (int i = 0; i < indent * INDENT_WIDTH; ++i) { - *oi++ = ' '; - } - } - - template void value::_serialize(Iter oi, int indent) const { - switch (type_) { - case string_type: - serialize_str(*u_.string_, oi); - break; - case array_type: { - *oi++ = '['; - if (indent != -1) { - ++indent; - } - for (array::const_iterator i = u_.array_->begin(); - i != u_.array_->end(); - ++i) { - if (i != u_.array_->begin()) { - *oi++ = ','; - } - if (indent != -1) { - _indent(oi, indent); - } - i->_serialize(oi, indent); - } - if (indent != -1) { - --indent; - if (! u_.array_->empty()) { - _indent(oi, indent); - } - } - *oi++ = ']'; - break; - } - case object_type: { - *oi++ = '{'; - if (indent != -1) { - ++indent; - } - for (object::const_iterator i = u_.object_->begin(); - i != u_.object_->end(); - ++i) { - if (i != u_.object_->begin()) { - *oi++ = ','; - } - if (indent != -1) { - _indent(oi, indent); - } - serialize_str(i->first, oi); - *oi++ = ':'; - if (indent != -1) { - *oi++ = ' '; - } - i->second._serialize(oi, indent); - } - if (indent != -1) { - --indent; - if (! u_.object_->empty()) { - _indent(oi, indent); - } - } - *oi++ = '}'; - break; - } - default: - copy(to_str(), oi); - break; - } - if (indent == 0) { - *oi++ = '\n'; - } - } - - inline std::string value::_serialize(int indent) const { - std::string s; - _serialize(std::back_inserter(s), indent); - return s; - } - - template class input { - protected: - Iter cur_, end_; - int last_ch_; - bool ungot_; - int line_; - public: - input(const Iter& first, const Iter& last) : cur_(first), end_(last), last_ch_(-1), ungot_(false), line_(1) {} - int getc() { - if (ungot_) { - ungot_ = false; - return last_ch_; - } - if (cur_ == end_) { - last_ch_ = -1; - return -1; - } - if (last_ch_ == '\n') { - line_++; - } - last_ch_ = *cur_ & 0xff; - ++cur_; - return last_ch_; - } - void ungetc() { - if (last_ch_ != -1) { - PICOJSON_ASSERT(! ungot_); - ungot_ = true; - } - } - Iter cur() const { return cur_; } - int line() const { return line_; } - void skip_ws() { - while (1) { - int ch = getc(); - if (! (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')) { - ungetc(); - break; - } - } - } - bool expect(int expect) { - skip_ws(); - if (getc() != expect) { - ungetc(); - return false; - } - return true; - } - bool match(const std::string& pattern) { - for (std::string::const_iterator pi(pattern.begin()); - pi != pattern.end(); - ++pi) { - if (getc() != *pi) { - ungetc(); - return false; - } - } - return true; - } - }; - - template inline int _parse_quadhex(input &in) { - int uni_ch = 0, hex; - for (int i = 0; i < 4; i++) { - if ((hex = in.getc()) == -1) { - return -1; - } - if ('0' <= hex && hex <= '9') { - hex -= '0'; - } else if ('A' <= hex && hex <= 'F') { - hex -= 'A' - 0xa; - } else if ('a' <= hex && hex <= 'f') { - hex -= 'a' - 0xa; - } else { - in.ungetc(); - return -1; - } - uni_ch = uni_ch * 16 + hex; - } - return uni_ch; - } - - template inline bool _parse_codepoint(String& out, input& in) { - int uni_ch; - if ((uni_ch = _parse_quadhex(in)) == -1) { - return false; - } - if (0xd800 <= uni_ch && uni_ch <= 0xdfff) { - if (0xdc00 <= uni_ch) { - // a second 16-bit of a surrogate pair appeared - return false; - } - // first 16-bit of surrogate pair, get the next one - if (in.getc() != '\\' || in.getc() != 'u') { - in.ungetc(); - return false; - } - int second = _parse_quadhex(in); - if (! (0xdc00 <= second && second <= 0xdfff)) { - return false; - } - uni_ch = ((uni_ch - 0xd800) << 10) | ((second - 0xdc00) & 0x3ff); - uni_ch += 0x10000; - } - if (uni_ch < 0x80) { - out.push_back(uni_ch); - } else { - if (uni_ch < 0x800) { - out.push_back(0xc0 | (uni_ch >> 6)); - } else { - if (uni_ch < 0x10000) { - out.push_back(0xe0 | (uni_ch >> 12)); - } else { - out.push_back(0xf0 | (uni_ch >> 18)); - out.push_back(0x80 | ((uni_ch >> 12) & 0x3f)); - } - out.push_back(0x80 | ((uni_ch >> 6) & 0x3f)); - } - out.push_back(0x80 | (uni_ch & 0x3f)); - } + case string_type: + return !u_.string_->empty(); + default: return true; } - - template inline bool _parse_string(String& out, input& in) { - while (1) { - int ch = in.getc(); - if (ch < ' ') { - in.ungetc(); - return false; - } else if (ch == '"') { - return true; - } else if (ch == '\\') { - if ((ch = in.getc()) == -1) { - return false; - } - switch (ch) { -#define MAP(sym, val) case sym: out.push_back(val); break - MAP('"', '\"'); - MAP('\\', '\\'); - MAP('/', '/'); - MAP('b', '\b'); - MAP('f', '\f'); - MAP('n', '\n'); - MAP('r', '\r'); - MAP('t', '\t'); -#undef MAP - case 'u': - if (! _parse_codepoint(out, in)) { - return false; - } - break; - default: - return false; - } - } else { - out.push_back(ch); - } - } - return false; +} + +inline const value &value::get(const size_t idx) const { + static value s_null; + PICOJSON_ASSERT(is()); + return idx < u_.array_->size() ? (*u_.array_)[idx] : s_null; +} + +inline value &value::get(const size_t idx) { + static value s_null; + PICOJSON_ASSERT(is()); + return idx < u_.array_->size() ? (*u_.array_)[idx] : s_null; +} + +inline const value &value::get(const std::string &key) const { + static value s_null; + PICOJSON_ASSERT(is()); + object::const_iterator i = u_.object_->find(key); + return i != u_.object_->end() ? i->second : s_null; +} + +inline value &value::get(const std::string &key) { + static value s_null; + PICOJSON_ASSERT(is()); + object::iterator i = u_.object_->find(key); + return i != u_.object_->end() ? i->second : s_null; +} + +inline bool value::contains(const size_t idx) const { + PICOJSON_ASSERT(is()); + return idx < u_.array_->size(); +} + +inline bool value::contains(const std::string &key) const { + PICOJSON_ASSERT(is()); + object::const_iterator i = u_.object_->find(key); + return i != u_.object_->end(); +} + +inline std::string value::to_str() const { + switch (type_) { + case null_type: + return "null"; + case boolean_type: + return u_.boolean_ ? "true" : "false"; +#ifdef PICOJSON_USE_INT64 + case int64_type: { + char buf[sizeof("-9223372036854775808")]; + SNPRINTF(buf, sizeof(buf), "%" PRId64, u_.int64_); + return buf; } - - template inline bool _parse_array(Context& ctx, input& in) { - if (! ctx.parse_array_start()) { - return false; - } - size_t idx = 0; - if (in.expect(']')) { - return ctx.parse_array_stop(idx); - } - do { - if (! ctx.parse_array_item(in, idx)) { - return false; - } - idx++; - } while (in.expect(',')); - return in.expect(']') && ctx.parse_array_stop(idx); - } - - template inline bool _parse_object(Context& ctx, input& in) { - if (! ctx.parse_object_start()) { - return false; - } - if (in.expect('}')) { - return true; - } - do { - std::string key; - if (! in.expect('"') - || ! _parse_string(key, in) - || ! in.expect(':')) { - return false; - } - if (! ctx.parse_object_item(in, key)) { - return false; - } - } while (in.expect(',')); - return in.expect('}'); - } - - template inline std::string _parse_number(input& in) { - std::string num_str; - while (1) { - int ch = in.getc(); - if (('0' <= ch && ch <= '9') || ch == '+' || ch == '-' - || ch == 'e' || ch == 'E') { - num_str.push_back(ch); - } else if (ch == '.') { +#endif + case number_type: { + char buf[256]; + double tmp; + SNPRINTF(buf, sizeof(buf), fabs(u_.number_) < (1ULL << 53) && modf(u_.number_, &tmp) == 0 ? "%.f" : "%.17g", u_.number_); #if PICOJSON_USE_LOCALE - num_str += localeconv()->decimal_point; -#else - num_str.push_back('.'); -#endif - } else { - in.ungetc(); - break; - } - } - return num_str; - } - - template inline bool _parse(Context& ctx, input& in) { - in.skip_ws(); - int ch = in.getc(); - switch (ch) { -#define IS(ch, text, op) case ch: \ - if (in.match(text) && op) { \ - return true; \ - } else { \ - return false; \ - } - IS('n', "ull", ctx.set_null()); - IS('f', "alse", ctx.set_bool(false)); - IS('t', "rue", ctx.set_bool(true)); -#undef IS - case '"': - return ctx.parse_string(in); - case '[': - return _parse_array(ctx, in); - case '{': - return _parse_object(ctx, in); - default: - if (('0' <= ch && ch <= '9') || ch == '-') { - double f; - char *endp; - in.ungetc(); - std::string num_str = _parse_number(in); - if (num_str.empty()) { - return false; + char *decimal_point = localeconv()->decimal_point; + if (strcmp(decimal_point, ".") != 0) { + size_t decimal_point_len = strlen(decimal_point); + for (char *p = buf; *p != '\0'; ++p) { + if (strncmp(p, decimal_point, decimal_point_len) == 0) { + return std::string(buf, p) + "." + (p + decimal_point_len); } -#ifdef PICOJSON_USE_INT64 - { - errno = 0; - intmax_t ival = strtoimax(num_str.c_str(), &endp, 10); - if (errno == 0 - && std::numeric_limits::min() <= ival - && ival <= std::numeric_limits::max() - && endp == num_str.c_str() + num_str.size()) { - ctx.set_int64(ival); - return true; - } - } -#endif - f = strtod(num_str.c_str(), &endp); - if (endp == num_str.c_str() + num_str.size()) { - ctx.set_number(f); - return true; - } - return false; - } - break; - } - in.ungetc(); - return false; - } - - class deny_parse_context { - public: - bool set_null() { return false; } - bool set_bool(bool) { return false; } -#ifdef PICOJSON_USE_INT64 - bool set_int64(int64_t) { return false; } -#endif - bool set_number(double) { return false; } - template bool parse_string(input&) { return false; } - bool parse_array_start() { return false; } - template bool parse_array_item(input&, size_t) { - return false; - } - bool parse_array_stop(size_t) { return false; } - bool parse_object_start() { return false; } - template bool parse_object_item(input&, const std::string&) { - return false; - } - }; - - class default_parse_context { - protected: - value* out_; - public: - default_parse_context(value* out) : out_(out) {} - bool set_null() { - *out_ = value(); - return true; - } - bool set_bool(bool b) { - *out_ = value(b); - return true; - } -#ifdef PICOJSON_USE_INT64 - bool set_int64(int64_t i) { - *out_ = value(i); - return true; - } -#endif - bool set_number(double f) { - *out_ = value(f); - return true; - } - template bool parse_string(input& in) { - *out_ = value(string_type, false); - return _parse_string(out_->get(), in); - } - bool parse_array_start() { - *out_ = value(array_type, false); - return true; - } - template bool parse_array_item(input& in, size_t) { - array& a = out_->get(); - a.push_back(value()); - default_parse_context ctx(&a.back()); - return _parse(ctx, in); - } - bool parse_array_stop(size_t) { return true; } - bool parse_object_start() { - *out_ = value(object_type, false); - return true; - } - template bool parse_object_item(input& in, const std::string& key) { - object& o = out_->get(); - default_parse_context ctx(&o[key]); - return _parse(ctx, in); - } - private: - default_parse_context(const default_parse_context&); - default_parse_context& operator=(const default_parse_context&); - }; - - class null_parse_context { - public: - struct dummy_str { - void push_back(int) {} - }; - public: - null_parse_context() {} - bool set_null() { return true; } - bool set_bool(bool) { return true; } -#ifdef PICOJSON_USE_INT64 - bool set_int64(int64_t) { return true; } -#endif - bool set_number(double) { return true; } - template bool parse_string(input& in) { - dummy_str s; - return _parse_string(s, in); - } - bool parse_array_start() { return true; } - template bool parse_array_item(input& in, size_t) { - return _parse(*this, in); - } - bool parse_array_stop(size_t) { return true; } - bool parse_object_start() { return true; } - template bool parse_object_item(input& in, const std::string&) { - return _parse(*this, in); - } - private: - null_parse_context(const null_parse_context&); - null_parse_context& operator=(const null_parse_context&); - }; - - // obsolete, use the version below - template inline std::string parse(value& out, Iter& pos, const Iter& last) { - std::string err; - pos = parse(out, pos, last, &err); - return err; - } - - template inline Iter _parse(Context& ctx, const Iter& first, const Iter& last, std::string* err) { - input in(first, last); - if (! _parse(ctx, in) && err != NULL) { - char buf[64]; - SNPRINTF(buf, sizeof(buf), "syntax error at line %d near: ", in.line()); - *err = buf; - while (1) { - int ch = in.getc(); - if (ch == -1 || ch == '\n') { - break; - } else if (ch >= ' ') { - err->push_back(ch); - } } } - return in.cur(); +#endif + return buf; } - - template inline Iter parse(value& out, const Iter& first, const Iter& last, std::string* err) { - default_parse_context ctx(&out); - return _parse(ctx, first, last, err); - } - - inline std::string parse(value& out, const std::string& s) { - std::string err; - parse(out, s.begin(), s.end(), &err); - return err; - } - - inline std::string parse(value& out, std::istream& is) { - std::string err; - parse(out, std::istreambuf_iterator(is.rdbuf()), - std::istreambuf_iterator(), &err); - return err; - } - - template struct last_error_t { - static std::string s; - }; - template std::string last_error_t::s; - - inline void set_last_error(const std::string& s) { - last_error_t::s = s; - } - - inline const std::string& get_last_error() { - return last_error_t::s; - } - - inline bool operator==(const value& x, const value& y) { - if (x.is()) - return y.is(); -#define PICOJSON_CMP(type) \ - if (x.is()) \ - return y.is() && x.get() == y.get() - PICOJSON_CMP(bool); - PICOJSON_CMP(double); - PICOJSON_CMP(std::string); - PICOJSON_CMP(array); - PICOJSON_CMP(object); -#undef PICOJSON_CMP + case string_type: + return *u_.string_; + case array_type: + return "array"; + case object_type: + return "object"; + default: PICOJSON_ASSERT(0); #ifdef _MSC_VER __assume(0); #endif - return false; } - - inline bool operator!=(const value& x, const value& y) { - return ! (x == y); + return std::string(); +} + +template void copy(const std::string &s, Iter oi) { + std::copy(s.begin(), s.end(), oi); +} + +template struct serialize_str_char { + Iter oi; + void operator()(char c) { + switch (c) { +#define MAP(val, sym) \ + case val: \ + copy(sym, oi); \ + break + MAP('"', "\\\""); + MAP('\\', "\\\\"); + MAP('/', "\\/"); + MAP('\b', "\\b"); + MAP('\f', "\\f"); + MAP('\n', "\\n"); + MAP('\r', "\\r"); + MAP('\t', "\\t"); +#undef MAP + default: + if (static_cast(c) < 0x20 || c == 0x7f) { + char buf[7]; + SNPRINTF(buf, sizeof(buf), "\\u%04x", c & 0xff); + copy(buf, buf + 6, oi); + } else { + *oi++ = c; + } + break; + } + } +}; + +template void serialize_str(const std::string &s, Iter oi) { + *oi++ = '"'; + serialize_str_char process_char = {oi}; + std::for_each(s.begin(), s.end(), process_char); + *oi++ = '"'; +} + +template void value::serialize(Iter oi, bool prettify) const { + return _serialize(oi, prettify ? 0 : -1); +} + +inline std::string value::serialize(bool prettify) const { + return _serialize(prettify ? 0 : -1); +} + +template void value::_indent(Iter oi, int indent) { + *oi++ = '\n'; + for (int i = 0; i < indent * INDENT_WIDTH; ++i) { + *oi++ = ' '; } } -#if !PICOJSON_USE_RVALUE_REFERENCE -namespace std { - template<> inline void swap(picojson::value& x, picojson::value& y) - { - x.swap(y); +template void value::_serialize(Iter oi, int indent) const { + switch (type_) { + case string_type: + serialize_str(*u_.string_, oi); + break; + case array_type: { + *oi++ = '['; + if (indent != -1) { + ++indent; } + for (array::const_iterator i = u_.array_->begin(); i != u_.array_->end(); ++i) { + if (i != u_.array_->begin()) { + *oi++ = ','; + } + if (indent != -1) { + _indent(oi, indent); + } + i->_serialize(oi, indent); + } + if (indent != -1) { + --indent; + if (!u_.array_->empty()) { + _indent(oi, indent); + } + } + *oi++ = ']'; + break; + } + case object_type: { + *oi++ = '{'; + if (indent != -1) { + ++indent; + } + for (object::const_iterator i = u_.object_->begin(); i != u_.object_->end(); ++i) { + if (i != u_.object_->begin()) { + *oi++ = ','; + } + if (indent != -1) { + _indent(oi, indent); + } + serialize_str(i->first, oi); + *oi++ = ':'; + if (indent != -1) { + *oi++ = ' '; + } + i->second._serialize(oi, indent); + } + if (indent != -1) { + --indent; + if (!u_.object_->empty()) { + _indent(oi, indent); + } + } + *oi++ = '}'; + break; + } + default: + copy(to_str(), oi); + break; + } + if (indent == 0) { + *oi++ = '\n'; + } +} + +inline std::string value::_serialize(int indent) const { + std::string s; + _serialize(std::back_inserter(s), indent); + return s; +} + +template class input { +protected: + Iter cur_, end_; + bool consumed_; + int line_; + +public: + input(const Iter &first, const Iter &last) : cur_(first), end_(last), consumed_(false), line_(1) { + } + int getc() { + if (consumed_) { + if (*cur_ == '\n') { + ++line_; + } + ++cur_; + } + if (cur_ == end_) { + consumed_ = false; + return -1; + } + consumed_ = true; + return *cur_ & 0xff; + } + void ungetc() { + consumed_ = false; + } + Iter cur() const { + if (consumed_) { + input *self = const_cast *>(this); + self->consumed_ = false; + ++self->cur_; + } + return cur_; + } + int line() const { + return line_; + } + void skip_ws() { + while (1) { + int ch = getc(); + if (!(ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')) { + ungetc(); + break; + } + } + } + bool expect(const int expected) { + skip_ws(); + if (getc() != expected) { + ungetc(); + return false; + } + return true; + } + bool match(const std::string &pattern) { + for (std::string::const_iterator pi(pattern.begin()); pi != pattern.end(); ++pi) { + if (getc() != *pi) { + ungetc(); + return false; + } + } + return true; + } +}; + +template inline int _parse_quadhex(input &in) { + int uni_ch = 0, hex; + for (int i = 0; i < 4; i++) { + if ((hex = in.getc()) == -1) { + return -1; + } + if ('0' <= hex && hex <= '9') { + hex -= '0'; + } else if ('A' <= hex && hex <= 'F') { + hex -= 'A' - 0xa; + } else if ('a' <= hex && hex <= 'f') { + hex -= 'a' - 0xa; + } else { + in.ungetc(); + return -1; + } + uni_ch = uni_ch * 16 + hex; + } + return uni_ch; +} + +template inline bool _parse_codepoint(String &out, input &in) { + int uni_ch; + if ((uni_ch = _parse_quadhex(in)) == -1) { + return false; + } + if (0xd800 <= uni_ch && uni_ch <= 0xdfff) { + if (0xdc00 <= uni_ch) { + // a second 16-bit of a surrogate pair appeared + return false; + } + // first 16-bit of surrogate pair, get the next one + if (in.getc() != '\\' || in.getc() != 'u') { + in.ungetc(); + return false; + } + int second = _parse_quadhex(in); + if (!(0xdc00 <= second && second <= 0xdfff)) { + return false; + } + uni_ch = ((uni_ch - 0xd800) << 10) | ((second - 0xdc00) & 0x3ff); + uni_ch += 0x10000; + } + if (uni_ch < 0x80) { + out.push_back(static_cast(uni_ch)); + } else { + if (uni_ch < 0x800) { + out.push_back(static_cast(0xc0 | (uni_ch >> 6))); + } else { + if (uni_ch < 0x10000) { + out.push_back(static_cast(0xe0 | (uni_ch >> 12))); + } else { + out.push_back(static_cast(0xf0 | (uni_ch >> 18))); + out.push_back(static_cast(0x80 | ((uni_ch >> 12) & 0x3f))); + } + out.push_back(static_cast(0x80 | ((uni_ch >> 6) & 0x3f))); + } + out.push_back(static_cast(0x80 | (uni_ch & 0x3f))); + } + return true; +} + +template inline bool _parse_string(String &out, input &in) { + while (1) { + int ch = in.getc(); + if (ch < ' ') { + in.ungetc(); + return false; + } else if (ch == '"') { + return true; + } else if (ch == '\\') { + if ((ch = in.getc()) == -1) { + return false; + } + switch (ch) { +#define MAP(sym, val) \ + case sym: \ + out.push_back(val); \ + break + MAP('"', '\"'); + MAP('\\', '\\'); + MAP('/', '/'); + MAP('b', '\b'); + MAP('f', '\f'); + MAP('n', '\n'); + MAP('r', '\r'); + MAP('t', '\t'); +#undef MAP + case 'u': + if (!_parse_codepoint(out, in)) { + return false; + } + break; + default: + return false; + } + } else { + out.push_back(static_cast(ch)); + } + } + return false; +} + +template inline bool _parse_array(Context &ctx, input &in) { + if (!ctx.parse_array_start()) { + return false; + } + size_t idx = 0; + if (in.expect(']')) { + return ctx.parse_array_stop(idx); + } + do { + if (!ctx.parse_array_item(in, idx)) { + return false; + } + idx++; + } while (in.expect(',')); + return in.expect(']') && ctx.parse_array_stop(idx); +} + +template inline bool _parse_object(Context &ctx, input &in) { + if (!ctx.parse_object_start()) { + return false; + } + if (in.expect('}')) { + return true; + } + do { + std::string key; + if (!in.expect('"') || !_parse_string(key, in) || !in.expect(':')) { + return false; + } + if (!ctx.parse_object_item(in, key)) { + return false; + } + } while (in.expect(',')); + return in.expect('}'); +} + +template inline std::string _parse_number(input &in) { + std::string num_str; + while (1) { + int ch = in.getc(); + if (('0' <= ch && ch <= '9') || ch == '+' || ch == '-' || ch == 'e' || ch == 'E') { + num_str.push_back(static_cast(ch)); + } else if (ch == '.') { +#if PICOJSON_USE_LOCALE + num_str += localeconv()->decimal_point; +#else + num_str.push_back('.'); +#endif + } else { + in.ungetc(); + break; + } + } + return num_str; +} + +template inline bool _parse(Context &ctx, input &in) { + in.skip_ws(); + int ch = in.getc(); + switch (ch) { +#define IS(ch, text, op) \ + case ch: \ + if (in.match(text) && op) { \ + return true; \ + } else { \ + return false; \ + } + IS('n', "ull", ctx.set_null()); + IS('f', "alse", ctx.set_bool(false)); + IS('t', "rue", ctx.set_bool(true)); +#undef IS + case '"': + return ctx.parse_string(in); + case '[': + return _parse_array(ctx, in); + case '{': + return _parse_object(ctx, in); + default: + if (('0' <= ch && ch <= '9') || ch == '-') { + double f; + char *endp; + in.ungetc(); + std::string num_str(_parse_number(in)); + if (num_str.empty()) { + return false; + } +#ifdef PICOJSON_USE_INT64 + { + errno = 0; + intmax_t ival = strtoimax(num_str.c_str(), &endp, 10); + if (errno == 0 && std::numeric_limits::min() <= ival && ival <= std::numeric_limits::max() && + endp == num_str.c_str() + num_str.size()) { + ctx.set_int64(ival); + return true; + } + } +#endif + f = strtod(num_str.c_str(), &endp); + if (endp == num_str.c_str() + num_str.size()) { + ctx.set_number(f); + return true; + } + return false; + } + break; + } + in.ungetc(); + return false; +} + +class deny_parse_context { +public: + bool set_null() { + return false; + } + bool set_bool(bool) { + return false; + } +#ifdef PICOJSON_USE_INT64 + bool set_int64(int64_t) { + return false; + } +#endif + bool set_number(double) { + return false; + } + template bool parse_string(input &) { + return false; + } + bool parse_array_start() { + return false; + } + template bool parse_array_item(input &, size_t) { + return false; + } + bool parse_array_stop(size_t) { + return false; + } + bool parse_object_start() { + return false; + } + template bool parse_object_item(input &, const std::string &) { + return false; + } +}; + +class default_parse_context { +protected: + value *out_; + +public: + default_parse_context(value *out) : out_(out) { + } + bool set_null() { + *out_ = value(); + return true; + } + bool set_bool(bool b) { + *out_ = value(b); + return true; + } +#ifdef PICOJSON_USE_INT64 + bool set_int64(int64_t i) { + *out_ = value(i); + return true; + } +#endif + bool set_number(double f) { + *out_ = value(f); + return true; + } + template bool parse_string(input &in) { + *out_ = value(string_type, false); + return _parse_string(out_->get(), in); + } + bool parse_array_start() { + *out_ = value(array_type, false); + return true; + } + template bool parse_array_item(input &in, size_t) { + array &a = out_->get(); + a.push_back(value()); + default_parse_context ctx(&a.back()); + return _parse(ctx, in); + } + bool parse_array_stop(size_t) { + return true; + } + bool parse_object_start() { + *out_ = value(object_type, false); + return true; + } + template bool parse_object_item(input &in, const std::string &key) { + object &o = out_->get(); + default_parse_context ctx(&o[key]); + return _parse(ctx, in); + } + +private: + default_parse_context(const default_parse_context &); + default_parse_context &operator=(const default_parse_context &); +}; + +class null_parse_context { +public: + struct dummy_str { + void push_back(int) { + } + }; + +public: + null_parse_context() { + } + bool set_null() { + return true; + } + bool set_bool(bool) { + return true; + } +#ifdef PICOJSON_USE_INT64 + bool set_int64(int64_t) { + return true; + } +#endif + bool set_number(double) { + return true; + } + template bool parse_string(input &in) { + dummy_str s; + return _parse_string(s, in); + } + bool parse_array_start() { + return true; + } + template bool parse_array_item(input &in, size_t) { + return _parse(*this, in); + } + bool parse_array_stop(size_t) { + return true; + } + bool parse_object_start() { + return true; + } + template bool parse_object_item(input &in, const std::string &) { + return _parse(*this, in); + } + +private: + null_parse_context(const null_parse_context &); + null_parse_context &operator=(const null_parse_context &); +}; + +// obsolete, use the version below +template inline std::string parse(value &out, Iter &pos, const Iter &last) { + std::string err; + pos = parse(out, pos, last, &err); + return err; +} + +template inline Iter _parse(Context &ctx, const Iter &first, const Iter &last, std::string *err) { + input in(first, last); + if (!_parse(ctx, in) && err != NULL) { + char buf[64]; + SNPRINTF(buf, sizeof(buf), "syntax error at line %d near: ", in.line()); + *err = buf; + while (1) { + int ch = in.getc(); + if (ch == -1 || ch == '\n') { + break; + } else if (ch >= ' ') { + err->push_back(static_cast(ch)); + } + } + } + return in.cur(); +} + +template inline Iter parse(value &out, const Iter &first, const Iter &last, std::string *err) { + default_parse_context ctx(&out); + return _parse(ctx, first, last, err); +} + +inline std::string parse(value &out, const std::string &s) { + std::string err; + parse(out, s.begin(), s.end(), &err); + return err; +} + +inline std::string parse(value &out, std::istream &is) { + std::string err; + parse(out, std::istreambuf_iterator(is.rdbuf()), std::istreambuf_iterator(), &err); + return err; +} + +template struct last_error_t { static std::string s; }; +template std::string last_error_t::s; + +inline void set_last_error(const std::string &s) { + last_error_t::s = s; +} + +inline const std::string &get_last_error() { + return last_error_t::s; +} + +inline bool operator==(const value &x, const value &y) { + if (x.is()) + return y.is(); +#define PICOJSON_CMP(type) \ + if (x.is()) \ + return y.is() && x.get() == y.get() + PICOJSON_CMP(bool); + PICOJSON_CMP(double); + PICOJSON_CMP(std::string); + PICOJSON_CMP(array); + PICOJSON_CMP(object); +#undef PICOJSON_CMP + PICOJSON_ASSERT(0); +#ifdef _MSC_VER + __assume(0); +#endif + return false; +} + +inline bool operator!=(const value &x, const value &y) { + return !(x == y); +} +} + +#if !PICOJSON_USE_RVALUE_REFERENCE +namespace std { +template <> inline void swap(picojson::value &x, picojson::value &y) { + x.swap(y); +} } #endif -inline std::istream& operator>>(std::istream& is, picojson::value& x) -{ +inline std::istream &operator>>(std::istream &is, picojson::value &x) { picojson::set_last_error(std::string()); - std::string err = picojson::parse(x, is); - if (! err.empty()) { + const std::string err(picojson::parse(x, is)); + if (!err.empty()) { picojson::set_last_error(err); is.setstate(std::ios::failbit); } return is; } -inline std::ostream& operator<<(std::ostream& os, const picojson::value& x) -{ +inline std::ostream &operator<<(std::ostream &os, const picojson::value &x) { x.serialize(std::ostream_iterator(os)); return os; } #ifdef _MSC_VER - #pragma warning(pop) +#pragma warning(pop) #endif #endif diff --git a/tiny_gltf_loader.h b/tiny_gltf_loader.h index 467c3e0..7c37bce 100644 --- a/tiny_gltf_loader.h +++ b/tiny_gltf_loader.h @@ -1,10 +1,10 @@ // -// Tiny glTF loader. +// Header-only tiny glTF 2.0 loader. // // // The MIT License (MIT) // -// Copyright (c) 2015 - 2016 Syoyo Fujita and many contributors. +// Copyright (c) 2015 - 2017 Syoyo Fujita, Aurélien Chatelain and many contributors. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -25,13 +25,7 @@ // THE SOFTWARE. // Version: -// - v0.9.5 Support parsing `extras` parameter. -// - v0.9.4 Support parsing `shader`, `program` and `tecnique` thanks to -// @lukesanantonio -// - v0.9.3 Support binary glTF -// - v0.9.2 Support parsing `texture` -// - v0.9.1 Support loading glTF asset from memory -// - v0.9.0 Initial +// - v2.0.0 glTF 2.0!. // // Tiny glTF loader is using following third party libraries: // @@ -298,21 +292,22 @@ struct AnimationChannel { Value extras; AnimationChannel() + : sampler(-1) + , target_node(-1) { - sampler = -1; - target_node = -1; } }; struct AnimationSampler { int input; // required - std::string interpolation; // in ["LINEAR", "STEP", "CATMULLROMSPLINE", "CUBICSPLINE"], default "LINEAR" int output; // required + std::string interpolation; // in ["LINEAR", "STEP", "CATMULLROMSPLINE", "CUBICSPLINE"], default "LINEAR" AnimationSampler() + : input(-1) + , output(-1) + , interpolation("LINEAR") { - input = -1; - output = -1; } }; @@ -346,9 +341,9 @@ struct Sampler { Value extras; Sampler() + : wrapS(TINYGLTF_TEXTURE_WRAP_RPEAT) + , wrapT(TINYGLTF_TEXTURE_WRAP_RPEAT) { - wrapS = TINYGLTF_TEXTURE_WRAP_RPEAT; - wrapT = TINYGLTF_TEXTURE_WRAP_RPEAT; } }; @@ -376,9 +371,9 @@ struct Texture { Value extras; Texture() + : sampler(-1) + , source(-1) { - sampler = -1; - source =-1; } }; @@ -482,9 +477,9 @@ typedef struct { class Node { public: Node() + : skin(-1) + , mesh(-1) { - mesh = -1, - skin = -1; } ~Node() {} @@ -1274,7 +1269,7 @@ static bool ParseStringIntProperty(std::map *ret, picojson::object::const_iterator dictItEnd(dict.end()); for (; dictIt != dictItEnd; ++dictIt) { - if (!dictIt->second.is()) { + if (!dictIt->second.is()) { if (required) { if (err) { (*err) += "'" + property + "' value is not an int.\n"; @@ -1841,7 +1836,7 @@ static bool ParseNode(Node *node, std::string *err, const picojson::object &o) { double mesh = -1.0; ParseNumberProperty(&mesh, err, o, "mesh", false); - node->mesh = mesh; + node->mesh = int(mesh); node->children.clear(); picojson::object::const_iterator childrenObject = o.find("children"); @@ -1850,7 +1845,7 @@ static bool ParseNode(Node *node, std::string *err, const picojson::object &o) { const picojson::array &childrenArray = (childrenObject->second).get(); for (size_t i = 0; i < childrenArray.size(); i++) { - if (!childrenArray[i].is()) { + if (!childrenArray[i].is()) { if (err) { (*err) += "Invalid `children` array.\n"; } @@ -1918,9 +1913,9 @@ static bool ParseMaterial(Material *material, std::string *err, (it->second).get(); picojson::object::const_iterator itVal(values_object.begin()); - picojson::object::const_iterator itEnd(values_object.end()); + picojson::object::const_iterator itValEnd(values_object.end()); - for (; itVal != itEnd; itVal++) { + for (; itVal != itValEnd; itVal++) { Parameter param; if (ParseParameterProperty(¶m, err, values_object, itVal->first, false)) { @@ -1942,9 +1937,9 @@ static bool ParseMaterial(Material *material, std::string *err, (extIt->second).get(); picojson::object::const_iterator itVal(values_object.begin()); - picojson::object::const_iterator itEnd(values_object.end()); + picojson::object::const_iterator itValEnd(values_object.end()); - for (; itVal != itEnd; itVal++) { + for (; itVal != itValEnd; itVal++) { Parameter param; if (ParseParameterProperty(¶m, err, values_object, itVal->first, false)) { @@ -2323,7 +2318,7 @@ if (v.contains("scenes") && v.get("scenes").is()) { // 7. Parse default scenes. if (v.contains("scene") && v.get("scene").is()) { - const int defaultScene = v.get("scene").get(); + const int defaultScene = int(v.get("scene").get()); model->defaultScene = static_cast(defaultScene); } @@ -2362,7 +2357,7 @@ if (v.contains("scenes") && v.get("scenes").is()) { if (image.bufferView != -1) { // Load image from the buffer view. - if ((size_t)image.bufferView >= model->bufferViews.size()) { + if (size_t(image.bufferView) >= model->bufferViews.size()) { if (err) { std::stringstream ss; ss << "bufferView \"" << image.bufferView @@ -2372,8 +2367,8 @@ if (v.contains("scenes") && v.get("scenes").is()) { return false; } - const BufferView &bufferView = model->bufferViews[image.bufferView]; - const Buffer &buffer = model->buffers[bufferView.buffer]; + const BufferView &bufferView = model->bufferViews[size_t(image.bufferView)]; + const Buffer &buffer = model->buffers[size_t(bufferView.buffer)]; bool ret = LoadImageData(&image, err, image.width, image.height, &buffer.data[bufferView.byteOffset], From 1866e11237415cc22bf43dceae19cfe00e702cd1 Mon Sep 17 00:00:00 2001 From: Syoyo Fujita Date: Sat, 27 May 2017 23:55:32 +0900 Subject: [PATCH 10/10] Add Cube test model. --- README.md | 6 +- models/Cube/Cube.bin | Bin 0 -> 1800 bytes models/Cube/Cube.gltf | 193 +++++++ models/Cube/Cube_BaseColor.png | 715 +++++++++++++++++++++++++ models/Cube/Cube_MetallicRoughness.png | 715 +++++++++++++++++++++++++ models/Cube/README.md | 4 + 6 files changed, 1630 insertions(+), 3 deletions(-) create mode 100644 models/Cube/Cube.bin create mode 100644 models/Cube/Cube.gltf create mode 100644 models/Cube/Cube_BaseColor.png create mode 100644 models/Cube/Cube_MetallicRoughness.png create mode 100644 models/Cube/README.md diff --git a/README.md b/README.md index 90ccab8..4e2aae2 100644 --- a/README.md +++ b/README.md @@ -42,11 +42,11 @@ * [ ] Support `extensions` and `extras` property * [ ] HDR image? -## License +## Licenses -TinyGLTFLoader is licensed under MIT license. +TinyGLTF is licensed under MIT license. -TinyGLTFLoader uses the following third party libraries. +TinyGLTF uses the following third party libraries. * picojson.h : Copyright 2009-2010 Cybozu Labs, Inc. Copyright 2011-2014 Kazuho Oku * base64 : Copyright (C) 2004-2008 René Nyffenegger diff --git a/models/Cube/Cube.bin b/models/Cube/Cube.bin new file mode 100644 index 0000000000000000000000000000000000000000..7dae4b0b93e3251ca8886c43b6a9403f27648a39 GIT binary patch literal 1800 zcmcIhNm2wc3={jX@B1<=Z=g8#)5wWmQS&680G1PF(jh%P2S`;{Y*|ulH?V?LtYIA+ z*u)kl*v1Zav4?#e;1EYR#tBYwhI3rt5?8p!4Q_FVdpux@M?B#fF91Sk->kS959VLr z@8oxrsPot`@w+0f-8FtBIc~hgDG4+1eGd6JQYQAF) zU*f9i?i!eQ^_{o~QDeW(f`OPNhH^g zGgfh|f4+UZiu*fWv=`dZn0fUy zjohgr`J2aB?taGS(VMy7)I&251>eO*ZZ&GMAM19;=ZXK`x&HQ89zETBDgVR_skeXF zPwqv#OMPX$EB3-ZEZ5P#bUPmAeBwIVWvOSa)Rr}A%es4oxu#b$T&Ia!U7nf8+0vJ> I)N}Os0UGHvApigX literal 0 HcmV?d00001 diff --git a/models/Cube/Cube.gltf b/models/Cube/Cube.gltf new file mode 100644 index 0000000..bc873da --- /dev/null +++ b/models/Cube/Cube.gltf @@ -0,0 +1,193 @@ +{ + "accessors" : [ + { + "bufferView" : 0, + "byteOffset" : 0, + "componentType" : 5123, + "count" : 36, + "max" : [ + 35 + ], + "min" : [ + 0 + ], + "type" : "SCALAR" + }, + { + "bufferView" : 1, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 36, + "max" : [ + 1.000000, + 1.000000, + 1.000001 + ], + "min" : [ + -1.000000, + -1.000000, + -1.000000 + ], + "type" : "VEC3" + }, + { + "bufferView" : 2, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 36, + "max" : [ + 1.000000, + 1.000000, + 1.000000 + ], + "min" : [ + -1.000000, + -1.000000, + -1.000000 + ], + "type" : "VEC3" + }, + { + "bufferView" : 3, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 36, + "max" : [ + 1.000000, + -0.000000, + -0.000000, + 1.000000 + ], + "min" : [ + 0.000000, + -0.000000, + -1.000000, + -1.000000 + ], + "type" : "VEC4" + }, + { + "bufferView" : 4, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 36, + "max" : [ + 1.000000, + 1.000000 + ], + "min" : [ + -1.000000, + -1.000000 + ], + "type" : "VEC2" + } + ], + "asset" : { + "generator" : "VKTS glTF 2.0 exporter", + "version" : "2.0" + }, + "bufferViews" : [ + { + "buffer" : 0, + "byteLength" : 72, + "byteOffset" : 0, + "target" : 34963 + }, + { + "buffer" : 0, + "byteLength" : 432, + "byteOffset" : 72, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 432, + "byteOffset" : 504, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 576, + "byteOffset" : 936, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 288, + "byteOffset" : 1512, + "target" : 34962 + } + ], + "buffers" : [ + { + "byteLength" : 1800, + "uri" : "Cube.bin" + } + ], + "images" : [ + { + "uri" : "Cube_BaseColor.png" + }, + { + "uri" : "Cube_MetallicRoughness.png" + } + ], + "materials" : [ + { + "name" : "Cube", + "pbrMetallicRoughness" : { + "baseColorTexture" : { + "index" : 0 + }, + "metallicRoughnessTexture" : { + "index" : 1 + } + } + } + ], + "meshes" : [ + { + "name" : "Cube", + "primitives" : [ + { + "attributes" : { + "NORMAL" : 2, + "POSITION" : 1, + "TANGENT" : 3, + "TEXCOORD_0" : 4 + }, + "indices" : 0, + "material" : 0, + "mode" : 4 + } + ] + } + ], + "nodes" : [ + { + "mesh" : 0, + "name" : "Cube" + } + ], + "samplers" : [ + {} + ], + "scene" : 0, + "scenes" : [ + { + "nodes" : [ + 0 + ] + } + ], + "textures" : [ + { + "sampler" : 0, + "source" : 0 + }, + { + "sampler" : 0, + "source" : 1 + } + ] +} diff --git a/models/Cube/Cube_BaseColor.png b/models/Cube/Cube_BaseColor.png new file mode 100644 index 0000000..2e29233 --- /dev/null +++ b/models/Cube/Cube_BaseColor.png @@ -0,0 +1,715 @@ + + + + + + + + + + + + + + + + + + + + + + + glTF-Sample-Models/Cube_BaseColor.png at master · KhronosGroup/glTF-Sample-Models + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Skip to content +
+ + + + + + + + + + + + + +
+ +
+ +
+
+ + + +
+
+
+ + + + + +
+
+ +
    +
  • +
    + +
    + + + + Watch + + + + +
    +
    +
    + + Notifications +
    + + + +
    +
    +
    +
    +
  • + +
  • +
    +
    + + +
    +
    + + +
    + +
  • + +
  • + + + Fork + + + + + +
  • +
+ +

+ + /glTF-Sample-Models + +

+ +
+ +
+ +
+
+ + + + +Permalink + + + +
+ +
+ + +
+ +
+
+ + Switch branches/tags +
+ +
+
+ +
+
+ +
+
+ + + +
+
+ + +
+ +
Nothing to show
+
+ +
+
+
+ +
+ + Find file + + +
+ +
+ + + +
+ Fetching contributors… +
+ +
+ + Cannot retrieve contributors at this time +
+
+
+
+
+ + + + + + + +
+ +
+ +
+ 871 KB +
+
+ + + +
+
+ Cube_BaseColor.png +
+
+ +
+ + + + + +
+ +
+ +
+
+ +
+ + + + + + +
+ + + You can't perform that action at this time. +
+ + + + + + + + + +
+ + You signed in with another tab or window. Reload to refresh your session. + You signed out in another tab or window. Reload to refresh your session. +
+ + + + + + diff --git a/models/Cube/Cube_MetallicRoughness.png b/models/Cube/Cube_MetallicRoughness.png new file mode 100644 index 0000000..a944391 --- /dev/null +++ b/models/Cube/Cube_MetallicRoughness.png @@ -0,0 +1,715 @@ + + + + + + + + + + + + + + + + + + + + + + + glTF-Sample-Models/Cube_MetallicRoughness.png at master · KhronosGroup/glTF-Sample-Models + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Skip to content +
+ + + + + + + + + + + + + +
+ +
+ +
+
+ + + +
+
+
+ + + + + +
+
+ +
    +
  • +
    + +
    + + + + Watch + + + + +
    +
    +
    + + Notifications +
    + + + +
    +
    +
    +
    +
  • + +
  • +
    +
    + + +
    +
    + + +
    + +
  • + +
  • + + + Fork + + + + + +
  • +
+ +

+ + /glTF-Sample-Models + +

+ +
+ +
+ +
+
+ + + + +Permalink + + + +
+ +
+ + +
+ +
+
+ + Switch branches/tags +
+ +
+
+ +
+
+ +
+
+ + + +
+
+ + +
+ +
Nothing to show
+
+ +
+
+
+ +
+ + Find file + + +
+ +
+ + + +
+ Fetching contributors… +
+ +
+ + Cannot retrieve contributors at this time +
+
+
+
+
+ + + + + + + +
+ +
+ +
+ 319 Bytes +
+
+ + + +
+
+ Cube_MetallicRoughness.png +
+
+ +
+ + + + + +
+ +
+ +
+
+ +
+ + + + + + +
+ + + You can't perform that action at this time. +
+ + + + + + + + + +
+ + You signed in with another tab or window. Reload to refresh your session. + You signed out in another tab or window. Reload to refresh your session. +
+ + + + + + diff --git a/models/Cube/README.md b/models/Cube/README.md new file mode 100644 index 0000000..6a2f622 --- /dev/null +++ b/models/Cube/README.md @@ -0,0 +1,4 @@ +License: Donated by Norbert Nopper for glTF testing. + +https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Cube +