Browse Source

add some support libs, move sources to src/

main
cinnaboot 5 years ago
parent
commit
ec144d48e2
  1. 2
      .gitattributes
  2. 2
      .gitignore
  3. 26
      Makefile
  4. 349
      main.cpp
  5. BIN
      shader_testing
  6. 96
      shader_testing.h
  7. 442
      src/asset.cpp
  8. 113
      src/asset.h
  9. 38
      src/dumbLog.cpp
  10. 30
      src/dumbLog.h
  11. 9
      src/dumpShader.inl
  12. 20406
      src/json.hpp
  13. 601
      src/main.cpp
  14. 134
      src/shader_testing.h
  15. 7530
      src/stb_image.h
  16. 1621
      src/stb_image_write.h
  17. 4
      src/tiny_gltf.cc
  18. 7760
      src/tiny_gltf.h

2
.gitattributes vendored

@ -4,3 +4,5 @@ data/textured_cube.gltf filter=lfs diff=lfs merge=lfs -text
data/Color[[:space:]]Palette[[:space:]]140.png filter=lfs diff=lfs merge=lfs -text
data/shader.frag filter=lfs diff=lfs merge=lfs -text
data/shader.vert filter=lfs diff=lfs merge=lfs -text
*.frag filter=lfs diff=lfs merge=lfs -text
*.vert filter=lfs diff=lfs merge=lfs -text

2
.gitignore vendored

@ -1,6 +1,6 @@
tags
*.d
*.bin
build/
shader_testing

26
Makefile

@ -1,15 +1,35 @@
SHELL = /bin/sh
CXX = g++
CXXFLAGS = -std=c++11 -g -ggdb3 -Wall -I/usr/include/SDL2
CXXFLAGS = -std=c++11 -g -ggdb3 -Wall -Isrc/ -I/usr/include/SDL2
LDFLAGS = -lSDL2 -lGLEW -lGL
OBJDIR = build
SRCDIR = src
BIN = shader_testing
all:
$(CXX) $(CXXFLAGS) -MMD main.cpp -o $(BIN) $(LDFLAGS)
SOURCES = $(wildcard $(SRCDIR)/*.cpp)
OBJECTS = $(patsubst $(SRCDIR)/%.cpp, $(OBJDIR)/%.o, $(SOURCES))
NDBG_SOURCES = $(wildcard $(SRCDIR)/*.cc)
NDBG_OBJS = $(patsubst $(SRCDIR)/%.cc, $(OBJDIR)/%.o, $(NDBG_SOURCES))
all: $(BIN)
.PHONY: all
-include $(OBJDIR)/*.d
$(OBJECTS): $(OBJDIR)/%.o : $(SRCDIR)/%.cpp
$(CXX) $(CXXFLAGS) -c -MMD $< -o $@
$(NDBG_OBJS): $(OBJDIR)/%.o : $(SRCDIR)/%.cc
$(CXX) -std=c++11 -Wall -Isrc/ -c $< -o $@
$(BIN): $(OBJECTS) $(NDBG_OBJS)
$(CXX) -o $@ $(LDFLAGS) $^
clean:
rm -rf $(BIN)
rm -rf build/*
.PHONY: clean

349
main.cpp

@ -1,349 +0,0 @@
#include <cassert>
#include <cstdlib>
#include <cstring>
#include <string>
#include <fstream>
#include <iostream>
#include <SDL2/SDL.h>
#include <glm/geometric.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include "shader_testing.h"
#include "dumpShader.inl"
SDL_Window *g_window = 0;
SDL_GLContext g_glContext;
SDL_DisplayMode g_display_mode;
transforms g_xforms;
mesh g_cube_mesh;
const u32 NUM_CUBES = 4;
gl_mesh g_gl_cubes[NUM_CUBES];
glm::vec3 g_cube_locs[NUM_CUBES] = {
glm::vec3(-10, 10, 0),
glm::vec3(-10, -10, 0),
glm::vec3( 10, 10, 0),
glm::vec3( 10, -10, 0),
};
void
openglDebugCallback(GLenum source,
GLenum type,
GLuint id,
GLenum severity,
GLsizei length,
const GLchar* message,
const void* userParam)
{
std::cout << ((type == GL_DEBUG_TYPE_ERROR) ? "Error" : "Debug")
<< (type == GL_DEBUG_TYPE_ERROR ? "** GL Error **" : "")
<< ", type: " << type
<< ", severity: " << severity
<< ", message: " << message << "\n";
}
bool
init()
{
g_window = SDL_CreateWindow(
"shader_testing",
SDL_WINDOWPOS_CENTERED_DISPLAY(0),
SDL_WINDOWPOS_CENTERED_DISPLAY(0),
1280,
720,
SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE);
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
std::cout << "error, sdl init: " << SDL_GetError() << "\n";
return false;
}
SDL_GL_SetSwapInterval(1);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS,
SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,
SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GetCurrentDisplayMode(0, &g_display_mode);
g_glContext = SDL_GL_CreateContext(g_window);
if (!g_glContext) {
std::cout << "error creating context\n";
return false;
}
if (glewInit()) {
std::cout << "error initializing opengl\n";
return false;
}
std::cout << "opengl vendor: " << glGetString(GL_VENDOR) << "\n";
std::cout << "opengl renderer: " << glGetString(GL_RENDERER) << "\n";
std::cout << "opengl version: " << glGetString(GL_VERSION) << "\n";
glEnable(GL_DEPTH_TEST);
glEnable(GL_LINE_SMOOTH);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glEnable (GL_DEBUG_OUTPUT);
glDebugMessageCallback((GLDEBUGPROC) openglDebugCallback, 0);
return g_window != nullptr;
}
const std::string
dumpTextFile(const char* filepath)
{
std::ifstream fs { filepath };
std::string s {
std::istreambuf_iterator<char>(fs),
std::istreambuf_iterator<char>()};
if (!fs || !fs.good())
std::cout << "error reading file, " << filepath << "\n";
return s;
}
bool
loadShaderProgram(const char* vs, const char* fs, shader* s)
{
std::string vert = dumpTextFile(vs);
std::string frag = dumpTextFile(fs);
if (vert.size() > 0 && frag.size() > 0) {
const char* vert_c = vert.c_str();
const char* frag_c = frag.c_str();
GLuint vs_id = glCreateShader(GL_VERTEX_SHADER);
GLuint fs_id = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(vs_id, 1, &vert_c, NULL);
glShaderSource(fs_id, 1, &frag_c, NULL);
glCompileShader(vs_id);
glCompileShader(fs_id);
s->prog_id = glCreateProgram();
glAttachShader(s->prog_id, vs_id);
glAttachShader(s->prog_id, fs_id);
glLinkProgram(s->prog_id);
glDetachShader(s->prog_id, vs_id);
glDetachShader(s->prog_id, fs_id);
glDeleteShader(vs_id);
glDeleteShader(fs_id);
GLint is_linked = 0;
glGetProgramiv(s->prog_id, GL_LINK_STATUS, &is_linked);
return (is_linked == GL_TRUE);
}
return false;
}
transforms
initXformUBO(shader* s,
float fov,
float near_clip_plane,
float aspect_ratio,
glm::vec3 cam_pos,
glm::vec3 look_pos)
{
transforms xforms;
xforms.view_xform = glm::lookAt(cam_pos, look_pos, glm::vec3(0, 1, 0));
xforms.proj_xform = glm::infinitePerspective(
glm::radians(fov), aspect_ratio, near_clip_plane);
xforms.normal_xform = glm::mat4(1);
glGenBuffers(1, &s->xforms_ubo_id);
glBindBufferBase(GL_UNIFORM_BUFFER, 0, s->xforms_ubo_id);
glBindBuffer(GL_UNIFORM_BUFFER, s->xforms_ubo_id);
glBufferData(GL_UNIFORM_BUFFER, sizeof(xforms), &xforms, GL_STATIC_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
return xforms;
};
mesh
initCubeMesh()
{
mesh m = {0};
m.num_vertices = 8;
m.vertices = (glm::vec3*) std::calloc(m.num_vertices, sizeof(glm::vec3));
m.vertices[0] = { -1, 1, -1 };
m.vertices[1] = { -1, -1, -1 };
m.vertices[2] = { 1, -1, -1 };
m.vertices[3] = { 1, 1, -1 };
m.vertices[4] = { -1, 1, 1 };
m.vertices[5] = { -1, -1, 1 };
m.vertices[6] = { 1, -1, 1 };
m.vertices[7] = { 1, 1, 1 };
m.num_indices = 36; // 6 sides, 2 tris per side, 3 verts per tri
m.indices = (u32*) std::calloc(m.num_indices, sizeof(u32));
u32 indices[36] = {
0, 1, 2, 0, 2, 3,
3, 2, 6, 3, 6, 7,
7, 6, 5, 7, 5, 4,
4, 5, 0, 4, 1, 0,
0, 3, 4, 0, 3, 7,
1, 2, 5, 2, 6, 5
};
std::memcpy(m.indices, indices, m.num_indices * sizeof(u32));
return m;
}
gl_mesh
loadGLMesh(shader* s, const mesh& m, GLenum draw_mode, const glm::vec3& pos)
{
gl_mesh gm = {0};
gm.num_indices = m.num_indices;
gm.draw_mode = draw_mode;
glUseProgram(s->prog_id);
glGenVertexArrays(1, &gm.vao_id);
glBindVertexArray(gm.vao_id);
gm.model_xform = (glm::mat4*) std::calloc(1, sizeof(glm::mat4));
*gm.model_xform = glm::translate(glm::mat4(1), pos);
gm.model_xform_id = glGetUniformLocation(s->prog_id, "model_xform");
glUniformMatrix4fv(
gm.model_xform_id, 1, GL_FALSE, (float*) gm.model_xform);
glGenBuffers(1, &gm.vert_buf_id);
glBindBuffer(GL_ARRAY_BUFFER, gm.vert_buf_id);
glBufferData(GL_ARRAY_BUFFER,
m.num_vertices * 3 * sizeof(GLfloat),
m.vertices,
GL_STATIC_DRAW);
glVertexAttribPointer(POSITION, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(POSITION);
glGenBuffers(1, &gm.idx_buf_id);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gm.idx_buf_id);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
m.num_indices * sizeof(GLuint),
m.indices,
GL_STATIC_DRAW);
glBindVertexArray(0);
glUseProgram(0);
return gm;
}
void
loop(shader* s, gl_mesh* mesh_arr, u32 num_meshes)
{
u32 delay = 60;
u32 frame_start, frame_time;
bool running = true;
SDL_Event e;
while (running) {
frame_start = SDL_GetTicks();
while (SDL_PollEvent(&e)) {
if (e.type == SDL_QUIT ||
(e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_ESCAPE))
{
running = false;
break;
}
}
glClearColor(0.2, 0.2, 0.2, 1);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glUseProgram(s->prog_id);
glBindBuffer(GL_UNIFORM_BUFFER, s->xforms_ubo_id);
for (u32 i = 0; i < num_meshes; i++) {
const gl_mesh& m = mesh_arr[i];
*m.model_xform = glm::rotate(
*m.model_xform, (float) M_PI / 60, glm::vec3(0, 1, 0));
glBindVertexArray(m.vao_id);
glUniformMatrix4fv(
m.model_xform_id, 1, GL_FALSE, (float*) m.model_xform);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m.idx_buf_id);
glDrawElements(m.draw_mode, m.num_indices, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
}
SDL_GL_SwapWindow(g_window);
glUseProgram(0);
frame_time = SDL_GetTicks() - frame_start;
if (delay > frame_time)
SDL_Delay(delay - frame_time);
}
}
void
quit(shader* s)
{
glDeleteProgram(s->prog_id);
SDL_GL_DeleteContext(g_glContext);
SDL_DestroyWindow(g_window);
SDL_Quit();
for (u32 i = 0; i < NUM_CUBES; i++) {
gl_mesh& c = g_gl_cubes[i];
if (c.model_xform != nullptr)
free(c.model_xform);
}
mesh& cm = g_cube_mesh;
if (cm.vertices != nullptr)
free(cm.vertices);
if (cm.normals != nullptr)
free(cm.normals);
if (cm.uvs != nullptr)
free(cm.uvs);
if (cm.colors != nullptr)
free(cm.colors);
if (cm.indices != nullptr)
free(cm.indices);
}
int
main()
{
if (!init())
return 1;
shader s = {0};
if (loadShaderProgram("data/shader.vert", "data/shader.frag", &s)) {
dumpShader(s.prog_id);
g_xforms = initXformUBO(&s);
g_cube_mesh = initCubeMesh();
for (u32 i = 0; i < NUM_CUBES; i++) {
g_gl_cubes[i] =
loadGLMesh(&s, g_cube_mesh, GL_TRIANGLES, g_cube_locs[i]);
assert(g_gl_cubes[i].vao_id != 0);
}
loop(&s, g_gl_cubes, NUM_CUBES);
quit(&s);
return 0;
}
std::cout << "error loading shader program\n";
quit(&s);
return 1;
}

BIN
shader_testing

Binary file not shown.

96
shader_testing.h

@ -1,96 +0,0 @@
#pragma once
#include <GL/glew.h>
#include <glm/glm.hpp>
typedef uint32_t u32;
struct gl_uniform
{
GLenum id;
GLenum data_type;
};
struct gl_buffer
{
GLuint id;
GLenum data_type;
};
struct shader
{
GLuint prog_id;
GLuint xforms_ubo_id;
};
struct transforms
{
glm::mat4 view_xform;
glm::mat4 proj_xform;
glm::mat4 normal_xform;
};
enum glsl_layout
{
POSITION,
NORMAL,
UV,
COLOR
};
struct mesh
{
u32 num_vertices;
u32 num_indices;
glm::vec3* vertices;
glm::vec3* normals;
glm::vec3* uvs;
glm::vec3* colors;
u32* indices;
};
struct gl_mesh
{
u32 num_indices;
GLuint vao_id;
GLuint tex_id;
GLenum draw_mode;
glm::mat4* model_xform;
GLuint model_xform_id;
GLuint vert_buf_id;
GLuint norm_buf_id;
GLuint uv_buf_id;
GLuint clr_buf_id;
GLuint idx_buf_id;
};
struct node;
struct entity;
struct light;
struct animation;
const float DEFAULT_FOV = 60.f;
const float NEAR_CLIP_PLANE = 5.f;
const float DEFAULT_ASPECT_RATIO = 16.f / 9.f;
const glm::vec3 DEFAULT_CAM_POS = { 0, 0, -30.f };
const glm::vec3 DEFAULT_LOOK_POS = { 0, 0, 0 };
bool loadShaderProgram(const char* vs, const char* fs, shader* s);
transforms initXformUBO(shader* s,
float fov = DEFAULT_FOV,
float near_clip_plane = NEAR_CLIP_PLANE,
float aspect_ratio = DEFAULT_ASPECT_RATIO,
glm::vec3 cam_pos = DEFAULT_CAM_POS,
glm::vec3 look_pos = DEFAULT_LOOK_POS);
mesh initCubeMesh();
gl_mesh loadGLMesh(shader* s, const mesh& m, const glm::vec3& pos);
void loop(shader* s, gl_mesh* mesh_arr, u32 num_meshes);
void quit(shader* s);

442
src/asset.cpp

@ -0,0 +1,442 @@
#include <cassert>
#include <cstring>
#include <glm/ext/matrix_transform.hpp>
#include "tiny_gltf.h"
#include "asset.h"
#include "dumbLog.h"
//-----------------
// Hashing
uint64_t
utilFNV64a_str(const char* str, uint64_t hval)
{
unsigned char* s = (unsigned char *)str; // unsigned string
// FNV-1a hash each octet of the string
while (*s) {
// xor the bottom with the current octet
hval ^= (uint64_t)*s++;
// multiply by the 64 bit FNV magic prime mod 2^64
hval *= FNV_64_PRIME;
}
return hval;
}
//-----------------
// Memory allocation
memory_arena*
arenaInit(size_t initial_size)
{
uint sz = sizeof(memory_arena);
memory_arena* arena =
(memory_arena*) std::calloc(initial_size + sz, sizeof(u8));
arena->head = arena->next_free = (uint8_t*) arena + sz;
arena->max_size = initial_size;
return arena;
}
void
arenaFree(memory_arena*& arena)
{
if (arena != nullptr) {
std::free(arena);
arena = nullptr;
}
}
uint
arenaGetFreeSize(memory_arena* arena)
{
return (uint8_t*) arena->head
+ arena->max_size
- (uint8_t*) arena->next_free;
}
void*
arenaAllocateBlock(memory_arena* arena, size_t block_size)
{
// TODO: resizable memory arena
assert(arenaGetFreeSize(arena) >= block_size);
void* ret = arena->next_free;
arena->next_free = (uint8_t*) arena->next_free + block_size;
return ret;
}
// forward declarations
void dumpNodes(tinygltf::Model t_mdl);
model* initModel(model_assets* assets,
memory_arena* arena,
tinygltf::Model t_mdl,
const char* filename);
bool parseMeshNode(mesh* m,
texture_assets* textures,
memory_arena* arena,
const tinygltf::Node& node,
const tinygltf::Model& t_mdl);
// interface
model_assets*
assetInitModelBlock(memory_arena* arena, uint asset_count)
{
model_assets* assets =
(model_assets*) arenaAllocateBlock(arena, sizeof(model_assets));
assets->models =
(model*) arenaAllocateBlock(arena, asset_count * sizeof(model));
assets->max = asset_count;
return assets;
}
texture_assets*
assetInitTextureBlock(memory_arena* arena, uint asset_count)
{
texture_assets* assets =
(texture_assets*) arenaAllocateBlock(arena, sizeof(texture_assets));
assets->images = (util_image*) arenaAllocateBlock(
arena, asset_count * sizeof(util_image));
assets->max = asset_count;
return assets;
}
// FIXME: move to internal when finished
util_image*
copyDiffuseTexture(texture_assets* textures,
memory_arena* arena,
const tinygltf::Model& t_mdl)
{
// NOTE: assuming material[0] since we're using pallete texture
assert(t_mdl.materials.size() == 1
&& t_mdl.textures.size() == 1
&& t_mdl.images.size() == 1
&& t_mdl.images[0].image.size() > 0);
tinygltf::Image t_img = t_mdl.images[0];
// TODO: re-alloc array when out of space
assert(textures->count < textures->max && arena != nullptr);
util_image* dtex = &textures->images[textures->count];
textures->count++;
dtex->w = t_img.width;
dtex->h = t_img.height;
dtex->bits_per_channel = t_img.bits;
dtex->num_channels = t_img.component;
dtex->data_len = t_img.image.size();
dtex->pixels = (u8*) arenaAllocateBlock(arena, dtex->data_len);
// FIXME: overwriting memory here... also fix in libTangerine
std::strncpy(dtex->file_path, t_img.uri.c_str(), t_img.uri.size());
dtex->filepath_hash = utilFNV64a_str(t_img.uri.c_str());
std::memcpy(dtex->pixels, t_img.image.data(), dtex->data_len);
return dtex;
}
model*
assetLoadFromFile(model_assets* assets,
texture_assets* textures,
memory_arena* arena,
const char* filename)
{
tinygltf::Model t_mdl;
tinygltf::TinyGLTF gltf_ctx;
std::string err;
std::string warn;
LOG(Info) << "Loading model: " << filename << "\n";
if (!gltf_ctx.LoadASCIIFromFile(&t_mdl, &err, &warn, filename)) {
LOG(Error) << "Error loading file: " << filename
<< " , msg: " << err << "\n";
return nullptr;
}
#if 0
dumpNodes(t_mdl);
#endif
// NOTE: assume we're working with a single buffer
assert(t_mdl.buffers.size() == 1);
model* mdl = initModel(assets, arena, t_mdl, filename);
#if 0
// FIXME: probably a bug here with overwriting arena memory
mdl->diffuse_texture = copyDiffuseTexture(textures, arena, t_mdl);
if (mdl->diffuse_texture == nullptr) {
LOG(Error) << "Error Loading diffuse texture\n";
// TODO: reclaim arena memory
return nullptr;
}
#endif
uint mesh_idx = 0;
for (tinygltf::Node node : t_mdl.nodes) {
if (node.mesh >= 0) {
if (!parseMeshNode(&mdl->meshes[mesh_idx++],
textures, arena, node, t_mdl))
{
LOG(Error) << "Error parsing node\n";
return nullptr;
}
}
}
return mdl;
}
model*
assetGetCached(model_assets* assets, uint64_t path_hash)
{
for (uint i = 0; i < assets->count; i++) {
if (assets->models[i].filepath_hash == path_hash)
return &assets->models[i];
}
LOG(Debug) << "asset not cached: " << path_hash << "\n";
return nullptr;
}
// internal
model*
initModel(model_assets* assets,
memory_arena* arena,
tinygltf::Model t_mdl,
const char* filename)
{
// TODO: re-alloc array when out of space
assert(assets->count < assets->max && arena != nullptr);
model* mdl = &assets->models[assets->count];
assets->count++;
uint buf_count = t_mdl.bufferViews.size();
mdl->meshes = (mesh*) arenaAllocateBlock(arena, buf_count * sizeof(mesh));
mdl->num_meshes = t_mdl.meshes.size();
uint name_len = std::strlen(filename);
assert(name_len < MAX_PATH_SIZE);
mdl->filepath = (char*) arenaAllocateBlock(arena, name_len + 1);
std::strncpy(mdl->filepath, filename, name_len);
mdl->filepath_hash = utilFNV64a_str(mdl->filepath);
return mdl;
}
bool
copyBuffer(uint8_t*& buffer_ref,
memory_arena* arena,
int acc_idx,
const tinygltf::Model& t_mdl)
{
const tinygltf::Accessor& acc = t_mdl.accessors[acc_idx];
const tinygltf::BufferView& bv = t_mdl.bufferViews[acc.bufferView];
const tinygltf::Buffer& t_buf = t_mdl.buffers[bv.buffer];
// TODO: clean up validation
if (bv.target == TINYGLTF_TARGET_ARRAY_BUFFER) {
assert(acc.componentType == TINYGLTF_COMPONENT_TYPE_FLOAT
&& (acc.type == TINYGLTF_TYPE_VEC3
|| acc.type == TINYGLTF_TYPE_VEC2));
} else if (bv.target == TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER) {
assert(acc.type == TINYGLTF_TYPE_SCALAR
&& acc.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT);
} else {
LOG(Error) << "unknown target\n";
return false;
}
assert(bv.byteStride == 0);
buffer_ref = (uint8_t*) arenaAllocateBlock(arena, bv.byteLength);
std::memcpy(buffer_ref, &t_buf.data[bv.byteOffset], bv.byteLength);
return buffer_ref != nullptr;
}
// FIXME: need to implement tree structure for blender models to work properly
glm::mat4*
parseNodeTransform(memory_arena* arena, const tinygltf::Node* node)
{
if (node->rotation.size() == 4
&& node->scale.size() == 3
&& node->translation.size() == 3)
{
glm::mat4* xform =
(glm::mat4*) arenaAllocateBlock(arena, sizeof(glm::mat4));
*xform = glm::mat4(1.0f);
*xform = glm::rotate(*xform, (float) node->rotation[3],
glm::vec3((float) node->rotation[0],
(float) node->rotation[1],
(float) node->rotation[2])
);
*xform = glm::scale(*xform,
glm::vec3((float) node->scale[0],
(float) node->scale[0],
(float) node->scale[0])
);
*xform = glm::translate(*xform,
glm::vec3((float) node->translation[0],
(float) node->translation[0],
(float) node->translation[0])
);
return xform;
}
LOG(Error) << "Unknown transform\n";
return nullptr;
}
bool
parseMeshNode(mesh* m,
texture_assets* textures,
memory_arena* arena,
const tinygltf::Node& node,
const tinygltf::Model& t_mdl)
{
tinygltf::Mesh t_mesh = t_mdl.meshes[node.mesh];
// NOTE: assume only 1 primitive object per mesh
assert(t_mdl.meshes[node.mesh].primitives.size() == 1);
tinygltf::Primitive prim = t_mesh.primitives[0];
// NOTE: verify assumptions about input
assert(prim.attributes.find("POSITION") != prim.attributes.end()
&& prim.attributes.find("NORMAL") != prim.attributes.end()
&& prim.attributes.find("TEXCOORD_0") != prim.attributes.end()
&& prim.indices >= 0);
const tinygltf::Accessor& vert_acc =
t_mdl.accessors[prim.attributes["POSITION"]];
const tinygltf::Accessor& index_acc = t_mdl.accessors[prim.indices];
m->num_vertices = vert_acc.count;
m->num_indices = index_acc.count;
m->draw_mode = prim.mode;
m->usage = GL_STATIC_DRAW; // TODO: logic for updating dynamic meshes
// FIXME: the node transforms from blender only work as part of a node tree
#if 1
m->xform = (glm::mat4*) arenaAllocateBlock(arena, sizeof(glm::mat4));
*m->xform = glm::mat4(1.0f);
#else
m->xform = parseNodeTransform(arena, &node);
#endif
if (m->xform != nullptr
&& copyBuffer((uint8_t*&) m->vertices, arena,
prim.attributes["POSITION"], t_mdl)
&& copyBuffer((uint8_t*&) m->normals, arena,
prim.attributes["NORMAL"], t_mdl)
&& copyBuffer((uint8_t*&) m->uvs, arena,
prim.attributes["TEXCOORD_0"], t_mdl)
&& copyBuffer((uint8_t*&) m->indices, arena,
prim.indices, t_mdl))
{
return true;
}
return false;
}
const char*
getTargetStr(int target)
{
switch (target) {
case 34962: return "GL_ARRAY_BUFFER";
case 34963: return "GL_ELEMENT_ARRAY_BUFFER";
default: return "UNKNOWN";
}
}
const char*
getElementType(int type)
{
switch (type) {
case 2: return "TINYGLTF_TYPE_VEC2";
case 3: return "TINYGLTF_TYPE_VEC3";
case 4: return "TINYGLTF_TYPE_VEC4";
case 65: return "TINYGLTF_TYPE_SCALAR";
default: return "UNKNOWN";
}
}
const char*
getComponentType(int componentType)
{
switch (componentType) {
case 5123: return "TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT";
case 5124: return "TINYGLTF_COMPONENT_TYPE_INT";
case 5125: return "TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT";
case 5126: return "TINYGLTF_COMPONENT_TYPE_FLOAT";
case 5130: return "TINYGLTF_COMPONENT_TYPE_DOUBLE";
default: return "UNKOWN"; }
}
const char*
getDrawMode(int drawMode)
{
switch (drawMode) {
case 0: return "TINYGLTF_MODE_POINTS";
case 1: return "TINYGLTF_MODE_LINE";
case 2: return "TINYGLTF_MODE_LINE_LOOP";
case 3: return "TINYGLTF_MODE_LINE_STRIP";
case 4: return "TINYGLTF_MODE_TRIANGLES";
case 5: return "TINYGLTF_MODE_TRIANGLE_STRIP";
case 6: return "TINYGLTF_MODE_TRIANGLE_FAN";
default: return "UNKOWN MODE";
}
}
void
dumpBuffer(tinygltf::Model model, tinygltf::Accessor acc)
{
size_t bv_idx = acc.bufferView;
assert(bv_idx >= 0 && bv_idx < model.bufferViews.size());
tinygltf::BufferView bv = model.bufferViews[bv_idx];
LOG(Debug) << "-----------------------\n";
LOG(Debug) << "buf idx: " << bv_idx << "\n";
LOG(Debug) << "buf target: " << getTargetStr(bv.target) << "\n";
LOG(Debug) << "buf len: " << bv.byteLength << "\n";
LOG(Debug) << "buf offset: " << bv.byteOffset << "\n";
LOG(Debug) << "buf stride: " << bv.byteStride << "\n";
LOG(Debug) << "acc component type: "
<< getComponentType(acc.componentType) << "\n";
LOG(Debug) << "acc element type: "
<< getElementType(acc.type) << "\n";
}
void
dumpNodes(tinygltf::Model t_mdl)
{
for (tinygltf::Node node : t_mdl.nodes) {
LOG(Debug) << "##################\n";
LOG(Debug) << "node name: " << node.name << "\n";
LOG(Debug) << "node mesh idx: " << node.mesh << "\n";
if (node.mesh >= 0) {
tinygltf::Mesh t_mesh = t_mdl.meshes[node.mesh];
LOG(Debug) << "node mesh name: " << t_mesh.name << "\n";
// NOTE: assume only 1 primitive object per mesh
assert(t_mdl.meshes[node.mesh].primitives.size() == 1);
tinygltf::Primitive prim = t_mesh.primitives[0];
LOG(Debug) << "node draw mode: " << getDrawMode(prim.mode) << "\n";
for (auto& att : prim.attributes) {
LOG(Debug) << "dumping buffer: " << att.first << "\n";
dumpBuffer(t_mdl, t_mdl.accessors[att.second]);
}
LOG(Debug) << "dumping index buffer\n";
dumpBuffer(t_mdl, t_mdl.accessors[prim.indices]);
} else {
LOG(Debug) << "Not a mesh node\n";
}
}
}

113
src/asset.h

@ -0,0 +1,113 @@
#pragma once
#include <GL/glew.h>
#include <glm/glm.hpp>
typedef uint8_t u8;
typedef int32_t i32;
typedef uint64_t u64;
//-----------------
// Hashing
// NOTE: FNV1a hashing algorithm http://www.isthe.com/chongo/tech/comp/fnv/
#define FNV1_64_INIT ((u64) 0xcbf29ce484222325ULL)
#define FNV_64_PRIME ((u64) 0x100000001b3ULL)
u64
utilFNV64a_str(const char *str, u64 hval = FNV1_64_INIT);
//-----------------
// Memory allocation
struct memory_arena
{
size_t max_size;
void* head;
void* next_free;
};
#define DEFAULT_ARENA_SIZE 10 * 1024 * 1024 // 10MB
memory_arena* arenaInit(size_t initial_size = DEFAULT_ARENA_SIZE);
void arenaFree(memory_arena*& arena);
uint arenaGetFreeSize(memory_arena* arena);
void* arenaAllocateBlock(memory_arena* arena, size_t block_size);
// NOTE: wrapper for stb_image
struct util_image
{
i32 w;
i32 h;
i32 bits_per_channel;
i32 num_channels;
uint data_len;
u8* pixels;
u64 filepath_hash;
// FIXME: should use a pointer here, and just add the length of file_path
// onto the allocation for util_image
char file_path[256];
};
// NOTE: wrapper for tinygltf https://github.com/syoyo/tinygltf
// https://github.com/KhronosGroup/glTF
struct mesh
{
GLenum draw_mode; // NOTE: GL_LINES, GL_TRIANGLES
GLenum usage; // NOTE: GL_STATIC_DRAW, GL_DYNAMIC_DRAW
uint num_vertices;
uint num_indices;
glm::vec3* vertices;
glm::vec3* normals;
glm::vec2* uvs;
glm::vec3* colors;
uint* indices;
glm::mat4* xform;
};
#define MAX_PATH_SIZE 256
struct model
{
char* filepath;
u64 filepath_hash;
uint num_meshes;
mesh* meshes;
util_image* diffuse_texture;
};
struct model_assets
{
model* models;
uint count;
uint max;
};
struct texture_assets
{
util_image* images;
uint count;
uint max;
};
// TODO: would be nice to make these init functions generic
model_assets*
assetInitModelBlock(memory_arena* arena, uint asset_count);
texture_assets*
assetInitTextureBlock(memory_arena* arena, uint asset_count);
model*
assetLoadFromFile(model_assets* assets,
texture_assets* textures,
memory_arena* arena,
const char* filename);
model*
assetGetCached(model_assets* assets, u64 path_hash);

38
src/dumbLog.cpp

@ -0,0 +1,38 @@
#include <ctime>
#include <chrono>
#include "dumbLog.h"
void dumbLog::setOutputStream(std::ostream* out)
{
this->OUT = out;
}
const char*
dumbLog::logLevelToString(log_level level)
{
switch (level) {
case log_level::Error: return "Error";
case log_level::Warning: return "Warning";
case log_level::Info: return "Info";
default: return "Potato";
}
};
std::tm*
dumbLog::getCurrentTime()
{
auto now = std::chrono::system_clock::now();
auto t_c = std::chrono::system_clock::to_time_t(now);
return std::localtime(&t_c);
}
int
dumbLog::getCurrentMS()
{
auto now = std::chrono::system_clock::now();
long long total_ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
return int(total_ms % 1000);
}

30
src/dumbLog.h

@ -0,0 +1,30 @@
#pragma once
#include <iomanip>
#include <iostream>
enum log_level {
Error,
Warning,
Info,
Debug
};
struct dumbLog
{
std::ostream* OUT = &std::cout;
void setOutputStream(std::ostream* out);
const char* logLevelToString(log_level level);
std::tm* getCurrentTime();
int getCurrentMS();
};
static dumbLog logger;
#define LOG(level) *logger.OUT \
<< std::put_time(logger.getCurrentTime(), "%F %T.") << logger.getCurrentMS() << " " \
<< "[" << logger.logLevelToString(level) << "] " \
<< "(" << __FUNCTION__ << ") "

9
dumpShader.inl → src/dumpShader.inl

@ -35,15 +35,15 @@ dumpShader(GLuint prog_id)
for (int i = 0; i < active_uniforms; i++) {
glGetActiveUniform(prog_id, i, sizeof(uni_name),
&length, &size, &type, uni_name);
printf("uniform idx: %d, len: %d, type: %s, name: %s \n",
i, length, gl_enum_to_string(type), uni_name);
printf("uniform idx: %d, type: %s, name: %s \n",
i, gl_enum_to_string(type), uni_name);
}
for (int i = 0; i < active_attribs; i++) {
glGetActiveAttrib(prog_id, i, sizeof(uni_name),
&length, &size, &type, uni_name);
printf("attribute idx: %d, len: %d, type: %s, name: %s \n",
i, length, gl_enum_to_string(type), uni_name);
printf("attribute idx: %d, type: %s, name: %s \n",
i, gl_enum_to_string(type), uni_name);
}
}
@ -54,6 +54,7 @@ gl_enum_to_string(GLenum e)
switch (e) {
case 0x8b5c: return "GL_FLOAT_MAT4";
case 0x8b51: return "GL_FLOAT_VEC3";
case 0x8B52: return "GL_FLOAT_VEC4";
default: return "???";
}

20406
src/json.hpp

File diff suppressed because it is too large Load Diff

601
src/main.cpp

@ -0,0 +1,601 @@
#include <cassert>
#include <cstddef>
#include <cstdlib>
#include <cstring>
#include <string>
#include <fstream>
#include <iostream>
#include <SDL2/SDL.h>
#include <glm/geometric.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include "asset.h"
#include "shader_testing.h"
#include "dumpShader.inl"
const float DEFAULT_FOV = 60.f;
const float NEAR_CLIP_PLANE = 5.f;
const float DEFAULT_ASPECT_RATIO = 16.f / 9.f;
const glm::vec3 DEFAULT_CAM_POS = { 0, 0, -30.f };
const glm::vec3 DEFAULT_LOOK_POS = { 0, 0, 0 };
SDL_Window *g_window = 0;
SDL_GLContext g_glContext;
SDL_DisplayMode g_display_mode;
void
openglDebugCallback(GLenum source,
GLenum type,
GLuint id,
GLenum severity,
GLsizei length,
const GLchar* message,
const void* userParam)
{
std::cout << ((type == GL_DEBUG_TYPE_ERROR) ? "Error" : "Debug")
<< (type == GL_DEBUG_TYPE_ERROR ? "** GL Error **" : "")
<< ", type: " << type
<< ", severity: " << severity
<< ", message: " << message << "\n";
}
bool
initGraphics()
{
g_window = SDL_CreateWindow(
"shader_testing",
SDL_WINDOWPOS_CENTERED_DISPLAY(0),
SDL_WINDOWPOS_CENTERED_DISPLAY(0),
1280,
720,
SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE);
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
std::cout << "error, sdl init: " << SDL_GetError() << "\n";
return false;
}
SDL_GL_SetSwapInterval(1);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS,
SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,
SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GetCurrentDisplayMode(0, &g_display_mode);
g_glContext = SDL_GL_CreateContext(g_window);
if (!g_glContext) {
std::cout << "error creating context\n";
return false;
}
if (glewInit()) {
std::cout << "error initializing opengl\n";
return false;
}
std::cout << "opengl vendor: " << glGetString(GL_VENDOR) << "\n";
std::cout << "opengl renderer: " << glGetString(GL_RENDERER) << "\n";
std::cout << "opengl version: " << glGetString(GL_VERSION) << "\n";
glEnable(GL_DEPTH_TEST);
glEnable(GL_LINE_SMOOTH);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glEnable (GL_DEBUG_OUTPUT);
glDebugMessageCallback((GLDEBUGPROC) openglDebugCallback, 0);
return g_window != nullptr;
}
const std::string
dumpTextFile(const char* filepath)
{
std::ifstream fs { filepath };
std::string s {
std::istreambuf_iterator<char>(fs),
std::istreambuf_iterator<char>()};
if (!fs || !fs.good())
std::cout << "error reading file, " << filepath << "\n";
return s;
}
void
parseShaderUniforms(memory_arena* arena, shader_program* s, GLContext* gl_ctx)
{
GLint unif_count;
glGetProgramiv(s->prog_id, GL_ACTIVE_UNIFORMS, &unif_count);
s->num_uniforms = unif_count;
s->uniforms = (gl_uniform*) arenaAllocateBlock(
arena, s->num_uniforms * sizeof(gl_uniform));
for (u32 i = 0; i < s->num_uniforms; i++) {
GLchar unif_name[256] = {0};
GLsizei length;
GLint size;
GLenum type;
glGetActiveUniform(s->prog_id, i, sizeof(unif_name),
&length, &size, &type, unif_name);
s->uniforms[i].data_type = type;
s->uniforms[i].name = (char*) arenaAllocateBlock(
arena, (length + 1) * sizeof(char));
std::strncpy(s->uniforms[i].name, unif_name, length);
glGetActiveUniformsiv(s->prog_id, 1, &i,
GL_UNIFORM_BLOCK_INDEX, &s->uniforms[i].block_idx);
// FIXME: testing idx == unif location
s->uniforms[i].idx = i;
GLuint location = glGetUniformLocation(s->prog_id, s->uniforms[i].name);
printf("idx: %d, loc: %d, block idx: %d \n",
i, location, s->uniforms[i].block_idx);
// TODO: get uniform.data_size from data_type
//printf("i: %d, uniform name: %s, l: %d \n", i, unif_name, length);
}
GLint max_vert_ublocks;
GLint max_frag_ublocks;
GLint max_ublock_size;
glGetIntegerv(GL_MAX_VERTEX_UNIFORM_BLOCKS, &max_vert_ublocks);
glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_BLOCKS, &max_frag_ublocks);
glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &max_ublock_size);
printf("max vert uniform blocks: %d, max frag uniform blocks: %d,"
"max uniform block size: %d bytes \n",
max_vert_ublocks, max_frag_ublocks, max_ublock_size);
GLint max_ubo_bindings;
glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &max_ubo_bindings);
printf("max uniform buffer object binding points: %d \n", max_ubo_bindings);
}
gl_buffer
initTransforms(transforms* xforms,
GLContext* gl_ctx,
float fov = DEFAULT_FOV,
float near_clip_plane = NEAR_CLIP_PLANE,
float aspect_ratio = DEFAULT_ASPECT_RATIO,
glm::vec3 cam_pos = DEFAULT_CAM_POS,
glm::vec3 look_pos = DEFAULT_LOOK_POS)
{
xforms->view_xform = glm::lookAt(cam_pos, look_pos, glm::vec3(0, 1, 0));
xforms->proj_xform = glm::infinitePerspective(
glm::radians(fov), aspect_ratio, near_clip_plane);
gl_buffer ubo = {0};
glGenBuffers(1, &ubo.id);
ubo.target = GL_UNIFORM_BUFFER;
ubo.data_type = GL_FLOAT;
ubo.data_size = sizeof(*xforms);
glBindBuffer(GL_UNIFORM_BUFFER, ubo.id);
glBufferData(GL_UNIFORM_BUFFER, sizeof(*xforms), xforms, GL_DYNAMIC_DRAW);
// NOTE: need to manually keep track of block bindings
glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &gl_ctx->max_binding_points);
glBindBufferBase(GL_UNIFORM_BUFFER, gl_ctx->binding_count, ubo.id);
ubo.binding_idx = gl_ctx->binding_count;
gl_ctx->binding_count++;
glBindBuffer(GL_UNIFORM_BUFFER, 0);
return ubo;
}
mesh
initCubeMesh()
{
mesh m = {0};
m.num_vertices = 8;
m.vertices = (glm::vec3*) std::calloc(m.num_vertices, sizeof(glm::vec3));
m.vertices[0] = { -1, 1, -1 };
m.vertices[1] = { -1, -1, -1 };
m.vertices[2] = { 1, -1, -1 };
m.vertices[3] = { 1, 1, -1 };
m.vertices[4] = { -1, 1, 1 };
m.vertices[5] = { -1, -1, 1 };
m.vertices[6] = { 1, -1, 1 };
m.vertices[7] = { 1, 1, 1 };
m.num_indices = 36; // 6 sides, 2 tris per side, 3 verts per tri
m.indices = (u32*) std::calloc(m.num_indices, sizeof(u32));
u32 indices[36] = {
0, 1, 2, 0, 2, 3,
3, 2, 6, 3, 6, 7,
7, 6, 5, 7, 5, 4,
4, 5, 0, 4, 1, 0,
0, 3, 4, 0, 3, 7,
1, 2, 5, 2, 6, 5
};
std::memcpy(m.indices, indices, m.num_indices * sizeof(u32));
return m;
}
gl_mesh
loadGLMesh(shader_program* s,
const mesh& m,
GLenum draw_mode,
const glm::vec3& pos)
{
gl_mesh gm = {0};
gm.num_indices = m.num_indices;
gm.draw_mode = draw_mode;
// NOTE: okay to store shader_program pointer on gl_mesh here because we
// won't ever delete the shader
gm.shader = s;
glUseProgram(s->prog_id);
glGenVertexArrays(1, &gm.vao_id);
glBindVertexArray(gm.vao_id);
gm.model_xform = (glm::mat4*) std::calloc(1, sizeof(glm::mat4));
*gm.model_xform = glm::translate(glm::mat4(1), pos);
glUniformMatrix4fv(
s->model_xform_id, 1, GL_FALSE, (float*) gm.model_xform);
glGenBuffers(1, &gm.vert_buf_id);
glBindBuffer(GL_ARRAY_BUFFER, gm.vert_buf_id);
glBufferData(GL_ARRAY_BUFFER,
m.num_vertices * 3 * sizeof(GLfloat),
m.vertices,
GL_STATIC_DRAW);
glVertexAttribPointer(POSITION, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(POSITION);
glGenBuffers(1, &gm.idx_buf_id);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gm.idx_buf_id);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
m.num_indices * sizeof(GLuint),
m.indices,
GL_STATIC_DRAW);
glBindVertexArray(0);
glUseProgram(0);
return gm;
}
shader_program*
getShaderByID(ShaderArray* sarr, GLuint prog_id)
{
for (u32 i = 0; i < sarr->count; i++) {
if (sarr->shaders[i].prog_id)
return &sarr->shaders[i];
}
std::cout << "Error, shader not found\n";
return nullptr;
}
void
loop(RenderState* rs)
{
u32 delay = 60;
u32 frame_start, frame_time;
bool running = true;
SDL_Event e;
while (running) {
frame_start = SDL_GetTicks();
while (SDL_PollEvent(&e)) {
if (e.type == SDL_QUIT ||
(e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_ESCAPE))
{
running = false;
break;
}
}
glClearColor(0.2, 0.2, 0.2, 1);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
for (u32 i = 0; i < rs->gl_mesh_arr->count; i++) {
gl_mesh& glm = rs->gl_mesh_arr->gl_meshes[i];
*glm.model_xform = glm::rotate(
*glm.model_xform, (float) M_PI / 60, glm::vec3(0, 1, 0));
glUseProgram(glm.shader->prog_id);
glBindVertexArray(glm.vao_id);
glUniformMatrix4fv(glm.shader->model_xform_id, 1, GL_FALSE,
(float*) glm.model_xform);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, glm.idx_buf_id);
glDrawElements(
glm.draw_mode, glm.num_indices, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
}
SDL_GL_SwapWindow(g_window);
glUseProgram(0);
frame_time = SDL_GetTicks() - frame_start;
if (delay > frame_time)
SDL_Delay(delay - frame_time);
}
}
void
quit(RenderState* rs)
{
if (rs->arena)
std::free(rs->arena);
SDL_GL_DeleteContext(g_glContext);
SDL_DestroyWindow(g_window);
SDL_Quit();
}
// NOTE: equivalent to rgAppend() in libTangerine
model*
getModel(RenderState* rs, const char* filepath)
{
model* mdl = assetGetCached(rs->assets, utilFNV64a_str(filepath));
if (!mdl)
mdl = assetLoadFromFile(rs->assets, rs->textures, rs->arena, filepath);
return mdl;
}
ShaderArray*
initShaderArray(memory_arena* arena, u32 count)
{
ShaderArray* arr =
(ShaderArray*) arenaAllocateBlock(arena, sizeof(ShaderArray));
arr->max = count;
arr->count = 0;
arr->shaders = (shader_program*) arenaAllocateBlock(
arena, count * sizeof(shader_program));
return arr;
}
gl_mesh_array*
initGLMeshArray(memory_arena* arena, u32 count)
{
gl_mesh_array* gma =
(gl_mesh_array*) arenaAllocateBlock(arena, sizeof(gl_mesh_array));
gma->max = count;
gma->count = 0;
gma->gl_meshes =
(gl_mesh*) arenaAllocateBlock(arena, count * sizeof(gl_mesh));
return gma;
}
GLContext*
initGLContext(memory_arena* arena)
{
GLContext* gl_ctx =
(GLContext*) arenaAllocateBlock(arena, sizeof(GLContext));
gl_ctx->shader_arr = initShaderArray(arena, 256);
glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &gl_ctx->max_binding_points);
gl_ctx->binding_count = 0;
return gl_ctx;
}
RenderState*
initRenderState(memory_arena* arena)
{
RenderState* rs =
(RenderState*) arenaAllocateBlock(arena, sizeof(RenderState));
if (rs) {
rs->arena = arena;
rs->assets = assetInitModelBlock(arena, 256);
rs->textures = assetInitTextureBlock(arena, 256);
rs->gl_ctx = initGLContext(arena);
rs->xforms =
(transforms*) arenaAllocateBlock(arena, sizeof(transforms));
rs->gl_mesh_arr = initGLMeshArray(arena, 256);
}
return rs;
}
// TODO: clean up this function
bool
addShaderProgram(memory_arena* arena,
GLContext* gl_ctx,
const char* vs,
const char* fs,
const char* name)
{
if (gl_ctx->shader_arr->count >= gl_ctx->shader_arr->max) {
std::cout << "ShaderArray full\n";
return false;
}
shader_program* s = &gl_ctx->shader_arr->shaders[gl_ctx->shader_arr->count];
gl_ctx->shader_arr->count++;
u32 name_len = std::strlen(name) + 1;
s->name = (char*) arenaAllocateBlock(arena, name_len);
std::strncpy(s->name, name, name_len);
const u32 max_len = 256;
std::string hash_str = vs;
hash_str += fs;
s->hash = utilFNV64a_str(hash_str.substr(0, max_len).c_str());
// FIXME: should probably check the hash here against other shaders loaded
std::string vert = dumpTextFile(vs);
std::string frag = dumpTextFile(fs);
if (vert.size() > 0 && frag.size() > 0) {
const char* vert_c = vert.c_str();
const char* frag_c = frag.c_str();
GLuint vs_id = glCreateShader(GL_VERTEX_SHADER);
GLuint fs_id = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(vs_id, 1, &vert_c, NULL);
glShaderSource(fs_id, 1, &frag_c, NULL);
// TODO: both of these can fail
glCompileShader(vs_id);
glCompileShader(fs_id);
s->prog_id = glCreateProgram();
glAttachShader(s->prog_id, vs_id);
glAttachShader(s->prog_id, fs_id);
glLinkProgram(s->prog_id);
GLint is_linked = 0;
glGetProgramiv(s->prog_id, GL_LINK_STATUS, &is_linked);
if (is_linked) {
s->model_xform_id = glGetUniformLocation(s->prog_id, "model_xform");
// FIXME: testing
// NOTE: set block binding for shader xforms uniform block
GLuint block_idx = glGetUniformBlockIndex(s->prog_id, "matrices");
glUniformBlockBinding(s->prog_id,
block_idx,
gl_ctx->xform_ubo.binding_idx);
// FIXME: fill out new shader extra uniforms and buffers here
dumpShader(s->prog_id);
printf("offset of RenderState.xforms: %lu bytes\n",
offsetof(RenderState, xforms));
parseShaderUniforms(arena, s, gl_ctx);
///
glDetachShader(s->prog_id, vs_id);
glDetachShader(s->prog_id, fs_id);
glDeleteShader(vs_id);
glDeleteShader(fs_id);
return true;
}
printf("%s(), Error linking shader\n", __FUNCTION__);
return false;
}
return false;
}
bool
addGLMesh(gl_mesh_array* gma, gl_mesh* gm)
{
if (gma->count < gma->max) {
// FIXME: wtf was I doing here?
gma->count++;
}
return false;
}
shader_program*
getShaderByName(const char* name, ShaderArray* s_arr)
{
u64 hash = utilFNV64a_str(name);
for (u32 i = 0; i < s_arr->count; i++) {
if (utilFNV64a_str(s_arr->shaders[i].name) == hash)
return &s_arr->shaders[i];
}
std::cout << "shader not found, " << name << "\n";
return nullptr;
}
gl_mesh*
getGLMesh(gl_mesh_array* gma)
{
if (gma->count < gma->max) {
gl_mesh* glm = &gma->gl_meshes[gma->count];
gma->count++;
return glm;
}
std::cout << "Error, gl_mesh_array is full\n";
return nullptr;
}
bool
loadScene(RenderState* rs)
{
mesh cube = initCubeMesh();
const u32 NUM_CUBES = 4;
glm::vec3 cube_locs[NUM_CUBES] = {
glm::vec3(-10, 10, 0),
glm::vec3(-10, -10, 0),
glm::vec3( 10, 10, 0),
glm::vec3( 10, -10, 0),
};
// TODO: full lighting model
//model* tex_cube = getModel(rs, "data/textured_cube.gltf");
// TODO: load debug shader from libTangerine for textured_cube
shader_program* s = getShaderByName("default", rs->gl_ctx->shader_arr);
if (!s)
return false;
for (u32 i = 0; i < NUM_CUBES; i++) {
gl_mesh* gmesh = getGLMesh(rs->gl_mesh_arr);
if (!gmesh)
return false;
*gmesh = loadGLMesh(s, cube, GL_TRIANGLES, cube_locs[i]);
if (gmesh->vao_id == 0)
return false;
}
return true;
}
int
main()
{
if (!initGraphics())
return 1;
memory_arena* arena = arenaInit(DEFAULT_ARENA_SIZE);
RenderState* rs = initRenderState(arena);
if (rs) {
rs->gl_ctx->xform_ubo = initTransforms(rs->xforms, rs->gl_ctx);
if (!addShaderProgram(arena,
rs->gl_ctx,
"data/shader.vert",
"data/shader.frag",
"default"))
{
std::cout << "error loading shader program\n";
return 1;
}
if (!loadScene(rs)) {
std::cout << "error loading scene\n";
return 1;
}
loop(rs);
quit(rs);
return 0;
}
std::cout << "error loading scene\n";
return 1;
}

134
src/shader_testing.h

@ -0,0 +1,134 @@
#pragma once
#include <GL/glew.h>
#include <glm/glm.hpp>
typedef uint32_t u32;
// FIXME: won't need this enum when dynamic shader parsing is working
enum glsl_layout
{
POSITION,
NORMAL,
UV
};
struct gl_buffer
{
GLuint id;
GLenum target;
GLenum data_type;
GLuint data_size;
GLuint binding_idx; // NOTE: set when used as backing for UBO
};
struct gl_uniform
{
GLuint idx; // NOTE: seems to map to location if not part of uniform block
//GLuint location;
GLint block_idx;
GLenum data_type;
GLint data_size;
char* name;
};
struct shader_program
{
GLuint prog_id;
GLuint xforms_ubo_id;
GLuint model_xform_id;
u32 num_uniforms;
gl_uniform* uniforms;
u32 num_buffers;
gl_buffer* buffers;
char* name;
u64 hash; // NOTE: hash of vs filpath + fs filepath concat
};
// TODO: is it a good idea to merge this into GLContext?
struct ShaderArray
{
u32 count;
u32 max;
shader_program* shaders;
};
struct GLContext
{
gl_buffer xform_ubo;
// TODO: keep an array of uniform buffer objects store on ctx?
GLuint binding_count;
GLint max_binding_points;
ShaderArray* shader_arr;
};
struct transforms
{
glm::mat4 view_xform;
glm::mat4 proj_xform;
glm::mat4 normal_xform;
};
struct gl_mesh
{
u32 num_indices;
GLuint vao_id;
GLuint tex_id;
GLenum draw_mode; // NOTE: GL_LINES, GL_TRIANGLES
GLenum usage; // NOTE: GL_STATIC_DRAW, GL_DYNAMIC_DRAW
shader_program* shader;
glm::mat4* model_xform;
GLuint vert_buf_id;
GLuint norm_buf_id;
GLuint uv_buf_id;
GLuint clr_buf_id;
GLuint idx_buf_id;
};
struct gl_mesh_array
{
u32 count;
u32 max;
gl_mesh* gl_meshes;
};
struct point_light
{
glm::vec3 position;
glm::vec3 color;
u32 intensity;
};
struct light_array
{
u32 count;
point_light* lights;
};
struct RenderState
{
memory_arena* arena;
model_assets* assets;
texture_assets* textures;
transforms* xforms; // NOTE: would be part of camera in libTangerine
GLContext* gl_ctx;
gl_mesh_array* gl_mesh_arr;
light_array lights;
};
struct node;
struct entity;
struct animation;

7530
src/stb_image.h

File diff suppressed because it is too large Load Diff

1621
src/stb_image_write.h

File diff suppressed because it is too large Load Diff

4
src/tiny_gltf.cc

@ -0,0 +1,4 @@
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
#define TINYGLTF_IMPLEMENTATION
#include "tiny_gltf.h"

7760
src/tiny_gltf.h

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save