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