From fbc6118c6a751d9e9081e0dbf7c6b151477eac6a Mon Sep 17 00:00:00 2001 From: Syoyo Fujita Date: Sun, 5 Jun 2016 22:17:19 +0900 Subject: [PATCH 1/8] Missing indices print. --- loader_example.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/loader_example.cc b/loader_example.cc index 15a2860..8cbff1d 100644 --- a/loader_example.cc +++ b/loader_example.cc @@ -146,6 +146,8 @@ static void DumpNode(const tinygltf::Node &node, int indent) { static void DumpPrimitive(const tinygltf::Primitive &primitive, int indent) { std::cout << Indent(indent) << "material : " << primitive.material << std::endl; + std::cout << Indent(indent) << "indices : " << primitive.indices + << std::endl; std::cout << Indent(indent) << "mode : " << PrintMode(primitive.mode) << "(" << primitive.mode << ")" << std::endl; std::cout << Indent(indent) From e04b1b56d86dcc012064cb94c645854d559dfbab Mon Sep 17 00:00:00 2001 From: Syoyo Fujita Date: Sun, 5 Jun 2016 22:31:20 +0900 Subject: [PATCH 2/8] Add error check for `scenes` property. --- tiny_gltf_loader.h | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/tiny_gltf_loader.h b/tiny_gltf_loader.h index 867cfa9..12f89d4 100644 --- a/tiny_gltf_loader.h +++ b/tiny_gltf_loader.h @@ -1,7 +1,7 @@ // // Tiny glTF loader. // -// Copyright (c) 2015, Syoyo Fujita. +// Copyright (c) 2015-2016, Syoyo Fujita. // All rights reserved. // (Licensed under 2-clause BSD liecense) // @@ -1124,8 +1124,8 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, if (err) { std::stringstream ss; ss << "Invalid `byteLength'. Must be equal or less than binary size: " - "`byteLength' = " << byteLength - << ", binary size = " << bin_size << std::endl; + "`byteLength' = " + << byteLength << ", binary size = " << bin_size << std::endl; (*err) += ss.str(); } return false; @@ -1589,6 +1589,12 @@ bool TinyGLTFLoader::LoadFromString(Scene *scene, std::string *err, picojson::object::const_iterator it(root.begin()); picojson::object::const_iterator itEnd(root.end()); for (; it != itEnd; it++) { + if (!((it->second).is())) { + if (err) { + (*err) += "`scenes' does not contain an object."; + } + return false; + } const picojson::object &o = (it->second).get(); std::vector nodes; if (!ParseStringArrayProperty(&nodes, err, o, "nodes", false)) { From b37b7de27c316051991e1c929447e2237014268e Mon Sep 17 00:00:00 2001 From: Syoyo Fujita Date: Sun, 5 Jun 2016 22:35:37 +0900 Subject: [PATCH 3/8] Retinal display fix for glview. --- examples/glview/glview.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/glview/glview.cc b/examples/glview/glview.cc index 3002815..55037e0 100644 --- a/examples/glview/glview.cc +++ b/examples/glview/glview.cc @@ -142,7 +142,9 @@ bool LinkShader(GLuint &prog, GLuint &vertShader, GLuint &fragShader) { void reshapeFunc(GLFWwindow *window, int w, int h) { (void)window; - glViewport(0, 0, w, h); + int fb_w, fb_h; + glfwGetFramebufferSize(window, &fb_w, &fb_h); + glViewport(0, 0, fb_w, fb_h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0, (float)w / (float)h, 0.1f, 1000.0f); From d286bd9ac040ebe58d81c88e407e2583594e4ff1 Mon Sep 17 00:00:00 2001 From: Syoyo Fujita Date: Mon, 6 Jun 2016 01:20:32 +0900 Subject: [PATCH 4/8] Print bufferView.target. --- loader_example.cc | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/loader_example.cc b/loader_example.cc index 8cbff1d..e88848c 100644 --- a/loader_example.cc +++ b/loader_example.cc @@ -29,6 +29,16 @@ static std::string PrintMode(int mode) { return "**UNKNOWN**"; } +static std::string PrintTarget(int target) { + if (target == 34962) { + return "GL_ARRAY_BUFFER"; + } else if (target == 34963) { + return "GL_ELEMENT_ARRAY_BUFFER"; + } else { + return "**UNKNOWN**"; + } +} + static std::string PrintType(int ty) { if (ty == TINYGLTF_TYPE_SCALAR) { return "SCALAR"; @@ -267,6 +277,8 @@ static void Dump(const tinygltf::Scene &scene) { << std::endl; std::cout << Indent(2) << "byteOffset : " << it->second.byteOffset << std::endl; + std::cout << Indent(2) << "target : " << PrintTarget(it->second.target) + << std::endl; } } From 064d1774484cd9ad769303755fd5feb01f7c3e94 Mon Sep 17 00:00:00 2001 From: Syoyo Fujita Date: Mon, 6 Jun 2016 01:20:52 +0900 Subject: [PATCH 5/8] Print warning when bufferView.target == 0. --- examples/glview/glview.cc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/examples/glview/glview.cc b/examples/glview/glview.cc index 55037e0..9fb5632 100644 --- a/examples/glview/glview.cc +++ b/examples/glview/glview.cc @@ -237,6 +237,7 @@ static void SetupGLState(tinygltf::Scene &scene, GLuint progId) { for (; it != itEnd; it++) { const tinygltf::BufferView &bufferView = it->second; if (bufferView.target == 0) { + std::cout << "WARN: bufferView.target is zero" << std::endl; continue; // Unsupported bufferView. } @@ -244,6 +245,7 @@ static void SetupGLState(tinygltf::Scene &scene, GLuint progId) { 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); glBindBuffer(bufferView.target, 0); @@ -351,6 +353,8 @@ void DrawMesh(tinygltf::Scene &scene, const tinygltf::Mesh &mesh) { count = 3; } else if (accessor.type == TINYGLTF_TYPE_VEC4) { count = 4; + } else { + assert(0); } // it->first would be "POSITION", "NORMAL", "TEXCOORD_0", ... if ((it->first.compare("POSITION") == 0) || @@ -382,7 +386,9 @@ void DrawMesh(tinygltf::Scene &scene, const tinygltf::Mesh &mesh) { mode = GL_LINES; } else if (primitive.mode == TINYGLTF_MODE_LINE_LOOP) { mode = GL_LINE_LOOP; - }; + } else { + assert(0); + } glDrawElements(mode, indexAccessor.count, indexAccessor.componentType, BUFFER_OFFSET(indexAccessor.byteOffset)); CheckErrors("draw elements"); @@ -536,6 +542,8 @@ int main(int argc, char **argv) { SetupGLState(scene, progId); CheckErrors("SetupGLState"); + std::cout << "# of meshes = " << scene.meshes.size() << std::endl; + while (glfwWindowShouldClose(window) == GL_FALSE) { glfwPollEvents(); glClearColor(0.1f, 0.2f, 0.3f, 1.0f); From 0a3b09f33e86d55698d3453c1a4701db70730adf Mon Sep 17 00:00:00 2001 From: Syoyo Fujita Date: Mon, 6 Jun 2016 01:26:18 +0900 Subject: [PATCH 6/8] Initial glTF writer example(W.I.P). --- examples/writer/Makefile | 2 + examples/writer/README.md | 11 + examples/writer/writer.cc | 429 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 442 insertions(+) create mode 100644 examples/writer/Makefile create mode 100644 examples/writer/README.md create mode 100644 examples/writer/writer.cc diff --git a/examples/writer/Makefile b/examples/writer/Makefile new file mode 100644 index 0000000..7f7a703 --- /dev/null +++ b/examples/writer/Makefile @@ -0,0 +1,2 @@ +all: + $(CXX) -o gltf_writer -I../../ writer.cc diff --git a/examples/writer/README.md b/examples/writer/README.md new file mode 100644 index 0000000..32f2399 --- /dev/null +++ b/examples/writer/README.md @@ -0,0 +1,11 @@ +# Simple glTF writer in C++. + +Read glTF with tinygltfloader, and write it to glTF JSON. + +## TODO + +* [ ] Asset export option(embed, external file) +* [ ] Textures +* [ ] Materials +* [ ] etc. + diff --git a/examples/writer/writer.cc b/examples/writer/writer.cc new file mode 100644 index 0000000..e30ff67 --- /dev/null +++ b/examples/writer/writer.cc @@ -0,0 +1,429 @@ +#include +#include +#include +#include + +#define TINYGLTF_LOADER_IMPLEMENTATION +#define STB_IMAGE_IMPLEMENTATION +#include "../../tiny_gltf_loader.h" + +static std::string GetFilePathExtension(const std::string &filename) { + if (filename.find_last_of(".") != std::string::npos) + return filename.substr(filename.find_last_of(".") + 1); + return ""; +} + +// ---------------------------------------------------------------- +// writer module +// @todo { move writer code to tiny_gltf_writer.h } + +static std::string EncodeType(int ty) { + if (ty == TINYGLTF_TYPE_SCALAR) { + return "SCALAR"; + } else if (ty == TINYGLTF_TYPE_VECTOR) { + return "VECTOR"; + } else if (ty == TINYGLTF_TYPE_VEC2) { + return "VEC2"; + } else if (ty == TINYGLTF_TYPE_VEC3) { + return "VEC3"; + } else if (ty == TINYGLTF_TYPE_VEC4) { + return "VEC4"; + } else if (ty == TINYGLTF_TYPE_MATRIX) { + return "MATRIX"; + } else if (ty == TINYGLTF_TYPE_MAT2) { + return "MAT2"; + } else if (ty == TINYGLTF_TYPE_MAT3) { + return "MAT3"; + } else if (ty == TINYGLTF_TYPE_MAT4) { + return "MAT4"; + } + return "**UNKNOWN**"; +} + + +// http://www.adp-gmbh.ch/cpp/common/base64.html +static const std::string base64_chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + +std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) { + std::string ret; + int i = 0; + int j = 0; + unsigned char char_array_3[3]; + unsigned char char_array_4[4]; + + while (in_len--) { + char_array_3[i++] = *(bytes_to_encode++); + if (i == 3) { + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for(i = 0; (i <4) ; i++) + ret += base64_chars[char_array_4[i]]; + i = 0; + } + } + + if (i) + { + for(j = i; j < 3; j++) + char_array_3[j] = '\0'; + + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for (j = 0; (j < i + 1); j++) + ret += base64_chars[char_array_4[j]]; + + while((i++ < 3)) + ret += '='; + + } + + return ret; + +} + +bool EncodeBuffers(picojson::object* o, const std::map& buffers) +{ + std::map::const_iterator it(buffers.begin()); + std::map::const_iterator itEnd(buffers.end()); + for (; it != itEnd; it++) { + // @todo { Support external file resource. } + picojson::object buf; + std::string b64_data = base64_encode(it->second.data.data(), it->second.data.size()); + buf["type"] = picojson::value("arraybuffer"); + buf["uri"] = picojson::value(std::string("data:application/octet-stream;base64,") + b64_data); + buf["byteLength"] = picojson::value(static_cast(it->second.data.size())); + + (*o)[it->first] = picojson::value(buf); + } + + return true; +} + +bool EncodeBufferViews(picojson::object* o, const std::map& bufferViews) + { + std::map::const_iterator it( + bufferViews.begin()); + std::map::const_iterator itEnd( + bufferViews.end()); + + for (; it != itEnd; it++) { + picojson::object buf; + buf["buffer"] = picojson::value(it->second.buffer); + buf["byteLength"] = picojson::value(static_cast(it->second.byteLength)); + buf["byteOffset"] = picojson::value(static_cast(it->second.byteOffset)); + buf["target"] = picojson::value(static_cast(it->second.target)); + + (*o)[it->first] = picojson::value(buf); + } + + return true; + } + +bool EncodeFloatArray(picojson::array *arr, const std::vector& values) +{ + for (size_t i = 0; i < values.size(); i++) { + arr->push_back(picojson::value(values[i])); + } + + return true; +} + +bool EncodeStringArray(picojson::array *arr, const std::vector& values) +{ + for (size_t i = 0; i < values.size(); i++) { + arr->push_back(picojson::value(values[i])); + } + + return true; +} + +bool EncodeNode(picojson::object *o, const tinygltf::Node &node) { + (*o)["name"] = picojson::value(node.name); + (*o)["camera"] = picojson::value(node.camera); + + if (!node.rotation.empty()) { + picojson::array arr; + EncodeFloatArray(&arr, node.rotation); + (*o)["rotation"] = picojson::value(arr); + } + if (!node.scale.empty()) { + picojson::array arr; + EncodeFloatArray(&arr, node.scale); + (*o)["scale"] = picojson::value(arr); + } + if (!node.translation.empty()) { + picojson::array arr; + EncodeFloatArray(&arr, node.translation); + (*o)["translation"] = picojson::value(arr); + } + + if (!node.matrix.empty()) { + picojson::array arr; + EncodeFloatArray(&arr, node.matrix); + (*o)["matrix"] = picojson::value(arr); + } + + if (!node.meshes.empty()) { + picojson::array arr; + EncodeStringArray(&arr, node.meshes); + (*o)["meshes"] = picojson::value(arr); + } + + if (!node.children.empty()) { + picojson::array arr; + EncodeStringArray(&arr, node.children); + (*o)["children"] = picojson::value(arr); + } + + return true; +} + +bool EncodeNodes(picojson::object* o, const std::map &nodes) + { + std::map::const_iterator it(nodes.begin()); + std::map::const_iterator itEnd(nodes.end()); + + for (; it != itEnd; it++) { + picojson::object node; + EncodeNode(&node, it->second); + + (*o)[it->first] = picojson::value(node); + } + + return true; + } + +bool EncodeScenes(picojson::object* o, const std::map >& scenes) + { + std::map >::const_iterator it( + scenes.begin()); + std::map >::const_iterator itEnd( + scenes.end()); + + for (; it != itEnd; it++) { + + picojson::object buf; + picojson::array arr; + for (size_t i = 0; i < it->second.size(); i++) { + arr.push_back(picojson::value(it->second[i])); + } + + buf["nodes"] = picojson::value(arr); + + (*o)[it->first] = picojson::value(buf); + } + + return true; + } + +bool EncodeAccessors(picojson::object* o, const std::map& accessors) + { + std::map::const_iterator it(accessors.begin()); + std::map::const_iterator itEnd( + accessors.end()); + for (; it != itEnd; it++) { + picojson::object buf; + buf["bufferView"] = picojson::value(it->second.bufferView); + buf["byteOffset"] = picojson::value(static_cast(it->second.byteOffset)); + buf["byteStride"] = picojson::value(static_cast(it->second.byteStride)); + buf["componentType"] = picojson::value(static_cast(it->second.componentType)); + buf["count"] = picojson::value(static_cast(it->second.count)); + buf["type"] = picojson::value(EncodeType(it->second.type)); + + if (!it->second.minValues.empty()) { + picojson::array arr; + EncodeFloatArray(&arr, it->second.minValues); + buf["min"] = picojson::value(arr); + } + if (!it->second.maxValues.empty()) { + picojson::array arr; + EncodeFloatArray(&arr, it->second.maxValues); + buf["max"] = picojson::value(arr); + } + + (*o)[it->first] = picojson::value(buf); + } + + return true; + } + +bool EncodePrimitive(picojson::object* o, const tinygltf::Primitive &primitive) { + (*o)["material"] = picojson::value(primitive.material); + (*o)["indices"] = picojson::value(primitive.indices); + (*o)["mode"] = picojson::value(static_cast(primitive.mode)); + + std::map::const_iterator it( + primitive.attributes.begin()); + std::map::const_iterator itEnd( + primitive.attributes.end()); + + picojson::object attributes; + for (; it != itEnd; it++) { + picojson::object buf; + attributes[it->first] = picojson::value(it->second); + } + + (*o)["attributes"] = picojson::value(attributes); + + return true; +} + +bool EncodeMeshes(picojson::object* o, const std::map& meshes) +{ + std::map::const_iterator it(meshes.begin()); + std::map::const_iterator itEnd(meshes.end()); + for (; it != itEnd; it++) { + picojson::object buf; + + buf["name"] = picojson::value(it->second.name); + + picojson::array arr; + for (size_t i = 0; i < it->second.primitives.size(); i++) { + picojson::object primitive; + EncodePrimitive(&primitive, it->second.primitives[i]); + arr.push_back(picojson::value(primitive)); + } + buf["primitives"] = picojson::value(arr); + + (*o)[it->first] = picojson::value(buf); + } + return true; + } + +bool SaveGLTF(const std::string& output_filename, const tinygltf::Scene& scene) +{ + picojson::object root; + + { + picojson::object asset; + asset["generator"] = picojson::value("tinygltf_writer"); + asset["premultipliedAlpha"] = picojson::value(true); + asset["version"] = picojson::value(static_cast(1)); + picojson::object profile; + profile["api"] = picojson::value("WebGL"); + profile["version"] = picojson::value("1.0.2"); + asset["profile"] = picojson::value(profile); + root["assets"] = picojson::value(asset); + } + + { + picojson::object buffers; + bool ret = EncodeBuffers(&buffers, scene.buffers); + assert(ret); + root["buffers"] = picojson::value(buffers); + } + + { + picojson::object bufferViews; + bool ret = EncodeBufferViews(&bufferViews, scene.bufferViews); + assert(ret); + root["bufferViews"] = picojson::value(bufferViews); + } + + { + picojson::object accessors; + bool ret = EncodeAccessors(&accessors, scene.accessors); + assert(ret); + root["accessors"] = picojson::value(accessors); + } + + { + picojson::object meshes; + bool ret = EncodeMeshes(&meshes, scene.meshes); + assert(ret); + root["meshes"] = picojson::value(meshes); + } + + { + picojson::object nodes; + bool ret = EncodeNodes(&nodes, scene.nodes); + assert(ret); + root["nodes"] = picojson::value(nodes); + } + + root["scene"] = picojson::value(scene.defaultScene); + { + picojson::object scenes; + bool ret = EncodeScenes(&scenes, scene.scenes); + assert(ret); + root["scenes"] = picojson::value(scenes); + } + + + // @todo {} + picojson::object shaders; + picojson::object programs; + picojson::object techniques; + picojson::object materials; + picojson::object skins; + root["shaders"] = picojson::value(shaders); + root["programs"] = picojson::value(programs); + root["techniques"] = picojson::value(techniques); + root["materials"] = picojson::value(materials); + root["skins"] = picojson::value(skins); + + picojson::value v = picojson::value(root); + + std::ofstream ifs(output_filename); + if (ifs.bad()) { + std::cerr << "Failed to open " << output_filename << std::endl; + return false; + } + + std::string s = v.serialize(); + ifs.write(s.data(), s.size()); + ifs.close(); + + return true; +} + +// ---------------------------------------------------------------- + +int +main( + int argc, + char **argv) +{ + if (argc < 3) { + printf("Needs input.gltf output.gltf\n"); + exit(1); + } + + tinygltf::Scene scene; + tinygltf::TinyGLTFLoader loader; + std::string err; + std::string input_filename(argv[1]); + std::string ext = GetFilePathExtension(input_filename); + + bool ret = false; + if (ext.compare("glb") == 0) { + // assume binary glTF. + ret = loader.LoadBinaryFromFile(&scene, &err, input_filename.c_str()); + } else { + // assume ascii glTF. + ret = loader.LoadASCIIFromFile(&scene, &err, input_filename.c_str()); + } + + if (!err.empty()) { + printf("Err: %s\n", err.c_str()); + } + + if (!ret) { + printf("Failed to parse glTF\n"); + return -1; + } + + ret = SaveGLTF(argv[2], scene); + + return ret ? EXIT_SUCCESS : EXIT_FAILURE; + +} From 9a478238c75fed8e7bfc2ea8f36157b6b29c9208 Mon Sep 17 00:00:00 2001 From: Syoyo Fujita Date: Mon, 6 Jun 2016 01:26:57 +0900 Subject: [PATCH 7/8] Format source. --- examples/writer/writer.cc | 286 +++++++++++++++++++------------------- 1 file changed, 144 insertions(+), 142 deletions(-) diff --git a/examples/writer/writer.cc b/examples/writer/writer.cc index e30ff67..01d66b2 100644 --- a/examples/writer/writer.cc +++ b/examples/writer/writer.cc @@ -1,13 +1,13 @@ #include #include -#include #include +#include #define TINYGLTF_LOADER_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION #include "../../tiny_gltf_loader.h" -static std::string GetFilePathExtension(const std::string &filename) { +static std::string GetFilePathExtension(const std::string& filename) { if (filename.find_last_of(".") != std::string::npos) return filename.substr(filename.find_last_of(".") + 1); return ""; @@ -40,14 +40,14 @@ static std::string EncodeType(int ty) { return "**UNKNOWN**"; } - // http://www.adp-gmbh.ch/cpp/common/base64.html -static const std::string base64_chars = - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/"; +static const std::string base64_chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; -std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) { +std::string base64_encode(unsigned char const* bytes_to_encode, + unsigned int in_len) { std::string ret; int i = 0; int j = 0; @@ -58,49 +58,49 @@ std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_ char_array_3[i++] = *(bytes_to_encode++); if (i == 3) { char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; - char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); - char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[1] = + ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = + ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); char_array_4[3] = char_array_3[2] & 0x3f; - for(i = 0; (i <4) ; i++) - ret += base64_chars[char_array_4[i]]; + for (i = 0; (i < 4); i++) ret += base64_chars[char_array_4[i]]; i = 0; } } - if (i) - { - for(j = i; j < 3; j++) - char_array_3[j] = '\0'; + if (i) { + for (j = i; j < 3; j++) char_array_3[j] = '\0'; char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; - char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); - char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[1] = + ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = + ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); char_array_4[3] = char_array_3[2] & 0x3f; - for (j = 0; (j < i + 1); j++) - ret += base64_chars[char_array_4[j]]; - - while((i++ < 3)) - ret += '='; + for (j = 0; (j < i + 1); j++) ret += base64_chars[char_array_4[j]]; + while ((i++ < 3)) ret += '='; } return ret; - } -bool EncodeBuffers(picojson::object* o, const std::map& buffers) -{ +bool EncodeBuffers(picojson::object* o, + const std::map& buffers) { std::map::const_iterator it(buffers.begin()); std::map::const_iterator itEnd(buffers.end()); for (; it != itEnd; it++) { - // @todo { Support external file resource. } + // @todo { Support external file resource. } picojson::object buf; - std::string b64_data = base64_encode(it->second.data.data(), it->second.data.size()); + std::string b64_data = + base64_encode(it->second.data.data(), it->second.data.size()); buf["type"] = picojson::value("arraybuffer"); - buf["uri"] = picojson::value(std::string("data:application/octet-stream;base64,") + b64_data); - buf["byteLength"] = picojson::value(static_cast(it->second.data.size())); + buf["uri"] = picojson::value( + std::string("data:application/octet-stream;base64,") + b64_data); + buf["byteLength"] = + picojson::value(static_cast(it->second.data.size())); (*o)[it->first] = picojson::value(buf); } @@ -108,28 +108,30 @@ bool EncodeBuffers(picojson::object* o, const std::map& bufferViews) - { - std::map::const_iterator it( - bufferViews.begin()); - std::map::const_iterator itEnd( - bufferViews.end()); +bool EncodeBufferViews( + picojson::object* o, + const std::map& bufferViews) { + std::map::const_iterator it( + bufferViews.begin()); + std::map::const_iterator itEnd( + bufferViews.end()); - for (; it != itEnd; it++) { - picojson::object buf; - buf["buffer"] = picojson::value(it->second.buffer); - buf["byteLength"] = picojson::value(static_cast(it->second.byteLength)); - buf["byteOffset"] = picojson::value(static_cast(it->second.byteOffset)); - buf["target"] = picojson::value(static_cast(it->second.target)); + for (; it != itEnd; it++) { + picojson::object buf; + buf["buffer"] = picojson::value(it->second.buffer); + buf["byteLength"] = + picojson::value(static_cast(it->second.byteLength)); + buf["byteOffset"] = + picojson::value(static_cast(it->second.byteOffset)); + buf["target"] = picojson::value(static_cast(it->second.target)); - (*o)[it->first] = picojson::value(buf); - } - - return true; + (*o)[it->first] = picojson::value(buf); } -bool EncodeFloatArray(picojson::array *arr, const std::vector& values) -{ + return true; +} + +bool EncodeFloatArray(picojson::array* arr, const std::vector& values) { for (size_t i = 0; i < values.size(); i++) { arr->push_back(picojson::value(values[i])); } @@ -137,8 +139,8 @@ bool EncodeFloatArray(picojson::array *arr, const std::vector& values) return true; } -bool EncodeStringArray(picojson::array *arr, const std::vector& values) -{ +bool EncodeStringArray(picojson::array* arr, + const std::vector& values) { for (size_t i = 0; i < values.size(); i++) { arr->push_back(picojson::value(values[i])); } @@ -146,7 +148,7 @@ bool EncodeStringArray(picojson::array *arr, const std::vector& val return true; } -bool EncodeNode(picojson::object *o, const tinygltf::Node &node) { +bool EncodeNode(picojson::object* o, const tinygltf::Node& node) { (*o)["name"] = picojson::value(node.name); (*o)["camera"] = picojson::value(node.camera); @@ -187,76 +189,82 @@ bool EncodeNode(picojson::object *o, const tinygltf::Node &node) { return true; } -bool EncodeNodes(picojson::object* o, const std::map &nodes) - { - std::map::const_iterator it(nodes.begin()); - std::map::const_iterator itEnd(nodes.end()); +bool EncodeNodes(picojson::object* o, + const std::map& nodes) { + std::map::const_iterator it(nodes.begin()); + std::map::const_iterator itEnd(nodes.end()); - for (; it != itEnd; it++) { - picojson::object node; - EncodeNode(&node, it->second); + for (; it != itEnd; it++) { + picojson::object node; + EncodeNode(&node, it->second); - (*o)[it->first] = picojson::value(node); - } - - return true; + (*o)[it->first] = picojson::value(node); } -bool EncodeScenes(picojson::object* o, const std::map >& scenes) - { - std::map >::const_iterator it( - scenes.begin()); - std::map >::const_iterator itEnd( - scenes.end()); - - for (; it != itEnd; it++) { - - picojson::object buf; - picojson::array arr; - for (size_t i = 0; i < it->second.size(); i++) { - arr.push_back(picojson::value(it->second[i])); - } - - buf["nodes"] = picojson::value(arr); - - (*o)[it->first] = picojson::value(buf); - } - - return true; - } - -bool EncodeAccessors(picojson::object* o, const std::map& accessors) - { - std::map::const_iterator it(accessors.begin()); - std::map::const_iterator itEnd( - accessors.end()); - for (; it != itEnd; it++) { - picojson::object buf; - buf["bufferView"] = picojson::value(it->second.bufferView); - buf["byteOffset"] = picojson::value(static_cast(it->second.byteOffset)); - buf["byteStride"] = picojson::value(static_cast(it->second.byteStride)); - buf["componentType"] = picojson::value(static_cast(it->second.componentType)); - buf["count"] = picojson::value(static_cast(it->second.count)); - buf["type"] = picojson::value(EncodeType(it->second.type)); - - if (!it->second.minValues.empty()) { - picojson::array arr; - EncodeFloatArray(&arr, it->second.minValues); - buf["min"] = picojson::value(arr); - } - if (!it->second.maxValues.empty()) { - picojson::array arr; - EncodeFloatArray(&arr, it->second.maxValues); - buf["max"] = picojson::value(arr); - } - - (*o)[it->first] = picojson::value(buf); - } - return true; +} + +bool EncodeScenes( + picojson::object* o, + const std::map >& scenes) { + std::map >::const_iterator it( + scenes.begin()); + std::map >::const_iterator itEnd( + scenes.end()); + + for (; it != itEnd; it++) { + picojson::object buf; + picojson::array arr; + for (size_t i = 0; i < it->second.size(); i++) { + arr.push_back(picojson::value(it->second[i])); + } + + buf["nodes"] = picojson::value(arr); + + (*o)[it->first] = picojson::value(buf); } -bool EncodePrimitive(picojson::object* o, const tinygltf::Primitive &primitive) { + return true; +} + +bool EncodeAccessors( + picojson::object* o, + const std::map& accessors) { + std::map::const_iterator it( + accessors.begin()); + std::map::const_iterator itEnd( + accessors.end()); + for (; it != itEnd; it++) { + picojson::object buf; + buf["bufferView"] = picojson::value(it->second.bufferView); + buf["byteOffset"] = + picojson::value(static_cast(it->second.byteOffset)); + buf["byteStride"] = + picojson::value(static_cast(it->second.byteStride)); + buf["componentType"] = + picojson::value(static_cast(it->second.componentType)); + buf["count"] = picojson::value(static_cast(it->second.count)); + buf["type"] = picojson::value(EncodeType(it->second.type)); + + if (!it->second.minValues.empty()) { + picojson::array arr; + EncodeFloatArray(&arr, it->second.minValues); + buf["min"] = picojson::value(arr); + } + if (!it->second.maxValues.empty()) { + picojson::array arr; + EncodeFloatArray(&arr, it->second.maxValues); + buf["max"] = picojson::value(arr); + } + + (*o)[it->first] = picojson::value(buf); + } + + return true; +} + +bool EncodePrimitive(picojson::object* o, + const tinygltf::Primitive& primitive) { (*o)["material"] = picojson::value(primitive.material); (*o)["indices"] = picojson::value(primitive.indices); (*o)["mode"] = picojson::value(static_cast(primitive.mode)); @@ -277,30 +285,30 @@ bool EncodePrimitive(picojson::object* o, const tinygltf::Primitive &primitive) return true; } -bool EncodeMeshes(picojson::object* o, const std::map& meshes) -{ - std::map::const_iterator it(meshes.begin()); - std::map::const_iterator itEnd(meshes.end()); - for (; it != itEnd; it++) { - picojson::object buf; +bool EncodeMeshes(picojson::object* o, + const std::map& meshes) { + std::map::const_iterator it(meshes.begin()); + std::map::const_iterator itEnd(meshes.end()); + for (; it != itEnd; it++) { + picojson::object buf; - buf["name"] = picojson::value(it->second.name); + buf["name"] = picojson::value(it->second.name); - picojson::array arr; - for (size_t i = 0; i < it->second.primitives.size(); i++) { - picojson::object primitive; - EncodePrimitive(&primitive, it->second.primitives[i]); - arr.push_back(picojson::value(primitive)); - } - buf["primitives"] = picojson::value(arr); - - (*o)[it->first] = picojson::value(buf); + picojson::array arr; + for (size_t i = 0; i < it->second.primitives.size(); i++) { + picojson::object primitive; + EncodePrimitive(&primitive, it->second.primitives[i]); + arr.push_back(picojson::value(primitive)); } - return true; - } + buf["primitives"] = picojson::value(arr); -bool SaveGLTF(const std::string& output_filename, const tinygltf::Scene& scene) -{ + (*o)[it->first] = picojson::value(buf); + } + return true; +} + +bool SaveGLTF(const std::string& output_filename, + const tinygltf::Scene& scene) { picojson::object root; { @@ -336,7 +344,7 @@ bool SaveGLTF(const std::string& output_filename, const tinygltf::Scene& scene) root["accessors"] = picojson::value(accessors); } - { + { picojson::object meshes; bool ret = EncodeMeshes(&meshes, scene.meshes); assert(ret); @@ -358,7 +366,6 @@ bool SaveGLTF(const std::string& output_filename, const tinygltf::Scene& scene) root["scenes"] = picojson::value(scenes); } - // @todo {} picojson::object shaders; picojson::object programs; @@ -388,11 +395,7 @@ bool SaveGLTF(const std::string& output_filename, const tinygltf::Scene& scene) // ---------------------------------------------------------------- -int -main( - int argc, - char **argv) -{ +int main(int argc, char** argv) { if (argc < 3) { printf("Needs input.gltf output.gltf\n"); exit(1); @@ -425,5 +428,4 @@ main( ret = SaveGLTF(argv[2], scene); return ret ? EXIT_SUCCESS : EXIT_FAILURE; - } From 8317ffbe8a76a2b5b591a9306306f66345579894 Mon Sep 17 00:00:00 2001 From: Syoyo Fujita Date: Sat, 11 Jun 2016 16:10:39 +0900 Subject: [PATCH 8/8] Improve windows build. Don't report error when `in_normal` is not used in the shader. --- examples/glview/README.md | 9 ++++-- examples/glview/glview.cc | 28 +++++++++--------- examples/glview/premake4.lua | 55 ++++++++++++++++++++---------------- 3 files changed, 51 insertions(+), 41 deletions(-) diff --git a/examples/glview/README.md b/examples/glview/README.md index de1f25f..bb6194c 100644 --- a/examples/glview/README.md +++ b/examples/glview/README.md @@ -15,10 +15,15 @@ Simple OpenGL viewer for glTF geometry. > premake4 gmake $ make -### Windows(not tested) +### Windows(not tested well) + +Edit glew and glfw path in `premake4.lua`, then > premake5.exe vs2013 - Open .sln in Visual Studio 2013 + +Open .sln in Visual Studio 2013 + +When running .exe, glew and glfw dll must exist in the working directory. ## TODO diff --git a/examples/glview/glview.cc b/examples/glview/glview.cc index 9fb5632..a9abe16 100644 --- a/examples/glview/glview.cc +++ b/examples/glview/glview.cc @@ -360,12 +360,15 @@ void DrawMesh(tinygltf::Scene &scene, const tinygltf::Mesh &mesh) { if ((it->first.compare("POSITION") == 0) || (it->first.compare("NORMAL") == 0) || (it->first.compare("TEXCOORD_0") == 0)) { - glVertexAttribPointer( - gGLProgramState.attribs[it->first], count, accessor.componentType, - GL_FALSE, accessor.byteStride, BUFFER_OFFSET(accessor.byteOffset)); - CheckErrors("vertex attrib pointer"); - glEnableVertexAttribArray(gGLProgramState.attribs[it->first]); - CheckErrors("enable vertex attrib array"); + + if (gGLProgramState.attribs[it->first] >= 0) { + glVertexAttribPointer( + gGLProgramState.attribs[it->first], count, accessor.componentType, + GL_FALSE, accessor.byteStride, BUFFER_OFFSET(accessor.byteOffset)); + CheckErrors("vertex attrib pointer"); + glEnableVertexAttribArray(gGLProgramState.attribs[it->first]); + CheckErrors("enable vertex attrib array"); + } } } @@ -403,7 +406,9 @@ void DrawMesh(tinygltf::Scene &scene, const tinygltf::Mesh &mesh) { if ((it->first.compare("POSITION") == 0) || (it->first.compare("NORMAL") == 0) || (it->first.compare("TEXCOORD_0") == 0)) { - glDisableVertexAttribArray(gGLProgramState.attribs[it->first]); + if (gGLProgramState.attribs[it->first] >= 0) { + glDisableVertexAttribArray(gGLProgramState.attribs[it->first]); + } } } } @@ -497,7 +502,7 @@ int main(int argc, char **argv) { glfwSetMouseButtonCallback(window, clickFunc); glfwSetCursorPosCallback(window, motionFunc); - glewExperimental = true; + glewExperimental = true; // This may be only true for linux environment. if (glewInit() != GLEW_OK) { std::cerr << "Failed to initialize GLEW." << std::endl; return -1; @@ -523,17 +528,12 @@ int main(int argc, char **argv) { CheckErrors("link"); { + // At least `in_vertex` should be used in the shader. GLint vtxLoc = glGetAttribLocation(progId, "in_vertex"); if (vtxLoc < 0) { printf("vertex loc not found.\n"); exit(-1); } - - GLint tnLoc = glGetAttribLocation(progId, "in_normal"); - if (tnLoc < 0) { - printf("normal loc not found.\n"); - exit(-1); - } } glUseProgram(progId); diff --git a/examples/glview/premake4.lua b/examples/glview/premake4.lua index 773a194..51b4a73 100644 --- a/examples/glview/premake4.lua +++ b/examples/glview/premake4.lua @@ -1,36 +1,41 @@ solution "glview" - -- location ( "build" ) - configurations { "Debug", "Release" } - platforms {"native", "x64", "x32"} - - project "glview" + -- location ( "build" ) + configurations { "Debug", "Release" } + platforms {"native", "x64", "x32"} + + project "glview" - kind "ConsoleApp" - language "C++" - files { "glview.cc", "trackball.cc" } - includedirs { "./" } - includedirs { "../../" } + kind "ConsoleApp" + language "C++" + files { "glview.cc", "trackball.cc" } + includedirs { "./" } + includedirs { "../../" } - configuration { "linux" } - linkoptions { "`pkg-config --libs glfw3`" } - links { "GL", "GLU", "m", "GLEW", "X11", "Xrandr", "Xinerama", "Xi", "Xxf86vm", "Xcursor", "dl" } + configuration { "linux" } + linkoptions { "`pkg-config --libs glfw3`" } + links { "GL", "GLU", "m", "GLEW", "X11", "Xrandr", "Xinerama", "Xi", "Xxf86vm", "Xcursor", "dl" } - configuration { "windows" } - links { "glfw3", "gdi32", "winmm", "user32", "GLEW", "glu32","opengl32", "kernel32" } - defines { "_CRT_SECURE_NO_WARNINGS" } + configuration { "windows" } + -- Edit path to glew and GLFW3 fit to your environment. + includedirs { "../../../../local/glew-1.13.0/include/" } + includedirs { "../../../../local/glfw-3.2.bin.WIN32/include/" } + libdirs { "../../../../local/glew-1.13.0/lib/Release/Win32/" } + libdirs { "../../../../local/glfw-3.2.bin.WIN32/lib-vc2013/" } + links { "glfw3", "gdi32", "winmm", "user32", "glew32", "glu32","opengl32", "kernel32" } + defines { "_CRT_SECURE_NO_WARNINGS" } - configuration { "macosx" } + configuration { "macosx" } includedirs { "/usr/local/include" } buildoptions { "-Wno-deprecated-declarations" } libdirs { "/usr/local/lib" } - links { "glfw3", "GLEW" } - linkoptions { "-framework OpenGL", "-framework Cocoa", "-framework IOKit", "-framework CoreVideo" } + links { "glfw3", "GLEW" } + linkoptions { "-framework OpenGL", "-framework Cocoa", "-framework IOKit", "-framework CoreVideo" } - configuration "Debug" - defines { "DEBUG" } - flags { "Symbols", "ExtraWarnings"} + configuration "Debug" + defines { "DEBUG" } + flags { "Symbols", "ExtraWarnings"} - configuration "Release" - defines { "NDEBUG" } - flags { "Optimize", "ExtraWarnings"} + configuration "Release" + defines { "NDEBUG" } + flags { "Optimize", "ExtraWarnings"}