Merge branch '16bit-lodepng'
diff --git a/README.md b/README.md
index dc33e8c..0bd6fbc 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@
## Status
-v2.2.0 release(Support loading 16bit PNG)
+v2.2.0 release(Support loading 16bit PNG. Sparse accessor support)
v2.1.0 release(Draco support)
v2.0.0 release(22 Aug, 2018)!
@@ -45,7 +45,9 @@
* [x] Load BMP
* [x] Load GIF
* [x] Custom Image decoder callback(e.g. for decoding OpenEXR image)
-* Load from memory
+* Morph traget
+ * [x] Sparse accessor
+* Load glTF from memory
* Custom callback handler
* [x] Image load
* [x] Image save
@@ -71,15 +73,13 @@
* [ ] Write C++ code generator which emits C++ code from JSON schema for robust parsing.
* [ ] Mesh Compression/decompression(Open3DGC, etc)
* [x] Load Draco compressed mesh
- * [x] Save Draco compressed mesh
+ * [ ] Save Draco compressed mesh
* [ ] Open3DGC?
* [ ] Support `extensions` and `extras` property
* [ ] HDR image?
* [ ] OpenEXR extension through TinyEXR.
* [ ] 16bit PNG support in Serialization
* [ ] Write example and tests for `animation` and `skin`
- * [ ] Skinning
- * [ ] Morph targets
## Licenses
@@ -139,6 +139,10 @@
* `TINYGLTF_NO_EXTERNAL_IMAGE` : Do not try to load external image file. This option woulde be helpful if you do not want load image file during glTF parsing.
* `TINYGLTF_ANDROID_LOAD_FROM_ASSETS`: Load all files from packaged app assets instead of the regular file system. **Note:** You must pass a valid asset manager from your android app to `tinygltf::asset_manager` beforehand.
* `TINYGLTF_ENABLE_DRACO`: Enable Draco compression. User must provide include path and link correspnding libraries in your project file.
+* `TINYGLTF_NO_INCLUDE_JSON `: Disable including `json.hpp` from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`.
+* `TINYGLTF_NO_INCLUDE_STB_IMAGE `: Disable including `stb_image.h` from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`.
+* `TINYGLTF_NO_INCLUDE_STB_IMAGE_WRITE `: Disable including `stb_image_write.h` from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`.
+
### Saving gltTF 2.0 model
* [ ] Buffers.
diff --git a/examples/glview/glview.cc b/examples/glview/glview.cc
index b2a3d70..375b556 100644
--- a/examples/glview/glview.cc
+++ b/examples/glview/glview.cc
@@ -28,7 +28,6 @@
#include "tiny_gltf.h"
#endif
-
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
#define CheckGLErrors(desc) \
@@ -55,7 +54,9 @@
GLFWwindow *window;
-typedef struct { GLuint vb; } GLBufferState;
+typedef struct {
+ GLuint vb;
+} GLBufferState;
typedef struct {
std::vector<GLuint> diffuseTex; // for each primitive in mesh
@@ -254,6 +255,26 @@
prevMouseY = mouse_y;
}
+static size_t ComponentTypeByteSize(int type) {
+ switch (type) {
+ case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE:
+ case TINYGLTF_COMPONENT_TYPE_BYTE:
+ return sizeof(char);
+ case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT:
+ case TINYGLTF_COMPONENT_TYPE_SHORT:
+ return sizeof(short);
+ case TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT:
+ case TINYGLTF_COMPONENT_TYPE_INT:
+ return sizeof(int);
+ case TINYGLTF_COMPONENT_TYPE_FLOAT:
+ return sizeof(float);
+ case TINYGLTF_COMPONENT_TYPE_DOUBLE:
+ return sizeof(double);
+ default:
+ return 0;
+ }
+}
+
static void SetupMeshState(tinygltf::Model &model, GLuint progId) {
// Buffer
{
@@ -264,14 +285,117 @@
continue; // Unsupported bufferView.
}
+ int sparse_accessor = -1;
+ for (size_t a_i = 0; a_i < model.accessors.size(); ++a_i) {
+ const auto &accessor = model.accessors[a_i];
+ if (accessor.bufferView == i) {
+ std::cout << i << " is used by accessor " << a_i << std::endl;
+ if (accessor.sparse.isSparse) {
+ std::cout
+ << "WARN: this bufferView has at least one sparse accessor to "
+ "it. We are going to load the data as patched by this "
+ "sparse accessor, not the original data"
+ << std::endl;
+ sparse_accessor = a_i;
+ break;
+ }
+ }
+ }
+
const tinygltf::Buffer &buffer = model.buffers[bufferView.buffer];
GLBufferState state;
glGenBuffers(1, &state.vb);
glBindBuffer(bufferView.target, state.vb);
std::cout << "buffer.size= " << buffer.data.size()
<< ", byteOffset = " << bufferView.byteOffset << std::endl;
- glBufferData(bufferView.target, bufferView.byteLength,
- &buffer.data.at(0) + bufferView.byteOffset, GL_STATIC_DRAW);
+
+ if (sparse_accessor < 0)
+ glBufferData(bufferView.target, bufferView.byteLength,
+ &buffer.data.at(0) + bufferView.byteOffset,
+ GL_STATIC_DRAW);
+ else {
+ const auto accessor = model.accessors[sparse_accessor];
+ // copy the buffer to a temporary one for sparse patching
+ unsigned char *tmp_buffer = new unsigned char[bufferView.byteLength];
+ memcpy(tmp_buffer, buffer.data.data() + bufferView.byteOffset,
+ bufferView.byteLength);
+
+ const size_t size_of_object_in_buffer =
+ ComponentTypeByteSize(accessor.componentType);
+ const size_t size_of_sparse_indices =
+ ComponentTypeByteSize(accessor.sparse.indices.componentType);
+
+ const auto &indices_buffer_view =
+ model.bufferViews[accessor.sparse.indices.bufferView];
+ const auto &indices_buffer = model.buffers[indices_buffer_view.buffer];
+
+ const auto &values_buffer_view =
+ model.bufferViews[accessor.sparse.values.bufferView];
+ const auto &values_buffer = model.buffers[values_buffer_view.buffer];
+
+ for (size_t sparse_index = 0; sparse_index < accessor.sparse.count;
+ ++sparse_index) {
+ int index = 0;
+ // std::cout << "accessor.sparse.indices.componentType = " <<
+ // accessor.sparse.indices.componentType << std::endl;
+ switch (accessor.sparse.indices.componentType) {
+ case TINYGLTF_COMPONENT_TYPE_BYTE:
+ case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE:
+ index = (int)*(
+ unsigned char *)(indices_buffer.data.data() +
+ indices_buffer_view.byteOffset +
+ accessor.sparse.indices.byteOffset +
+ (sparse_index * size_of_sparse_indices));
+ break;
+ case TINYGLTF_COMPONENT_TYPE_SHORT:
+ case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT:
+ index = (int)*(
+ unsigned short *)(indices_buffer.data.data() +
+ indices_buffer_view.byteOffset +
+ accessor.sparse.indices.byteOffset +
+ (sparse_index * size_of_sparse_indices));
+ break;
+ case TINYGLTF_COMPONENT_TYPE_INT:
+ case TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT:
+ index = (int)*(
+ unsigned int *)(indices_buffer.data.data() +
+ indices_buffer_view.byteOffset +
+ accessor.sparse.indices.byteOffset +
+ (sparse_index * size_of_sparse_indices));
+ break;
+ }
+ std::cout << "updating sparse data at index : " << index
+ << std::endl;
+ // index is now the target of the sparse index to patch in
+ const unsigned char *read_from =
+ values_buffer.data.data() +
+ (values_buffer_view.byteOffset +
+ accessor.sparse.values.byteOffset) +
+ (sparse_index * (size_of_object_in_buffer * accessor.type));
+
+ /*
+ std::cout << ((float*)read_from)[0] << "\n";
+ std::cout << ((float*)read_from)[1] << "\n";
+ std::cout << ((float*)read_from)[2] << "\n";
+ */
+
+ unsigned char *write_to =
+ tmp_buffer + index * (size_of_object_in_buffer * accessor.type);
+
+ memcpy(write_to, read_from, size_of_object_in_buffer * accessor.type);
+ }
+
+ // debug:
+ /*for(size_t p = 0; p < bufferView.byteLength/sizeof(float); p++)
+ {
+ float* b = (float*)tmp_buffer;
+ std::cout << "modified_buffer [" << p << "] = " << b[p] << '\n';
+ }*/
+
+ glBufferData(bufferView.target, bufferView.byteLength, tmp_buffer,
+ GL_STATIC_DRAW);
+ delete[] tmp_buffer;
+ }
glBindBuffer(bufferView.target, 0);
gBufferState[i] = state;
@@ -279,55 +403,55 @@
}
#if 0 // TODO(syoyo): Implement
- // Texture
- {
- for (size_t i = 0; i < model.meshes.size(); i++) {
- const tinygltf::Mesh &mesh = model.meshes[i];
+ // Texture
+ {
+ for (size_t i = 0; i < model.meshes.size(); i++) {
+ const tinygltf::Mesh &mesh = model.meshes[i];
- gMeshState[mesh.name].diffuseTex.resize(mesh.primitives.size());
- for (size_t primId = 0; primId < mesh.primitives.size(); primId++) {
- const tinygltf::Primitive &primitive = mesh.primitives[primId];
+ gMeshState[mesh.name].diffuseTex.resize(mesh.primitives.size());
+ for (size_t primId = 0; primId < mesh.primitives.size(); primId++) {
+ const tinygltf::Primitive &primitive = mesh.primitives[primId];
- gMeshState[mesh.name].diffuseTex[primId] = 0;
+ gMeshState[mesh.name].diffuseTex[primId] = 0;
- if (primitive.material < 0) {
- continue;
- }
- tinygltf::Material &mat = model.materials[primitive.material];
- // printf("material.name = %s\n", mat.name.c_str());
- if (mat.values.find("diffuse") != mat.values.end()) {
- std::string diffuseTexName = mat.values["diffuse"].string_value;
- if (model.textures.find(diffuseTexName) != model.textures.end()) {
- tinygltf::Texture &tex = model.textures[diffuseTexName];
- if (scene.images.find(tex.source) != model.images.end()) {
- tinygltf::Image &image = model.images[tex.source];
- GLuint texId;
- glGenTextures(1, &texId);
- glBindTexture(tex.target, texId);
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
- glTexParameterf(tex.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameterf(tex.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ if (primitive.material < 0) {
+ continue;
+ }
+ tinygltf::Material &mat = model.materials[primitive.material];
+ // printf("material.name = %s\n", mat.name.c_str());
+ if (mat.values.find("diffuse") != mat.values.end()) {
+ std::string diffuseTexName = mat.values["diffuse"].string_value;
+ if (model.textures.find(diffuseTexName) != model.textures.end()) {
+ tinygltf::Texture &tex = model.textures[diffuseTexName];
+ if (scene.images.find(tex.source) != model.images.end()) {
+ tinygltf::Image &image = model.images[tex.source];
+ GLuint texId;
+ glGenTextures(1, &texId);
+ glBindTexture(tex.target, texId);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glTexParameterf(tex.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameterf(tex.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- // Ignore Texture.fomat.
- GLenum format = GL_RGBA;
- if (image.component == 3) {
- format = GL_RGB;
- }
- glTexImage2D(tex.target, 0, tex.internalFormat, image.width,
- image.height, 0, format, tex.type,
- &image.image.at(0));
+ // Ignore Texture.fomat.
+ GLenum format = GL_RGBA;
+ if (image.component == 3) {
+ format = GL_RGB;
+ }
+ glTexImage2D(tex.target, 0, tex.internalFormat, image.width,
+ image.height, 0, format, tex.type,
+ &image.image.at(0));
- CheckErrors("texImage2D");
- glBindTexture(tex.target, 0);
+ CheckErrors("texImage2D");
+ glBindTexture(tex.target, 0);
- printf("TexId = %d\n", texId);
- gMeshState[mesh.name].diffuseTex[primId] = texId;
- }
- }
- }
- }
- }
- }
+ printf("TexId = %d\n", texId);
+ gMeshState[mesh.name].diffuseTex[primId] = texId;
+ }
+ }
+ }
+ }
+ }
+ }
#endif
glUseProgram(progId);
@@ -348,164 +472,164 @@
#if 0 // TODO(syoyo): Implement
// Setup curves geometry extension
static void SetupCurvesState(tinygltf::Scene &scene, GLuint progId) {
- // Find curves primitive.
- {
- std::map<std::string, tinygltf::Mesh>::const_iterator it(
- scene.meshes.begin());
- std::map<std::string, tinygltf::Mesh>::const_iterator itEnd(
- scene.meshes.end());
+ // Find curves primitive.
+ {
+ std::map<std::string, tinygltf::Mesh>::const_iterator it(
+ scene.meshes.begin());
+ std::map<std::string, tinygltf::Mesh>::const_iterator itEnd(
+ scene.meshes.end());
- for (; it != itEnd; it++) {
- const tinygltf::Mesh &mesh = it->second;
+ for (; it != itEnd; it++) {
+ const tinygltf::Mesh &mesh = it->second;
- // Currently we only support one primitive per mesh.
- if (mesh.primitives.size() > 1) {
- continue;
- }
+ // Currently we only support one primitive per mesh.
+ if (mesh.primitives.size() > 1) {
+ continue;
+ }
- for (size_t primId = 0; primId < mesh.primitives.size(); primId++) {
- const tinygltf::Primitive &primitive = mesh.primitives[primId];
+ for (size_t primId = 0; primId < mesh.primitives.size(); primId++) {
+ const tinygltf::Primitive &primitive = mesh.primitives[primId];
- gMeshState[mesh.name].diffuseTex[primId] = 0;
+ gMeshState[mesh.name].diffuseTex[primId] = 0;
- if (primitive.material.empty()) {
- continue;
- }
+ if (primitive.material.empty()) {
+ continue;
+ }
- bool has_curves = false;
- if (primitive.extras.IsObject()) {
- if (primitive.extras.Has("ext_mode")) {
- const tinygltf::Value::Object &o =
- primitive.extras.Get<tinygltf::Value::Object>();
- const tinygltf::Value &ext_mode = o.find("ext_mode")->second;
+ bool has_curves = false;
+ if (primitive.extras.IsObject()) {
+ if (primitive.extras.Has("ext_mode")) {
+ const tinygltf::Value::Object &o =
+ primitive.extras.Get<tinygltf::Value::Object>();
+ const tinygltf::Value &ext_mode = o.find("ext_mode")->second;
- if (ext_mode.IsString()) {
- const std::string &str = ext_mode.Get<std::string>();
- if (str.compare("curves") == 0) {
- has_curves = true;
- }
- }
- }
- }
+ if (ext_mode.IsString()) {
+ const std::string &str = ext_mode.Get<std::string>();
+ if (str.compare("curves") == 0) {
+ has_curves = true;
+ }
+ }
+ }
+ }
- if (!has_curves) {
- continue;
- }
+ if (!has_curves) {
+ continue;
+ }
- // Construct curves buffer
- const tinygltf::Accessor &vtx_accessor =
- scene.accessors[primitive.attributes.find("POSITION")->second];
- const tinygltf::Accessor &nverts_accessor =
- scene.accessors[primitive.attributes.find("NVERTS")->second];
- const tinygltf::BufferView &vtx_bufferView =
- scene.bufferViews[vtx_accessor.bufferView];
- const tinygltf::BufferView &nverts_bufferView =
- scene.bufferViews[nverts_accessor.bufferView];
- const tinygltf::Buffer &vtx_buffer =
- scene.buffers[vtx_bufferView.buffer];
- const tinygltf::Buffer &nverts_buffer =
- scene.buffers[nverts_bufferView.buffer];
+ // Construct curves buffer
+ const tinygltf::Accessor &vtx_accessor =
+ scene.accessors[primitive.attributes.find("POSITION")->second];
+ const tinygltf::Accessor &nverts_accessor =
+ scene.accessors[primitive.attributes.find("NVERTS")->second];
+ const tinygltf::BufferView &vtx_bufferView =
+ scene.bufferViews[vtx_accessor.bufferView];
+ const tinygltf::BufferView &nverts_bufferView =
+ scene.bufferViews[nverts_accessor.bufferView];
+ const tinygltf::Buffer &vtx_buffer =
+ scene.buffers[vtx_bufferView.buffer];
+ const tinygltf::Buffer &nverts_buffer =
+ scene.buffers[nverts_bufferView.buffer];
- // std::cout << "vtx_bufferView = " << vtx_accessor.bufferView <<
- // std::endl;
- // std::cout << "nverts_bufferView = " << nverts_accessor.bufferView <<
- // std::endl;
- // std::cout << "vtx_buffer.size = " << vtx_buffer.data.size() <<
- // std::endl;
- // std::cout << "nverts_buffer.size = " << nverts_buffer.data.size() <<
- // std::endl;
+ // std::cout << "vtx_bufferView = " << vtx_accessor.bufferView <<
+ // std::endl;
+ // std::cout << "nverts_bufferView = " << nverts_accessor.bufferView <<
+ // std::endl;
+ // std::cout << "vtx_buffer.size = " << vtx_buffer.data.size() <<
+ // std::endl;
+ // std::cout << "nverts_buffer.size = " << nverts_buffer.data.size() <<
+ // std::endl;
- const int *nverts =
- reinterpret_cast<const int *>(nverts_buffer.data.data());
- const float *vtx =
- reinterpret_cast<const float *>(vtx_buffer.data.data());
+ const int *nverts =
+ reinterpret_cast<const int *>(nverts_buffer.data.data());
+ const float *vtx =
+ reinterpret_cast<const float *>(vtx_buffer.data.data());
- // Convert to GL_LINES data.
- std::vector<float> line_pts;
- size_t vtx_offset = 0;
- for (int k = 0; k < static_cast<int>(nverts_accessor.count); k++) {
- for (int n = 0; n < nverts[k] - 1; n++) {
+ // Convert to GL_LINES data.
+ std::vector<float> line_pts;
+ size_t vtx_offset = 0;
+ for (int k = 0; k < static_cast<int>(nverts_accessor.count); k++) {
+ for (int n = 0; n < nverts[k] - 1; n++) {
- line_pts.push_back(vtx[3 * (vtx_offset + n) + 0]);
- line_pts.push_back(vtx[3 * (vtx_offset + n) + 1]);
- line_pts.push_back(vtx[3 * (vtx_offset + n) + 2]);
+ line_pts.push_back(vtx[3 * (vtx_offset + n) + 0]);
+ line_pts.push_back(vtx[3 * (vtx_offset + n) + 1]);
+ line_pts.push_back(vtx[3 * (vtx_offset + n) + 2]);
- line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 0]);
- line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 1]);
- line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 2]);
+ line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 0]);
+ line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 1]);
+ line_pts.push_back(vtx[3 * (vtx_offset + n + 1) + 2]);
- // std::cout << "p0 " << vtx[3 * (vtx_offset + n) + 0] << ", "
- // << vtx[3 * (vtx_offset + n) + 1] << ", "
- // << vtx[3 * (vtx_offset + n) + 2] << std::endl;
+ // std::cout << "p0 " << vtx[3 * (vtx_offset + n) + 0] << ", "
+ // << vtx[3 * (vtx_offset + n) + 1] << ", "
+ // << vtx[3 * (vtx_offset + n) + 2] << std::endl;
- // std::cout << "p1 " << vtx[3 * (vtx_offset + n+1) + 0] << ", "
- // << vtx[3 * (vtx_offset + n+1) + 1] << ", "
- // << vtx[3 * (vtx_offset + n+1) + 2] << std::endl;
- }
+ // std::cout << "p1 " << vtx[3 * (vtx_offset + n+1) + 0] << ", "
+ // << vtx[3 * (vtx_offset + n+1) + 1] << ", "
+ // << vtx[3 * (vtx_offset + n+1) + 2] << std::endl;
+ }
- vtx_offset += nverts[k];
- }
+ vtx_offset += nverts[k];
+ }
- GLCurvesState state;
- glGenBuffers(1, &state.vb);
- glBindBuffer(GL_ARRAY_BUFFER, state.vb);
- glBufferData(GL_ARRAY_BUFFER, line_pts.size() * sizeof(float),
- line_pts.data(), GL_STATIC_DRAW);
- glBindBuffer(GL_ARRAY_BUFFER, 0);
+ GLCurvesState state;
+ glGenBuffers(1, &state.vb);
+ glBindBuffer(GL_ARRAY_BUFFER, state.vb);
+ glBufferData(GL_ARRAY_BUFFER, line_pts.size() * sizeof(float),
+ line_pts.data(), GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
- state.count = line_pts.size() / 3;
- gCurvesMesh[mesh.name] = state;
+ state.count = line_pts.size() / 3;
+ gCurvesMesh[mesh.name] = state;
- // Material
- tinygltf::Material &mat = scene.materials[primitive.material];
- // printf("material.name = %s\n", mat.name.c_str());
- if (mat.values.find("diffuse") != mat.values.end()) {
- std::string diffuseTexName = mat.values["diffuse"].string_value;
- if (scene.textures.find(diffuseTexName) != scene.textures.end()) {
- tinygltf::Texture &tex = scene.textures[diffuseTexName];
- if (scene.images.find(tex.source) != scene.images.end()) {
- tinygltf::Image &image = scene.images[tex.source];
- GLuint texId;
- glGenTextures(1, &texId);
- glBindTexture(tex.target, texId);
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
- glTexParameterf(tex.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameterf(tex.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ // Material
+ tinygltf::Material &mat = scene.materials[primitive.material];
+ // printf("material.name = %s\n", mat.name.c_str());
+ if (mat.values.find("diffuse") != mat.values.end()) {
+ std::string diffuseTexName = mat.values["diffuse"].string_value;
+ if (scene.textures.find(diffuseTexName) != scene.textures.end()) {
+ tinygltf::Texture &tex = scene.textures[diffuseTexName];
+ if (scene.images.find(tex.source) != scene.images.end()) {
+ tinygltf::Image &image = scene.images[tex.source];
+ GLuint texId;
+ glGenTextures(1, &texId);
+ glBindTexture(tex.target, texId);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glTexParameterf(tex.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameterf(tex.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- // Ignore Texture.fomat.
- GLenum format = GL_RGBA;
- if (image.component == 3) {
- format = GL_RGB;
- }
- glTexImage2D(tex.target, 0, tex.internalFormat, image.width,
- image.height, 0, format, tex.type,
- &image.image.at(0));
+ // Ignore Texture.fomat.
+ GLenum format = GL_RGBA;
+ if (image.component == 3) {
+ format = GL_RGB;
+ }
+ glTexImage2D(tex.target, 0, tex.internalFormat, image.width,
+ image.height, 0, format, tex.type,
+ &image.image.at(0));
- CheckErrors("texImage2D");
- glBindTexture(tex.target, 0);
+ CheckErrors("texImage2D");
+ glBindTexture(tex.target, 0);
- printf("TexId = %d\n", texId);
- gMeshState[mesh.name].diffuseTex[primId] = texId;
- }
- }
- }
- }
- }
- }
+ printf("TexId = %d\n", texId);
+ gMeshState[mesh.name].diffuseTex[primId] = texId;
+ }
+ }
+ }
+ }
+ }
+ }
- glUseProgram(progId);
- GLint vtloc = glGetAttribLocation(progId, "in_vertex");
- GLint nrmloc = glGetAttribLocation(progId, "in_normal");
- GLint uvloc = glGetAttribLocation(progId, "in_texcoord");
+ glUseProgram(progId);
+ GLint vtloc = glGetAttribLocation(progId, "in_vertex");
+ GLint nrmloc = glGetAttribLocation(progId, "in_normal");
+ GLint uvloc = glGetAttribLocation(progId, "in_texcoord");
- GLint diffuseTexLoc = glGetUniformLocation(progId, "diffuseTex");
- GLint isCurvesLoc = glGetUniformLocation(progId, "uIsCurves");
+ GLint diffuseTexLoc = glGetUniformLocation(progId, "diffuseTex");
+ GLint isCurvesLoc = glGetUniformLocation(progId, "uIsCurves");
- gGLProgramState.attribs["POSITION"] = vtloc;
- gGLProgramState.attribs["NORMAL"] = nrmloc;
- gGLProgramState.attribs["TEXCOORD_0"] = uvloc;
- gGLProgramState.uniforms["diffuseTex"] = diffuseTexLoc;
- gGLProgramState.uniforms["uIsCurves"] = isCurvesLoc;
+ gGLProgramState.attribs["POSITION"] = vtloc;
+ gGLProgramState.attribs["NORMAL"] = nrmloc;
+ gGLProgramState.attribs["TEXCOORD_0"] = uvloc;
+ gGLProgramState.uniforms["diffuseTex"] = diffuseTexLoc;
+ gGLProgramState.uniforms["uIsCurves"] = isCurvesLoc;
};
#endif
@@ -558,12 +682,13 @@
(it->first.compare("TEXCOORD_0") == 0)) {
if (gGLProgramState.attribs[it->first] >= 0) {
// Compute byteStride from Accessor + BufferView combination.
- int byteStride = accessor.ByteStride(model.bufferViews[accessor.bufferView]);
+ int byteStride =
+ accessor.ByteStride(model.bufferViews[accessor.bufferView]);
assert(byteStride != -1);
glVertexAttribPointer(gGLProgramState.attribs[it->first], size,
- accessor.componentType, accessor.normalized ? GL_TRUE : GL_FALSE,
- byteStride,
- BUFFER_OFFSET(accessor.byteOffset));
+ accessor.componentType,
+ accessor.normalized ? GL_TRUE : GL_FALSE,
+ byteStride, BUFFER_OFFSET(accessor.byteOffset));
CheckErrors("vertex attrib pointer");
glEnableVertexAttribArray(gGLProgramState.attribs[it->first]);
CheckErrors("enable vertex attrib array");
@@ -617,32 +742,32 @@
#if 0 // TODO(syoyo): Implement
static void DrawCurves(tinygltf::Scene &scene, const tinygltf::Mesh &mesh) {
- (void)scene;
+ (void)scene;
- if (gCurvesMesh.find(mesh.name) == gCurvesMesh.end()) {
- return;
- }
+ if (gCurvesMesh.find(mesh.name) == gCurvesMesh.end()) {
+ return;
+ }
- if (gGLProgramState.uniforms["isCurvesLoc"] >= 0) {
- glUniform1i(gGLProgramState.uniforms["isCurvesLoc"], 1);
- }
+ if (gGLProgramState.uniforms["isCurvesLoc"] >= 0) {
+ glUniform1i(gGLProgramState.uniforms["isCurvesLoc"], 1);
+ }
- GLCurvesState &state = gCurvesMesh[mesh.name];
+ GLCurvesState &state = gCurvesMesh[mesh.name];
- if (gGLProgramState.attribs["POSITION"] >= 0) {
- glBindBuffer(GL_ARRAY_BUFFER, state.vb);
- glVertexAttribPointer(gGLProgramState.attribs["POSITION"], 3, GL_FLOAT,
- GL_FALSE, /* stride */ 0, BUFFER_OFFSET(0));
- CheckErrors("curve: vertex attrib pointer");
- glEnableVertexAttribArray(gGLProgramState.attribs["POSITION"]);
- CheckErrors("curve: enable vertex attrib array");
- }
+ if (gGLProgramState.attribs["POSITION"] >= 0) {
+ glBindBuffer(GL_ARRAY_BUFFER, state.vb);
+ glVertexAttribPointer(gGLProgramState.attribs["POSITION"], 3, GL_FLOAT,
+ GL_FALSE, /* stride */ 0, BUFFER_OFFSET(0));
+ CheckErrors("curve: vertex attrib pointer");
+ glEnableVertexAttribArray(gGLProgramState.attribs["POSITION"]);
+ CheckErrors("curve: enable vertex attrib array");
+ }
- glDrawArrays(GL_LINES, 0, state.count);
+ glDrawArrays(GL_LINES, 0, state.count);
- if (gGLProgramState.attribs["POSITION"] >= 0) {
- glDisableVertexAttribArray(gGLProgramState.attribs["POSITION"]);
- }
+ if (gGLProgramState.attribs["POSITION"] >= 0) {
+ glDisableVertexAttribArray(gGLProgramState.attribs["POSITION"]);
+ }
}
#endif
@@ -693,16 +818,16 @@
static void DrawModel(tinygltf::Model &model) {
#if 0
- std::map<std::string, tinygltf::Mesh>::const_iterator it(scene.meshes.begin());
- std::map<std::string, tinygltf::Mesh>::const_iterator itEnd(scene.meshes.end());
+ std::map<std::string, tinygltf::Mesh>::const_iterator it(scene.meshes.begin());
+ std::map<std::string, tinygltf::Mesh>::const_iterator itEnd(scene.meshes.end());
- for (; it != itEnd; it++) {
- DrawMesh(scene, it->second);
- DrawCurves(scene, it->second);
- }
+ for (; it != itEnd; it++) {
+ DrawMesh(scene, it->second);
+ DrawCurves(scene, it->second);
+ }
#else
- //If the glTF asset has at least one scene, and doesn't define a default one
- //just show the first one we can find
+ // If the glTF asset has at least one scene, and doesn't define a default one
+ // just show the first one we can find
assert(model.scenes.size() > 0);
int scene_to_display = model.defaultScene > -1 ? model.defaultScene : 0;
const tinygltf::Scene &scene = model.scenes[scene_to_display];
@@ -752,7 +877,8 @@
#ifdef _WIN32
#ifdef _DEBUG
- std::string input_filename(argv[1] ? argv[1] : "../../../models/Cube/Cube.gltf");
+ std::string input_filename(argv[1] ? argv[1]
+ : "../../../models/Cube/Cube.gltf");
#endif
#else
std::string input_filename(argv[1] ? argv[1] : "../../models/Cube/Cube.gltf");
@@ -763,7 +889,8 @@
bool ret = false;
if (ext.compare("glb") == 0) {
// assume binary glTF.
- ret = loader.LoadBinaryFromFile(&model, &err, &warn, input_filename.c_str());
+ ret =
+ loader.LoadBinaryFromFile(&model, &err, &warn, input_filename.c_str());
} else {
// assume ascii glTF.
ret = loader.LoadASCIIFromFile(&model, &err, &warn, input_filename.c_str());
@@ -825,15 +952,14 @@
#ifdef _WIN32
#ifdef _DEBUG
- const char *shader_frag_filename = "../shader.frag";
- const char *shader_vert_filename = "../shader.vert";
+ const char *shader_frag_filename = "../shader.frag";
+ const char *shader_vert_filename = "../shader.vert";
#endif
#else
const char *shader_frag_filename = "shader.frag";
const char *shader_vert_filename = "shader.vert";
#endif
-
if (false == LoadShader(GL_VERTEX_SHADER, vertId, shader_vert_filename)) {
return -1;
}
diff --git a/loader_example.cc b/loader_example.cc
index 7f8a426..c0eec95 100644
--- a/loader_example.cc
+++ b/loader_example.cc
@@ -228,7 +228,8 @@
#endif
static std::string PrintValue(const std::string &name,
- const tinygltf::Value &value, const int indent, const bool tag = true) {
+ const tinygltf::Value &value, const int indent,
+ const bool tag = true) {
std::stringstream ss;
if (value.IsObject()) {
@@ -265,11 +266,10 @@
} else if (value.IsArray()) {
ss << Indent(indent) << name << " [ ";
for (size_t i = 0; i < value.Size(); i++) {
- ss << PrintValue("", value.Get(int(i)), indent + 1, /* tag */false);
- if (i != (value.ArrayLen()-1)) {
+ ss << PrintValue("", value.Get(int(i)), indent + 1, /* tag */ false);
+ if (i != (value.ArrayLen() - 1)) {
ss << ", ";
}
-
}
ss << Indent(indent) << "] ";
}
@@ -330,13 +330,13 @@
<< PrintValue("extras", primitive.extras, indent + 1) << std::endl;
}
-static void DumpExtensions(const tinygltf::ExtensionMap &extension, const int indent)
-{
+static void DumpExtensions(const tinygltf::ExtensionMap &extension,
+ const int indent) {
// TODO(syoyo): pritty print Value
for (auto &e : extension) {
std::cout << Indent(indent) << e.first << std::endl;
- std::cout << PrintValue("extensions", e.second, indent+1) << std::endl;
- }
+ std::cout << PrintValue("extensions", e.second, indent + 1) << std::endl;
+ }
}
static void Dump(const tinygltf::Model &model) {
@@ -409,6 +409,30 @@
}
std::cout << "]" << std::endl;
}
+
+ if (accessor.sparse.isSparse) {
+ std::cout << Indent(2) << "sparse:" << std::endl;
+ std::cout << Indent(3) << "count : " << accessor.sparse.count
+ << std::endl;
+ std::cout << Indent(3) << "indices: " << std::endl;
+ std::cout << Indent(4)
+ << "bufferView : " << accessor.sparse.indices.bufferView
+ << std::endl;
+ std::cout << Indent(4)
+ << "byteOffset : " << accessor.sparse.indices.byteOffset
+ << std::endl;
+ std::cout << Indent(4) << "componentType: "
+ << PrintComponentType(accessor.sparse.indices.componentType)
+ << "(" << accessor.sparse.indices.componentType << ")"
+ << std::endl;
+ std::cout << Indent(3) << "values : " << std::endl;
+ std::cout << Indent(4)
+ << "bufferView : " << accessor.sparse.values.bufferView
+ << std::endl;
+ std::cout << Indent(4)
+ << "byteOffset : " << accessor.sparse.values.byteOffset
+ << std::endl;
+ }
}
}
@@ -585,10 +609,11 @@
}
}
}
-
+
// toplevel extensions
{
- std::cout << "extensions(items=" << model.extensions.size() << ")" << std::endl;
+ std::cout << "extensions(items=" << model.extensions.size() << ")"
+ << std::endl;
DumpExtensions(model.extensions, 1);
}
}
@@ -602,7 +627,7 @@
tinygltf::Model model;
tinygltf::TinyGLTF gltf_ctx;
std::string err;
- std::string warn;
+ std::string warn;
std::string input_filename(argv[1]);
std::string ext = GetFilePathExtension(input_filename);
@@ -610,18 +635,19 @@
if (ext.compare("glb") == 0) {
std::cout << "Reading binary glTF" << std::endl;
// assume binary glTF.
- ret = gltf_ctx.LoadBinaryFromFile(&model, &err, &warn, input_filename.c_str());
+ ret = gltf_ctx.LoadBinaryFromFile(&model, &err, &warn,
+ input_filename.c_str());
} else {
std::cout << "Reading ASCII glTF" << std::endl;
// assume ascii glTF.
- ret = gltf_ctx.LoadASCIIFromFile(&model, &err, &warn, input_filename.c_str());
+ ret =
+ gltf_ctx.LoadASCIIFromFile(&model, &err, &warn, input_filename.c_str());
}
if (!warn.empty()) {
printf("Warn: %s\n", warn.c_str());
}
-
if (!err.empty()) {
printf("Err: %s\n", err.c_str());
}
diff --git a/tiny_gltf.h b/tiny_gltf.h
index d675777..3c1015a 100644
--- a/tiny_gltf.h
+++ b/tiny_gltf.h
@@ -4,7 +4,7 @@
//
// The MIT License (MIT)
//
-// Copyright (c) 2015 - 2018 Syoyo Fujita, Aurélien Chatelain and many
+// Copyright (c) 2015 - 2019 Syoyo Fujita, Aurélien Chatelain and many
// contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -26,7 +26,8 @@
// THE SOFTWARE.
// Version:
-// - v2.2.0 Add loading 16bit PNG support.
+// - v2.2.0 Add loading 16bit PNG support. Add Sparse accessor support(Thanks
+// to @Ybalrid)
// - v2.1.0 Add draco compression.
// - v2.0.1 Add comparsion feature(Thanks to @Selmar).
// - v2.0.0 glTF 2.0!.
@@ -150,7 +151,7 @@
#ifdef __ANDROID__
#ifdef TINYGLTF_ANDROID_LOAD_FROM_ASSETS
- AAssetManager* asset_manager = nullptr;
+AAssetManager *asset_manager = nullptr;
#endif
#endif
@@ -381,15 +382,15 @@
return -1;
}
- /// Return the index of a texture coordinate set if this Parameter is a texture map.
- /// Returned value is only valid if the parameter represent a texture from a
- /// material
+ /// Return the index of a texture coordinate set if this Parameter is a
+ /// texture map. Returned value is only valid if the parameter represent a
+ /// texture from a material
int TextureTexCoord() const {
- const auto it = json_double_value.find("texCoord");
- if (it != std::end(json_double_value)) {
- return int(it->second);
- }
- return 0;
+ const auto it = json_double_value.find("texCoord");
+ if (it != std::end(json_double_value)) {
+ return int(it->second);
+ }
+ return 0;
}
/// Material factor, like the roughness or metalness of a material
@@ -484,7 +485,7 @@
magFilter(TINYGLTF_TEXTURE_FILTER_LINEAR),
wrapS(TINYGLTF_TEXTURE_WRAP_REPEAT),
wrapT(TINYGLTF_TEXTURE_WRAP_REPEAT),
- wrapR(TINYGLTF_TEXTURE_WRAP_REPEAT){}
+ wrapR(TINYGLTF_TEXTURE_WRAP_REPEAT) {}
bool operator==(const Sampler &) const;
};
@@ -493,8 +494,9 @@
int width;
int height;
int component;
- int bits; // bit depth per channel. 8(byte), 16 or 32.
- int pixel_type; // pixel type(TINYGLTF_COMPONENT_TYPE_***). usually UBYTE(bits = 8) or USHORT(bits = 16)
+ int bits; // bit depth per channel. 8(byte), 16 or 32.
+ int pixel_type; // pixel type(TINYGLTF_COMPONENT_TYPE_***). usually
+ // UBYTE(bits = 8) or USHORT(bits = 16)
std::vector<unsigned char> image;
int bufferView; // (required if no uri)
std::string mimeType; // (required if no uri) ["image/jpeg", "image/png",
@@ -576,7 +578,19 @@
std::vector<double> minValues; // optional
std::vector<double> maxValues; // optional
- // TODO(syoyo): "sparse"
+ struct {
+ int count;
+ bool isSparse;
+ struct {
+ int byteOffset;
+ int bufferView;
+ int componentType; // a TINYGLTF_COMPONENT_TYPE_ value
+ } indices;
+ struct {
+ int bufferView;
+ int byteOffset;
+ } values;
+ } sparse;
///
/// Utility function to compute byteStride for a given bufferView object.
@@ -615,7 +629,10 @@
return 0;
}
- Accessor() { bufferView = -1; }
+ Accessor() {
+ bufferView = -1;
+ sparse.isSparse = false;
+ }
bool operator==(const tinygltf::Accessor &) const;
};
@@ -821,9 +838,9 @@
///
/// LoadImageDataFunction type. Signature for custom image loading callbacks.
///
-typedef bool (*LoadImageDataFunction)(Image *, const int, std::string *, std::string *,
- int, int, const unsigned char *, int,
- void *);
+typedef bool (*LoadImageDataFunction)(Image *, const int, std::string *,
+ std::string *, int, int,
+ const unsigned char *, int, void *);
///
/// WriteImageDataFunction type. Signature for custom image writing callbacks.
@@ -833,9 +850,9 @@
#ifndef TINYGLTF_NO_STB_IMAGE
// Declaration of default image loader callback
-bool LoadImageData(Image *image, const int image_idx, std::string *err, std::string *warn,
- int req_width, int req_height, const unsigned char *bytes,
- int size, void *);
+bool LoadImageData(Image *image, const int image_idx, std::string *err,
+ std::string *warn, int req_width, int req_height,
+ const unsigned char *bytes, int size, void *);
#endif
#ifndef TINYGLTF_NO_STB_IMAGE_WRITE
@@ -955,10 +972,8 @@
/// Write glTF to file.
///
bool WriteGltfSceneToFile(Model *model, const std::string &filename,
- bool embedImages,
- bool embedBuffers,
- bool prettyPrint,
- bool writeBinary);
+ bool embedImages, bool embedBuffers,
+ bool prettyPrint, bool writeBinary);
///
/// Set callback to use for loading image data
@@ -1090,22 +1105,28 @@
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wtype-limits"
-#endif // __GNUC__
+#endif // __GNUC__
+#ifndef TINYGLTF_NO_INCLUDE_JSON
#include "json.hpp"
+#endif
#ifdef TINYGLTF_ENABLE_DRACO
-#include "draco/core/decoder_buffer.h"
#include "draco/compression/decode.h"
+#include "draco/core/decoder_buffer.h"
#endif
#ifndef TINYGLTF_NO_STB_IMAGE
+#ifndef TINYGLTF_NO_INCLUDE_STB_IMAGE
#include "stb_image.h"
#endif
+#endif
#ifndef TINYGLTF_NO_STB_IMAGE_WRITE
+#ifndef TINYGLTF_NO_INCLUDE_STB_IMAGE_WRITE
#include "stb_image_write.h"
#endif
+#endif
#ifdef __clang__
#pragma clang diagnostic pop
@@ -1129,7 +1150,7 @@
#define WIN32_LEAN_AND_MEAN
#define TINYGLTF_INTERNAL_WIN32_LEAN_AND_MEAN
#endif
-#include <windows.h> // include API for expanding a file path
+#include <windows.h> // include API for expanding a file path
#ifdef TINYGLTF_INTERNAL_WIN32_LEAN_AND_MEAN
#undef WIN32_LEAN_AND_MEAN
@@ -1773,7 +1794,8 @@
std::vector<unsigned char> data;
if (ext == "png") {
- if ((image->bits != 8) || (image->pixel_type != TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE)) {
+ if ((image->bits != 8) ||
+ (image->pixel_type != TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE)) {
// Unsupported pixel format
return false;
}
@@ -1841,16 +1863,17 @@
bool FileExists(const std::string &abs_filename, void *) {
bool ret;
#ifdef TINYGLTF_ANDROID_LOAD_FROM_ASSETS
- if (asset_manager) {
- AAsset* asset = AAssetManager_open(asset_manager, abs_filename.c_str(), AASSET_MODE_STREAMING);
- if (!asset) {
- return false;
- }
- AAsset_close(asset);
- ret = true;
- } else {
+ if (asset_manager) {
+ AAsset *asset = AAssetManager_open(asset_manager, abs_filename.c_str(),
+ AASSET_MODE_STREAMING);
+ if (!asset) {
return false;
}
+ AAsset_close(asset);
+ ret = true;
+ } else {
+ return false;
+ }
#else
#ifdef _WIN32
FILE *fp;
@@ -1923,7 +1946,8 @@
const std::string &filepath, void *) {
#ifdef TINYGLTF_ANDROID_LOAD_FROM_ASSETS
if (asset_manager) {
- AAsset* asset = AAssetManager_open(asset_manager, filepath.c_str(), AASSET_MODE_STREAMING);
+ AAsset *asset = AAssetManager_open(asset_manager, filepath.c_str(),
+ AASSET_MODE_STREAMING);
if (!asset) {
if (err) {
(*err) += "File open error : " + filepath + "\n";
@@ -2500,12 +2524,13 @@
json::const_iterator extIt = it.value().begin();
for (; extIt != it.value().end(); extIt++) {
if (!extIt.value().is_object()) continue;
- if (!ParseJsonAsValue(&extensions[extIt.key()], extIt.value())) {
+ if (!ParseJsonAsValue(&extensions[extIt.key()], extIt.value())) {
if (!extIt.key().empty()) {
- // create empty object so that an extension object is still of type object
- extensions[extIt.key()] = Value{ Value::Object{} };
+ // create empty object so that an extension object is still of type
+ // object
+ extensions[extIt.key()] = Value{Value::Object{}};
}
- }
+ }
}
if (ret) {
(*ret) = extensions;
@@ -2526,9 +2551,9 @@
return true;
}
-static bool ParseImage(Image *image, const int image_idx, std::string *err, std::string *warn,
- const json &o, const std::string &basedir,
- FsCallbacks *fs,
+static bool ParseImage(Image *image, const int image_idx, std::string *err,
+ std::string *warn, const json &o,
+ const std::string &basedir, FsCallbacks *fs,
LoadImageDataFunction *LoadImageData = nullptr,
void *load_image_user_data = nullptr) {
// A glTF image must either reference a bufferView or an image uri
@@ -2545,14 +2570,17 @@
if (err) {
(*err) +=
"Only one of `bufferView` or `uri` should be defined, but both are "
- "defined for image[" + std::to_string(image_idx) + "] name = \"" + image->name + "\"\n";
+ "defined for image[" +
+ std::to_string(image_idx) + "] name = \"" + image->name + "\"\n";
}
return false;
}
if (!hasBufferView && !hasURI) {
if (err) {
- (*err) += "Neither required `bufferView` nor `uri` defined for image[" + std::to_string(image_idx) + "] name = \"" + image->name + "\"\n";
+ (*err) += "Neither required `bufferView` nor `uri` defined for image[" +
+ std::to_string(image_idx) + "] name = \"" + image->name +
+ "\"\n";
}
return false;
}
@@ -2564,7 +2592,9 @@
double bufferView = -1;
if (!ParseNumberProperty(&bufferView, err, o, "bufferView", true)) {
if (err) {
- (*err) += "Failed to parse `bufferView` for image[" + std::to_string(image_idx) + "] name = \"" + image->name + "\"\n";
+ (*err) += "Failed to parse `bufferView` for image[" +
+ std::to_string(image_idx) + "] name = \"" + image->name +
+ "\"\n";
}
return false;
}
@@ -2594,7 +2624,8 @@
std::string tmp_err;
if (!ParseStringProperty(&uri, &tmp_err, o, "uri", true)) {
if (err) {
- (*err) += "Failed to parse `uri` for image[" + std::to_string(image_idx) + "] name = \"" + image->name + "\".\n";
+ (*err) += "Failed to parse `uri` for image[" + std::to_string(image_idx) +
+ "] name = \"" + image->name + "\".\n";
}
return false;
}
@@ -2604,7 +2635,9 @@
if (IsDataURI(uri)) {
if (!DecodeDataURI(&img, image->mimeType, uri, 0, false)) {
if (err) {
- (*err) += "Failed to decode 'uri' for image[" + std::to_string(image_idx) + "] name = [" + image->name + "]\n";
+ (*err) += "Failed to decode 'uri' for image[" +
+ std::to_string(image_idx) + "] name = [" + image->name +
+ "]\n";
}
return false;
}
@@ -2617,7 +2650,9 @@
#endif
if (!LoadExternalFile(&img, err, warn, uri, basedir, false, 0, false, fs)) {
if (warn) {
- (*warn) += "Failed to load external 'uri' for image[" + std::to_string(image_idx) + "] name = [" + image->name + "]\n";
+ (*warn) += "Failed to load external 'uri' for image[" +
+ std::to_string(image_idx) + "] name = [" + image->name +
+ "]\n";
}
// If the image cannot be loaded, keep uri as image->uri.
return true;
@@ -2625,7 +2660,9 @@
if (img.empty()) {
if (warn) {
- (*warn) += "Image data is empty for image[" + std::to_string(image_idx) + "] name = [" + image->name + "] \n";
+ (*warn) += "Image data is empty for image[" +
+ std::to_string(image_idx) + "] name = [" + image->name +
+ "] \n";
}
return false;
}
@@ -2821,6 +2858,51 @@
bufferView->byteOffset = static_cast<size_t>(byteOffset);
bufferView->byteLength = static_cast<size_t>(byteLength);
bufferView->byteStride = static_cast<size_t>(byteStride);
+ return true;
+}
+
+static bool ParseSparseAccessor(Accessor *accessor, std::string *err,
+ const json &o) {
+ accessor->sparse.isSparse = true;
+
+ double count = 0.0;
+ ParseNumberProperty(&count, err, o, "count", true);
+
+ const auto indices_iterator = o.find("indices");
+ const auto values_iterator = o.find("values");
+ if (indices_iterator == o.end()) {
+ (*err) = "the sparse object of this accessor doesn't have indices";
+ return false;
+ }
+
+ if (values_iterator == o.end()) {
+ (*err) = "the sparse object ob ths accessor doesn't have values";
+ return false;
+ }
+
+ const json &indices_obj = *indices_iterator;
+ const json &values_obj = *values_iterator;
+
+ double indices_buffer_view = 0.0, indices_byte_offset = 0.0,
+ component_type = 0.0;
+ ParseNumberProperty(&indices_buffer_view, err, indices_obj, "bufferView",
+ true);
+ ParseNumberProperty(&indices_byte_offset, err, indices_obj, "byteOffset",
+ true);
+ ParseNumberProperty(&component_type, err, indices_obj, "componentType", true);
+
+ double values_buffer_view = 0.0, values_byte_offset = 0.0;
+ ParseNumberProperty(&values_buffer_view, err, values_obj, "bufferView", true);
+ ParseNumberProperty(&values_byte_offset, err, values_obj, "byteOffset", true);
+
+ accessor->sparse.count = static_cast<int>(count);
+ accessor->sparse.indices.bufferView = static_cast<int>(indices_buffer_view);
+ accessor->sparse.indices.byteOffset = static_cast<int>(indices_byte_offset);
+ accessor->sparse.indices.componentType = static_cast<int>(component_type);
+ accessor->sparse.values.bufferView = static_cast<int>(values_buffer_view);
+ accessor->sparse.values.byteOffset = static_cast<int>(values_byte_offset);
+
+ // todo check theses values
return true;
}
@@ -2906,112 +2988,128 @@
ParseExtrasProperty(&(accessor->extras), o);
+ // check if accessor has a "sparse" object:
+ const auto iterator = o.find("sparse");
+ if (iterator != o.end()) {
+ // here this accessor has a "sparse" subobject
+ return ParseSparseAccessor(accessor, err, *iterator);
+ }
+
return true;
}
#ifdef TINYGLTF_ENABLE_DRACO
-static void DecodeIndexBuffer(draco::Mesh* mesh, size_t componentSize, std::vector<uint8_t>& outBuffer)
-{
- if (componentSize == 4)
- {
+static void DecodeIndexBuffer(draco::Mesh *mesh, size_t componentSize,
+ std::vector<uint8_t> &outBuffer) {
+ if (componentSize == 4) {
assert(sizeof(mesh->face(draco::FaceIndex(0))[0]) == componentSize);
- memcpy(outBuffer.data(), &mesh->face(draco::FaceIndex(0))[0], outBuffer.size());
- }
- else
- {
+ memcpy(outBuffer.data(), &mesh->face(draco::FaceIndex(0))[0],
+ outBuffer.size());
+ } else {
size_t faceStride = componentSize * 3;
- for (draco::FaceIndex f(0); f < mesh->num_faces(); ++f)
- {
- const draco::Mesh::Face& face = mesh->face(f);
- if (componentSize == 2)
- {
- uint16_t indices[3] = { (uint16_t)face[0].value(), (uint16_t)face[1].value(), (uint16_t)face[2].value() };
- memcpy(outBuffer.data() + f.value() * faceStride, &indices[0], faceStride);
- }
- else
- {
- uint8_t indices[3] = { (uint8_t)face[0].value(), (uint8_t)face[1].value(), (uint8_t)face[2].value() };
- memcpy(outBuffer.data() + f.value() * faceStride, &indices[0], faceStride);
+ for (draco::FaceIndex f(0); f < mesh->num_faces(); ++f) {
+ const draco::Mesh::Face &face = mesh->face(f);
+ if (componentSize == 2) {
+ uint16_t indices[3] = {(uint16_t)face[0].value(),
+ (uint16_t)face[1].value(),
+ (uint16_t)face[2].value()};
+ memcpy(outBuffer.data() + f.value() * faceStride, &indices[0],
+ faceStride);
+ } else {
+ uint8_t indices[3] = {(uint8_t)face[0].value(),
+ (uint8_t)face[1].value(),
+ (uint8_t)face[2].value()};
+ memcpy(outBuffer.data() + f.value() * faceStride, &indices[0],
+ faceStride);
}
}
}
}
-template<typename T>
-static bool GetAttributeForAllPoints(draco::Mesh* mesh, const draco::PointAttribute* pAttribute, std::vector<uint8_t>& outBuffer)
-{
+template <typename T>
+static bool GetAttributeForAllPoints(draco::Mesh *mesh,
+ const draco::PointAttribute *pAttribute,
+ std::vector<uint8_t> &outBuffer) {
size_t byteOffset = 0;
- T values[4] = { 0, 0, 0, 0 };
- for (draco::PointIndex i(0); i < mesh->num_points(); ++i)
- {
+ T values[4] = {0, 0, 0, 0};
+ for (draco::PointIndex i(0); i < mesh->num_points(); ++i) {
const draco::AttributeValueIndex val_index = pAttribute->mapped_index(i);
- if (!pAttribute->ConvertValue<T>(val_index, pAttribute->num_components(), values))
+ if (!pAttribute->ConvertValue<T>(val_index, pAttribute->num_components(),
+ values))
return false;
- memcpy(outBuffer.data() + byteOffset, &values[0], sizeof(T) * pAttribute->num_components());
+ memcpy(outBuffer.data() + byteOffset, &values[0],
+ sizeof(T) * pAttribute->num_components());
byteOffset += sizeof(T) * pAttribute->num_components();
}
return true;
}
-static bool GetAttributeForAllPoints(uint32_t componentType, draco::Mesh* mesh, const draco::PointAttribute* pAttribute, std::vector<uint8_t>& outBuffer)
-{
+static bool GetAttributeForAllPoints(uint32_t componentType, draco::Mesh *mesh,
+ const draco::PointAttribute *pAttribute,
+ std::vector<uint8_t> &outBuffer) {
bool decodeResult = false;
- switch (componentType)
- {
- case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE:
- decodeResult = GetAttributeForAllPoints<uint8_t>(mesh, pAttribute, outBuffer);
- break;
- case TINYGLTF_COMPONENT_TYPE_BYTE:
- decodeResult = GetAttributeForAllPoints<int8_t>(mesh, pAttribute, outBuffer);
- break;
- case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT:
- decodeResult = GetAttributeForAllPoints<uint16_t>(mesh, pAttribute, outBuffer);
- break;
- case TINYGLTF_COMPONENT_TYPE_SHORT:
- decodeResult = GetAttributeForAllPoints<int16_t>(mesh, pAttribute, outBuffer);
- break;
- case TINYGLTF_COMPONENT_TYPE_INT:
- decodeResult = GetAttributeForAllPoints<int32_t>(mesh, pAttribute, outBuffer);
- break;
- case TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT:
- decodeResult = GetAttributeForAllPoints<uint32_t>(mesh, pAttribute, outBuffer);
- break;
- case TINYGLTF_COMPONENT_TYPE_FLOAT:
- decodeResult = GetAttributeForAllPoints<float>(mesh, pAttribute, outBuffer);
- break;
- case TINYGLTF_COMPONENT_TYPE_DOUBLE:
- decodeResult = GetAttributeForAllPoints<double>(mesh, pAttribute, outBuffer);
- break;
- default:
- return false;
+ switch (componentType) {
+ case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE:
+ decodeResult =
+ GetAttributeForAllPoints<uint8_t>(mesh, pAttribute, outBuffer);
+ break;
+ case TINYGLTF_COMPONENT_TYPE_BYTE:
+ decodeResult =
+ GetAttributeForAllPoints<int8_t>(mesh, pAttribute, outBuffer);
+ break;
+ case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT:
+ decodeResult =
+ GetAttributeForAllPoints<uint16_t>(mesh, pAttribute, outBuffer);
+ break;
+ case TINYGLTF_COMPONENT_TYPE_SHORT:
+ decodeResult =
+ GetAttributeForAllPoints<int16_t>(mesh, pAttribute, outBuffer);
+ break;
+ case TINYGLTF_COMPONENT_TYPE_INT:
+ decodeResult =
+ GetAttributeForAllPoints<int32_t>(mesh, pAttribute, outBuffer);
+ break;
+ case TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT:
+ decodeResult =
+ GetAttributeForAllPoints<uint32_t>(mesh, pAttribute, outBuffer);
+ break;
+ case TINYGLTF_COMPONENT_TYPE_FLOAT:
+ decodeResult =
+ GetAttributeForAllPoints<float>(mesh, pAttribute, outBuffer);
+ break;
+ case TINYGLTF_COMPONENT_TYPE_DOUBLE:
+ decodeResult =
+ GetAttributeForAllPoints<double>(mesh, pAttribute, outBuffer);
+ break;
+ default:
+ return false;
}
return decodeResult;
}
-static bool ParseDracoExtension(Primitive *primitive, Model *model, std::string *err, const Value &dracoExtensionValue)
-{
+static bool ParseDracoExtension(Primitive *primitive, Model *model,
+ std::string *err,
+ const Value &dracoExtensionValue) {
auto bufferViewValue = dracoExtensionValue.Get("bufferView");
- if (!bufferViewValue.IsInt())
- return false;
+ if (!bufferViewValue.IsInt()) return false;
auto attributesValue = dracoExtensionValue.Get("attributes");
- if (!attributesValue.IsObject())
- return false;
+ if (!attributesValue.IsObject()) return false;
auto attributesObject = attributesValue.Get<Value::Object>();
int bufferView = bufferViewValue.Get<int>();
- BufferView& view = model->bufferViews[bufferView];
- Buffer& buffer = model->buffers[view.buffer];
+ BufferView &view = model->bufferViews[bufferView];
+ Buffer &buffer = model->buffers[view.buffer];
// BufferView has already been decoded
- if (view.dracoDecoded)
- return true;
+ if (view.dracoDecoded) return true;
view.dracoDecoded = true;
- const char* bufferViewData = reinterpret_cast<const char*>(buffer.data.data() + view.byteOffset);
+ const char *bufferViewData =
+ reinterpret_cast<const char *>(buffer.data.data() + view.byteOffset);
size_t bufferViewSize = view.byteLength;
// decode draco
@@ -3022,12 +3120,12 @@
if (!decodeResult.ok()) {
return false;
}
- const std::unique_ptr<draco::Mesh>& mesh = decodeResult.value();
+ const std::unique_ptr<draco::Mesh> &mesh = decodeResult.value();
// create new bufferView for indices
- if (primitive->indices >= 0)
- {
- int32_t componentSize = GetComponentSizeInBytes(model->accessors[primitive->indices].componentType);
+ if (primitive->indices >= 0) {
+ int32_t componentSize = GetComponentSizeInBytes(
+ model->accessors[primitive->indices].componentType);
Buffer decodedIndexBuffer;
decodedIndexBuffer.data.resize(mesh->num_faces() * 3 * componentSize);
@@ -3037,35 +3135,37 @@
BufferView decodedIndexBufferView;
decodedIndexBufferView.buffer = int(model->buffers.size() - 1);
- decodedIndexBufferView.byteLength = int(mesh->num_faces() * 3 * componentSize);
+ decodedIndexBufferView.byteLength =
+ int(mesh->num_faces() * 3 * componentSize);
decodedIndexBufferView.byteOffset = 0;
decodedIndexBufferView.byteStride = 0;
decodedIndexBufferView.target = TINYGLTF_TARGET_ARRAY_BUFFER;
model->bufferViews.emplace_back(std::move(decodedIndexBufferView));
- model->accessors[primitive->indices].bufferView = int(model->bufferViews.size() - 1);
+ model->accessors[primitive->indices].bufferView =
+ int(model->bufferViews.size() - 1);
model->accessors[primitive->indices].count = int(mesh->num_faces() * 3);
}
- for (const auto& attribute : attributesObject)
- {
- if (!attribute.second.IsInt())
- return false;
+ for (const auto &attribute : attributesObject) {
+ if (!attribute.second.IsInt()) return false;
auto primitiveAttribute = primitive->attributes.find(attribute.first);
- if (primitiveAttribute == primitive->attributes.end())
- return false;
+ if (primitiveAttribute == primitive->attributes.end()) return false;
int dracoAttributeIndex = attribute.second.Get<int>();
const auto pAttribute = mesh->GetAttributeByUniqueId(dracoAttributeIndex);
const auto pBuffer = pAttribute->buffer();
- const auto componentType = model->accessors[primitiveAttribute->second].componentType;
+ const auto componentType =
+ model->accessors[primitiveAttribute->second].componentType;
// Create a new buffer for this decoded buffer
Buffer decodedBuffer;
- size_t bufferSize = mesh->num_points() * pAttribute->num_components() * GetComponentSizeInBytes(componentType);
+ size_t bufferSize = mesh->num_points() * pAttribute->num_components() *
+ GetComponentSizeInBytes(componentType);
decodedBuffer.data.resize(bufferSize);
- if (!GetAttributeForAllPoints(componentType, mesh.get(), pAttribute, decodedBuffer.data))
+ if (!GetAttributeForAllPoints(componentType, mesh.get(), pAttribute,
+ decodedBuffer.data))
return false;
model->buffers.emplace_back(std::move(decodedBuffer));
@@ -3075,11 +3175,15 @@
decodedBufferView.byteLength = bufferSize;
decodedBufferView.byteOffset = pAttribute->byte_offset();
decodedBufferView.byteStride = pAttribute->byte_stride();
- decodedBufferView.target = primitive->indices >= 0 ? TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER : TINYGLTF_TARGET_ARRAY_BUFFER;
+ decodedBufferView.target = primitive->indices >= 0
+ ? TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER
+ : TINYGLTF_TARGET_ARRAY_BUFFER;
model->bufferViews.emplace_back(std::move(decodedBufferView));
- model->accessors[primitiveAttribute->second].bufferView = int(model->bufferViews.size() - 1);
- model->accessors[primitiveAttribute->second].count = int(mesh->num_points());
+ model->accessors[primitiveAttribute->second].bufferView =
+ int(model->bufferViews.size() - 1);
+ model->accessors[primitiveAttribute->second].count =
+ int(mesh->num_points());
}
return true;
@@ -3129,10 +3233,10 @@
ParseExtensionsProperty(&primitive->extensions, err, o);
#ifdef TINYGLTF_ENABLE_DRACO
- auto dracoExtension = primitive->extensions.find("KHR_draco_mesh_compression");
- if (dracoExtension != primitive->extensions.end())
- {
- ParseDracoExtension(primitive, model, err, dracoExtension->second);
+ auto dracoExtension =
+ primitive->extensions.find("KHR_draco_mesh_compression");
+ if (dracoExtension != primitive->extensions.end()) {
+ ParseDracoExtension(primitive, model, err, dracoExtension->second);
}
#else
(void)model;
@@ -3141,7 +3245,8 @@
return true;
}
-static bool ParseMesh(Mesh *mesh, Model *model, std::string *err, const json &o) {
+static bool ParseMesh(Mesh *mesh, Model *model, std::string *err,
+ const json &o) {
ParseStringProperty(&mesh->name, err, o, "name", false);
mesh->primitives.clear();
@@ -3816,22 +3921,22 @@
// Assign missing bufferView target types
// - Look for missing Mesh indices
// - Look for missing bufferView targets
- for (auto &mesh : model->meshes)
- {
- for (auto &primitive : mesh.primitives)
- {
- if (primitive.indices > -1) // has indices from parsing step, must be Element Array Buffer
+ for (auto &mesh : model->meshes) {
+ for (auto &primitive : mesh.primitives) {
+ if (primitive.indices >
+ -1) // has indices from parsing step, must be Element Array Buffer
{
model->bufferViews[model->accessors[primitive.indices].bufferView]
.target = TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER;
- // we could optionally check if acessors' bufferView type is Scalar, as it should be
+ // we could optionally check if acessors' bufferView type is Scalar, as
+ // it should be
}
}
}
- // find any missing targets, must be an array buffer type if not fulfilled from previous check
- for (auto &bufferView : model->bufferViews)
- {
- if (bufferView.target == 0) // missing target type
+ // find any missing targets, must be an array buffer type if not fulfilled
+ // from previous check
+ for (auto &bufferView : model->bufferViews) {
+ if (bufferView.target == 0) // missing target type
{
bufferView.target = TINYGLTF_TARGET_ARRAY_BUFFER;
}
@@ -3950,7 +4055,8 @@
for (; it != itEnd; it++, idx++) {
if (!it.value().is_object()) {
if (err) {
- (*err) += "image[" + std::to_string(idx) + "] is not a JSON object.";
+ (*err) +=
+ "image[" + std::to_string(idx) + "] is not a JSON object.";
}
return false;
}
@@ -3982,10 +4088,10 @@
}
return false;
}
- bool ret = LoadImageData(&image, idx, err, warn, image.width, image.height,
- &buffer.data[bufferView.byteOffset],
- static_cast<int>(bufferView.byteLength),
- load_image_user_data_);
+ bool ret = LoadImageData(
+ &image, idx, err, warn, image.width, image.height,
+ &buffer.data[bufferView.byteOffset],
+ static_cast<int>(bufferView.byteLength), load_image_user_data_);
if (!ret) {
return false;
}
@@ -4439,7 +4545,7 @@
static bool SerializeGltfBufferData(const std::vector<unsigned char> &data,
const std::string &binFilename) {
std::ofstream output(binFilename.c_str(), std::ofstream::binary);
- if(!output.is_open()) return false;
+ if (!output.is_open()) return false;
output.write(reinterpret_cast<const char *>(&data[0]),
std::streamsize(data.size()));
output.close();
@@ -4488,9 +4594,10 @@
if (ValueToJson(extIt->second, &ret)) {
extMap[extIt->first] = ret;
}
- if(ret.is_null()) {
- if (!(extIt->first.empty())) { // name should not be empty, but for sure
- // create empty object so that an extension name is still included in json.
+ if (ret.is_null()) {
+ if (!(extIt->first.empty())) { // name should not be empty, but for sure
+ // create empty object so that an extension name is still included in
+ // json.
extMap[extIt->first] = json({});
}
}
@@ -4621,7 +4728,7 @@
static bool SerializeGltfBuffer(Buffer &buffer, json &o,
const std::string &binFilename,
const std::string &binBaseFilename) {
- if(!SerializeGltfBufferData(buffer.data, binFilename)) return false;
+ if (!SerializeGltfBufferData(buffer.data, binFilename)) return false;
SerializeNumberProperty("byteLength", buffer.data.size(), o);
SerializeStringProperty("uri", binBaseFilename, o);
@@ -4909,7 +5016,8 @@
const int version = 2;
const int padding_size = content.size() % 4;
- // 12 bytes for header, JSON content length, 8 bytes for JSON chunk info, padding
+ // 12 bytes for header, JSON content length, 8 bytes for JSON chunk info,
+ // padding
const int length = 12 + 8 + int(content.size()) + padding_size;
gltfFile.write(header.c_str(), header.size());
@@ -4919,8 +5027,10 @@
// JSON chunk info, then JSON data
const int model_length = int(content.size()) + padding_size;
const int model_format = 0x4E4F534A;
- gltfFile.write(reinterpret_cast<const char *>(&model_length), sizeof(model_length));
- gltfFile.write(reinterpret_cast<const char *>(&model_format), sizeof(model_format));
+ gltfFile.write(reinterpret_cast<const char *>(&model_length),
+ sizeof(model_length));
+ gltfFile.write(reinterpret_cast<const char *>(&model_format),
+ sizeof(model_format));
gltfFile.write(content.c_str(), content.size());
// Chunk must be multiplies of 4, so pad with spaces
@@ -4966,7 +5076,8 @@
std::string defaultBinFilename = GetBaseFilename(filename);
std::string defaultBinFileExt = ".bin";
- std::string::size_type pos = defaultBinFilename.rfind('.', defaultBinFilename.length());
+ std::string::size_type pos =
+ defaultBinFilename.rfind('.', defaultBinFilename.length());
if (pos != std::string::npos) {
defaultBinFilename = defaultBinFilename.substr(0, pos);
@@ -4986,28 +5097,27 @@
} else {
std::string binSavePath;
std::string binUri;
- if (!model->buffers[i].uri.empty()
- && !IsDataURI(model->buffers[i].uri)) {
+ if (!model->buffers[i].uri.empty() && !IsDataURI(model->buffers[i].uri)) {
binUri = model->buffers[i].uri;
- }
- else {
+ } else {
binUri = defaultBinFilename + defaultBinFileExt;
bool inUse = true;
int numUsed = 0;
- while(inUse) {
+ while (inUse) {
inUse = false;
- for (const std::string& usedName : usedUris) {
+ for (const std::string &usedName : usedUris) {
if (binUri.compare(usedName) != 0) continue;
inUse = true;
- binUri = defaultBinFilename + std::to_string(numUsed++) + defaultBinFileExt;
+ binUri = defaultBinFilename + std::to_string(numUsed++) +
+ defaultBinFileExt;
break;
}
}
}
usedUris.push_back(binUri);
- binSavePath = JoinPath(baseDir, binUri);
- if(!SerializeGltfBuffer(model->buffers[i], buffer, binSavePath,
- binUri)) {
+ binSavePath = JoinPath(baseDir, binUri);
+ if (!SerializeGltfBuffer(model->buffers[i], buffer, binSavePath,
+ binUri)) {
return false;
}
}