From 5307850555fa07cc17065e1fe9a23a410e74dc48 Mon Sep 17 00:00:00 2001 From: Syoyo Fujita Date: Wed, 21 Jun 2017 19:27:18 +0900 Subject: [PATCH 01/14] Update README. --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 61b0ed5..f9e0f80 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # Header only C++ tiny glTF library(loader/saver). -`TinyGLTF` is a header only C++ glTF https://github.com/KhronosGroup/glTF library. +**NOTICE! Tiny glTF is still in development and does not provide official release at the morment. Please take a look at `devel` branch** + +`TinyGLTF` is a header only C++ glTF 2.0 https://github.com/KhronosGroup/glTF library. ![](images/glview_duck.png) From 57f8e7ca3ba5c402b180ffde2aef547a10d2f790 Mon Sep 17 00:00:00 2001 From: Syoyo Fujita Date: Mon, 4 Jun 2018 17:52:08 +0900 Subject: [PATCH 02/14] Correctly handle filename containing spaces for external resources. Fixes #74. --- experimental/README.md | 15 +++++++++++++++ experimental/gen.py | 34 ++++++++++++++++++++++++++++++++++ tiny_gltf_loader.h | 10 ++++++---- 3 files changed, 55 insertions(+), 4 deletions(-) create mode 100644 experimental/README.md create mode 100644 experimental/gen.py diff --git a/experimental/README.md b/experimental/README.md new file mode 100644 index 0000000..cf8f21e --- /dev/null +++ b/experimental/README.md @@ -0,0 +1,15 @@ +# Python script which generates C++11 code from JSON schema. + +## Requirements + +* python3 +* jsonref + +## Generate + +Run `gen.py` by specifing the path to glTF schema directory(from https://github.com/KhronosGroup/glTF.git) + +``` +$ python gen.py /path/to/glTF/specification/2.0/schema +``` + diff --git a/experimental/gen.py b/experimental/gen.py new file mode 100644 index 0000000..25b0484 --- /dev/null +++ b/experimental/gen.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import sys, os +import subprocess +import json +from pprint import pprint +import jsonref + +# glTF 2.0 +schema_files = [ + "glTF.schema.json" +] + +def main(): + if len(sys.argv) < 2: + print("Requires path to glTF scheme directory.") + sys.exit(-1) + + gltf_schema_dir = sys.argv[1] + + gltf_schema_filepath = os.path.join(gltf_schema_dir, schema_files[0]) + if not os.path.exists(gltf_schema_filepath): + print("File not found: {}".format(gltf_schema_filepath)) + sys.exit(-1) + + gltf_schema_uri = 'file://{}/'.format(gltf_schema_dir) + with open(gltf_schema_filepath) as schema_file: + j = jsonref.loads(schema_file.read(), base_uri=gltf_schema_uri, jsonschema=True) + pprint(j) + + + +main() diff --git a/tiny_gltf_loader.h b/tiny_gltf_loader.h index 90e02f3..6e55276 100644 --- a/tiny_gltf_loader.h +++ b/tiny_gltf_loader.h @@ -733,15 +733,17 @@ static std::string ExpandFilePath(const std::string &filepath) { } // char** w; - int ret = wordexp(filepath.c_str(), &p, 0); + // wrap filepath by quotes to avoid splitting file path when the path contains spaces(more precisely, $IFS environment variables). + std::string quoted_filepath = "\"" + filepath + "\""; + int ret = wordexp(quoted_filepath.c_str(), &p, 0); if (ret) { // err s = filepath; return s; } - // Use first element only. if (p.we_wordv) { + // Use first item. s = std::string(p.we_wordv[0]); wordfree(&p); } else { @@ -902,7 +904,7 @@ static bool LoadExternalFile(std::vector *out, std::string *err, std::string filepath = FindFile(paths, filename); if (filepath.empty()) { if (err) { - (*err) += "File not found : " + filename + "\n"; + (*err) += "File not found : \"" + filename + "\"\n"; } return false; } @@ -910,7 +912,7 @@ static bool LoadExternalFile(std::vector *out, std::string *err, std::ifstream f(filepath.c_str(), std::ifstream::binary); if (!f) { if (err) { - (*err) += "File open error : " + filepath + "\n"; + (*err) += "File open error : \"" + filepath + "\"\n"; } return false; } From 0067a9e43a60cd3dbdccfad5db33c5b22df63f06 Mon Sep 17 00:00:00 2001 From: Syoyo Fujita Date: Mon, 4 Jun 2018 18:26:05 +0900 Subject: [PATCH 03/14] Support `gltf-buffer` mime. Make `min` and `max` parameters in `Accessor` optional. --- tiny_gltf_loader.h | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/tiny_gltf_loader.h b/tiny_gltf_loader.h index 6e55276..0389a8d 100644 --- a/tiny_gltf_loader.h +++ b/tiny_gltf_loader.h @@ -1010,6 +1010,14 @@ static bool IsDataURI(const std::string &in) { return true; } + // NOTE(syoyo) `gltf-buffer` is still in draft as of Jun 4, 2018, + // but some glTF sample model uses `gltf-buffer` so we deal with it. + // https://github.com/KhronosGroup/glTF/pull/1180 + header = "data:application/gltf-buffer;base64,"; + if (in.find(header) == 0) { + return true; + } + header = "data:image/png;base64,"; if (in.find(header) == 0) { return true; @@ -1037,6 +1045,13 @@ static bool DecodeDataURI(std::vector *out, data = base64_decode(in.substr(header.size())); // cut mime string. } + if (data.empty()) { + header = "data:application/gltf-buffer;base64,"; + if (in.find(header) == 0) { + data = base64_decode(in.substr(header.size())); // cut mime string. + } + } + if (data.empty()) { header = "data:image/jpeg;base64,"; if (in.find(header) == 0) { @@ -1662,11 +1677,11 @@ static bool ParseAccessor(Accessor *accessor, std::string *err, accessor->minValues.clear(); accessor->maxValues.clear(); - if(!ParseNumberArrayProperty(&accessor->minValues, err, o, "min", true, "Accessor")) { + if(!ParseNumberArrayProperty(&accessor->minValues, err, o, "min", false, "Accessor")) { return false; } - if(!ParseNumberArrayProperty(&accessor->maxValues, err, o, "max", true, "Accessor")) { + if(!ParseNumberArrayProperty(&accessor->maxValues, err, o, "max", false, "Accessor")) { return false; } From 4769b1ca3799bf12a8e1e260ff9f13587f16e27b Mon Sep 17 00:00:00 2001 From: Syoyo Fujita Date: Mon, 4 Jun 2018 18:40:16 +0900 Subject: [PATCH 04/14] Apply clang-format. --- tiny_gltf_loader.h | 362 +++++++++++++++++++++------------------------ 1 file changed, 166 insertions(+), 196 deletions(-) diff --git a/tiny_gltf_loader.h b/tiny_gltf_loader.h index 0389a8d..1aca76d 100644 --- a/tiny_gltf_loader.h +++ b/tiny_gltf_loader.h @@ -4,7 +4,8 @@ // // The MIT License (MIT) // -// Copyright (c) 2015 - 2017 Syoyo Fujita, AurĂ©lien Chatelain 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 @@ -286,29 +287,22 @@ typedef struct { 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"] + 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() - : sampler(-1) - , target_node(-1) - { - } + AnimationChannel() : sampler(-1), target_node(-1) {} }; struct AnimationSampler { - int input; // required - int output; // required - std::string interpolation; // in ["LINEAR", "STEP", "CATMULLROMSPLINE", "CUBICSPLINE"], default "LINEAR" + int input; // required + int output; // required + std::string interpolation; // in ["LINEAR", "STEP", "CATMULLROMSPLINE", + // "CUBICSPLINE"], default "LINEAR" - AnimationSampler() - : input(-1) - , output(-1) - , interpolation("LINEAR") - { - } + AnimationSampler() : input(-1), output(-1), interpolation("LINEAR") {} }; typedef struct { @@ -320,61 +314,53 @@ typedef struct { 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 + 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; - } + 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 wrapR; // TinyGLTF extension + 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() - : wrapS(TINYGLTF_TEXTURE_WRAP_RPEAT) - , wrapT(TINYGLTF_TEXTURE_WRAP_RPEAT) - { - } + : wrapS(TINYGLTF_TEXTURE_WRAP_RPEAT), + wrapT(TINYGLTF_TEXTURE_WRAP_RPEAT) {} }; -struct Image{ +struct Image { 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) + 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() - { - bufferView = -1; - } + Image() { bufferView = -1; } }; struct Texture { int sampler; - int source; // Required (not specified in the spec ?) + int source; // Required (not specified in the spec ?) Value extras; - Texture() - : sampler(-1) - , source(-1) - { - } + Texture() : sampler(-1), source(-1) {} }; // Each extension should be stored in a ParameterMap. @@ -383,47 +369,41 @@ struct Texture { struct Material { std::string name; - ParameterMap values; // PBR metal/roughness workflow - ParameterMap additionalValues; // normal/occlusion/emissive values - ParameterMap extCommonValues; // KHR_common_material extension + ParameterMap values; // PBR metal/roughness workflow + ParameterMap additionalValues; // normal/occlusion/emissive values + ParameterMap extCommonValues; // KHR_common_material extension ParameterMap extPBRValues; Value extras; }; -struct BufferView{ +struct BufferView { std::string name; - int buffer; // Required - size_t byteOffset; // minimum 0, default 0 - size_t byteLength; // required, minimum 1 + 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 target; // ["ARRAY_BUFFER", "ELEMENT_ARRAY_BUFFER"] int pad0; Value extras; - BufferView() - : byteOffset(0) - , byteStride(4) - {} - + BufferView() : byteOffset(0), byteStride(4) {} }; struct Accessor { - int bufferView; // optional in spec but required here since sparse accessor are not supported + 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; // (required) One of TINYGLTF_COMPONENT_TYPE_*** - size_t count; // required - int type; // (required) One of TINYGLTF_TYPE_*** .. + size_t count; // required + int type; // (required) One of TINYGLTF_TYPE_*** .. Value extras; std::vector minValues; // required std::vector maxValues; // required - Accessor() - { - bufferView = -1; - } + Accessor() { bufferView = -1; } }; class Camera { @@ -435,16 +415,16 @@ class Camera { bool isOrthographic; // false = perspective. // Orthographic properties - float xMag; // required - float yMag; // required - float zFar; // required - float zNear; //required + float xMag; // required + float yMag; // required + float zFar; // required + float zNear; // required // Perspective properties float aspectRatio; - float yfov; // required + float yfov; // required float zfar; - float znear; // required + float znear; // required ParameterMap extensions; Value extras; @@ -456,16 +436,17 @@ struct Primitive { // is the index of the accessor // containing an attribute. int material; // The index of the material to apply to this primitive - // when rendering. + // 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 + 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() - { + Primitive() { material = -1; indices = -1; } @@ -474,19 +455,15 @@ struct Primitive { typedef struct { std::string name; std::vector primitives; - std::vector weights; // weights to be applied to the Morph Targets - std::vector >targets; + std::vector weights; // weights to be applied to the Morph Targets + std::vector > targets; ParameterMap extensions; Value extras; } Mesh; class Node { public: - Node() - : skin(-1) - , mesh(-1) - { - } + Node() : skin(-1), mesh(-1) {} ~Node() {} @@ -500,7 +477,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 weights; // The weights of the instantiated Morph Target + std::vector weights; // The weights of the instantiated Morph Target Value extras; }; @@ -508,12 +485,13 @@ 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) + 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 version; // required std::string generator; std::string minVersion; std::string copyright; @@ -733,8 +711,9 @@ static std::string ExpandFilePath(const std::string &filepath) { } // char** w; - // wrap filepath by quotes to avoid splitting file path when the path contains spaces(more precisely, $IFS environment variables). - std::string quoted_filepath = "\"" + filepath + "\""; + // wrap filepath by quotes to avoid splitting file path when the path contains + // spaces(more precisely, $IFS environment variables). + std::string quoted_filepath = "\"" + filepath + "\""; int ret = wordexp(quoted_filepath.c_str(), &p, 0); if (ret) { // err @@ -921,6 +900,9 @@ static bool LoadExternalFile(std::vector *out, std::string *err, size_t sz = static_cast(f.tellg()); if (int(sz) < 0) { // Looks reading directory, not a file. + if (err) { + (*err) += "Looks like filepath is a directory : \"" + filepath + "\"\n"; + } return false; } std::vector buf(sz); @@ -955,8 +937,10 @@ static bool LoadImageData(Image *image, std::string *err, int req_width, 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) + // 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) { @@ -1164,7 +1148,9 @@ static bool ParseBooleanProperty(bool *ret, std::string *err, static bool ParseNumberProperty(double *ret, std::string *err, const picojson::object &o, - const std::string &property, const bool required, const std::string &parent_node = "") { + const std::string &property, + const bool required, + const std::string &parent_node = "") { picojson::object::const_iterator it = o.find(property); if (it == o.end()) { if (required) { @@ -1197,8 +1183,7 @@ static bool ParseNumberProperty(double *ret, std::string *err, static bool ParseNumberArrayProperty(std::vector *ret, std::string *err, const picojson::object &o, - const std::string &property, - bool required, + const std::string &property, bool required, const std::string &parent_node = "") { picojson::object::const_iterator it = o.find(property); if (it == o.end()) { @@ -1328,23 +1313,20 @@ static bool ParseStringIntProperty(std::map *ret, return true; } -static bool ParseJSONProperty(std::map *ret, std::string *err, - const picojson::object &o, - const std::string &property, - bool required) -{ +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 (it == o.end()) { if (required) { - if(err) { + if (err) { (*err) += "'" + property + "' property is missing. \n'"; } } return false; } - if(!it->second.is()) { + if (!it->second.is()) { if (required) { if (err) { (*err) += "'" + property + "' property is not a JSON object.\n"; @@ -1358,8 +1340,9 @@ static bool ParseJSONProperty(std::map *ret, std::string *e 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())); + if (it2->second.is()) + ret->insert(std::pair(it2->first, + it2->second.get())); } return true; @@ -1383,7 +1366,8 @@ static bool ParseImage(Image *image, std::string *err, 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); + bool isEmbedded = + ParseNumberProperty(&bufferView, err, o, "bufferView", true); isEmbedded = isEmbedded && static_cast(bufferView) != -1; std::string uri; @@ -1508,11 +1492,10 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, ParseStringProperty(&uri, err, o, "uri", false, "Buffer"); // having an empty uri for a non embedded image should not be valid - if(!is_binary && uri.empty()) - { - if (err) { - (*err) += "'uri' is missing from non binary glTF file buffer.\n"; - } + if (!is_binary && uri.empty()) { + if (err) { + (*err) += "'uri' is missing from non binary glTF file buffer.\n"; + } } picojson::object::const_iterator type = o.find("type"); @@ -1529,13 +1512,10 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, if (is_binary) { // Still binary glTF accepts external dataURI. First try external resources. - if(!uri.empty()) - { + if (!uri.empty()) { // External .bin file. LoadExternalFile(&buffer->data, err, uri, basedir, bytes, true); - } - else - { + } else { // load data from (embedded) binary data if ((bin_size == 0) || (bin_data == NULL)) { @@ -1558,8 +1538,7 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, // Read buffer data buffer->data.resize(static_cast(byteLength)); - memcpy(&(buffer->data.at(0)), bin_data, - static_cast(byteLength)); + memcpy(&(buffer->data.at(0)), bin_data, static_cast(byteLength)); } } else { @@ -1594,7 +1573,8 @@ static bool ParseBufferView(BufferView *bufferView, std::string *err, ParseNumberProperty(&byteOffset, err, o, "byteOffset", false); double byteLength = 1.0; - if(!ParseNumberProperty(&byteLength, err, o, "byteLength", true, "BufferView")) { + if (!ParseNumberProperty(&byteLength, err, o, "byteLength", true, + "BufferView")) { return false; } @@ -1625,7 +1605,8 @@ static bool ParseBufferView(BufferView *bufferView, std::string *err, static bool ParseAccessor(Accessor *accessor, std::string *err, const picojson::object &o) { double bufferView = -1.0; - if (!ParseNumberProperty(&bufferView, err, o, "bufferView", true, "Accessor")) { + if (!ParseNumberProperty(&bufferView, err, o, "bufferView", true, + "Accessor")) { return false; } @@ -1633,7 +1614,8 @@ static bool ParseAccessor(Accessor *accessor, std::string *err, ParseNumberProperty(&byteOffset, err, o, "byteOffset", false, "Accessor"); double componentType = 0.0; - if (!ParseNumberProperty(&componentType, err, o, "componentType", true, "Accessor")) { + if (!ParseNumberProperty(&componentType, err, o, "componentType", true, + "Accessor")) { return false; } @@ -1677,13 +1659,11 @@ static bool ParseAccessor(Accessor *accessor, std::string *err, accessor->minValues.clear(); accessor->maxValues.clear(); - if(!ParseNumberArrayProperty(&accessor->minValues, err, o, "min", false, "Accessor")) { - return false; - } + ParseNumberArrayProperty(&accessor->minValues, err, o, "min", false, + "Accessor"); - if(!ParseNumberArrayProperty(&accessor->maxValues, err, o, "max", false, "Accessor")) { - return false; - } + ParseNumberArrayProperty(&accessor->maxValues, err, o, "max", false, + "Accessor"); accessor->count = static_cast(count); accessor->bufferView = static_cast(bufferView); @@ -1721,7 +1701,7 @@ static bool ParsePrimitive(Primitive *primitive, std::string *err, ParseNumberProperty(&mode, err, o, "mode", false); int primMode = static_cast(mode); - primitive->mode = primMode; // Why only triangled were supported ? + primitive->mode = primMode; // Why only triangled were supported ? double indices = -1.0; ParseNumberProperty(&indices, err, o, "indices", false); @@ -1756,7 +1736,8 @@ 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()) { + if ((targetsObject != o.end()) && + (targetsObject->second).is()) { const picojson::array &targetArray = (targetsObject->second).get(); for (size_t i = 0; i < targetArray.size(); i++) { @@ -1767,7 +1748,8 @@ static bool ParseMesh(Mesh *mesh, std::string *err, const picojson::object &o) { picojson::object::const_iterator dictItEnd(dict.end()); for (; dictIt != dictItEnd; ++dictIt) { - targetAttribues[dictIt->first] = static_cast(dictIt->second.get()); + targetAttribues[dictIt->first] = + static_cast(dictIt->second.get()); } mesh->targets.push_back(targetAttribues); } @@ -1789,8 +1771,7 @@ static bool ParseNode(Node *node, std::string *err, const picojson::object &o) { node->skin = static_cast(skin); // Matrix and T/R/S are exclusive - if(!ParseNumberArrayProperty(&node->matrix, err, o, "matrix", false)) { - + 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); @@ -1817,7 +1798,8 @@ static bool ParseNode(Node *node, std::string *err, const picojson::object &o) { } return false; } - const int &childrenNode = static_cast(childrenArray[i].get()); + const int &childrenNode = + static_cast(childrenArray[i].get()); node->children.push_back(childrenNode); } } @@ -1847,9 +1829,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)) { + } else if (ParseJSONProperty(¶m->json_double_value, err, o, prop, + false)) { return true; - } else if(ParseBooleanProperty(¶m->bool_value, err, o, prop, false)) { + } else if (ParseBooleanProperty(¶m->bool_value, err, o, prop, false)) { return true; } else { if (required) { @@ -1862,8 +1845,7 @@ static bool ParseParameterProperty(Parameter *param, std::string *err, } static bool ParseMaterial(Material *material, std::string *err, - const picojson::object &o) { - + const picojson::object &o) { material->values.clear(); material->extPBRValues.clear(); material->additionalValues.clear(); @@ -1872,8 +1854,7 @@ static bool ParseMaterial(Material *material, std::string *err, picojson::object::const_iterator itEnd(o.end()); for (; it != itEnd; it++) { - if(it->first == "pbrMetallicRoughness") - { + if (it->first == "pbrMetallicRoughness") { if ((it->second).is()) { const picojson::object &values_object = (it->second).get(); @@ -1889,40 +1870,35 @@ static bool ParseMaterial(Material *material, std::string *err, } } } - } - else if(it->first == "extensions") - { + } else if (it->first == "extensions") { if ((it->second).is()) { - const picojson::object &extension = (it->second).get(); + const picojson::object &extension = + (it->second).get(); - picojson::object::const_iterator extIt = extension.begin(); - if(!extIt->second.is()) - continue; + picojson::object::const_iterator extIt = extension.begin(); + if (!extIt->second.is()) continue; - const picojson::object &values_object = - (extIt->second).get(); + const picojson::object &values_object = + (extIt->second).get(); - picojson::object::const_iterator itVal(values_object.begin()); - picojson::object::const_iterator itValEnd(values_object.end()); + picojson::object::const_iterator itVal(values_object.begin()); + picojson::object::const_iterator itValEnd(values_object.end()); - for (; itVal != itValEnd; itVal++) { - Parameter param; - if (ParseParameterProperty(¶m, err, values_object, itVal->first, - false)) { - material->extPBRValues[itVal->first] = param; + for (; itVal != itValEnd; 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; - } + } else { + Parameter param; + if (ParseParameterProperty(¶m, err, o, it->first, false)) { + material->additionalValues[it->first] = param; } } + } ParseExtrasProperty(&(material->extras), o); @@ -1945,8 +1921,7 @@ static bool ParseAnimationChannel(AnimationChannel *channel, std::string *err, const picojson::object &target_object = (targetIt->second).get(); - if (!ParseNumberProperty(&targetIndex, err, target_object, "node", - true)) { + if (!ParseNumberProperty(&targetIndex, err, target_object, "node", true)) { if (err) { (*err) += "`id` field is missing in animation.channels.target\n"; } @@ -2060,9 +2035,7 @@ static bool ParseSampler(Sampler *sampler, std::string *err, return true; } -static bool ParseSkin(Skin *skin, std::string *err, - const picojson::object &o) { - +static bool ParseSkin(Skin *skin, std::string *err, const picojson::object &o) { ParseStringProperty(&skin->name, err, o, "name", false, "Skin"); std::vector joints; @@ -2098,9 +2071,9 @@ bool TinyGLTFLoader::LoadFromString(Model *model, std::string *err, } // scene is not mandatory. - //FIXME Maybe a better way to handle it than removing the code + // 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) { @@ -2136,8 +2109,7 @@ if (v.contains("scenes") && v.get("scenes").is()) { return false; } - if (v.contains("bufferViews") && - v.get("bufferViews").is()) { + if (v.contains("bufferViews") && v.get("bufferViews").is()) { // OK } else if (check_sections & REQUIRE_BUFFER_VIEWS) { if (err) { @@ -2162,10 +2134,11 @@ if (v.contains("scenes") && v.get("scenes").is()) { } // 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) - { + 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()); } } @@ -2178,8 +2151,8 @@ if (v.contains("scenes") && v.get("scenes").is()) { picojson::array::const_iterator itEnd(root.end()); for (; it != itEnd; it++) { Buffer buffer; - if (!ParseBuffer(&buffer, err, it->get(), - base_dir, is_binary_, bin_data_, bin_size_)) { + if (!ParseBuffer(&buffer, err, it->get(), base_dir, + is_binary_, bin_data_, bin_size_)) { return false; } @@ -2187,17 +2160,16 @@ if (v.contains("scenes") && v.get("scenes").is()) { } } + // 2. Parse BufferView - if (v.contains("bufferViews") && - v.get("bufferViews").is()) { + if (v.contains("bufferViews") && v.get("bufferViews").is()) { const picojson::array &root = v.get("bufferViews").get(); 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->get())) { + if (!ParseBufferView(&bufferView, err, it->get())) { return false; } @@ -2213,8 +2185,7 @@ if (v.contains("scenes") && v.get("scenes").is()) { picojson::array::const_iterator itEnd(root.end()); for (; it != itEnd; it++) { Accessor accessor; - if (!ParseAccessor(&accessor, err, - it->get())) { + if (!ParseAccessor(&accessor, err, it->get())) { return false; } @@ -2316,8 +2287,8 @@ if (v.contains("scenes") && v.get("scenes").is()) { picojson::array::const_iterator itEnd(root.end()); for (; it != itEnd; it++) { Image image; - if (!ParseImage(&image, err, it->get(), - base_dir, is_binary_, bin_data_, bin_size_)) { + if (!ParseImage(&image, err, it->get(), base_dir, + is_binary_, bin_data_, bin_size_)) { return false; } @@ -2333,7 +2304,8 @@ if (v.contains("scenes") && v.get("scenes").is()) { return false; } - const BufferView &bufferView = model->bufferViews[size_t(image.bufferView)]; + 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, @@ -2356,8 +2328,7 @@ if (v.contains("scenes") && v.get("scenes").is()) { picojson::array::const_iterator itEnd(root.end()); for (; it != itEnd; it++) { Texture texture; - if (!ParseTexture(&texture, err, it->get(), - base_dir)) { + if (!ParseTexture(&texture, err, it->get(), base_dir)) { return false; } @@ -2373,8 +2344,7 @@ if (v.contains("scenes") && v.get("scenes").is()) { picojson::array::const_iterator itEnd(root.end()); for (; it != itEnd; ++it) { Animation animation; - if (!ParseAnimation(&animation, err, - it->get())) { + if (!ParseAnimation(&animation, err, it->get())) { return false; } @@ -2390,8 +2360,7 @@ if (v.contains("scenes") && v.get("scenes").is()) { picojson::array::const_iterator itEnd(root.end()); for (; it != itEnd; ++it) { Skin skin; - if (!ParseSkin(&skin, err, - it->get())) { + if (!ParseSkin(&skin, err, it->get())) { return false; } @@ -2516,7 +2485,8 @@ bool TinyGLTFLoader::LoadBinaryFromMemory(Model *model, std::string *err, model_length); is_binary_ = true; - bin_data_ = bytes + 20 + model_length + 8; // 4 bytes (buffer_length) + 4 bytes(buffer_format) + bin_data_ = bytes + 20 + model_length + + 8; // 4 bytes (buffer_length) + 4 bytes(buffer_format) bin_size_ = length - (20 + model_length); // extract header + JSON scene data. From dfc3545d79e0cec89eab03f31c2a1f4322fd237c Mon Sep 17 00:00:00 2001 From: Syoyo Fujita Date: Wed, 22 Aug 2018 20:35:04 +0900 Subject: [PATCH 05/14] Fix unit test. Update README. --- README.md | 10 ++++++++-- tests/tester.cc | 6 ++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 734783b..5b357aa 100644 --- a/README.md +++ b/README.md @@ -96,9 +96,15 @@ using namespace tinygltf; Model model; TinyGLTF loader; std::string err; +std::string warn; -bool ret = loader.LoadASCIIFromFile(&model, &err, argv[1]); -//bool ret = loader.LoadBinaryFromFile(&model, &err, argv[1]); // for binary glTF(.glb) +bool ret = loader.LoadASCIIFromFile(&model, &err, &warn, argv[1]); +//bool ret = loader.LoadBinaryFromFile(&model, &err, &warn, argv[1]); // for binary glTF(.glb) + +if (!warn.empty()) { + printf("Warn: %s\n", warn.c_str()); +} + if (!err.empty()) { printf("Err: %s\n", err.c_str()); } diff --git a/tests/tester.cc b/tests/tester.cc index 377ea0e..ca0ced3 100644 --- a/tests/tester.cc +++ b/tests/tester.cc @@ -18,8 +18,9 @@ TEST_CASE("parse-error", "[parse]") { tinygltf::Model model; tinygltf::TinyGLTF ctx; std::string err; + std::string warn; - bool ret = ctx.LoadASCIIFromString(&model, &err, "bora", strlen("bora"), /* basedir*/ ""); + bool ret = ctx.LoadASCIIFromString(&model, &err, &warn, "bora", strlen("bora"), /* basedir*/ ""); REQUIRE(false == ret); @@ -30,8 +31,9 @@ TEST_CASE("datauri-in-glb", "[issue-79]") { tinygltf::Model model; tinygltf::TinyGLTF ctx; std::string err; + std::string warn; - bool ret = ctx.LoadBinaryFromFile(&model, &err, "../models/box01.glb"); + bool ret = ctx.LoadBinaryFromFile(&model, &err, &warn, "../models/box01.glb"); if (!err.empty()) { std::cerr << err << std::endl; } From 0d0e97e8cd0e3e0d294b622ad4de9f13f86b5d3f Mon Sep 17 00:00:00 2001 From: Selmar Kok Date: Wed, 22 Aug 2018 14:01:57 +0200 Subject: [PATCH 06/14] forward declare DataURI helper functions to allow usage outside of implementation file (in case of custom image handling) --- tiny_gltf.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tiny_gltf.h b/tiny_gltf.h index e253fce..fb8070d 100644 --- a/tiny_gltf.h +++ b/tiny_gltf.h @@ -189,6 +189,11 @@ static inline int32_t GetTypeSizeInBytes(uint32_t ty) { } } +bool IsDataURI(const std::string &in); +bool DecodeDataURI(std::vector *out, + std::string &mime_type, const std::string &in, + size_t reqBytes, bool checkSize); + #ifdef __clang__ #pragma clang diagnostic push // Suppress warning for : static Value null_value @@ -1608,7 +1613,7 @@ static void UpdateImageObject(Image &image, std::string &baseDir, int index, } } -static bool IsDataURI(const std::string &in) { +bool IsDataURI(const std::string &in) { std::string header = "data:application/octet-stream;base64,"; if (in.find(header) == 0) { return true; @@ -1647,7 +1652,7 @@ static bool IsDataURI(const std::string &in) { return false; } -static bool DecodeDataURI(std::vector *out, +bool DecodeDataURI(std::vector *out, std::string &mime_type, const std::string &in, size_t reqBytes, bool checkSize) { std::string header = "data:application/octet-stream;base64,"; From cda38e03ed8a6dc407319e1363ad710f581de662 Mon Sep 17 00:00:00 2001 From: Selmar Kok Date: Wed, 22 Aug 2018 18:26:10 +0200 Subject: [PATCH 07/14] change from warning to error for missing bin files --- tiny_gltf.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tiny_gltf.h b/tiny_gltf.h index fb8070d..d00be44 100644 --- a/tiny_gltf.h +++ b/tiny_gltf.h @@ -1257,8 +1257,8 @@ static bool LoadExternalFile(std::vector *out, std::string *err, std::string filepath = FindFile(paths, filename, fs); if (filepath.empty() || filename.empty()) { - if (warn) { - (*warn) += "File not found : " + filename + "\n"; + if (err) { + (*err) += "File not found : " + filename + "\n"; } return false; } From e3b3fa9eb663468e96f200754eed9b003501ef4f Mon Sep 17 00:00:00 2001 From: Selmar Kok Date: Wed, 22 Aug 2018 19:04:21 +0200 Subject: [PATCH 08/14] add required parameter to LoadExternalFile --- tiny_gltf.h | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/tiny_gltf.h b/tiny_gltf.h index d00be44..3d18c48 100644 --- a/tiny_gltf.h +++ b/tiny_gltf.h @@ -1238,7 +1238,7 @@ std::string base64_decode(std::string const &encoded_string) { static bool LoadExternalFile(std::vector *out, std::string *err, std::string *warn, const std::string &filename, - const std::string &basedir, size_t reqBytes, + const std::string &basedir, bool required, size_t reqBytes, bool checkSize, FsCallbacks *fs) { if (fs == nullptr || fs->FileExists == nullptr || fs->ExpandFilePath == nullptr || fs->ReadWholeFile == nullptr) { @@ -1249,6 +1249,8 @@ static bool LoadExternalFile(std::vector *out, std::string *err, return false; } + std::string* failMsgOut = required ? err : warn; + out->clear(); std::vector paths; @@ -1257,8 +1259,8 @@ static bool LoadExternalFile(std::vector *out, std::string *err, std::string filepath = FindFile(paths, filename, fs); if (filepath.empty() || filename.empty()) { - if (err) { - (*err) += "File not found : " + filename + "\n"; + if (failMsgOut) { + (*failMsgOut) += "File not found : " + filename + "\n"; } return false; } @@ -1268,15 +1270,17 @@ static bool LoadExternalFile(std::vector *out, std::string *err, bool fileRead = fs->ReadWholeFile(&buf, &fileReadErr, filepath, fs->user_data); if (!fileRead) { - if (err) { - (*err) += "File read error : " + filepath + " : " + fileReadErr + "\n"; + if (failMsgOut) { + (*failMsgOut) += "File read error : " + filepath + " : " + fileReadErr + "\n"; } return false; } size_t sz = buf.size(); if (sz == 0) { - (*err) += "File is empty : " + filepath + "\n"; + if(failMsgOut) { + (*failMsgOut) += "File is empty : " + filepath + "\n"; + } return false; } @@ -1288,8 +1292,8 @@ static bool LoadExternalFile(std::vector *out, std::string *err, std::stringstream ss; ss << "File size mismatch : " << filepath << ", requestedBytes " << reqBytes << ", but got " << sz << std::endl; - if (err) { - (*err) += ss.str(); + if (failMsgOut) { + (*failMsgOut) += ss.str(); } return false; } @@ -2171,7 +2175,7 @@ static bool ParseImage(Image *image, std::string *err, std::string *warn, #ifdef TINYGLTF_NO_EXTERNAL_IMAGE return true; #endif - if (!LoadExternalFile(&img, err, warn, uri, basedir, 0, false, fs)) { + if (!LoadExternalFile(&img, err, warn, uri, basedir, false, 0, false, fs)) { if (warn) { (*warn) += "Failed to load external 'uri' for image parameter\n"; } @@ -2266,7 +2270,7 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const json &o, } else { // External .bin file. if (!LoadExternalFile(&buffer->data, err, /* warn */ nullptr, buffer->uri, - basedir, bytes, true, fs)) { + basedir, true, bytes, true, fs)) { return false; } } @@ -2308,7 +2312,7 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const json &o, } else { // Assume external .bin file. if (!LoadExternalFile(&buffer->data, err, /* warn */ nullptr, buffer->uri, - basedir, bytes, true, fs)) { + basedir, true, bytes, true, fs)) { return false; } } From 18ef338ff5a1875e0bdbc2550a8c9460d3c2e4bc Mon Sep 17 00:00:00 2001 From: Victor Bushong Date: Wed, 22 Aug 2018 22:03:30 -0500 Subject: [PATCH 09/14] Force default image loader to use 32-bit images for Vulkan compatibility. --- tiny_gltf.h | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tiny_gltf.h b/tiny_gltf.h index 3d18c48..b12827b 100644 --- a/tiny_gltf.h +++ b/tiny_gltf.h @@ -1314,14 +1314,19 @@ bool LoadImageData(Image *image, std::string *err, std::string *warn, int size, void *) { (void)warn; - int w, h, comp; + int w, h, comp, req_comp; + + // force 32-bit textures for common Vulkan compatibility. It appears that + // some GPU drivers do not support 24-bit images for Vulkan + req_comp = 4; + // 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); + unsigned char *data = stbi_load_from_memory(bytes, size, &w, &h, &comp, req_comp); if (!data) { // NOTE: you can use `warn` instead of `err` if (err) { @@ -1360,9 +1365,9 @@ bool LoadImageData(Image *image, std::string *err, std::string *warn, image->width = w; image->height = h; - image->component = comp; - image->image.resize(static_cast(w * h * comp)); - std::copy(data, data + w * h * comp, image->image.begin()); + image->component = req_comp; + image->image.resize(static_cast(w * h * req_comp)); + std::copy(data, data + w * h * req_comp, image->image.begin()); free(data); From a8f0b1c3833603ba14f9ed9f0ae248882d38e868 Mon Sep 17 00:00:00 2001 From: Syoyo Fujita Date: Tue, 28 Aug 2018 21:33:40 +0900 Subject: [PATCH 10/14] Suppress unknown pragma warning on clang 3.7 --- tiny_gltf.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tiny_gltf.h b/tiny_gltf.h index e253fce..05624a9 100644 --- a/tiny_gltf.h +++ b/tiny_gltf.h @@ -954,7 +954,6 @@ class TinyGLTF { #pragma clang diagnostic ignored "-Wexit-time-destructors" #pragma clang diagnostic ignored "-Wconversion" #pragma clang diagnostic ignored "-Wold-style-cast" -#pragma clang diagnostic ignored "-Wdouble-promotion" #pragma clang diagnostic ignored "-Wglobal-constructors" #pragma clang diagnostic ignored "-Wreserved-id-macro" #pragma clang diagnostic ignored "-Wdisabled-macro-expansion" @@ -966,6 +965,9 @@ class TinyGLTF { #pragma clang diagnostic ignored "-Wimplicit-fallthrough" #pragma clang diagnostic ignored "-Wweak-vtables" #pragma clang diagnostic ignored "-Wcovered-switch-default" +#if __has_warning("-Wdouble-promotion") +#pragma clang diagnostic ignored "-Wdouble-promotion" +#endif #if __has_warning("-Wcomma") #pragma clang diagnostic ignored "-Wcomma" #endif From 9ec710908963ae05f83d619908365e882efa9ccf Mon Sep 17 00:00:00 2001 From: Syoyo Fujita Date: Thu, 30 Aug 2018 21:27:11 +0900 Subject: [PATCH 11/14] Bump clang version from 3.7 to 3.9 since clang-3.7 apt source is untrusted. --- .travis.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6e731e5..37779f1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,15 +7,15 @@ matrix: sources: - george-edison55-precise-backports - ubuntu-toolchain-r-test - - llvm-toolchain-precise-3.7 + - llvm-toolchain-trusty-3.9 packages: - g++-4.9 - - clang-3.7 + - clang-3.9 compiler: clang - env: COMPILER_VERSION=3.7 BUILD_TYPE=Debug + env: COMPILER_VERSION=3.9 BUILD_TYPE=Debug - addons: *1 compiler: clang - env: COMPILER_VERSION=3.7 BUILD_TYPE=Release + env: COMPILER_VERSION=3.9 BUILD_TYPE=Release - addons: &2 apt: sources: @@ -30,7 +30,7 @@ matrix: env: COMPILER_VERSION=4.9 BUILD_TYPE=Release EXTRA_CXXFLAGS="-fsanitize=address" - addons: *1 compiler: clang - env: COMPILER_VERSION=3.7 BUILD_TYPE=Debug CFLAGS="-O0" CXXFLAGS="-O0" + env: COMPILER_VERSION=3.9 BUILD_TYPE=Debug CFLAGS="-O0" CXXFLAGS="-O0" before_install: - ./.travis-before-install.sh From 3e53feb04642aab9a58fce32ef8e2417f8ed608f Mon Sep 17 00:00:00 2001 From: Syoyo Fujita Date: Sun, 2 Sep 2018 15:36:17 +0900 Subject: [PATCH 12/14] Parse `extensions` property of Image. --- loader_example.cc | 5 +++++ tiny_gltf.h | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/loader_example.cc b/loader_example.cc index 8ae20bc..7f8a426 100644 --- a/loader_example.cc +++ b/loader_example.cc @@ -1,3 +1,6 @@ +// +// TODO(syoyo): Print extensions and extras for each glTF object. +// #define TINYGLTF_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_WRITE_IMPLEMENTATION @@ -514,6 +517,7 @@ static void Dump(const tinygltf::Model &model) { std::cout << Indent(2) << "width : " << image.width << std::endl; std::cout << Indent(2) << "height : " << image.height << std::endl; std::cout << Indent(2) << "component : " << image.component << std::endl; + DumpExtensions(image.extensions, 1); } } @@ -525,6 +529,7 @@ static void Dump(const tinygltf::Model &model) { << std::endl; std::cout << Indent(1) << "source : " << texture.source << std::endl; + DumpExtensions(texture.extensions, 1); } } diff --git a/tiny_gltf.h b/tiny_gltf.h index 9b6494d..6f2855c 100644 --- a/tiny_gltf.h +++ b/tiny_gltf.h @@ -456,6 +456,7 @@ struct Image { // "image/bmp", "image/gif"] std::string uri; // (required if no mimeType) Value extras; + ExtensionMap extensions; Image() { bufferView = -1; } }; @@ -2126,6 +2127,7 @@ static bool ParseImage(Image *image, std::string *err, std::string *warn, } ParseStringProperty(&image->name, err, o, "name", false); + ParseExtensionsProperty(&image->extensions, err, o); if (hasBufferView) { double bufferView = -1; @@ -4014,6 +4016,8 @@ static void SerializeGltfImage(Image &image, json &o) { if (image.extras.Type() != NULL_TYPE) { SerializeValue("extras", image.extras, o); } + + SerializeExtensionMap(image.extensions, o); } static void SerializeGltfMaterial(Material &material, json &o) { From e66d8c992fa406e8086fb23192e1915630d9dd08 Mon Sep 17 00:00:00 2001 From: Syoyo Fujita Date: Sun, 2 Sep 2018 16:58:43 +0900 Subject: [PATCH 13/14] Add as-is flag to Image. Tentative solution for issue #82 --- tiny_gltf.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tiny_gltf.h b/tiny_gltf.h index 6f2855c..05d7097 100644 --- a/tiny_gltf.h +++ b/tiny_gltf.h @@ -458,7 +458,14 @@ struct Image { Value extras; ExtensionMap extensions; - Image() { bufferView = -1; } + // When this flag is true, data is stored to `image` in as-is format(e.g. jpeg compressed for "image/jpeg" mime) + // This feature is good if you use custom image loader function. + // (e.g. delayed decoding of images for faster glTF parsing) + // Default parser for Image does not provide as-is loading feature at the moment. + // (You can manipulate this by providing your own LoadImageData function) + bool as_is; + + Image() : as_is(false) { bufferView = -1; } }; struct Texture { From e59dd6a5c0fc982b82f3f376e13068c4cedd904a Mon Sep 17 00:00:00 2001 From: Syoyo Fujita Date: Tue, 25 Sep 2018 03:03:49 +0900 Subject: [PATCH 14/14] Update TODOs. --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 5b357aa..4e68225 100644 --- a/README.md +++ b/README.md @@ -57,13 +57,13 @@ v2.0.0 release(22 Aug, 2018)! ## TODOs -* [ ] Write C++ code generator from jSON schema for robust parsing. -* [x] Serialization -* [ ] Compression/decompression(Open3DGC, etc) +* [ ] Write C++ code generator which emits C++ code from JSON schema for robust parsing. +* [ ] Mesh Compression/decompression(Open3DGC, etc) + * [ ] Load Draco compressed mesh * [ ] Support `extensions` and `extras` property * [ ] HDR image? * [ ] OpenEXR extension through TinyEXR. -* [ ] Write tests for `animation` and `skin` +* [ ] Write exampple and tests for `animation` and `skin` ## Licenses