From 08c9d256294c5010f334dc5ffce2379445bc423c Mon Sep 17 00:00:00 2001 From: Syoyo Fujita Date: Wed, 31 May 2017 00:16:45 +0900 Subject: [PATCH] Revert "Feature/update tinygltf 20" --- tiny_gltf_loader.h | 1244 +++++++++++++++++++++++--------------------- 1 file changed, 658 insertions(+), 586 deletions(-) diff --git a/tiny_gltf_loader.h b/tiny_gltf_loader.h index 467c3e0..3e33d4c 100644 --- a/tiny_gltf_loader.h +++ b/tiny_gltf_loader.h @@ -283,147 +283,102 @@ 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; -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"] +typedef struct { + std::string sampler; + std::string target_id; + std::string target_path; Value extras; +} AnimationChannel; - 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 input; + std::string interpolation; + std::string output; + Value extras; +} AnimationSampler; typedef struct { std::string name; std::vector channels; - std::vector samplers; + std::map samplers; + ParameterMap parameters; Value extras; } Animation; -struct Skin { +typedef struct { 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"] - 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 minFilter; + int magFilter; + int wrapS; + int wrapT; int wrapR; // TinyGLTF extension int pad0; Value extras; +} Sampler; - Sampler() - { - wrapS = TINYGLTF_TEXTURE_WRAP_RPEAT; - wrapT = TINYGLTF_TEXTURE_WRAP_RPEAT; - } -}; - -struct Image{ +typedef struct { std::string name; int width; int height; int component; int pad0; std::vector image; - int bufferView; // (required if no uri) - std::string mimeType; // (required if no uri) ["image/jpeg", "image/png"] - std::string uri; // (reqiored if no mimeType) + + std::string bufferView; // KHR_binary_glTF extenstion. + std::string mimeType; // KHR_binary_glTF extenstion. + Value extras; +} Image; - Image() - { - bufferView = -1; - } -}; - -struct Texture { - int sampler; - int source; // Required (not specified in the spec ?) - Value extras; - - Texture() - { - sampler = -1; - source =-1; - } -}; - -// 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 { +typedef struct { + int format; + int internalFormat; + std::string sampler; // Required + std::string source; // Required + int target; + int type; std::string name; - - ParameterMap values; // PBR metal/roughness workflow - ParameterMap additionalValues; // normal/occlusion/emissive values - ParameterMap extCommonValues; // KHR_common_material extension - ParameterMap extPBRValues; Value extras; -}; +} Texture; -struct BufferView{ +typedef struct { std::string name; - 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"] + std::string technique; + ParameterMap values; + + Value extras; +} Material; + +typedef struct { + std::string name; + std::string buffer; // Required + size_t byteOffset; // Required + size_t byteLength; // default: 0 + int target; int pad0; Value extras; -}; +} BufferView; -struct Accessor { - int bufferView; // optional in spec but required here since sparse accessor are not supported +typedef struct { + std::string bufferView; std::string name; size_t byteOffset; size_t byteStride; - int componentType; // (required) One of TINYGLTF_COMPONENT_TYPE_*** - size_t count; // required - int type; // (required) One of TINYGLTF_TYPE_*** .. + 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 Value extras; - - std::vector minValues; // required - std::vector maxValues; // required - - Accessor() - { - bufferView = -1; - } -}; +} Accessor; class Camera { public: @@ -433,73 +388,47 @@ class Camera { std::string name; bool isOrthographic; // false = perspective. - // Orthographic properties - float xMag; // required - float yMag; // required - float zFar; // required - float zNear; //required - - // Perspective properties + // Some common properties. float aspectRatio; - float yfov; // required - float zfar; - float znear; // required - - ParameterMap extensions; - Value extras; + float yFov; + float zFar; + float zNear; }; -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_*** - 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; +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; - Primitive() - { - material = -1; - indices = -1; - } -}; + Value extras; // "extra" property +} 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; class Node { public: - Node() - { - mesh = -1, - skin = -1; - } - + Node() {} ~Node() {} - int camera; // the index of the camera referenced by this node + std::string camera; // camera object referenced by this node. std::string name; - int skin; - int mesh; - std::vector children; + 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 std::vector matrix; // length must be 0 or 16 - std::vector weights; // The weights of the instantiated Morph Target + std::vector meshes; Value extras; }; @@ -507,47 +436,78 @@ 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; typedef struct { - std::string version; // required + 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 minVersion; - std::string copyright; - ParameterMap extensions; + std::string version; + std::string profile_api; + std::string profile_version; + bool premultipliedAlpha; + char pad[7]; Value extras; } Asset; -struct Scene { - std::string name; - std::vector nodes; - - ParameterMap extensions; - ParameterMap extras; -}; - -class Model { +class Scene { public: - Model() {} - ~Model() {} + Scene() {} + ~Scene() {} - 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 skins; - std::vector samplers; - std::vector scenes; + 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 shaders; + std::map programs; + std::map techniques; + std::map samplers; + std::map > scenes; // list of nodes - int defaultScene; - std::vector extensionsUsed; + std::string defaultScene; Asset asset; @@ -574,28 +534,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(Model *model, std::string *err, + bool LoadASCIIFromFile(Scene *scene, 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(Model *model, std::string *err, const char *str, + bool LoadASCIIFromString(Scene *scene, 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(Model *model, std::string *err, + bool LoadBinaryFromFile(Scene *scene, 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(Model *model, std::string *err, + bool LoadBinaryFromMemory(Scene *scene, std::string *err, const unsigned char *bytes, const unsigned int length, const std::string &base_dir = "", @@ -605,7 +565,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(Model *model, std::string *err, const char *str, + bool LoadFromString(Scene *scene, std::string *err, const char *str, const unsigned int length, const std::string &base_dir, unsigned int check_sections); @@ -946,16 +906,12 @@ 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 true; + return false; } if (w < 1 || h < 1) { @@ -963,7 +919,7 @@ static bool LoadImageData(Image *image, std::string *err, int req_width, if (err) { (*err) += "Unknown image format.\n"; } - return true; + return false; } if (req_width > 0) { @@ -1244,7 +1200,48 @@ static bool ParseStringProperty( return true; } -static bool ParseStringIntProperty(std::map *ret, +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); @@ -1274,23 +1271,24 @@ static bool ParseStringIntProperty(std::map *ret, picojson::object::const_iterator dictItEnd(dict.end()); for (; dictIt != dictItEnd; ++dictIt) { - if (!dictIt->second.is()) { + // Check that the value is a string. + if (!dictIt->second.is()) { if (required) { if (err) { - (*err) += "'" + property + "' value is not an int.\n"; + (*err) += "'" + property + "' value is not a string.\n"; } } return false; } // Insert into the list. - (*ret)[dictIt->first] = static_cast(dictIt->second.get()); + (*ret)[dictIt->first] = dictIt->second.get(); } return true; } static bool ParseKHRBinaryExtension(const picojson::object &o, std::string *err, - double *buffer_view, + std::string *buffer_view, std::string *mime_type, int *image_width, int *image_height) { picojson::object j = o; @@ -1328,7 +1326,7 @@ static bool ParseKHRBinaryExtension(const picojson::object &o, std::string *err, picojson::object k = ext["KHR_binary_glTF"].get(); - if (!ParseNumberProperty(buffer_view, err, k, "bufferView", true)) { + if (!ParseStringProperty(buffer_view, err, k, "bufferView", true)) { return false; } @@ -1353,51 +1351,24 @@ 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->version, err, o, "version", true); ParseStringProperty(&asset->generator, err, o, "generator", false); - ParseStringProperty(&asset->minVersion, err, o, "minVersion", false); + ParseBooleanProperty(&asset->premultipliedAlpha, err, o, "premultipliedAlpha", + false); - // Unity exporter version is added as extra here - ParseExtrasProperty(&(asset->extras), o); + 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(); + } + } return true; } @@ -1406,16 +1377,8 @@ 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) && !isEmbedded) { - if (err) { - (*err) += "Invalid image data (required data is missing).\n"; - } + if (!ParseStringProperty(&uri, err, o, "uri", true)) { return false; } @@ -1446,7 +1409,7 @@ static bool ParseImage(Image *image, std::string *err, // There should be "extensions" property. // "extensions":{"KHR_binary_glTF":{"bufferView": "id", ... - double buffer_view = -1.0; + std::string buffer_view; std::string mime_type; int image_width; int image_height; @@ -1467,7 +1430,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 = static_cast(buffer_view); + image->bufferView = buffer_view; image->mimeType = mime_type; image->width = image_width; image->height = image_height; @@ -1484,16 +1447,11 @@ 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"; } - // If the image cannot be loaded, keep uri as image->uri. - return true; + return false; } if (img.empty()) { if (err) { @@ -1512,16 +1470,33 @@ 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 (!ParseNumberProperty(&source, err, o, "source", true)) { + if (!ParseStringProperty(&texture->sampler, err, o, "sampler", true)) { return false; } - texture->sampler = static_cast(sampler); - texture->source = static_cast(source); + 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); return true; } @@ -1620,8 +1595,8 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, static bool ParseBufferView(BufferView *bufferView, std::string *err, const picojson::object &o) { - double buffer = -1.0; - if (!ParseNumberProperty(&buffer, err, o, "buffer", true)) { + std::string buffer; + if (!ParseStringProperty(&buffer, err, o, "buffer", true)) { return false; } @@ -1630,13 +1605,8 @@ static bool ParseBufferView(BufferView *bufferView, std::string *err, return 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 byteLength = 0.0; + ParseNumberProperty(&byteLength, err, o, "byteLength", false); double target = 0.0; ParseNumberProperty(&target, err, o, "target", false); @@ -1651,27 +1621,26 @@ static bool ParseBufferView(BufferView *bufferView, std::string *err, ParseStringProperty(&bufferView->name, err, o, "name", false); - bufferView->buffer = static_cast(buffer); + bufferView->buffer = 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) { - double bufferView = -1.0; - if (!ParseNumberProperty(&bufferView, err, o, "bufferView", true)) { + std::string bufferView; + if (!ParseStringProperty(&bufferView, err, o, "bufferView", true)) { return false; } - double byteOffset = 0.0; + double byteOffset; if (!ParseNumberProperty(&byteOffset, err, o, "byteOffset", true)) { return false; } - double componentType = 0.0; + double componentType; if (!ParseNumberProperty(&componentType, err, o, "componentType", true)) { return false; } @@ -1716,16 +1685,11 @@ static bool ParseAccessor(Accessor *accessor, std::string *err, accessor->minValues.clear(); accessor->maxValues.clear(); - if(!ParseNumberArrayProperty(&accessor->minValues, err, o, "min", true)) { - return false; - } - - if(!ParseNumberArrayProperty(&accessor->maxValues, err, o, "max", true)) { - return false; - } + ParseNumberArrayProperty(&accessor->minValues, err, o, "min", false); + ParseNumberArrayProperty(&accessor->maxValues, err, o, "max", false); accessor->count = static_cast(count); - accessor->bufferView = static_cast(bufferView); + accessor->bufferView = bufferView; accessor->byteOffset = static_cast(byteOffset); accessor->byteStride = static_cast(byteStride); @@ -1752,23 +1716,21 @@ static bool ParseAccessor(Accessor *accessor, std::string *err, static bool ParsePrimitive(Primitive *primitive, std::string *err, const picojson::object &o) { - double material = -1.0; - ParseNumberProperty(&material, err, o, "material", false); - primitive->material = static_cast(material); + if (!ParseStringProperty(&primitive->material, err, o, "material", true, + "mesh.primitive")) { + return false; + } double mode = static_cast(TINYGLTF_MODE_TRIANGLES); ParseNumberProperty(&mode, err, o, "mode", false); int primMode = static_cast(mode); - primitive->mode = primMode; // Why only triangled were supported ? + primitive->mode = primMode; - 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; - } + primitive->indices = ""; + ParseStringProperty(&primitive->indices, err, o, "indices", false); + + ParseStringMapProperty(&primitive->attributes, err, o, "attributes", false); ParseExtrasProperty(&(primitive->extras), o); @@ -1793,28 +1755,6 @@ 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; @@ -1823,25 +1763,11 @@ 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)) { - - 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; + 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); node->children.clear(); picojson::object::const_iterator childrenObject = o.find("children"); @@ -1850,13 +1776,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 int &childrenNode = static_cast(childrenArray[i].get()); + const std::string &childrenNode = childrenArray[i].get(); node->children.push_back(childrenNode); } } @@ -1886,10 +1812,6 @@ 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) { @@ -1901,78 +1823,214 @@ static bool ParseParameterProperty(Parameter *param, std::string *err, } static bool ParseMaterial(Material *material, std::string *err, - const picojson::object &o) { + const picojson::object &o) { + ParseStringProperty(&material->name, err, o, "name", false); + ParseStringProperty(&material->technique, err, o, "technique", false); material->values.clear(); - material->extPBRValues.clear(); - material->additionalValues.clear(); + picojson::object::const_iterator valuesIt = o.find("values"); - picojson::object::const_iterator it(o.begin()); - picojson::object::const_iterator itEnd(o.end()); + if ((valuesIt != o.end()) && (valuesIt->second).is()) { + const picojson::object &values_object = + (valuesIt->second).get(); - for (; it != itEnd; it++) { - if(it->first == "pbrMetallicRoughness") - { - if ((it->second).is()) { - const picojson::object &values_object = - (it->second).get(); + picojson::object::const_iterator it(values_object.begin()); + picojson::object::const_iterator itEnd(values_object.end()); - 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; - } + for (; it != itEnd; it++) { + Parameter param; + if (ParseParameterProperty(¶m, err, values_object, it->first, + false)) { + material->values[it->first] = param; } } + } ParseExtrasProperty(&(material->extras), o); 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) { - double samplerIndex = -1.0; - double targetIndex = -1.0; - if (!ParseNumberProperty(&samplerIndex, err, o, "sampler", true)) { + if (!ParseStringProperty(&channel->sampler, err, o, "sampler", true)) { if (err) { (*err) += "`sampler` field is missing in animation channels\n"; } @@ -1984,7 +2042,7 @@ static bool ParseAnimationChannel(AnimationChannel *channel, std::string *err, const picojson::object &target_object = (targetIt->second).get(); - if (!ParseNumberProperty(&targetIndex, err, target_object, "node", + if (!ParseStringProperty(&channel->target_id, err, target_object, "id", true)) { if (err) { (*err) += "`id` field is missing in animation.channels.target\n"; @@ -2001,9 +2059,6 @@ 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; @@ -2029,20 +2084,21 @@ 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::array &sampler_array = - (samplerIt->second).get(); + if ((samplerIt != o.end()) && (samplerIt->second).is()) { + const picojson::object &sampler_object = + (samplerIt->second).get(); - picojson::array::const_iterator it = sampler_array.begin(); - picojson::array::const_iterator itEnd = sampler_array.end(); + picojson::object::const_iterator it = sampler_object.begin(); + picojson::object::const_iterator itEnd = sampler_object.end(); for (; it != itEnd; it++) { - const picojson::object &s = it->get(); + // Skip non-objects + if (!it->second.is()) continue; + + const picojson::object &s = it->second.get(); AnimationSampler sampler; - double inputIndex = -1.0; - double outputIndex = -1.0; - if (!ParseNumberProperty(&inputIndex, err, s, "input", true)) { + if (!ParseStringProperty(&sampler.input, err, s, "input", true)) { if (err) { (*err) += "`input` field is missing in animation.sampler\n"; } @@ -2055,19 +2111,35 @@ static bool ParseAnimation(Animation *animation, std::string *err, } return false; } - if (!ParseNumberProperty(&outputIndex, err, s, "output", true)) { + if (!ParseStringProperty(&sampler.output, err, s, "output", true)) { if (err) { (*err) += "`output` field is missing in animation.sampler\n"; } return false; } - sampler.input = static_cast(inputIndex); - sampler.output = static_cast(outputIndex); - animation->samplers.push_back(sampler); + + animation->samplers[it->first] = 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); @@ -2099,30 +2171,7 @@ 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, +bool TinyGLTFLoader::LoadFromString(Scene *scene, std::string *err, const char *str, unsigned int length, const std::string &base_dir, unsigned int check_sections) { @@ -2136,10 +2185,16 @@ bool TinyGLTFLoader::LoadFromString(Model *model, std::string *err, return false; } - // scene is not mandatory. - //FIXME Maybe a better way to handle it than removing the code + 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; + } -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) { @@ -2148,7 +2203,7 @@ if (v.contains("scenes") && v.get("scenes").is()) { 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) { @@ -2157,7 +2212,7 @@ if (v.contains("scenes") && v.get("scenes").is()) { 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) { @@ -2166,7 +2221,7 @@ if (v.contains("scenes") && v.get("scenes").is()) { 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) { @@ -2176,7 +2231,7 @@ if (v.contains("scenes") && v.get("scenes").is()) { } if (v.contains("bufferViews") && - v.get("bufferViews").is()) { + v.get("bufferViews").is()) { // OK } else if (check_sections & REQUIRE_BUFFER_VIEWS) { if (err) { @@ -2185,184 +2240,168 @@ if (v.contains("scenes") && v.get("scenes").is()) { return false; } - model->buffers.clear(); - model->bufferViews.clear(); - model->accessors.clear(); - model->meshes.clear(); - model->nodes.clear(); - model->extensionsUsed.clear(); - model->defaultScene = -1; + scene->buffers.clear(); + scene->bufferViews.clear(); + scene->accessors.clear(); + scene->meshes.clear(); + scene->nodes.clear(); + scene->defaultScene = ""; // 0. Parse Asset if (v.contains("asset") && v.get("asset").is()) { const picojson::object &root = v.get("asset").get(); - 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()); - } + ParseAsset(&scene->asset, err, root); } // 1. Parse Buffer - if (v.contains("buffers") && v.get("buffers").is()) { - const picojson::array &root = v.get("buffers").get(); + if (v.contains("buffers") && v.get("buffers").is()) { + const picojson::object &root = v.get("buffers").get(); - picojson::array::const_iterator it(root.begin()); - picojson::array::const_iterator itEnd(root.end()); + picojson::object::const_iterator it(root.begin()); + picojson::object::const_iterator itEnd(root.end()); for (; it != itEnd; it++) { Buffer buffer; - if (!ParseBuffer(&buffer, err, it->get(), + if (!ParseBuffer(&buffer, err, (it->second).get(), base_dir, is_binary_, bin_data_, bin_size_)) { return false; } - model->buffers.push_back(buffer); + scene->buffers[it->first] = buffer; } } // 2. Parse BufferView if (v.contains("bufferViews") && - v.get("bufferViews").is()) { - const picojson::array &root = v.get("bufferViews").get(); + v.get("bufferViews").is()) { + const picojson::object &root = v.get("bufferViews").get(); - picojson::array::const_iterator it(root.begin()); - picojson::array::const_iterator itEnd(root.end()); + picojson::object::const_iterator it(root.begin()); + picojson::object::const_iterator itEnd(root.end()); for (; it != itEnd; it++) { BufferView bufferView; if (!ParseBufferView(&bufferView, err, - it->get())) { + (it->second).get())) { return false; } - model->bufferViews.push_back(bufferView); + scene->bufferViews[it->first] = bufferView; } } // 3. Parse Accessor - if (v.contains("accessors") && v.get("accessors").is()) { - const picojson::array &root = v.get("accessors").get(); + if (v.contains("accessors") && v.get("accessors").is()) { + const picojson::object &root = v.get("accessors").get(); - picojson::array::const_iterator it(root.begin()); - picojson::array::const_iterator itEnd(root.end()); + picojson::object::const_iterator it(root.begin()); + picojson::object::const_iterator itEnd(root.end()); for (; it != itEnd; it++) { Accessor accessor; if (!ParseAccessor(&accessor, err, - it->get())) { + (it->second).get())) { return false; } - model->accessors.push_back(accessor); + scene->accessors[it->first] = accessor; } } // 4. Parse Mesh - if (v.contains("meshes") && v.get("meshes").is()) { - const picojson::array &root = v.get("meshes").get(); + if (v.contains("meshes") && v.get("meshes").is()) { + const picojson::object &root = v.get("meshes").get(); - picojson::array::const_iterator it(root.begin()); - picojson::array::const_iterator itEnd(root.end()); + picojson::object::const_iterator it(root.begin()); + picojson::object::const_iterator itEnd(root.end()); for (; it != itEnd; it++) { Mesh mesh; - if (!ParseMesh(&mesh, err, it->get())) { + if (!ParseMesh(&mesh, err, (it->second).get())) { return false; } - model->meshes.push_back(mesh); + scene->meshes[it->first] = mesh; } } // 5. Parse Node - if (v.contains("nodes") && v.get("nodes").is()) { - const picojson::array &root = v.get("nodes").get(); + if (v.contains("nodes") && v.get("nodes").is()) { + const picojson::object &root = v.get("nodes").get(); - picojson::array::const_iterator it(root.begin()); - picojson::array::const_iterator itEnd(root.end()); + picojson::object::const_iterator it(root.begin()); + picojson::object::const_iterator itEnd(root.end()); for (; it != itEnd; it++) { Node node; - if (!ParseNode(&node, err, it->get())) { + if (!ParseNode(&node, err, (it->second).get())) { return false; } - model->nodes.push_back(node); + scene->nodes[it->first] = node; } } // 6. Parse scenes. - if (v.contains("scenes") && v.get("scenes").is()) { - const picojson::array &root = v.get("scenes").get(); + if (v.contains("scenes") && v.get("scenes").is()) { + const picojson::object &root = v.get("scenes").get(); - picojson::array::const_iterator it(root.begin()); - picojson::array::const_iterator itEnd(root.end()); + picojson::object::const_iterator it(root.begin()); + picojson::object::const_iterator itEnd(root.end()); for (; it != itEnd; it++) { - if (!(it->is())) { + if (!((it->second).is())) { if (err) { (*err) += "`scenes' does not contain an object."; } return false; } - const picojson::object &o = it->get(); - std::vector nodes; - if (!ParseNumberArrayProperty(&nodes, err, o, "nodes", false)) { + const picojson::object &o = (it->second).get(); + std::vector nodes; + if (!ParseStringArrayProperty(&nodes, err, o, "nodes", false)) { return false; } - Scene scene; - ParseStringProperty(&scene.name, err, o, "name", false); - std::vector nodesIds(nodes.begin(), nodes.end()); - scene.nodes = nodesIds; - - model->scenes.push_back(scene); + scene->scenes[it->first] = nodes; } } // 7. Parse default scenes. - if (v.contains("scene") && v.get("scene").is()) { - const int defaultScene = v.get("scene").get(); + if (v.contains("scene") && v.get("scene").is()) { + const std::string defaultScene = v.get("scene").get(); - model->defaultScene = static_cast(defaultScene); + scene->defaultScene = defaultScene; } // 8. Parse Material - 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()); + 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()); for (; it != itEnd; it++) { - picojson::object jsonMaterial = it->get(); - Material material; - ParseStringProperty(&material.name, err, jsonMaterial, "name", false); - - if (!ParseMaterial(&material, err, jsonMaterial)) { + if (!ParseMaterial(&material, err, + (it->second).get())) { return false; } - model->materials.push_back(material); + scene->materials[it->first] = material; } } // 9. Parse Image - if (v.contains("images") && v.get("images").is()) { - const picojson::array &root = v.get("images").get(); + if (v.contains("images") && v.get("images").is()) { + const picojson::object &root = v.get("images").get(); - picojson::array::const_iterator it(root.begin()); - picojson::array::const_iterator itEnd(root.end()); + picojson::object::const_iterator it(root.begin()); + picojson::object::const_iterator itEnd(root.end()); for (; it != itEnd; it++) { Image image; - if (!ParseImage(&image, err, it->get(), + if (!ParseImage(&image, err, (it->second).get(), base_dir, is_binary_, bin_data_, bin_size_)) { return false; } - if (image.bufferView != -1) { + if (!image.bufferView.empty()) { // Load image from the buffer view. - if ((size_t)image.bufferView >= model->bufferViews.size()) { + if (scene->bufferViews.find(image.bufferView) == + scene->bufferViews.end()) { if (err) { std::stringstream ss; ss << "bufferView \"" << image.bufferView @@ -2372,8 +2411,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 = scene->bufferViews[image.bufferView]; + const Buffer &buffer = scene->buffers[bufferView.buffer]; bool ret = LoadImageData(&image, err, image.width, image.height, &buffer.data[bufferView.byteOffset], @@ -2383,80 +2422,113 @@ if (v.contains("scenes") && v.get("scenes").is()) { } } - model->images.push_back(image); + scene->images[it->first] = image; } } // 10. Parse Texture - if (v.contains("textures") && v.get("textures").is()) { - const picojson::array &root = v.get("textures").get(); + if (v.contains("textures") && v.get("textures").is()) { + const picojson::object &root = v.get("textures").get(); - picojson::array::const_iterator it(root.begin()); - picojson::array::const_iterator itEnd(root.end()); + picojson::object::const_iterator it(root.begin()); + picojson::object::const_iterator itEnd(root.end()); for (; it != itEnd; it++) { Texture texture; - if (!ParseTexture(&texture, err, it->get(), + if (!ParseTexture(&texture, err, (it->second).get(), base_dir)) { return false; } - model->textures.push_back(texture); + scene->textures[it->first] = texture; } } - // 11. Parse Animation - if (v.contains("animations") && v.get("animations").is()) { - const picojson::array &root = v.get("animations").get(); + // 11. Parse Shader + if (v.contains("shaders") && v.get("shaders").is()) { + const picojson::object &root = v.get("shaders").get(); - picojson::array::const_iterator it(root.begin()); - picojson::array::const_iterator itEnd(root.end()); + 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 + 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()); for (; it != itEnd; ++it) { Animation animation; if (!ParseAnimation(&animation, err, - it->get())) { + (it->second).get())) { return false; } - model->animations.push_back(animation); + scene->animations[it->first] = animation; } } - // 12. Parse Skin - if (v.contains("skins") && v.get("skins").is()) { - const picojson::array &root = v.get("skins").get(); + // 15. Parse Sampler + if (v.contains("samplers") && v.get("samplers").is()) { + const picojson::object &root = v.get("samplers").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(); - - picojson::array::const_iterator it(root.begin()); - picojson::array::const_iterator itEnd(root.end()); + picojson::object::const_iterator it(root.begin()); + picojson::object::const_iterator itEnd(root.end()); for (; it != itEnd; ++it) { Sampler sampler; - if (!ParseSampler(&sampler, err, it->get())) { + if (!ParseSampler(&sampler, err, (it->second).get())) { return false; } - model->samplers.push_back(sampler); + scene->samplers[it->first] = sampler; } } return true; } -bool TinyGLTFLoader::LoadASCIIFromString(Model *model, std::string *err, +bool TinyGLTFLoader::LoadASCIIFromString(Scene *scene, std::string *err, const char *str, unsigned int length, const std::string &base_dir, unsigned int check_sections) { @@ -2464,10 +2536,10 @@ bool TinyGLTFLoader::LoadASCIIFromString(Model *model, std::string *err, bin_data_ = NULL; bin_size_ = 0; - return LoadFromString(model, err, str, length, base_dir, check_sections); + return LoadFromString(scene, err, str, length, base_dir, check_sections); } -bool TinyGLTFLoader::LoadASCIIFromFile(Model *model, std::string *err, +bool TinyGLTFLoader::LoadASCIIFromFile(Scene *scene, std::string *err, const std::string &filename, unsigned int check_sections) { std::stringstream ss; @@ -2498,14 +2570,14 @@ bool TinyGLTFLoader::LoadASCIIFromFile(Model *model, std::string *err, std::string basedir = GetBaseDir(filename); - bool ret = LoadASCIIFromString(model, err, &buf.at(0), + bool ret = LoadASCIIFromString(scene, err, &buf.at(0), static_cast(buf.size()), basedir, check_sections); return ret; } -bool TinyGLTFLoader::LoadBinaryFromMemory(Model *model, std::string *err, +bool TinyGLTFLoader::LoadBinaryFromMemory(Scene *scene, std::string *err, const unsigned char *bytes, unsigned int size, const std::string &base_dir, @@ -2529,21 +2601,21 @@ bool TinyGLTFLoader::LoadBinaryFromMemory(Model *model, std::string *err, unsigned int version; // 4 bytes unsigned int length; // 4 bytes - unsigned int model_length; // 4 bytes - unsigned int model_format; // 4 bytes; + unsigned int scene_length; // 4 bytes + unsigned int scene_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(&model_length, bytes + 12, 4); - swap4(&model_length); - memcpy(&model_format, bytes + 16, 4); - swap4(&model_format); + memcpy(&scene_length, bytes + 12, 4); + swap4(&scene_length); + memcpy(&scene_format, bytes + 16, 4); + swap4(&scene_format); - if ((20 + model_length >= size) || (model_length < 1) || - (model_format != 0)) { // 0 = JSON format. + if ((20 + scene_length >= size) || (scene_length < 1) || + (scene_format != 0)) { // 0 = JSON format. if (err) { (*err) = "Invalid glTF binary."; } @@ -2552,16 +2624,16 @@ bool TinyGLTFLoader::LoadBinaryFromMemory(Model *model, std::string *err, // Extract JSON string. std::string jsonString(reinterpret_cast(&bytes[20]), - model_length); + scene_length); is_binary_ = true; - bin_data_ = bytes + 20 + model_length; + bin_data_ = bytes + 20 + scene_length; bin_size_ = - length - (20 + model_length); // extract header + JSON scene data. + length - (20 + scene_length); // extract header + JSON scene data. bool ret = - LoadFromString(model, err, reinterpret_cast(&bytes[20]), - model_length, base_dir, check_sections); + LoadFromString(scene, err, reinterpret_cast(&bytes[20]), + scene_length, base_dir, check_sections); if (!ret) { return ret; } @@ -2569,7 +2641,7 @@ bool TinyGLTFLoader::LoadBinaryFromMemory(Model *model, std::string *err, return true; } -bool TinyGLTFLoader::LoadBinaryFromFile(Model *model, std::string *err, +bool TinyGLTFLoader::LoadBinaryFromFile(Scene *scene, std::string *err, const std::string &filename, unsigned int check_sections) { std::stringstream ss; @@ -2594,7 +2666,7 @@ bool TinyGLTFLoader::LoadBinaryFromFile(Model *model, std::string *err, std::string basedir = GetBaseDir(filename); bool ret = LoadBinaryFromMemory( - model, err, reinterpret_cast(&buf.at(0)), + scene, err, reinterpret_cast(&buf.at(0)), static_cast(buf.size()), basedir, check_sections); return ret;