89bc1d8432c2b63eaaf7fa205244ec91d0d486e8
[fishladder.git] / fishladder.c
1 // Copyright (C) 2021 Harry Godden (hgn) - All Rights Reserved
2
3 //#define VG_STEAM
4 #include "vg/vg.h"
5
6 #define CELL_SHEET_X 512
7 #define CELL_SHEET_Y 512
8
9 SHADER_DEFINE( colour_shader,
10
11 // VERTEX
12 "layout (location=0) in vec2 a_co;"
13 "uniform mat4 uPv;"
14 "uniform mat4 uMdl;"
15 ""
16 "void main()"
17 "{"
18 " vec4 vert_pos = uPv * uMdl * vec4( a_co.x, 0.0, a_co.y, 1.0 );"
19 " gl_Position = vert_pos;"
20 "}",
21
22 // FRAGMENT
23 "out vec4 FragColor;"
24 "uniform vec4 uColour;"
25 ""
26 "void main()"
27 "{"
28 " FragColor = uColour;"
29 "}"
30 ,
31 UNIFORMS({ "uPv", "uMdl", "uColour" })
32 )
33
34 SHADER_DEFINE( tilemap_shader,
35
36 // VERTEX
37 "layout (location=0) in vec2 a_co;" // XY
38 "layout (location=1) in vec2 a_offset;" // XY offset
39 "layout (location=2) in vec4 a_data;" // atlas-uv, amt, other
40 "uniform mat4 uPv;"
41 "uniform vec2 uOrigin;"
42 ""
43 "out vec4 aCoords;"
44 ""
45 "void main()"
46 "{"
47 "vec2 world_coord = a_co+a_offset+uOrigin;"
48 "gl_Position = uPv * vec4( world_coord.x, 0.0, world_coord.y, 1.0 );"
49 "aCoords = vec4((a_co*0.98+0.01 + vec2(a_data.x,0.0)) * 0.0625, a_data.zw);"
50 "}",
51
52 // FRAGMENT
53 "uniform sampler2D uTexTiles;"
54 "uniform sampler2D uTexRipples;"
55 "uniform float uTime;"
56
57 "in vec4 aCoords;"
58 "out vec4 FragColor;"
59
60 "void main()"
61 "{"
62 "vec4 glyph = texture( uTexTiles, aCoords.xy );"
63 "vec4 ripple = texture( uTexRipples, vec2( glyph.x - uTime, glyph.y ));"
64 "float wstatus = -((aCoords.z/128.0)-1.0);" // -1 := None in, 0.0 := Hold middle, 1.0 := All out
65 "float dev = step( 0.0, glyph.x+wstatus ) * step( glyph.x+wstatus, 1.0 );" //+ abs(glyph.y-0.5) );"
66 "vec3 composite = mix( vec3(0.5,0.5,0.5), vec3(0.3,0.6,1.0) + ripple.xyz * 0.05, step( 0.75, glyph.a )*dev ) * glyph.z;"
67 "FragColor = vec4( composite, 1.0 );"
68 "}"
69 ,
70 UNIFORMS({ "uPv", "uTexTiles", "uTexRipples", "uTime", "uOrigin" })
71 )
72
73 SHADER_DEFINE( fish_shader,
74 // VERTEX
75 "layout (location=0) in vec2 a_co;" // XY UV
76
77 "uniform mat4 uPv;"
78 "uniform vec3 uPosition;"
79
80 "out vec2 aTexCoords;"
81
82 "void main()"
83 "{"
84 "vec2 world_coord = a_co + uPosition.xy;"
85 "gl_Position = uPv * vec4( world_coord.x, 0.0, world_coord.y, 1.0 );"
86 "aTexCoords = vec2( (a_co.x + uPosition.z) * 0.125, a_co.y );"
87 "}",
88 // FRAGMENT
89 "uniform sampler2D uTexMain;"
90 "uniform vec3 uColour;"
91
92 "in vec2 aTexCoords;"
93 "out vec4 FragColor;"
94
95 "void main()"
96 "{"
97 "vec4 maintex = texture( uTexMain, aTexCoords );"
98 "vec3 comp = mix( vec3(0.0,0.03,0.04), uColour, maintex.r );"
99 "FragColor = vec4( comp, maintex.g * 0.7 );"
100 "}",
101 UNIFORMS({ "uPv", "uTexMain", "uColour", "uPosition" })
102 )
103
104 mat4 m_projection;
105 mat4 m_view;
106 mat4 m_mdl;
107
108 int main( int argc, char *argv[] )
109 {
110 vg_init( argc, argv, "FishLadder" );
111 }
112
113 #define CELL_FLAG_INPUT 0x1
114 #define CELL_FLAG_OUTPUT 0x2
115 #define CELL_FLAG_IO (CELL_FLAG_INPUT|CELL_FLAG_OUTPUT)
116 #define CELL_FLAG_WALL 0x4
117 #define CELL_FLAG_HOVER 0x8
118 #define CELL_FLAG_ITER 0x10
119 #define CELL_FLAG_CANAL 0x20
120 #define CELL_FLAG_SPLIT 0x40 /* Does this cell split and have an incoming vertical connection? */
121 #define CELL_FLAG_WALKABLE (CELL_FLAG_IO|CELL_FLAG_CANAL)
122 #define CELL_FLAG_VISITED 0x80
123 #define CELL_FLAG_UPLVL 0x100
124 #define CELL_FLAG_MERGE 0x200
125
126 static struct
127 {
128 u32 x,y;
129
130 struct cell
131 {
132 u32 flags;
133 u32 model_id;
134
135 char *conditions;
136
137 int level;
138 int state;
139 int flowing[2];
140 int source_count;
141 }
142 * cells;
143
144 struct fish
145 {
146 int alive;
147 int co[2];
148 int dir[2];
149 char data;
150 }
151 fishes[ 20 ];
152 int num_fishes;
153
154 vec3 origin;
155 struct cell *selected;
156 int select_valid;
157 int playing;
158 u32 frame;
159
160 u32 *io;
161
162 struct vstack
163 {
164 struct vframe
165 {
166 int x, y;
167 int i;
168 }
169 frames[ 64 ];
170
171 int level;
172 u32 flags;
173 }
174 stack;
175
176 GLuint tile_texture;
177 GLuint flow_texture;
178
179 GLuint tiles_vao;
180 GLuint tiles_vbo;
181 }
182 map;
183
184 static void map_free(void)
185 {
186 for( int i = 0; i < arrlen( map.io ); i ++ )
187 {
188 arrfree( map.cells[ map.io[i] ].conditions );
189 }
190
191 arrfree( map.cells );
192 arrfree( map.io );
193 map.x = 0;
194 map.y = 0;
195 map.cells = NULL;
196 map.io = NULL;
197 }
198
199 static struct cell *map_tile( int pos[2] )
200 {
201 return map.cells + pos[1]*map.x + pos[0];
202 }
203
204 static struct cell *map_tile_at( int pos[2] )
205 {
206 if( pos[0] >= 0 && pos[0] < map.x && pos[1] >= 0 && pos[1] < map.y )
207 return map.cells + pos[1]*map.x + pos[0];
208 return NULL;
209 }
210
211 static struct cell *map_tile_at_cond( int pos[2], u32 flags )
212 {
213 struct cell *cell = map_tile_at( pos );
214 if( cell && (cell->flags & flags) )
215 return cell;
216
217 return NULL;
218 }
219
220 static void map_tile_coords_from_index( int i, int coords[2] )
221 {
222 coords[0] = i % map.x;
223 coords[1] = (i - coords[0])/map.x;
224 }
225
226 static void map_stack_refresh(void)
227 {
228 for( int i = 0; i < map.x*map.y; i ++ )
229 map.cells[i].flags &= ~CELL_FLAG_VISITED;
230 }
231
232 static void map_stack_init( int coords[2] )
233 {
234 map.stack.level = 0;
235 map.stack.frames[0].i = 0;
236 map.stack.frames[0].x = coords[0];
237 map.stack.frames[0].y = coords[1];
238 }
239
240 static struct cell *map_stack_next(void)
241 {
242 struct cell *tile = NULL;
243
244 while( !tile )
245 {
246 struct vframe *frame = &map.stack.frames[ map.stack.level ];
247
248 int output_dirs[][2] = { {0,1}, {-1,0}, {1,0} };
249
250 if( frame->i < 3 )
251 {
252 int *dir = output_dirs[ frame->i ];
253 tile = map_tile_at_cond( (int[2]){frame->x+dir[0], frame->y+dir[1]}, CELL_FLAG_WALKABLE );
254
255 if( tile && !(tile->flags & CELL_FLAG_VISITED) )
256 {
257 map.stack.level ++;
258 frame[1].i = 0;
259 frame[1].x = frame[0].x+dir[0];
260 frame[1].y = frame[0].y+dir[1];
261
262 tile->flags |= CELL_FLAG_VISITED;
263
264 if( frame->i == 0 )
265 frame->i = 400;
266 }
267 else
268 tile = NULL;
269
270 frame->i ++;
271 }
272 else
273 {
274 map.stack.level --;
275 tile = NULL;
276
277 if( map.stack.level < 0 )
278 return NULL;
279 }
280 }
281
282 return tile;
283 }
284
285 static void map_stack_current_coords( int coords[2], int offset )
286 {
287 coords[0] = map.stack.frames[ map.stack.level+offset ].x;
288 coords[1] = map.stack.frames[ map.stack.level+offset ].y;
289 }
290
291 static void map_update_visual(void)
292 {
293 u8 celldata[ 4096 ];
294
295 static int compute_flow_counter = 0;
296 compute_flow_counter ^= 0x1;
297
298 for( int i = 0; i < map.y*map.x; i ++ )
299 {
300 struct cell *cell = map.cells + i;
301
302 cell->flowing[compute_flow_counter] = cell->flowing[compute_flow_counter^0x1];
303
304 if( !map.cells[i].source_count )
305 cell->flowing[ compute_flow_counter ] = vg_max( cell->flowing[ compute_flow_counter ] - 10, 0 );
306
307 map.cells[i].source_count = 0;
308 }
309
310 for( int y = 0; y < map.y; y ++ )
311 {
312 for( int x = 0; x < map.x; x ++ )
313 {
314 struct cell *cur = map.cells + y*map.x + x;
315 u8 *cellbytes = celldata + (y*map.x+x)*4;
316
317 if( cur->flags & CELL_FLAG_WALKABLE )
318 {
319 struct cell *a, *b, *c, *d;
320
321 a = map_tile_at_cond( (int[2]){ x,y+1 }, CELL_FLAG_WALKABLE );
322 b = map_tile_at_cond( (int[2]){ x+1,y }, CELL_FLAG_WALKABLE );
323 c = map_tile_at_cond( (int[2]){ x,y-1 }, CELL_FLAG_WALKABLE );
324 d = map_tile_at_cond( (int[2]){ x-1,y }, CELL_FLAG_WALKABLE );
325
326 u32 config = (a?0x1:0x0) | (b?0x2:0x0) | (c?0x4:0x0) | (d?0x8:0x0);
327 cellbytes[ 0 ] = config;
328
329 if( cur->flags & CELL_FLAG_OUTPUT )
330 cur->flowing[ compute_flow_counter ] = 128;
331 }
332 else
333 {
334 // TODO: Random background tiles
335 cellbytes[ 0 ] = 15;
336 }
337 }
338 }
339
340 int const k_rate_flow = 16;
341
342 map_stack_refresh();
343 for( int i = 0; i < arrlen( map.io ); i ++ )
344 {
345 int inputcoord[2];
346 if( map.cells[ map.io[i] ].flags & CELL_FLAG_OUTPUT )
347 {
348 map_tile_coords_from_index( map.io[i], inputcoord );
349 map_stack_init( inputcoord );
350 struct cell *cell = map_tile_at( inputcoord );
351
352 int cr[2];
353
354 do
355 {
356 map_stack_current_coords( cr, 0 );
357
358 u8 *cellbytes = celldata + (cr[1]*map.x+cr[0])*4;
359
360 int outflow = cell->flowing[ compute_flow_counter ^ 0x1 ];
361 int sourcing = outflow? 1: 0;
362 int outrate = outflow == 128? k_rate_flow: 0;
363
364 struct cell *a, *b, *d;
365 a = map_tile( (int[2]){ cr[0], cr[1]+1 } );
366 b = map_tile( (int[2]){ cr[0]+1, cr[1] } );
367 d = map_tile( (int[2]){ cr[0]-1, cr[1] } );
368
369 int compute_l = 0, compute_r = 0;
370
371 switch( cellbytes[0] )
372 {
373 // DOWN
374 case 1: case 5: case 11: case 9: case 3:
375 a->flowing[ compute_flow_counter ] += outrate;
376 a->source_count += sourcing;
377 break;
378 case 2: case 6: compute_r = 1; break;
379 case 8: case 12: compute_l = 1; break;
380 case 10: case 14: compute_l = 1; compute_r = 1; break;
381 default: break;
382 }
383
384 if( compute_r && (celldata[ (cr[1]*map.x+cr[0]+1)*4 ] != 14) )
385 {
386 b->flowing[ compute_flow_counter ] += outrate;
387 b->source_count += sourcing;
388 }
389
390 if( compute_l && (celldata[ (cr[1]*map.x+cr[0]-1)*4 ] != 14) )
391 {
392 d->flowing[ compute_flow_counter ] += outrate;
393 d->source_count += sourcing;
394 }
395
396 if( cellbytes[0] == 10 )
397 {
398 int crl[2];
399 map_stack_current_coords( crl, -1 );
400
401 if( crl[0] < cr[0] )
402 {
403 // TODO: Add reverse flag
404 //cellbytes[1] = 1;
405 }
406 }
407 }
408 while( (cell = map_stack_next()) );
409 }
410 }
411
412 for( int i = 0; i < map.y*map.x; i ++ )
413 {
414 map.cells[i].flowing[ compute_flow_counter ] = vg_min( 128, map.cells[i].flowing[ compute_flow_counter ] );
415 celldata[ i*4+2 ] = map.cells[i].flowing[ compute_flow_counter ];
416 }
417
418 glBindBuffer( GL_ARRAY_BUFFER, map.tiles_vbo );
419 glBufferSubData( GL_ARRAY_BUFFER, 16*sizeof(float) + 1024*2*sizeof(float), map.x*map.y*4, celldata );
420 }
421
422 static int map_load( const char *str )
423 {
424 map_free();
425
426 char *c = str;
427
428 // Scan for width
429 for(;; map.x ++)
430 {
431 if( str[map.x] == ';' )
432 break;
433 else if( !str[map.x] )
434 {
435 vg_error( "Unexpected EOF when parsing level!\n" );
436 return 0;
437 }
438 }
439
440 struct cell *row = arraddnptr( map.cells, map.x );
441 int cx = 0;
442 int reg_start = 0, reg_end = 0;
443
444 for(;;)
445 {
446 if( !*c )
447 break;
448
449 if( *c == ';' )
450 {
451 c ++;
452
453 // Parse attribs
454 if( *c != '\n' )
455 {
456 while( *c )
457 {
458 if( reg_start < reg_end )
459 {
460 if( *c >= 'a' && *c <= 'z' )
461 {
462 arrpush( map.cells[ map.io[ reg_start ] ].conditions, *c );
463 }
464 else
465 {
466 if( *c == ',' || *c == '\n' )
467 {
468 reg_start ++;
469
470 if( *c == '\n' )
471 break;
472 }
473 else
474 {
475 vg_error( "Unkown attrib '%c' (row: %u)\n", *c, map.y );
476 return 0;
477 }
478 }
479 }
480 else
481 {
482 vg_error( "Over-assigned values (row: %u)\n", map.y );
483 return 0;
484 }
485
486 c ++;
487 }
488 }
489
490 if( reg_start != reg_end )
491 {
492 vg_error( "Not enough values assigned (row: %u, %u of %u)\n", map.y, reg_start, reg_end );
493 return 0;
494 }
495
496 if( cx != map.x )
497 {
498 vg_error( "Map row underflow (row: %u, %u<%u)\n", map.y, cx, map.x );
499 return 0;
500 }
501
502 row = arraddnptr( map.cells, map.x );
503 cx = 0;
504 map.y ++;
505 reg_end = reg_start = arrlen( map.io );
506 }
507 else
508 {
509 if( cx == map.x )
510 {
511 vg_error( "Map row overflow (row: %u, %u>%u)\n", map.y, cx, map.x );
512 return 0;
513 }
514
515 row[ cx ].conditions = NULL;
516 row[ cx ].flowing[ 0 ] = 0;
517 row[ cx ].source_count = 0;
518
519 // Parse the various cell types
520 if( *c == '+' || *c == '-' )
521 {
522 arrpush( map.io, cx + map.y*map.x );
523 row[ cx ++ ].flags = *c == '+'? CELL_FLAG_INPUT: CELL_FLAG_OUTPUT;
524 reg_end ++;
525 }
526 else if( *c == '#' )
527 {
528 row[ cx ++ ].flags = CELL_FLAG_WALL;
529 }
530 else
531 {
532 row[ cx ++ ].flags = 0x00;
533 }
534 }
535
536 c ++;
537 }
538
539 // Origin top left corner
540 map.origin[0] = -((float)map.x) * 0.5f;
541 map.origin[2] = -((float)map.y) * 0.5f;
542
543 float *offset_array = (float *)malloc( map.x*map.y*2*sizeof(float) );
544
545 for( int y = 0; y < map.y; y ++ )
546 {
547 for( int x = 0; x < map.x; x ++ )
548 {
549 float *coord = offset_array + (y*map.x+x)*2;
550 coord[0] = x;
551 coord[1] = y;
552 }
553 }
554
555 glBindBuffer( GL_ARRAY_BUFFER, map.tiles_vbo );
556 glBufferSubData( GL_ARRAY_BUFFER, 16*sizeof(float), map.x*map.y*2*sizeof(float), offset_array );
557
558 free( offset_array );
559 vg_success( "Map loaded! (%u:%u)\n", map.x, map.y );
560 return 1;
561 }
562
563 static int map_tile_availible( int co[2] )
564 {
565 // Extract 5x5 grid surrounding tile
566 u32 blob = 0x1000;
567 for( int y = vg_max( co[1]-2, 0 ); y < vg_min( map.y, co[1]+3 ); y ++ )
568 for( int x = vg_max( co[0]-2, 0 ); x < vg_min( map.x, co[0]+3 ); x ++ )
569 {
570 struct cell *cell = map_tile( (int[2]){ x, y } );
571
572 if( cell && (cell->flags & CELL_FLAG_WALKABLE) )
573 blob |= 0x1 << ((y-(co[1]-2))*5 + x-(co[0]-2));
574 }
575
576 // Run filter over center 3x3 grid to check for invalid configurations
577 int kernel[] = { 0, 1, 2, 5, 6, 7, 10, 11, 12 };
578 for( int i = 0; i < vg_list_size(kernel); i ++ )
579 {
580 if( blob & (0x1 << (6+kernel[i])) )
581 {
582 // (reference window: 0x1CE7) Illegal moves
583 // 0100011100010 ;
584 // 0000001100011 ;
585 // 0000011000110 ;
586 // 0110001100000 ;
587 // 1100011000000 ;
588 // 0100001100010 ;
589 // 0100011000010 ;
590
591 u32 invalid[] = { 0x8E2, 0x63, 0xC6, 0xC60, 0x18C0, 0x862, 0x8C2 };
592 u32 window = blob >> kernel[i];
593
594 for( int j = 0; j < vg_list_size(invalid); j ++ )
595 if((window & invalid[j]) == invalid[j])
596 return 0;
597 }
598 }
599
600 return 1;
601 }
602
603 void vg_update(void)
604 {
605 // Update camera
606 float ratio = (float)vg_window_y / (float)vg_window_x;
607 float const size = 7.5f;
608 glm_ortho( -size, size, -size*ratio, size*ratio, 0.01f, 150.f, m_projection );
609
610 glm_mat4_identity( m_view );
611 glm_translate_z( m_view, -10.f );
612 glm_rotate_x( m_view, 1.5708f, m_view );
613
614 glm_mat4_mul( m_projection, m_view, vg_pv );
615
616 // Compute map update
617 for( int y = 0; y < map.y; y ++ )
618 {
619 for( int x = 0; x < map.x; x ++ )
620 {
621 struct cell *tile, *upper, *lower, *l, *r;
622 tile = map_tile_at( (int [2]){ x, y } );
623 tile->flags &= ~(CELL_FLAG_SPLIT|CELL_FLAG_MERGE|CELL_FLAG_UPLVL);
624
625 if( tile->flags & CELL_FLAG_WALKABLE )
626 {
627 r = map_tile_at_cond( (int[2]){ x+1, y }, CELL_FLAG_WALKABLE );
628 l = map_tile_at_cond( (int[2]){ x-1, y }, CELL_FLAG_WALKABLE );
629
630 if( r && l )
631 {
632 upper = map_tile_at_cond( (int[2]){ x, y-1 }, CELL_FLAG_WALKABLE );
633 lower = map_tile_at_cond( (int[2]){ x, y+1 }, CELL_FLAG_WALKABLE );
634
635 if( upper )
636 {
637 tile->flags |= CELL_FLAG_MERGE | CELL_FLAG_UPLVL;
638 }
639
640 if( lower )
641 {
642 tile->flags |= CELL_FLAG_SPLIT;
643 l->flags |= CELL_FLAG_UPLVL;
644 r->flags |= CELL_FLAG_UPLVL;
645 }
646 }
647 }
648 }
649 }
650
651 // Compute classification
652 /*
653 map_stack_refresh();
654
655 for( int i = 0; i < arrlen( map.io ); i ++ )
656 {
657 struct *cell cell = &map.cells[ map.io ];
658 int coords[2];
659
660 if( cell->flags & CELL_FLAG_INPUT )
661 {
662 map_tile_coords_from_index( map.io, coords );
663 map_stack_init( coords );
664
665 do
666 {
667 if( cell->flags & CELL_FLAG_CONNECTOR )
668 {
669
670 }
671 }
672 while( (cell = map_stack_next()) );
673 }
674 }*/
675
676 // Get mouse ray
677 vec3 ray_origin;
678 vec3 ray_dir;
679
680 mat4 pv_inverse;
681 vec4 vp = { 0.f, 0.f, vg_window_x, vg_window_y };
682 glm_mat4_inv( vg_pv, pv_inverse );
683 glm_unprojecti( (vec3){ vg_mouse_x, vg_window_y-vg_mouse_y, -1.f }, pv_inverse, vp, ray_dir );
684 glm_unprojecti( (vec3){ vg_mouse_x, vg_window_y-vg_mouse_y, 0.f }, pv_inverse, vp, ray_origin );
685 glm_vec3_sub( ray_dir, ray_origin, ray_dir );
686
687 // Get floor tile intersection
688 float ray_t = -ray_origin[1] / ray_dir[1];
689
690 vec3 tile_pos;
691 glm_vec3_copy( ray_origin, tile_pos );
692 glm_vec3_muladds( ray_dir, ray_t, tile_pos );
693 glm_vec3_sub( tile_pos, map.origin, tile_pos );
694
695 int tile_x = floorf( tile_pos[0] );
696 int tile_y = floorf( tile_pos[2] );
697
698 map.selected = map_tile_at( (int [2]){tile_x, tile_y} );
699
700 if( map.playing )
701 {
702 static int fish_counter = 0;
703 fish_counter ++;
704
705 if( fish_counter > 20 )
706 {
707 fish_counter = 0;
708
709 // Advance characters
710 for( int i = 0; i < map.num_fishes; i ++ )
711 {
712 struct fish *fish = map.fishes + i;
713
714 if( !fish->alive )
715 continue;
716
717 struct cell *tile, *next;
718 tile = map_tile_at( fish->co );
719
720 if( tile->flags & CELL_FLAG_OUTPUT )
721 {
722 vg_info( "Fish got zucced (%d)\n", i );
723 fish->alive = 0;
724 continue;
725 }
726
727 int die = 0;
728 if( tile->flags & CELL_FLAG_SPLIT )
729 {
730 die = 1;
731 int new_dir[][2] = { {0,-1},{1,0},{-1,0} };
732 int *test_dir;
733
734 for( int j = 0; j < 3; j ++ )
735 {
736 test_dir = new_dir[ tile->state ];
737 tile->state = (tile->state+1)%3;
738
739 next = map_tile_at( (int[2]){ fish->co[0]+test_dir[0], fish->co[1]+test_dir[1] } );
740 if( next && (next->flags & (CELL_FLAG_WALKABLE)) )
741 {
742 fish->dir[0] = test_dir[0];
743 fish->dir[1] = test_dir[1];
744 die = 0;
745 break;
746 }
747 }
748 }
749
750 next = map_tile_at( (int[2]){ fish->co[0]+fish->dir[0], fish->co[1]+fish->dir[1] } );
751 if( !next || (next && !(next->flags & CELL_FLAG_WALKABLE)) )
752 {
753 // Try UP
754 die = 1;
755 }
756
757 if( die )
758 {
759 vg_info( "Fish died! (%d)\n", i );
760 fish->alive = 0;
761 continue;
762 }
763
764
765 fish->co[0] += fish->dir[0];
766 fish->co[1] += fish->dir[1];
767 }
768
769 // Try spawn fish
770 for( int i = 0; i < arrlen( map.io ); i ++ )
771 {
772 struct cell *input = &map.cells[ map.io[i] ];
773
774 if( input->flags & CELL_FLAG_INPUT )
775 {
776 if( input->state < arrlen( input->conditions ) )
777 {
778 struct fish *fish = &map.fishes[ map.num_fishes ];
779 map_tile_coords_from_index( map.io[i], fish->co );
780
781 int output_dirs[][2] = { {0,-1}, {-1,0}, {1,0} };
782 int can_spawn = 0;
783
784 for( int i = 0; i < vg_list_size( output_dirs ); i ++ )
785 {
786 int *dir = output_dirs[i];
787 struct cell *next = map_tile_at( (int[2]){ fish->co[0]+dir[0], fish->co[1]+dir[1] } );
788 if( next && next->flags & CELL_FLAG_CANAL )
789 {
790 fish->dir[0] = dir[0];
791 fish->dir[1] = dir[1];
792 can_spawn = 1;
793 }
794 }
795
796 if( can_spawn )
797 {
798 fish->alive = 1;
799 input->state ++;
800 map.num_fishes ++;
801 }
802 }
803 }
804 }
805
806 vg_info( "There are now %u active fish\n", map.num_fishes );
807 }
808
809 if( vg_get_button_down( "go" ) )
810 {
811 map.playing = 0;
812 map.num_fishes = 0;
813
814 vg_info( "Ending!\n" );
815 }
816 }
817 else
818 {
819 if( vg_get_button_down( "go" ) )
820 {
821 map.playing = 1;
822
823 // Reset everything
824 for( int i = 0; i < map.x*map.y; i ++ )
825 map.cells[ i ].state = 0;
826
827 vg_info( "Starting!\n" );
828 }
829
830 if( map.selected )
831 {
832 map.select_valid = map_tile_availible( (int[2]){ tile_x, tile_y } );
833
834 if( map.select_valid )
835 {
836 if( vg_get_button_down("primary") )
837 {
838 if( map.selected->flags & CELL_FLAG_CANAL )
839 {
840 map.selected->flags &= ~(CELL_FLAG_CANAL);
841 }
842 else
843 {
844 map.selected->flags |= CELL_FLAG_CANAL;
845 }
846 }
847 }
848 }
849 }
850 }
851
852 GLuint tile_vao;
853 GLuint tile_vbo;
854 GLuint fish_texture;
855
856 void vg_render(void)
857 {
858 glViewport( 0,0, vg_window_x, vg_window_y );
859
860 //glEnable( GL_DEPTH_TEST );
861 glClearColor( 0.94f, 0.94f, 0.94f, 1.0f );
862 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
863
864 glBindVertexArray( map.tiles_vao );
865
866 map_update_visual();
867
868 SHADER_USE( tilemap_shader );
869 glUniformMatrix4fv( SHADER_UNIFORM( tilemap_shader, "uPv" ), 1, GL_FALSE, (float *)vg_pv );
870
871 glUniform1i( SHADER_UNIFORM( tilemap_shader, "uTexTiles" ), 0 );
872 glActiveTexture( GL_TEXTURE0 );
873 glBindTexture( GL_TEXTURE_2D, map.tile_texture );
874
875 glUniform1i( SHADER_UNIFORM( tilemap_shader, "uTexRipples" ), 1 );
876 glActiveTexture( GL_TEXTURE1 );
877 glBindTexture( GL_TEXTURE_2D, map.flow_texture );
878
879 glUniform2f( SHADER_UNIFORM( tilemap_shader, "uOrigin" ), map.origin[0], map.origin[2] );
880 glUniform1f( SHADER_UNIFORM( tilemap_shader, "uTime" ), vg_time * 0.5f );
881
882 glDrawArraysInstanced( GL_TRIANGLES, 0, 6, map.x*map.y );
883
884 SHADER_USE( fish_shader );
885 glUniformMatrix4fv( SHADER_UNIFORM( fish_shader, "uPv" ), 1, GL_FALSE, (float *)vg_pv );
886 glUniform1i( SHADER_UNIFORM( fish_shader, "uTexMain" ), 0 );
887 glActiveTexture( GL_TEXTURE0 );
888 glBindTexture( GL_TEXTURE_2D, fish_texture );
889 glUniform3f( SHADER_UNIFORM( fish_shader, "uPosition" ), 0.0f, 0.0f, floorf( vg_time*20.0f ) );
890 glUniform3f( SHADER_UNIFORM( fish_shader, "uColour" ), 1.0f, 0.1f, 0.1f );
891
892 glEnable( GL_BLEND );
893 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
894 glBlendEquation( GL_FUNC_ADD );
895
896 glDrawArrays( GL_TRIANGLES, 0, 6 );
897
898 glDisable( GL_BLEND );
899 }
900
901 void vg_register(void)
902 {
903 SHADER_INIT( colour_shader );
904 SHADER_INIT( tilemap_shader );
905 SHADER_INIT( fish_shader );
906 }
907
908 void vg_start(void)
909 {
910 glGenVertexArrays( 1, &tile_vao );
911 glGenBuffers( 1, &tile_vbo );
912
913 float quad_mesh[] =
914 {
915 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
916 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f,
917
918 // Padding
919 0.0f, 0.0f, 0.0f, 0.0f
920 };
921
922 glBindVertexArray( tile_vao );
923 glBindBuffer( GL_ARRAY_BUFFER, tile_vbo );
924 glBufferData
925 (
926 GL_ARRAY_BUFFER,
927 sizeof( quad_mesh ),
928 quad_mesh,
929 GL_STATIC_DRAW
930 );
931
932 glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0 );
933 glEnableVertexAttribArray( 0 );
934
935 VG_CHECK_GL();
936
937 // Create map buffers
938 glGenVertexArrays( 1, &map.tiles_vao );
939 glGenBuffers( 1, &map.tiles_vbo );
940
941 glBindVertexArray( map.tiles_vao );
942 glBindBuffer( GL_ARRAY_BUFFER, map.tiles_vbo );
943 glBufferData( GL_ARRAY_BUFFER,
944 sizeof( quad_mesh ) +
945 sizeof( float )*2 * 1024 +
946 sizeof( u8 )*4 * 1024,
947 NULL,
948 GL_DYNAMIC_DRAW
949 );
950
951 glBufferSubData( GL_ARRAY_BUFFER, 0, sizeof( quad_mesh ), quad_mesh );
952
953 // Base quad
954 glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, 2*sizeof(float), (void*)0 );
955 glEnableVertexAttribArray( 0 );
956
957 // Offset, data arrays (instancing)
958 glVertexAttribPointer( 1, 2, GL_FLOAT, GL_FALSE, 2*sizeof(float), (void*)(sizeof(quad_mesh)) );
959 glEnableVertexAttribArray( 1 );
960 glVertexAttribDivisor( 1, 1 );
961
962 glVertexAttribPointer( 2, 4, GL_UNSIGNED_BYTE, GL_FALSE, 4, (void*)(sizeof(quad_mesh)+sizeof(float)*2*1024) );
963 glEnableVertexAttribArray( 2 );
964 glVertexAttribDivisor( 2, 1 );
965
966 map.tile_texture = vg_tex2d_rgba( "textures/rivertiles_flowm.tga" );
967 vg_tex2d_nearest();
968 vg_tex2d_repeat();
969
970 map.flow_texture = vg_tex2d_rgba( "textures/rivertiles_ripple.tga" );
971 vg_tex2d_nearest();
972 vg_tex2d_repeat();
973
974 fish_texture = vg_tex2d_rgba( "textures/fishe_swim.tga" );
975 vg_tex2d_nearest();
976 vg_tex2d_repeat();
977
978 map_load
979 (
980 "##-#####-##;aaa,aa\n"
981 "# #;\n"
982 "# #;\n"
983 "# #;\n"
984 "# #;\n"
985 "# #;\n"
986 "# #;\n"
987 "##+#####+##;aa,aaa\n"
988 );
989 }
990
991 void vg_free(void)
992 {
993 map_free();
994
995 glDeleteVertexArrays( 1, &tile_vao );
996 glDeleteVertexArrays( 1, &map.tiles_vao );
997
998 glDeleteBuffers( 1, &tile_vbo );
999 glDeleteBuffers( 1, &map.tiles_vbo );
1000
1001 glDeleteTextures( 1, &map.tile_texture );
1002 glDeleteTextures( 1, &map.flow_texture );
1003 }
1004
1005 void vg_ui(void)
1006 {
1007
1008 }