Add tinyktx.

Add workaround for OpenGL3 context creation in `basic` example.
This commit is contained in:
Syoyo Fujita 2019-07-03 16:41:11 +09:00
parent d6b0d0a61f
commit 6f7518255f
3 changed files with 427 additions and 366 deletions

25
LICENSE.tinyktx Normal file
View File

@ -0,0 +1,25 @@
BSD 2-Clause License
Copyright (c) 2019, DeanoC
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -7,6 +7,7 @@ If you are looking for old, C++03 version, please use `devel-picojson` branch.
## Status ## Status
- v2.3.0 release(Support loading KTX image through tiny_ktx)
- v2.2.0 release(Support loading 16bit PNG. Sparse accessor support) - v2.2.0 release(Support loading 16bit PNG. Sparse accessor support)
- v2.1.0 release(Draco support) - v2.1.0 release(Draco support)
- v2.0.0 release(22 Aug, 2018)! - v2.0.0 release(22 Aug, 2018)!
@ -52,7 +53,8 @@ If you are looking for old, C++03 version, please use `devel-picojson` branch.
* [x] Image load * [x] Image load
* [x] Image save * [x] Image save
* Extensions * Extensions
* [x] Draco mesh decoding * [x] Draco mesh decoding(`TINYGLTF_ENABLE_DRACO` required)
* [x] KTX image support(`TINYGLTF_ENABLE_KTX` required)
## Examples ## Examples
@ -143,6 +145,7 @@ if (!ret) {
* `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_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 `: 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`. * `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`.
* `TINYGLTF_ENABLE_KTX` : Enable loading KTX images( https://www.khronos.org/opengles/sdk/tools/KTX/ ) using `tiny_ktx.h`. Supported MIME is `image/ktx` ( https://github.com/KhronosGroup/glTF/issues/835 ). See `models/Cube-KTX` for details. Application also defined `TINYKTX_IMPLEMENTATION` in **one** .cc file.
### Saving gltTF 2.0 model ### Saving gltTF 2.0 model
@ -186,3 +189,4 @@ $ ./tester_noexcept
* json.hpp : Licensed under the MIT License <http://opensource.org/licenses/MIT>. Copyright (c) 2013-2017 Niels Lohmann <http://nlohmann.me>. * json.hpp : Licensed under the MIT License <http://opensource.org/licenses/MIT>. Copyright (c) 2013-2017 Niels Lohmann <http://nlohmann.me>.
* stb_image : Public domain. * stb_image : Public domain.
* catch : Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. Distributed under the Boost Software License, Version 1.0. * catch : Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. Distributed under the Boost Software License, Version 1.0.
* tiny_ktx : Copyright (c) 2019, DeanoC. Licensed under 2 clause BSD license.

View File

@ -1,365 +1,397 @@
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <GL/glew.h> #include <GL/glew.h>
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
#include "shaders.h" #include "shaders.h"
#include "window.h" #include "window.h"
#define TINYGLTF_IMPLEMENTATION #ifdef __clang__
#define STB_IMAGE_IMPLEMENTATION #pragma clang diagnostic push
#define STB_IMAGE_WRITE_IMPLEMENTATION #pragma clang diagnostic ignored "-Weverything"
#define TINYGLTF_NOEXCEPTION #endif
#define JSON_NOEXCEPTION
#include "../../tiny_gltf.h" // Inlude tinyktx.h before tiny_gltf.h
#define TINYKTX_IMPLEMENTATION
#define BUFFER_OFFSET(i) ((char *)NULL + (i)) #include "../../tinyktx.h"
bool loadModel(tinygltf::Model &model, const char *filename) { #ifdef __clang__
tinygltf::TinyGLTF loader; #pragma clang diagnostic pop
std::string err; #endif
std::string warn;
#define TINYGLTF_IMPLEMENTATION
bool res = loader.LoadASCIIFromFile(&model, &err, &warn, filename); #define STB_IMAGE_IMPLEMENTATION
if (!warn.empty()) { #define STB_IMAGE_WRITE_IMPLEMENTATION
std::cout << "WARN: " << warn << std::endl; #define TINYGLTF_NOEXCEPTION
} #define JSON_NOEXCEPTION
#define TINYGLTF_ENABLE_KTX
if (!err.empty()) { #define TINYGLTF_NO_INCLUDE_TINY_KTX
std::cout << "ERR: " << err << std::endl; #include "../../tiny_gltf.h"
}
//#define BUFFER_OFFSET(i) ((char *)nullptr + (i))
if (!res) #define BUFFER_OFFSET(i) \
std::cout << "Failed to load glTF: " << filename << std::endl; (reinterpret_cast<void *>(i)) // TODO(syoyo): Is this right way?
else
std::cout << "Loaded glTF: " << filename << std::endl; bool loadModel(tinygltf::Model &model, const char *filename) {
tinygltf::TinyGLTF loader;
return res; std::string err;
} std::string warn;
std::map<int, GLuint> bindMesh(std::map<int, GLuint> vbos, bool res = loader.LoadASCIIFromFile(&model, &err, &warn, filename);
tinygltf::Model &model, tinygltf::Mesh &mesh) { if (!warn.empty()) {
for (size_t i = 0; i < model.bufferViews.size(); ++i) { std::cout << "WARN: " << warn << std::endl;
const tinygltf::BufferView &bufferView = model.bufferViews[i]; }
if (bufferView.target == 0) { // TODO impl drawarrays
std::cout << "WARN: bufferView.target is zero" << std::endl; if (!err.empty()) {
continue; // Unsupported bufferView. std::cout << "ERR: " << err << std::endl;
/* }
From spec2.0 readme:
https://github.com/KhronosGroup/glTF/tree/master/specification/2.0 if (!res)
... drawArrays function should be used with a count equal to std::cout << "Failed to load glTF: " << filename << std::endl;
the count property of any of the accessors referenced by the else
attributes property (they are all equal for a given std::cout << "Loaded glTF: " << filename << std::endl;
primitive).
*/ return res;
} }
tinygltf::Buffer buffer = model.buffers[bufferView.buffer]; std::map<int, GLuint> bindMesh(std::map<int, GLuint> vbos,
std::cout << "bufferview.target " << bufferView.target << std::endl; tinygltf::Model &model, tinygltf::Mesh &mesh) {
for (size_t i = 0; i < model.bufferViews.size(); ++i) {
GLuint vbo; const tinygltf::BufferView &bufferView = model.bufferViews[i];
glGenBuffers(1, &vbo); if (bufferView.target == 0) { // TODO impl drawarrays
vbos[i] = vbo; std::cout << "WARN: bufferView.target is zero" << std::endl;
glBindBuffer(bufferView.target, vbo); continue; // Unsupported bufferView.
/*
std::cout << "buffer.data.size = " << buffer.data.size() From spec2.0 readme:
<< ", bufferview.byteOffset = " << bufferView.byteOffset https://github.com/KhronosGroup/glTF/tree/master/specification/2.0
<< std::endl; ... drawArrays function should be used with a count equal to
the count property of any of the accessors referenced by the
glBufferData(bufferView.target, bufferView.byteLength, attributes property (they are all equal for a
&buffer.data.at(0) + bufferView.byteOffset, GL_STATIC_DRAW); given primitive).
} */
}
for (size_t i = 0; i < mesh.primitives.size(); ++i) {
tinygltf::Primitive primitive = mesh.primitives[i]; tinygltf::Buffer buffer = model.buffers[bufferView.buffer];
tinygltf::Accessor indexAccessor = model.accessors[primitive.indices]; std::cout << "bufferview.target " << bufferView.target << std::endl;
for (auto &attrib : primitive.attributes) { GLuint vbo;
tinygltf::Accessor accessor = model.accessors[attrib.second]; glGenBuffers(1, &vbo);
int byteStride = vbos[i] = vbo;
accessor.ByteStride(model.bufferViews[accessor.bufferView]); glBindBuffer(bufferView.target, vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbos[accessor.bufferView]);
std::cout << "buffer.data.size = " << buffer.data.size()
int size = 1; << ", bufferview.byteOffset = " << bufferView.byteOffset
if (accessor.type != TINYGLTF_TYPE_SCALAR) { << std::endl;
size = accessor.type;
} glBufferData(bufferView.target, bufferView.byteLength,
&buffer.data.at(0) + bufferView.byteOffset, GL_STATIC_DRAW);
int vaa = -1; }
if (attrib.first.compare("POSITION") == 0) vaa = 0;
if (attrib.first.compare("NORMAL") == 0) vaa = 1; for (size_t i = 0; i < mesh.primitives.size(); ++i) {
if (attrib.first.compare("TEXCOORD_0") == 0) vaa = 2; tinygltf::Primitive primitive = mesh.primitives[i];
if (vaa > -1) { tinygltf::Accessor indexAccessor = model.accessors[primitive.indices];
glEnableVertexAttribArray(vaa);
glVertexAttribPointer(vaa, size, accessor.componentType, for (auto &attrib : primitive.attributes) {
accessor.normalized ? GL_TRUE : GL_FALSE, tinygltf::Accessor accessor = model.accessors[attrib.second];
byteStride, BUFFER_OFFSET(accessor.byteOffset)); int byteStride =
} else accessor.ByteStride(model.bufferViews[accessor.bufferView]);
std::cout << "vaa missing: " << attrib.first << std::endl; glBindBuffer(GL_ARRAY_BUFFER, vbos[accessor.bufferView]);
}
int size = 1;
GLuint texid; if (accessor.type != TINYGLTF_TYPE_SCALAR) {
glGenTextures(1, &texid); size = accessor.type;
}
tinygltf::Texture &tex = model.textures[0];
tinygltf::Image &image = model.images[tex.source]; int vaa = -1;
if (attrib.first.compare("POSITION") == 0) vaa = 0;
glBindTexture(GL_TEXTURE_2D, texid); if (attrib.first.compare("NORMAL") == 0) vaa = 1;
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); if (attrib.first.compare("TEXCOORD_0") == 0) vaa = 2;
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); if (vaa > -1) {
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glEnableVertexAttribArray(vaa);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glVertexAttribPointer(vaa, size, accessor.componentType,
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); accessor.normalized ? GL_TRUE : GL_FALSE,
byteStride, BUFFER_OFFSET(accessor.byteOffset));
GLenum format = GL_RGBA; } else
std::cout << "vaa missing: " << attrib.first << std::endl;
if (image.component == 1) { }
format = GL_RED;
} else if (image.component == 2) { GLuint texid;
format = GL_RG; glGenTextures(1, &texid);
} else if (image.component == 3) {
format = GL_RGB; tinygltf::Texture &tex = model.textures[0];
} else { tinygltf::Image &image = model.images[tex.source];
// ???
} glBindTexture(GL_TEXTURE_2D, texid);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
GLenum type = GL_UNSIGNED_BYTE; glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
if (image.bits == 8) { glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// ok glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
} else if (image.bits == 16) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
type = GL_UNSIGNED_SHORT;
} else { GLenum format = GL_RGBA;
// ???
} if (image.component == 1) {
format = GL_RED;
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0, } else if (image.component == 2) {
format, type, &image.image.at(0)); format = GL_RG;
} } else if (image.component == 3) {
format = GL_RGB;
return vbos; } else {
} // ???
}
// bind models
void bindModelNodes(std::map<int, GLuint> vbos, tinygltf::Model &model, GLenum type = GL_UNSIGNED_BYTE;
tinygltf::Node &node) { if (image.bits == 8) {
bindMesh(vbos, model, model.meshes[node.mesh]); // ok
for (size_t i = 0; i < node.children.size(); i++) { } else if (image.bits == 16) {
bindModelNodes(vbos, model, model.nodes[node.children[i]]); type = GL_UNSIGNED_SHORT;
} } else {
} // ???
GLuint bindModel(tinygltf::Model &model) { }
std::map<int, GLuint> vbos;
GLuint vao; glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0,
glGenVertexArrays(1, &vao); format, type, &image.image.at(0));
glBindVertexArray(vao); }
const tinygltf::Scene &scene = model.scenes[model.defaultScene]; return vbos;
for (size_t i = 0; i < scene.nodes.size(); ++i) { }
bindModelNodes(vbos, model, model.nodes[scene.nodes[i]]);
} // bind models
void bindModelNodes(std::map<int, GLuint> vbos, tinygltf::Model &model,
glBindVertexArray(0); tinygltf::Node &node) {
// cleanup vbos bindMesh(vbos, model, model.meshes[node.mesh]);
for (size_t i = 0; i < vbos.size(); ++i) { for (size_t i = 0; i < node.children.size(); i++) {
glDeleteBuffers(1, &vbos[i]); bindModelNodes(vbos, model, model.nodes[node.children[i]]);
} }
}
return vao; GLuint bindModel(tinygltf::Model &model) {
} std::map<int, GLuint> vbos;
GLuint vao;
void drawMesh(tinygltf::Model &model, tinygltf::Mesh &mesh) { glGenVertexArrays(1, &vao);
for (size_t i = 0; i < mesh.primitives.size(); ++i) { glBindVertexArray(vao);
tinygltf::Primitive primitive = mesh.primitives[i];
tinygltf::Accessor indexAccessor = model.accessors[primitive.indices]; const tinygltf::Scene &scene = model.scenes[model.defaultScene];
for (size_t i = 0; i < scene.nodes.size(); ++i) {
glDrawElements(primitive.mode, indexAccessor.count, bindModelNodes(vbos, model, model.nodes[scene.nodes[i]]);
indexAccessor.componentType, }
BUFFER_OFFSET(indexAccessor.byteOffset));
} glBindVertexArray(0);
} // cleanup vbos
for (size_t i = 0; i < vbos.size(); ++i) {
// recursively draw node and children nodes of model glDeleteBuffers(1, &vbos[i]);
void drawModelNodes(tinygltf::Model &model, tinygltf::Node &node) { }
drawMesh(model, model.meshes[node.mesh]);
for (size_t i = 0; i < node.children.size(); i++) { return vao;
drawModelNodes(model, model.nodes[node.children[i]]); }
}
} void drawMesh(tinygltf::Model &model, tinygltf::Mesh &mesh) {
void drawModel(GLuint vao, tinygltf::Model &model) { for (size_t i = 0; i < mesh.primitives.size(); ++i) {
glBindVertexArray(vao); tinygltf::Primitive primitive = mesh.primitives[i];
tinygltf::Accessor indexAccessor = model.accessors[primitive.indices];
const tinygltf::Scene &scene = model.scenes[model.defaultScene];
for (size_t i = 0; i < scene.nodes.size(); ++i) { glDrawElements(primitive.mode, indexAccessor.count,
drawModelNodes(model, model.nodes[scene.nodes[i]]); indexAccessor.componentType,
} BUFFER_OFFSET(indexAccessor.byteOffset));
}
glBindVertexArray(0); }
}
// recursively draw node and children nodes of model
void dbgModel(tinygltf::Model &model) { void drawModelNodes(tinygltf::Model &model, tinygltf::Node &node) {
for (auto &mesh : model.meshes) { drawMesh(model, model.meshes[node.mesh]);
std::cout << "mesh : " << mesh.name << std::endl; for (size_t i = 0; i < node.children.size(); i++) {
for (auto &primitive : mesh.primitives) { drawModelNodes(model, model.nodes[node.children[i]]);
const tinygltf::Accessor &indexAccessor = }
model.accessors[primitive.indices]; }
void drawModel(GLuint vao, tinygltf::Model &model) {
std::cout << "indexaccessor: count " << indexAccessor.count << ", type " glBindVertexArray(vao);
<< indexAccessor.componentType << std::endl;
const tinygltf::Scene &scene = model.scenes[model.defaultScene];
tinygltf::Material &mat = model.materials[primitive.material]; for (size_t i = 0; i < scene.nodes.size(); ++i) {
for (auto &mats : mat.values) { drawModelNodes(model, model.nodes[scene.nodes[i]]);
std::cout << "mat : " << mats.first.c_str() << std::endl; }
}
glBindVertexArray(0);
for (auto &image : model.images) { }
std::cout << "image name : " << image.uri << std::endl;
std::cout << " size : " << image.image.size() << std::endl; void dbgModel(tinygltf::Model &model) {
std::cout << " w/h : " << image.width << "/" << image.height for (auto &mesh : model.meshes) {
<< std::endl; std::cout << "mesh : " << mesh.name << std::endl;
} for (auto &primitive : mesh.primitives) {
const tinygltf::Accessor &indexAccessor =
std::cout << "indices : " << primitive.indices << std::endl; model.accessors[primitive.indices];
std::cout << "mode : "
<< "(" << primitive.mode << ")" << std::endl; std::cout << "indexaccessor: count " << indexAccessor.count << ", type "
<< indexAccessor.componentType << std::endl;
for (auto &attrib : primitive.attributes) {
std::cout << "attribute : " << attrib.first.c_str() << std::endl; tinygltf::Material &mat = model.materials[primitive.material];
} for (auto &mats : mat.values) {
} std::cout << "mat : " << mats.first.c_str() << std::endl;
} }
}
for (auto &image : model.images) {
glm::mat4 genView(glm::vec3 pos, glm::vec3 lookat) { std::cout << "image name : " << image.uri << std::endl;
// Camera matrix std::cout << " size : " << image.image.size() << std::endl;
glm::mat4 view = glm::lookAt( std::cout << " w/h : " << image.width << "/" << image.height
pos, // Camera in World Space << std::endl;
lookat, // and looks at the origin }
glm::vec3(0, 1, 0) // Head is up (set to 0,-1,0 to look upside-down)
); std::cout << "indices : " << primitive.indices << std::endl;
std::cout << "mode : "
return view; << "(" << primitive.mode << ")" << std::endl;
}
for (auto &attrib : primitive.attributes) {
glm::mat4 genMVP(glm::mat4 view_mat, glm::mat4 model_mat, float fov, int w, std::cout << "attribute : " << attrib.first.c_str() << std::endl;
int h) { }
glm::mat4 Projection = }
glm::perspective(glm::radians(fov), (float)w / (float)h, 0.01f, 1000.0f); }
}
// Or, for an ortho camera :
// glm::mat4 Projection = glm::ortho(-10.0f,10.0f,-10.0f,10.0f,0.0f,100.0f); glm::mat4 genView(glm::vec3 pos, glm::vec3 lookat) {
// // In world coordinates // Camera matrix
glm::mat4 view = glm::lookAt(
glm::mat4 mvp = Projection * view_mat * model_mat; pos, // Camera in World Space
lookat, // and looks at the origin
return mvp; glm::vec3(0, 1, 0) // Head is up (set to 0,-1,0 to look upside-down)
} );
void displayLoop(Window &window, const std::string &filename) { return view;
Shaders shader = Shaders(); }
glUseProgram(shader.pid);
glm::mat4 genMVP(glm::mat4 view_mat, glm::mat4 model_mat, float fov, int w,
// grab uniforms to modify int h) {
GLuint MVP_u = glGetUniformLocation(shader.pid, "MVP"); glm::mat4 Projection =
GLuint sun_position_u = glGetUniformLocation(shader.pid, "sun_position"); glm::perspective(glm::radians(fov), (float)w / (float)h, 0.01f, 1000.0f);
GLuint sun_color_u = glGetUniformLocation(shader.pid, "sun_color");
// Or, for an ortho camera :
tinygltf::Model model; // glm::mat4 Projection = glm::ortho(-10.0f,10.0f,-10.0f,10.0f,0.0f,100.0f);
if (!loadModel(model, filename.c_str())) return; // // In world coordinates
GLuint vao = bindModel(model); glm::mat4 mvp = Projection * view_mat * model_mat;
// dbgModel(model); return;
return mvp;
// Model matrix : an identity matrix (model will be at the origin) }
glm::mat4 model_mat = glm::mat4(1.0f);
glm::mat4 model_rot = glm::mat4(1.0f); void displayLoop(Window &window, const std::string &filename) {
glm::vec3 model_pos = glm::vec3(-3, 0, -3); Shaders shader = Shaders();
glUseProgram(shader.pid);
// generate a camera view, based on eye-position and lookAt world-position
glm::mat4 view_mat = genView(glm::vec3(2, 2, 20), model_pos); // grab uniforms to modify
GLuint MVP_u = glGetUniformLocation(shader.pid, "MVP");
glm::vec3 sun_position = glm::vec3(3.0, 10.0, -5.0); GLuint sun_position_u = glGetUniformLocation(shader.pid, "sun_position");
glm::vec3 sun_color = glm::vec3(1.0); GLuint sun_color_u = glGetUniformLocation(shader.pid, "sun_color");
while (!window.Close()) { tinygltf::Model model;
window.Resize(); if (!loadModel(model, filename.c_str())) return;
glClearColor(0.2, 0.2, 0.2, 1.0); GLuint vao = bindModel(model);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // dbgModel(model); return;
glm::mat4 trans = // Model matrix : an identity matrix (model will be at the origin)
glm::translate(glm::mat4(1.0f), model_pos); // reposition model glm::mat4 model_mat = glm::mat4(1.0f);
model_rot = glm::rotate(model_rot, glm::radians(0.8f), glm::mat4 model_rot = glm::mat4(1.0f);
glm::vec3(0, 1, 0)); // rotate model on y axis glm::vec3 model_pos = glm::vec3(-3, 0, -3);
model_mat = trans * model_rot;
// generate a camera view, based on eye-position and lookAt world-position
// build a model-view-projection glm::mat4 view_mat = genView(glm::vec3(2, 2, 20), model_pos);
GLint w, h;
glfwGetWindowSize(window.window, &w, &h); glm::vec3 sun_position = glm::vec3(3.0, 10.0, -5.0);
glm::mat4 mvp = genMVP(view_mat, model_mat, 45.0f, w, h); glm::vec3 sun_color = glm::vec3(1.0);
glUniformMatrix4fv(MVP_u, 1, GL_FALSE, &mvp[0][0]);
while (!window.Close()) {
glUniform3fv(sun_position_u, 1, &sun_position[0]); window.Resize();
glUniform3fv(sun_color_u, 1, &sun_color[0]);
glClearColor(0.2, 0.2, 0.2, 1.0);
drawModel(vao, model); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glfwSwapBuffers(window.window);
glfwPollEvents(); glm::mat4 trans =
} glm::translate(glm::mat4(1.0f), model_pos); // reposition model
} model_rot = glm::rotate(model_rot, glm::radians(0.8f),
glm::vec3(0, 1, 0)); // rotate model on y axis
static void error_callback(int error, const char *description) { model_mat = trans * model_rot;
(void)error;
fprintf(stderr, "Error: %s\n", description); // build a model-view-projection
} GLint w, h;
glfwGetWindowSize(window.window, &w, &h);
int main(int argc, char **argv) { glm::mat4 mvp = genMVP(view_mat, model_mat, 45.0f, w, h);
std::string filename = "../../models/Cube/Cube.gltf"; glUniformMatrix4fv(MVP_u, 1, GL_FALSE, &mvp[0][0]);
if (argc > 1) { glUniform3fv(sun_position_u, 1, &sun_position[0]);
filename = argv[1]; glUniform3fv(sun_color_u, 1, &sun_color[0]);
}
drawModel(vao, model);
glfwSetErrorCallback(error_callback); glfwSwapBuffers(window.window);
glfwPollEvents();
if (!glfwInit()) return -1; }
}
// Force create OpenGL 3.3
// NOTE(syoyo): Linux + NVIDIA driver segfaults for some reason? commenting out glfwWindowHint will work. static void error_callback(int error, const char *description) {
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); (void)error;
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); fprintf(stderr, "Error: %s\n", description);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); }
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); int main(int argc, char **argv) {
#endif std::string filename = "../../models/Cube/Cube.gltf";
#endif
if (argc > 1) {
Window window = Window(800, 600, "TinyGLTF basic example"); filename = argv[1];
glfwMakeContextCurrent(window.window); }
#ifdef __APPLE__ glfwSetErrorCallback(error_callback);
// https://stackoverflow.com/questions/50192625/openggl-segmentation-fault
glewExperimental = GL_TRUE; if (!glfwInit()) return -1;
#endif
// NOTE(syoyo): For some reason, Linux + NVIDIA driver + apt-installed
glewInit(); // glew(1.13) cannot initialize some ARB functions when CONTEXT_VERSION are
std::cout << glGetString(GL_RENDERER) << ", " << glGetString(GL_VERSION) // explicitly given. Proably we need to compile app with recent glfw and
<< std::endl; // glew(or use glad) package
#if !defined(__linux__)
if (!GLEW_VERSION_3_3) { // Try to create OpenGL 3.3 context on Windows and macOS
std::cerr << "OpenGL 3.3 is required to execute this app." << std::endl; glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
return EXIT_FAILURE; glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
} #endif
glEnable(GL_DEPTH_TEST); // glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glDepthFunc(GL_LESS); #ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glEnable(GL_BLEND); #endif
displayLoop(window, filename); Window window = Window(800, 600, "TinyGLTF basic example");
glfwMakeContextCurrent(window.window);
glfwTerminate();
return 0; #ifdef __APPLE__
} // https://stackoverflow.com/questions/50192625/openggl-segmentation-fault
glewExperimental = GL_TRUE;
#endif
if (glewInit() != GLEW_OK) {
std::cerr << "Failed to initialie glew." << std::endl;
return EXIT_FAILURE;
}
std::cout << glGetString(GL_RENDERER) << ", " << glGetString(GL_VERSION)
<< std::endl;
if (!GLEW_ARB_vertex_array_object) {
std::cerr << "GLEW_ARB_vertex_array_object was not available." << std::endl;
return EXIT_FAILURE;
}
if (!GLEW_VERSION_3_3) {
std::cerr << "OpenGL 3.3 is required to execute this app." << std::endl;
return EXIT_FAILURE;
}
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
displayLoop(window, filename);
glfwTerminate();
return 0;
}