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