summaryrefslogtreecommitdiff
path: root/gfx/src/core/shader.c
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/src/core/shader.c')
-rw-r--r--gfx/src/core/shader.c92
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
12static 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
23static 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.
38static 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
79bool gfx_compile_shader(Shader* shader, const ShaderDesc* desc) {
80 shader->id = create_shader(desc);
81 return shader->id != 0;
82}
83
84void 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}