diff --git a/examples/glview/README.md b/examples/glview/README.md index b248bcf..cff927a 100644 --- a/examples/glview/README.md +++ b/examples/glview/README.md @@ -18,6 +18,7 @@ Simple OpenGL viewer for glTF geometry. ## TODO -* [ ] Texture +* [x] Texture + * [ ] Various texture format. * [ ] Shader * [ ] Animation diff --git a/examples/glview/glview.cc b/examples/glview/glview.cc index 1ab9817..fd3a466 100644 --- a/examples/glview/glview.cc +++ b/examples/glview/glview.cc @@ -20,6 +20,16 @@ #define BUFFER_OFFSET(i) ((char *)NULL + (i)) +#define CheckGLErrors(desc) \ + { \ + GLenum e = glGetError(); \ + if (e != GL_NO_ERROR) { \ + printf("OpenGL error in \"%s\": %d (%d) %s:%d\n", desc, e, e, __FILE__, \ + __LINE__); \ + exit(20); \ + } \ + } + #define CAM_Z (3.0f) int width = 768; int height = 768; @@ -32,19 +42,21 @@ float curr_quat[4]; float prev_quat[4]; float eye[3], lookat[3], up[3]; -GLFWwindow* window; +GLFWwindow *window; -typedef struct -{ - GLuint vb; -} GLBufferState; +typedef struct { GLuint vb; } GLBufferState; -typedef struct -{ +typedef struct { + std::vector diffuseTex; // for each primitive in mesh +} GLMeshState; + +typedef struct { std::map attribs; + std::map uniforms; } GLProgramState; std::map gBufferState; +std::map gMeshState; GLProgramState gGLProgramState; void CheckErrors(std::string desc) { @@ -79,7 +91,7 @@ bool LoadShader(GLenum shaderType, // GL_VERTEX_SHADER or GL_FRAGMENT_SHADER(or srcbuf[len] = 0; fclose(fp); - const GLchar* srcs[1]; + const GLchar *srcs[1]; srcs[0] = &srcbuf.at(0); shader = glCreateShader(shaderType); @@ -93,7 +105,7 @@ bool LoadShader(GLenum shaderType, // GL_VERTEX_SHADER or GL_FRAGMENT_SHADER(or printf("%s\n", log); // assert(val == GL_TRUE && "failed to compile shader"); printf("ERR: Failed to load or compile shader [ %s ]\n", - shaderSourceFilename); + shaderSourceFilename); return false; } @@ -122,8 +134,7 @@ bool LinkShader(GLuint &prog, GLuint &vertShader, GLuint &fragShader) { return true; } -void reshapeFunc(GLFWwindow* window, int w, int h) -{ +void reshapeFunc(GLFWwindow *window, int w, int h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); @@ -135,113 +146,187 @@ void reshapeFunc(GLFWwindow* window, int w, int h) height = h; } -void keyboardFunc(GLFWwindow *window, int key, int scancode, int action, int mods) { - if(action == GLFW_PRESS || action == GLFW_REPEAT){ +void keyboardFunc(GLFWwindow *window, int key, int scancode, int action, + int mods) { + if (action == GLFW_PRESS || action == GLFW_REPEAT) { // Close window - if(key == GLFW_KEY_Q || key == GLFW_KEY_ESCAPE) glfwSetWindowShouldClose(window, GL_TRUE); + if (key == GLFW_KEY_Q || key == GLFW_KEY_ESCAPE) + glfwSetWindowShouldClose(window, GL_TRUE); } } -void clickFunc(GLFWwindow* window, int button, int action, int mods){ - double x, y; - glfwGetCursorPos(window,&x, &y); +void clickFunc(GLFWwindow *window, int button, int action, int mods) { + double x, y; + glfwGetCursorPos(window, &x, &y); - if(button == GLFW_MOUSE_BUTTON_LEFT){ - mouseLeftPressed = true; - if(action == GLFW_PRESS){ - int id = -1; - //int id = ui.Proc(x, y); - if (id < 0) { // outside of UI - trackball(prev_quat, 0.0, 0.0, 0.0, 0.0); - } - } else if(action == GLFW_RELEASE){ - mouseLeftPressed = false; - } + if (button == GLFW_MOUSE_BUTTON_LEFT) { + mouseLeftPressed = true; + if (action == GLFW_PRESS) { + int id = -1; + // int id = ui.Proc(x, y); + if (id < 0) { // outside of UI + trackball(prev_quat, 0.0, 0.0, 0.0, 0.0); + } + } else if (action == GLFW_RELEASE) { + mouseLeftPressed = false; + } } - if(button == GLFW_MOUSE_BUTTON_RIGHT){ - if(action == GLFW_PRESS){ + if (button == GLFW_MOUSE_BUTTON_RIGHT) { + if (action == GLFW_PRESS) { mouseRightPressed = true; - } else if(action == GLFW_RELEASE){ + } else if (action == GLFW_RELEASE) { mouseRightPressed = false; } } - if(button == GLFW_MOUSE_BUTTON_MIDDLE){ - if(action == GLFW_PRESS){ + if (button == GLFW_MOUSE_BUTTON_MIDDLE) { + if (action == GLFW_PRESS) { mouseMiddlePressed = true; - } else if(action == GLFW_RELEASE){ + } else if (action == GLFW_RELEASE) { mouseMiddlePressed = false; } } } -void motionFunc(GLFWwindow* window, double mouse_x, double mouse_y){ +void motionFunc(GLFWwindow *window, double mouse_x, double mouse_y) { float rotScale = 1.0f; float transScale = 2.0f; - if(mouseLeftPressed){ - trackball(prev_quat, - rotScale * (2.0f * prevMouseX - width) / (float)width, - rotScale * (height - 2.0f * prevMouseY) / (float)height, - rotScale * (2.0f * mouse_x - width) / (float)width, - rotScale * (height - 2.0f * mouse_y) / (float)height); + if (mouseLeftPressed) { + trackball(prev_quat, rotScale * (2.0f * prevMouseX - width) / (float)width, + rotScale * (height - 2.0f * prevMouseY) / (float)height, + rotScale * (2.0f * mouse_x - width) / (float)width, + rotScale * (height - 2.0f * mouse_y) / (float)height); - add_quats(prev_quat, curr_quat, curr_quat); - } else if (mouseMiddlePressed) { - eye[0] += -transScale * (mouse_x - prevMouseX) / (float)width; - lookat[0] += -transScale * (mouse_x - prevMouseX) / (float)width; - eye[1] += transScale * (mouse_y - prevMouseY) / (float)height; - lookat[1] += transScale * (mouse_y - prevMouseY) / (float)height; - } else if (mouseRightPressed) { - eye[2] += transScale * (mouse_y - prevMouseY) / (float)height; - lookat[2] += transScale * (mouse_y - prevMouseY) / (float)height; - } + add_quats(prev_quat, curr_quat, curr_quat); + } else if (mouseMiddlePressed) { + eye[0] += -transScale * (mouse_x - prevMouseX) / (float)width; + lookat[0] += -transScale * (mouse_x - prevMouseX) / (float)width; + eye[1] += transScale * (mouse_y - prevMouseY) / (float)height; + lookat[1] += transScale * (mouse_y - prevMouseY) / (float)height; + } else if (mouseRightPressed) { + eye[2] += transScale * (mouse_y - prevMouseY) / (float)height; + lookat[2] += transScale * (mouse_y - prevMouseY) / (float)height; + } // Update mouse point prevMouseX = mouse_x; prevMouseY = mouse_y; } -static void SetupGLState(Scene& scene, GLuint progId) -{ - std::map::const_iterator it(scene.bufferViews.begin()); - std::map::const_iterator itEnd(scene.bufferViews.end()); +static void SetupGLState(Scene &scene, GLuint progId) { + // Buffer + { + std::map::const_iterator it( + scene.bufferViews.begin()); + std::map::const_iterator itEnd( + scene.bufferViews.end()); - for (; it != itEnd; it++) { - const BufferView& bufferView = it->second; - if (bufferView.target == 0) { - continue; // Unsupported bufferView. + for (; it != itEnd; it++) { + const BufferView &bufferView = it->second; + if (bufferView.target == 0) { + continue; // Unsupported bufferView. + } + + const Buffer &buffer = scene.buffers[bufferView.buffer]; + GLBufferState state; + glGenBuffers(1, &state.vb); + glBindBuffer(bufferView.target, state.vb); + glBufferData(bufferView.target, bufferView.byteLength, + &buffer.data.at(0) + bufferView.byteOffset, GL_STATIC_DRAW); + glBindBuffer(bufferView.target, 0); + + gBufferState[it->first] = state; } + } - const Buffer& buffer = scene.buffers[bufferView.buffer]; - GLBufferState state; - glGenBuffers(1, &state.vb); - glBindBuffer(bufferView.target, state.vb); - glBufferData(bufferView.target, bufferView.byteLength, &buffer.data.at(0) + bufferView.byteOffset, GL_STATIC_DRAW); - glBindBuffer(bufferView.target, 0); - - gBufferState[it->first] = state; + // Texture + { + std::map::const_iterator it(scene.meshes.begin()); + std::map::const_iterator itEnd(scene.meshes.end()); + + for (; it != itEnd; it++) { + const Mesh &mesh = it->second; + + gMeshState[mesh.name].diffuseTex.resize(mesh.primitives.size()); + for (size_t primId = 0; primId < mesh.primitives.size(); primId++) { + const Primitive &primitive = mesh.primitives[primId]; + + gMeshState[mesh.name].diffuseTex[primId] = 0; + + if (primitive.material.empty()) { + continue; + } + 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"].stringValue; + if (scene.textures.find(diffuseTexName) != scene.textures.end()) { + Texture &tex = scene.textures[diffuseTexName]; + if (scene.images.find(tex.source) != scene.images.end()) { + 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)); + + CheckErrors("texImage2D"); + glBindTexture(tex.target, 0); + + 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"); + + GLint diffuseTexLoc = glGetUniformLocation(progId, "diffuseTex"); + gGLProgramState.attribs["POSITION"] = vtloc; gGLProgramState.attribs["NORMAL"] = nrmloc; - + gGLProgramState.attribs["TEXCOORD_0"] = uvloc; + gGLProgramState.uniforms["diffuseTex"] = diffuseTexLoc; }; -void DrawMesh(Scene& scene, const Mesh& mesh) -{ - for (size_t i = 0; i < mesh.primitives.size(); i++) { - const Primitive& primitive = mesh.primitives[i]; +void DrawMesh(Scene &scene, const Mesh &mesh) { - if (primitive.indices.empty()) return; + if (gGLProgramState.uniforms["diffuseTex"] >= 0) { + glUniform1i(gGLProgramState.uniforms["diffuseTex"], 0); // TEXTURE0 + } - std::map::const_iterator it(primitive.attributes.begin()); - std::map::const_iterator itEnd(primitive.attributes.end()); + for (size_t i = 0; i < mesh.primitives.size(); i++) { + const Primitive &primitive = mesh.primitives[i]; + + if (primitive.indices.empty()) + return; + + std::map::const_iterator it( + primitive.attributes.begin()); + std::map::const_iterator itEnd( + primitive.attributes.end()); + + // Assume TEXTURE_2D target for the texture object. + glBindTexture(GL_TEXTURE_2D, gMeshState[mesh.name].diffuseTex[i]); for (; it != itEnd; it++) { - const Accessor& accessor = scene.accessors[it->second]; + const Accessor &accessor = scene.accessors[it->second]; glBindBuffer(GL_ARRAY_BUFFER, gBufferState[accessor.bufferView].vb); CheckErrors("bind buffer"); int count = 1; @@ -254,18 +339,22 @@ void DrawMesh(Scene& scene, const Mesh& mesh) } else if (accessor.type == TINYGLTF_TYPE_VEC4) { count = 4; } - // it->first would be "POSITION", "NORMAL", ... - if ( (it->first.compare("POSITION") == 0) || - (it->first.compare("NORMAL") == 0)) { - glVertexAttribPointer(gGLProgramState.attribs[it->first], count, accessor.componentType, GL_FALSE, accessor.byteStride, BUFFER_OFFSET(accessor.byteOffset)); + // it->first would be "POSITION", "NORMAL", "TEXCOORD_0", ... + 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"); } } - const Accessor& indexAccessor = scene.accessors[primitive.indices]; - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gBufferState[indexAccessor.bufferView].vb); + const Accessor &indexAccessor = scene.accessors[primitive.indices]; + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, + gBufferState[indexAccessor.bufferView].vb); CheckErrors("bind buffer"); int mode = -1; if (primitive.mode == TINYGLTF_MODE_TRIANGLES) { @@ -281,26 +370,28 @@ void DrawMesh(Scene& scene, const Mesh& mesh) } else if (primitive.mode == TINYGLTF_MODE_LINE_LOOP) { mode = GL_LINE_LOOP; }; - glDrawElements(mode, indexAccessor.count, indexAccessor.componentType, BUFFER_OFFSET(indexAccessor.byteOffset)); + glDrawElements(mode, indexAccessor.count, indexAccessor.componentType, + BUFFER_OFFSET(indexAccessor.byteOffset)); CheckErrors("draw elements"); { - std::map::const_iterator it(primitive.attributes.begin()); - std::map::const_iterator itEnd(primitive.attributes.end()); + std::map::const_iterator it( + primitive.attributes.begin()); + std::map::const_iterator itEnd( + primitive.attributes.end()); for (; it != itEnd; it++) { - if ( (it->first.compare("POSITION") == 0) || - (it->first.compare("NORMAL") == 0)) { + if ((it->first.compare("POSITION") == 0) || + (it->first.compare("NORMAL") == 0) || + (it->first.compare("TEXCOORD_0") == 0)) { glDisableVertexAttribArray(gGLProgramState.attribs[it->first]); } } } } - } -void DrawScene(Scene& scene) -{ +void DrawScene(Scene &scene) { std::map::const_iterator it(scene.meshes.begin()); std::map::const_iterator itEnd(scene.meshes.end()); @@ -309,7 +400,6 @@ void DrawScene(Scene& scene) } } - static void Init() { trackball(curr_quat, 0, 0, 0, 0); @@ -326,8 +416,7 @@ static void Init() { up[2] = 0.0f; } -int main(int argc, char **argv) -{ +int main(int argc, char **argv) { if (argc < 2) { std::cout << "glview input.gltf \n" << std::endl; return 0; @@ -338,10 +427,10 @@ int main(int argc, char **argv) scale = atof(argv[2]); } - Scene scene; + Scene scene; TinyGLTFLoader loader; std::string err; - + bool ret = loader.LoadFromFile(scene, err, argv[1]); if (!err.empty()) { printf("ERR: %s\n", err.c_str()); @@ -353,13 +442,14 @@ int main(int argc, char **argv) Init(); - if(!glfwInit()){ + if (!glfwInit()) { std::cerr << "Failed to initialize GLFW." << std::endl; return -1; } - window = glfwCreateWindow(width, height, "Simple glTF geometry viewer", NULL, NULL); - if(window == NULL){ + window = glfwCreateWindow(width, height, "Simple glTF geometry viewer", NULL, + NULL); + if (window == NULL) { std::cerr << "Failed to open GLFW window. " << std::endl; glfwTerminate(); return 1; @@ -420,7 +510,7 @@ int main(int argc, char **argv) SetupGLState(scene, progId); CheckErrors("SetupGLState"); - while(glfwWindowShouldClose(window) == GL_FALSE) { + while (glfwWindowShouldClose(window) == GL_FALSE) { glfwPollEvents(); glClearColor(0.1f, 0.2f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -433,7 +523,8 @@ int main(int argc, char **argv) // camera(define it in projection matrix) glMatrixMode(GL_PROJECTION); glPushMatrix(); - gluLookAt(eye[0], eye[1], eye[2], lookat[0], lookat[1], lookat[2], up[0], up[1], up[2]); + gluLookAt(eye[0], eye[1], eye[2], lookat[0], lookat[1], lookat[2], up[0], + up[1], up[2]); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); diff --git a/examples/glview/shader.frag b/examples/glview/shader.frag index bd2fc49..1f30d3e 100644 --- a/examples/glview/shader.frag +++ b/examples/glview/shader.frag @@ -1,6 +1,11 @@ +uniform sampler2D diffuseTex; + varying vec3 normal; +varying vec2 texcoord; void main(void) { - gl_FragColor = vec4(0.5 * normalize(normal) + 0.5, 1.0); + //gl_FragColor = vec4(0.5 * normalize(normal) + 0.5, 1.0); + //gl_FragColor = vec4(texcoord, 0.0, 1.0); + gl_FragColor = texture2D(diffuseTex, texcoord); } diff --git a/examples/glview/shader.vert b/examples/glview/shader.vert index a21fa30..e21752d 100644 --- a/examples/glview/shader.vert +++ b/examples/glview/shader.vert @@ -1,7 +1,9 @@ attribute vec3 in_vertex; attribute vec3 in_normal; +attribute vec2 in_texcoord; varying vec3 normal; +varying vec2 texcoord; void main(void) { @@ -9,4 +11,6 @@ void main(void) gl_Position = p; vec4 nn = gl_ModelViewMatrixInverseTranspose * vec4(normalize(in_normal), 0); normal = nn.xyz; + + texcoord = in_texcoord; } diff --git a/test.cc b/test.cc index 8b3bfd1..7d6056d 100644 --- a/test.cc +++ b/test.cc @@ -6,8 +6,7 @@ #include #include -std::string PrintMode(int mode) -{ +std::string PrintMode(int mode) { if (mode == TINYGLTF_MODE_POINTS) { return "POINTS"; } else if (mode == TINYGLTF_MODE_LINE) { @@ -24,9 +23,7 @@ std::string PrintMode(int mode) return "**UNKNOWN**"; } - -std::string PrintType(int ty) -{ +std::string PrintType(int ty) { if (ty == TINYGLTF_TYPE_SCALAR) { return "SCALAR"; } else if (ty == TINYGLTF_TYPE_VECTOR) { @@ -49,8 +46,7 @@ std::string PrintType(int ty) return "**UNKNOWN**"; } -std::string PrintComponentType(int ty) -{ +std::string PrintComponentType(int ty) { if (ty == TINYGLTF_COMPONENT_TYPE_BYTE) { return "BYTE"; } else if (ty == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) { @@ -72,8 +68,7 @@ std::string PrintComponentType(int ty) return "**UNKNOWN**"; } -std::string PrintFloatArray(const std::vector& arr) -{ +std::string PrintFloatArray(const std::vector &arr) { if (arr.size() == 0) { return ""; } @@ -88,8 +83,7 @@ std::string PrintFloatArray(const std::vector& arr) return ss.str(); } -std::string PrintStringArray(const std::vector& arr) -{ +std::string PrintStringArray(const std::vector &arr) { if (arr.size() == 0) { return ""; } @@ -104,9 +98,7 @@ std::string PrintStringArray(const std::vector& arr) return ss.str(); } - -std::string Indent(int indent) -{ +std::string Indent(int indent) { std::string s; for (int i = 0; i < indent; i++) { s += " "; @@ -115,64 +107,82 @@ std::string Indent(int indent) return s; } -void DumpNode(const Node& node, int indent) -{ - std::cout << Indent(indent) << "name : " << node.name << std::endl; - std::cout << Indent(indent) << "camera : " << node.camera << std::endl; +void DumpNode(const Node &node, int indent) { + std::cout << Indent(indent) << "name : " << node.name << std::endl; + std::cout << Indent(indent) << "camera : " << node.camera << std::endl; if (!node.rotation.empty()) { - std::cout << Indent(indent) << "rotation : " << PrintFloatArray(node.rotation) << std::endl; + std::cout << Indent(indent) + << "rotation : " << PrintFloatArray(node.rotation) + << std::endl; } if (!node.scale.empty()) { - std::cout << Indent(indent) << "scale : " << PrintFloatArray(node.scale) << std::endl; + std::cout << Indent(indent) + << "scale : " << PrintFloatArray(node.scale) << std::endl; } if (!node.translation.empty()) { - std::cout << Indent(indent) << "translation : " << PrintFloatArray(node.translation) << std::endl; + std::cout << Indent(indent) + << "translation : " << PrintFloatArray(node.translation) + << std::endl; } if (!node.matrix.empty()) { - std::cout << Indent(indent) << "matrix : " << PrintFloatArray(node.matrix) << std::endl; + std::cout << Indent(indent) + << "matrix : " << PrintFloatArray(node.matrix) << std::endl; } - std::cout << Indent(indent) << "meshes : " << PrintStringArray(node.meshes) << std::endl; - - std::cout << Indent(indent) << "children : " << PrintStringArray(node.children) << std::endl; + std::cout << Indent(indent) + << "meshes : " << PrintStringArray(node.meshes) << std::endl; + std::cout << Indent(indent) + << "children : " << PrintStringArray(node.children) << std::endl; } -void DumpPrimitive(const Primitive& primitive, int indent) -{ - std::cout << Indent(indent) << "material : " << primitive.material << std::endl; - std::cout << Indent(indent) << "mode : " << PrintMode(primitive.mode) << "(" << primitive.mode << ")" << std::endl; - std::cout << Indent(indent) << "attributes(items=" << primitive.attributes.size() << ")" << std::endl; - std::map::const_iterator it(primitive.attributes.begin()); - std::map::const_iterator itEnd(primitive.attributes.end()); +void DumpPrimitive(const Primitive &primitive, int indent) { + std::cout << Indent(indent) << "material : " << primitive.material + << std::endl; + std::cout << Indent(indent) << "mode : " << PrintMode(primitive.mode) + << "(" << primitive.mode << ")" << std::endl; + std::cout << Indent(indent) + << "attributes(items=" << primitive.attributes.size() << ")" + << std::endl; + std::map::const_iterator it( + primitive.attributes.begin()); + std::map::const_iterator itEnd( + primitive.attributes.end()); for (; it != itEnd; it++) { - std::cout << Indent(indent + 1) << it->first << ": " << it->second << std::endl; + std::cout << Indent(indent + 1) << it->first << ": " << it->second + << std::endl; } - } -void Dump(const Scene& scene) -{ +void Dump(const Scene &scene) { std::cout << "=== Dump glTF ===" << std::endl; - std::cout << "asset.generator : " << scene.asset.generator << std::endl; - std::cout << "asset.premultipliedAlpha : " << scene.asset.premultipliedAlpha << std::endl; - std::cout << "asset.version : " << scene.asset.version << std::endl; - std::cout << "asset.profile.api : " << scene.asset.profile_api << std::endl; - std::cout << "asset.profile.version : " << scene.asset.profile_version << std::endl; + std::cout << "asset.generator : " << scene.asset.generator + << std::endl; + std::cout << "asset.premultipliedAlpha : " << scene.asset.premultipliedAlpha + << std::endl; + std::cout << "asset.version : " << scene.asset.version + << std::endl; + std::cout << "asset.profile.api : " << scene.asset.profile_api + << std::endl; + std::cout << "asset.profile.version : " << scene.asset.profile_version + << std::endl; std::cout << std::endl; std::cout << "=== Dump scene ===" << std::endl; std::cout << "defaultScene: " << scene.defaultScene << std::endl; { - std::map >::const_iterator it(scene.scenes.begin()); - std::map >::const_iterator itEnd(scene.scenes.end()); + std::map >::const_iterator it( + scene.scenes.begin()); + std::map >::const_iterator itEnd( + scene.scenes.end()); std::cout << "scenes(items=" << scene.scenes.size() << ")" << std::endl; for (; it != itEnd; it++) { std::cout << Indent(1) << "name : " << it->first << std::endl; std::cout << Indent(2) << "nodes : [ "; for (size_t i = 0; i < it->second.size(); i++) { - std::cout << it->second[i] << ((i != it->second.size()) ? ", " : ""); + std::cout << it->second[i] + << ((i != (it->second.size() - 1)) ? ", " : ""); } std::cout << " ] " << std::endl; } @@ -184,8 +194,10 @@ void Dump(const Scene& scene) std::cout << "meshes(item=" << scene.meshes.size() << ")" << std::endl; for (; it != itEnd; it++) { std::cout << Indent(1) << "name : " << it->second.name << std::endl; - std::cout << Indent(1) << "primitives(items=" << it->second.primitives.size() << "): " << std::endl; - + std::cout << Indent(1) + << "primitives(items=" << it->second.primitives.size() + << "): " << std::endl; + for (size_t i = 0; i < it->second.primitives.size(); i++) { DumpPrimitive(it->second.primitives[i], 2); } @@ -194,27 +206,38 @@ void Dump(const Scene& scene) { std::map::const_iterator it(scene.accessors.begin()); - std::map::const_iterator itEnd(scene.accessors.end()); - std::cout << "accessos(items=" << scene.accessors.size() << ")" << std::endl; + std::map::const_iterator itEnd( + scene.accessors.end()); + std::cout << "accessos(items=" << scene.accessors.size() << ")" + << std::endl; for (; it != itEnd; it++) { std::cout << Indent(1) << "name : " << it->first << std::endl; - std::cout << Indent(2) << "bufferView : " << it->second.bufferView << std::endl; - std::cout << Indent(2) << "byteOffset : " << it->second.byteOffset << std::endl; - std::cout << Indent(2) << "byteStride : " << it->second.byteStride << std::endl; - std::cout << Indent(2) << "componentType: " << PrintComponentType(it->second.componentType) << "(" << it->second.componentType << ")" << std::endl; - std::cout << Indent(2) << "count : " << it->second.count << std::endl; - std::cout << Indent(2) << "type : " << PrintType(it->second.type) << std::endl; + std::cout << Indent(2) << "bufferView : " << it->second.bufferView + << std::endl; + std::cout << Indent(2) << "byteOffset : " << it->second.byteOffset + << std::endl; + std::cout << Indent(2) << "byteStride : " << it->second.byteStride + << std::endl; + std::cout << Indent(2) << "componentType: " + << PrintComponentType(it->second.componentType) << "(" + << it->second.componentType << ")" << std::endl; + std::cout << Indent(2) << "count : " << it->second.count + << std::endl; + std::cout << Indent(2) << "type : " << PrintType(it->second.type) + << std::endl; if (!it->second.minValues.empty()) { std::cout << Indent(2) << "min : ["; for (size_t i = 0; i < it->second.minValues.size(); i++) { - std::cout << it->second.minValues[i] << ((i != it->second.minValues.size()-1) ? ", " : ""); + std::cout << it->second.minValues[i] + << ((i != it->second.minValues.size() - 1) ? ", " : ""); } std::cout << "]" << std::endl; } if (!it->second.maxValues.empty()) { std::cout << Indent(2) << "max : ["; for (size_t i = 0; i < it->second.maxValues.size(); i++) { - std::cout << it->second.maxValues[i] << ((i != it->second.maxValues.size()-1) ? ", " : ""); + std::cout << it->second.maxValues[i] + << ((i != it->second.maxValues.size() - 1) ? ", " : ""); } std::cout << "]" << std::endl; } @@ -222,14 +245,20 @@ void Dump(const Scene& scene) } { - std::map::const_iterator it(scene.bufferViews.begin()); - std::map::const_iterator itEnd(scene.bufferViews.end()); - std::cout << "bufferViews(items=" << scene.bufferViews.size() << ")" << std::endl; + std::map::const_iterator it( + scene.bufferViews.begin()); + std::map::const_iterator itEnd( + scene.bufferViews.end()); + std::cout << "bufferViews(items=" << scene.bufferViews.size() << ")" + << std::endl; for (; it != itEnd; it++) { std::cout << Indent(1) << "name : " << it->first << std::endl; - std::cout << Indent(2) << "buffer : " << it->second.buffer << std::endl; - std::cout << Indent(2) << "byteLength : " << it->second.byteLength << std::endl; - std::cout << Indent(2) << "byteOffset : " << it->second.byteOffset << std::endl; + std::cout << Indent(2) << "buffer : " << it->second.buffer + << std::endl; + std::cout << Indent(2) << "byteLength : " << it->second.byteLength + << std::endl; + std::cout << Indent(2) << "byteOffset : " << it->second.byteOffset + << std::endl; } } @@ -239,23 +268,35 @@ void Dump(const Scene& scene) std::cout << "buffers(items=" << scene.buffers.size() << ")" << std::endl; for (; it != itEnd; it++) { std::cout << Indent(1) << "name : " << it->first << std::endl; - std::cout << Indent(2) << "byteLength : " << it->second.data.size() << std::endl; + std::cout << Indent(2) << "byteLength : " << it->second.data.size() + << std::endl; } } { std::map::const_iterator it(scene.materials.begin()); - std::map::const_iterator itEnd(scene.materials.end()); - std::cout << "materials(items=" << scene.materials.size() << ")" << std::endl; + std::map::const_iterator itEnd( + scene.materials.end()); + std::cout << "materials(items=" << scene.materials.size() << ")" + << std::endl; for (; it != itEnd; it++) { std::cout << Indent(1) << "name : " << it->first << std::endl; - std::cout << Indent(1) << "technique : " << it->second.technique << std::endl; - std::cout << Indent(1) << "values(items=" << it->second.values.size() << std::endl; + std::cout << Indent(1) << "technique : " << it->second.technique + << std::endl; + std::cout << Indent(1) << "values(items=" << it->second.values.size() + << std::endl; - FloatParameterMap::const_iterator p(it->second.values.begin()); - FloatParameterMap::const_iterator pEnd(it->second.values.end()); + ParameterMap::const_iterator p(it->second.values.begin()); + ParameterMap::const_iterator pEnd(it->second.values.end()); for (; p != pEnd; p++) { - std::cout << Indent(3) << p->first << PrintFloatArray(p->second) << std::endl; + if (!p->second.numberArray.empty()) { + std::cout << Indent(3) << p->first + << PrintFloatArray(p->second.numberArray) << std::endl; + } + if (!p->second.stringValue.empty()) { + std::cout << Indent(3) << p->first << " : " << p->second.stringValue + << std::endl; + } } } } @@ -270,7 +311,7 @@ void Dump(const Scene& scene) DumpNode(it->second, 2); } } - + { std::map::const_iterator it(scene.images.begin()); std::map::const_iterator itEnd(scene.images.end()); @@ -279,24 +320,46 @@ void Dump(const Scene& scene) std::cout << Indent(1) << "name : " << it->first << std::endl; std::cout << Indent(2) << "width : " << it->second.width << std::endl; - std::cout << Indent(2) << "height : " << it->second.height << std::endl; - std::cout << Indent(2) << "component : " << it->second.component << std::endl; + std::cout << Indent(2) << "height : " << it->second.height + << std::endl; + std::cout << Indent(2) << "component : " << it->second.component + << std::endl; std::cout << Indent(2) << "name : " << it->second.name << std::endl; } } + + { + std::map::const_iterator it(scene.textures.begin()); + std::map::const_iterator itEnd(scene.textures.end()); + std::cout << "textures(items=" << scene.textures.size() << ")" << std::endl; + for (; it != itEnd; it++) { + std::cout << Indent(1) << "name : " << it->first << std::endl; + std::cout << Indent(1) << "format : " << it->second.format + << std::endl; + std::cout << Indent(1) << "internalFormat : " << it->second.internalFormat + << std::endl; + std::cout << Indent(1) << "sampler : " << it->second.sampler + << std::endl; + std::cout << Indent(1) << "source : " << it->second.source + << std::endl; + std::cout << Indent(1) << "target : " << it->second.target + << std::endl; + std::cout << Indent(1) << "type : " << it->second.type + << std::endl; + } + } } -int main(int argc, char** argv) -{ +int main(int argc, char **argv) { if (argc < 2) { printf("Needs input.gltf\n"); exit(1); } - Scene scene; + Scene scene; TinyGLTFLoader loader; std::string err; - + bool ret = loader.LoadFromFile(scene, err, argv[1]); if (!err.empty()) { diff --git a/tiny_gltf_loader.h b/tiny_gltf_loader.h index 0481db6..361d634 100644 --- a/tiny_gltf_loader.h +++ b/tiny_gltf_loader.h @@ -31,7 +31,8 @@ // // // Version: -// - v0.9.1 Support loading glTF asset from memory +// - v0.9.2 Support parsing `texture` +// - v0.9.1 Support loading glTF asset from memory // - v0.9.0 Initial // // Tiny glTF loader is using following libraries: @@ -80,12 +81,20 @@ namespace tinygltf { #define TINYGLTF_IMAGE_FORMAT_BMP (2) #define TINYGLTF_IMAGE_FORMAT_GIF (3) +#define TINYGLTF_TEXTURE_FORMAT_RGBA (6408) +#define TINYGLTF_TEXTURE_TARGET_TEXTURE2D (3553) +#define TINYGLTF_TEXTURE_TYPE_UNSIGNED_BYTE (5121) + #define TINYGLTF_TARGET_ARRAY_BUFFER (34962) #define TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER (34963) -typedef std::map > FloatParameterMap; +typedef struct { + std::string stringValue; + std::vector numberArray; +} Parameter; + +typedef std::map ParameterMap; -// LDR 8bit image typedef struct { std::string name; int width; @@ -94,10 +103,20 @@ typedef struct { std::vector image; } Image; +typedef struct { + int format; + int internalFormat; + std::string sampler; // Required + std::string source; // Required + int target; + int type; + std::string name; +} Texture; + typedef struct { std::string name; std::string technique; - FloatParameterMap values; + ParameterMap values; } Material; typedef struct { @@ -191,6 +210,7 @@ public: std::map materials; std::map meshes; std::map nodes; + std::map textures; std::map images; std::map > scenes; // list of nodes @@ -212,9 +232,8 @@ public: /// Loads glTF asset from string(memory). /// `length` = strlen(str); /// Returns false and set error string to `err` if there's an error. - bool LoadFromString(Scene &scene, std::string &err, - const char* str, const unsigned int length, const std::string& baseDir); - + bool LoadFromString(Scene &scene, std::string &err, const char *str, + const unsigned int length, const std::string &baseDir); }; } // namespace tinygltf @@ -557,7 +576,7 @@ bool DecodeDataURI(std::vector &out, const std::string &in, if (data.empty()) { return false; - } + } if (checkSize) { if (data.size() != reqBytes) { @@ -780,6 +799,39 @@ bool ParseImage(Image &image, std::string &err, const picojson::object &o, return true; } +bool ParseTexture(Texture &texture, std::string &err, const picojson::object &o, + const std::string &basedir) { + + if (!ParseStringProperty(texture.sampler, err, o, "sampler", true)) { + return false; + } + + if (!ParseStringProperty(texture.source, err, o, "source", true)) { + return false; + } + + ParseStringProperty(texture.name, err, o, "name", false); + + double format = TINYGLTF_TEXTURE_FORMAT_RGBA; + ParseNumberProperty(format, err, o, "format", false); + + double internalFormat = TINYGLTF_TEXTURE_FORMAT_RGBA; + ParseNumberProperty(internalFormat, err, o, "internalFormat", false); + + double target = TINYGLTF_TEXTURE_TARGET_TEXTURE2D; + ParseNumberProperty(target, err, o, "target", false); + + double type = TINYGLTF_TEXTURE_TYPE_UNSIGNED_BYTE; + ParseNumberProperty(type, err, o, "type", false); + + texture.format = static_cast(format); + texture.internalFormat = static_cast(internalFormat); + texture.target = static_cast(target); + texture.type = static_cast(type); + + return true; +} + bool ParseBuffer(Buffer &buffer, std::string &err, const picojson::object &o, const std::string &basedir) { double byteLength; @@ -1041,17 +1093,20 @@ bool ParseMaterial(Material &material, std::string &err, for (; it != itEnd; it++) { // Assume number values. - std::vector values; - if (!ParseNumberArrayProperty(values, err, valuesObject, it->first, - false)) { + Parameter param; + if (ParseStringProperty(param.stringValue, err, valuesObject, it->first, + false)) { + // Found string property. + } else if (!ParseNumberArrayProperty(param.numberArray, err, valuesObject, + it->first, false)) { // Fallback to numer property. double value; if (ParseNumberProperty(value, err, valuesObject, it->first, false)) { - values.push_back(value); + param.numberArray.push_back(value); } } - material.values[it->first] = values; + material.values[it->first] = param; } } @@ -1060,7 +1115,8 @@ bool ParseMaterial(Material &material, std::string &err, } bool TinyGLTFLoader::LoadFromString(Scene &scene, std::string &err, - const char *str, unsigned int length, const std::string& baseDir) { + const char *str, unsigned int length, + const std::string &baseDir) { picojson::value v; std::string perr = picojson::parse(v, str, str + length); @@ -1282,6 +1338,25 @@ bool TinyGLTFLoader::LoadFromString(Scene &scene, std::string &err, } } + // 9. Parse Texture + if (v.contains("textures") && v.get("textures").is()) { + + const picojson::object &root = v.get("textures").get(); + + picojson::object::const_iterator it(root.begin()); + picojson::object::const_iterator itEnd(root.end()); + for (; it != itEnd; it++) { + + Texture texture; + if (!ParseTexture(texture, err, (it->second).get(), + baseDir)) { + return false; + } + + scene.textures[it->first] = texture; + } + } + return true; }