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