cb4cc4b8894ef5f488f1e0430a4007ea470b9458
[vg.git] / vg_build_utils_shader.h
1 #define STB_INCLUDE_IMPLEMENTATION
2 #define STB_INCLUDE_LINE_GLSL
3 #include "submodules/stb/stb_include.h"
4
5 struct
6 {
7 struct uniform
8 {
9 char name[32];
10 char type[20];
11 char uniform_code_id[128];
12
13 int array;
14 }
15 uniform_buffer[100];
16
17 int uniform_count,
18 uniform_uid;
19 char shader_dir[ 256 ];
20 char current_shader_name[ 128 ];
21
22 vg_str code_register,
23 code_link,
24 code_function_body;
25
26 bool init;
27 }
28 static vg_shaderbuild;
29
30 static void vg_shader_set_include_dir( char *dir )
31 {
32 strcpy( vg_shaderbuild.shader_dir, dir );
33 }
34
35 static void parse_uniform_name( char *start, struct uniform *uf )
36 {
37 uf->array = 0;
38 int type_set = 0;
39
40 for( int i=0;; i++ )
41 {
42 if( start[i] == '\0' )
43 break;
44
45 if( start[i] == ';' )
46 {
47 start[i] = '\0';
48 vg_strncpy( start, uf->name, sizeof(uf->name),
49 k_strncpy_always_add_null );
50 }
51
52 if( start[i] == '[' )
53 {
54 start[i] = '\0';
55 vg_strncpy( start, uf->name, sizeof(uf->name),
56 k_strncpy_always_add_null );
57 uf->array = 1;
58 }
59
60 if( start[i] == ' ' )
61 {
62 start[i] = '\0';
63
64 if( !type_set )
65 {
66 vg_strncpy( start, uf->type, sizeof(uf->type),
67 k_strncpy_always_add_null );
68 type_set = 1;
69 }
70 start = start+i+1;
71 i=0;
72 }
73 }
74
75 snprintf( uf->uniform_code_id, 64, "_uniform_%s_%s",
76 vg_shaderbuild.current_shader_name,
77 uf->name );
78 }
79
80 static int compile_subshader( vg_str *str, char *name )
81 {
82 char error[256];
83 char *full = stb_include_file( name, "", vg_shaderbuild.shader_dir, error );
84
85 if( !full )
86 {
87 fprintf( stderr, "stb_include_file error:\n%s\n", error );
88 return 0;
89 }
90 else
91 {
92 vg_strcatf( str, "{\n"
93 ".orig_file = \"%s\",\n"
94 ".static_src = \n",
95 name );
96
97 char *cur = full, *start = full;
98 while( 1 )
99 {
100 char c = *cur;
101 if( c == '\n' || c == '\0' )
102 {
103 *cur = '\0';
104 vg_strcatf( str, "\"" );
105 vg_strcatf( str, start );
106
107 if( !strncmp(start,"uniform",7) )
108 {
109 start += 8;
110 struct uniform *uf =
111 &vg_shaderbuild.uniform_buffer[
112 vg_shaderbuild.uniform_count ++ ];
113
114 parse_uniform_name( start, uf );
115 }
116
117 if( c == '\0' )
118 {
119 vg_strcatf( str, "\"" );
120 break;
121 }
122
123 vg_strcatf( str, "\\n\"\n" );
124 start = cur+1;
125 }
126 cur ++;
127 }
128
129 vg_strcatf( str, "}," );
130 }
131
132 free( full );
133 return 1;
134 }
135
136 void vg_build_shader_impl( char *path )
137 {
138 FILE *fp = fopen( path, "w" );
139 fputs( vg_shaderbuild.code_function_body.buffer, fp );
140 fputs( "\n\n", fp );
141
142 fputs( "void vg_auto_shader_link(void)\n{\n", fp );
143 fputs( vg_shaderbuild.code_link.buffer, fp );
144 fputs( "}\n\n", fp );
145
146 fputs( "void vg_auto_shader_register(void)\n{\n", fp );
147 fputs( vg_shaderbuild.code_register.buffer, fp );
148 fputs( "}\n\n", fp );
149
150 fclose( fp );
151 }
152
153 int vg_build_shader( char *src_vert, /* path/to/vert.vs */
154 char *src_frag, /* path/to/frag.fs */
155 char *src_geo, /* unused currently */
156 char *dst_h, /* folder where .h go */
157 char *name /* shader name */ )
158 {
159 if( !vg_shaderbuild.init )
160 {
161 vg_strnull( &vg_shaderbuild.code_link, NULL, -1 );
162 vg_strnull( &vg_shaderbuild.code_register, NULL, -1 );
163 vg_strnull( &vg_shaderbuild.code_function_body, NULL, -1 );
164 vg_shaderbuild.init = 1;
165 }
166
167 vg_str *c_link = &vg_shaderbuild.code_link,
168 *c_reg = &vg_shaderbuild.code_register,
169 *c_body = &vg_shaderbuild.code_function_body;
170
171 char path_header[260];
172
173 strcpy( vg_shaderbuild.current_shader_name, name );
174 strcpy( path_header, dst_h );
175 strcat( path_header, "/" );
176 strcat( path_header, name );
177 strcat( path_header, ".h" );
178
179 vg_low( "Compiling shader called '%s'\r", name );
180
181 FILE *header = fopen( path_header, "w" );
182 if( !header )
183 {
184 fprintf(stderr, "Could not open '%s'\n", path_header );
185 return 0;
186 }
187
188 fprintf( header, "#pragma once\n" );
189 fprintf( header, "#include \"vg/vg_engine.h\"\n" );
190 vg_strcatf( c_body, "#include \"%s\"\n", path_header );
191 fprintf( header, "extern struct vg_shader _shader_%s;\n", name );
192 vg_strcatf( c_body, "struct vg_shader _shader_%s = {\n"
193 " .name = \"%s\",\n"
194 " .vs = \n", name, name, name );
195
196 vg_shaderbuild.uniform_count = 0;
197 if( !compile_subshader( c_body, src_vert ) )
198 {
199 fclose( header );
200 return 0;
201 }
202
203 vg_strcatf( c_body, "\n .fs = \n" );
204 if( !compile_subshader( c_body, src_frag ) )
205 {
206 fclose( header );
207 return 0;
208 }
209
210 vg_strcatf( c_body, "\n};\n\n" );
211
212 for( int i=0; i<vg_shaderbuild.uniform_count; i++ )
213 {
214 struct uniform *uf = &vg_shaderbuild.uniform_buffer[i];
215 fprintf( header, "extern GLuint %s;\n", uf->uniform_code_id );
216 vg_strcatf( c_body, "GLuint %s;\n", uf->uniform_code_id );
217 }
218
219 struct type_info
220 {
221 const char *glsl_type,
222 *args,
223 *gl_call_pattern;
224 }
225 types[] =
226 {
227 { "float", "f32 f", "glUniform1f(%s,f);" },
228 { "bool", "int b", "glUniform1i(%s,b);" },
229 { "vec2", "v2f v", "glUniform2fv(%s,1,v);" },
230 { "vec3", "v3f v", "glUniform3fv(%s,1,v);" },
231 { "vec4", "v4f v", "glUniform4fv(%s,1,v);" },
232 { "sampler2D", "int i", "glUniform1i(%s,i);" },
233 { "samplerCube", "int i", "glUniform1i(%s,i);" },
234 { "mat2", "m2x2f m", "glUniformMatrix2fv(%s,1,GL_FALSE,(f32*)m);" },
235 { "mat4x3", "m4x3f m", "glUniformMatrix4x3fv(%s,1,GL_FALSE,(f32*)m);" },
236 { "mat3", "m3x3f m", "glUniformMatrix3fv(%s,1,GL_FALSE,(f32*)m);" },
237 { "mat4", "m4x4f m", "glUniformMatrix4fv(%s,1,GL_FALSE,(f32*)m);" },
238 };
239
240 for( int i=0; i<vg_shaderbuild.uniform_count; i++ )
241 {
242 struct uniform *uf = &vg_shaderbuild.uniform_buffer[i];
243 if( uf->array )
244 continue;
245
246 for( int j=0; j<vg_list_size(types); j ++ )
247 {
248 struct type_info *inf = &types[j];
249
250 if( !strcmp( inf->glsl_type, uf->type ) )
251 {
252 fprintf( header, "static inline void shader_%s_%s(%s)\n{\n",
253 name, uf->name, inf->args );
254 fprintf( header, " " );
255 fprintf( header, inf->gl_call_pattern, uf->uniform_code_id );
256 fprintf( header, "\n}\n" );
257 }
258 }
259 }
260
261 vg_strcatf( c_reg, " vg_shader_register( &_shader_%s );\n", name );
262 fprintf( header, "static inline void shader_%s_use(void);\n", name );
263 fprintf( header, "static inline void shader_%s_use(void)\n{\n", name );
264 fprintf( header, " glUseProgram(_shader_%s.id);\n}\n", name );
265
266 for( int i=0; i<vg_shaderbuild.uniform_count; i++ )
267 {
268 struct uniform *uf = &vg_shaderbuild.uniform_buffer[i];
269 vg_strcatf( c_link,
270 " _uniform_%s_%s = "
271 "glGetUniformLocation( _shader_%s.id, \"%s\" );\n",
272 name, uf->name,
273 name, uf->name );
274 }
275
276 fclose( header );
277 return 1;
278 }