diff options
Diffstat (limited to 'gfx/src/core/shader.c')
-rw-r--r-- | gfx/src/core/shader.c | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/gfx/src/core/shader.c b/gfx/src/core/shader.c new file mode 100644 index 0000000..af2f89f --- /dev/null +++ b/gfx/src/core/shader.c | |||
@@ -0,0 +1,92 @@ | |||
1 | #include "shader.h" | ||
2 | |||
3 | #include "gl_util.h" | ||
4 | #include <gfx_assert.h> | ||
5 | |||
6 | #include <cstring.h> | ||
7 | #include <log/log.h> | ||
8 | |||
9 | #include <stdlib.h> | ||
10 | #include <string.h> | ||
11 | |||
12 | static GLenum shader_type_to_gl(ShaderType type) { | ||
13 | switch (type) { | ||
14 | case VertexShader: | ||
15 | return GL_VERTEX_SHADER; | ||
16 | case FragmentShader: | ||
17 | return GL_FRAGMENT_SHADER; | ||
18 | } | ||
19 | FAIL("shader_type_to_gl(): missing case"); | ||
20 | return GL_INVALID_ENUM; | ||
21 | } | ||
22 | |||
23 | static lstring make_defines_string(const ShaderDesc* desc) { | ||
24 | lstring defines = {0}; | ||
25 | for (size_t i = 0; i < desc->num_defines; ++i) { | ||
26 | const ShaderCompilerDefine* define = &desc->defines[i]; | ||
27 | lstring_append_cstr(&defines, "#define "); | ||
28 | lstring_append_cstr(&defines, sstring_cstr(&define->name)); | ||
29 | lstring_append_cstr(&defines, " "); | ||
30 | lstring_append_cstr(&defines, sstring_cstr(&define->value)); | ||
31 | lstring_append_cstr(&defines, "\n"); | ||
32 | } | ||
33 | return defines; | ||
34 | } | ||
35 | |||
36 | /// Creates an OpenGL shader. | ||
37 | /// Returns non-zero on success, 0 on failure. | ||
38 | static GLuint create_shader(const ShaderDesc* desc) { | ||
39 | const GLuint shader = glCreateShader(shader_type_to_gl(desc->type)); | ||
40 | if (!shader) { | ||
41 | return 0; | ||
42 | } | ||
43 | |||
44 | #if GFX_GL_CONTEXT == GFX_GL_CONTEXT_ES | ||
45 | const char* header = "#version 300 es\n\nprecision highp float;"; | ||
46 | #else | ||
47 | const char* header = "#version 400 core\n\n"; | ||
48 | #endif | ||
49 | |||
50 | lstring defines = make_defines_string(desc); | ||
51 | |||
52 | const char* source_bits[] = {header, lstring_cstr(&defines), desc->code}; | ||
53 | const GLint source_lengths[] = { | ||
54 | strlen(header), lstring_length(defines), strlen(desc->code)}; | ||
55 | |||
56 | glShaderSource(shader, 3, source_bits, source_lengths); | ||
57 | glCompileShader(shader); | ||
58 | GLint result; | ||
59 | glGetShaderiv(shader, GL_COMPILE_STATUS, &result); | ||
60 | if (result == GL_FALSE) { | ||
61 | GLint log_len; | ||
62 | glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_len); | ||
63 | if (log_len > 0) { | ||
64 | char* log = calloc(log_len, sizeof(char)); | ||
65 | glGetShaderInfoLog(shader, log_len, NULL, log); | ||
66 | static const char* sep = "----------"; | ||
67 | LOGE("Failed loading shader: %s\n%s\n%s\n%s", log, sep, desc->code, sep); | ||
68 | free(log); | ||
69 | } else { | ||
70 | LOGE("Failed loading shader:\n%s", desc->code); | ||
71 | } | ||
72 | glDeleteShader(shader); | ||
73 | return 0; | ||
74 | } | ||
75 | ASSERT_GL; | ||
76 | return shader; | ||
77 | } | ||
78 | |||
79 | bool gfx_compile_shader(Shader* shader, const ShaderDesc* desc) { | ||
80 | shader->id = create_shader(desc); | ||
81 | return shader->id != 0; | ||
82 | } | ||
83 | |||
84 | void gfx_del_shader(Shader* shader) { | ||
85 | assert(shader); | ||
86 | |||
87 | if (shader->id) { | ||
88 | glDeleteShader(shader->id); | ||
89 | shader->id = 0; | ||
90 | } | ||
91 | ASSERT_GL; | ||
92 | } | ||