Skip to content

Instantly share code, notes, and snippets.

@viperscape
Last active November 14, 2018 07:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save viperscape/989cf91ecbd42a2dd89780e30a166c0a to your computer and use it in GitHub Desktop.
Save viperscape/989cf91ecbd42a2dd89780e30a166c0a to your computer and use it in GitHub Desktop.
gltf cpp
#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;
}
#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()
{
}
@viperscape
Copy link
Author

work in progress, basic gltf rendering using glfw on Windows

@viperscape
Copy link
Author

chirp-gltf

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment