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