api change
[vg.git] / vg_build_utils_shader.h
1 #include "vg.h"
2
3 #ifdef VG_GAME
4 #error !
5 #endif
6
7 #define STB_INCLUDE_IMPLEMENTATION
8 #define STB_INCLUDE_LINE_GLSL
9 #include "submodules/stb/stb_include.h"
10
11 struct
12 {
13 struct uniform
14 {
15 char name[32];
16 char type[20];
17 char uniform_code_id[128];
18
19 int array;
20 }
21 uniform_buffer[100];
22
23 int uniform_count,
24 uniform_uid;
25 char shader_dir[ 256 ];
26 char current_shader_name[ 128 ];
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( FILE *header, 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 fprintf( header, "{\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 fputs( "\"", header );
105 fputs( start, header );
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 fputs( "\"", header );
120 break;
121 }
122
123 fputs( "\\n\"\n", header );
124 start = cur+1;
125 }
126 cur ++;
127 }
128
129 fputs( "},", header );
130 }
131
132 free( full );
133 return 1;
134 }
135
136 int vg_build_shader( char *src_vert, /* path/to/vert.vs */
137 char *src_frag, /* path/to/frag.fs */
138 char *src_geo, /* unused currently */
139 char *dst_h, /* folder where .h go */
140 char *name /* shader name */ )
141 {
142 char path[260];
143
144 strcpy( vg_shaderbuild.current_shader_name, name );
145
146 strcpy( path, dst_h );
147 strcat( path, "/" );
148 strcat( path, name );
149 strcat( path, ".h" );
150
151 printf( "Compiling shader called '%s'\n", name );
152
153 FILE *header = fopen( path, "w" );
154 if( !header )
155 {
156 fprintf(stderr, "Could not open '%s'\n", path );
157 return 0;
158 }
159
160 fprintf( header, "#ifndef SHADER_%s_H\n"
161 "#define SHADER_%s_H\n", name, name );
162 fprintf( header, "static void shader_%s_link(void);\n", name );
163 fprintf( header, "static void shader_%s_register(void);\n", name );
164 fprintf( header, "static struct vg_shader _shader_%s = {\n"
165 " .name = \"%s\",\n"
166 " .link = shader_%s_link,\n"
167 " .vs = \n", name, name, name );
168
169 vg_shaderbuild.uniform_count = 0;
170 if( !compile_subshader(header,src_vert) )
171 {
172 fclose( header );
173 return 0;
174 }
175
176 fprintf( header, "\n .fs = \n" );
177 if( !compile_subshader(header,src_frag) )
178 {
179 fclose( header );
180 return 0;
181 }
182
183 fprintf( header, "\n};\n\n" );
184
185 for( int i=0; i<vg_shaderbuild.uniform_count; i++ )
186 {
187 struct uniform *uf = &vg_shaderbuild.uniform_buffer[i];
188 fprintf( header, "static GLuint %s;\n", uf->uniform_code_id );
189 }
190
191 struct type_info
192 {
193 const char *glsl_type,
194 *args,
195 *gl_call_pattern;
196 }
197 types[] =
198 {
199 { "float", "float f", "glUniform1f(%s,f);" },
200 { "bool", "int b", "glUniform1i(%s,b);" },
201
202 { "vec2", "v2f v", "glUniform2fv(%s,1,v);" },
203 { "vec3", "v3f v", "glUniform3fv(%s,1,v);" },
204 { "vec4", "v4f v", "glUniform4fv(%s,1,v);" },
205
206 { "sampler2D", "int i", "glUniform1i(%s,i);" },
207 { "samplerCube", "int i", "glUniform1i(%s,i);" },
208 { "mat4x3", "m4x3f m", "glUniformMatrix4x3fv(%s,1,GL_FALSE,(float*)m);" },
209 { "mat3", "m3x3f m", "glUniformMatrix3fv(%s,1,GL_FALSE,(float*)m);" },
210 { "mat4", "m4x4f m", "glUniformMatrix4fv(%s,1,GL_FALSE,(float*)m);" },
211 };
212
213 for( int i=0; i<vg_shaderbuild.uniform_count; i++ )
214 {
215 struct uniform *uf = &vg_shaderbuild.uniform_buffer[i];
216 if( uf->array )
217 continue;
218
219 for( int j=0; j<vg_list_size(types); j ++ )
220 {
221 struct type_info *inf = &types[j];
222
223 if( !strcmp( inf->glsl_type, uf->type ) )
224 {
225 fprintf( header, "static void shader_%s_%s(%s){\n",
226 name, uf->name, inf->args );
227 fprintf( header, " " );
228 fprintf( header, inf->gl_call_pattern, uf->uniform_code_id );
229 fprintf( header, "\n}\n" );
230 }
231 }
232 }
233
234 fprintf( header,
235 "static void shader_%s_register(void){\n"
236 " vg_shader_register( &_shader_%s );\n"
237 "}\n",
238 name,name );
239
240 fprintf( header,
241 "static void shader_%s_use(void){ glUseProgram(_shader_%s.id); }\n",
242 name, name );
243
244 fprintf( header,
245 "static void shader_%s_link(void){\n",
246 name );
247
248 for( int i=0; i<vg_shaderbuild.uniform_count; i++ )
249 {
250 struct uniform *uf = &vg_shaderbuild.uniform_buffer[i];
251 fprintf( header,
252 " _uniform_%s_%s = "
253 "glGetUniformLocation( _shader_%s.id, \"%s\" );\n",
254 name, uf->name,
255 name, uf->name );
256 }
257
258 fprintf( header, "}\n" );
259 fprintf( header, "#endif /* SHADER_%s_H */\n", name );
260 fclose( header );
261
262 return 1;
263 }