vg2 port: build script and resource loading
[fishladder.git] / fishladder_resources_vg1.h
1 // TEXTURES
2 // ===========================================================================================================
3
4 typedef struct vg1_tex2d vg1_tex2d;
5 struct vg1_tex2d {
6 const char *path;
7 GLuint name;
8 };
9
10 vg1_tex2d tex_tile_data = { "textures/tileset.qoi" };
11 vg1_tex2d tex_tile_glow = { "textures/lineset.qoi" };
12 vg1_tex2d tex_tile_detail = { "textures/tile_overlays.qoi" };
13 vg1_tex2d tex_tiles_wood = { "textures/tile_wood.qoi" };
14 vg1_tex2d tex_tiles_min = { "textures/tile_minimal.qoi" };
15 vg1_tex2d tex_tiles_lab = { "textures/tile_lab.qoi" };
16 vg1_tex2d tex_ball_noise = { "textures/bnoise.qoi" };
17 vg1_tex2d tex_unkown = { "textures/unkown.qoi" };
18 vg1_tex2d tex_buttons = { "textures/buttons.qoi" };
19 vg1_tex2d tex_sprites = { "textures/autocombine.qoi" };
20
21 vg1_tex2d *texture_list[] = {
22 &tex_tile_detail,
23 &tex_tile_data,
24 &tex_tile_glow,
25 &tex_tiles_wood,
26 &tex_tiles_min,
27 &tex_tiles_lab,
28 &tex_ball_noise,
29 &tex_unkown,
30 &tex_buttons,
31 &tex_sprites
32 };
33
34 #include "sprites_autocombine.h"
35
36 // AUDIO
37 // ===========================================================================================================
38
39 #if 0
40 sfx_vol_control audio_volume_sfx = { .val = 1.0f, .name = "Sound effects" };
41 sfx_vol_control audio_volume_music = { .val = 1.0f, .name = "Music" };
42
43 sfx_system audio_system_sfx =
44 {
45 .vol = 1.f,
46 .ch = 1,
47 .vol_src = &audio_volume_sfx,
48 .name = "sfx"
49 };
50 #endif
51
52 audio_clip audio_tile_mod[] = {
53 { .path="sound/mod_01.ogg" },
54 { .path="sound/mod_02.ogg" },
55 { .path="sound/mod_03.ogg" },
56 { .path="sound/mod_04.ogg" },
57 { .path="sound/mod_05.ogg" },
58 { .path="sound/mod_06.ogg" },
59 };
60
61 audio_clip audio_splitter[] = {
62 { .path="sound/splitter_01.ogg" },
63 };
64
65 audio_clip audio_rolls[] = {
66 { .path="sound/rolling_01.ogg" },
67 { .path="sound/rolling_02.ogg" }
68 };
69
70 audio_clip audio_random[] ={
71 { .path="sound/random_01.ogg" },
72 { .path="sound/random_02.ogg" },
73 { .path="sound/random_03.ogg" },
74 { .path="sound/random_04.ogg" },
75 { .path="sound/random_05.ogg" },
76 { .path="sound/random_06.ogg" },
77 { .path="sound/random_07.ogg" },
78 { .path="sound/random_08.ogg" },
79 };
80
81 audio_clip audio_clicks[] = {
82 { .path="sound/click_a.ogg" },
83 { .path="sound/click_b.ogg" },
84 { .path="sound/click_c.ogg" },
85 };
86
87 audio_clip audio_tones[] = {
88 { .path="sound/y0.ogg" },
89 { .path="sound/y1.ogg" },
90 { .path="sound/y2.ogg" },
91 { .path="sound/y3.ogg" },
92 { .path="sound/y4.ogg" },
93 { .path="sound/y5.ogg" },
94 { .path="sound/y6.ogg" },
95 { .path="sound/y7.ogg" },
96 { .path="sound/y8.ogg" },
97 { .path="sound/win.ogg" },
98 };
99
100 audio_clip audio_music[] = {
101 { .path="sound/mccompt2.ogg" },
102 };
103
104 #if 0
105 static void *load_and_play_bgm( void *_inf )
106 {
107 sfx_set_init( &audio_music, NULL );
108 sfx_set_play( &audio_music, &audio_system_music, 0 );
109 return NULL;
110 }
111 #endif
112
113 #define INIT_AUDIO( X ) audio_clip_loadn( X, vg_list_size(X), NULL );
114
115 static void resource_load_main(void){
116 // Textures // UI
117 for( u32 i=0; i<vg_list_size(texture_list); i ++ ){
118 struct vg1_tex2d *tex = texture_list[i];
119 vg_tex2d_load_qoi_async_file( tex->path, 0, &tex->name );
120 }
121
122 // Audio
123 INIT_AUDIO( audio_tile_mod );
124 INIT_AUDIO( audio_tile_mod );
125 INIT_AUDIO( audio_splitter );
126 INIT_AUDIO( audio_rolls );
127 INIT_AUDIO( audio_random );
128 INIT_AUDIO( audio_clicks );
129 INIT_AUDIO( audio_tones );
130
131 #if 0
132 vg_thread_run( load_and_play_bgm, NULL );
133 #endif
134 }
135
136 // SHADERS
137 // ===========================================================================================================
138
139 SHADER_DEFINE( shader_tile_colour,
140
141 // VERTEX
142 "layout (location=0) in vec2 a_co;"
143 "uniform mat3 uPv;"
144 "uniform vec3 uOffset;"
145 ""
146 "void main()"
147 "{"
148 "gl_Position = vec4( uPv * vec3( a_co * uOffset.z + uOffset.xy, 1.0 ), 1.0 );"
149 "}",
150
151 // FRAGMENT
152 "out vec4 FragColor;"
153 "uniform vec4 uColour;"
154 ""
155 "void main()"
156 "{"
157 "FragColor = uColour;"
158 "}"
159 ,
160 UNIFORMS({ "uPv", "uOffset", "uColour" })
161 )
162
163 SHADER_DEFINE( shader_ball,
164 // VERTEX
165 "layout (location=0) in vec2 a_co;"
166 "uniform vec3 uOffset;"
167 "uniform mat3 uPv;"
168 ""
169 "out vec4 aTexCoords;"
170 ""
171 "void main()"
172 "{"
173 // Vertex transform
174 "vec3 worldpos = vec3( (a_co * 0.5 - 0.25) * uOffset.z + uOffset.xy, 1.0 );"
175 "gl_Position = vec4( uPv * worldpos, 1.0 );"
176
177 // Create texture coords
178 "aTexCoords = vec4( a_co, worldpos.xy );"
179 "}",
180
181 // FRAGMENT
182 "out vec4 FragColor;"
183 ""
184 "uniform sampler2D uTexMain;"
185 "uniform vec3 uColour;"
186 "uniform vec2 uTexOffset;"
187 ""
188 "in vec4 aTexCoords;"
189 ""
190 "void main()"
191 "{"
192 "vec2 center_coords = aTexCoords.xy - 0.5;"
193 "vec2 center_coords_sqr = center_coords*center_coords;"
194 "float circle_factor = smoothstep( 0.07, 0.0625, center_coords_sqr.x+center_coords_sqr.y );"
195
196 "float bulge_amt = center_coords_sqr.x+center_coords_sqr.y;"
197 "vec2 warped_coords = aTexCoords.zw+uTexOffset - center_coords;"
198 "vec4 noise_sample = texture( uTexMain, warped_coords );"
199
200 "float rim_light = (center_coords_sqr.x+center_coords_sqr.y)*15.0;"
201
202 "vec2 shadow_coords = center_coords + vec2(0.02,0.07);"
203 "vec2 shadow_coords_sqr = shadow_coords*shadow_coords;"
204 "float shadow = exp(-((shadow_coords_sqr.x+shadow_coords_sqr.y)-0.0125)*15.0);"
205
206 "vec3 marble_comp = uColour*0.6 + (noise_sample.x*2.7+pow(rim_light,3.0)*2.0) * 0.1;"
207 //"vec4 colour_comp = mix( vec4(0.74,0.53,0.34,shadow), vec4(marble_comp,1.0), circle_factor );"
208 "vec4 colour_comp = mix( vec4(0.0,0.0,0.0,shadow), vec4(marble_comp,1.0), circle_factor );"
209
210 "FragColor = colour_comp;"
211 "}"
212 ,
213 UNIFORMS({ "uTexMain", "uColour", "uOffset", "uPv", "uTexOffset" })
214 )
215
216 SHADER_DEFINE( shader_tile_main,
217 // VERTEX
218 "layout (location=0) in vec2 a_co;"
219 "uniform vec4 uOffset;" // Tile x/y, uv x/y
220 "uniform mat3 uPv;"
221 "uniform mat2 uSubTransform;"
222 "uniform float uVisibility;"
223 ""
224 "out vec4 aTexCoords;"
225 "out vec2 aWorldCoords;"
226 ""
227 "vec2 hash22(vec2 p)"
228 "{"
229 "vec3 p3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973));"
230 "p3 += dot(p3, p3.yzx+33.33);"
231 "return fract((p3.xx+p3.yz)*p3.zy);"
232 "}"
233 ""
234 "void main()"
235 "{"
236 "vec2 hash_val = hash22(uOffset.xy);"
237 "float scaling_factor = smoothstep( hash_val.x, hash_val.x+1.0, uVisibility );"
238
239 // Vertex transform
240 "vec2 subtransform = uSubTransform * (a_co-0.5) * scaling_factor + 0.5;"
241 "vec3 worldpos = vec3( subtransform + uOffset.xy, 1.0 );"
242 "gl_Position = vec4( uPv * worldpos, 1.0 );"
243
244 // Create texture coords
245 "vec2 random_offset = floor(hash_val * 4.0) * 0.25;"
246 "vec2 edge_safe_coords = a_co * 0.98 + 0.01;"
247 "aTexCoords = vec4((edge_safe_coords + uOffset.zw) * 0.25, edge_safe_coords * 0.25 + random_offset );"
248 "aWorldCoords = worldpos.xy;"
249 "}",
250
251 // FRAGMENT
252 "out vec4 FragColor;"
253 ""
254 "uniform sampler2D uTexGlyphs;"
255 "uniform sampler2D uTexGlow;"
256 "uniform sampler2D uTexWood;"
257 "uniform float uGhost;"
258 "uniform float uForeground;"
259 "uniform vec2 uMousePos;"
260 "uniform vec4 uColour;"
261 "uniform vec3 uShadowing;"
262 "uniform vec3 uGlowA;"
263 "uniform vec3 uGlowB;"
264 ""
265 "in vec4 aTexCoords;"
266 "in vec2 aWorldCoords;"
267 ""
268 "void main()"
269 "{"
270 //"vec3 shadowing_colour = vec3( 0.93, 0.88536, 0.8184 ) * 0.97;"
271 //"vec3 shadowing_colour = vec3( 0.8, 0.8, 0.8 );"
272
273 "vec4 glyph = texture( uTexGlyphs, aTexCoords.xy );"
274 "vec4 glyph_glow = texture( uTexGlow, aTexCoords.xy );"
275 "vec4 wood = texture( uTexWood, aTexCoords.zw );"
276 "vec4 wood_secondary = texture( uTexWood, aTexCoords.zw + 0.25 );"
277 "vec3 wood_comp = mix( wood_secondary.rgb * uShadowing, wood.rgb, clamp( glyph.b*2.0-1.0, 0.0, 1.0 ) );"
278
279 //"vec3 shadows = mix( vec3( 0.85, 0.7344, 0.561 ), vec3(1.0,1.0,1.0), glyph.r );"
280 "vec3 shadows = mix( uShadowing, vec3(1.0,1.0,1.0), glyph.r );"
281
282 "vec4 output_regular = vec4( wood_comp * shadows, mix( glyph.a, glyph.b, uForeground ) );"
283
284 "float ghost_dist = clamp( 1.5 - distance(uMousePos, aWorldCoords), 0.0, 1.0 );"
285 "vec4 output_ghost = vec4( 1.0, 1.0, 1.0, glyph.g*ghost_dist );"
286 "vec4 glow_comp = vec4(glyph_glow.b*uGlowA+glyph_glow.g*uGlowB,0.0);"
287
288 "FragColor = mix( output_regular, output_ghost, uGhost )*uColour + glow_comp;"
289 "}"
290 ,
291 UNIFORMS({ "uPv", "uOffset", "uTexGlyphs", "uTexWood", "uSubTransform", "uGhost", "uMousePos",
292 "uColour", "uForeground", "uVisibility", "uShadowing", "uTexGlow",
293 "uGlowA", "uGlowB" })
294 )
295
296 SHADER_DEFINE( shader_background,
297 // VERTEX
298 "layout (location=0) in vec2 a_co;"
299 "uniform mat3 uPv;"
300 "uniform vec3 uOffset;"
301 ""
302 "out vec2 aTexCoords;"
303 ""
304 "void main()"
305 "{"
306 "vec2 world_pos = a_co * uOffset.z + uOffset.xy;"
307 "gl_Position = vec4( uPv * vec3( world_pos, 1.0 ), 1.0 );"
308 "aTexCoords = a_co;"
309 "}",
310
311 // FRAGMENT
312 "out vec4 FragColor;"
313 ""
314 "uniform sampler2D uTexMain;"
315 "uniform sampler2D uSamplerNoise;"
316 "uniform float uVariance;"
317 "uniform float uVisibility;"
318 ""
319 "in vec2 aTexCoords;"
320 ""
321 "void main()"
322 "{"
323 "vec4 data_this_tile = texture( uTexMain, aTexCoords );"
324
325 "float ao_accum = 0.0;"
326
327 "vec2 random_noise;"
328
329 "for( int i=0; i<10; ++i )"
330 "{"
331 "random_noise = (texture( uSamplerNoise, aTexCoords * 10.0 + float(i) * 0.2 ).xy - vec2( 0.5, 0.5 )) * uVariance;"
332 "vec4 background = texture( uTexMain, aTexCoords + random_noise );"
333 "float height_diff = min(data_this_tile.r - background.r,0.0);"
334
335 "ao_accum += height_diff * clamp((1.0 - length( random_noise )), 0.0, 1.0);"
336 "}"
337 "ao_accum *= 0.15;"
338
339 #if 0
340 "vec3 colour_main = mix( vec3( 0.369768, 0.3654, 0.42 ), vec3( 0.275, 0.388, 0.553 ), data_this_tile.g * uVisibility );"
341 #endif
342
343 "vec2 square_coords = fract( aTexCoords * 64.0 );"
344 "vec2 grid_coords = abs( square_coords - 0.5 );"
345 "float gridline = step( 0.49, max(grid_coords.x,grid_coords.y) );"
346
347 "vec3 colour_main = mix( vec3( 0.14 ) + random_noise.x*0.5, vec3( 0.1 ) + gridline*0.02, data_this_tile.g * uVisibility );"
348 "FragColor = vec4( colour_main + ao_accum*0.05, 1.0 );"
349 "}"
350 ,
351 UNIFORMS({ "uPv", "uOffset", "uTexMain", "uVariance", "uSamplerNoise", "uVisibility" })
352 )
353
354 SHADER_DEFINE( shader_wire,
355 // VERTEX
356 "layout (location=0) in vec2 a_co;"
357 "uniform vec3 uStart;"
358 "uniform vec3 uEnd;"
359 "uniform mat3 uPv;"
360 "uniform float uCurve;"
361 ""
362 "out vec2 aTexCoords;"
363 ""
364 "vec3 sample_curve_time( float t )"
365 "{"
366 "vec3 line_coord = mix( uStart, uEnd, t );"
367
368 "float curve_amt = 1.0-(pow((t*2.0-1.0),2.0));"
369 "return vec3( line_coord.x, line_coord.y - curve_amt*uCurve, line_coord.z );"
370 "}"
371 ""
372 "void main()"
373 "{"
374 // Vertex transform
375 "vec3 p0 = sample_curve_time( a_co.x );"
376 "vec3 p1 = sample_curve_time( a_co.x + 0.025 );"
377
378 "vec2 line_tangent = normalize(p1.xy-p0.xy);"
379 "vec2 line_normal = vec2( -line_tangent.y, line_tangent.x );"
380
381 "vec2 worldfinal = p0.xy + line_normal*a_co.y*p0.z;"
382
383 "gl_Position = vec4( uPv * vec3(worldfinal, 1.0), 1.0 );"
384
385 // Create texture coords (todo: include stretch adjusted coords?)
386 "aTexCoords = vec2( a_co.x, a_co.y + 0.5 );"
387 "}",
388
389 // FRAGMENT
390 "out vec4 FragColor;"
391 ""
392 "uniform sampler2D uTexMain;"
393 "uniform vec4 uColour;"
394 "uniform float uTime;"
395 "uniform float uGlow;"
396 ""
397 "in vec2 aTexCoords;"
398 ""
399 "void main()"
400 "{"
401 // Compute shadowing
402 "float shadow = 1.0 - abs(aTexCoords.y - 0.5) * 2.0;"
403 "float masking = smoothstep( 0.5, 0.8, shadow );"
404
405 "vec3 colour_comp = mix( vec3(0.0,0.0,0.0), uColour.rgb, masking );"
406
407 "float flow_thing = fract( aTexCoords.x + uTime );"
408 "vec3 final_comp = colour_comp + flow_thing * uGlow;"
409
410 "FragColor = vec4( final_comp, max( shadow* 0.2, masking ) * uColour.a );"
411 "}"
412 ,
413 UNIFORMS({ "uPv", "uColour", "uTexMain", "uStart", "uEnd", "uCurve", "uTime", "uGlow" })
414 )
415
416 SHADER_DEFINE( shader_buttons,
417 // VERTEX
418 "layout (location=0) in vec2 a_co;"
419 "uniform vec4 uOffset;" // Tile x/y, uv x/y
420 "uniform mat3 uPv;"
421 ""
422 "out vec2 aTexCoords;"
423 ""
424 "void main()"
425 "{"
426 // Vertex transform
427 "vec3 worldpos = vec3( a_co + uOffset.xy, 1.0 );"
428 "gl_Position = vec4( uPv * worldpos, 1.0 );"
429
430 // Create texture coords
431 "vec2 edge_safe_coords = a_co * 0.98 + 0.01;"
432 "aTexCoords = (edge_safe_coords + uOffset.zw) * 0.25;"
433 "}",
434
435 // FRAGMENT
436 "out vec4 FragColor;"
437 ""
438 "uniform sampler2D uTexMain;"
439 "uniform vec4 uColour;" // rgb, light amount
440 ""
441 "in vec2 aTexCoords;"
442 ""
443 "void main()"
444 "{"
445 "vec4 glyph = texture( uTexMain, aTexCoords.xy );"
446
447 "FragColor = vec4( uColour.rgb * (mix(glyph.r, glyph.g, uColour.a)+0.02)*2.6 + glyph.b * 0.4, glyph.a );"
448 "}"
449 ,
450 UNIFORMS({ "uPv", "uOffset", "uTexMain", "uColour" })
451 )
452
453 SHADER_DEFINE( shader_sprite,
454
455 // VERTEX
456 "layout (location=0) in vec2 a_co;" // quad mesh
457 "uniform vec4 uUv;"
458 "uniform vec3 uPos;"
459 ""
460 "uniform mat3 uPv;"
461 ""
462 "out vec2 aTexCoords;"
463 ""
464 "void main()"
465 "{"
466 "vec2 vertex_world = uUv.zw * (a_co-0.5) * uPos.z + uPos.xy;"
467 "gl_Position = vec4( uPv * vec3( vertex_world, 1.0 ), 1.0 );"
468 "aTexCoords = uUv.xy + a_co*uUv.zw;"
469 "}",
470
471 // FRAGMENT
472 "uniform sampler2D uTexMain;"
473 "out vec4 FragColor;"
474 ""
475 "in vec2 aTexCoords;"
476 ""
477 "void main()"
478 "{"
479 "vec4 texture_sample = texture( uTexMain, aTexCoords );"
480 "FragColor = texture_sample;"
481 "}"
482 ,
483 UNIFORMS({ "uPv", "uTexMain", "uUv", "uPos" })
484 )
485
486 SHADER_DEFINE( shader_post_darken,
487 "layout (location=0) in vec2 a_co;"
488 "out vec2 aTexCoords;"
489 ""
490 "void main()"
491 "{"
492 "gl_Position = vec4( a_co * 2.0 - 1.0, 0.0, 1.0 );"
493 "aTexCoords = a_co;"
494 "}",
495
496 "uniform sampler2D uTexMain;"
497 "out vec4 FragColor;"
498 ""
499 "in vec2 aTexCoords;"
500 ""
501 "void main()"
502 "{"
503 "vec4 texture_sample = texture( uTexMain, aTexCoords );"
504 "FragColor = vec4(pow(texture_sample.rgb,vec3(2.2)), 1.0);"
505 "}"
506 ,
507 UNIFORMS({"uTexMain"})
508 )
509
510 SHADER_DEFINE( shader_post_blur,
511 "layout (location=0) in vec2 a_co;"
512 "out vec2 aTexCoords;"
513 ""
514 "void main()"
515 "{"
516 "gl_Position = vec4( a_co * 2.0 - 1.0, 0.0, 1.0 );"
517 "aTexCoords = a_co;"
518 "}",
519
520 "uniform sampler2D uTexMain;"
521 "uniform vec2 uDir;"
522 "out vec4 FragColor;"
523 ""
524 "in vec2 aTexCoords;"
525 ""
526 "void main()"
527 "{"
528 "vec4 colour = vec4(0.0);"
529
530 "vec2 off1 = vec2(1.411764705882353) * uDir;"
531 "vec2 off2 = vec2(3.2941176470588234) * uDir;"
532 "vec2 off3 = vec2(5.176470588235294) * uDir;"
533 "colour += texture2D( uTexMain, aTexCoords ) * 0.1964825501511404;"
534 "colour += texture2D( uTexMain, aTexCoords + off1 ) * 0.2969069646728344;"
535 "colour += texture2D( uTexMain, aTexCoords - off1 ) * 0.2969069646728344;"
536 "colour += texture2D( uTexMain, aTexCoords + off2 ) * 0.09447039785044732;"
537 "colour += texture2D( uTexMain, aTexCoords - off2 ) * 0.09447039785044732;"
538 "colour += texture2D( uTexMain, aTexCoords + off3 ) * 0.010381362401148057;"
539 "colour += texture2D( uTexMain, aTexCoords - off3 ) * 0.010381362401148057;"
540 "FragColor = colour;"
541 "}"
542 ,
543 UNIFORMS({"uTexMain","uDir"})
544 )
545
546 SHADER_DEFINE( shader_post_comp,
547 "layout (location=0) in vec2 a_co;"
548 "out vec2 aTexCoords;"
549 ""
550 "void main()"
551 "{"
552 "gl_Position = vec4( a_co * 2.0 - 1.0, 0.0, 1.0 );"
553 "aTexCoords = a_co;"
554 "}",
555
556 "uniform sampler2D uTexMain;"
557 "uniform sampler2D uTexBloom;"
558 "uniform vec2 uComp;" /* x: bloom, y: vignette */
559 "out vec4 FragColor;"
560 ""
561 "in vec2 aTexCoords;"
562 ""
563 "void main()"
564 "{"
565 "vec4 texture_sample = texture( uTexMain, aTexCoords );"
566 "vec4 bloom_sample = texture( uTexBloom, aTexCoords );"
567
568 "vec2 vigCoord = aTexCoords - 0.5;"
569 "float vig = pow(1.0 - dot( vigCoord, vigCoord ), 2.0);"
570
571 "FragColor = (texture_sample + bloom_sample*0.3*uComp.x)"
572 " * max(uComp.y, vig);"
573 "}"
574 ,
575 UNIFORMS({"uTexMain", "uTexBloom", "uComp"})
576 )
577
578 void vg_register(void)
579 {
580 SHADER_INIT( shader_tile_colour );
581 SHADER_INIT( shader_tile_main );
582 SHADER_INIT( shader_ball );
583 SHADER_INIT( shader_background );
584 SHADER_INIT( shader_wire );
585 SHADER_INIT( shader_buttons );
586 SHADER_INIT( shader_sprite );
587 SHADER_INIT( shader_post_darken );
588 SHADER_INIT( shader_post_comp );
589 SHADER_INIT( shader_post_blur );
590 }
591
592 /*
593 0000 0 | 0001 1 | 0010 2 | 0011 3
594 | | | | |
595 X | X= | X | X=
596 | | |
597 0100 4 | 0101 5 | 0110 6 | 0111 7
598 | | | | |
599 =X | =X= | =X | =X=
600 | | |
601 1000 8 | 1001 9 | 1010 10 | 1011 11
602 | | | | |
603 X | X= | X | X=
604 | | | | | | |
605 1100 12 | 1101 13 | 1110 14 | 1111 15
606 | | | | |
607 =X | =X= | =X | =X=
608 | | | | | | |
609 */
610
611 struct cmp_level
612 {
613 // Basic info
614 int serial_id;
615
616 const char *map_name;
617 const char *title;
618 const char *description;
619
620 const char *achievement;
621
622 int _unlock, _linked; // When completed, unlock this level
623 int is_tutorial;
624
625 // Aesthetic
626 struct world_string
627 {
628 enum placement
629 {
630 k_placement_top,
631 k_placement_bottom
632 }
633 placement;
634
635 const char *str;
636 }
637 strings[2];
638
639 // Persistent stats
640 int unlocked;
641 int completed_score;
642
643 // Runtime
644 struct world_button btn;
645 struct cmp_level *unlock, *linked;
646
647 #ifdef VG_STEAM
648 SteamLeaderboard_t steam_leaderboard;
649 #endif
650 };
651
652 static struct cmp_level cmp_levels_tutorials[] =
653 {
654 {
655 0, "cmp_t01", "PRINCIPLE 1", "",
656 ._unlock = 1,
657 .is_tutorial = 1
658 },
659 {
660 1, "cmp_t02", "PRINCIPLE 2", "",
661 ._unlock = 2,
662 .is_tutorial = 1,
663 },
664 {
665 2, "cmp_t03", "PRINCIPLE 3", "",
666 ._unlock = 12,
667 .is_tutorial = 1
668 },
669 {
670 12, "cmp_t04", "PRINCIPLE 4", "",
671 ._unlock = 6,
672 .is_tutorial = 1,
673 .achievement = "TUTORIALS"
674 },
675 {
676 15, "cmp_b10", "PRINCIPLE 5", "",
677 ._unlock = 16,
678 .is_tutorial = 1
679 },
680 {
681 17, "cmp_b11", "PRINCIPLE 6", "(Right click)",
682 ._unlock = 18,
683 .is_tutorial = 1
684 },
685 {
686 26, "cmp_p7", "PRINCIPLE 7", "Emitters",
687 ._unlock = 27,
688 ._linked = 13,
689 .is_tutorial = 1
690 }
691 };
692
693 static struct cmp_level cmp_levels_basic[] =
694 {
695 {
696 6, "cmp_b04", "PATCH", "",
697 ._unlock = 7,
698 ._linked = 3
699 },
700 {
701 3, "cmp_b01", "SUBDIVISION 1", "",
702 ._linked = 4,
703 ._unlock = 5
704 },
705 {
706 4, "cmp_b02", "SUBDIVISION 2", "",
707 ._unlock = 7
708 },
709 {
710 5, "cmp_b03", "RESTRUCTURE", "",
711 ._unlock = 8,
712 ._linked = 31
713 },
714 {
715 31, "cmp_121", "1-2-1", "",
716 ._unlock = 8
717 },
718 {
719 7, "cmp_b05", "PATTERNS 1", "",
720 ._unlock = 15,
721 ._linked = 8
722 },
723 {
724 8, "cmp_b06", "PATTERNS 2", "",
725 ._unlock = 15
726 },
727 {
728 16, "cmp_routing", "ROUTING PROBLEM", "",
729 ._linked = 9
730 },
731 {
732 9, "cmp_b07", "MIGHTY CONSUMER", "",
733 ._linked = 10,
734 ._unlock = 11,
735 .achievement = "MIGHTY_CONSUMER"
736 },
737 {
738 10, "cmp_b08", "SHIFT", "",
739 ._unlock = 17
740 },
741 {
742 11, "cmp_b09", "REVERSE", "",
743 ._unlock = 17
744 },
745 {
746 18, "cmp_not", "NOT GATE", "",
747 ._linked = 19,
748 ._unlock = 20
749 },
750 {
751 19, "cmp_and", "AND GATE", "",
752 ._unlock = 20
753 },
754 {
755 20, "cmp_xor", "QUALIFICATION PROJECT", "",
756 ._unlock = 26,
757 .achievement = "GRADUATE"
758 },
759 {
760 27, "cmp_expander", "EXPAND", "",
761 ._unlock = 28
762 },
763 {
764 28, "cmp_pattern3", "PATTERNS 3", "",
765 ._linked = 29
766 },
767 {
768 29, "cmp_routing2", "ROUTING PROBLEM 2", "Spaghetti!",
769 ._linked = 30,
770 ._unlock = 32
771 },
772 {
773 30, "cmp_exact5", "EXACTLY 5", "",
774 ._unlock = 32
775 },
776 {
777 32, "cmp_3and2", "THREE AND FOUR", "",
778 ._linked = 34
779 },
780 {
781 34, "doublex2", "DOUBLE DOUBLE", "Delay & repeat",
782 ._linked = 35
783 },
784 {
785 35, "oddoreven", "ODD OR EVEN", ""
786 }
787 };
788
789 static struct cmp_level cmp_levels_grad[] =
790 {
791 {
792 13, "cmp_i01", "SORT", "",
793 ._linked = 14
794 },
795 {
796 14, "cmp_i02", "THIRDS", "",
797 ._linked = 21
798 },
799 {
800 21, "cmp_grad", "SIMPLE ADDITION", "",
801 ._linked = 22,
802 ._unlock = 23
803 },
804 {
805 22, "cmp_secret", "SECRET CODE", "",
806 ._unlock = 23
807 }
808 };
809
810 static struct cmp_level cmp_levels_computer[] =
811 {
812 {
813 23, "cmp_binary", "3 BIT BINARY", "Convert amount to binary",
814 ._unlock = 24,
815 .strings =
816 {
817 {
818 .placement = k_placement_bottom,
819 .str =
820 "\t\t\t\t\t\t\t\t\t\t\x83 \x84\n"
821 "\t\t\t\t\t\t\t\t\t\t\x83 \x84 Binary\n"
822 "\t\t\t\t\t\t\t\t\t\t\x83 4 2 1 \x84"
823 },
824 {
825 .placement = k_placement_top,
826 .str =
827 "\n"
828 "\t\t\t\t\t\t\t\t\t\t\t Count"
829 }
830 }
831 },
832 {
833 24, "cmp_add3b", "3 BIT ADDER", "Binary addition",
834 ._unlock = 25,
835 .strings =
836 {
837 {
838 .placement = k_placement_top,
839 //.str ="\t\t\t\t\t\t\t\t\t| NUMBER A | | NUMBER B |\n"
840 .str =""
841 "\t\t\t\t\t\t\t\t\t\x8A 4 2 1 \x8B \x8A 4 2 1 \x8B\n"
842 "\t\t\t\t\t\t\t\t\t\x83 \x84 add \x83 \x84\n"
843 "\t\t\t\t\t\t\t\t\t\x83 \x84 \x83 \x84"
844 },
845 {
846 .placement = k_placement_bottom,
847 .str =
848 "\t\t\t\x83 \x84\n"
849 "\t\t\t\x83 \x84 result a+b\n"
850 "\t\t\t\x83 8 4 2 1 \x84"
851 }
852 }
853 },
854 {
855 25, "cmp_plot3x3", "3x3 PLOT", "2 bit x/y",
856 ._unlock = 33,
857 .strings =
858 {
859 {
860 .placement = k_placement_top,
861 .str=
862 "\t\t\t\t\t\t\t\t\x8A 2 1 \x8B \x8A 2 1 \x8B\n"
863 "\t\t\t\t\t\t\t\t\x83 \x84 X Y \x83 \x84\n"
864 "\t\t\t\t\t\t\t\t\x83 \x84 \x83 \x84"
865 }
866 }
867 },
868 {
869 33, "compactxor", "Compact XOR", "",
870 .strings =
871 {
872 {
873 .placement = k_placement_top,
874 .str=
875 "\t\t\t\t\x8A \x8B \x8A \x8B\n"
876 "\t\t\t\t\x83 \x84""A B\x83 \x84\n"
877 "\t\t\t\t\x83 \x84 \x83 \x84"
878 },
879 {
880 .placement = k_placement_bottom,
881 .str =
882 "\t\t\t\x83 \x84\n"
883 "\t\t\t\x83 \x84 result a xor b\n"
884 "\t\t\t\x83 \x84"
885 }
886 }
887 }
888 };
889
890 #define NUM_CAMPAIGN_LEVELS (vg_list_size( cmp_levels_tutorials ) + vg_list_size( cmp_levels_basic ) + vg_list_size( cmp_levels_grad ) + vg_list_size( cmp_levels_computer ) )
891
892 static struct career_level_pack
893 {
894 struct cmp_level *pack;
895 const char *title;
896 int count;
897
898 v3f primary_colour;
899 v2i origin;
900 v2i dims;
901 }
902 career_packs[] =
903 {
904 {
905 .pack = cmp_levels_tutorials,
906 .title = "",
907 .count = vg_list_size( cmp_levels_tutorials ),
908 .primary_colour = { 0.204f, 0.345f, 0.553f },
909 .origin = { -4, -2 },
910 .dims = { 1, 7 }
911 },
912 {
913 .pack = cmp_levels_basic,
914 .title = "\x8C\x8D"" Core",
915 .count = vg_list_size( cmp_levels_basic ),
916 .primary_colour = { 0.304f, 0.245f, 0.553f },
917 .origin = { -3, -2 },
918 .dims = { 3, 7 }
919 },
920 {
921 .pack = cmp_levels_grad,
922 .title = "\x8C\x8E"" Challenge",
923 .count = vg_list_size( cmp_levels_grad ),
924 .primary_colour = { 0.75f, 0.23f, 0.39f },
925 .origin = { -4, 5 },
926 .dims = { 4, 1 }
927 },
928 {
929 .pack = cmp_levels_computer,
930 .title = "\x8C\x8F"" 3 Bit computer\n\n (preview)",
931 .count = vg_list_size( cmp_levels_computer ),
932 .primary_colour = { 0.75f, 0.14f, 0.1f },
933 .origin = { -4, 6 },
934 .dims = { 4, 1 }
935 }
936 };
937
938 // Setup pointers and that
939 static void career_local_data_init(void)
940 {
941 struct cmp_level *level_ptrs[ NUM_CAMPAIGN_LEVELS ];
942 for( int i = 0; i < NUM_CAMPAIGN_LEVELS; i ++ )
943 level_ptrs[i] = NULL;
944
945 // COllect pointers
946 for( int i = 0; i < vg_list_size( career_packs ); i ++ )
947 {
948 struct career_level_pack *set = &career_packs[i];
949
950 for( int j = 0; j < set->count; j ++ )
951 {
952 int id = set->pack[j].serial_id;
953
954 if( level_ptrs[ id ] )
955 vg_error( "Serial id %u already used!\n", id );
956 else
957 level_ptrs[ set->pack[j].serial_id ] = &set->pack[j];
958 }
959 }
960
961 // Apply
962 for( int i = 0; i < vg_list_size( career_packs ); i ++ )
963 {
964 struct career_level_pack *set = &career_packs[i];
965
966 for( int j = 0; j < set->count; j ++ )
967 {
968 struct cmp_level *lvl = &set->pack[j];
969
970 if( lvl->_unlock >= NUM_CAMPAIGN_LEVELS ||
971 lvl->_linked >= NUM_CAMPAIGN_LEVELS )
972 {
973 vg_error( "_unlock / _linked out of range (%d, %d)\n",
974 lvl->_unlock, lvl->_linked );
975 }
976 else
977 {
978 lvl->unlock = lvl->_unlock? level_ptrs[ lvl->_unlock ]: NULL;
979 lvl->linked = lvl->_linked? level_ptrs[ lvl->_linked ]: NULL;
980 }
981 }
982 }
983 }