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