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