various
[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 if( shader->vs.orig_file && shader->fs.orig_file ){
86 use_source_files = 1;
87 }
88 else {
89 vg_warn( "No source files for shader '%s'\n", shader->name );
90 return 1;
91 }
92 }
93
94 vg_info( "Compile shader '%s'\n", shader->name );
95
96 if( use_source_files ){
97 char error[260];
98 char path[260];
99
100 strcpy( path, "../../" );
101 strcat( path, shader->vs.orig_file );
102 char *vertex_src = stb_include_file( path, "", "../../shaders", error );
103
104 strcpy( path, "../../" );
105 strcat( path, shader->fs.orig_file );
106 char *fragment_src = stb_include_file( path, "", "../../shaders", error );
107
108 if( !vertex_src || !fragment_src ){
109 const char *errstr = "Could not find shader source files (%s)\n";
110 if( shader->compiled ){
111 vg_warn( errstr, shader->vs.orig_file );
112 free( vertex_src );
113 free( fragment_src );
114 return 1;
115 }
116 else{
117 vg_error( errstr, shader->vs.orig_file );
118 free( vertex_src );
119 free( fragment_src );
120 return 0;
121 }
122 }
123
124 vert = vg_shader_subshader( vertex_src, GL_VERTEX_SHADER );
125 frag = vg_shader_subshader( fragment_src, GL_FRAGMENT_SHADER );
126
127 free( vertex_src );
128 free( fragment_src );
129 }
130 else{
131 vert = vg_shader_subshader( shader->vs.static_src, GL_VERTEX_SHADER );
132 frag = vg_shader_subshader( shader->fs.static_src, GL_FRAGMENT_SHADER );
133 }
134
135 if( !vert || !frag )
136 return 0;
137
138 program = glCreateProgram();
139
140 glAttachShader( program, vert );
141 glAttachShader( program, frag );
142 glLinkProgram( program );
143
144 glDeleteShader( vert );
145 glDeleteShader( frag );
146
147 /* Check for link errors */
148 char infoLog[ 512 ];
149 int success_link = 1;
150
151 glGetProgramiv( program, GL_LINK_STATUS, &success_link );
152 if( !success_link )
153 {
154 glGetProgramInfoLog( program, 512, NULL, infoLog );
155 vg_error( "Link failed: %s\n", infoLog );
156 glDeleteProgram( program );
157 return 0;
158 }
159
160 if( shader->compiled )
161 glDeleteProgram( shader->id );
162
163 shader->id = program;
164 shader->compiled = 1;
165 if( shader->link )
166 shader->link();
167 return 1;
168 }
169
170 VG_STATIC void vg_free_shader( struct vg_shader *shader )
171 {
172 if( shader->compiled )
173 {
174 glDeleteProgram( shader->id );
175 shader->compiled = 0;
176 }
177 }
178
179 VG_STATIC void vg_shaders_compile(void)
180 {
181 vg_info( "Compiling shaders\n" );
182
183 for( int i=0; i<vg_shaders.count; i ++ ){
184 vg_shader *shader = vg_shaders.shaders[i];
185
186 if( !vg_shader_compile( shader ) )
187 vg_fatal_error( "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_error( "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 */