#include "shader.h" #include "gl_util.h" #include #include #include #include #include static GLenum shader_type_to_gl(ShaderType type) { switch (type) { case VertexShader: return GL_VERTEX_SHADER; case FragmentShader: return GL_FRAGMENT_SHADER; } FAIL("shader_type_to_gl(): missing case"); return GL_INVALID_ENUM; } static lstring make_defines_string(const ShaderDesc* desc) { lstring defines = {0}; for (size_t i = 0; i < desc->num_defines; ++i) { const ShaderCompilerDefine* define = &desc->defines[i]; lstring_append_cstr(&defines, "#define "); lstring_append_cstr(&defines, sstring_cstr(&define->name)); lstring_append_cstr(&defines, " "); lstring_append_cstr(&defines, sstring_cstr(&define->value)); lstring_append_cstr(&defines, "\n"); } return defines; } /// Creates an OpenGL shader. /// Returns non-zero on success, 0 on failure. static GLuint create_shader(const ShaderDesc* desc) { const GLuint shader = glCreateShader(shader_type_to_gl(desc->type)); if (!shader) { return 0; } #if GFX_GL_CONTEXT == GFX_GL_CONTEXT_ES const char* header = "#version 300 es\n\nprecision highp float;"; #else const char* header = "#version 400 core\n\n"; #endif lstring defines = make_defines_string(desc); const char* source_bits[] = {header, lstring_cstr(&defines), desc->code}; const GLint source_lengths[] = { strlen(header), lstring_length(&defines), strlen(desc->code)}; glShaderSource(shader, 3, source_bits, source_lengths); glCompileShader(shader); GLint result; glGetShaderiv(shader, GL_COMPILE_STATUS, &result); if (result == GL_FALSE) { GLint log_len; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_len); if (log_len > 0) { char* log = calloc(log_len, sizeof(char)); glGetShaderInfoLog(shader, log_len, NULL, log); static const char* sep = "----------"; LOGE("Failed loading shader: %s\n%s\n%s\n%s", log, sep, desc->code, sep); free(log); } else { LOGE("Failed loading shader:\n%s", desc->code); } glDeleteShader(shader); return 0; } ASSERT_GL; return shader; } bool gfx_compile_shader(Shader* shader, const ShaderDesc* desc) { shader->id = create_shader(desc); return shader->id != 0; } void gfx_del_shader(Shader* shader) { assert(shader); if (shader->id) { glDeleteShader(shader->id); shader->id = 0; } ASSERT_GL; }