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