fish shader/texture
[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 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 ] = 1;
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 cellbytes[0] = 15;
404 }
405 }
406 }
407 while( (cell = map_stack_next()) );
408 }
409 }
410
411 for( int i = 0; i < map.y*map.x; i ++ )
412 {
413 map.cells[i].flowing[ compute_flow_counter ] = vg_min( 128, map.cells[i].flowing[ compute_flow_counter ] );
414 celldata[ i*4+2 ] = map.cells[i].flowing[ compute_flow_counter ];
415 }
416
417 glBindBuffer( GL_ARRAY_BUFFER, map.tiles_vbo );
418 glBufferSubData( GL_ARRAY_BUFFER, 16*sizeof(float) + 1024*2*sizeof(float), map.x*map.y*4, celldata );
419 }
420
421 static int map_load( const char *str )
422 {
423 map_free();
424
425 char *c = str;
426
427 // Scan for width
428 for(;; map.x ++)
429 {
430 if( str[map.x] == ';' )
431 break;
432 else if( !str[map.x] )
433 {
434 vg_error( "Unexpected EOF when parsing level!\n" );
435 return 0;
436 }
437 }
438
439 struct cell *row = arraddnptr( map.cells, map.x );
440 int cx = 0;
441 int reg_start = 0, reg_end = 0;
442
443 for(;;)
444 {
445 if( !*c )
446 break;
447
448 if( *c == ';' )
449 {
450 c ++;
451
452 // Parse attribs
453 if( *c != '\n' )
454 {
455 while( *c )
456 {
457 if( reg_start < reg_end )
458 {
459 if( *c >= 'a' && *c <= 'z' )
460 {
461 arrpush( map.cells[ map.io[ reg_start ] ].conditions, *c );
462 }
463 else
464 {
465 if( *c == ',' || *c == '\n' )
466 {
467 reg_start ++;
468
469 if( *c == '\n' )
470 break;
471 }
472 else
473 {
474 vg_error( "Unkown attrib '%c' (row: %u)\n", *c, map.y );
475 return 0;
476 }
477 }
478 }
479 else
480 {
481 vg_error( "Over-assigned values (row: %u)\n", map.y );
482 return 0;
483 }
484
485 c ++;
486 }
487 }
488
489 if( reg_start != reg_end )
490 {
491 vg_error( "Not enough values assigned (row: %u, %u of %u)\n", map.y, reg_start, reg_end );
492 return 0;
493 }
494
495 if( cx != map.x )
496 {
497 vg_error( "Map row underflow (row: %u, %u<%u)\n", map.y, cx, map.x );
498 return 0;
499 }
500
501 row = arraddnptr( map.cells, map.x );
502 cx = 0;
503 map.y ++;
504 reg_end = reg_start = arrlen( map.io );
505 }
506 else
507 {
508 if( cx == map.x )
509 {
510 vg_error( "Map row overflow (row: %u, %u>%u)\n", map.y, cx, map.x );
511 return 0;
512 }
513
514 row[ cx ].conditions = NULL;
515 row[ cx ].flowing[ 0 ] = 0;
516 row[ cx ].source_count = 0;
517
518 // Parse the various cell types
519 if( *c == '+' || *c == '-' )
520 {
521 arrpush( map.io, cx + map.y*map.x );
522 row[ cx ++ ].flags = *c == '+'? CELL_FLAG_INPUT: CELL_FLAG_OUTPUT;
523 reg_end ++;
524 }
525 else if( *c == '#' )
526 {
527 row[ cx ++ ].flags = CELL_FLAG_WALL;
528 }
529 else
530 {
531 row[ cx ++ ].flags = 0x00;
532 }
533 }
534
535 c ++;
536 }
537
538 // Origin top left corner
539 map.origin[0] = -((float)map.x) * 0.5f;
540 map.origin[2] = -((float)map.y) * 0.5f;
541
542 float *offset_array = (float *)malloc( map.x*map.y*2*sizeof(float) );
543
544 for( int y = 0; y < map.y; y ++ )
545 {
546 for( int x = 0; x < map.x; x ++ )
547 {
548 float *coord = offset_array + (y*map.x+x)*2;
549 coord[0] = x;
550 coord[1] = y;
551 }
552 }
553
554 glBindBuffer( GL_ARRAY_BUFFER, map.tiles_vbo );
555 glBufferSubData( GL_ARRAY_BUFFER, 16*sizeof(float), map.x*map.y*2*sizeof(float), offset_array );
556
557 free( offset_array );
558 vg_success( "Map loaded! (%u:%u)\n", map.x, map.y );
559 return 1;
560 }
561
562 static int map_tile_availible( int co[2] )
563 {
564 // Extract 5x5 grid surrounding tile
565 u32 blob = 0x1000;
566 for( int y = vg_max( co[1]-2, 0 ); y < vg_min( map.y, co[1]+3 ); y ++ )
567 for( int x = vg_max( co[0]-2, 0 ); x < vg_min( map.x, co[0]+3 ); x ++ )
568 {
569 struct cell *cell = map_tile( (int[2]){ x, y } );
570
571 if( cell && (cell->flags & CELL_FLAG_WALKABLE) )
572 blob |= 0x1 << ((y-(co[1]-2))*5 + x-(co[0]-2));
573 }
574
575 // Run filter over center 3x3 grid to check for invalid configurations
576 int kernel[] = { 0, 1, 2, 5, 6, 7, 10, 11, 12 };
577 for( int i = 0; i < vg_list_size(kernel); i ++ )
578 {
579 if( blob & (0x1 << (6+kernel[i])) )
580 {
581 // (reference window: 0x1CE7) Illegal moves
582 // 0100011100010 ;
583 // 0000001100011 ;
584 // 0000011000110 ;
585 // 0110001100000 ;
586 // 1100011000000 ;
587 // 0100001100010 ;
588 // 0100011000010 ;
589
590 u32 invalid[] = { 0x8E2, 0x63, 0xC6, 0xC60, 0x18C0, 0x862, 0x8C2 };
591 u32 window = blob >> kernel[i];
592
593 for( int j = 0; j < vg_list_size(invalid); j ++ )
594 if((window & invalid[j]) == invalid[j])
595 return 0;
596 }
597 }
598
599 return 1;
600 }
601
602 void vg_update(void)
603 {
604 // Update camera
605 float ratio = (float)vg_window_y / (float)vg_window_x;
606 float const size = 7.5f;
607 glm_ortho( -size, size, -size*ratio, size*ratio, 0.01f, 150.f, m_projection );
608
609 glm_mat4_identity( m_view );
610 glm_translate_z( m_view, -10.f );
611 glm_rotate_x( m_view, 1.5708f, m_view );
612
613 glm_mat4_mul( m_projection, m_view, vg_pv );
614
615 // Compute map update
616 for( int y = 0; y < map.y; y ++ )
617 {
618 for( int x = 0; x < map.x; x ++ )
619 {
620 struct cell *tile, *upper, *lower, *l, *r;
621 tile = map_tile_at( (int [2]){ x, y } );
622 tile->flags &= ~(CELL_FLAG_SPLIT|CELL_FLAG_MERGE|CELL_FLAG_UPLVL);
623
624 if( tile->flags & CELL_FLAG_WALKABLE )
625 {
626 r = map_tile_at_cond( (int[2]){ x+1, y }, CELL_FLAG_WALKABLE );
627 l = map_tile_at_cond( (int[2]){ x-1, y }, CELL_FLAG_WALKABLE );
628
629 if( r && l )
630 {
631 upper = map_tile_at_cond( (int[2]){ x, y-1 }, CELL_FLAG_WALKABLE );
632 lower = map_tile_at_cond( (int[2]){ x, y+1 }, CELL_FLAG_WALKABLE );
633
634 if( upper )
635 {
636 tile->flags |= CELL_FLAG_MERGE | CELL_FLAG_UPLVL;
637 }
638
639 if( lower )
640 {
641 tile->flags |= CELL_FLAG_SPLIT;
642 l->flags |= CELL_FLAG_UPLVL;
643 r->flags |= CELL_FLAG_UPLVL;
644 }
645 }
646 }
647 }
648 }
649
650 // Compute classification
651 /*
652 map_stack_refresh();
653
654 for( int i = 0; i < arrlen( map.io ); i ++ )
655 {
656 struct *cell cell = &map.cells[ map.io ];
657 int coords[2];
658
659 if( cell->flags & CELL_FLAG_INPUT )
660 {
661 map_tile_coords_from_index( map.io, coords );
662 map_stack_init( coords );
663
664 do
665 {
666 if( cell->flags & CELL_FLAG_CONNECTOR )
667 {
668
669 }
670 }
671 while( (cell = map_stack_next()) );
672 }
673 }*/
674
675 // Get mouse ray
676 vec3 ray_origin;
677 vec3 ray_dir;
678
679 mat4 pv_inverse;
680 vec4 vp = { 0.f, 0.f, vg_window_x, vg_window_y };
681 glm_mat4_inv( vg_pv, pv_inverse );
682 glm_unprojecti( (vec3){ vg_mouse_x, vg_window_y-vg_mouse_y, -1.f }, pv_inverse, vp, ray_dir );
683 glm_unprojecti( (vec3){ vg_mouse_x, vg_window_y-vg_mouse_y, 0.f }, pv_inverse, vp, ray_origin );
684 glm_vec3_sub( ray_dir, ray_origin, ray_dir );
685
686 // Get floor tile intersection
687 float ray_t = -ray_origin[1] / ray_dir[1];
688
689 vec3 tile_pos;
690 glm_vec3_copy( ray_origin, tile_pos );
691 glm_vec3_muladds( ray_dir, ray_t, tile_pos );
692 glm_vec3_sub( tile_pos, map.origin, tile_pos );
693
694 int tile_x = floorf( tile_pos[0] );
695 int tile_y = floorf( tile_pos[2] );
696
697 map.selected = map_tile_at( (int [2]){tile_x, tile_y} );
698
699 if( map.playing )
700 {
701 static int fish_counter = 0;
702 fish_counter ++;
703
704 if( fish_counter > 20 )
705 {
706 fish_counter = 0;
707
708 // Advance characters
709 for( int i = 0; i < map.num_fishes; i ++ )
710 {
711 struct fish *fish = map.fishes + i;
712
713 if( !fish->alive )
714 continue;
715
716 struct cell *tile, *next;
717 tile = map_tile_at( fish->co );
718
719 if( tile->flags & CELL_FLAG_OUTPUT )
720 {
721 vg_info( "Fish got zucced (%d)\n", i );
722 fish->alive = 0;
723 continue;
724 }
725
726 int die = 0;
727 if( tile->flags & CELL_FLAG_SPLIT )
728 {
729 die = 1;
730 int new_dir[][2] = { {0,-1},{1,0},{-1,0} };
731 int *test_dir;
732
733 for( int j = 0; j < 3; j ++ )
734 {
735 test_dir = new_dir[ tile->state ];
736 tile->state = (tile->state+1)%3;
737
738 next = map_tile_at( (int[2]){ fish->co[0]+test_dir[0], fish->co[1]+test_dir[1] } );
739 if( next && (next->flags & (CELL_FLAG_WALKABLE)) )
740 {
741 fish->dir[0] = test_dir[0];
742 fish->dir[1] = test_dir[1];
743 die = 0;
744 break;
745 }
746 }
747 }
748
749 next = map_tile_at( (int[2]){ fish->co[0]+fish->dir[0], fish->co[1]+fish->dir[1] } );
750 if( !next || (next && !(next->flags & CELL_FLAG_WALKABLE)) )
751 {
752 // Try UP
753 die = 1;
754 }
755
756 if( die )
757 {
758 vg_info( "Fish died! (%d)\n", i );
759 fish->alive = 0;
760 continue;
761 }
762
763
764 fish->co[0] += fish->dir[0];
765 fish->co[1] += fish->dir[1];
766 }
767
768 // Try spawn fish
769 for( int i = 0; i < arrlen( map.io ); i ++ )
770 {
771 struct cell *input = &map.cells[ map.io[i] ];
772
773 if( input->flags & CELL_FLAG_INPUT )
774 {
775 if( input->state < arrlen( input->conditions ) )
776 {
777 struct fish *fish = &map.fishes[ map.num_fishes ];
778 map_tile_coords_from_index( map.io[i], fish->co );
779
780 int output_dirs[][2] = { {0,-1}, {-1,0}, {1,0} };
781 int can_spawn = 0;
782
783 for( int i = 0; i < vg_list_size( output_dirs ); i ++ )
784 {
785 int *dir = output_dirs[i];
786 struct cell *next = map_tile_at( (int[2]){ fish->co[0]+dir[0], fish->co[1]+dir[1] } );
787 if( next && next->flags & CELL_FLAG_CANAL )
788 {
789 fish->dir[0] = dir[0];
790 fish->dir[1] = dir[1];
791 can_spawn = 1;
792 }
793 }
794
795 if( can_spawn )
796 {
797 fish->alive = 1;
798 input->state ++;
799 map.num_fishes ++;
800 }
801 }
802 }
803 }
804
805 vg_info( "There are now %u active fish\n", map.num_fishes );
806 }
807
808 if( vg_get_button_down( "go" ) )
809 {
810 map.playing = 0;
811 map.num_fishes = 0;
812
813 vg_info( "Ending!\n" );
814 }
815 }
816 else
817 {
818 if( vg_get_button_down( "go" ) )
819 {
820 map.playing = 1;
821
822 // Reset everything
823 for( int i = 0; i < map.x*map.y; i ++ )
824 map.cells[ i ].state = 0;
825
826 vg_info( "Starting!\n" );
827 }
828
829 if( map.selected )
830 {
831 map.select_valid = map_tile_availible( (int[2]){ tile_x, tile_y } );
832
833 if( map.select_valid )
834 {
835 if( vg_get_button_down("primary") )
836 {
837 if( map.selected->flags & CELL_FLAG_CANAL )
838 {
839 map.selected->flags &= ~(CELL_FLAG_CANAL);
840 }
841 else
842 {
843 map.selected->flags |= CELL_FLAG_CANAL;
844 }
845 }
846 }
847 }
848 }
849 }
850
851 GLuint tile_vao;
852 GLuint tile_vbo;
853 GLuint fish_texture;
854
855 void vg_render(void)
856 {
857 glViewport( 0,0, vg_window_x, vg_window_y );
858
859 //glEnable( GL_DEPTH_TEST );
860 glClearColor( 0.94f, 0.94f, 0.94f, 1.0f );
861 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
862
863 glBindVertexArray( map.tiles_vao );
864
865 map_update_visual();
866
867 SHADER_USE( tilemap_shader );
868 glUniformMatrix4fv( SHADER_UNIFORM( tilemap_shader, "uPv" ), 1, GL_FALSE, (float *)vg_pv );
869
870 glUniform1i( SHADER_UNIFORM( tilemap_shader, "uTexTiles" ), 0 );
871 glActiveTexture( GL_TEXTURE0 );
872 glBindTexture( GL_TEXTURE_2D, map.tile_texture );
873
874 glUniform1i( SHADER_UNIFORM( tilemap_shader, "uTexRipples" ), 1 );
875 glActiveTexture( GL_TEXTURE1 );
876 glBindTexture( GL_TEXTURE_2D, map.flow_texture );
877
878 glUniform2f( SHADER_UNIFORM( tilemap_shader, "uOrigin" ), map.origin[0], map.origin[2] );
879 glUniform1f( SHADER_UNIFORM( tilemap_shader, "uTime" ), vg_time * 0.5f );
880
881 glDrawArraysInstanced( GL_TRIANGLES, 0, 6, map.x*map.y );
882
883 SHADER_USE( fish_shader );
884 glUniformMatrix4fv( SHADER_UNIFORM( fish_shader, "uPv" ), 1, GL_FALSE, (float *)vg_pv );
885 glUniform1i( SHADER_UNIFORM( fish_shader, "uTexMain" ), 0 );
886 glActiveTexture( GL_TEXTURE0 );
887 glBindTexture( GL_TEXTURE_2D, fish_texture );
888 glUniform3f( SHADER_UNIFORM( fish_shader, "uPosition" ), 0.0f, 0.0f, floorf( vg_time*20.0f ) );
889 glUniform3f( SHADER_UNIFORM( fish_shader, "uColour" ), 1.0f, 0.1f, 0.1f );
890
891 glEnable( GL_BLEND );
892 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
893 glBlendEquation( GL_FUNC_ADD );
894
895 glDrawArrays( GL_TRIANGLES, 0, 6 );
896
897 glDisable( GL_BLEND );
898 }
899
900 void vg_register(void)
901 {
902 SHADER_INIT( colour_shader );
903 SHADER_INIT( tilemap_shader );
904 SHADER_INIT( fish_shader );
905 }
906
907 void vg_start(void)
908 {
909 glGenVertexArrays( 1, &tile_vao );
910 glGenBuffers( 1, &tile_vbo );
911
912 float quad_mesh[] =
913 {
914 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
915 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f,
916
917 // Padding
918 0.0f, 0.0f, 0.0f, 0.0f
919 };
920
921 glBindVertexArray( tile_vao );
922 glBindBuffer( GL_ARRAY_BUFFER, tile_vbo );
923 glBufferData
924 (
925 GL_ARRAY_BUFFER,
926 sizeof( quad_mesh ),
927 quad_mesh,
928 GL_STATIC_DRAW
929 );
930
931 glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0 );
932 glEnableVertexAttribArray( 0 );
933
934 VG_CHECK_GL();
935
936 // Create map buffers
937 glGenVertexArrays( 1, &map.tiles_vao );
938 glGenBuffers( 1, &map.tiles_vbo );
939
940 glBindVertexArray( map.tiles_vao );
941 glBindBuffer( GL_ARRAY_BUFFER, map.tiles_vbo );
942 glBufferData( GL_ARRAY_BUFFER,
943 sizeof( quad_mesh ) +
944 sizeof( float )*2 * 1024 +
945 sizeof( u8 )*4 * 1024,
946 NULL,
947 GL_DYNAMIC_DRAW
948 );
949
950 glBufferSubData( GL_ARRAY_BUFFER, 0, sizeof( quad_mesh ), quad_mesh );
951
952 // Base quad
953 glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, 2*sizeof(float), (void*)0 );
954 glEnableVertexAttribArray( 0 );
955
956 // Offset, data arrays (instancing)
957 glVertexAttribPointer( 1, 2, GL_FLOAT, GL_FALSE, 2*sizeof(float), (void*)(sizeof(quad_mesh)) );
958 glEnableVertexAttribArray( 1 );
959 glVertexAttribDivisor( 1, 1 );
960
961 glVertexAttribPointer( 2, 4, GL_UNSIGNED_BYTE, GL_FALSE, 4, (void*)(sizeof(quad_mesh)+sizeof(float)*2*1024) );
962 glEnableVertexAttribArray( 2 );
963 glVertexAttribDivisor( 2, 1 );
964
965 map.tile_texture = vg_tex2d_rgba( "textures/rivertiles_flowm.tga" );
966 vg_tex2d_nearest();
967 vg_tex2d_repeat();
968
969 map.flow_texture = vg_tex2d_rgba( "textures/rivertiles_ripple.tga" );
970 vg_tex2d_nearest();
971 vg_tex2d_repeat();
972
973 fish_texture = vg_tex2d_rgba( "textures/fishe_swim.tga" );
974 vg_tex2d_nearest();
975 vg_tex2d_repeat();
976
977 map_load
978 (
979 "##-#####-##;aaa,aa\n"
980 "# #;\n"
981 "# #;\n"
982 "# #;\n"
983 "# #;\n"
984 "# #;\n"
985 "# #;\n"
986 "##+#####+##;aa,aaa\n"
987 );
988 }
989
990 void vg_free(void)
991 {
992 map_free();
993
994 glDeleteVertexArrays( 1, &tile_vao );
995 glDeleteVertexArrays( 1, &map.tiles_vao );
996
997 glDeleteBuffers( 1, &tile_vbo );
998 glDeleteBuffers( 1, &map.tiles_vbo );
999
1000 glDeleteTextures( 1, &map.tile_texture );
1001 glDeleteTextures( 1, &map.flow_texture );
1002 }
1003
1004 void vg_ui(void)
1005 {
1006
1007 }