50e8bd0e291589a17d32b17fe1c11f0038e9234e
[vg.git] / vg_shader.h
1 /* Copyright (C) 2021-2022 Harry Godden (hgn) - All Rights Reserved */
2
3 #ifndef VG_SHADER_H
4 #define VG_SHADER_H
5
6 #define VG_GAME
7 #include "vg/vg.h"
8 #include "vg/vg_platform.h"
9
10 #define STB_INCLUDE_IMPLEMENTATION
11 #define STB_INCLUDE_LINE_GLSL
12 #define STB_MALLOC vg_alloc
13 #define STB_FREE vg_free
14 #define STB_REALLOC vg_realloc
15 #include "submodules/stb/stb_include.h"
16
17 const char *vg_shader_gl_ver = "#version 330 core\n";
18
19 typedef struct vg_shader vg_shader;
20
21 struct
22 {
23 struct vg_shader
24 {
25 GLuint id;
26 const char *name;
27
28 struct vg_subshader
29 {
30 const char *orig_file,
31 *static_src;
32 }
33 vs, fs;
34
35 void (*link)(void);
36 int compiled;
37 }
38 * shaders[32];
39 u32 count;
40 }
41 static vg_shaders;
42
43 VG_STATIC GLuint vg_shader_subshader( const char *src, GLint gliShaderType )
44 {
45 GLint shader = glCreateShader( gliShaderType );
46
47 if( shader == GL_NONE )
48 {
49 vg_error( "Could not 'glCreateShader()'\n" );
50 return 0;
51 }
52
53 glShaderSource( shader, 2, (const char*[2]){ vg_shader_gl_ver, src }, NULL );
54 glCompileShader( shader );
55
56 GLint status;
57 glGetShaderiv( shader, GL_COMPILE_STATUS, &status );
58
59 if( status != GL_TRUE )
60 {
61 GLchar info[1024];
62 GLsizei len;
63
64 glGetShaderInfoLog( shader, sizeof(info), &len, info );
65 vg_error( "Error info:\n%s\n", info );
66 return 0;
67 }
68
69 return shader;
70 }
71
72 VG_STATIC int vg_shader_compile( struct vg_shader *shader )
73 {
74 GLuint program, vert, frag;
75
76 /* If we are compiling this again, we obviously need to try to take the src
77 * from the disk instead.
78 *
79 * Only do this if we have filenames set on the shader, so engine shaders
80 * dont have to do it (text.. etc).
81 */
82
83 int use_source_files = 0;
84 if( shader->compiled )
85 {
86 if( shader->vs.orig_file && shader->fs.orig_file )
87 {
88 use_source_files = 1;
89 }
90 else
91 {
92 vg_warn( "No source files for shader '%s'\n", shader->name );
93 return 1;
94 }
95 }
96
97 vg_info( "Compile shader '%s'\n", shader->name );
98
99 if( use_source_files )
100 {
101 char error[260];
102 char path[260];
103
104 strcpy( path, "../../" );
105 strcat( path, shader->vs.orig_file );
106 char *vertex_src = stb_include_file( path, "", "../../shaders", error );
107
108 strcpy( path, "../../" );
109 strcat( path, shader->fs.orig_file );
110 char *fragment_src = stb_include_file( path, "", "../../shaders", error );
111
112 if( !vertex_src || !fragment_src )
113 {
114 vg_error( "Could not find shader source files (%s)\n",
115 shader->vs.orig_file );
116
117 free( vertex_src );
118 free( fragment_src );
119 return 0;
120 }
121
122 vert = vg_shader_subshader( vertex_src, GL_VERTEX_SHADER );
123 frag = vg_shader_subshader( fragment_src, GL_FRAGMENT_SHADER );
124
125 free( vertex_src );
126 free( fragment_src );
127 }
128 else
129 {
130 vert = vg_shader_subshader( shader->vs.static_src, GL_VERTEX_SHADER );
131 frag = vg_shader_subshader( shader->fs.static_src, GL_FRAGMENT_SHADER );
132 }
133
134 if( !vert || !frag )
135 return 0;
136
137 program = glCreateProgram();
138
139 glAttachShader( program, vert );
140 glAttachShader( program, frag );
141 glLinkProgram( program );
142
143 glDeleteShader( vert );
144 glDeleteShader( frag );
145
146 /* Check for link errors */
147 char infoLog[ 512 ];
148 int success_link = 1;
149
150 glGetProgramiv( program, GL_LINK_STATUS, &success_link );
151 if( !success_link )
152 {
153 glGetProgramInfoLog( program, 512, NULL, infoLog );
154 vg_error( "Link failed: %s\n", infoLog );
155 glDeleteProgram( program );
156 return 0;
157 }
158
159 if( shader->compiled )
160 glDeleteProgram( shader->id );
161
162 shader->id = program;
163 shader->compiled = 1;
164 if( shader->link )
165 shader->link();
166 return 1;
167 }
168
169 VG_STATIC void vg_free_shader( struct vg_shader *shader )
170 {
171 if( shader->compiled )
172 {
173 glDeleteProgram( shader->id );
174 shader->compiled = 0;
175 }
176 }
177
178 VG_STATIC void vg_shaders_compile(void)
179 {
180 vg_info( "Compiling shaders\n" );
181
182 for( int i=0; i<vg_shaders.count; i ++ )
183 {
184 vg_shader *shader = vg_shaders.shaders[i];
185
186 if( !vg_shader_compile( shader ) )
187 vg_fatal_exit_loop( "Failed to compile shader" );
188 }
189 }
190
191 VG_STATIC int vg_shaders_live_recompile(int argc, const char *argv[])
192 {
193 vg_info( "Recompiling shaders\n" );
194 for( int i=0; i<vg_shaders.count; i ++ )
195 {
196 struct vg_shader *shader = vg_shaders.shaders[i];
197 vg_shader_compile( shader );
198 }
199
200 return 0;
201 }
202
203 VG_STATIC void vg_shader_register( struct vg_shader *shader )
204 {
205 if( vg_shaders.count == vg_list_size(vg_shaders.shaders) )
206 vg_fatal_exit_loop( "Too many shaders" );
207
208 shader->compiled = 0;
209 shader->id = 0; /* TODO: make this an error shader */
210 vg_shaders.shaders[ vg_shaders.count ++ ] = shader;
211 }
212
213 #endif /* VG_SHADER_H */