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