|
|
|
@ -19,18 +19,40 @@ |
|
|
|
// NOTE: forward declarations
|
|
|
|
// NOTE: forward declarations
|
|
|
|
|
|
|
|
|
|
|
|
const std::string dumpTextFile(const char* filepath); |
|
|
|
const std::string dumpTextFile(const char* filepath); |
|
|
|
bool |
|
|
|
bool parseShader(memory_arena* arena, GLContext* gl_ctx, shader_program* s); |
|
|
|
parseShaderUniforms(memory_arena* arena, shader_program* s, GLContext* gl_ctx); |
|
|
|
|
|
|
|
bool |
|
|
|
|
|
|
|
parseUniformBlocks(memory_arena* arena, shader_program* s, GLContext* gl_ctx); |
|
|
|
|
|
|
|
bool |
|
|
|
|
|
|
|
parseAttributes(memory_arena* arena, shader_program* s, GLContext* gl_ctx); |
|
|
|
|
|
|
|
void initCTXSizes(GLContext* gl_ctx); |
|
|
|
void initCTXSizes(GLContext* gl_ctx); |
|
|
|
|
|
|
|
bool compileAndLinkShader(shader_program* shader, |
|
|
|
|
|
|
|
const char* vert_src, |
|
|
|
|
|
|
|
const char* frag_src, |
|
|
|
|
|
|
|
GLuint& vs_id, |
|
|
|
|
|
|
|
GLuint& fs_id); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// NOTE: interface
|
|
|
|
// NOTE: interface
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: clean up this function
|
|
|
|
shader_program* |
|
|
|
|
|
|
|
getFreeShader(GLContext* gl_ctx) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (gl_ctx->num_shaders >= gl_ctx->max_shaders) { |
|
|
|
|
|
|
|
printf("%s(), GLContext->shaders full\n", __FUNCTION__); |
|
|
|
|
|
|
|
return nullptr; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
shader_program* s = &gl_ctx->shaders[gl_ctx->num_shaders++]; |
|
|
|
|
|
|
|
return s; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
shader_program* |
|
|
|
|
|
|
|
getShaderByHash(GLContext* gl_ctx, u64 hash) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
for (u32 i; i < gl_ctx->num_shaders; i++) { |
|
|
|
|
|
|
|
if (gl_ctx->shaders[i].hash == hash) |
|
|
|
|
|
|
|
return &gl_ctx->shaders[i]; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return nullptr; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool |
|
|
|
bool |
|
|
|
addShaderProgram(memory_arena* arena, |
|
|
|
addShaderProgram(memory_arena* arena, |
|
|
|
GLContext* gl_ctx, |
|
|
|
GLContext* gl_ctx, |
|
|
|
@ -38,72 +60,45 @@ addShaderProgram(memory_arena* arena, |
|
|
|
const char* fs, |
|
|
|
const char* fs, |
|
|
|
const char* name) |
|
|
|
const char* name) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (gl_ctx->num_shaders >= gl_ctx->max_shaders) { |
|
|
|
// TODO: replace std::string w/ utilAllocCStr() ?
|
|
|
|
printf("%s(), GLContext->shaders full\n", __FUNCTION__); |
|
|
|
std::string hash_str = std::string(vs) + std::string(fs); |
|
|
|
|
|
|
|
const u32 max_len = 256; |
|
|
|
|
|
|
|
u64 hash = utilFNV64a_str(hash_str.substr(0, max_len).c_str()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (getShaderByHash(gl_ctx, hash)) { |
|
|
|
|
|
|
|
printf("%s(), shader is already loaded\n", __FUNCTION__); |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
shader_program* s = &gl_ctx->shaders[gl_ctx->num_shaders]; |
|
|
|
shader_program* s = getFreeShader(gl_ctx); |
|
|
|
gl_ctx->num_shaders++; |
|
|
|
|
|
|
|
s->name = arenaCopyCStr(arena, name); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const u32 max_len = 256; |
|
|
|
if (s) { |
|
|
|
std::string hash_str = vs; |
|
|
|
s->name = arenaCopyCStr(arena, name); |
|
|
|
hash_str += fs; |
|
|
|
s->hash = hash; |
|
|
|
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); |
|
|
|
// TODO: replace std::string w/ utilAllocCStr() ?
|
|
|
|
GLint is_linked = 0; |
|
|
|
std::string vert = dumpTextFile(vs); |
|
|
|
glGetProgramiv(s->prog_id, GL_LINK_STATUS, &is_linked); |
|
|
|
std::string frag = dumpTextFile(fs); |
|
|
|
|
|
|
|
GLuint vs_id, fs_id; |
|
|
|
|
|
|
|
|
|
|
|
if (is_linked) { |
|
|
|
if (compileAndLinkShader(s, vert.c_str(), frag.c_str(), vs_id, fs_id)) { |
|
|
|
// NOTE: need to set context maximums after at least one shader has
|
|
|
|
// NOTE: we call this here because we can only make the GL_MAX*
|
|
|
|
// been linked
|
|
|
|
// queries after at least one shader has been linked
|
|
|
|
initCTXSizes(gl_ctx); |
|
|
|
initCTXSizes(gl_ctx); |
|
|
|
#if 0 |
|
|
|
|
|
|
|
dumpShader(s->prog_id); |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
s->model_xform_id = glGetUniformLocation(s->prog_id, "model_xform"); |
|
|
|
s->model_xform_id = glGetUniformLocation(s->prog_id, "model_xform"); |
|
|
|
glDetachShader(s->prog_id, vs_id); |
|
|
|
glDetachShader(s->prog_id, vs_id); |
|
|
|
glDetachShader(s->prog_id, fs_id); |
|
|
|
glDetachShader(s->prog_id, fs_id); |
|
|
|
glDeleteShader(vs_id); |
|
|
|
glDeleteShader(vs_id); |
|
|
|
glDeleteShader(fs_id); |
|
|
|
glDeleteShader(fs_id); |
|
|
|
|
|
|
|
|
|
|
|
if (parseShaderUniforms(arena, s, gl_ctx) |
|
|
|
return parseShader(arena, gl_ctx, s); |
|
|
|
&& parseUniformBlocks(arena, s, gl_ctx) |
|
|
|
|
|
|
|
&& parseAttributes(arena, s, gl_ctx)) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
printf("%s(), Error parsing shader component\n", __FUNCTION__); |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
printf("%s(), Error linking shader\n", __FUNCTION__); |
|
|
|
printf("%s(), Error linking shader\n", __FUNCTION__); |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
printf("%s(), error loading shader\n", __FUNCTION__); |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -231,8 +226,44 @@ loadGLMesh(shader_program* s, |
|
|
|
return gm; |
|
|
|
return gm; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// NOTE: internal
|
|
|
|
// NOTE: internal
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool |
|
|
|
|
|
|
|
compileAndLinkShader(shader_program* shader, |
|
|
|
|
|
|
|
const char* vert_src, |
|
|
|
|
|
|
|
const char* frag_src, |
|
|
|
|
|
|
|
GLuint& vs_id, |
|
|
|
|
|
|
|
GLuint& fs_id) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (strlen(vert_src) > 0 && strlen(frag_src) > 0) { |
|
|
|
|
|
|
|
vs_id = glCreateShader(GL_VERTEX_SHADER); |
|
|
|
|
|
|
|
fs_id = glCreateShader(GL_FRAGMENT_SHADER); |
|
|
|
|
|
|
|
glShaderSource(vs_id, 1, &vert_src, NULL); |
|
|
|
|
|
|
|
glShaderSource(fs_id, 1, &frag_src, NULL); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: add a glError to string function in GLDebug.h
|
|
|
|
|
|
|
|
glCompileShader(vs_id); |
|
|
|
|
|
|
|
assert(glGetError() == GL_NO_ERROR); |
|
|
|
|
|
|
|
glCompileShader(fs_id); |
|
|
|
|
|
|
|
assert(glGetError() == GL_NO_ERROR); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
shader->prog_id = glCreateProgram(); |
|
|
|
|
|
|
|
glAttachShader(shader->prog_id, vs_id); |
|
|
|
|
|
|
|
glAttachShader(shader->prog_id, fs_id); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
glLinkProgram(shader->prog_id); |
|
|
|
|
|
|
|
GLint is_linked = 0; |
|
|
|
|
|
|
|
glGetProgramiv(shader->prog_id, GL_LINK_STATUS, &is_linked); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return (is_linked == GL_TRUE); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: make another logging macro for printf style logging
|
|
|
|
|
|
|
|
printf("%s(), empty shader source\n", __FUNCTION__); |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const std::string |
|
|
|
const std::string |
|
|
|
dumpTextFile(const char* filepath) |
|
|
|
dumpTextFile(const char* filepath) |
|
|
|
{ |
|
|
|
{ |
|
|
|
@ -412,3 +443,17 @@ parseAttributes(memory_arena* arena, shader_program* s, GLContext* gl_ctx) |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool |
|
|
|
|
|
|
|
parseShader(memory_arena* arena, GLContext* gl_ctx, shader_program* s) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (parseShaderUniforms(arena, s, gl_ctx) |
|
|
|
|
|
|
|
&& parseUniformBlocks(arena, s, gl_ctx) |
|
|
|
|
|
|
|
&& parseAttributes(arena, s, gl_ctx)) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
printf("%s(), Error parsing shader\n", __FUNCTION__); |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|