Last active
November 14, 2018 07:03
-
-
Save viperscape/989cf91ecbd42a2dd89780e30a166c0a to your computer and use it in GitHub Desktop.
gltf cpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <fstream> | |
#include <GL/glew.h> | |
#include <GLFW/glfw3.h> | |
#include <glm/gtc/matrix_transform.hpp> | |
#include "window.h" | |
#include "shaders.h" | |
#define TINYGLTF_IMPLEMENTATION | |
#define STB_IMAGE_IMPLEMENTATION | |
#define STB_IMAGE_WRITE_IMPLEMENTATION | |
#define TINYGLTF_NOEXCEPTION | |
#define JSON_NOEXCEPTION | |
#include "tiny_gltf.h" | |
#define BUFFER_OFFSET(i) ((char *)NULL + (i)) | |
GLuint gVao; | |
std::map<std::string, GLint> gAttribs; | |
bool loadModel(tinygltf::Model &model) | |
{ | |
tinygltf::TinyGLTF loader; | |
std::string err; | |
std::string warn; | |
const char* filename = "cube/cube.gltf"; | |
bool res = loader.LoadASCIIFromFile(&model, &err, &warn, filename); | |
if (!warn.empty()) { | |
printf("Warn: %s\n", warn.c_str()); | |
} | |
if (!err.empty()) { | |
printf("Err: %s\n", err.c_str()); | |
} | |
if (!res) | |
printf("Failed to parse glTF\n"); | |
else std::cout << "loaded gltf " << filename << std::endl; | |
return res; | |
} | |
std::map<int, GLuint> bindMesh(std::map<int, GLuint> vbos, tinygltf::Model &model, tinygltf::Mesh &mesh) | |
{ | |
glGenVertexArrays(1, &gVao); | |
glBindVertexArray(gVao); | |
for (size_t i = 0; i < model.bufferViews.size(); ++i) { | |
const tinygltf::BufferView &bufferView = model.bufferViews[i]; | |
if (bufferView.target == 0) { // TODO impl drawarrays | |
std::cout << "WARN: bufferView.target is zero" << std::endl; | |
continue; // Unsupported bufferView. | |
} | |
tinygltf::Buffer buffer = model.buffers[bufferView.buffer]; | |
std::cout << "bufferview.target " << bufferView.target << std::endl; | |
GLuint vbo; | |
glGenBuffers(1, &vbo); | |
glBindBuffer(bufferView.target, vbo); | |
std::cout << "buffer.data.size = " << buffer.data.size() << ", bufferview.byteOffset = " | |
<< bufferView.byteOffset << std::endl; | |
glBufferData(bufferView.target, bufferView.byteLength, | |
&buffer.data.at(0) + bufferView.byteOffset, GL_STATIC_DRAW); | |
for (size_t i = 0; i < mesh.primitives.size(); ++i) | |
{ | |
tinygltf::Primitive primitive = mesh.primitives[i]; | |
tinygltf::Accessor indexAccessor = model.accessors[primitive.indices]; | |
for (auto& attrib : primitive.attributes) | |
{ | |
tinygltf::Accessor accessor = model.accessors[attrib.second]; | |
int byteStride = accessor.ByteStride(model.bufferViews[accessor.bufferView]); | |
int size = 1; | |
if (accessor.type != TINYGLTF_TYPE_SCALAR) { | |
size = accessor.type; | |
} | |
int vaa = -1; | |
if (attrib.first.compare("POSITION") == 0) vaa = 0; | |
if (attrib.first.compare("NORMAL") == 0) vaa = 1; | |
if (attrib.first.compare("TEXCOORD_0") == 0) vaa = 2; | |
if (vaa > -1) | |
{ | |
glEnableVertexAttribArray(vaa); | |
glVertexAttribPointer( | |
vaa, | |
size, | |
accessor.componentType, | |
accessor.normalized ? GL_TRUE : GL_FALSE, | |
byteStride, | |
BUFFER_OFFSET(accessor.byteOffset) | |
); | |
} | |
else std::cout << "vaa missing: " << attrib.first << std::endl; | |
} | |
} | |
vbos[i] = vbo; | |
} | |
glBindVertexArray(0); | |
return vbos; | |
} | |
// bind models | |
void bindModelNodes(std::map<int, GLuint> vbos, tinygltf::Model &model, tinygltf::Node &node) | |
{ | |
bindMesh(vbos, model, model.meshes[node.mesh]); | |
for (size_t i = 0; i < node.children.size(); i++) { | |
bindModelNodes(vbos, model, model.nodes[node.children[i]]); | |
} | |
} | |
void bindModel(std::map<int, GLuint> vbos, tinygltf::Model &model) | |
{ | |
const tinygltf::Scene &scene = model.scenes[model.defaultScene]; | |
for (size_t i = 0; i < scene.nodes.size(); ++i) { | |
bindModelNodes(vbos, model, model.nodes[scene.nodes[i]]); | |
} | |
} | |
void drawMesh(std::map<int, GLuint> vbos, tinygltf::Model &model, tinygltf::Mesh &mesh) | |
{ | |
glBindVertexArray(gVao); | |
for (size_t i = 0; i < mesh.primitives.size(); ++i) | |
{ | |
tinygltf::Primitive primitive = mesh.primitives[i]; | |
tinygltf::Accessor indexAccessor = model.accessors[primitive.indices]; | |
glDrawElements(primitive.mode, indexAccessor.count, indexAccessor.componentType, | |
BUFFER_OFFSET(indexAccessor.byteOffset)); | |
} | |
} | |
// recursively draw node and children nodes of model | |
void drawModelNodes(std::map<int, GLuint> vbos, tinygltf::Model &model, tinygltf::Node &node) | |
{ | |
drawMesh(vbos, model, model.meshes[node.mesh]); | |
for (size_t i = 0; i < node.children.size(); i++) { | |
drawModelNodes(vbos, model, model.nodes[node.children[i]]); | |
} | |
} | |
void drawModel(std::map<int, GLuint> vbos, tinygltf::Model &model) | |
{ | |
const tinygltf::Scene &scene = model.scenes[model.defaultScene]; | |
for (size_t i = 0; i < scene.nodes.size(); ++i) { | |
drawModelNodes(vbos, model, model.nodes[scene.nodes[i]]); | |
} | |
} | |
void dbgMesh(tinygltf::Model &model) | |
{ | |
tinygltf::Primitive primitive = model.meshes[0].primitives[0]; | |
const tinygltf::Accessor &indexAccessor = model.accessors[primitive.indices]; | |
std::cout << "indexaccessor: count " << indexAccessor.count << ", type " << | |
indexAccessor.componentType << std::endl; | |
std::cout << "material : " << primitive.material << std::endl; | |
std::cout << "indices : " << primitive.indices << std::endl; | |
std::cout << "mode : " << "(" << primitive.mode << ")" << std::endl; | |
std::cout << "attributes(items=" << primitive.attributes.size() << ")" << std::endl; | |
} | |
glm::mat4 genMVP(glm::mat4 model_mat, float fov, int w, 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); // In world coordinates | |
// Camera matrix | |
glm::mat4 View = glm::lookAt( | |
glm::vec3(5, 5, -10), // Camera in World Space | |
glm::vec3(0, 0, 0), // and looks at the origin | |
glm::vec3(0, 1, 0) // Head is up (set to 0,-1,0 to look upside-down) | |
); | |
glm::mat4 mvp = Projection * View * model_mat; | |
return mvp; | |
} | |
void displayLoop(Window& window) | |
{ | |
Shaders shader = Shaders(); | |
tinygltf::Model model; | |
if (!loadModel(model)) return; | |
std::map<int, GLuint> vbos; | |
bindModel(vbos, model); | |
//dbgMesh(model); | |
// Model matrix : an identity matrix (model will be at the origin) | |
glm::mat4 model_mat = glm::mat4(1.0f); | |
while (!window.Close()) | |
{ | |
window.Resize(); | |
glClearColor(0.2, 0.2, 0.2, 1.0); | |
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |
glUseProgram(shader.pid); | |
//glEnableVertexAttribArray(0); | |
GLuint MVP_u = glGetUniformLocation(shader.pid, "MVP"); | |
GLint w, h; | |
glfwGetWindowSize(window.window, &w, &h); | |
glm::mat4 mvp = genMVP(model_mat, 45.0f, w, h); | |
glUniformMatrix4fv(MVP_u, 1, GL_FALSE, &mvp[0][0]); | |
GLuint MVI_u = glGetUniformLocation(shader.pid, "MVI"); | |
glm::mat3 mvi = glm::transpose(glm::inverse(glm::mat3(model_mat))); | |
glUniformMatrix4fv(MVI_u, 1, GL_FALSE, &mvi[0][0]); | |
drawModel(vbos, model); | |
glfwSwapBuffers(window.window); | |
glfwPollEvents(); | |
} | |
// cleanup vbos | |
for (size_t i = 0; i < vbos.size(); ++i) | |
{ | |
glDeleteBuffers(1, &vbos[i]); | |
} | |
} | |
int main(int argc, char **argv) | |
{ | |
if (!glfwInit()) return -1; | |
Window window = Window(800, 600, "Chirp"); | |
glfwMakeContextCurrent(window.window); | |
glewInit(); | |
std::cout << glGetString(GL_RENDERER) << '\n'; | |
std::cout << glGetString(GL_VERSION) << '\n'; | |
glEnable(GL_DEPTH_TEST); | |
glDepthFunc(GL_LESS); | |
displayLoop(window); | |
glfwTerminate(); | |
return 0; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "shaders.h" | |
#include <iostream> | |
#include <vector> | |
#include <GL/glew.h> | |
#include <GLFW/glfw3.h> | |
std::string FragmentShaderCode = | |
"#version 330 core\n\ | |
in vec3 in_normal;\n\ | |
in vec2 in_texcoord;\n\ | |
uniform mat3 MVI; \n\ | |
\n\ | |
out vec4 color;\n\ | |
void main() {\n\ | |
color = vec4(0.5 * normalize(in_normal) + 0.5, 1.0);\n\ | |
}\n\ | |
"; | |
std::string VertexShaderCode = | |
"#version 330 core\n\ | |
layout(location = 0) in vec3 in_vertex;\n\ | |
layout(location = 1) in vec3 in_normal;\n\ | |
layout(location = 2) in vec2 in_texcoord;\n\ | |
\n\ | |
uniform mat4 MVP;\n\ | |
uniform mat3 MVI;\n\ | |
\n\ | |
out vec3 normal;\n\ | |
out vec2 texcoord;\n\ | |
\n\ | |
void main(){\n\ | |
// Output position of the vertex, in clip space : MVP * position\n\ | |
gl_Position = MVP * vec4(in_vertex, 1);\n\ | |
\n\ | |
normal = MVI * vec4(normalize(in_normal), 0).xyz;\n\ | |
\n\ | |
texcoord = in_texcoord;\n\ | |
}"; | |
Shaders::Shaders() | |
{ | |
// Create the shaders | |
GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER); | |
GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); | |
GLint Result = GL_FALSE; | |
int InfoLogLength; | |
// Compile Vertex Shader | |
char const * VertexSourcePointer = VertexShaderCode.c_str(); | |
glShaderSource(VertexShaderID, 1, &VertexSourcePointer, NULL); | |
glCompileShader(VertexShaderID); | |
// Check Vertex Shader | |
glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result); | |
glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); | |
if (InfoLogLength > 0) { | |
std::vector<char> VertexShaderErrorMessage(InfoLogLength + 1); | |
glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]); | |
printf("%s\n", &VertexShaderErrorMessage[0]); | |
} | |
// Compile Fragment Shader | |
char const * FragmentSourcePointer = FragmentShaderCode.c_str(); | |
glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer, NULL); | |
glCompileShader(FragmentShaderID); | |
// Check Fragment Shader | |
glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result); | |
glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); | |
if (InfoLogLength > 0) { | |
std::vector<char> FragmentShaderErrorMessage(InfoLogLength + 1); | |
glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]); | |
printf("%s\n", &FragmentShaderErrorMessage[0]); | |
} | |
// Link the program | |
printf("Linking program\n"); | |
GLuint ProgramID = glCreateProgram(); | |
glAttachShader(ProgramID, VertexShaderID); | |
glAttachShader(ProgramID, FragmentShaderID); | |
glLinkProgram(ProgramID); | |
// Check the program | |
glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result); | |
glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength); | |
if (InfoLogLength > 0) { | |
std::vector<char> ProgramErrorMessage(InfoLogLength + 1); | |
glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]); | |
printf("%s\n", &ProgramErrorMessage[0]); | |
} | |
glDetachShader(ProgramID, VertexShaderID); | |
glDetachShader(ProgramID, FragmentShaderID); | |
glDeleteShader(VertexShaderID); | |
glDeleteShader(FragmentShaderID); | |
this->pid = ProgramID; | |
} | |
Shaders::~Shaders() | |
{ | |
} |
Author
viperscape
commented
Nov 14, 2018
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment