5 changed files with 441 additions and 391 deletions
@ -0,0 +1,262 @@
|
||||
|
||||
#include <cassert> |
||||
#include <cstddef> |
||||
#include <cstdlib> |
||||
#include <cstring> |
||||
#include <string> |
||||
#include <fstream> |
||||
#include <iostream> |
||||
|
||||
#include <glm/gtc/matrix_transform.hpp> |
||||
|
||||
#include "asset.h" |
||||
#include "shader.h" |
||||
|
||||
#include "dumpShader.inl" |
||||
|
||||
|
||||
// NOTE: forward declarations
|
||||
|
||||
const std::string dumpTextFile(const char* filepath); |
||||
void |
||||
parseShaderUniforms(memory_arena* arena, shader_program* s, GLContext* gl_ctx); |
||||
|
||||
|
||||
// NOTE: interface
|
||||
|
||||
// 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; |
||||
} |
||||
|
||||
void |
||||
renderVAO(gl_mesh* glmesh) |
||||
{ |
||||
glUseProgram(glmesh->shader->prog_id); |
||||
glBindVertexArray(glmesh->vao_id); |
||||
glUniformMatrix4fv(glmesh->shader->model_xform_id, 1, GL_FALSE, |
||||
(float*) glmesh->model_xform); |
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, glmesh->idx_buf_id); |
||||
glDrawElements( |
||||
glmesh->draw_mode, glmesh->num_indices, GL_UNSIGNED_INT, 0); |
||||
glBindVertexArray(0); |
||||
} |
||||
|
||||
|
||||
// NOTE: internal
|
||||
|
||||
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, |
||||
float near_clip_plane, |
||||
float aspect_ratio, |
||||
glm::vec3 cam_pos, |
||||
glm::vec3 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; |
||||
} |
||||
|
||||
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; |
||||
} |
||||
|
||||
Loading…
Reference in new issue